121
|
1 //===-- ResourceScriptStmt.h ------------------------------------*- C++-*-===//
|
|
2 //
|
147
|
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
4 // See https://llvm.org/LICENSE.txt for license information.
|
|
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
121
|
6 //
|
|
7 //===---------------------------------------------------------------------===//
|
|
8 //
|
|
9 // This lists all the resource and statement types occurring in RC scripts.
|
|
10 //
|
|
11 //===---------------------------------------------------------------------===//
|
|
12
|
|
13 #ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
|
|
14 #define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
|
|
15
|
|
16 #include "ResourceScriptToken.h"
|
|
17 #include "ResourceVisitor.h"
|
|
18
|
|
19 #include "llvm/ADT/StringSet.h"
|
|
20
|
|
21 namespace llvm {
|
|
22 namespace rc {
|
|
23
|
|
24 // Integer wrapper that also holds information whether the user declared
|
|
25 // the integer to be long (by appending L to the end of the integer) or not.
|
|
26 // It allows to be implicitly cast from and to uint32_t in order
|
|
27 // to be compatible with the parts of code that don't care about the integers
|
|
28 // being marked long.
|
|
29 class RCInt {
|
|
30 uint32_t Val;
|
|
31 bool Long;
|
|
32
|
|
33 public:
|
|
34 RCInt(const RCToken &Token)
|
|
35 : Val(Token.intValue()), Long(Token.isLongInt()) {}
|
|
36 RCInt(uint32_t Value) : Val(Value), Long(false) {}
|
|
37 RCInt(uint32_t Value, bool IsLong) : Val(Value), Long(IsLong) {}
|
|
38 operator uint32_t() const { return Val; }
|
|
39 bool isLong() const { return Long; }
|
|
40
|
|
41 RCInt &operator+=(const RCInt &Rhs) {
|
|
42 std::tie(Val, Long) = std::make_pair(Val + Rhs.Val, Long | Rhs.Long);
|
|
43 return *this;
|
|
44 }
|
|
45
|
|
46 RCInt &operator-=(const RCInt &Rhs) {
|
|
47 std::tie(Val, Long) = std::make_pair(Val - Rhs.Val, Long | Rhs.Long);
|
|
48 return *this;
|
|
49 }
|
|
50
|
|
51 RCInt &operator|=(const RCInt &Rhs) {
|
|
52 std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long);
|
|
53 return *this;
|
|
54 }
|
|
55
|
|
56 RCInt &operator&=(const RCInt &Rhs) {
|
|
57 std::tie(Val, Long) = std::make_pair(Val & Rhs.Val, Long | Rhs.Long);
|
|
58 return *this;
|
|
59 }
|
|
60
|
|
61 RCInt operator-() const { return {-Val, Long}; }
|
|
62 RCInt operator~() const { return {~Val, Long}; }
|
|
63
|
|
64 friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) {
|
|
65 return OS << Int.Val << (Int.Long ? "L" : "");
|
|
66 }
|
|
67 };
|
|
68
|
147
|
69 class IntWithNotMask {
|
|
70 private:
|
|
71 RCInt Value;
|
|
72 int32_t NotMask;
|
|
73
|
|
74 public:
|
|
75 IntWithNotMask() : IntWithNotMask(RCInt(0)) {}
|
|
76 IntWithNotMask(RCInt Value, int32_t NotMask = 0) : Value(Value), NotMask(NotMask) {}
|
|
77
|
|
78 RCInt getValue() const {
|
|
79 return Value;
|
|
80 }
|
|
81
|
|
82 uint32_t getNotMask() const {
|
|
83 return NotMask;
|
|
84 }
|
|
85
|
|
86 IntWithNotMask &operator+=(const IntWithNotMask &Rhs) {
|
|
87 Value &= ~Rhs.NotMask;
|
|
88 Value += Rhs.Value;
|
|
89 NotMask |= Rhs.NotMask;
|
|
90 return *this;
|
|
91 }
|
|
92
|
|
93 IntWithNotMask &operator-=(const IntWithNotMask &Rhs) {
|
|
94 Value &= ~Rhs.NotMask;
|
|
95 Value -= Rhs.Value;
|
|
96 NotMask |= Rhs.NotMask;
|
|
97 return *this;
|
|
98 }
|
|
99
|
|
100 IntWithNotMask &operator|=(const IntWithNotMask &Rhs) {
|
|
101 Value &= ~Rhs.NotMask;
|
|
102 Value |= Rhs.Value;
|
|
103 NotMask |= Rhs.NotMask;
|
|
104 return *this;
|
|
105 }
|
|
106
|
|
107 IntWithNotMask &operator&=(const IntWithNotMask &Rhs) {
|
|
108 Value &= ~Rhs.NotMask;
|
|
109 Value &= Rhs.Value;
|
|
110 NotMask |= Rhs.NotMask;
|
|
111 return *this;
|
|
112 }
|
|
113
|
|
114 IntWithNotMask operator-() const { return {-Value, NotMask}; }
|
|
115 IntWithNotMask operator~() const { return {~Value, 0}; }
|
|
116
|
|
117 friend raw_ostream &operator<<(raw_ostream &OS, const IntWithNotMask &Int) {
|
|
118 return OS << Int.Value;
|
|
119 }
|
|
120 };
|
|
121
|
121
|
122 // A class holding a name - either an integer or a reference to the string.
|
|
123 class IntOrString {
|
|
124 private:
|
|
125 union Data {
|
|
126 RCInt Int;
|
|
127 StringRef String;
|
|
128 Data(RCInt Value) : Int(Value) {}
|
|
129 Data(const StringRef Value) : String(Value) {}
|
|
130 Data(const RCToken &Token) {
|
|
131 if (Token.kind() == RCToken::Kind::Int)
|
|
132 Int = RCInt(Token);
|
|
133 else
|
|
134 String = Token.value();
|
|
135 }
|
|
136 } Data;
|
|
137 bool IsInt;
|
|
138
|
|
139 public:
|
|
140 IntOrString() : IntOrString(RCInt(0)) {}
|
|
141 IntOrString(uint32_t Value) : Data(Value), IsInt(1) {}
|
|
142 IntOrString(RCInt Value) : Data(Value), IsInt(1) {}
|
|
143 IntOrString(StringRef Value) : Data(Value), IsInt(0) {}
|
|
144 IntOrString(const RCToken &Token)
|
|
145 : Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {}
|
|
146
|
|
147 bool equalsLower(const char *Str) {
|
|
148 return !IsInt && Data.String.equals_lower(Str);
|
|
149 }
|
|
150
|
|
151 bool isInt() const { return IsInt; }
|
|
152
|
|
153 RCInt getInt() const {
|
|
154 assert(IsInt);
|
|
155 return Data.Int;
|
|
156 }
|
|
157
|
|
158 const StringRef &getString() const {
|
|
159 assert(!IsInt);
|
|
160 return Data.String;
|
|
161 }
|
|
162
|
|
163 operator Twine() const {
|
|
164 return isInt() ? Twine(getInt()) : Twine(getString());
|
|
165 }
|
|
166
|
|
167 friend raw_ostream &operator<<(raw_ostream &, const IntOrString &);
|
|
168 };
|
|
169
|
|
170 enum ResourceKind {
|
|
171 // These resource kinds have corresponding .res resource type IDs
|
|
172 // (TYPE in RESOURCEHEADER structure). The numeric value assigned to each
|
|
173 // kind is equal to this type ID.
|
|
174 RkNull = 0,
|
|
175 RkSingleCursor = 1,
|
147
|
176 RkBitmap = 2,
|
121
|
177 RkSingleIcon = 3,
|
|
178 RkMenu = 4,
|
|
179 RkDialog = 5,
|
|
180 RkStringTableBundle = 6,
|
|
181 RkAccelerators = 9,
|
147
|
182 RkRcData = 10,
|
121
|
183 RkCursorGroup = 12,
|
|
184 RkIconGroup = 14,
|
|
185 RkVersionInfo = 16,
|
|
186 RkHTML = 23,
|
|
187
|
|
188 // These kinds don't have assigned type IDs (they might be the resources
|
|
189 // of invalid kind, expand to many resource structures in .res files,
|
|
190 // or have variable type ID). In order to avoid ID clashes with IDs above,
|
|
191 // we assign the kinds the values 256 and larger.
|
|
192 RkInvalid = 256,
|
|
193 RkBase,
|
|
194 RkCursor,
|
|
195 RkIcon,
|
|
196 RkStringTable,
|
|
197 RkUser,
|
|
198 RkSingleCursorOrIconRes,
|
|
199 RkCursorOrIconGroupRes,
|
|
200 };
|
|
201
|
|
202 // Non-zero memory flags.
|
|
203 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
|
|
204 enum MemoryFlags {
|
|
205 MfMoveable = 0x10,
|
|
206 MfPure = 0x20,
|
|
207 MfPreload = 0x40,
|
|
208 MfDiscardable = 0x1000
|
|
209 };
|
|
210
|
|
211 // Base resource. All the resources should derive from this base.
|
|
212 class RCResource {
|
|
213 public:
|
|
214 IntOrString ResName;
|
147
|
215 uint16_t MemoryFlags = getDefaultMemoryFlags();
|
121
|
216 void setName(const IntOrString &Name) { ResName = Name; }
|
|
217 virtual raw_ostream &log(raw_ostream &OS) const {
|
|
218 return OS << "Base statement\n";
|
|
219 };
|
147
|
220 RCResource() {}
|
|
221 RCResource(uint16_t Flags) : MemoryFlags(Flags) {}
|
121
|
222 virtual ~RCResource() {}
|
|
223
|
|
224 virtual Error visit(Visitor *) const {
|
|
225 llvm_unreachable("This is unable to call methods from Visitor base");
|
|
226 }
|
|
227
|
|
228 // Apply the statements attached to this resource. Generic resources
|
|
229 // don't have any.
|
|
230 virtual Error applyStmts(Visitor *) const { return Error::success(); }
|
|
231
|
|
232 // By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
|
147
|
233 static uint16_t getDefaultMemoryFlags() {
|
121
|
234 return MfDiscardable | MfPure | MfMoveable;
|
|
235 }
|
147
|
236
|
121
|
237 virtual ResourceKind getKind() const { return RkBase; }
|
|
238 static bool classof(const RCResource *Res) { return true; }
|
|
239
|
|
240 virtual IntOrString getResourceType() const {
|
|
241 llvm_unreachable("This cannot be called on objects without types.");
|
|
242 }
|
|
243 virtual Twine getResourceTypeName() const {
|
|
244 llvm_unreachable("This cannot be called on objects without types.");
|
|
245 };
|
|
246 };
|
|
247
|
|
248 // An empty resource. It has no content, type 0, ID 0 and all of its
|
|
249 // characteristics are equal to 0.
|
|
250 class NullResource : public RCResource {
|
|
251 public:
|
147
|
252 NullResource() : RCResource(0) {}
|
121
|
253 raw_ostream &log(raw_ostream &OS) const override {
|
|
254 return OS << "Null resource\n";
|
|
255 }
|
|
256 Error visit(Visitor *V) const override { return V->visitNullResource(this); }
|
|
257 IntOrString getResourceType() const override { return 0; }
|
|
258 Twine getResourceTypeName() const override { return "(NULL)"; }
|
|
259 };
|
|
260
|
|
261 // Optional statement base. All such statements should derive from this base.
|
|
262 class OptionalStmt : public RCResource {};
|
|
263
|
|
264 class OptionalStmtList : public OptionalStmt {
|
|
265 std::vector<std::unique_ptr<OptionalStmt>> Statements;
|
|
266
|
|
267 public:
|
|
268 OptionalStmtList() {}
|
|
269 raw_ostream &log(raw_ostream &OS) const override;
|
|
270
|
|
271 void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
|
|
272 Statements.push_back(std::move(Stmt));
|
|
273 }
|
|
274
|
|
275 Error visit(Visitor *V) const override {
|
|
276 for (auto &StmtPtr : Statements)
|
|
277 if (auto Err = StmtPtr->visit(V))
|
|
278 return Err;
|
|
279 return Error::success();
|
|
280 }
|
|
281 };
|
|
282
|
|
283 class OptStatementsRCResource : public RCResource {
|
|
284 public:
|
|
285 std::unique_ptr<OptionalStmtList> OptStatements;
|
|
286
|
147
|
287 OptStatementsRCResource(OptionalStmtList &&Stmts,
|
|
288 uint16_t Flags = RCResource::getDefaultMemoryFlags())
|
|
289 : RCResource(Flags),
|
|
290 OptStatements(llvm::make_unique<OptionalStmtList>(std::move(Stmts))) {}
|
121
|
291
|
|
292 virtual Error applyStmts(Visitor *V) const { return OptStatements->visit(V); }
|
|
293 };
|
|
294
|
|
295 // LANGUAGE statement. It can occur both as a top-level statement (in such
|
|
296 // a situation, it changes the default language until the end of the file)
|
|
297 // and as an optional resource statement (then it changes the language
|
|
298 // of a single resource).
|
|
299 //
|
|
300 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx
|
|
301 class LanguageResource : public OptionalStmt {
|
|
302 public:
|
|
303 uint32_t Lang, SubLang;
|
|
304
|
|
305 LanguageResource(uint32_t LangId, uint32_t SubLangId)
|
|
306 : Lang(LangId), SubLang(SubLangId) {}
|
|
307 raw_ostream &log(raw_ostream &) const override;
|
|
308
|
|
309 // This is not a regular top-level statement; when it occurs, it just
|
|
310 // modifies the language context.
|
|
311 Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
|
|
312 Twine getResourceTypeName() const override { return "LANGUAGE"; }
|
|
313 };
|
|
314
|
|
315 // ACCELERATORS resource. Defines a named table of accelerators for the app.
|
|
316 //
|
|
317 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx
|
|
318 class AcceleratorsResource : public OptStatementsRCResource {
|
|
319 public:
|
|
320 class Accelerator {
|
|
321 public:
|
|
322 IntOrString Event;
|
|
323 uint32_t Id;
|
|
324 uint16_t Flags;
|
|
325
|
|
326 enum Options {
|
|
327 // This is actually 0x0000 (accelerator is assumed to be ASCII if it's
|
|
328 // not VIRTKEY). However, rc.exe behavior is different in situations
|
|
329 // "only ASCII defined" and "neither ASCII nor VIRTKEY defined".
|
|
330 // Therefore, we include ASCII as another flag. This must be zeroed
|
|
331 // when serialized.
|
|
332 ASCII = 0x8000,
|
|
333 VIRTKEY = 0x0001,
|
|
334 NOINVERT = 0x0002,
|
|
335 ALT = 0x0010,
|
|
336 SHIFT = 0x0004,
|
|
337 CONTROL = 0x0008
|
|
338 };
|
|
339
|
|
340 static constexpr size_t NumFlags = 6;
|
|
341 static StringRef OptionsStr[NumFlags];
|
|
342 static uint32_t OptionsFlags[NumFlags];
|
|
343 };
|
|
344
|
147
|
345 AcceleratorsResource(OptionalStmtList &&List, uint16_t Flags)
|
|
346 : OptStatementsRCResource(std::move(List), Flags) {}
|
|
347
|
121
|
348 std::vector<Accelerator> Accelerators;
|
|
349
|
|
350 void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
|
|
351 Accelerators.push_back(Accelerator{Event, Id, Flags});
|
|
352 }
|
|
353 raw_ostream &log(raw_ostream &) const override;
|
|
354
|
|
355 IntOrString getResourceType() const override { return RkAccelerators; }
|
147
|
356 static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
|
121
|
357 Twine getResourceTypeName() const override { return "ACCELERATORS"; }
|
|
358
|
|
359 Error visit(Visitor *V) const override {
|
|
360 return V->visitAcceleratorsResource(this);
|
|
361 }
|
|
362 ResourceKind getKind() const override { return RkAccelerators; }
|
|
363 static bool classof(const RCResource *Res) {
|
|
364 return Res->getKind() == RkAccelerators;
|
|
365 }
|
|
366 };
|
|
367
|
147
|
368 // BITMAP resource. Represents a bitmap (".bmp") file.
|
|
369 //
|
|
370 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx
|
|
371 class BitmapResource : public RCResource {
|
|
372 public:
|
|
373 StringRef BitmapLoc;
|
|
374
|
|
375 BitmapResource(StringRef Location, uint16_t Flags)
|
|
376 : RCResource(Flags), BitmapLoc(Location) {}
|
|
377 raw_ostream &log(raw_ostream &) const override;
|
|
378
|
|
379 IntOrString getResourceType() const override { return RkBitmap; }
|
|
380 static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
|
|
381
|
|
382 Twine getResourceTypeName() const override { return "BITMAP"; }
|
|
383 Error visit(Visitor *V) const override {
|
|
384 return V->visitBitmapResource(this);
|
|
385 }
|
|
386 ResourceKind getKind() const override { return RkBitmap; }
|
|
387 static bool classof(const RCResource *Res) {
|
|
388 return Res->getKind() == RkBitmap;
|
|
389 }
|
|
390 };
|
|
391
|
121
|
392 // CURSOR resource. Represents a single cursor (".cur") file.
|
|
393 //
|
|
394 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
|
|
395 class CursorResource : public RCResource {
|
|
396 public:
|
|
397 StringRef CursorLoc;
|
|
398
|
147
|
399 CursorResource(StringRef Location, uint16_t Flags)
|
|
400 : RCResource(Flags), CursorLoc(Location) {}
|
121
|
401 raw_ostream &log(raw_ostream &) const override;
|
|
402
|
|
403 Twine getResourceTypeName() const override { return "CURSOR"; }
|
147
|
404 static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
|
121
|
405 Error visit(Visitor *V) const override {
|
|
406 return V->visitCursorResource(this);
|
|
407 }
|
|
408 ResourceKind getKind() const override { return RkCursor; }
|
|
409 static bool classof(const RCResource *Res) {
|
|
410 return Res->getKind() == RkCursor;
|
|
411 }
|
|
412 };
|
|
413
|
|
414 // ICON resource. Represents a single ".ico" file containing a group of icons.
|
|
415 //
|
|
416 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
|
|
417 class IconResource : public RCResource {
|
|
418 public:
|
|
419 StringRef IconLoc;
|
|
420
|
147
|
421 IconResource(StringRef Location, uint16_t Flags)
|
|
422 : RCResource(Flags), IconLoc(Location) {}
|
121
|
423 raw_ostream &log(raw_ostream &) const override;
|
|
424
|
|
425 Twine getResourceTypeName() const override { return "ICON"; }
|
147
|
426 static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
|
121
|
427 Error visit(Visitor *V) const override { return V->visitIconResource(this); }
|
|
428 ResourceKind getKind() const override { return RkIcon; }
|
|
429 static bool classof(const RCResource *Res) {
|
|
430 return Res->getKind() == RkIcon;
|
|
431 }
|
|
432 };
|
|
433
|
|
434 // HTML resource. Represents a local webpage that is to be embedded into the
|
|
435 // resulting resource file. It embeds a file only - no additional resources
|
|
436 // (images etc.) are included with this resource.
|
|
437 //
|
|
438 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx
|
|
439 class HTMLResource : public RCResource {
|
|
440 public:
|
|
441 StringRef HTMLLoc;
|
|
442
|
147
|
443 HTMLResource(StringRef Location, uint16_t Flags)
|
|
444 : RCResource(Flags), HTMLLoc(Location) {}
|
121
|
445 raw_ostream &log(raw_ostream &) const override;
|
|
446
|
|
447 Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
|
|
448
|
|
449 // Curiously, file resources don't have DISCARDABLE flag set.
|
147
|
450 static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
|
121
|
451 IntOrString getResourceType() const override { return RkHTML; }
|
|
452 Twine getResourceTypeName() const override { return "HTML"; }
|
|
453 ResourceKind getKind() const override { return RkHTML; }
|
|
454 static bool classof(const RCResource *Res) {
|
|
455 return Res->getKind() == RkHTML;
|
|
456 }
|
|
457 };
|
|
458
|
|
459 // -- MENU resource and its helper classes --
|
|
460 // This resource describes the contents of an application menu
|
|
461 // (usually located in the upper part of the dialog.)
|
|
462 //
|
|
463 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx
|
|
464
|
|
465 // Description of a single submenu item.
|
|
466 class MenuDefinition {
|
|
467 public:
|
|
468 enum Options {
|
|
469 CHECKED = 0x0008,
|
|
470 GRAYED = 0x0001,
|
|
471 HELP = 0x4000,
|
|
472 INACTIVE = 0x0002,
|
|
473 MENUBARBREAK = 0x0020,
|
|
474 MENUBREAK = 0x0040
|
|
475 };
|
|
476
|
|
477 enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
|
|
478
|
|
479 static constexpr size_t NumFlags = 6;
|
|
480 static StringRef OptionsStr[NumFlags];
|
|
481 static uint32_t OptionsFlags[NumFlags];
|
|
482 static raw_ostream &logFlags(raw_ostream &, uint16_t Flags);
|
|
483 virtual raw_ostream &log(raw_ostream &OS) const {
|
|
484 return OS << "Base menu definition\n";
|
|
485 }
|
|
486 virtual ~MenuDefinition() {}
|
|
487
|
|
488 virtual uint16_t getResFlags() const { return 0; }
|
|
489 virtual MenuDefKind getKind() const { return MkBase; }
|
|
490 };
|
|
491
|
|
492 // Recursive description of a whole submenu.
|
|
493 class MenuDefinitionList : public MenuDefinition {
|
|
494 public:
|
|
495 std::vector<std::unique_ptr<MenuDefinition>> Definitions;
|
|
496
|
|
497 void addDefinition(std::unique_ptr<MenuDefinition> Def) {
|
|
498 Definitions.push_back(std::move(Def));
|
|
499 }
|
|
500 raw_ostream &log(raw_ostream &) const override;
|
|
501 };
|
|
502
|
|
503 // Separator in MENU definition (MENUITEM SEPARATOR).
|
|
504 //
|
|
505 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
|
|
506 class MenuSeparator : public MenuDefinition {
|
|
507 public:
|
|
508 raw_ostream &log(raw_ostream &) const override;
|
|
509
|
|
510 MenuDefKind getKind() const override { return MkSeparator; }
|
|
511 static bool classof(const MenuDefinition *D) {
|
|
512 return D->getKind() == MkSeparator;
|
|
513 }
|
|
514 };
|
|
515
|
|
516 // MENUITEM statement definition.
|
|
517 //
|
|
518 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
|
|
519 class MenuItem : public MenuDefinition {
|
|
520 public:
|
|
521 StringRef Name;
|
|
522 uint32_t Id;
|
|
523 uint16_t Flags;
|
|
524
|
|
525 MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
|
|
526 : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
|
|
527 raw_ostream &log(raw_ostream &) const override;
|
|
528
|
|
529 uint16_t getResFlags() const override { return Flags; }
|
|
530 MenuDefKind getKind() const override { return MkMenuItem; }
|
|
531 static bool classof(const MenuDefinition *D) {
|
|
532 return D->getKind() == MkMenuItem;
|
|
533 }
|
|
534 };
|
|
535
|
|
536 // POPUP statement definition.
|
|
537 //
|
|
538 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
|
|
539 class PopupItem : public MenuDefinition {
|
|
540 public:
|
|
541 StringRef Name;
|
|
542 uint16_t Flags;
|
|
543 MenuDefinitionList SubItems;
|
|
544
|
|
545 PopupItem(StringRef Caption, uint16_t ItemFlags,
|
|
546 MenuDefinitionList &&SubItemsList)
|
|
547 : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
|
|
548 raw_ostream &log(raw_ostream &) const override;
|
|
549
|
|
550 // This has an additional (0x10) flag. It doesn't match with documented
|
|
551 // 0x01 flag, though.
|
|
552 uint16_t getResFlags() const override { return Flags | 0x10; }
|
|
553 MenuDefKind getKind() const override { return MkPopup; }
|
|
554 static bool classof(const MenuDefinition *D) {
|
|
555 return D->getKind() == MkPopup;
|
|
556 }
|
|
557 };
|
|
558
|
|
559 // Menu resource definition.
|
|
560 class MenuResource : public OptStatementsRCResource {
|
|
561 public:
|
|
562 MenuDefinitionList Elements;
|
|
563
|
147
|
564 MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
|
|
565 uint16_t Flags)
|
|
566 : OptStatementsRCResource(std::move(OptStmts), Flags),
|
121
|
567 Elements(std::move(Items)) {}
|
|
568 raw_ostream &log(raw_ostream &) const override;
|
|
569
|
|
570 IntOrString getResourceType() const override { return RkMenu; }
|
|
571 Twine getResourceTypeName() const override { return "MENU"; }
|
|
572 Error visit(Visitor *V) const override { return V->visitMenuResource(this); }
|
|
573 ResourceKind getKind() const override { return RkMenu; }
|
|
574 static bool classof(const RCResource *Res) {
|
|
575 return Res->getKind() == RkMenu;
|
|
576 }
|
|
577 };
|
|
578
|
|
579 // STRINGTABLE resource. Contains a list of strings, each having its unique ID.
|
|
580 //
|
|
581 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
|
|
582 class StringTableResource : public OptStatementsRCResource {
|
|
583 public:
|
|
584 std::vector<std::pair<uint32_t, StringRef>> Table;
|
|
585
|
147
|
586 StringTableResource(OptionalStmtList &&List, uint16_t Flags)
|
|
587 : OptStatementsRCResource(std::move(List), Flags) {}
|
121
|
588 void addString(uint32_t ID, StringRef String) {
|
|
589 Table.emplace_back(ID, String);
|
|
590 }
|
|
591 raw_ostream &log(raw_ostream &) const override;
|
|
592 Twine getResourceTypeName() const override { return "STRINGTABLE"; }
|
|
593 Error visit(Visitor *V) const override {
|
|
594 return V->visitStringTableResource(this);
|
|
595 }
|
|
596 };
|
|
597
|
|
598 // -- DIALOG(EX) resource and its helper classes --
|
|
599 //
|
|
600 // This resource describes dialog boxes and controls residing inside them.
|
|
601 //
|
|
602 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx
|
|
603 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
|
|
604
|
|
605 // Single control definition.
|
|
606 class Control {
|
|
607 public:
|
|
608 StringRef Type;
|
|
609 IntOrString Title;
|
|
610 uint32_t ID, X, Y, Width, Height;
|
147
|
611 Optional<IntWithNotMask> Style;
|
|
612 Optional<uint32_t> ExtStyle, HelpID;
|
|
613 IntOrString Class;
|
121
|
614
|
|
615 // Control classes as described in DLGITEMTEMPLATEEX documentation.
|
|
616 //
|
|
617 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx
|
|
618 enum CtlClasses {
|
|
619 ClsButton = 0x80,
|
|
620 ClsEdit = 0x81,
|
|
621 ClsStatic = 0x82,
|
|
622 ClsListBox = 0x83,
|
|
623 ClsScrollBar = 0x84,
|
|
624 ClsComboBox = 0x85
|
|
625 };
|
|
626
|
|
627 // Simple information about a single control type.
|
|
628 struct CtlInfo {
|
|
629 uint32_t Style;
|
|
630 uint16_t CtlClass;
|
|
631 bool HasTitle;
|
|
632 };
|
|
633
|
|
634 Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
|
|
635 uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
|
147
|
636 Optional<IntWithNotMask> ItemStyle, Optional<uint32_t> ExtItemStyle,
|
|
637 Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
|
121
|
638 : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
|
|
639 Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
|
147
|
640 ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
|
121
|
641
|
|
642 static const StringMap<CtlInfo> SupportedCtls;
|
|
643
|
|
644 raw_ostream &log(raw_ostream &) const;
|
|
645 };
|
|
646
|
|
647 // Single dialog definition. We don't create distinct classes for DIALOG and
|
|
648 // DIALOGEX because of their being too similar to each other. We only have a
|
|
649 // flag determining the type of the dialog box.
|
|
650 class DialogResource : public OptStatementsRCResource {
|
|
651 public:
|
|
652 uint32_t X, Y, Width, Height, HelpID;
|
|
653 std::vector<Control> Controls;
|
|
654 bool IsExtended;
|
|
655
|
|
656 DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
|
|
657 uint32_t DlgHeight, uint32_t DlgHelpID,
|
147
|
658 OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
|
|
659 : OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
|
121
|
660 Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
|
|
661 IsExtended(IsDialogEx) {}
|
|
662
|
|
663 void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
|
|
664
|
|
665 raw_ostream &log(raw_ostream &) const override;
|
|
666
|
|
667 // It was a weird design decision to assign the same resource type number
|
|
668 // both for DIALOG and DIALOGEX (and the same structure version number).
|
|
669 // It makes it possible for DIALOG to be mistaken for DIALOGEX.
|
|
670 IntOrString getResourceType() const override { return RkDialog; }
|
|
671 Twine getResourceTypeName() const override {
|
|
672 return "DIALOG" + Twine(IsExtended ? "EX" : "");
|
|
673 }
|
|
674 Error visit(Visitor *V) const override {
|
|
675 return V->visitDialogResource(this);
|
|
676 }
|
|
677 ResourceKind getKind() const override { return RkDialog; }
|
|
678 static bool classof(const RCResource *Res) {
|
|
679 return Res->getKind() == RkDialog;
|
|
680 }
|
|
681 };
|
|
682
|
|
683 // User-defined resource. It is either:
|
|
684 // * a link to the file, e.g. NAME TYPE "filename",
|
|
685 // * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}.
|
|
686 class UserDefinedResource : public RCResource {
|
|
687 public:
|
|
688 IntOrString Type;
|
|
689 StringRef FileLoc;
|
|
690 std::vector<IntOrString> Contents;
|
|
691 bool IsFileResource;
|
|
692
|
147
|
693 UserDefinedResource(IntOrString ResourceType, StringRef FileLocation,
|
|
694 uint16_t Flags)
|
|
695 : RCResource(Flags), Type(ResourceType), FileLoc(FileLocation),
|
|
696 IsFileResource(true) {}
|
|
697 UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data,
|
|
698 uint16_t Flags)
|
|
699 : RCResource(Flags), Type(ResourceType), Contents(std::move(Data)),
|
|
700 IsFileResource(false) {}
|
121
|
701
|
|
702 raw_ostream &log(raw_ostream &) const override;
|
|
703 IntOrString getResourceType() const override { return Type; }
|
|
704 Twine getResourceTypeName() const override { return Type; }
|
147
|
705 static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
|
121
|
706
|
|
707 Error visit(Visitor *V) const override {
|
|
708 return V->visitUserDefinedResource(this);
|
|
709 }
|
|
710 ResourceKind getKind() const override { return RkUser; }
|
|
711 static bool classof(const RCResource *Res) {
|
|
712 return Res->getKind() == RkUser;
|
|
713 }
|
|
714 };
|
|
715
|
|
716 // -- VERSIONINFO resource and its helper classes --
|
|
717 //
|
|
718 // This resource lists the version information on the executable/library.
|
|
719 // The declaration consists of the following items:
|
|
720 // * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS)
|
|
721 // * BEGIN
|
|
722 // * A number of BLOCK and/or VALUE statements. BLOCK recursively defines
|
|
723 // another block of version information, whereas VALUE defines a
|
|
724 // key -> value correspondence. There might be more than one value
|
|
725 // corresponding to the single key.
|
|
726 // * END
|
|
727 //
|
|
728 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
|
|
729
|
|
730 // A single VERSIONINFO statement;
|
|
731 class VersionInfoStmt {
|
|
732 public:
|
|
733 enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
|
|
734
|
|
735 virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
|
|
736 virtual ~VersionInfoStmt() {}
|
|
737
|
|
738 virtual StmtKind getKind() const { return StBase; }
|
|
739 static bool classof(const VersionInfoStmt *S) {
|
|
740 return S->getKind() == StBase;
|
|
741 }
|
|
742 };
|
|
743
|
|
744 // BLOCK definition; also the main VERSIONINFO declaration is considered a
|
|
745 // BLOCK, although it has no name.
|
|
746 // The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
|
|
747 // care about them at the parsing phase.
|
|
748 class VersionInfoBlock : public VersionInfoStmt {
|
|
749 public:
|
|
750 std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
|
|
751 StringRef Name;
|
|
752
|
|
753 VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
|
|
754 void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
|
|
755 Stmts.push_back(std::move(Stmt));
|
|
756 }
|
|
757 raw_ostream &log(raw_ostream &) const override;
|
|
758
|
|
759 StmtKind getKind() const override { return StBlock; }
|
|
760 static bool classof(const VersionInfoStmt *S) {
|
|
761 return S->getKind() == StBlock;
|
|
762 }
|
|
763 };
|
|
764
|
|
765 class VersionInfoValue : public VersionInfoStmt {
|
|
766 public:
|
|
767 StringRef Key;
|
|
768 std::vector<IntOrString> Values;
|
|
769 std::vector<bool> HasPrecedingComma;
|
|
770
|
|
771 VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
|
|
772 std::vector<bool> &&CommasBeforeVals)
|
|
773 : Key(InfoKey), Values(std::move(Vals)),
|
|
774 HasPrecedingComma(std::move(CommasBeforeVals)) {}
|
|
775 raw_ostream &log(raw_ostream &) const override;
|
|
776
|
|
777 StmtKind getKind() const override { return StValue; }
|
|
778 static bool classof(const VersionInfoStmt *S) {
|
|
779 return S->getKind() == StValue;
|
|
780 }
|
|
781 };
|
|
782
|
|
783 class VersionInfoResource : public RCResource {
|
|
784 public:
|
|
785 // A class listing fixed VERSIONINFO statements (occuring before main BEGIN).
|
|
786 // If any of these is not specified, it is assumed by the original tool to
|
|
787 // be equal to 0.
|
|
788 class VersionInfoFixed {
|
|
789 public:
|
|
790 enum VersionInfoFixedType {
|
|
791 FtUnknown,
|
|
792 FtFileVersion,
|
|
793 FtProductVersion,
|
|
794 FtFileFlagsMask,
|
|
795 FtFileFlags,
|
|
796 FtFileOS,
|
|
797 FtFileType,
|
|
798 FtFileSubtype,
|
|
799 FtNumTypes
|
|
800 };
|
|
801
|
|
802 private:
|
|
803 static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
|
|
804 static const StringRef FixedFieldsNames[FtNumTypes];
|
|
805
|
|
806 public:
|
|
807 SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
|
|
808 SmallVector<bool, FtNumTypes> IsTypePresent;
|
|
809
|
|
810 static VersionInfoFixedType getFixedType(StringRef Type);
|
|
811 static bool isTypeSupported(VersionInfoFixedType Type);
|
|
812 static bool isVersionType(VersionInfoFixedType Type);
|
|
813
|
|
814 VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
|
|
815
|
|
816 void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
|
|
817 FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end());
|
|
818 IsTypePresent[Type] = true;
|
|
819 }
|
|
820
|
|
821 raw_ostream &log(raw_ostream &) const;
|
|
822 };
|
|
823
|
|
824 VersionInfoBlock MainBlock;
|
|
825 VersionInfoFixed FixedData;
|
|
826
|
|
827 VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
|
147
|
828 VersionInfoFixed &&FixedInfo, uint16_t Flags)
|
|
829 : RCResource(Flags), MainBlock(std::move(TopLevelBlock)),
|
|
830 FixedData(std::move(FixedInfo)) {}
|
121
|
831
|
|
832 raw_ostream &log(raw_ostream &) const override;
|
|
833 IntOrString getResourceType() const override { return RkVersionInfo; }
|
147
|
834 static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
|
121
|
835 Twine getResourceTypeName() const override { return "VERSIONINFO"; }
|
|
836 Error visit(Visitor *V) const override {
|
|
837 return V->visitVersionInfoResource(this);
|
|
838 }
|
|
839 ResourceKind getKind() const override { return RkVersionInfo; }
|
|
840 static bool classof(const RCResource *Res) {
|
|
841 return Res->getKind() == RkVersionInfo;
|
|
842 }
|
|
843 };
|
|
844
|
|
845 // CHARACTERISTICS optional statement.
|
|
846 //
|
|
847 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
|
|
848 class CharacteristicsStmt : public OptionalStmt {
|
|
849 public:
|
|
850 uint32_t Value;
|
|
851
|
|
852 CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
|
|
853 raw_ostream &log(raw_ostream &) const override;
|
|
854
|
|
855 Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
|
|
856 Error visit(Visitor *V) const override {
|
|
857 return V->visitCharacteristicsStmt(this);
|
|
858 }
|
|
859 };
|
|
860
|
|
861 // VERSION optional statement.
|
|
862 //
|
|
863 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
|
|
864 class VersionStmt : public OptionalStmt {
|
|
865 public:
|
|
866 uint32_t Value;
|
|
867
|
|
868 VersionStmt(uint32_t Version) : Value(Version) {}
|
|
869 raw_ostream &log(raw_ostream &) const override;
|
|
870
|
|
871 Twine getResourceTypeName() const override { return "VERSION"; }
|
|
872 Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
|
|
873 };
|
|
874
|
|
875 // CAPTION optional statement.
|
|
876 //
|
|
877 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
|
|
878 class CaptionStmt : public OptionalStmt {
|
|
879 public:
|
|
880 StringRef Value;
|
|
881
|
|
882 CaptionStmt(StringRef Caption) : Value(Caption) {}
|
|
883 raw_ostream &log(raw_ostream &) const override;
|
|
884 Twine getResourceTypeName() const override { return "CAPTION"; }
|
|
885 Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
|
|
886 };
|
|
887
|
|
888 // FONT optional statement.
|
|
889 // Note that the documentation is inaccurate: it expects five arguments to be
|
|
890 // given, however the example provides only two. In fact, the original tool
|
|
891 // expects two arguments - point size and name of the typeface.
|
|
892 //
|
|
893 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx
|
|
894 class FontStmt : public OptionalStmt {
|
|
895 public:
|
|
896 uint32_t Size, Weight, Charset;
|
|
897 StringRef Name;
|
|
898 bool Italic;
|
|
899
|
|
900 FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
|
|
901 bool FontItalic, uint32_t FontCharset)
|
|
902 : Size(FontSize), Weight(FontWeight), Charset(FontCharset),
|
|
903 Name(FontName), Italic(FontItalic) {}
|
|
904 raw_ostream &log(raw_ostream &) const override;
|
|
905 Twine getResourceTypeName() const override { return "FONT"; }
|
|
906 Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
|
|
907 };
|
|
908
|
|
909 // STYLE optional statement.
|
|
910 //
|
|
911 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
|
|
912 class StyleStmt : public OptionalStmt {
|
|
913 public:
|
|
914 uint32_t Value;
|
|
915
|
|
916 StyleStmt(uint32_t Style) : Value(Style) {}
|
|
917 raw_ostream &log(raw_ostream &) const override;
|
|
918 Twine getResourceTypeName() const override { return "STYLE"; }
|
|
919 Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
|
|
920 };
|
|
921
|
147
|
922 // EXSTYLE optional statement.
|
|
923 //
|
|
924 // Ref: docs.microsoft.com/en-us/windows/desktop/menurc/exstyle-statement
|
|
925 class ExStyleStmt : public OptionalStmt {
|
|
926 public:
|
|
927 uint32_t Value;
|
|
928
|
|
929 ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {}
|
|
930 raw_ostream &log(raw_ostream &) const override;
|
|
931 Twine getResourceTypeName() const override { return "EXSTYLE"; }
|
|
932 Error visit(Visitor *V) const override { return V->visitExStyleStmt(this); }
|
|
933 };
|
|
934
|
|
935 // CLASS optional statement.
|
|
936 //
|
|
937 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380883(v=vs.85).aspx
|
|
938 class ClassStmt : public OptionalStmt {
|
|
939 public:
|
|
940 IntOrString Value;
|
|
941
|
|
942 ClassStmt(IntOrString Class) : Value(Class) {}
|
|
943 raw_ostream &log(raw_ostream &) const override;
|
|
944 Twine getResourceTypeName() const override { return "CLASS"; }
|
|
945 Error visit(Visitor *V) const override { return V->visitClassStmt(this); }
|
|
946 };
|
|
947
|
121
|
948 } // namespace rc
|
|
949 } // namespace llvm
|
|
950
|
|
951 #endif
|