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