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