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