ResourceScriptStmt.h 30 KB

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