forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			952 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			952 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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<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(std::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<IntWithNotMask> Style;
 | |
|   Optional<uint32_t> 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<IntWithNotMask> 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); }
 | |
| };
 | |
| 
 | |
| // 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
 |