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