llvm.org GIT mirror llvm / b121e77
[llvm-rc] Serialize ACCELERATORS to .res files (serialization, pt 2). This allows llvm-rc to serialize ACCELERATORS resources. Additionally, as this is the first type of resource to support basic optional resource statements (LANGUAGE, CHARACTERISTICS, VERSION), ACCELERATORS statement documentation: msdn.microsoft.com/en-us/library/windows/desktop/aa380610.aspx Accelerator table structure documentation: msdn.microsoft.com/en-us/library/windows/desktop/ms648010.aspx Optional resource statement fields are described in: msdn.microsoft.com/en-us/library/windows/desktop/ms648027.aspx Thanks for Nico Weber for his original work in this area. Differential Revision: https://reviews.llvm.org/D37824 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@314549 91177308-0d34-0410-b5e6-96231b3b80d8 Marek Sokolowski 2 years ago
20 changed file(s) with 531 addition(s) and 11 deletion(s). Raw diff Collapse all Expand all
0 2 ACCELERATORS {
1 "A", 15, ASCII, ALT
2 }
3
0 2 ACCELERATORS {
1 "A", 15, ASCII, CONTROL
2 }
3
0 2 ACCELERATORS {
1 "A", 15, ASCII, SHIFT
2 }
3
0 2 ACCELERATORS {
1 "A", 15, ASCII, VIRTKEY
2 }
3
0 1 ACCELERATORS {
1 "A", 1234567, VIRTKEY
2 }
3
0 9 ACCELERATORS {
1 1234567, 0, VIRTKEY
2 }
0 100 ACCELERATORS {
1 "^X", 10, VIRTKEY
2 }
3
0 50 ACCELERATORS {
1 "XY", 1, ASCII
2 }
3
0 12 ACCELERATORS {
1 "Hello", 5, ASCII
2 }
3
0 10 ACCELERATORS {
1 "", 12, VIRTKEY
2 }
3
0 1 ACCELERATORS
1 VERSION 700
2 LANGUAGE 5, 1
3 {
4 "a", 3
5 "a", 4, ASCII
6 "a", 5, VIRTKEY
7 "A", 6
8 "A", 7, ASCII
9 "A", 8, VIRTKEY
10 "1", 9
11 "1", 10, ASCII
12 "1", 11, VIRTKEY
13 "$", 12
14 "$", 13, ASCII
15 "]", 15
16 "]", 16, ASCII
17 "^a", 18
18 "^a", 19, ASCII
19 0, 37, ASCII
20 0, 38, VIRTKEY
21 1, 40, ASCII
22 1, 41, VIRTKEY
23 127, 43, ASCII
24 127, 44, VIRTKEY
25 128, 46, ASCII
26 128, 47, VIRTKEY
27 255, 49, ASCII
28 255, 50, VIRTKEY
29 256, 52, ASCII
30 256, 53, VIRTKEY
31 "^A", 66
32 "^A", 67, ASCII
33 54321, 70, ASCII
34 54321, 71, VIRTKEY
35 }
36
37 2 ACCELERATORS {
38 42, 0, ASCII
39 42, 1, VIRTKEY
40 42, 2, ASCII, NOINVERT
41 42, 3, VIRTKEY, NOINVERT
42 42, 4, VIRTKEY, CONTROL
43 42, 5, VIRTKEY, SHIFT
44 42, 6, VIRTKEY, ALT
45 42, 7, VIRTKEY, NOINVERT, CONTROL
46 42, 8, VIRTKEY, NOINVERT, SHIFT
47 42, 9, VIRTKEY, NOINVERT, ALT
48 42, 10, VIRTKEY, CONTROL, SHIFT
49 42, 11, VIRTKEY, CONTROL, ALT
50 42, 12, VIRTKEY, SHIFT, ALT
51 42, 13, VIRTKEY, NOINVERT, CONTROL, SHIFT
52 42, 14, VIRTKEY, NOINVERT, CONTROL, ALT
53 42, 15, VIRTKEY, NOINVERT, SHIFT, ALT
54 42, 16, VIRTKEY, CONTROL, SHIFT, ALT
55 42, 17, VIRTKEY, NOINVERT, CONTROL, SHIFT, ALT
56 "f", 18, ASCII
57 "f", 19, VIRTKEY
58 "f", 20, ASCII, NOINVERT
59 "f", 21, VIRTKEY, NOINVERT
60 "f", 22, VIRTKEY, CONTROL
61 "f", 23, VIRTKEY, SHIFT
62 "f", 24, VIRTKEY, ALT
63 "f", 25, VIRTKEY, NOINVERT, CONTROL
64 "f", 26, VIRTKEY, NOINVERT, SHIFT
65 "f", 27, VIRTKEY, NOINVERT, ALT
66 "f", 28, VIRTKEY, CONTROL, SHIFT
67 "f", 29, VIRTKEY, CONTROL, ALT
68 "f", 30, VIRTKEY, SHIFT, ALT
69 "f", 31, VIRTKEY, NOINVERT, CONTROL, SHIFT
70 "f", 32, VIRTKEY, NOINVERT, CONTROL, ALT
71 "f", 33, VIRTKEY, NOINVERT, SHIFT, ALT
72 "f", 34, VIRTKEY, CONTROL, SHIFT, ALT
73 "f", 35, VIRTKEY, NOINVERT, CONTROL, SHIFT, ALT
74 "U", 36, ASCII
75 "U", 37, VIRTKEY
76 "U", 38, ASCII, NOINVERT
77 "U", 39, VIRTKEY, NOINVERT
78 "U", 40, VIRTKEY, CONTROL
79 "U", 41, VIRTKEY, SHIFT
80 "U", 42, VIRTKEY, ALT
81 "U", 43, VIRTKEY, NOINVERT, CONTROL
82 "U", 44, VIRTKEY, NOINVERT, SHIFT
83 "U", 45, VIRTKEY, NOINVERT, ALT
84 "U", 46, VIRTKEY, CONTROL, SHIFT
85 "U", 47, VIRTKEY, CONTROL, ALT
86 "U", 48, VIRTKEY, SHIFT, ALT
87 "U", 49, VIRTKEY, NOINVERT, CONTROL, SHIFT
88 "U", 50, VIRTKEY, NOINVERT, CONTROL, ALT
89 "U", 51, VIRTKEY, NOINVERT, SHIFT, ALT
90 "U", 52, VIRTKEY, CONTROL, SHIFT, ALT
91 "U", 53, VIRTKEY, NOINVERT, CONTROL, SHIFT, ALT
92 "7", 54, ASCII
93 "7", 55, VIRTKEY
94 "7", 56, ASCII, NOINVERT
95 "7", 57, VIRTKEY, NOINVERT
96 "7", 58, VIRTKEY, CONTROL
97 "7", 59, VIRTKEY, SHIFT
98 "7", 60, VIRTKEY, ALT
99 "7", 61, VIRTKEY, NOINVERT, CONTROL
100 "7", 62, VIRTKEY, NOINVERT, SHIFT
101 "7", 63, VIRTKEY, NOINVERT, ALT
102 "7", 64, VIRTKEY, CONTROL, SHIFT
103 "7", 65, VIRTKEY, CONTROL, ALT
104 "7", 66, VIRTKEY, SHIFT, ALT
105 "7", 67, VIRTKEY, NOINVERT, CONTROL, SHIFT
106 "7", 68, VIRTKEY, NOINVERT, CONTROL, ALT
107 "7", 69, VIRTKEY, NOINVERT, SHIFT, ALT
108 "7", 70, VIRTKEY, CONTROL, SHIFT, ALT
109 "7", 71, VIRTKEY, NOINVERT, CONTROL, SHIFT, ALT
110 "^j", 72, ASCII
111 "^j", 73, ASCII, NOINVERT
112 }
113
0 ; RUN: llvm-rc /FO %t %p/Inputs/tag-accelerators.rc
1 ; RUN: llvm-readobj %t | FileCheck %s --check-prefix=ACCELERATORS
2
3 ; ACCELERATORS: Resource type (int): 9
4 ; ACCELERATORS-NEXT: Resource name (int): 1
5 ; ACCELERATORS-NEXT: Data version: 0
6 ; ACCELERATORS-NEXT: Memory flags: 0x30
7 ; ACCELERATORS-NEXT: Language ID: 1029
8 ; ACCELERATORS-NEXT: Version (major): 0
9 ; ACCELERATORS-NEXT: Version (minor): 700
10 ; ACCELERATORS-NEXT: Characteristics: 0
11 ; ACCELERATORS-NEXT: Data size: 248
12 ; ACCELERATORS-NEXT: Data: (
13 ; ACCELERATORS-NEXT: 0000: 00006100 03000000 00006100 04000000 |..a.......a.....|
14 ; ACCELERATORS-NEXT: 0010: 01004100 05000000 00004100 06000000 |..A.......A.....|
15 ; ACCELERATORS-NEXT: 0020: 00004100 07000000 01004100 08000000 |..A.......A.....|
16 ; ACCELERATORS-NEXT: 0030: 00003100 09000000 00003100 0A000000 |..1.......1.....|
17 ; ACCELERATORS-NEXT: 0040: 01003100 0B000000 00002400 0C000000 |..1.......$.....|
18 ; ACCELERATORS-NEXT: 0050: 00002400 0D000000 00005D00 0F000000 |..$.......].....|
19 ; ACCELERATORS-NEXT: 0060: 00005D00 10000000 00000100 12000000 |..].............|
20 ; ACCELERATORS-NEXT: 0070: 00000100 13000000 00000000 25000000 |............%...|
21 ; ACCELERATORS-NEXT: 0080: 01000000 26000000 00000100 28000000 |....&.......(...|
22 ; ACCELERATORS-NEXT: 0090: 01000100 29000000 00007F00 2B000000 |....).......+...|
23 ; ACCELERATORS-NEXT: 00A0: 01007F00 2C000000 00008000 2E000000 |....,...........|
24 ; ACCELERATORS-NEXT: 00B0: 01008000 2F000000 0000FF00 31000000 |..../.......1...|
25 ; ACCELERATORS-NEXT: 00C0: 0100FF00 32000000 00000001 34000000 |....2.......4...|
26 ; ACCELERATORS-NEXT: 00D0: 01000001 35000000 00000100 42000000 |....5.......B...|
27 ; ACCELERATORS-NEXT: 00E0: 00000100 43000000 000031D4 46000000 |....C.....1.F...|
28 ; ACCELERATORS-NEXT: 00F0: 810031D4 47000000 |..1.G...|
29 ; ACCELERATORS-NEXT: )
30
31 ; ACCELERATORS-DAG: Resource type (int): 9
32 ; ACCELERATORS-NEXT: Resource name (int): 2
33 ; ACCELERATORS-NEXT: Data version: 0
34 ; ACCELERATORS-NEXT: Memory flags: 0x30
35 ; ACCELERATORS-NEXT: Language ID: 1033
36 ; ACCELERATORS-NEXT: Version (major): 0
37 ; ACCELERATORS-NEXT: Version (minor): 0
38 ; ACCELERATORS-NEXT: Characteristics: 0
39 ; ACCELERATORS-NEXT: Data size: 592
40 ; ACCELERATORS-NEXT: Data: (
41 ; ACCELERATORS-NEXT: 0000: 00002A00 00000000 01002A00 01000000 |..*.......*.....|
42 ; ACCELERATORS-NEXT: 0010: 02002A00 02000000 03002A00 03000000 |..*.......*.....|
43 ; ACCELERATORS-NEXT: 0020: 09002A00 04000000 05002A00 05000000 |..*.......*.....|
44 ; ACCELERATORS-NEXT: 0030: 11002A00 06000000 0B002A00 07000000 |..*.......*.....|
45 ; ACCELERATORS-NEXT: 0040: 07002A00 08000000 13002A00 09000000 |..*.......*.....|
46 ; ACCELERATORS-NEXT: 0050: 0D002A00 0A000000 19002A00 0B000000 |..*.......*.....|
47 ; ACCELERATORS-NEXT: 0060: 15002A00 0C000000 0F002A00 0D000000 |..*.......*.....|
48 ; ACCELERATORS-NEXT: 0070: 1B002A00 0E000000 17002A00 0F000000 |..*.......*.....|
49 ; ACCELERATORS-NEXT: 0080: 1D002A00 10000000 1F002A00 11000000 |..*.......*.....|
50 ; ACCELERATORS-NEXT: 0090: 00006600 12000000 01004600 13000000 |..f.......F.....|
51 ; ACCELERATORS-NEXT: 00A0: 02006600 14000000 03004600 15000000 |..f.......F.....|
52 ; ACCELERATORS-NEXT: 00B0: 09004600 16000000 05004600 17000000 |..F.......F.....|
53 ; ACCELERATORS-NEXT: 00C0: 11004600 18000000 0B004600 19000000 |..F.......F.....|
54 ; ACCELERATORS-NEXT: 00D0: 07004600 1A000000 13004600 1B000000 |..F.......F.....|
55 ; ACCELERATORS-NEXT: 00E0: 0D004600 1C000000 19004600 1D000000 |..F.......F.....|
56 ; ACCELERATORS-NEXT: 00F0: 15004600 1E000000 0F004600 1F000000 |..F.......F.....|
57 ; ACCELERATORS-NEXT: 0100: 1B004600 20000000 17004600 21000000 |..F. .....F.!...|
58 ; ACCELERATORS-NEXT: 0110: 1D004600 22000000 1F004600 23000000 |..F.".....F.#...|
59 ; ACCELERATORS-NEXT: 0120: 00005500 24000000 01005500 25000000 |..U.$.....U.%...|
60 ; ACCELERATORS-NEXT: 0130: 02005500 26000000 03005500 27000000 |..U.&.....U.'...|
61 ; ACCELERATORS-NEXT: 0140: 09005500 28000000 05005500 29000000 |..U.(.....U.)...|
62 ; ACCELERATORS-NEXT: 0150: 11005500 2A000000 0B005500 2B000000 |..U.*.....U.+...|
63 ; ACCELERATORS-NEXT: 0160: 07005500 2C000000 13005500 2D000000 |..U.,.....U.-...|
64 ; ACCELERATORS-NEXT: 0170: 0D005500 2E000000 19005500 2F000000 |..U.......U./...|
65 ; ACCELERATORS-NEXT: 0180: 15005500 30000000 0F005500 31000000 |..U.0.....U.1...|
66 ; ACCELERATORS-NEXT: 0190: 1B005500 32000000 17005500 33000000 |..U.2.....U.3...|
67 ; ACCELERATORS-NEXT: 01A0: 1D005500 34000000 1F005500 35000000 |..U.4.....U.5...|
68 ; ACCELERATORS-NEXT: 01B0: 00003700 36000000 01003700 37000000 |..7.6.....7.7...|
69 ; ACCELERATORS-NEXT: 01C0: 02003700 38000000 03003700 39000000 |..7.8.....7.9...|
70 ; ACCELERATORS-NEXT: 01D0: 09003700 3A000000 05003700 3B000000 |..7.:.....7.;...|
71 ; ACCELERATORS-NEXT: 01E0: 11003700 3C000000 0B003700 3D000000 |..7.<.....7.=...|
72 ; ACCELERATORS-NEXT: 01F0: 07003700 3E000000 13003700 3F000000 |..7.>.....7.?...|
73 ; ACCELERATORS-NEXT: 0200: 0D003700 40000000 19003700 41000000 |..7.@.....7.A...|
74 ; ACCELERATORS-NEXT: 0210: 15003700 42000000 0F003700 43000000 |..7.B.....7.C...|
75 ; ACCELERATORS-NEXT: 0220: 1B003700 44000000 17003700 45000000 |..7.D.....7.E...|
76 ; ACCELERATORS-NEXT: 0230: 1D003700 46000000 1F003700 47000000 |..7.F.....7.G...|
77 ; ACCELERATORS-NEXT: 0240: 00000A00 48000000 82000A00 49000000 |....H.......I...|
78 ; ACCELERATORS-NEXT: )
79
80
81 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-bad-id.rc 2>&1 | FileCheck %s --check-prefix BADID
82
83 ; BADID: llvm-rc: Error in ACCELERATORS statement (ID 1):
84 ; BADID-NEXT: ACCELERATORS entry ID (1234567) does not fit in 16 bits.
85
86
87 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-ascii-virtkey.rc 2>&1 | FileCheck %s --check-prefix ASCII1
88
89 ; ASCII1: llvm-rc: Error in ACCELERATORS statement (ID 2):
90 ; ASCII1-NEXT: Accelerator ID 15: Accelerator can't be both ASCII and VIRTKEY
91
92
93 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-ascii-control.rc 2>&1 | FileCheck %s --check-prefix ASCII2
94
95 ; ASCII2: llvm-rc: Error in ACCELERATORS statement (ID 2):
96 ; ASCII2-NEXT: Accelerator ID 15: Can only apply ALT, SHIFT or CONTROL to VIRTKEY accelerators
97
98
99 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-ascii-shift.rc 2>&1 | FileCheck %s --check-prefix ASCII3
100
101 ; ASCII3: llvm-rc: Error in ACCELERATORS statement (ID 2):
102 ; ASCII3-NEXT: Accelerator ID 15: Can only apply ALT, SHIFT or CONTROL to VIRTKEY accelerators
103
104
105 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-ascii-alt.rc 2>&1 | FileCheck %s --check-prefix ASCII4
106
107 ; ASCII4: llvm-rc: Error in ACCELERATORS statement (ID 2):
108 ; ASCII4-NEXT: Accelerator ID 15: Can only apply ALT, SHIFT or CONTROL to VIRTKEY accelerators
109
110
111 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-bad-key-id.rc 2>&1 | FileCheck %s --check-prefix BADKEYID
112
113 ; BADKEYID: llvm-rc: Error in ACCELERATORS statement (ID 9):
114 ; BADKEYID-NEXT: Numeric event key ID (1234567) does not fit in 16 bits.
115
116
117 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-too-short.rc 2>&1 | FileCheck %s --check-prefix LENGTH1
118
119 ; LENGTH1: llvm-rc: Error in ACCELERATORS statement (ID 10):
120 ; LENGTH1-NEXT: Accelerator ID 12: Accelerator string events should have length 1 or 2
121
122
123 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-too-long.rc 2>&1 | FileCheck %s --check-prefix LENGTH2
124
125 ; LENGTH2: llvm-rc: Error in ACCELERATORS statement (ID 12):
126 ; LENGTH2-NEXT: Accelerator ID 5: Accelerator string events should have length 1 or 2
127
128
129 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-only-caret.rc 2>&1 | FileCheck %s --check-prefix CARET1
130
131 ; CARET1: llvm-rc: Error in ACCELERATORS statement (ID 555):
132 ; CARET1-NEXT: Accelerator ID 100: No character following '^' in accelerator event
133
134
135 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-no-caret.rc 2>&1 | FileCheck %s --check-prefix CARET2
136
137 ; CARET2: llvm-rc: Error in ACCELERATORS statement (ID 50):
138 ; CARET2-NEXT: Accelerator ID 1: Event string should be one-character, possibly preceded by '^'
139
140
141 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-long-virtkey.rc 2>&1 | FileCheck %s --check-prefix CARET3
142
143 ; CARET3: llvm-rc: Error in ACCELERATORS statement (ID 100):
144 ; CARET3-NEXT: Accelerator ID 10: VIRTKEY accelerator events can't be preceded by '^'
145
146
147 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-control-nonalpha.rc 2>&1 | FileCheck %s --check-prefix NONALPHA1
148
149 ; NONALPHA1: llvm-rc: Error in ACCELERATORS statement (ID 100):
150 ; NONALPHA1-NEXT: Accelerator ID 1: Control character accelerator event should be alphabetic
151
152
153 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-accelerators-virtual-nonalpha.rc 2>&1 | FileCheck %s --check-prefix NONALPHA2
154
155 ; NONALPHA2: llvm-rc: Error in ACCELERATORS statement (ID 42):
156 ; NONALPHA2-NEXT: Accelerator ID 1: Non-alphanumeric characters cannot describe virtual keys
2626
2727 namespace llvm {
2828 namespace rc {
29
30 // Class that employs RAII to save the current serializator object state
31 // and revert to it as soon as we leave the scope. This is useful if resources
32 // declare their own resource-local statements.
33 class ContextKeeper {
34 ResourceFileWriter *FileWriter;
35 ResourceFileWriter::ObjectInfo SavedInfo;
36
37 public:
38 ContextKeeper(ResourceFileWriter *V)
39 : FileWriter(V), SavedInfo(V->ObjectData) {}
40 ~ContextKeeper() { FileWriter->ObjectData = SavedInfo; }
41 };
2942
3043 static Error createError(Twine Message,
3144 std::errc Type = std::errc::invalid_argument) {
183196 return writeResource(Res, &ResourceFileWriter::writeNullBody);
184197 }
185198
199 Error ResourceFileWriter::visitAcceleratorsResource(const RCResource *Res) {
200 return writeResource(Res, &ResourceFileWriter::writeAcceleratorsBody);
201 }
202
186203 Error ResourceFileWriter::visitHTMLResource(const RCResource *Res) {
187204 return writeResource(Res, &ResourceFileWriter::writeHTMLBody);
205 }
206
207 Error ResourceFileWriter::visitCharacteristicsStmt(
208 const CharacteristicsStmt *Stmt) {
209 ObjectData.Characteristics = Stmt->Value;
210 return Error::success();
188211 }
189212
190213 Error ResourceFileWriter::visitLanguageStmt(const LanguageResource *Stmt) {
191214 RETURN_IF_ERROR(checkNumberFits(Stmt->Lang, 10, "Primary language ID"));
192215 RETURN_IF_ERROR(checkNumberFits(Stmt->SubLang, 6, "Sublanguage ID"));
193216 ObjectData.LanguageInfo = Stmt->Lang | (Stmt->SubLang << 10);
217 return Error::success();
218 }
219
220 Error ResourceFileWriter::visitVersionStmt(const VersionStmt *Stmt) {
221 ObjectData.VersionInfo = Stmt->Value;
194222 return Error::success();
195223 }
196224
207235 RETURN_IF_ERROR(handleError(writeIdentifier(ResType), Res));
208236 RETURN_IF_ERROR(handleError(writeIdentifier(Res->ResName), Res));
209237
238 // Apply the resource-local optional statements.
239 ContextKeeper RAII(this);
240 RETURN_IF_ERROR(handleError(Res->applyStmts(this), Res));
241
210242 padStream(sizeof(uint32_t));
211243 object::WinResHeaderSuffix HeaderSuffix{
212244 ulittle32_t(0), // DataVersion; seems to always be 0
213245 ulittle16_t(Res->getMemoryFlags()), ulittle16_t(ObjectData.LanguageInfo),
214 ulittle32_t(0), // VersionInfo
215 ulittle32_t(0)}; // Characteristics
246 ulittle32_t(ObjectData.VersionInfo),
247 ulittle32_t(ObjectData.Characteristics)};
216248 writeObject(HeaderSuffix);
217249
218250 uint64_t DataLoc = tell();
228260 return Error::success();
229261 }
230262
263 // --- NullResource helpers. --- //
264
231265 Error ResourceFileWriter::writeNullBody(const RCResource *) {
232266 return Error::success();
233267 }
268
269 // --- AcceleratorsResource helpers. --- //
270
271 Error ResourceFileWriter::writeSingleAccelerator(
272 const AcceleratorsResource::Accelerator &Obj, bool IsLastItem) {
273 using Accelerator = AcceleratorsResource::Accelerator;
274 using Opt = Accelerator::Options;
275
276 struct AccelTableEntry {
277 ulittle16_t Flags;
278 ulittle16_t ANSICode;
279 ulittle16_t Id;
280 uint16_t Padding;
281 } Entry{ulittle16_t(0), ulittle16_t(0), ulittle16_t(0), 0};
282
283 bool IsASCII = Obj.Flags & Opt::ASCII, IsVirtKey = Obj.Flags & Opt::VIRTKEY;
284
285 // Remove ASCII flags (which doesn't occur in .res files).
286 Entry.Flags = Obj.Flags & ~Opt::ASCII;
287
288 if (IsLastItem)
289 Entry.Flags |= 0x80;
290
291 RETURN_IF_ERROR(checkNumberFits(Obj.Id, "ACCELERATORS entry ID"));
292 Entry.Id = ulittle16_t(Obj.Id);
293
294 auto createAccError = [&Obj](const char *Msg) {
295 return createError("Accelerator ID " + Twine(Obj.Id) + ": " + Msg);
296 };
297
298 if (IsASCII && IsVirtKey)
299 return createAccError("Accelerator can't be both ASCII and VIRTKEY");
300
301 if (!IsVirtKey && (Obj.Flags & (Opt::ALT | Opt::SHIFT | Opt::CONTROL)))
302 return createAccError("Can only apply ALT, SHIFT or CONTROL to VIRTKEY"
303 " accelerators");
304
305 if (Obj.Event.isInt()) {
306 if (!IsASCII && !IsVirtKey)
307 return createAccError(
308 "Accelerator with a numeric event must be either ASCII"
309 " or VIRTKEY");
310
311 uint32_t EventVal = Obj.Event.getInt();
312 RETURN_IF_ERROR(
313 checkNumberFits(EventVal, "Numeric event key ID"));
314 Entry.ANSICode = ulittle16_t(EventVal);
315 writeObject(Entry);
316 return Error::success();
317 }
318
319 StringRef Str = Obj.Event.getString();
320 bool IsWide;
321 stripQuotes(Str, IsWide);
322
323 if (Str.size() == 0 || Str.size() > 2)
324 return createAccError(
325 "Accelerator string events should have length 1 or 2");
326
327 if (Str[0] == '^') {
328 if (Str.size() == 1)
329 return createAccError("No character following '^' in accelerator event");
330 if (IsVirtKey)
331 return createAccError(
332 "VIRTKEY accelerator events can't be preceded by '^'");
333
334 char Ch = Str[1];
335 if (Ch >= 'a' && Ch <= 'z')
336 Entry.ANSICode = ulittle16_t(Ch - 'a' + 1);
337 else if (Ch >= 'A' && Ch <= 'Z')
338 Entry.ANSICode = ulittle16_t(Ch - 'A' + 1);
339 else
340 return createAccError("Control character accelerator event should be"
341 " alphabetic");
342
343 writeObject(Entry);
344 return Error::success();
345 }
346
347 if (Str.size() == 2)
348 return createAccError("Event string should be one-character, possibly"
349 " preceded by '^'");
350
351 uint8_t EventCh = Str[0];
352 // The original tool just warns in this situation. We chose to fail.
353 if (IsVirtKey && !isalnum(EventCh))
354 return createAccError("Non-alphanumeric characters cannot describe virtual"
355 " keys");
356 if (EventCh > 0x7F)
357 return createAccError("Non-ASCII description of accelerator");
358
359 if (IsVirtKey)
360 EventCh = toupper(EventCh);
361 Entry.ANSICode = ulittle16_t(EventCh);
362 writeObject(Entry);
363 return Error::success();
364 }
365
366 Error ResourceFileWriter::writeAcceleratorsBody(const RCResource *Base) {
367 auto *Res = cast(Base);
368 size_t AcceleratorId = 0;
369 for (auto &Acc : Res->Accelerators) {
370 ++AcceleratorId;
371 RETURN_IF_ERROR(
372 writeSingleAccelerator(Acc, AcceleratorId == Res->Accelerators.size()));
373 }
374 return Error::success();
375 }
376
377 // --- HTMLResource helpers. --- //
378
234379
235380 Error ResourceFileWriter::writeHTMLBody(const RCResource *Base) {
236381 return appendFile(cast(Base)->HTMLLoc);
2929 }
3030
3131 Error visitNullResource(const RCResource *) override;
32 Error visitAcceleratorsResource(const RCResource *) override;
3233 Error visitHTMLResource(const RCResource *) override;
3334
35 Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
3436 Error visitLanguageStmt(const LanguageResource *) override;
37 Error visitVersionStmt(const VersionStmt *) override;
3538
3639 struct ObjectInfo {
3740 uint16_t LanguageInfo;
41 uint32_t Characteristics;
42 uint32_t VersionInfo;
3843
39 ObjectInfo() : LanguageInfo(0) {}
44 ObjectInfo() : LanguageInfo(0), Characteristics(0), VersionInfo(0) {}
4045 } ObjectData;
4146
4247 private:
4651 writeResource(const RCResource *Res,
4752 Error (ResourceFileWriter::*BodyWriter)(const RCResource *));
4853
54 // NullResource
4955 Error writeNullBody(const RCResource *);
56
57 // AcceleratorsResource
58 Error writeSingleAccelerator(const AcceleratorsResource::Accelerator &,
59 bool IsLastItem);
60 Error writeAcceleratorsBody(const RCResource *);
61
62 // HTMLResource
5063 Error writeHTMLBody(const RCResource *);
5164
5265 // Output stream handling.
103103 class RCResource {
104104 public:
105105 IntOrString ResName;
106
107 RCResource() = default;
108 RCResource(RCResource &&) = default;
109106 void setName(const IntOrString &Name) { ResName = Name; }
110107 virtual raw_ostream &log(raw_ostream &OS) const {
111108 return OS << "Base statement\n";
116113 llvm_unreachable("This is unable to call methods from Visitor base");
117114 }
118115
116 // Apply the statements attached to this resource. Generic resources
117 // don't have any.
118 virtual Error applyStmts(Visitor *) const { return Error::success(); }
119
119120 // By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
120121 virtual uint16_t getMemoryFlags() const {
121122 return MfDiscardable | MfPure | MfMoveable;
152153
153154 public:
154155 OptionalStmtList() {}
155 virtual raw_ostream &log(raw_ostream &OS) const;
156 raw_ostream &log(raw_ostream &OS) const override;
156157
157158 void addStmt(std::unique_ptr Stmt) {
158159 Statements.push_back(std::move(Stmt));
159160 }
161
162 Error visit(Visitor *V) const override {
163 for (auto &StmtPtr : Statements)
164 if (auto Err = StmtPtr->visit(V))
165 return Err;
166 return Error::success();
167 }
160168 };
161169
162170 class OptStatementsRCResource : public RCResource {
165173
166174 OptStatementsRCResource(OptionalStmtList &&Stmts)
167175 : OptStatements(llvm::make_unique(std::move(Stmts))) {}
176
177 virtual Error applyStmts(Visitor *V) const { return OptStatements->visit(V); }
168178 };
169179
170180 // LANGUAGE statement. It can occur both as a top-level statement (in such
217227 static uint32_t OptionsFlags[NumFlags];
218228 };
219229
230 std::vector Accelerators;
231
220232 using OptStatementsRCResource::OptStatementsRCResource;
221233 void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
222234 Accelerators.push_back(Accelerator{Event, Id, Flags});
223235 }
224236 raw_ostream &log(raw_ostream &) const override;
225237
226 private:
227 std::vector Accelerators;
238 IntOrString getResourceType() const override { return RkAccelerators; }
239 uint16_t getMemoryFlags() const override {
240 return MfPure | MfMoveable;
241 }
242 Twine getResourceTypeName() const override { return "ACCELERATORS"; }
243
244 Error visit(Visitor *V) const override {
245 return V->visitAcceleratorsResource(this);
246 }
247 ResourceKind getKind() const override { return RkAccelerators; }
248 static bool classof(const RCResource *Res) {
249 return Res->getKind() == RkAccelerators;
250 }
228251 };
229252
230253 // CURSOR resource. Represents a single cursor (".cur") file.
545568 //
546569 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
547570 class CharacteristicsStmt : public OptionalStmt {
571 public:
548572 uint32_t Value;
549573
550 public:
551574 CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
552575 raw_ostream &log(raw_ostream &) const override;
576
577 Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
578 Error visit(Visitor *V) const override {
579 return V->visitCharacteristicsStmt(this);
580 }
553581 };
554582
555583 // VERSION optional statement.
556584 //
557585 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
558586 class VersionStmt : public OptionalStmt {
587 public:
559588 uint32_t Value;
560589
561 public:
562590 VersionStmt(uint32_t Version) : Value(Version) {}
563591 raw_ostream &log(raw_ostream &) const override;
592
593 Twine getResourceTypeName() const override { return "VERSION"; }
594 Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
564595 };
565596
566597 // CAPTION optional statement.
2020
2121 class RCResource;
2222
23 class CharacteristicsStmt;
2324 class LanguageResource;
25 class VersionStmt;
2426
2527 class Visitor {
2628 public:
2729 virtual Error visitNullResource(const RCResource *) = 0;
30 virtual Error visitAcceleratorsResource(const RCResource *) = 0;
2831 virtual Error visitHTMLResource(const RCResource *) = 0;
2932
33 virtual Error visitCharacteristicsStmt(const CharacteristicsStmt *) = 0;
3034 virtual Error visitLanguageStmt(const LanguageResource *) = 0;
35 virtual Error visitVersionStmt(const VersionStmt *) = 0;
3136
3237 virtual ~Visitor() {}
3338 };