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:
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 
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 
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,
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();
216   void setName(const IntOrString &Name) { ResName = Name; }
217   virtual raw_ostream &log(raw_ostream &OS) const {
218     return OS << "Base statement\n";
219   };
220   RCResource() {}
221   RCResource(uint16_t Flags) : MemoryFlags(Flags) {}
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.
233   static uint16_t getDefaultMemoryFlags() {
234     return MfDiscardable | MfPure | MfMoveable;
235   }
236 
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:
252   NullResource() : RCResource(0) {}
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 
287   OptStatementsRCResource(OptionalStmtList &&Stmts,
288                           uint16_t Flags = RCResource::getDefaultMemoryFlags())
289       : RCResource(Flags),
290         OptStatements(std::make_unique<OptionalStmtList>(std::move(Stmts))) {}
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 
345   AcceleratorsResource(OptionalStmtList &&List, uint16_t Flags)
346       : OptStatementsRCResource(std::move(List), Flags) {}
347 
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; }
356   static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
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 
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 
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 
399   CursorResource(StringRef Location, uint16_t Flags)
400       : RCResource(Flags), CursorLoc(Location) {}
401   raw_ostream &log(raw_ostream &) const override;
402 
403   Twine getResourceTypeName() const override { return "CURSOR"; }
404   static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
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 
421   IconResource(StringRef Location, uint16_t Flags)
422       : RCResource(Flags), IconLoc(Location) {}
423   raw_ostream &log(raw_ostream &) const override;
424 
425   Twine getResourceTypeName() const override { return "ICON"; }
426   static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
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 
443   HTMLResource(StringRef Location, uint16_t Flags)
444       : RCResource(Flags), HTMLLoc(Location) {}
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.
450   static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
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 
564   MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
565                uint16_t Flags)
566       : OptStatementsRCResource(std::move(OptStmts), Flags),
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 
586   StringTableResource(OptionalStmtList &&List, uint16_t Flags)
587       : OptStatementsRCResource(std::move(List), Flags) {}
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;
611   Optional<IntWithNotMask> Style;
612   Optional<uint32_t> ExtStyle, HelpID;
613   IntOrString Class;
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,
636           Optional<IntWithNotMask> ItemStyle, Optional<uint32_t> ExtItemStyle,
637           Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
638       : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
639         Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
640         ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
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,
658                  OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
659       : OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
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 
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) {}
701 
702   raw_ostream &log(raw_ostream &) const override;
703   IntOrString getResourceType() const override { return Type; }
704   Twine getResourceTypeName() const override { return Type; }
705   static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
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,
828                       VersionInfoFixed &&FixedInfo, uint16_t Flags)
829       : RCResource(Flags), MainBlock(std::move(TopLevelBlock)),
830         FixedData(std::move(FixedInfo)) {}
831 
832   raw_ostream &log(raw_ostream &) const override;
833   IntOrString getResourceType() const override { return RkVersionInfo; }
834   static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
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 
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 
948 } // namespace rc
949 } // namespace llvm
950 
951 #endif
952