| //===-- ResourceScriptStmt.h ------------------------------------*- C++-*-===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===---------------------------------------------------------------------===// | |
| // | |
| // This lists all the resource and statement types occurring in RC scripts. | |
| // | |
| //===---------------------------------------------------------------------===// | |
| #ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H | |
| #define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H | |
| #include "ResourceScriptToken.h" | |
| #include "ResourceVisitor.h" | |
| #include "llvm/ADT/StringSet.h" | |
| namespace llvm { | |
| namespace rc { | |
| // Integer wrapper that also holds information whether the user declared | |
| // the integer to be long (by appending L to the end of the integer) or not. | |
| // It allows to be implicitly cast from and to uint32_t in order | |
| // to be compatible with the parts of code that don't care about the integers | |
| // being marked long. | |
| class RCInt { | |
| uint32_t Val; | |
| bool Long; | |
| public: | |
| RCInt(const RCToken &Token) | |
| : Val(Token.intValue()), Long(Token.isLongInt()) {} | |
| RCInt(uint32_t Value) : Val(Value), Long(false) {} | |
| RCInt(uint32_t Value, bool IsLong) : Val(Value), Long(IsLong) {} | |
| operator uint32_t() const { return Val; } | |
| bool isLong() const { return Long; } | |
| RCInt &operator+=(const RCInt &Rhs) { | |
| std::tie(Val, Long) = std::make_pair(Val + Rhs.Val, Long | Rhs.Long); | |
| return *this; | |
| } | |
| RCInt &operator-=(const RCInt &Rhs) { | |
| std::tie(Val, Long) = std::make_pair(Val - Rhs.Val, Long | Rhs.Long); | |
| return *this; | |
| } | |
| RCInt &operator|=(const RCInt &Rhs) { | |
| std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long); | |
| return *this; | |
| } | |
| RCInt &operator&=(const RCInt &Rhs) { | |
| std::tie(Val, Long) = std::make_pair(Val & Rhs.Val, Long | Rhs.Long); | |
| return *this; | |
| } | |
| RCInt operator-() const { return {-Val, Long}; } | |
| RCInt operator~() const { return {~Val, Long}; } | |
| friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) { | |
| return OS << Int.Val << (Int.Long ? "L" : ""); | |
| } | |
| }; | |
| // A class holding a name - either an integer or a reference to the string. | |
| class IntOrString { | |
| private: | |
| union Data { | |
| RCInt Int; | |
| StringRef String; | |
| Data(RCInt Value) : Int(Value) {} | |
| Data(const StringRef Value) : String(Value) {} | |
| Data(const RCToken &Token) { | |
| if (Token.kind() == RCToken::Kind::Int) | |
| Int = RCInt(Token); | |
| else | |
| String = Token.value(); | |
| } | |
| } Data; | |
| bool IsInt; | |
| public: | |
| IntOrString() : IntOrString(RCInt(0)) {} | |
| IntOrString(uint32_t Value) : Data(Value), IsInt(1) {} | |
| IntOrString(RCInt Value) : Data(Value), IsInt(1) {} | |
| IntOrString(StringRef Value) : Data(Value), IsInt(0) {} | |
| IntOrString(const RCToken &Token) | |
| : Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {} | |
| bool equalsLower(const char *Str) { | |
| return !IsInt && Data.String.equals_lower(Str); | |
| } | |
| bool isInt() const { return IsInt; } | |
| RCInt getInt() const { | |
| assert(IsInt); | |
| return Data.Int; | |
| } | |
| const StringRef &getString() const { | |
| assert(!IsInt); | |
| return Data.String; | |
| } | |
| operator Twine() const { | |
| return isInt() ? Twine(getInt()) : Twine(getString()); | |
| } | |
| friend raw_ostream &operator<<(raw_ostream &, const IntOrString &); | |
| }; | |
| enum ResourceKind { | |
| // These resource kinds have corresponding .res resource type IDs | |
| // (TYPE in RESOURCEHEADER structure). The numeric value assigned to each | |
| // kind is equal to this type ID. | |
| RkNull = 0, | |
| RkSingleCursor = 1, | |
| RkBitmap = 2, | |
| RkSingleIcon = 3, | |
| RkMenu = 4, | |
| RkDialog = 5, | |
| RkStringTableBundle = 6, | |
| RkAccelerators = 9, | |
| RkRcData = 10, | |
| RkCursorGroup = 12, | |
| RkIconGroup = 14, | |
| RkVersionInfo = 16, | |
| RkHTML = 23, | |
| // These kinds don't have assigned type IDs (they might be the resources | |
| // of invalid kind, expand to many resource structures in .res files, | |
| // or have variable type ID). In order to avoid ID clashes with IDs above, | |
| // we assign the kinds the values 256 and larger. | |
| RkInvalid = 256, | |
| RkBase, | |
| RkCursor, | |
| RkIcon, | |
| RkStringTable, | |
| RkUser, | |
| RkSingleCursorOrIconRes, | |
| RkCursorOrIconGroupRes, | |
| }; | |
| // Non-zero memory flags. | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx | |
| enum MemoryFlags { | |
| MfMoveable = 0x10, | |
| MfPure = 0x20, | |
| MfPreload = 0x40, | |
| MfDiscardable = 0x1000 | |
| }; | |
| // Base resource. All the resources should derive from this base. | |
| class RCResource { | |
| public: | |
| IntOrString ResName; | |
| uint16_t MemoryFlags = getDefaultMemoryFlags(); | |
| void setName(const IntOrString &Name) { ResName = Name; } | |
| virtual raw_ostream &log(raw_ostream &OS) const { | |
| return OS << "Base statement\n"; | |
| }; | |
| RCResource() {} | |
| RCResource(uint16_t Flags) : MemoryFlags(Flags) {} | |
| virtual ~RCResource() {} | |
| virtual Error visit(Visitor *) const { | |
| llvm_unreachable("This is unable to call methods from Visitor base"); | |
| } | |
| // Apply the statements attached to this resource. Generic resources | |
| // don't have any. | |
| virtual Error applyStmts(Visitor *) const { return Error::success(); } | |
| // By default, memory flags are DISCARDABLE | PURE | MOVEABLE. | |
| static uint16_t getDefaultMemoryFlags() { | |
| return MfDiscardable | MfPure | MfMoveable; | |
| } | |
| virtual ResourceKind getKind() const { return RkBase; } | |
| static bool classof(const RCResource *Res) { return true; } | |
| virtual IntOrString getResourceType() const { | |
| llvm_unreachable("This cannot be called on objects without types."); | |
| } | |
| virtual Twine getResourceTypeName() const { | |
| llvm_unreachable("This cannot be called on objects without types."); | |
| }; | |
| }; | |
| // An empty resource. It has no content, type 0, ID 0 and all of its | |
| // characteristics are equal to 0. | |
| class NullResource : public RCResource { | |
| public: | |
| NullResource() : RCResource(0) {} | |
| raw_ostream &log(raw_ostream &OS) const override { | |
| return OS << "Null resource\n"; | |
| } | |
| Error visit(Visitor *V) const override { return V->visitNullResource(this); } | |
| IntOrString getResourceType() const override { return 0; } | |
| Twine getResourceTypeName() const override { return "(NULL)"; } | |
| }; | |
| // Optional statement base. All such statements should derive from this base. | |
| class OptionalStmt : public RCResource {}; | |
| class OptionalStmtList : public OptionalStmt { | |
| std::vector<std::unique_ptr<OptionalStmt>> Statements; | |
| public: | |
| OptionalStmtList() {} | |
| raw_ostream &log(raw_ostream &OS) const override; | |
| void addStmt(std::unique_ptr<OptionalStmt> Stmt) { | |
| Statements.push_back(std::move(Stmt)); | |
| } | |
| Error visit(Visitor *V) const override { | |
| for (auto &StmtPtr : Statements) | |
| if (auto Err = StmtPtr->visit(V)) | |
| return Err; | |
| return Error::success(); | |
| } | |
| }; | |
| class OptStatementsRCResource : public RCResource { | |
| public: | |
| std::unique_ptr<OptionalStmtList> OptStatements; | |
| OptStatementsRCResource(OptionalStmtList &&Stmts, | |
| uint16_t Flags = RCResource::getDefaultMemoryFlags()) | |
| : RCResource(Flags), | |
| OptStatements(llvm::make_unique<OptionalStmtList>(std::move(Stmts))) {} | |
| virtual Error applyStmts(Visitor *V) const { return OptStatements->visit(V); } | |
| }; | |
| // LANGUAGE statement. It can occur both as a top-level statement (in such | |
| // a situation, it changes the default language until the end of the file) | |
| // and as an optional resource statement (then it changes the language | |
| // of a single resource). | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx | |
| class LanguageResource : public OptionalStmt { | |
| public: | |
| uint32_t Lang, SubLang; | |
| LanguageResource(uint32_t LangId, uint32_t SubLangId) | |
| : Lang(LangId), SubLang(SubLangId) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| // This is not a regular top-level statement; when it occurs, it just | |
| // modifies the language context. | |
| Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); } | |
| Twine getResourceTypeName() const override { return "LANGUAGE"; } | |
| }; | |
| // ACCELERATORS resource. Defines a named table of accelerators for the app. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx | |
| class AcceleratorsResource : public OptStatementsRCResource { | |
| public: | |
| class Accelerator { | |
| public: | |
| IntOrString Event; | |
| uint32_t Id; | |
| uint16_t Flags; | |
| enum Options { | |
| // This is actually 0x0000 (accelerator is assumed to be ASCII if it's | |
| // not VIRTKEY). However, rc.exe behavior is different in situations | |
| // "only ASCII defined" and "neither ASCII nor VIRTKEY defined". | |
| // Therefore, we include ASCII as another flag. This must be zeroed | |
| // when serialized. | |
| ASCII = 0x8000, | |
| VIRTKEY = 0x0001, | |
| NOINVERT = 0x0002, | |
| ALT = 0x0010, | |
| SHIFT = 0x0004, | |
| CONTROL = 0x0008 | |
| }; | |
| static constexpr size_t NumFlags = 6; | |
| static StringRef OptionsStr[NumFlags]; | |
| static uint32_t OptionsFlags[NumFlags]; | |
| }; | |
| AcceleratorsResource(OptionalStmtList &&List, uint16_t Flags) | |
| : OptStatementsRCResource(std::move(List), Flags) {} | |
| std::vector<Accelerator> Accelerators; | |
| void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) { | |
| Accelerators.push_back(Accelerator{Event, Id, Flags}); | |
| } | |
| raw_ostream &log(raw_ostream &) const override; | |
| IntOrString getResourceType() const override { return RkAccelerators; } | |
| static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; } | |
| Twine getResourceTypeName() const override { return "ACCELERATORS"; } | |
| Error visit(Visitor *V) const override { | |
| return V->visitAcceleratorsResource(this); | |
| } | |
| ResourceKind getKind() const override { return RkAccelerators; } | |
| static bool classof(const RCResource *Res) { | |
| return Res->getKind() == RkAccelerators; | |
| } | |
| }; | |
| // BITMAP resource. Represents a bitmap (".bmp") file. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx | |
| class BitmapResource : public RCResource { | |
| public: | |
| StringRef BitmapLoc; | |
| BitmapResource(StringRef Location, uint16_t Flags) | |
| : RCResource(Flags), BitmapLoc(Location) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| IntOrString getResourceType() const override { return RkBitmap; } | |
| static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; } | |
| Twine getResourceTypeName() const override { return "BITMAP"; } | |
| Error visit(Visitor *V) const override { | |
| return V->visitBitmapResource(this); | |
| } | |
| ResourceKind getKind() const override { return RkBitmap; } | |
| static bool classof(const RCResource *Res) { | |
| return Res->getKind() == RkBitmap; | |
| } | |
| }; | |
| // CURSOR resource. Represents a single cursor (".cur") file. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx | |
| class CursorResource : public RCResource { | |
| public: | |
| StringRef CursorLoc; | |
| CursorResource(StringRef Location, uint16_t Flags) | |
| : RCResource(Flags), CursorLoc(Location) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| Twine getResourceTypeName() const override { return "CURSOR"; } | |
| static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; } | |
| Error visit(Visitor *V) const override { | |
| return V->visitCursorResource(this); | |
| } | |
| ResourceKind getKind() const override { return RkCursor; } | |
| static bool classof(const RCResource *Res) { | |
| return Res->getKind() == RkCursor; | |
| } | |
| }; | |
| // ICON resource. Represents a single ".ico" file containing a group of icons. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx | |
| class IconResource : public RCResource { | |
| public: | |
| StringRef IconLoc; | |
| IconResource(StringRef Location, uint16_t Flags) | |
| : RCResource(Flags), IconLoc(Location) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| Twine getResourceTypeName() const override { return "ICON"; } | |
| static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; } | |
| Error visit(Visitor *V) const override { return V->visitIconResource(this); } | |
| ResourceKind getKind() const override { return RkIcon; } | |
| static bool classof(const RCResource *Res) { | |
| return Res->getKind() == RkIcon; | |
| } | |
| }; | |
| // HTML resource. Represents a local webpage that is to be embedded into the | |
| // resulting resource file. It embeds a file only - no additional resources | |
| // (images etc.) are included with this resource. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx | |
| class HTMLResource : public RCResource { | |
| public: | |
| StringRef HTMLLoc; | |
| HTMLResource(StringRef Location, uint16_t Flags) | |
| : RCResource(Flags), HTMLLoc(Location) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| Error visit(Visitor *V) const override { return V->visitHTMLResource(this); } | |
| // Curiously, file resources don't have DISCARDABLE flag set. | |
| static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; } | |
| IntOrString getResourceType() const override { return RkHTML; } | |
| Twine getResourceTypeName() const override { return "HTML"; } | |
| ResourceKind getKind() const override { return RkHTML; } | |
| static bool classof(const RCResource *Res) { | |
| return Res->getKind() == RkHTML; | |
| } | |
| }; | |
| // -- MENU resource and its helper classes -- | |
| // This resource describes the contents of an application menu | |
| // (usually located in the upper part of the dialog.) | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx | |
| // Description of a single submenu item. | |
| class MenuDefinition { | |
| public: | |
| enum Options { | |
| CHECKED = 0x0008, | |
| GRAYED = 0x0001, | |
| HELP = 0x4000, | |
| INACTIVE = 0x0002, | |
| MENUBARBREAK = 0x0020, | |
| MENUBREAK = 0x0040 | |
| }; | |
| enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup }; | |
| static constexpr size_t NumFlags = 6; | |
| static StringRef OptionsStr[NumFlags]; | |
| static uint32_t OptionsFlags[NumFlags]; | |
| static raw_ostream &logFlags(raw_ostream &, uint16_t Flags); | |
| virtual raw_ostream &log(raw_ostream &OS) const { | |
| return OS << "Base menu definition\n"; | |
| } | |
| virtual ~MenuDefinition() {} | |
| virtual uint16_t getResFlags() const { return 0; } | |
| virtual MenuDefKind getKind() const { return MkBase; } | |
| }; | |
| // Recursive description of a whole submenu. | |
| class MenuDefinitionList : public MenuDefinition { | |
| public: | |
| std::vector<std::unique_ptr<MenuDefinition>> Definitions; | |
| void addDefinition(std::unique_ptr<MenuDefinition> Def) { | |
| Definitions.push_back(std::move(Def)); | |
| } | |
| raw_ostream &log(raw_ostream &) const override; | |
| }; | |
| // Separator in MENU definition (MENUITEM SEPARATOR). | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx | |
| class MenuSeparator : public MenuDefinition { | |
| public: | |
| raw_ostream &log(raw_ostream &) const override; | |
| MenuDefKind getKind() const override { return MkSeparator; } | |
| static bool classof(const MenuDefinition *D) { | |
| return D->getKind() == MkSeparator; | |
| } | |
| }; | |
| // MENUITEM statement definition. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx | |
| class MenuItem : public MenuDefinition { | |
| public: | |
| StringRef Name; | |
| uint32_t Id; | |
| uint16_t Flags; | |
| MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags) | |
| : Name(Caption), Id(ItemId), Flags(ItemFlags) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| uint16_t getResFlags() const override { return Flags; } | |
| MenuDefKind getKind() const override { return MkMenuItem; } | |
| static bool classof(const MenuDefinition *D) { | |
| return D->getKind() == MkMenuItem; | |
| } | |
| }; | |
| // POPUP statement definition. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx | |
| class PopupItem : public MenuDefinition { | |
| public: | |
| StringRef Name; | |
| uint16_t Flags; | |
| MenuDefinitionList SubItems; | |
| PopupItem(StringRef Caption, uint16_t ItemFlags, | |
| MenuDefinitionList &&SubItemsList) | |
| : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| // This has an additional (0x10) flag. It doesn't match with documented | |
| // 0x01 flag, though. | |
| uint16_t getResFlags() const override { return Flags | 0x10; } | |
| MenuDefKind getKind() const override { return MkPopup; } | |
| static bool classof(const MenuDefinition *D) { | |
| return D->getKind() == MkPopup; | |
| } | |
| }; | |
| // Menu resource definition. | |
| class MenuResource : public OptStatementsRCResource { | |
| public: | |
| MenuDefinitionList Elements; | |
| MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items, | |
| uint16_t Flags) | |
| : OptStatementsRCResource(std::move(OptStmts), Flags), | |
| Elements(std::move(Items)) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| IntOrString getResourceType() const override { return RkMenu; } | |
| Twine getResourceTypeName() const override { return "MENU"; } | |
| Error visit(Visitor *V) const override { return V->visitMenuResource(this); } | |
| ResourceKind getKind() const override { return RkMenu; } | |
| static bool classof(const RCResource *Res) { | |
| return Res->getKind() == RkMenu; | |
| } | |
| }; | |
| // STRINGTABLE resource. Contains a list of strings, each having its unique ID. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx | |
| class StringTableResource : public OptStatementsRCResource { | |
| public: | |
| std::vector<std::pair<uint32_t, StringRef>> Table; | |
| StringTableResource(OptionalStmtList &&List, uint16_t Flags) | |
| : OptStatementsRCResource(std::move(List), Flags) {} | |
| void addString(uint32_t ID, StringRef String) { | |
| Table.emplace_back(ID, String); | |
| } | |
| raw_ostream &log(raw_ostream &) const override; | |
| Twine getResourceTypeName() const override { return "STRINGTABLE"; } | |
| Error visit(Visitor *V) const override { | |
| return V->visitStringTableResource(this); | |
| } | |
| }; | |
| // -- DIALOG(EX) resource and its helper classes -- | |
| // | |
| // This resource describes dialog boxes and controls residing inside them. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx | |
| // Single control definition. | |
| class Control { | |
| public: | |
| StringRef Type; | |
| IntOrString Title; | |
| uint32_t ID, X, Y, Width, Height; | |
| Optional<uint32_t> Style, ExtStyle, HelpID; | |
| IntOrString Class; | |
| // Control classes as described in DLGITEMTEMPLATEEX documentation. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx | |
| enum CtlClasses { | |
| ClsButton = 0x80, | |
| ClsEdit = 0x81, | |
| ClsStatic = 0x82, | |
| ClsListBox = 0x83, | |
| ClsScrollBar = 0x84, | |
| ClsComboBox = 0x85 | |
| }; | |
| // Simple information about a single control type. | |
| struct CtlInfo { | |
| uint32_t Style; | |
| uint16_t CtlClass; | |
| bool HasTitle; | |
| }; | |
| Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID, | |
| uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight, | |
| Optional<uint32_t> ItemStyle, Optional<uint32_t> ExtItemStyle, | |
| Optional<uint32_t> CtlHelpID, IntOrString CtlClass) | |
| : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY), | |
| Width(ItemWidth), Height(ItemHeight), Style(ItemStyle), | |
| ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {} | |
| static const StringMap<CtlInfo> SupportedCtls; | |
| raw_ostream &log(raw_ostream &) const; | |
| }; | |
| // Single dialog definition. We don't create distinct classes for DIALOG and | |
| // DIALOGEX because of their being too similar to each other. We only have a | |
| // flag determining the type of the dialog box. | |
| class DialogResource : public OptStatementsRCResource { | |
| public: | |
| uint32_t X, Y, Width, Height, HelpID; | |
| std::vector<Control> Controls; | |
| bool IsExtended; | |
| DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth, | |
| uint32_t DlgHeight, uint32_t DlgHelpID, | |
| OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags) | |
| : OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY), | |
| Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID), | |
| IsExtended(IsDialogEx) {} | |
| void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); } | |
| raw_ostream &log(raw_ostream &) const override; | |
| // It was a weird design decision to assign the same resource type number | |
| // both for DIALOG and DIALOGEX (and the same structure version number). | |
| // It makes it possible for DIALOG to be mistaken for DIALOGEX. | |
| IntOrString getResourceType() const override { return RkDialog; } | |
| Twine getResourceTypeName() const override { | |
| return "DIALOG" + Twine(IsExtended ? "EX" : ""); | |
| } | |
| Error visit(Visitor *V) const override { | |
| return V->visitDialogResource(this); | |
| } | |
| ResourceKind getKind() const override { return RkDialog; } | |
| static bool classof(const RCResource *Res) { | |
| return Res->getKind() == RkDialog; | |
| } | |
| }; | |
| // User-defined resource. It is either: | |
| // * a link to the file, e.g. NAME TYPE "filename", | |
| // * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}. | |
| class UserDefinedResource : public RCResource { | |
| public: | |
| IntOrString Type; | |
| StringRef FileLoc; | |
| std::vector<IntOrString> Contents; | |
| bool IsFileResource; | |
| UserDefinedResource(IntOrString ResourceType, StringRef FileLocation, | |
| uint16_t Flags) | |
| : RCResource(Flags), Type(ResourceType), FileLoc(FileLocation), | |
| IsFileResource(true) {} | |
| UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data, | |
| uint16_t Flags) | |
| : RCResource(Flags), Type(ResourceType), Contents(std::move(Data)), | |
| IsFileResource(false) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| IntOrString getResourceType() const override { return Type; } | |
| Twine getResourceTypeName() const override { return Type; } | |
| static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; } | |
| Error visit(Visitor *V) const override { | |
| return V->visitUserDefinedResource(this); | |
| } | |
| ResourceKind getKind() const override { return RkUser; } | |
| static bool classof(const RCResource *Res) { | |
| return Res->getKind() == RkUser; | |
| } | |
| }; | |
| // -- VERSIONINFO resource and its helper classes -- | |
| // | |
| // This resource lists the version information on the executable/library. | |
| // The declaration consists of the following items: | |
| // * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS) | |
| // * BEGIN | |
| // * A number of BLOCK and/or VALUE statements. BLOCK recursively defines | |
| // another block of version information, whereas VALUE defines a | |
| // key -> value correspondence. There might be more than one value | |
| // corresponding to the single key. | |
| // * END | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx | |
| // A single VERSIONINFO statement; | |
| class VersionInfoStmt { | |
| public: | |
| enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 }; | |
| virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; } | |
| virtual ~VersionInfoStmt() {} | |
| virtual StmtKind getKind() const { return StBase; } | |
| static bool classof(const VersionInfoStmt *S) { | |
| return S->getKind() == StBase; | |
| } | |
| }; | |
| // BLOCK definition; also the main VERSIONINFO declaration is considered a | |
| // BLOCK, although it has no name. | |
| // The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't | |
| // care about them at the parsing phase. | |
| class VersionInfoBlock : public VersionInfoStmt { | |
| public: | |
| std::vector<std::unique_ptr<VersionInfoStmt>> Stmts; | |
| StringRef Name; | |
| VersionInfoBlock(StringRef BlockName) : Name(BlockName) {} | |
| void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) { | |
| Stmts.push_back(std::move(Stmt)); | |
| } | |
| raw_ostream &log(raw_ostream &) const override; | |
| StmtKind getKind() const override { return StBlock; } | |
| static bool classof(const VersionInfoStmt *S) { | |
| return S->getKind() == StBlock; | |
| } | |
| }; | |
| class VersionInfoValue : public VersionInfoStmt { | |
| public: | |
| StringRef Key; | |
| std::vector<IntOrString> Values; | |
| std::vector<bool> HasPrecedingComma; | |
| VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals, | |
| std::vector<bool> &&CommasBeforeVals) | |
| : Key(InfoKey), Values(std::move(Vals)), | |
| HasPrecedingComma(std::move(CommasBeforeVals)) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| StmtKind getKind() const override { return StValue; } | |
| static bool classof(const VersionInfoStmt *S) { | |
| return S->getKind() == StValue; | |
| } | |
| }; | |
| class VersionInfoResource : public RCResource { | |
| public: | |
| // A class listing fixed VERSIONINFO statements (occuring before main BEGIN). | |
| // If any of these is not specified, it is assumed by the original tool to | |
| // be equal to 0. | |
| class VersionInfoFixed { | |
| public: | |
| enum VersionInfoFixedType { | |
| FtUnknown, | |
| FtFileVersion, | |
| FtProductVersion, | |
| FtFileFlagsMask, | |
| FtFileFlags, | |
| FtFileOS, | |
| FtFileType, | |
| FtFileSubtype, | |
| FtNumTypes | |
| }; | |
| private: | |
| static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap; | |
| static const StringRef FixedFieldsNames[FtNumTypes]; | |
| public: | |
| SmallVector<uint32_t, 4> FixedInfo[FtNumTypes]; | |
| SmallVector<bool, FtNumTypes> IsTypePresent; | |
| static VersionInfoFixedType getFixedType(StringRef Type); | |
| static bool isTypeSupported(VersionInfoFixedType Type); | |
| static bool isVersionType(VersionInfoFixedType Type); | |
| VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {} | |
| void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) { | |
| FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end()); | |
| IsTypePresent[Type] = true; | |
| } | |
| raw_ostream &log(raw_ostream &) const; | |
| }; | |
| VersionInfoBlock MainBlock; | |
| VersionInfoFixed FixedData; | |
| VersionInfoResource(VersionInfoBlock &&TopLevelBlock, | |
| VersionInfoFixed &&FixedInfo, uint16_t Flags) | |
| : RCResource(Flags), MainBlock(std::move(TopLevelBlock)), | |
| FixedData(std::move(FixedInfo)) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| IntOrString getResourceType() const override { return RkVersionInfo; } | |
| static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; } | |
| Twine getResourceTypeName() const override { return "VERSIONINFO"; } | |
| Error visit(Visitor *V) const override { | |
| return V->visitVersionInfoResource(this); | |
| } | |
| ResourceKind getKind() const override { return RkVersionInfo; } | |
| static bool classof(const RCResource *Res) { | |
| return Res->getKind() == RkVersionInfo; | |
| } | |
| }; | |
| // CHARACTERISTICS optional statement. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx | |
| class CharacteristicsStmt : public OptionalStmt { | |
| public: | |
| uint32_t Value; | |
| CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| Twine getResourceTypeName() const override { return "CHARACTERISTICS"; } | |
| Error visit(Visitor *V) const override { | |
| return V->visitCharacteristicsStmt(this); | |
| } | |
| }; | |
| // VERSION optional statement. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx | |
| class VersionStmt : public OptionalStmt { | |
| public: | |
| uint32_t Value; | |
| VersionStmt(uint32_t Version) : Value(Version) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| Twine getResourceTypeName() const override { return "VERSION"; } | |
| Error visit(Visitor *V) const override { return V->visitVersionStmt(this); } | |
| }; | |
| // CAPTION optional statement. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx | |
| class CaptionStmt : public OptionalStmt { | |
| public: | |
| StringRef Value; | |
| CaptionStmt(StringRef Caption) : Value(Caption) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| Twine getResourceTypeName() const override { return "CAPTION"; } | |
| Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); } | |
| }; | |
| // FONT optional statement. | |
| // Note that the documentation is inaccurate: it expects five arguments to be | |
| // given, however the example provides only two. In fact, the original tool | |
| // expects two arguments - point size and name of the typeface. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx | |
| class FontStmt : public OptionalStmt { | |
| public: | |
| uint32_t Size, Weight, Charset; | |
| StringRef Name; | |
| bool Italic; | |
| FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight, | |
| bool FontItalic, uint32_t FontCharset) | |
| : Size(FontSize), Weight(FontWeight), Charset(FontCharset), | |
| Name(FontName), Italic(FontItalic) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| Twine getResourceTypeName() const override { return "FONT"; } | |
| Error visit(Visitor *V) const override { return V->visitFontStmt(this); } | |
| }; | |
| // STYLE optional statement. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx | |
| class StyleStmt : public OptionalStmt { | |
| public: | |
| uint32_t Value; | |
| StyleStmt(uint32_t Style) : Value(Style) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| Twine getResourceTypeName() const override { return "STYLE"; } | |
| Error visit(Visitor *V) const override { return V->visitStyleStmt(this); } | |
| }; | |
| // CLASS optional statement. | |
| // | |
| // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380883(v=vs.85).aspx | |
| class ClassStmt : public OptionalStmt { | |
| public: | |
| IntOrString Value; | |
| ClassStmt(IntOrString Class) : Value(Class) {} | |
| raw_ostream &log(raw_ostream &) const override; | |
| Twine getResourceTypeName() const override { return "CLASS"; } | |
| Error visit(Visitor *V) const override { return V->visitClassStmt(this); } | |
| }; | |
| } // namespace rc | |
| } // namespace llvm | |
| #endif |