mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
[llvm-rc] Serialize CURSOR and ICON resources to .res
This is part 6 of llvm-rc serialization. This adds ability to output cursors and icons as resources. Unfortunately, we can't just copy .cur or .ico files to output - as each file might contain multiple images, each of them needs to be unpacked and stored as a separate resource. This forces us to parse cursor and icon contents. (Fortunately, these formats are pretty similar and can be processed by mostly common code). As test files are binary, here is a short explanation of .cur and .ico files stored: cursor.cur, cursor-8.cur, cursor-32.cur are sample correct cursor files, differing in their bit depth. icon-old.ico, icon-new.ico are sample correct icon files; icon-png.ico is a sample correct icon file in PNG format (instead of usual BMP); cursor-eof.cur is an incorrect cursor file - this is cursor.cur with some of its final bytes removed. cursor-bad-offset.cur is an incorrect cursor file - image header states that image data begins at offset 0xFFFFFFFF. Sample correct cursors and icons were created by Nico Weber. Patch by Marek Sokolowski Differential Revision: https://reviews.llvm.org/D37878 llvm-svn: 315109
This commit is contained in:
parent
09bbca6bf0
commit
e5d5fbb1ef
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-bad-offset.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-bad-offset.rc
Normal file
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-bad-type.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-bad-type.rc
Normal file
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-eof.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-eof.rc
Normal file
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-nonexistent.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-nonexistent.rc
Normal file
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-nonsense.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor-nonsense.rc
Normal file
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/tag-icon-cursor.rc
Normal file
Binary file not shown.
357
test/tools/llvm-rc/tag-icon-cursor.test
Normal file
357
test/tools/llvm-rc/tag-icon-cursor.test
Normal file
@ -0,0 +1,357 @@
|
||||
; This .ico file used to write this test was lost when the author left
|
||||
; before comitting, and the binary wasn't uploaded to Phabricator. This
|
||||
; will be fixed as soon as we can recover the file.
|
||||
; XFAIL: *
|
||||
; RUN: rm -rf %t
|
||||
; RUN: mkdir %t
|
||||
; RUN: cd %t
|
||||
; RUN: cp %p/Inputs/icon*.ico .
|
||||
; RUN: cp %p/Inputs/cursor*.cur .
|
||||
; RUN: cp %p/Inputs/tag-icon-cursor-nonsense.rc .
|
||||
|
||||
; RUN: llvm-rc /FO %t/tag-icon-cursor.res %p/Inputs/tag-icon-cursor.rc
|
||||
; RUN: llvm-readobj %t/tag-icon-cursor.res | FileCheck %s
|
||||
|
||||
; CHECK: Resource type (int): 1
|
||||
; CHECK-NEXT: Resource name (int): 1
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 308
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 0A000B00 28000000 20000000 40000000 |....(... ...@...|
|
||||
; CHECK-NEXT: 0010: 01000100 00000000 80000000 00000000 |................|
|
||||
; CHECK-NEXT: 0020: 00000000 02000000 00000000 00000000 |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 0110: FFFFFFFF FFFFFFFF FFFFFFFF F3CFFFFF |................|
|
||||
; CHECK-NEXT: 0120: F3CFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
; CHECK-NEXT: 0130: FFFFFFFF |....|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 12
|
||||
; CHECK-NEXT: Resource name (int): 4464
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1030
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 20
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 00000200 01002000 40000100 01003401 |...... .@.....4.|
|
||||
; CHECK-NEXT: 0010: 00000100 |....|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 1
|
||||
; CHECK-NEXT: Resource name (int): 2
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 2220
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 01000C00 28000000 20000000 40000000 |....(... ...@...|
|
||||
; CHECK-NEXT: 0010: 01000800 00000000 00040000 00000000 |................|
|
||||
; CHECK-NEXT: 0020: 00000000 00010000 00000000 00000000 |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 0880: C001FFFF F557FFFF F557FFFF F551FFFF |.....W...W...Q..|
|
||||
; CHECK-NEXT: 0890: C005FFFF B557FFFF F557FFFF F557FFFF |.....W...W...W..|
|
||||
; CHECK-NEXT: 08A0: C001FFFF F557FFFF FFFFFFFF |.....W......|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 12
|
||||
; CHECK-NEXT: Resource name (int): 4465
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1030
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 20
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 00000200 01002000 40000100 0800AC08 |...... .@.......|
|
||||
; CHECK-NEXT: 0010: 00000200 |....|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 3
|
||||
; CHECK-NEXT: Resource name (int): 3
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 1128
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 28000000 10000000 20000000 01002000 |(....... ..... .|
|
||||
; CHECK-NEXT: 0010: 00000000 00040000 C30E0000 C30E0000 |................|
|
||||
; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 0440: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 0450: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 0460: 00000000 00000000 |........|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 3
|
||||
; CHECK-NEXT: Resource name (int): 4
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 2440
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 28000000 18000000 30000000 01002000 |(.......0..... .|
|
||||
; CHECK-NEXT: 0010: 00000000 00090000 C30E0000 C30E0000 |................|
|
||||
; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 0960: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 0970: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 0980: 00000000 00000000 |........|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 3
|
||||
; CHECK-NEXT: Resource name (int): 5
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 4264
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 28000000 20000000 40000000 01002000 |(... ...@..... .|
|
||||
; CHECK-NEXT: 0010: 00000000 00100000 C30E0000 C30E0000 |................|
|
||||
; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 1080: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 1090: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 10A0: 00000000 00000000 |........|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 3
|
||||
; CHECK-NEXT: Resource name (int): 6
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 9640
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 28000000 30000000 60000000 01002000 |(...0...`..... .|
|
||||
; CHECK-NEXT: 0010: 00000000 00240000 C30E0000 C30E0000 |.....$..........|
|
||||
; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 2580: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 2590: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 25A0: 00000000 00000000 |........|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 14
|
||||
; CHECK-NEXT: Resource name (int): 100
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1030
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 62
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 00000100 04001010 00000100 20006804 |............ .h.|
|
||||
; CHECK-NEXT: 0010: 00000300 18180000 01002000 88090000 |.......... .....|
|
||||
; CHECK-NEXT: 0020: 04002020 00000100 2000A810 00000500 |.. .... .......|
|
||||
; CHECK-NEXT: 0030: 30300000 01002000 A8250000 0600 |00.... ..%....|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 1
|
||||
; CHECK-NEXT: Resource name (int): 7
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 4268
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 0D000600 28000000 20000000 40000000 |....(... ...@...|
|
||||
; CHECK-NEXT: 0010: 01002000 00000000 00100000 00000000 |.. .............|
|
||||
; CHECK-NEXT: 0020: 00000000 00000000 00000000 00000000 |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 1080: E027FFFF C3F3FFFF FFFFFFFF FFFFFFFF |.'..............|
|
||||
; CHECK-NEXT: 1090: FFFFFFFF F3CFFFFF F3CFFFFF FFFFFFFF |................|
|
||||
; CHECK-NEXT: 10A0: FFFFFFFF FFFFFFFF FFFFFFFF |............|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 12
|
||||
; CHECK-NEXT: Resource name (int): 4466
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1030
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 20
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 00000200 01002000 40000100 2000AC10 |...... .@... ...|
|
||||
; CHECK-NEXT: 0010: 00000700 |....|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 3
|
||||
; CHECK-NEXT: Resource name (int): 8
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 1128
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 28000000 10000000 20000000 01002000 |(....... ..... .|
|
||||
; CHECK-NEXT: 0010: 00000000 00040000 C30E0000 C30E0000 |................|
|
||||
; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 0440: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 0450: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 0460: 00000000 00000000 |........|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 3
|
||||
; CHECK-NEXT: Resource name (int): 9
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 2440
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 28000000 18000000 30000000 01002000 |(.......0..... .|
|
||||
; CHECK-NEXT: 0010: 00000000 00090000 C30E0000 C30E0000 |................|
|
||||
; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 0960: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 0970: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 0980: 00000000 00000000 |........|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 3
|
||||
; CHECK-NEXT: Resource name (int): 10
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 4264
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 28000000 20000000 40000000 01002000 |(... ...@..... .|
|
||||
; CHECK-NEXT: 0010: 00000000 00100000 C30E0000 C30E0000 |................|
|
||||
; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 1080: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 1090: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 10A0: 00000000 00000000 |........|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 3
|
||||
; CHECK-NEXT: Resource name (int): 11
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 9640
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 28000000 30000000 60000000 01002000 |(...0...`..... .|
|
||||
; CHECK-NEXT: 0010: 00000000 00240000 C30E0000 C30E0000 |.....$..........|
|
||||
; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
|
||||
; (...)
|
||||
; CHECK-DAG: 2580: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 2590: 00000000 00000000 00000000 00000000 |................|
|
||||
; CHECK-NEXT: 25A0: 00000000 00000000 |........|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 14
|
||||
; CHECK-NEXT: Resource name (int): 100
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1030
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 62
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 00000100 04001010 00000100 20006804 |............ .h.|
|
||||
; CHECK-NEXT: 0010: 00000800 18180000 01002000 88090000 |.......... .....|
|
||||
; CHECK-NEXT: 0020: 09002020 00000100 2000A810 00000A00 |.. .... .......|
|
||||
; CHECK-NEXT: 0030: 30300000 01002000 A8250000 0B00 |00.... ..%....|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 3
|
||||
; CHECK-NEXT: Resource name (int): 12
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1010
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 82
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 89504E47 0D0A1A0A 0000000D 49484452 |.PNG........IHDR|
|
||||
; CHECK-NEXT: 0010: 00000010 00000010 08060000 001FF3FF |................|
|
||||
; CHECK-NEXT: 0020: 61000000 19494441 5438CB63 FC0F040C |a....IDAT8.c....|
|
||||
; CHECK-NEXT: 0030: 1400C651 03460D18 3560B818 0000251F |...Q.F..5`....%.|
|
||||
; CHECK-NEXT: 0040: 3FD1D6DC 546E0000 00004945 4E44AE42 |?...Tn....IEND.B|
|
||||
; CHECK-NEXT: 0050: 6082 |`.|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
; CHECK-DAG: Resource type (int): 14
|
||||
; CHECK-NEXT: Resource name (int): 100
|
||||
; CHECK-NEXT: Data version: 0
|
||||
; CHECK-NEXT: Memory flags: 0x1030
|
||||
; CHECK-NEXT: Language ID: 1033
|
||||
; CHECK-NEXT: Version (major): 0
|
||||
; CHECK-NEXT: Version (minor): 0
|
||||
; CHECK-NEXT: Characteristics: 0
|
||||
; CHECK-NEXT: Data size: 20
|
||||
; CHECK-NEXT: Data: (
|
||||
; CHECK-NEXT: 0000: 00000100 01001010 00000100 20005200 |............ .R.|
|
||||
; CHECK-NEXT: 0010: 00000C00 |....|
|
||||
; CHECK-NEXT: )
|
||||
|
||||
|
||||
; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-nonexistent.rc 2>&1 | FileCheck %s --check-prefix NOFILE
|
||||
; NOFILE: llvm-rc: Error in CURSOR statement (ID 500):
|
||||
; NOFILE-NEXT: Error opening cursor 'this-file-does-not-exist.cur':
|
||||
|
||||
|
||||
; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-nonsense.rc 2>&1 | FileCheck %s --check-prefix NONSENSE
|
||||
|
||||
; NONSENSE: llvm-rc: Error in ICON statement (ID 1):
|
||||
; NONSENSE-NEXT: Incorrect icon/cursor Reserved field; should be 0.
|
||||
|
||||
|
||||
; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-eof.rc 2>&1 | FileCheck %s --check-prefix EOF
|
||||
|
||||
; EOF: llvm-rc: Error in CURSOR statement (ID 72):
|
||||
; EOF-NEXT: Stream Error: The stream is too short to perform the requested operation.
|
||||
|
||||
|
||||
; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-bad-offset.rc 2>&1 | FileCheck %s --check-prefix OFFSET
|
||||
|
||||
; OFFSET: llvm-rc: Error in CURSOR statement (ID 50):
|
||||
; OFFSET-NEXT: Stream Error: The specified offset is invalid for the current stream.
|
||||
|
||||
|
||||
; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-bad-type.rc 2>&1 | FileCheck %s --check-prefix BADTYPE
|
||||
|
||||
; BADTYPE: llvm-rc: Error in ICON statement (ID 100):
|
||||
; BADTYPE-NEXT: Incorrect icon/cursor ResType field; should be 1.
|
@ -220,10 +220,18 @@ Error ResourceFileWriter::visitAcceleratorsResource(const RCResource *Res) {
|
||||
return writeResource(Res, &ResourceFileWriter::writeAcceleratorsBody);
|
||||
}
|
||||
|
||||
Error ResourceFileWriter::visitCursorResource(const RCResource *Res) {
|
||||
return handleError(visitIconOrCursorResource(Res), Res);
|
||||
}
|
||||
|
||||
Error ResourceFileWriter::visitDialogResource(const RCResource *Res) {
|
||||
return writeResource(Res, &ResourceFileWriter::writeDialogBody);
|
||||
}
|
||||
|
||||
Error ResourceFileWriter::visitIconResource(const RCResource *Res) {
|
||||
return handleError(visitIconOrCursorResource(Res), Res);
|
||||
}
|
||||
|
||||
Error ResourceFileWriter::visitCaptionStmt(const CaptionStmt *Stmt) {
|
||||
ObjectData.Caption = Stmt->Value;
|
||||
return Error::success();
|
||||
@ -422,6 +430,260 @@ Error ResourceFileWriter::writeAcceleratorsBody(const RCResource *Base) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// --- CursorResource and IconResource helpers. --- //
|
||||
|
||||
// ICONRESDIR structure. Describes a single icon in resouce group.
|
||||
//
|
||||
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648016.aspx
|
||||
struct IconResDir {
|
||||
uint8_t Width;
|
||||
uint8_t Height;
|
||||
uint8_t ColorCount;
|
||||
uint8_t Reserved;
|
||||
};
|
||||
|
||||
// CURSORDIR structure. Describes a single cursor in resource group.
|
||||
//
|
||||
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648011(v=vs.85).aspx
|
||||
struct CursorDir {
|
||||
ulittle16_t Width;
|
||||
ulittle16_t Height;
|
||||
};
|
||||
|
||||
// RESDIRENTRY structure, stripped from the last item. Stripping made
|
||||
// for compatibility with RESDIR.
|
||||
//
|
||||
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026(v=vs.85).aspx
|
||||
struct ResourceDirEntryStart {
|
||||
union {
|
||||
CursorDir Cursor; // Used in CURSOR resources.
|
||||
IconResDir Icon; // Used in .ico and .cur files, and ICON resources.
|
||||
};
|
||||
ulittle16_t Planes; // HotspotX (.cur files but not CURSOR resource).
|
||||
ulittle16_t BitCount; // HotspotY (.cur files but not CURSOR resource).
|
||||
ulittle32_t Size;
|
||||
// ulittle32_t ImageOffset; // Offset to image data (ICONDIRENTRY only).
|
||||
// ulittle16_t IconID; // Resource icon ID (RESDIR only).
|
||||
};
|
||||
|
||||
// BITMAPINFOHEADER structure. Describes basic information about the bitmap
|
||||
// being read.
|
||||
//
|
||||
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
|
||||
struct BitmapInfoHeader {
|
||||
ulittle32_t Size;
|
||||
ulittle32_t Width;
|
||||
ulittle32_t Height;
|
||||
ulittle16_t Planes;
|
||||
ulittle16_t BitCount;
|
||||
ulittle32_t Compression;
|
||||
ulittle32_t SizeImage;
|
||||
ulittle32_t XPelsPerMeter;
|
||||
ulittle32_t YPelsPerMeter;
|
||||
ulittle32_t ClrUsed;
|
||||
ulittle32_t ClrImportant;
|
||||
};
|
||||
|
||||
// Group icon directory header. Called ICONDIR in .ico/.cur files and
|
||||
// NEWHEADER in .res files.
|
||||
//
|
||||
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648023(v=vs.85).aspx
|
||||
struct GroupIconDir {
|
||||
ulittle16_t Reserved; // Always 0.
|
||||
ulittle16_t ResType; // 1 for icons, 2 for cursors.
|
||||
ulittle16_t ResCount; // Number of items.
|
||||
};
|
||||
|
||||
enum class IconCursorGroupType { Icon, Cursor };
|
||||
|
||||
class SingleIconCursorResource : public RCResource {
|
||||
public:
|
||||
IconCursorGroupType Type;
|
||||
const ResourceDirEntryStart &Header;
|
||||
ArrayRef<uint8_t> Image;
|
||||
|
||||
SingleIconCursorResource(IconCursorGroupType ResourceType,
|
||||
const ResourceDirEntryStart &HeaderEntry,
|
||||
ArrayRef<uint8_t> ImageData)
|
||||
: Type(ResourceType), Header(HeaderEntry), Image(ImageData) {}
|
||||
|
||||
Twine getResourceTypeName() const override { return "Icon/cursor image"; }
|
||||
IntOrString getResourceType() const override {
|
||||
return Type == IconCursorGroupType::Icon ? RkSingleIcon : RkSingleCursor;
|
||||
}
|
||||
uint16_t getMemoryFlags() const override {
|
||||
return MfDiscardable | MfMoveable;
|
||||
}
|
||||
ResourceKind getKind() const override { return RkSingleCursorOrIconRes; }
|
||||
static bool classof(const RCResource *Res) {
|
||||
return Res->getKind() == RkSingleCursorOrIconRes;
|
||||
}
|
||||
};
|
||||
|
||||
class IconCursorGroupResource : public RCResource {
|
||||
public:
|
||||
IconCursorGroupType Type;
|
||||
GroupIconDir Header;
|
||||
std::vector<ResourceDirEntryStart> ItemEntries;
|
||||
|
||||
IconCursorGroupResource(IconCursorGroupType ResourceType,
|
||||
const GroupIconDir &HeaderData,
|
||||
std::vector<ResourceDirEntryStart> &&Entries)
|
||||
: Type(ResourceType), Header(HeaderData),
|
||||
ItemEntries(std::move(Entries)) {}
|
||||
|
||||
Twine getResourceTypeName() const override { return "Icon/cursor group"; }
|
||||
IntOrString getResourceType() const override {
|
||||
return Type == IconCursorGroupType::Icon ? RkIconGroup : RkCursorGroup;
|
||||
}
|
||||
ResourceKind getKind() const override { return RkCursorOrIconGroupRes; }
|
||||
static bool classof(const RCResource *Res) {
|
||||
return Res->getKind() == RkCursorOrIconGroupRes;
|
||||
}
|
||||
};
|
||||
|
||||
Error ResourceFileWriter::writeSingleIconOrCursorBody(const RCResource *Base) {
|
||||
auto *Res = cast<SingleIconCursorResource>(Base);
|
||||
if (Res->Type == IconCursorGroupType::Cursor) {
|
||||
// In case of cursors, two WORDS are appended to the beginning
|
||||
// of the resource: HotspotX (Planes in RESDIRENTRY),
|
||||
// and HotspotY (BitCount).
|
||||
//
|
||||
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026.aspx
|
||||
// (Remarks section).
|
||||
writeObject(Res->Header.Planes);
|
||||
writeObject(Res->Header.BitCount);
|
||||
}
|
||||
|
||||
writeObject(Res->Image);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error ResourceFileWriter::writeIconOrCursorGroupBody(const RCResource *Base) {
|
||||
auto *Res = cast<IconCursorGroupResource>(Base);
|
||||
writeObject(Res->Header);
|
||||
for (auto Item : Res->ItemEntries) {
|
||||
writeObject(Item);
|
||||
writeObject(ulittle16_t(IconCursorID++));
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error ResourceFileWriter::visitSingleIconOrCursor(const RCResource *Res) {
|
||||
return writeResource(Res, &ResourceFileWriter::writeSingleIconOrCursorBody);
|
||||
}
|
||||
|
||||
Error ResourceFileWriter::visitIconOrCursorGroup(const RCResource *Res) {
|
||||
return writeResource(Res, &ResourceFileWriter::writeIconOrCursorGroupBody);
|
||||
}
|
||||
|
||||
Error ResourceFileWriter::visitIconOrCursorResource(const RCResource *Base) {
|
||||
IconCursorGroupType Type;
|
||||
StringRef FileStr;
|
||||
IntOrString ResName = Base->ResName;
|
||||
|
||||
if (auto *IconRes = dyn_cast<IconResource>(Base)) {
|
||||
FileStr = IconRes->IconLoc;
|
||||
Type = IconCursorGroupType::Icon;
|
||||
} else {
|
||||
auto *CursorRes = dyn_cast<CursorResource>(Base);
|
||||
FileStr = CursorRes->CursorLoc;
|
||||
Type = IconCursorGroupType::Cursor;
|
||||
}
|
||||
|
||||
bool IsLong;
|
||||
stripQuotes(FileStr, IsLong);
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> File =
|
||||
MemoryBuffer::getFile(FileStr, -1, false);
|
||||
|
||||
if (!File)
|
||||
return make_error<StringError>(
|
||||
"Error opening " +
|
||||
Twine(Type == IconCursorGroupType::Icon ? "icon" : "cursor") +
|
||||
" '" + FileStr + "': " + File.getError().message(),
|
||||
File.getError());
|
||||
|
||||
BinaryStreamReader Reader((*File)->getBuffer(), support::little);
|
||||
|
||||
// Read the file headers.
|
||||
// - At the beginning, ICONDIR/NEWHEADER header.
|
||||
// - Then, a number of RESDIR headers follow. These contain offsets
|
||||
// to data.
|
||||
const GroupIconDir *Header;
|
||||
|
||||
RETURN_IF_ERROR(Reader.readObject(Header));
|
||||
if (Header->Reserved != 0)
|
||||
return createError("Incorrect icon/cursor Reserved field; should be 0.");
|
||||
uint16_t NeededType = Type == IconCursorGroupType::Icon ? 1 : 2;
|
||||
if (Header->ResType != NeededType)
|
||||
return createError("Incorrect icon/cursor ResType field; should be " +
|
||||
Twine(NeededType) + ".");
|
||||
|
||||
uint16_t NumItems = Header->ResCount;
|
||||
|
||||
// Read single ico/cur headers.
|
||||
std::vector<ResourceDirEntryStart> ItemEntries;
|
||||
ItemEntries.reserve(NumItems);
|
||||
std::vector<uint32_t> ItemOffsets(NumItems);
|
||||
for (size_t ID = 0; ID < NumItems; ++ID) {
|
||||
const ResourceDirEntryStart *Object;
|
||||
RETURN_IF_ERROR(Reader.readObject(Object));
|
||||
ItemEntries.push_back(*Object);
|
||||
RETURN_IF_ERROR(Reader.readInteger(ItemOffsets[ID]));
|
||||
}
|
||||
|
||||
// Now write each icon/cursors one by one. At first, all the contents
|
||||
// without ICO/CUR header. This is described by SingleIconCursorResource.
|
||||
for (size_t ID = 0; ID < NumItems; ++ID) {
|
||||
// Load the fragment of file.
|
||||
Reader.setOffset(ItemOffsets[ID]);
|
||||
ArrayRef<uint8_t> Image;
|
||||
RETURN_IF_ERROR(Reader.readArray(Image, ItemEntries[ID].Size));
|
||||
SingleIconCursorResource SingleRes(Type, ItemEntries[ID], Image);
|
||||
SingleRes.setName(IconCursorID + ID);
|
||||
RETURN_IF_ERROR(visitSingleIconOrCursor(&SingleRes));
|
||||
}
|
||||
|
||||
// Now, write all the headers concatenated into a separate resource.
|
||||
for (size_t ID = 0; ID < NumItems; ++ID) {
|
||||
if (Type == IconCursorGroupType::Icon) {
|
||||
// rc.exe seems to always set NumPlanes to 1. No idea why it happens.
|
||||
ItemEntries[ID].Planes = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We need to rewrite the cursor headers.
|
||||
const auto &OldHeader = ItemEntries[ID];
|
||||
ResourceDirEntryStart NewHeader;
|
||||
NewHeader.Cursor.Width = OldHeader.Icon.Width;
|
||||
// Each cursor in fact stores two bitmaps, one under another.
|
||||
// Height provided in cursor definition describes the height of the
|
||||
// cursor, whereas the value existing in resource definition describes
|
||||
// the height of the bitmap. Therefore, we need to double this height.
|
||||
NewHeader.Cursor.Height = OldHeader.Icon.Height * 2;
|
||||
|
||||
// Now, we actually need to read the bitmap header to find
|
||||
// the number of planes and the number of bits per pixel.
|
||||
Reader.setOffset(ItemOffsets[ID]);
|
||||
const BitmapInfoHeader *BMPHeader;
|
||||
RETURN_IF_ERROR(Reader.readObject(BMPHeader));
|
||||
NewHeader.Planes = BMPHeader->Planes;
|
||||
NewHeader.BitCount = BMPHeader->BitCount;
|
||||
|
||||
// Two WORDs were written at the beginning of the resource (hotspot
|
||||
// location). This is reflected in Size field.
|
||||
NewHeader.Size = OldHeader.Size + 2 * sizeof(uint16_t);
|
||||
|
||||
ItemEntries[ID] = NewHeader;
|
||||
}
|
||||
|
||||
IconCursorGroupResource HeaderRes(Type, *Header, std::move(ItemEntries));
|
||||
HeaderRes.setName(ResName);
|
||||
RETURN_IF_ERROR(visitIconOrCursorGroup(&HeaderRes));
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// --- DialogResource helpers. --- //
|
||||
|
||||
Error ResourceFileWriter::writeSingleDialogControl(const Control &Ctl,
|
||||
|
@ -25,14 +25,16 @@ namespace rc {
|
||||
class ResourceFileWriter : public Visitor {
|
||||
public:
|
||||
ResourceFileWriter(std::unique_ptr<raw_fd_ostream> Stream)
|
||||
: FS(std::move(Stream)) {
|
||||
: FS(std::move(Stream)), IconCursorID(1) {
|
||||
assert(FS && "Output stream needs to be provided to the serializator");
|
||||
}
|
||||
|
||||
Error visitNullResource(const RCResource *) override;
|
||||
Error visitAcceleratorsResource(const RCResource *) override;
|
||||
Error visitCursorResource(const RCResource *) override;
|
||||
Error visitDialogResource(const RCResource *) override;
|
||||
Error visitHTMLResource(const RCResource *) override;
|
||||
Error visitIconResource(const RCResource *) override;
|
||||
Error visitMenuResource(const RCResource *) override;
|
||||
|
||||
Error visitCaptionStmt(const CaptionStmt *) override;
|
||||
@ -76,6 +78,13 @@ private:
|
||||
bool IsLastItem);
|
||||
Error writeAcceleratorsBody(const RCResource *);
|
||||
|
||||
// CursorResource and IconResource
|
||||
Error visitIconOrCursorResource(const RCResource *);
|
||||
Error visitIconOrCursorGroup(const RCResource *);
|
||||
Error visitSingleIconOrCursor(const RCResource *);
|
||||
Error writeSingleIconOrCursorBody(const RCResource *);
|
||||
Error writeIconOrCursorGroupBody(const RCResource *);
|
||||
|
||||
// DialogResource
|
||||
Error writeSingleDialogControl(const Control &, bool IsExtended);
|
||||
Error writeDialogBody(const RCResource *);
|
||||
@ -120,6 +129,10 @@ private:
|
||||
Error appendFile(StringRef Filename);
|
||||
|
||||
void padStream(uint64_t Length);
|
||||
|
||||
// Icon and cursor IDs are allocated starting from 1 and increasing for
|
||||
// each icon/cursor dumped. This maintains the current ID to be allocated.
|
||||
uint16_t IconCursorID;
|
||||
};
|
||||
|
||||
} // namespace rc
|
||||
|
@ -74,9 +74,13 @@ enum ResourceKind {
|
||||
// (TYPE in RESOURCEHEADER structure). The numeric value assigned to each
|
||||
// kind is equal to this type ID.
|
||||
RkNull = 0,
|
||||
RkSingleCursor = 1,
|
||||
RkSingleIcon = 3,
|
||||
RkMenu = 4,
|
||||
RkDialog = 5,
|
||||
RkAccelerators = 9,
|
||||
RkCursorGroup = 12,
|
||||
RkIconGroup = 14,
|
||||
RkVersionInfo = 16,
|
||||
RkHTML = 23,
|
||||
|
||||
@ -88,7 +92,9 @@ enum ResourceKind {
|
||||
RkBase,
|
||||
RkCursor,
|
||||
RkIcon,
|
||||
RkUser
|
||||
RkUser,
|
||||
RkSingleCursorOrIconRes,
|
||||
RkCursorOrIconGroupRes
|
||||
};
|
||||
|
||||
// Non-zero memory flags.
|
||||
@ -255,22 +261,38 @@ public:
|
||||
//
|
||||
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
|
||||
class CursorResource : public RCResource {
|
||||
public:
|
||||
StringRef CursorLoc;
|
||||
|
||||
public:
|
||||
CursorResource(StringRef Location) : CursorLoc(Location) {}
|
||||
raw_ostream &log(raw_ostream &) const override;
|
||||
|
||||
Twine getResourceTypeName() const override { return "CURSOR"; }
|
||||
Error visit(Visitor *V) const override {
|
||||
return V->visitCursorResource(this);
|
||||
}
|
||||
ResourceKind getKind() const override { return RkCursor; }
|
||||
static bool classof(const RCResource *Res) {
|
||||
return Res->getKind() == RkCursor;
|
||||
}
|
||||
};
|
||||
|
||||
// ICON resource. Represents a single ".ico" file containing a group of icons.
|
||||
//
|
||||
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
|
||||
class IconResource : public RCResource {
|
||||
public:
|
||||
StringRef IconLoc;
|
||||
|
||||
public:
|
||||
IconResource(StringRef Location) : IconLoc(Location) {}
|
||||
raw_ostream &log(raw_ostream &) const override;
|
||||
|
||||
Twine getResourceTypeName() const override { return "ICON"; }
|
||||
Error visit(Visitor *V) const override { return V->visitIconResource(this); }
|
||||
ResourceKind getKind() const override { return RkIcon; }
|
||||
static bool classof(const RCResource *Res) {
|
||||
return Res->getKind() == RkIcon;
|
||||
}
|
||||
};
|
||||
|
||||
// HTML resource. Represents a local webpage that is to be embedded into the
|
||||
|
@ -32,8 +32,10 @@ class Visitor {
|
||||
public:
|
||||
virtual Error visitNullResource(const RCResource *) = 0;
|
||||
virtual Error visitAcceleratorsResource(const RCResource *) = 0;
|
||||
virtual Error visitCursorResource(const RCResource *) = 0;
|
||||
virtual Error visitDialogResource(const RCResource *) = 0;
|
||||
virtual Error visitHTMLResource(const RCResource *) = 0;
|
||||
virtual Error visitIconResource(const RCResource *) = 0;
|
||||
virtual Error visitMenuResource(const RCResource *) = 0;
|
||||
|
||||
virtual Error visitCaptionStmt(const CaptionStmt *) = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user