//===-- ResourceScriptStmt.h ------------------------------------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===---------------------------------------------------------------------===// // // 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" : ""); } }; class IntWithNotMask { private: RCInt Value; int32_t NotMask; public: IntWithNotMask() : IntWithNotMask(RCInt(0)) {} IntWithNotMask(RCInt Value, int32_t NotMask = 0) : Value(Value), NotMask(NotMask) {} RCInt getValue() const { return Value; } uint32_t getNotMask() const { return NotMask; } IntWithNotMask &operator+=(const IntWithNotMask &Rhs) { Value &= ~Rhs.NotMask; Value += Rhs.Value; NotMask |= Rhs.NotMask; return *this; } IntWithNotMask &operator-=(const IntWithNotMask &Rhs) { Value &= ~Rhs.NotMask; Value -= Rhs.Value; NotMask |= Rhs.NotMask; return *this; } IntWithNotMask &operator|=(const IntWithNotMask &Rhs) { Value &= ~Rhs.NotMask; Value |= Rhs.Value; NotMask |= Rhs.NotMask; return *this; } IntWithNotMask &operator&=(const IntWithNotMask &Rhs) { Value &= ~Rhs.NotMask; Value &= Rhs.Value; NotMask |= Rhs.NotMask; return *this; } IntWithNotMask operator-() const { return {-Value, NotMask}; } IntWithNotMask operator~() const { return {~Value, 0}; } friend raw_ostream &operator<<(raw_ostream &OS, const IntWithNotMask &Int) { return OS << Int.Value; } }; // 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> Statements; public: OptionalStmtList() {} raw_ostream &log(raw_ostream &OS) const override; void addStmt(std::unique_ptr 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 OptStatements; OptStatementsRCResource(OptionalStmtList &&Stmts, uint16_t Flags = RCResource::getDefaultMemoryFlags()) : RCResource(Flags), OptStatements(std::make_unique(std::move(Stmts))) {} Error applyStmts(Visitor *V) const override { 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 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> Definitions; void addDefinition(std::unique_ptr 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>> Table; StringTableResource(OptionalStmtList &&List, uint16_t Flags) : OptStatementsRCResource(std::move(List), Flags) {} void addStrings(uint32_t ID, std::vector &&Strings) { Table.emplace_back(ID, Strings); } 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 Style; Optional 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 ItemStyle, Optional ExtItemStyle, Optional 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 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 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 Contents; bool IsFileResource; UserDefinedResource(IntOrString ResourceType, StringRef FileLocation, uint16_t Flags) : RCResource(Flags), Type(ResourceType), FileLoc(FileLocation), IsFileResource(true) {} UserDefinedResource(IntOrString ResourceType, std::vector &&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> Stmts; StringRef Name; VersionInfoBlock(StringRef BlockName) : Name(BlockName) {} void addStmt(std::unique_ptr 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 Values; std::vector HasPrecedingComma; VersionInfoValue(StringRef InfoKey, std::vector &&Vals, std::vector &&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 FixedFieldsInfoMap; static const StringRef FixedFieldsNames[FtNumTypes]; public: SmallVector FixedInfo[FtNumTypes]; SmallVector 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 Value) { FixedInfo[Type] = SmallVector(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); } }; // EXSTYLE optional statement. // // Ref: docs.microsoft.com/en-us/windows/desktop/menurc/exstyle-statement class ExStyleStmt : public OptionalStmt { public: uint32_t Value; ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {} raw_ostream &log(raw_ostream &) const override; Twine getResourceTypeName() const override { return "EXSTYLE"; } Error visit(Visitor *V) const override { return V->visitExStyleStmt(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