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