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