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