brintos

brintos / llvm-project-archived public Read only

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