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