llvm.org GIT mirror llvm / 4c72b95
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@315109 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
11 changed file(s) with 672 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
0 500 CURSOR "this-file-does-not-exist.cur"
0 1 ICON "tag-icon-cursor-nonsense.rc"
0 4464 CURSOR "cursor.cur"
1 4465 CUrsoR "cursor-8.cur"
2 100 ICON "icon-old.ico"
3 4466 cURSOR "cursor-32.cur"
4 100 ICON "icon-new.ico"
5 100 iCon "icon-png.ico"
0 ; This .ico file used to write this test was lost when the author left
1 ; before comitting, and the binary wasn't uploaded to Phabricator. This
2 ; will be fixed as soon as we can recover the file.
3 ; XFAIL: *
4 ; RUN: rm -rf %t
5 ; RUN: mkdir %t
6 ; RUN: cd %t
7 ; RUN: cp %p/Inputs/icon*.ico .
8 ; RUN: cp %p/Inputs/cursor*.cur .
9 ; RUN: cp %p/Inputs/tag-icon-cursor-nonsense.rc .
10
11 ; RUN: llvm-rc /FO %t/tag-icon-cursor.res %p/Inputs/tag-icon-cursor.rc
12 ; RUN: llvm-readobj %t/tag-icon-cursor.res | FileCheck %s
13
14 ; CHECK: Resource type (int): 1
15 ; CHECK-NEXT: Resource name (int): 1
16 ; CHECK-NEXT: Data version: 0
17 ; CHECK-NEXT: Memory flags: 0x1010
18 ; CHECK-NEXT: Language ID: 1033
19 ; CHECK-NEXT: Version (major): 0
20 ; CHECK-NEXT: Version (minor): 0
21 ; CHECK-NEXT: Characteristics: 0
22 ; CHECK-NEXT: Data size: 308
23 ; CHECK-NEXT: Data: (
24 ; CHECK-NEXT: 0000: 0A000B00 28000000 20000000 40000000 |....(... ...@...|
25 ; CHECK-NEXT: 0010: 01000100 00000000 80000000 00000000 |................|
26 ; CHECK-NEXT: 0020: 00000000 02000000 00000000 00000000 |................|
27 ; (...)
28 ; CHECK-DAG: 0110: FFFFFFFF FFFFFFFF FFFFFFFF F3CFFFFF |................|
29 ; CHECK-NEXT: 0120: F3CFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
30 ; CHECK-NEXT: 0130: FFFFFFFF |....|
31 ; CHECK-NEXT: )
32
33 ; CHECK-DAG: Resource type (int): 12
34 ; CHECK-NEXT: Resource name (int): 4464
35 ; CHECK-NEXT: Data version: 0
36 ; CHECK-NEXT: Memory flags: 0x1030
37 ; CHECK-NEXT: Language ID: 1033
38 ; CHECK-NEXT: Version (major): 0
39 ; CHECK-NEXT: Version (minor): 0
40 ; CHECK-NEXT: Characteristics: 0
41 ; CHECK-NEXT: Data size: 20
42 ; CHECK-NEXT: Data: (
43 ; CHECK-NEXT: 0000: 00000200 01002000 40000100 01003401 |...... .@.....4.|
44 ; CHECK-NEXT: 0010: 00000100 |....|
45 ; CHECK-NEXT: )
46
47 ; CHECK-DAG: Resource type (int): 1
48 ; CHECK-NEXT: Resource name (int): 2
49 ; CHECK-NEXT: Data version: 0
50 ; CHECK-NEXT: Memory flags: 0x1010
51 ; CHECK-NEXT: Language ID: 1033
52 ; CHECK-NEXT: Version (major): 0
53 ; CHECK-NEXT: Version (minor): 0
54 ; CHECK-NEXT: Characteristics: 0
55 ; CHECK-NEXT: Data size: 2220
56 ; CHECK-NEXT: Data: (
57 ; CHECK-NEXT: 0000: 01000C00 28000000 20000000 40000000 |....(... ...@...|
58 ; CHECK-NEXT: 0010: 01000800 00000000 00040000 00000000 |................|
59 ; CHECK-NEXT: 0020: 00000000 00010000 00000000 00000000 |................|
60 ; (...)
61 ; CHECK-DAG: 0880: C001FFFF F557FFFF F557FFFF F551FFFF |.....W...W...Q..|
62 ; CHECK-NEXT: 0890: C005FFFF B557FFFF F557FFFF F557FFFF |.....W...W...W..|
63 ; CHECK-NEXT: 08A0: C001FFFF F557FFFF FFFFFFFF |.....W......|
64 ; CHECK-NEXT: )
65
66 ; CHECK-DAG: Resource type (int): 12
67 ; CHECK-NEXT: Resource name (int): 4465
68 ; CHECK-NEXT: Data version: 0
69 ; CHECK-NEXT: Memory flags: 0x1030
70 ; CHECK-NEXT: Language ID: 1033
71 ; CHECK-NEXT: Version (major): 0
72 ; CHECK-NEXT: Version (minor): 0
73 ; CHECK-NEXT: Characteristics: 0
74 ; CHECK-NEXT: Data size: 20
75 ; CHECK-NEXT: Data: (
76 ; CHECK-NEXT: 0000: 00000200 01002000 40000100 0800AC08 |...... .@.......|
77 ; CHECK-NEXT: 0010: 00000200 |....|
78 ; CHECK-NEXT: )
79
80 ; CHECK-DAG: Resource type (int): 3
81 ; CHECK-NEXT: Resource name (int): 3
82 ; CHECK-NEXT: Data version: 0
83 ; CHECK-NEXT: Memory flags: 0x1010
84 ; CHECK-NEXT: Language ID: 1033
85 ; CHECK-NEXT: Version (major): 0
86 ; CHECK-NEXT: Version (minor): 0
87 ; CHECK-NEXT: Characteristics: 0
88 ; CHECK-NEXT: Data size: 1128
89 ; CHECK-NEXT: Data: (
90 ; CHECK-NEXT: 0000: 28000000 10000000 20000000 01002000 |(....... ..... .|
91 ; CHECK-NEXT: 0010: 00000000 00040000 C30E0000 C30E0000 |................|
92 ; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
93 ; (...)
94 ; CHECK-DAG: 0440: 00000000 00000000 00000000 00000000 |................|
95 ; CHECK-NEXT: 0450: 00000000 00000000 00000000 00000000 |................|
96 ; CHECK-NEXT: 0460: 00000000 00000000 |........|
97 ; CHECK-NEXT: )
98
99 ; CHECK-DAG: Resource type (int): 3
100 ; CHECK-NEXT: Resource name (int): 4
101 ; CHECK-NEXT: Data version: 0
102 ; CHECK-NEXT: Memory flags: 0x1010
103 ; CHECK-NEXT: Language ID: 1033
104 ; CHECK-NEXT: Version (major): 0
105 ; CHECK-NEXT: Version (minor): 0
106 ; CHECK-NEXT: Characteristics: 0
107 ; CHECK-NEXT: Data size: 2440
108 ; CHECK-NEXT: Data: (
109 ; CHECK-NEXT: 0000: 28000000 18000000 30000000 01002000 |(.......0..... .|
110 ; CHECK-NEXT: 0010: 00000000 00090000 C30E0000 C30E0000 |................|
111 ; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
112 ; (...)
113 ; CHECK-DAG: 0960: 00000000 00000000 00000000 00000000 |................|
114 ; CHECK-NEXT: 0970: 00000000 00000000 00000000 00000000 |................|
115 ; CHECK-NEXT: 0980: 00000000 00000000 |........|
116 ; CHECK-NEXT: )
117
118 ; CHECK-DAG: Resource type (int): 3
119 ; CHECK-NEXT: Resource name (int): 5
120 ; CHECK-NEXT: Data version: 0
121 ; CHECK-NEXT: Memory flags: 0x1010
122 ; CHECK-NEXT: Language ID: 1033
123 ; CHECK-NEXT: Version (major): 0
124 ; CHECK-NEXT: Version (minor): 0
125 ; CHECK-NEXT: Characteristics: 0
126 ; CHECK-NEXT: Data size: 4264
127 ; CHECK-NEXT: Data: (
128 ; CHECK-NEXT: 0000: 28000000 20000000 40000000 01002000 |(... ...@..... .|
129 ; CHECK-NEXT: 0010: 00000000 00100000 C30E0000 C30E0000 |................|
130 ; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
131 ; (...)
132 ; CHECK-DAG: 1080: 00000000 00000000 00000000 00000000 |................|
133 ; CHECK-NEXT: 1090: 00000000 00000000 00000000 00000000 |................|
134 ; CHECK-NEXT: 10A0: 00000000 00000000 |........|
135 ; CHECK-NEXT: )
136
137 ; CHECK-DAG: Resource type (int): 3
138 ; CHECK-NEXT: Resource name (int): 6
139 ; CHECK-NEXT: Data version: 0
140 ; CHECK-NEXT: Memory flags: 0x1010
141 ; CHECK-NEXT: Language ID: 1033
142 ; CHECK-NEXT: Version (major): 0
143 ; CHECK-NEXT: Version (minor): 0
144 ; CHECK-NEXT: Characteristics: 0
145 ; CHECK-NEXT: Data size: 9640
146 ; CHECK-NEXT: Data: (
147 ; CHECK-NEXT: 0000: 28000000 30000000 60000000 01002000 |(...0...`..... .|
148 ; CHECK-NEXT: 0010: 00000000 00240000 C30E0000 C30E0000 |.....$..........|
149 ; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
150 ; (...)
151 ; CHECK-DAG: 2580: 00000000 00000000 00000000 00000000 |................|
152 ; CHECK-NEXT: 2590: 00000000 00000000 00000000 00000000 |................|
153 ; CHECK-NEXT: 25A0: 00000000 00000000 |........|
154 ; CHECK-NEXT: )
155
156 ; CHECK-DAG: Resource type (int): 14
157 ; CHECK-NEXT: Resource name (int): 100
158 ; CHECK-NEXT: Data version: 0
159 ; CHECK-NEXT: Memory flags: 0x1030
160 ; CHECK-NEXT: Language ID: 1033
161 ; CHECK-NEXT: Version (major): 0
162 ; CHECK-NEXT: Version (minor): 0
163 ; CHECK-NEXT: Characteristics: 0
164 ; CHECK-NEXT: Data size: 62
165 ; CHECK-NEXT: Data: (
166 ; CHECK-NEXT: 0000: 00000100 04001010 00000100 20006804 |............ .h.|
167 ; CHECK-NEXT: 0010: 00000300 18180000 01002000 88090000 |.......... .....|
168 ; CHECK-NEXT: 0020: 04002020 00000100 2000A810 00000500 |.. .... .......|
169 ; CHECK-NEXT: 0030: 30300000 01002000 A8250000 0600 |00.... ..%....|
170 ; CHECK-NEXT: )
171
172 ; CHECK-DAG: Resource type (int): 1
173 ; CHECK-NEXT: Resource name (int): 7
174 ; CHECK-NEXT: Data version: 0
175 ; CHECK-NEXT: Memory flags: 0x1010
176 ; CHECK-NEXT: Language ID: 1033
177 ; CHECK-NEXT: Version (major): 0
178 ; CHECK-NEXT: Version (minor): 0
179 ; CHECK-NEXT: Characteristics: 0
180 ; CHECK-NEXT: Data size: 4268
181 ; CHECK-NEXT: Data: (
182 ; CHECK-NEXT: 0000: 0D000600 28000000 20000000 40000000 |....(... ...@...|
183 ; CHECK-NEXT: 0010: 01002000 00000000 00100000 00000000 |.. .............|
184 ; CHECK-NEXT: 0020: 00000000 00000000 00000000 00000000 |................|
185 ; (...)
186 ; CHECK-DAG: 1080: E027FFFF C3F3FFFF FFFFFFFF FFFFFFFF |.'..............|
187 ; CHECK-NEXT: 1090: FFFFFFFF F3CFFFFF F3CFFFFF FFFFFFFF |................|
188 ; CHECK-NEXT: 10A0: FFFFFFFF FFFFFFFF FFFFFFFF |............|
189 ; CHECK-NEXT: )
190
191 ; CHECK-DAG: Resource type (int): 12
192 ; CHECK-NEXT: Resource name (int): 4466
193 ; CHECK-NEXT: Data version: 0
194 ; CHECK-NEXT: Memory flags: 0x1030
195 ; CHECK-NEXT: Language ID: 1033
196 ; CHECK-NEXT: Version (major): 0
197 ; CHECK-NEXT: Version (minor): 0
198 ; CHECK-NEXT: Characteristics: 0
199 ; CHECK-NEXT: Data size: 20
200 ; CHECK-NEXT: Data: (
201 ; CHECK-NEXT: 0000: 00000200 01002000 40000100 2000AC10 |...... .@... ...|
202 ; CHECK-NEXT: 0010: 00000700 |....|
203 ; CHECK-NEXT: )
204
205 ; CHECK-DAG: Resource type (int): 3
206 ; CHECK-NEXT: Resource name (int): 8
207 ; CHECK-NEXT: Data version: 0
208 ; CHECK-NEXT: Memory flags: 0x1010
209 ; CHECK-NEXT: Language ID: 1033
210 ; CHECK-NEXT: Version (major): 0
211 ; CHECK-NEXT: Version (minor): 0
212 ; CHECK-NEXT: Characteristics: 0
213 ; CHECK-NEXT: Data size: 1128
214 ; CHECK-NEXT: Data: (
215 ; CHECK-NEXT: 0000: 28000000 10000000 20000000 01002000 |(....... ..... .|
216 ; CHECK-NEXT: 0010: 00000000 00040000 C30E0000 C30E0000 |................|
217 ; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
218 ; (...)
219 ; CHECK-DAG: 0440: 00000000 00000000 00000000 00000000 |................|
220 ; CHECK-NEXT: 0450: 00000000 00000000 00000000 00000000 |................|
221 ; CHECK-NEXT: 0460: 00000000 00000000 |........|
222 ; CHECK-NEXT: )
223
224 ; CHECK-DAG: Resource type (int): 3
225 ; CHECK-NEXT: Resource name (int): 9
226 ; CHECK-NEXT: Data version: 0
227 ; CHECK-NEXT: Memory flags: 0x1010
228 ; CHECK-NEXT: Language ID: 1033
229 ; CHECK-NEXT: Version (major): 0
230 ; CHECK-NEXT: Version (minor): 0
231 ; CHECK-NEXT: Characteristics: 0
232 ; CHECK-NEXT: Data size: 2440
233 ; CHECK-NEXT: Data: (
234 ; CHECK-NEXT: 0000: 28000000 18000000 30000000 01002000 |(.......0..... .|
235 ; CHECK-NEXT: 0010: 00000000 00090000 C30E0000 C30E0000 |................|
236 ; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
237 ; (...)
238 ; CHECK-DAG: 0960: 00000000 00000000 00000000 00000000 |................|
239 ; CHECK-NEXT: 0970: 00000000 00000000 00000000 00000000 |................|
240 ; CHECK-NEXT: 0980: 00000000 00000000 |........|
241 ; CHECK-NEXT: )
242
243 ; CHECK-DAG: Resource type (int): 3
244 ; CHECK-NEXT: Resource name (int): 10
245 ; CHECK-NEXT: Data version: 0
246 ; CHECK-NEXT: Memory flags: 0x1010
247 ; CHECK-NEXT: Language ID: 1033
248 ; CHECK-NEXT: Version (major): 0
249 ; CHECK-NEXT: Version (minor): 0
250 ; CHECK-NEXT: Characteristics: 0
251 ; CHECK-NEXT: Data size: 4264
252 ; CHECK-NEXT: Data: (
253 ; CHECK-NEXT: 0000: 28000000 20000000 40000000 01002000 |(... ...@..... .|
254 ; CHECK-NEXT: 0010: 00000000 00100000 C30E0000 C30E0000 |................|
255 ; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
256 ; (...)
257 ; CHECK-DAG: 1080: 00000000 00000000 00000000 00000000 |................|
258 ; CHECK-NEXT: 1090: 00000000 00000000 00000000 00000000 |................|
259 ; CHECK-NEXT: 10A0: 00000000 00000000 |........|
260 ; CHECK-NEXT: )
261
262 ; CHECK-DAG: Resource type (int): 3
263 ; CHECK-NEXT: Resource name (int): 11
264 ; CHECK-NEXT: Data version: 0
265 ; CHECK-NEXT: Memory flags: 0x1010
266 ; CHECK-NEXT: Language ID: 1033
267 ; CHECK-NEXT: Version (major): 0
268 ; CHECK-NEXT: Version (minor): 0
269 ; CHECK-NEXT: Characteristics: 0
270 ; CHECK-NEXT: Data size: 9640
271 ; CHECK-NEXT: Data: (
272 ; CHECK-NEXT: 0000: 28000000 30000000 60000000 01002000 |(...0...`..... .|
273 ; CHECK-NEXT: 0010: 00000000 00240000 C30E0000 C30E0000 |.....$..........|
274 ; CHECK-NEXT: 0020: 00000000 00000000 FFFFFFFF FFFFFFFF |................|
275 ; (...)
276 ; CHECK-DAG: 2580: 00000000 00000000 00000000 00000000 |................|
277 ; CHECK-NEXT: 2590: 00000000 00000000 00000000 00000000 |................|
278 ; CHECK-NEXT: 25A0: 00000000 00000000 |........|
279 ; CHECK-NEXT: )
280
281 ; CHECK-DAG: Resource type (int): 14
282 ; CHECK-NEXT: Resource name (int): 100
283 ; CHECK-NEXT: Data version: 0
284 ; CHECK-NEXT: Memory flags: 0x1030
285 ; CHECK-NEXT: Language ID: 1033
286 ; CHECK-NEXT: Version (major): 0
287 ; CHECK-NEXT: Version (minor): 0
288 ; CHECK-NEXT: Characteristics: 0
289 ; CHECK-NEXT: Data size: 62
290 ; CHECK-NEXT: Data: (
291 ; CHECK-NEXT: 0000: 00000100 04001010 00000100 20006804 |............ .h.|
292 ; CHECK-NEXT: 0010: 00000800 18180000 01002000 88090000 |.......... .....|
293 ; CHECK-NEXT: 0020: 09002020 00000100 2000A810 00000A00 |.. .... .......|
294 ; CHECK-NEXT: 0030: 30300000 01002000 A8250000 0B00 |00.... ..%....|
295 ; CHECK-NEXT: )
296
297 ; CHECK-DAG: Resource type (int): 3
298 ; CHECK-NEXT: Resource name (int): 12
299 ; CHECK-NEXT: Data version: 0
300 ; CHECK-NEXT: Memory flags: 0x1010
301 ; CHECK-NEXT: Language ID: 1033
302 ; CHECK-NEXT: Version (major): 0
303 ; CHECK-NEXT: Version (minor): 0
304 ; CHECK-NEXT: Characteristics: 0
305 ; CHECK-NEXT: Data size: 82
306 ; CHECK-NEXT: Data: (
307 ; CHECK-NEXT: 0000: 89504E47 0D0A1A0A 0000000D 49484452 |.PNG........IHDR|
308 ; CHECK-NEXT: 0010: 00000010 00000010 08060000 001FF3FF |................|
309 ; CHECK-NEXT: 0020: 61000000 19494441 5438CB63 FC0F040C |a....IDAT8.c....|
310 ; CHECK-NEXT: 0030: 1400C651 03460D18 3560B818 0000251F |...Q.F..5`....%.|
311 ; CHECK-NEXT: 0040: 3FD1D6DC 546E0000 00004945 4E44AE42 |?...Tn....IEND.B|
312 ; CHECK-NEXT: 0050: 6082 |`.|
313 ; CHECK-NEXT: )
314
315 ; CHECK-DAG: Resource type (int): 14
316 ; CHECK-NEXT: Resource name (int): 100
317 ; CHECK-NEXT: Data version: 0
318 ; CHECK-NEXT: Memory flags: 0x1030
319 ; CHECK-NEXT: Language ID: 1033
320 ; CHECK-NEXT: Version (major): 0
321 ; CHECK-NEXT: Version (minor): 0
322 ; CHECK-NEXT: Characteristics: 0
323 ; CHECK-NEXT: Data size: 20
324 ; CHECK-NEXT: Data: (
325 ; CHECK-NEXT: 0000: 00000100 01001010 00000100 20005200 |............ .R.|
326 ; CHECK-NEXT: 0010: 00000C00 |....|
327 ; CHECK-NEXT: )
328
329
330 ; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-nonexistent.rc 2>&1 | FileCheck %s --check-prefix NOFILE
331 ; NOFILE: llvm-rc: Error in CURSOR statement (ID 500):
332 ; NOFILE-NEXT: Error opening cursor 'this-file-does-not-exist.cur':
333
334
335 ; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-nonsense.rc 2>&1 | FileCheck %s --check-prefix NONSENSE
336
337 ; NONSENSE: llvm-rc: Error in ICON statement (ID 1):
338 ; NONSENSE-NEXT: Incorrect icon/cursor Reserved field; should be 0.
339
340
341 ; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-eof.rc 2>&1 | FileCheck %s --check-prefix EOF
342
343 ; EOF: llvm-rc: Error in CURSOR statement (ID 72):
344 ; EOF-NEXT: Stream Error: The stream is too short to perform the requested operation.
345
346
347 ; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-bad-offset.rc 2>&1 | FileCheck %s --check-prefix OFFSET
348
349 ; OFFSET: llvm-rc: Error in CURSOR statement (ID 50):
350 ; OFFSET-NEXT: Stream Error: The specified offset is invalid for the current stream.
351
352
353 ; RUN: not llvm-rc /FO %t/1 %p/Inputs/tag-icon-cursor-bad-type.rc 2>&1 | FileCheck %s --check-prefix BADTYPE
354
355 ; BADTYPE: llvm-rc: Error in ICON statement (ID 100):
356 ; BADTYPE-NEXT: Incorrect icon/cursor ResType field; should be 1.
219219 return writeResource(Res, &ResourceFileWriter::writeAcceleratorsBody);
220220 }
221221
222 Error ResourceFileWriter::visitCursorResource(const RCResource *Res) {
223 return handleError(visitIconOrCursorResource(Res), Res);
224 }
225
222226 Error ResourceFileWriter::visitDialogResource(const RCResource *Res) {
223227 return writeResource(Res, &ResourceFileWriter::writeDialogBody);
228 }
229
230 Error ResourceFileWriter::visitIconResource(const RCResource *Res) {
231 return handleError(visitIconOrCursorResource(Res), Res);
224232 }
225233
226234 Error ResourceFileWriter::visitCaptionStmt(const CaptionStmt *Stmt) {
418426 RETURN_IF_ERROR(
419427 writeSingleAccelerator(Acc, AcceleratorId == Res->Accelerators.size()));
420428 }
429 return Error::success();
430 }
431
432 // --- CursorResource and IconResource helpers. --- //
433
434 // ICONRESDIR structure. Describes a single icon in resouce group.
435 //
436 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648016.aspx
437 struct IconResDir {
438 uint8_t Width;
439 uint8_t Height;
440 uint8_t ColorCount;
441 uint8_t Reserved;
442 };
443
444 // CURSORDIR structure. Describes a single cursor in resource group.
445 //
446 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648011(v=vs.85).aspx
447 struct CursorDir {
448 ulittle16_t Width;
449 ulittle16_t Height;
450 };
451
452 // RESDIRENTRY structure, stripped from the last item. Stripping made
453 // for compatibility with RESDIR.
454 //
455 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026(v=vs.85).aspx
456 struct ResourceDirEntryStart {
457 union {
458 CursorDir Cursor; // Used in CURSOR resources.
459 IconResDir Icon; // Used in .ico and .cur files, and ICON resources.
460 };
461 ulittle16_t Planes; // HotspotX (.cur files but not CURSOR resource).
462 ulittle16_t BitCount; // HotspotY (.cur files but not CURSOR resource).
463 ulittle32_t Size;
464 // ulittle32_t ImageOffset; // Offset to image data (ICONDIRENTRY only).
465 // ulittle16_t IconID; // Resource icon ID (RESDIR only).
466 };
467
468 // BITMAPINFOHEADER structure. Describes basic information about the bitmap
469 // being read.
470 //
471 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
472 struct BitmapInfoHeader {
473 ulittle32_t Size;
474 ulittle32_t Width;
475 ulittle32_t Height;
476 ulittle16_t Planes;
477 ulittle16_t BitCount;
478 ulittle32_t Compression;
479 ulittle32_t SizeImage;
480 ulittle32_t XPelsPerMeter;
481 ulittle32_t YPelsPerMeter;
482 ulittle32_t ClrUsed;
483 ulittle32_t ClrImportant;
484 };
485
486 // Group icon directory header. Called ICONDIR in .ico/.cur files and
487 // NEWHEADER in .res files.
488 //
489 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648023(v=vs.85).aspx
490 struct GroupIconDir {
491 ulittle16_t Reserved; // Always 0.
492 ulittle16_t ResType; // 1 for icons, 2 for cursors.
493 ulittle16_t ResCount; // Number of items.
494 };
495
496 enum class IconCursorGroupType { Icon, Cursor };
497
498 class SingleIconCursorResource : public RCResource {
499 public:
500 IconCursorGroupType Type;
501 const ResourceDirEntryStart &Header;
502 ArrayRef Image;
503
504 SingleIconCursorResource(IconCursorGroupType ResourceType,
505 const ResourceDirEntryStart &HeaderEntry,
506 ArrayRef ImageData)
507 : Type(ResourceType), Header(HeaderEntry), Image(ImageData) {}
508
509 Twine getResourceTypeName() const override { return "Icon/cursor image"; }
510 IntOrString getResourceType() const override {
511 return Type == IconCursorGroupType::Icon ? RkSingleIcon : RkSingleCursor;
512 }
513 uint16_t getMemoryFlags() const override {
514 return MfDiscardable | MfMoveable;
515 }
516 ResourceKind getKind() const override { return RkSingleCursorOrIconRes; }
517 static bool classof(const RCResource *Res) {
518 return Res->getKind() == RkSingleCursorOrIconRes;
519 }
520 };
521
522 class IconCursorGroupResource : public RCResource {
523 public:
524 IconCursorGroupType Type;
525 GroupIconDir Header;
526 std::vector ItemEntries;
527
528 IconCursorGroupResource(IconCursorGroupType ResourceType,
529 const GroupIconDir &HeaderData,
530 std::vector &&Entries)
531 : Type(ResourceType), Header(HeaderData),
532 ItemEntries(std::move(Entries)) {}
533
534 Twine getResourceTypeName() const override { return "Icon/cursor group"; }
535 IntOrString getResourceType() const override {
536 return Type == IconCursorGroupType::Icon ? RkIconGroup : RkCursorGroup;
537 }
538 ResourceKind getKind() const override { return RkCursorOrIconGroupRes; }
539 static bool classof(const RCResource *Res) {
540 return Res->getKind() == RkCursorOrIconGroupRes;
541 }
542 };
543
544 Error ResourceFileWriter::writeSingleIconOrCursorBody(const RCResource *Base) {
545 auto *Res = cast(Base);
546 if (Res->Type == IconCursorGroupType::Cursor) {
547 // In case of cursors, two WORDS are appended to the beginning
548 // of the resource: HotspotX (Planes in RESDIRENTRY),
549 // and HotspotY (BitCount).
550 //
551 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026.aspx
552 // (Remarks section).
553 writeObject(Res->Header.Planes);
554 writeObject(Res->Header.BitCount);
555 }
556
557 writeObject(Res->Image);
558 return Error::success();
559 }
560
561 Error ResourceFileWriter::writeIconOrCursorGroupBody(const RCResource *Base) {
562 auto *Res = cast(Base);
563 writeObject(Res->Header);
564 for (auto Item : Res->ItemEntries) {
565 writeObject(Item);
566 writeObject(ulittle16_t(IconCursorID++));
567 }
568 return Error::success();
569 }
570
571 Error ResourceFileWriter::visitSingleIconOrCursor(const RCResource *Res) {
572 return writeResource(Res, &ResourceFileWriter::writeSingleIconOrCursorBody);
573 }
574
575 Error ResourceFileWriter::visitIconOrCursorGroup(const RCResource *Res) {
576 return writeResource(Res, &ResourceFileWriter::writeIconOrCursorGroupBody);
577 }
578
579 Error ResourceFileWriter::visitIconOrCursorResource(const RCResource *Base) {
580 IconCursorGroupType Type;
581 StringRef FileStr;
582 IntOrString ResName = Base->ResName;
583
584 if (auto *IconRes = dyn_cast(Base)) {
585 FileStr = IconRes->IconLoc;
586 Type = IconCursorGroupType::Icon;
587 } else {
588 auto *CursorRes = dyn_cast(Base);
589 FileStr = CursorRes->CursorLoc;
590 Type = IconCursorGroupType::Cursor;
591 }
592
593 bool IsLong;
594 stripQuotes(FileStr, IsLong);
595 ErrorOr> File =
596 MemoryBuffer::getFile(FileStr, -1, false);
597
598 if (!File)
599 return make_error(
600 "Error opening " +
601 Twine(Type == IconCursorGroupType::Icon ? "icon" : "cursor") +
602 " '" + FileStr + "': " + File.getError().message(),
603 File.getError());
604
605 BinaryStreamReader Reader((*File)->getBuffer(), support::little);
606
607 // Read the file headers.
608 // - At the beginning, ICONDIR/NEWHEADER header.
609 // - Then, a number of RESDIR headers follow. These contain offsets
610 // to data.
611 const GroupIconDir *Header;
612
613 RETURN_IF_ERROR(Reader.readObject(Header));
614 if (Header->Reserved != 0)
615 return createError("Incorrect icon/cursor Reserved field; should be 0.");
616 uint16_t NeededType = Type == IconCursorGroupType::Icon ? 1 : 2;
617 if (Header->ResType != NeededType)
618 return createError("Incorrect icon/cursor ResType field; should be " +
619 Twine(NeededType) + ".");
620
621 uint16_t NumItems = Header->ResCount;
622
623 // Read single ico/cur headers.
624 std::vector ItemEntries;
625 ItemEntries.reserve(NumItems);
626 std::vector ItemOffsets(NumItems);
627 for (size_t ID = 0; ID < NumItems; ++ID) {
628 const ResourceDirEntryStart *Object;
629 RETURN_IF_ERROR(Reader.readObject(Object));
630 ItemEntries.push_back(*Object);
631 RETURN_IF_ERROR(Reader.readInteger(ItemOffsets[ID]));
632 }
633
634 // Now write each icon/cursors one by one. At first, all the contents
635 // without ICO/CUR header. This is described by SingleIconCursorResource.
636 for (size_t ID = 0; ID < NumItems; ++ID) {
637 // Load the fragment of file.
638 Reader.setOffset(ItemOffsets[ID]);
639 ArrayRef Image;
640 RETURN_IF_ERROR(Reader.readArray(Image, ItemEntries[ID].Size));
641 SingleIconCursorResource SingleRes(Type, ItemEntries[ID], Image);
642 SingleRes.setName(IconCursorID + ID);
643 RETURN_IF_ERROR(visitSingleIconOrCursor(&SingleRes));
644 }
645
646 // Now, write all the headers concatenated into a separate resource.
647 for (size_t ID = 0; ID < NumItems; ++ID) {
648 if (Type == IconCursorGroupType::Icon) {
649 // rc.exe seems to always set NumPlanes to 1. No idea why it happens.
650 ItemEntries[ID].Planes = 1;
651 continue;
652 }
653
654 // We need to rewrite the cursor headers.
655 const auto &OldHeader = ItemEntries[ID];
656 ResourceDirEntryStart NewHeader;
657 NewHeader.Cursor.Width = OldHeader.Icon.Width;
658 // Each cursor in fact stores two bitmaps, one under another.
659 // Height provided in cursor definition describes the height of the
660 // cursor, whereas the value existing in resource definition describes
661 // the height of the bitmap. Therefore, we need to double this height.
662 NewHeader.Cursor.Height = OldHeader.Icon.Height * 2;
663
664 // Now, we actually need to read the bitmap header to find
665 // the number of planes and the number of bits per pixel.
666 Reader.setOffset(ItemOffsets[ID]);
667 const BitmapInfoHeader *BMPHeader;
668 RETURN_IF_ERROR(Reader.readObject(BMPHeader));
669 NewHeader.Planes = BMPHeader->Planes;
670 NewHeader.BitCount = BMPHeader->BitCount;
671
672 // Two WORDs were written at the beginning of the resource (hotspot
673 // location). This is reflected in Size field.
674 NewHeader.Size = OldHeader.Size + 2 * sizeof(uint16_t);
675
676 ItemEntries[ID] = NewHeader;
677 }
678
679 IconCursorGroupResource HeaderRes(Type, *Header, std::move(ItemEntries));
680 HeaderRes.setName(ResName);
681 RETURN_IF_ERROR(visitIconOrCursorGroup(&HeaderRes));
682
421683 return Error::success();
422684 }
423685
2424 class ResourceFileWriter : public Visitor {
2525 public:
2626 ResourceFileWriter(std::unique_ptr Stream)
27 : FS(std::move(Stream)) {
27 : FS(std::move(Stream)), IconCursorID(1) {
2828 assert(FS && "Output stream needs to be provided to the serializator");
2929 }
3030
3131 Error visitNullResource(const RCResource *) override;
3232 Error visitAcceleratorsResource(const RCResource *) override;
33 Error visitCursorResource(const RCResource *) override;
3334 Error visitDialogResource(const RCResource *) override;
3435 Error visitHTMLResource(const RCResource *) override;
36 Error visitIconResource(const RCResource *) override;
3537 Error visitMenuResource(const RCResource *) override;
3638
3739 Error visitCaptionStmt(const CaptionStmt *) override;
7476 Error writeSingleAccelerator(const AcceleratorsResource::Accelerator &,
7577 bool IsLastItem);
7678 Error writeAcceleratorsBody(const RCResource *);
79
80 // CursorResource and IconResource
81 Error visitIconOrCursorResource(const RCResource *);
82 Error visitIconOrCursorGroup(const RCResource *);
83 Error visitSingleIconOrCursor(const RCResource *);
84 Error writeSingleIconOrCursorBody(const RCResource *);
85 Error writeIconOrCursorGroupBody(const RCResource *);
7786
7887 // DialogResource
7988 Error writeSingleDialogControl(const Control &, bool IsExtended);
119128 Error appendFile(StringRef Filename);
120129
121130 void padStream(uint64_t Length);
131
132 // Icon and cursor IDs are allocated starting from 1 and increasing for
133 // each icon/cursor dumped. This maintains the current ID to be allocated.
134 uint16_t IconCursorID;
122135 };
123136
124137 } // namespace rc
7373 // (TYPE in RESOURCEHEADER structure). The numeric value assigned to each
7474 // kind is equal to this type ID.
7575 RkNull = 0,
76 RkSingleCursor = 1,
77 RkSingleIcon = 3,
7678 RkMenu = 4,
7779 RkDialog = 5,
7880 RkAccelerators = 9,
81 RkCursorGroup = 12,
82 RkIconGroup = 14,
7983 RkVersionInfo = 16,
8084 RkHTML = 23,
8185
8791 RkBase,
8892 RkCursor,
8993 RkIcon,
90 RkUser
94 RkUser,
95 RkSingleCursorOrIconRes,
96 RkCursorOrIconGroupRes
9197 };
9298
9399 // Non-zero memory flags.
254260 //
255261 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
256262 class CursorResource : public RCResource {
263 public:
257264 StringRef CursorLoc;
258265
259 public:
260266 CursorResource(StringRef Location) : CursorLoc(Location) {}
261267 raw_ostream &log(raw_ostream &) const override;
268
269 Twine getResourceTypeName() const override { return "CURSOR"; }
270 Error visit(Visitor *V) const override {
271 return V->visitCursorResource(this);
272 }
273 ResourceKind getKind() const override { return RkCursor; }
274 static bool classof(const RCResource *Res) {
275 return Res->getKind() == RkCursor;
276 }
262277 };
263278
264279 // ICON resource. Represents a single ".ico" file containing a group of icons.
265280 //
266281 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
267282 class IconResource : public RCResource {
283 public:
268284 StringRef IconLoc;
269285
270 public:
271286 IconResource(StringRef Location) : IconLoc(Location) {}
272287 raw_ostream &log(raw_ostream &) const override;
288
289 Twine getResourceTypeName() const override { return "ICON"; }
290 Error visit(Visitor *V) const override { return V->visitIconResource(this); }
291 ResourceKind getKind() const override { return RkIcon; }
292 static bool classof(const RCResource *Res) {
293 return Res->getKind() == RkIcon;
294 }
273295 };
274296
275297 // HTML resource. Represents a local webpage that is to be embedded into the
3131 public:
3232 virtual Error visitNullResource(const RCResource *) = 0;
3333 virtual Error visitAcceleratorsResource(const RCResource *) = 0;
34 virtual Error visitCursorResource(const RCResource *) = 0;
3435 virtual Error visitDialogResource(const RCResource *) = 0;
3536 virtual Error visitHTMLResource(const RCResource *) = 0;
37 virtual Error visitIconResource(const RCResource *) = 0;
3638 virtual Error visitMenuResource(const RCResource *) = 0;
3739
3840 virtual Error visitCaptionStmt(const CaptionStmt *) = 0;