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