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