summaryrefslogtreecommitdiff
path: root/tools/llvm-rc/ResourceScriptStmt.h
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-rc/ResourceScriptStmt.h')
-rw-r--r--tools/llvm-rc/ResourceScriptStmt.h827
1 files changed, 827 insertions, 0 deletions
diff --git a/tools/llvm-rc/ResourceScriptStmt.h b/tools/llvm-rc/ResourceScriptStmt.h
new file mode 100644
index 000000000000..e44120b770f3
--- /dev/null
+++ b/tools/llvm-rc/ResourceScriptStmt.h
@@ -0,0 +1,827 @@
+//===-- 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,
+ RkSingleIcon = 3,
+ RkMenu = 4,
+ RkDialog = 5,
+ RkStringTableBundle = 6,
+ RkAccelerators = 9,
+ 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;
+ void setName(const IntOrString &Name) { ResName = Name; }
+ virtual raw_ostream &log(raw_ostream &OS) const {
+ return OS << "Base statement\n";
+ };
+ 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.
+ virtual uint16_t getMemoryFlags() const {
+ 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:
+ 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)"; }
+ uint16_t getMemoryFlags() const override { return 0; }
+};
+
+// 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)
+ : 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];
+ };
+
+ std::vector<Accelerator> Accelerators;
+
+ using OptStatementsRCResource::OptStatementsRCResource;
+ 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; }
+ uint16_t getMemoryFlags() const override {
+ 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;
+ }
+};
+
+// 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) : CursorLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "CURSOR"; }
+ 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) : IconLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "ICON"; }
+ 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) : 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.
+ uint16_t getMemoryFlags() const override { 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)
+ : OptStatementsRCResource(std::move(OptStmts)),
+ 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;
+
+ using OptStatementsRCResource::OptStatementsRCResource;
+ 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;
+
+ // 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)
+ : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
+ Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
+ ExtStyle(ExtItemStyle), HelpID(CtlHelpID) {}
+
+ 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)
+ : OptStatementsRCResource(std::move(OptStmts)), 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)
+ : Type(ResourceType), FileLoc(FileLocation), IsFileResource(true) {}
+ UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data)
+ : 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; }
+ uint16_t getMemoryFlags() const override { 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)
+ : MainBlock(std::move(TopLevelBlock)), FixedData(std::move(FixedInfo)) {}
+
+ raw_ostream &log(raw_ostream &) const override;
+ IntOrString getResourceType() const override { return RkVersionInfo; }
+ uint16_t getMemoryFlags() const override { 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); }
+};
+
+} // namespace rc
+} // namespace llvm
+
+#endif