xref: /openbsd-src/gnu/llvm/llvm/tools/llvm-rc/ResourceScriptStmt.h (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
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