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