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