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