1 //===-- ResourceScriptStmt.h ------------------------------------*- C++-*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===---------------------------------------------------------------------===// 9 // 10 // This lists all the resource and statement types occurring in RC scripts. 11 // 12 //===---------------------------------------------------------------------===// 13 14 #ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H 15 #define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H 16 17 #include "ResourceScriptToken.h" 18 #include "ResourceVisitor.h" 19 20 #include "llvm/ADT/StringSet.h" 21 22 namespace llvm { 23 namespace rc { 24 25 // Integer wrapper that also holds information whether the user declared 26 // 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 order 28 // to be compatible with the parts of code that don't care about the integers 29 // being marked long. 30 class RCInt { 31 uint32_t Val; 32 bool Long; 33 34 public: 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 { return {-Val, Long}; } 63 RCInt operator~() const { return {~Val, Long}; } 64 65 friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) { 66 return OS << Int.Val << (Int.Long ? "L" : ""); 67 } 68 }; 69 70 // A class holding a name - either an integer or a reference to the string. 71 class IntOrString { 72 private: 73 union Data { 74 RCInt Int; 75 StringRef String; 76 Data(RCInt Value) : Int(Value) {} 77 Data(const StringRef Value) : String(Value) {} 78 Data(const RCToken &Token) { 79 if (Token.kind() == RCToken::Kind::Int) 80 Int = RCInt(Token); 81 else 82 String = Token.value(); 83 } 84 } Data; 85 bool IsInt; 86 87 public: 88 IntOrString() : IntOrString(RCInt(0)) {} 89 IntOrString(uint32_t Value) : Data(Value), IsInt(1) {} 90 IntOrString(RCInt Value) : Data(Value), IsInt(1) {} 91 IntOrString(StringRef Value) : Data(Value), IsInt(0) {} 92 IntOrString(const RCToken &Token) 93 : Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {} 94 95 bool equalsLower(const char *Str) { 96 return !IsInt && Data.String.equals_lower(Str); 97 } 98 99 bool isInt() const { return IsInt; } 100 101 RCInt getInt() const { 102 assert(IsInt); 103 return Data.Int; 104 } 105 106 const StringRef &getString() const { 107 assert(!IsInt); 108 return Data.String; 109 } 110 111 operator Twine() const { 112 return isInt() ? Twine(getInt()) : Twine(getString()); 113 } 114 115 friend raw_ostream &operator<<(raw_ostream &, const IntOrString &); 116 }; 117 118 enum ResourceKind { 119 // These resource kinds have corresponding .res resource type IDs 120 // (TYPE in RESOURCEHEADER structure). The numeric value assigned to each 121 // kind is equal to this type ID. 122 RkNull = 0, 123 RkSingleCursor = 1, 124 RkSingleIcon = 3, 125 RkMenu = 4, 126 RkDialog = 5, 127 RkStringTableBundle = 6, 128 RkAccelerators = 9, 129 RkCursorGroup = 12, 130 RkIconGroup = 14, 131 RkVersionInfo = 16, 132 RkHTML = 23, 133 134 // These kinds don't have assigned type IDs (they might be the resources 135 // of invalid kind, expand to many resource structures in .res files, 136 // or have variable type ID). In order to avoid ID clashes with IDs above, 137 // we assign the kinds the values 256 and larger. 138 RkInvalid = 256, 139 RkBase, 140 RkCursor, 141 RkIcon, 142 RkStringTable, 143 RkUser, 144 RkSingleCursorOrIconRes, 145 RkCursorOrIconGroupRes, 146 }; 147 148 // Non-zero memory flags. 149 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx 150 enum MemoryFlags { 151 MfMoveable = 0x10, 152 MfPure = 0x20, 153 MfPreload = 0x40, 154 MfDiscardable = 0x1000 155 }; 156 157 // Base resource. All the resources should derive from this base. 158 class RCResource { 159 public: 160 IntOrString ResName; 161 void setName(const IntOrString &Name) { ResName = Name; } 162 virtual raw_ostream &log(raw_ostream &OS) const { 163 return OS << "Base statement\n"; 164 }; 165 virtual ~RCResource() {} 166 167 virtual Error visit(Visitor *) const { 168 llvm_unreachable("This is unable to call methods from Visitor base"); 169 } 170 171 // Apply the statements attached to this resource. Generic resources 172 // don't have any. 173 virtual Error applyStmts(Visitor *) const { return Error::success(); } 174 175 // By default, memory flags are DISCARDABLE | PURE | MOVEABLE. 176 virtual uint16_t getMemoryFlags() const { 177 return MfDiscardable | MfPure | MfMoveable; 178 } 179 virtual ResourceKind getKind() const { return RkBase; } 180 static bool classof(const RCResource *Res) { return true; } 181 182 virtual IntOrString getResourceType() const { 183 llvm_unreachable("This cannot be called on objects without types."); 184 } 185 virtual Twine getResourceTypeName() const { 186 llvm_unreachable("This cannot be called on objects without types."); 187 }; 188 }; 189 190 // An empty resource. It has no content, type 0, ID 0 and all of its 191 // characteristics are equal to 0. 192 class NullResource : public RCResource { 193 public: 194 raw_ostream &log(raw_ostream &OS) const override { 195 return OS << "Null resource\n"; 196 } 197 Error visit(Visitor *V) const override { return V->visitNullResource(this); } 198 IntOrString getResourceType() const override { return 0; } 199 Twine getResourceTypeName() const override { return "(NULL)"; } 200 uint16_t getMemoryFlags() const override { return 0; } 201 }; 202 203 // Optional statement base. All such statements should derive from this base. 204 class OptionalStmt : public RCResource {}; 205 206 class OptionalStmtList : public OptionalStmt { 207 std::vector<std::unique_ptr<OptionalStmt>> Statements; 208 209 public: 210 OptionalStmtList() {} 211 raw_ostream &log(raw_ostream &OS) const override; 212 213 void addStmt(std::unique_ptr<OptionalStmt> Stmt) { 214 Statements.push_back(std::move(Stmt)); 215 } 216 217 Error visit(Visitor *V) const override { 218 for (auto &StmtPtr : Statements) 219 if (auto Err = StmtPtr->visit(V)) 220 return Err; 221 return Error::success(); 222 } 223 }; 224 225 class OptStatementsRCResource : public RCResource { 226 public: 227 std::unique_ptr<OptionalStmtList> OptStatements; 228 229 OptStatementsRCResource(OptionalStmtList &&Stmts) 230 : OptStatements(llvm::make_unique<OptionalStmtList>(std::move(Stmts))) {} 231 232 virtual Error applyStmts(Visitor *V) const { return OptStatements->visit(V); } 233 }; 234 235 // LANGUAGE statement. It can occur both as a top-level statement (in such 236 // a situation, it changes the default language until the end of the file) 237 // and as an optional resource statement (then it changes the language 238 // of a single resource). 239 // 240 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx 241 class LanguageResource : public OptionalStmt { 242 public: 243 uint32_t Lang, SubLang; 244 245 LanguageResource(uint32_t LangId, uint32_t SubLangId) 246 : Lang(LangId), SubLang(SubLangId) {} 247 raw_ostream &log(raw_ostream &) const override; 248 249 // This is not a regular top-level statement; when it occurs, it just 250 // modifies the language context. 251 Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); } 252 Twine getResourceTypeName() const override { return "LANGUAGE"; } 253 }; 254 255 // ACCELERATORS resource. Defines a named table of accelerators for the app. 256 // 257 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx 258 class AcceleratorsResource : public OptStatementsRCResource { 259 public: 260 class Accelerator { 261 public: 262 IntOrString Event; 263 uint32_t Id; 264 uint16_t Flags; 265 266 enum Options { 267 // This is actually 0x0000 (accelerator is assumed to be ASCII if it's 268 // not VIRTKEY). However, rc.exe behavior is different in situations 269 // "only ASCII defined" and "neither ASCII nor VIRTKEY defined". 270 // Therefore, we include ASCII as another flag. This must be zeroed 271 // when serialized. 272 ASCII = 0x8000, 273 VIRTKEY = 0x0001, 274 NOINVERT = 0x0002, 275 ALT = 0x0010, 276 SHIFT = 0x0004, 277 CONTROL = 0x0008 278 }; 279 280 static constexpr size_t NumFlags = 6; 281 static StringRef OptionsStr[NumFlags]; 282 static uint32_t OptionsFlags[NumFlags]; 283 }; 284 285 std::vector<Accelerator> Accelerators; 286 287 using OptStatementsRCResource::OptStatementsRCResource; 288 void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) { 289 Accelerators.push_back(Accelerator{Event, Id, Flags}); 290 } 291 raw_ostream &log(raw_ostream &) const override; 292 293 IntOrString getResourceType() const override { return RkAccelerators; } 294 uint16_t getMemoryFlags() const override { 295 return MfPure | MfMoveable; 296 } 297 Twine getResourceTypeName() const override { return "ACCELERATORS"; } 298 299 Error visit(Visitor *V) const override { 300 return V->visitAcceleratorsResource(this); 301 } 302 ResourceKind getKind() const override { return RkAccelerators; } 303 static bool classof(const RCResource *Res) { 304 return Res->getKind() == RkAccelerators; 305 } 306 }; 307 308 // CURSOR resource. Represents a single cursor (".cur") file. 309 // 310 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx 311 class CursorResource : public RCResource { 312 public: 313 StringRef CursorLoc; 314 315 CursorResource(StringRef Location) : CursorLoc(Location) {} 316 raw_ostream &log(raw_ostream &) const override; 317 318 Twine getResourceTypeName() const override { return "CURSOR"; } 319 Error visit(Visitor *V) const override { 320 return V->visitCursorResource(this); 321 } 322 ResourceKind getKind() const override { return RkCursor; } 323 static bool classof(const RCResource *Res) { 324 return Res->getKind() == RkCursor; 325 } 326 }; 327 328 // ICON resource. Represents a single ".ico" file containing a group of icons. 329 // 330 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx 331 class IconResource : public RCResource { 332 public: 333 StringRef IconLoc; 334 335 IconResource(StringRef Location) : IconLoc(Location) {} 336 raw_ostream &log(raw_ostream &) const override; 337 338 Twine getResourceTypeName() const override { return "ICON"; } 339 Error visit(Visitor *V) const override { return V->visitIconResource(this); } 340 ResourceKind getKind() const override { return RkIcon; } 341 static bool classof(const RCResource *Res) { 342 return Res->getKind() == RkIcon; 343 } 344 }; 345 346 // HTML resource. Represents a local webpage that is to be embedded into the 347 // resulting resource file. It embeds a file only - no additional resources 348 // (images etc.) are included with this resource. 349 // 350 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx 351 class HTMLResource : public RCResource { 352 public: 353 StringRef HTMLLoc; 354 355 HTMLResource(StringRef Location) : HTMLLoc(Location) {} 356 raw_ostream &log(raw_ostream &) const override; 357 358 Error visit(Visitor *V) const override { return V->visitHTMLResource(this); } 359 360 // Curiously, file resources don't have DISCARDABLE flag set. 361 uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; } 362 IntOrString getResourceType() const override { return RkHTML; } 363 Twine getResourceTypeName() const override { return "HTML"; } 364 ResourceKind getKind() const override { return RkHTML; } 365 static bool classof(const RCResource *Res) { 366 return Res->getKind() == RkHTML; 367 } 368 }; 369 370 // -- MENU resource and its helper classes -- 371 // This resource describes the contents of an application menu 372 // (usually located in the upper part of the dialog.) 373 // 374 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx 375 376 // Description of a single submenu item. 377 class MenuDefinition { 378 public: 379 enum Options { 380 CHECKED = 0x0008, 381 GRAYED = 0x0001, 382 HELP = 0x4000, 383 INACTIVE = 0x0002, 384 MENUBARBREAK = 0x0020, 385 MENUBREAK = 0x0040 386 }; 387 388 enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup }; 389 390 static constexpr size_t NumFlags = 6; 391 static StringRef OptionsStr[NumFlags]; 392 static uint32_t OptionsFlags[NumFlags]; 393 static raw_ostream &logFlags(raw_ostream &, uint16_t Flags); 394 virtual raw_ostream &log(raw_ostream &OS) const { 395 return OS << "Base menu definition\n"; 396 } 397 virtual ~MenuDefinition() {} 398 399 virtual uint16_t getResFlags() const { return 0; } 400 virtual MenuDefKind getKind() const { return MkBase; } 401 }; 402 403 // Recursive description of a whole submenu. 404 class MenuDefinitionList : public MenuDefinition { 405 public: 406 std::vector<std::unique_ptr<MenuDefinition>> Definitions; 407 408 void addDefinition(std::unique_ptr<MenuDefinition> Def) { 409 Definitions.push_back(std::move(Def)); 410 } 411 raw_ostream &log(raw_ostream &) const override; 412 }; 413 414 // Separator in MENU definition (MENUITEM SEPARATOR). 415 // 416 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx 417 class MenuSeparator : public MenuDefinition { 418 public: 419 raw_ostream &log(raw_ostream &) const override; 420 421 MenuDefKind getKind() const override { return MkSeparator; } 422 static bool classof(const MenuDefinition *D) { 423 return D->getKind() == MkSeparator; 424 } 425 }; 426 427 // MENUITEM statement definition. 428 // 429 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx 430 class MenuItem : public MenuDefinition { 431 public: 432 StringRef Name; 433 uint32_t Id; 434 uint16_t Flags; 435 436 MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags) 437 : Name(Caption), Id(ItemId), Flags(ItemFlags) {} 438 raw_ostream &log(raw_ostream &) const override; 439 440 uint16_t getResFlags() const override { return Flags; } 441 MenuDefKind getKind() const override { return MkMenuItem; } 442 static bool classof(const MenuDefinition *D) { 443 return D->getKind() == MkMenuItem; 444 } 445 }; 446 447 // POPUP statement definition. 448 // 449 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx 450 class PopupItem : public MenuDefinition { 451 public: 452 StringRef Name; 453 uint16_t Flags; 454 MenuDefinitionList SubItems; 455 456 PopupItem(StringRef Caption, uint16_t ItemFlags, 457 MenuDefinitionList &&SubItemsList) 458 : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {} 459 raw_ostream &log(raw_ostream &) const override; 460 461 // This has an additional (0x10) flag. It doesn't match with documented 462 // 0x01 flag, though. 463 uint16_t getResFlags() const override { return Flags | 0x10; } 464 MenuDefKind getKind() const override { return MkPopup; } 465 static bool classof(const MenuDefinition *D) { 466 return D->getKind() == MkPopup; 467 } 468 }; 469 470 // Menu resource definition. 471 class MenuResource : public OptStatementsRCResource { 472 public: 473 MenuDefinitionList Elements; 474 475 MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items) 476 : OptStatementsRCResource(std::move(OptStmts)), 477 Elements(std::move(Items)) {} 478 raw_ostream &log(raw_ostream &) const override; 479 480 IntOrString getResourceType() const override { return RkMenu; } 481 Twine getResourceTypeName() const override { return "MENU"; } 482 Error visit(Visitor *V) const override { return V->visitMenuResource(this); } 483 ResourceKind getKind() const override { return RkMenu; } 484 static bool classof(const RCResource *Res) { 485 return Res->getKind() == RkMenu; 486 } 487 }; 488 489 // STRINGTABLE resource. Contains a list of strings, each having its unique ID. 490 // 491 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx 492 class StringTableResource : public OptStatementsRCResource { 493 public: 494 std::vector<std::pair<uint32_t, StringRef>> Table; 495 496 using OptStatementsRCResource::OptStatementsRCResource; 497 void addString(uint32_t ID, StringRef String) { 498 Table.emplace_back(ID, String); 499 } 500 raw_ostream &log(raw_ostream &) const override; 501 Twine getResourceTypeName() const override { return "STRINGTABLE"; } 502 Error visit(Visitor *V) const override { 503 return V->visitStringTableResource(this); 504 } 505 }; 506 507 // -- DIALOG(EX) resource and its helper classes -- 508 // 509 // This resource describes dialog boxes and controls residing inside them. 510 // 511 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx 512 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx 513 514 // Single control definition. 515 class Control { 516 public: 517 StringRef Type; 518 IntOrString Title; 519 uint32_t ID, X, Y, Width, Height; 520 Optional<uint32_t> Style, ExtStyle, HelpID; 521 522 // Control classes as described in DLGITEMTEMPLATEEX documentation. 523 // 524 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx 525 enum CtlClasses { 526 ClsButton = 0x80, 527 ClsEdit = 0x81, 528 ClsStatic = 0x82, 529 ClsListBox = 0x83, 530 ClsScrollBar = 0x84, 531 ClsComboBox = 0x85 532 }; 533 534 // Simple information about a single control type. 535 struct CtlInfo { 536 uint32_t Style; 537 uint16_t CtlClass; 538 bool HasTitle; 539 }; 540 541 Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID, 542 uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight, 543 Optional<uint32_t> ItemStyle, Optional<uint32_t> ExtItemStyle, 544 Optional<uint32_t> CtlHelpID) 545 : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY), 546 Width(ItemWidth), Height(ItemHeight), Style(ItemStyle), 547 ExtStyle(ExtItemStyle), HelpID(CtlHelpID) {} 548 549 static const StringMap<CtlInfo> SupportedCtls; 550 551 raw_ostream &log(raw_ostream &) const; 552 }; 553 554 // Single dialog definition. We don't create distinct classes for DIALOG and 555 // DIALOGEX because of their being too similar to each other. We only have a 556 // flag determining the type of the dialog box. 557 class DialogResource : public OptStatementsRCResource { 558 public: 559 uint32_t X, Y, Width, Height, HelpID; 560 std::vector<Control> Controls; 561 bool IsExtended; 562 563 DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth, 564 uint32_t DlgHeight, uint32_t DlgHelpID, 565 OptionalStmtList &&OptStmts, bool IsDialogEx) 566 : OptStatementsRCResource(std::move(OptStmts)), X(PosX), Y(PosY), 567 Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID), 568 IsExtended(IsDialogEx) {} 569 570 void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); } 571 572 raw_ostream &log(raw_ostream &) const override; 573 574 // It was a weird design decision to assign the same resource type number 575 // both for DIALOG and DIALOGEX (and the same structure version number). 576 // It makes it possible for DIALOG to be mistaken for DIALOGEX. 577 IntOrString getResourceType() const override { return RkDialog; } 578 Twine getResourceTypeName() const override { 579 return "DIALOG" + Twine(IsExtended ? "EX" : ""); 580 } 581 Error visit(Visitor *V) const override { 582 return V->visitDialogResource(this); 583 } 584 ResourceKind getKind() const override { return RkDialog; } 585 static bool classof(const RCResource *Res) { 586 return Res->getKind() == RkDialog; 587 } 588 }; 589 590 // User-defined resource. It is either: 591 // * a link to the file, e.g. NAME TYPE "filename", 592 // * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}. 593 class UserDefinedResource : public RCResource { 594 public: 595 IntOrString Type; 596 StringRef FileLoc; 597 std::vector<IntOrString> Contents; 598 bool IsFileResource; 599 600 UserDefinedResource(IntOrString ResourceType, StringRef FileLocation) 601 : Type(ResourceType), FileLoc(FileLocation), IsFileResource(true) {} 602 UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data) 603 : Type(ResourceType), Contents(std::move(Data)), IsFileResource(false) {} 604 605 raw_ostream &log(raw_ostream &) const override; 606 IntOrString getResourceType() const override { return Type; } 607 Twine getResourceTypeName() const override { return Type; } 608 uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; } 609 610 Error visit(Visitor *V) const override { 611 return V->visitUserDefinedResource(this); 612 } 613 ResourceKind getKind() const override { return RkUser; } 614 static bool classof(const RCResource *Res) { 615 return Res->getKind() == RkUser; 616 } 617 }; 618 619 // -- VERSIONINFO resource and its helper classes -- 620 // 621 // This resource lists the version information on the executable/library. 622 // The declaration consists of the following items: 623 // * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS) 624 // * BEGIN 625 // * A number of BLOCK and/or VALUE statements. BLOCK recursively defines 626 // another block of version information, whereas VALUE defines a 627 // key -> value correspondence. There might be more than one value 628 // corresponding to the single key. 629 // * END 630 // 631 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx 632 633 // A single VERSIONINFO statement; 634 class VersionInfoStmt { 635 public: 636 enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 }; 637 638 virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; } 639 virtual ~VersionInfoStmt() {} 640 641 virtual StmtKind getKind() const { return StBase; } 642 static bool classof(const VersionInfoStmt *S) { 643 return S->getKind() == StBase; 644 } 645 }; 646 647 // BLOCK definition; also the main VERSIONINFO declaration is considered a 648 // BLOCK, although it has no name. 649 // The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't 650 // care about them at the parsing phase. 651 class VersionInfoBlock : public VersionInfoStmt { 652 public: 653 std::vector<std::unique_ptr<VersionInfoStmt>> Stmts; 654 StringRef Name; 655 656 VersionInfoBlock(StringRef BlockName) : Name(BlockName) {} 657 void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) { 658 Stmts.push_back(std::move(Stmt)); 659 } 660 raw_ostream &log(raw_ostream &) const override; 661 662 StmtKind getKind() const override { return StBlock; } 663 static bool classof(const VersionInfoStmt *S) { 664 return S->getKind() == StBlock; 665 } 666 }; 667 668 class VersionInfoValue : public VersionInfoStmt { 669 public: 670 StringRef Key; 671 std::vector<IntOrString> Values; 672 std::vector<bool> HasPrecedingComma; 673 674 VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals, 675 std::vector<bool> &&CommasBeforeVals) 676 : Key(InfoKey), Values(std::move(Vals)), 677 HasPrecedingComma(std::move(CommasBeforeVals)) {} 678 raw_ostream &log(raw_ostream &) const override; 679 680 StmtKind getKind() const override { return StValue; } 681 static bool classof(const VersionInfoStmt *S) { 682 return S->getKind() == StValue; 683 } 684 }; 685 686 class VersionInfoResource : public RCResource { 687 public: 688 // A class listing fixed VERSIONINFO statements (occuring before main BEGIN). 689 // If any of these is not specified, it is assumed by the original tool to 690 // be equal to 0. 691 class VersionInfoFixed { 692 public: 693 enum VersionInfoFixedType { 694 FtUnknown, 695 FtFileVersion, 696 FtProductVersion, 697 FtFileFlagsMask, 698 FtFileFlags, 699 FtFileOS, 700 FtFileType, 701 FtFileSubtype, 702 FtNumTypes 703 }; 704 705 private: 706 static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap; 707 static const StringRef FixedFieldsNames[FtNumTypes]; 708 709 public: 710 SmallVector<uint32_t, 4> FixedInfo[FtNumTypes]; 711 SmallVector<bool, FtNumTypes> IsTypePresent; 712 713 static VersionInfoFixedType getFixedType(StringRef Type); 714 static bool isTypeSupported(VersionInfoFixedType Type); 715 static bool isVersionType(VersionInfoFixedType Type); 716 717 VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {} 718 719 void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) { 720 FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end()); 721 IsTypePresent[Type] = true; 722 } 723 724 raw_ostream &log(raw_ostream &) const; 725 }; 726 727 VersionInfoBlock MainBlock; 728 VersionInfoFixed FixedData; 729 730 VersionInfoResource(VersionInfoBlock &&TopLevelBlock, 731 VersionInfoFixed &&FixedInfo) 732 : MainBlock(std::move(TopLevelBlock)), FixedData(std::move(FixedInfo)) {} 733 734 raw_ostream &log(raw_ostream &) const override; 735 IntOrString getResourceType() const override { return RkVersionInfo; } 736 uint16_t getMemoryFlags() const override { return MfMoveable | MfPure; } 737 Twine getResourceTypeName() const override { return "VERSIONINFO"; } 738 Error visit(Visitor *V) const override { 739 return V->visitVersionInfoResource(this); 740 } 741 ResourceKind getKind() const override { return RkVersionInfo; } 742 static bool classof(const RCResource *Res) { 743 return Res->getKind() == RkVersionInfo; 744 } 745 }; 746 747 // CHARACTERISTICS optional statement. 748 // 749 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx 750 class CharacteristicsStmt : public OptionalStmt { 751 public: 752 uint32_t Value; 753 754 CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {} 755 raw_ostream &log(raw_ostream &) const override; 756 757 Twine getResourceTypeName() const override { return "CHARACTERISTICS"; } 758 Error visit(Visitor *V) const override { 759 return V->visitCharacteristicsStmt(this); 760 } 761 }; 762 763 // VERSION optional statement. 764 // 765 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx 766 class VersionStmt : public OptionalStmt { 767 public: 768 uint32_t Value; 769 770 VersionStmt(uint32_t Version) : Value(Version) {} 771 raw_ostream &log(raw_ostream &) const override; 772 773 Twine getResourceTypeName() const override { return "VERSION"; } 774 Error visit(Visitor *V) const override { return V->visitVersionStmt(this); } 775 }; 776 777 // CAPTION optional statement. 778 // 779 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx 780 class CaptionStmt : public OptionalStmt { 781 public: 782 StringRef Value; 783 784 CaptionStmt(StringRef Caption) : Value(Caption) {} 785 raw_ostream &log(raw_ostream &) const override; 786 Twine getResourceTypeName() const override { return "CAPTION"; } 787 Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); } 788 }; 789 790 // FONT optional statement. 791 // Note that the documentation is inaccurate: it expects five arguments to be 792 // given, however the example provides only two. In fact, the original tool 793 // expects two arguments - point size and name of the typeface. 794 // 795 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx 796 class FontStmt : public OptionalStmt { 797 public: 798 uint32_t Size, Weight, Charset; 799 StringRef Name; 800 bool Italic; 801 802 FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight, 803 bool FontItalic, uint32_t FontCharset) 804 : Size(FontSize), Weight(FontWeight), Charset(FontCharset), 805 Name(FontName), Italic(FontItalic) {} 806 raw_ostream &log(raw_ostream &) const override; 807 Twine getResourceTypeName() const override { return "FONT"; } 808 Error visit(Visitor *V) const override { return V->visitFontStmt(this); } 809 }; 810 811 // STYLE optional statement. 812 // 813 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx 814 class StyleStmt : public OptionalStmt { 815 public: 816 uint32_t Value; 817 818 StyleStmt(uint32_t Style) : Value(Style) {} 819 raw_ostream &log(raw_ostream &) const override; 820 Twine getResourceTypeName() const override { return "STYLE"; } 821 Error visit(Visitor *V) const override { return V->visitStyleStmt(this); } 822 }; 823 824 } // namespace rc 825 } // namespace llvm 826 827 #endif 828