OSDN Git Service

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