blob: 82f7d11aeb41a939b4fd1b4d745735cda8638f3f [file] [log] [blame]
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +00001//===-- 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"
Marek Sokolowski8f193432017-09-29 17:14:09 +000018#include "ResourceVisitor.h"
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +000019
Marek Sokolowski4ac54d92017-08-29 16:49:59 +000020#include "llvm/ADT/StringSet.h"
21
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +000022namespace llvm {
23namespace rc {
24
Zachary Turner07bc04f2017-10-06 21:26:06 +000025// 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.
30class RCInt {
31 uint32_t Val;
32 bool Long;
33
34public:
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
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +000070// A class holding a name - either an integer or a reference to the string.
71class IntOrString {
72private:
73 union Data {
Zachary Turner07bc04f2017-10-06 21:26:06 +000074 RCInt Int;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +000075 StringRef String;
Zachary Turner07bc04f2017-10-06 21:26:06 +000076 Data(RCInt Value) : Int(Value) {}
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +000077 Data(const StringRef Value) : String(Value) {}
Marek Sokolowski7f110522017-08-28 22:58:31 +000078 Data(const RCToken &Token) {
79 if (Token.kind() == RCToken::Kind::Int)
Zachary Turner07bc04f2017-10-06 21:26:06 +000080 Int = RCInt(Token);
Marek Sokolowski7f110522017-08-28 22:58:31 +000081 else
82 String = Token.value();
83 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +000084 } Data;
85 bool IsInt;
86
87public:
Zachary Turner07bc04f2017-10-06 21:26:06 +000088 IntOrString() : IntOrString(RCInt(0)) {}
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +000089 IntOrString(uint32_t Value) : Data(Value), IsInt(1) {}
Zachary Turner07bc04f2017-10-06 21:26:06 +000090 IntOrString(RCInt Value) : Data(Value), IsInt(1) {}
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +000091 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
Marek Sokolowski8f193432017-09-29 17:14:09 +000099 bool isInt() const { return IsInt; }
100
Zachary Turner07bc04f2017-10-06 21:26:06 +0000101 RCInt getInt() const {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000102 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
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000115 friend raw_ostream &operator<<(raw_ostream &, const IntOrString &);
116};
117
Marek Sokolowski8f193432017-09-29 17:14:09 +0000118enum 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,
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000123 RkSingleCursor = 1,
Martin Storsjo577b9812018-05-07 20:27:37 +0000124 RkBitmap = 2,
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000125 RkSingleIcon = 3,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000126 RkMenu = 4,
127 RkDialog = 5,
Zachary Turnerda366692017-10-06 21:30:55 +0000128 RkStringTableBundle = 6,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000129 RkAccelerators = 9,
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000130 RkCursorGroup = 12,
131 RkIconGroup = 14,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000132 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,
Zachary Turnerda366692017-10-06 21:30:55 +0000143 RkStringTable,
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000144 RkUser,
145 RkSingleCursorOrIconRes,
Zachary Turnerda366692017-10-06 21:30:55 +0000146 RkCursorOrIconGroupRes,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000147};
148
149// Non-zero memory flags.
150// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
151enum MemoryFlags {
152 MfMoveable = 0x10,
153 MfPure = 0x20,
154 MfPreload = 0x40,
155 MfDiscardable = 0x1000
156};
157
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000158// Base resource. All the resources should derive from this base.
159class RCResource {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000160public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000161 IntOrString ResName;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000162 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() {}
Marek Sokolowski8f193432017-09-29 17:14:09 +0000167
168 virtual Error visit(Visitor *) const {
169 llvm_unreachable("This is unable to call methods from Visitor base");
170 }
171
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000172 // Apply the statements attached to this resource. Generic resources
173 // don't have any.
174 virtual Error applyStmts(Visitor *) const { return Error::success(); }
175
Marek Sokolowski8f193432017-09-29 17:14:09 +0000176 // 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.
193class NullResource : public RCResource {
194public:
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; }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000202};
203
204// Optional statement base. All such statements should derive from this base.
205class OptionalStmt : public RCResource {};
206
207class OptionalStmtList : public OptionalStmt {
208 std::vector<std::unique_ptr<OptionalStmt>> Statements;
209
210public:
211 OptionalStmtList() {}
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000212 raw_ostream &log(raw_ostream &OS) const override;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000213
214 void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
215 Statements.push_back(std::move(Stmt));
216 }
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000217
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 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000224};
225
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000226class OptStatementsRCResource : public RCResource {
227public:
228 std::unique_ptr<OptionalStmtList> OptStatements;
229
230 OptStatementsRCResource(OptionalStmtList &&Stmts)
231 : OptStatements(llvm::make_unique<OptionalStmtList>(std::move(Stmts))) {}
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000232
233 virtual Error applyStmts(Visitor *V) const { return OptStatements->visit(V); }
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000234};
235
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000236// 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
242class LanguageResource : public OptionalStmt {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000243public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000244 uint32_t Lang, SubLang;
245
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000246 LanguageResource(uint32_t LangId, uint32_t SubLangId)
247 : Lang(LangId), SubLang(SubLangId) {}
248 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski8f193432017-09-29 17:14:09 +0000249
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"; }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000254};
255
Marek Sokolowski7f110522017-08-28 22:58:31 +0000256// 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
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000259class AcceleratorsResource : public OptStatementsRCResource {
Marek Sokolowski7f110522017-08-28 22:58:31 +0000260public:
261 class Accelerator {
262 public:
263 IntOrString Event;
264 uint32_t Id;
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000265 uint16_t Flags;
Marek Sokolowski7f110522017-08-28 22:58:31 +0000266
267 enum Options {
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000268 // 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
Marek Sokolowski7f110522017-08-28 22:58:31 +0000279 };
280
281 static constexpr size_t NumFlags = 6;
282 static StringRef OptionsStr[NumFlags];
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000283 static uint32_t OptionsFlags[NumFlags];
Marek Sokolowski7f110522017-08-28 22:58:31 +0000284 };
285
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000286 std::vector<Accelerator> Accelerators;
287
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000288 using OptStatementsRCResource::OptStatementsRCResource;
289 void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
Marek Sokolowski7f110522017-08-28 22:58:31 +0000290 Accelerators.push_back(Accelerator{Event, Id, Flags});
291 }
292 raw_ostream &log(raw_ostream &) const override;
293
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000294 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 }
Marek Sokolowski7f110522017-08-28 22:58:31 +0000307};
308
Martin Storsjo577b9812018-05-07 20:27:37 +0000309// BITMAP resource. Represents a bitmap (".bmp") file.
310//
311// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx
312class BitmapResource : public RCResource {
313public:
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
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000332// CURSOR resource. Represents a single cursor (".cur") file.
333//
334// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
335class CursorResource : public RCResource {
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000336public:
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000337 StringRef CursorLoc;
338
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000339 CursorResource(StringRef Location) : CursorLoc(Location) {}
340 raw_ostream &log(raw_ostream &) const override;
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000341
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 }
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000350};
351
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000352// 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
355class IconResource : public RCResource {
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000356public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000357 StringRef IconLoc;
358
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000359 IconResource(StringRef Location) : IconLoc(Location) {}
360 raw_ostream &log(raw_ostream &) const override;
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000361
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 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000368};
369
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000370// 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
375class HTMLResource : public RCResource {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000376public:
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000377 StringRef HTMLLoc;
378
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000379 HTMLResource(StringRef Location) : HTMLLoc(Location) {}
380 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski8f193432017-09-29 17:14:09 +0000381
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 }
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000392};
393
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000394// -- 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.
401class MenuDefinition {
402public:
403 enum Options {
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000404 CHECKED = 0x0008,
405 GRAYED = 0x0001,
406 HELP = 0x4000,
407 INACTIVE = 0x0002,
408 MENUBARBREAK = 0x0020,
409 MENUBREAK = 0x0040
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000410 };
411
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000412 enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
413
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000414 static constexpr size_t NumFlags = 6;
415 static StringRef OptionsStr[NumFlags];
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000416 static uint32_t OptionsFlags[NumFlags];
417 static raw_ostream &logFlags(raw_ostream &, uint16_t Flags);
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000418 virtual raw_ostream &log(raw_ostream &OS) const {
419 return OS << "Base menu definition\n";
420 }
421 virtual ~MenuDefinition() {}
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000422
423 virtual uint16_t getResFlags() const { return 0; }
424 virtual MenuDefKind getKind() const { return MkBase; }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000425};
426
427// Recursive description of a whole submenu.
428class MenuDefinitionList : public MenuDefinition {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000429public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000430 std::vector<std::unique_ptr<MenuDefinition>> Definitions;
431
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000432 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
441class MenuSeparator : public MenuDefinition {
442public:
443 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000444
445 MenuDefKind getKind() const override { return MkSeparator; }
446 static bool classof(const MenuDefinition *D) {
447 return D->getKind() == MkSeparator;
448 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000449};
450
451// MENUITEM statement definition.
452//
453// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
454class MenuItem : public MenuDefinition {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000455public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000456 StringRef Name;
457 uint32_t Id;
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000458 uint16_t Flags;
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000459
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000460 MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000461 : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
462 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000463
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 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000469};
470
471// POPUP statement definition.
472//
473// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
474class PopupItem : public MenuDefinition {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000475public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000476 StringRef Name;
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000477 uint16_t Flags;
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000478 MenuDefinitionList SubItems;
479
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000480 PopupItem(StringRef Caption, uint16_t ItemFlags,
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000481 MenuDefinitionList &&SubItemsList)
482 : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
483 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000484
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 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000492};
493
494// Menu resource definition.
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000495class MenuResource : public OptStatementsRCResource {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000496public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000497 MenuDefinitionList Elements;
498
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000499 MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items)
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000500 : OptStatementsRCResource(std::move(OptStmts)),
501 Elements(std::move(Items)) {}
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000502 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000503
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 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000511};
512
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000513// 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
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000516class StringTableResource : public OptStatementsRCResource {
Zachary Turnerda366692017-10-06 21:30:55 +0000517public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000518 std::vector<std::pair<uint32_t, StringRef>> Table;
519
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000520 using OptStatementsRCResource::OptStatementsRCResource;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000521 void addString(uint32_t ID, StringRef String) {
522 Table.emplace_back(ID, String);
523 }
524 raw_ostream &log(raw_ostream &) const override;
Zachary Turnerda366692017-10-06 21:30:55 +0000525 Twine getResourceTypeName() const override { return "STRINGTABLE"; }
526 Error visit(Visitor *V) const override {
527 return V->visitStringTableResource(this);
528 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000529};
530
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000531// -- 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.
539class Control {
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000540public:
541 StringRef Type;
542 IntOrString Title;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000543 uint32_t ID, X, Y, Width, Height;
544 Optional<uint32_t> Style, ExtStyle, HelpID;
Martin Storsjo818bd562018-05-08 20:55:58 +0000545 IntOrString Class;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000546
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000547 // 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,
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000568 Optional<uint32_t> ItemStyle, Optional<uint32_t> ExtItemStyle,
Martin Storsjo818bd562018-05-08 20:55:58 +0000569 Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000570 : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
571 Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
Martin Storsjo818bd562018-05-08 20:55:58 +0000572 ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000573
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000574 static const StringMap<CtlInfo> SupportedCtls;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000575
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.
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000582class DialogResource : public OptStatementsRCResource {
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000583public:
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000584 uint32_t X, Y, Width, Height, HelpID;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000585 std::vector<Control> Controls;
586 bool IsExtended;
587
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000588 DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
589 uint32_t DlgHeight, uint32_t DlgHelpID,
590 OptionalStmtList &&OptStmts, bool IsDialogEx)
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000591 : OptStatementsRCResource(std::move(OptStmts)), X(PosX), Y(PosY),
592 Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
593 IsExtended(IsDialogEx) {}
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000594
595 void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
596
597 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000598
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 }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000613};
614
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000615// 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}.
618class UserDefinedResource : public RCResource {
Zachary Turner9d8b3582017-10-06 21:52:15 +0000619public:
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000620 IntOrString Type;
621 StringRef FileLoc;
622 std::vector<IntOrString> Contents;
623 bool IsFileResource;
624
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000625 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;
Zachary Turner9d8b3582017-10-06 21:52:15 +0000631 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 }
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000642};
643
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000644// -- 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;
659class VersionInfoStmt {
660public:
Zachary Turner07bc04f2017-10-06 21:26:06 +0000661 enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
662
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000663 virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
664 virtual ~VersionInfoStmt() {}
Zachary Turner07bc04f2017-10-06 21:26:06 +0000665
666 virtual StmtKind getKind() const { return StBase; }
667 static bool classof(const VersionInfoStmt *S) {
668 return S->getKind() == StBase;
669 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000670};
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.
676class VersionInfoBlock : public VersionInfoStmt {
Zachary Turner07bc04f2017-10-06 21:26:06 +0000677public:
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000678 std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
679 StringRef Name;
680
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000681 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;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000686
687 StmtKind getKind() const override { return StBlock; }
688 static bool classof(const VersionInfoStmt *S) {
689 return S->getKind() == StBlock;
690 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000691};
692
693class VersionInfoValue : public VersionInfoStmt {
Zachary Turner07bc04f2017-10-06 21:26:06 +0000694public:
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000695 StringRef Key;
696 std::vector<IntOrString> Values;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000697 std::vector<bool> HasPrecedingComma;
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000698
Zachary Turner07bc04f2017-10-06 21:26:06 +0000699 VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
700 std::vector<bool> &&CommasBeforeVals)
701 : Key(InfoKey), Values(std::move(Vals)),
702 HasPrecedingComma(std::move(CommasBeforeVals)) {}
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000703 raw_ostream &log(raw_ostream &) const override;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000704
705 StmtKind getKind() const override { return StValue; }
706 static bool classof(const VersionInfoStmt *S) {
707 return S->getKind() == StValue;
708 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000709};
710
711class VersionInfoResource : public RCResource {
712public:
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
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000752 VersionInfoBlock MainBlock;
753 VersionInfoFixed FixedData;
754
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000755 VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
756 VersionInfoFixed &&FixedInfo)
757 : MainBlock(std::move(TopLevelBlock)), FixedData(std::move(FixedInfo)) {}
758
759 raw_ostream &log(raw_ostream &) const override;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000760 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 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000770};
771
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000772// CHARACTERISTICS optional statement.
773//
774// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
775class CharacteristicsStmt : public OptionalStmt {
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000776public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000777 uint32_t Value;
778
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000779 CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
780 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000781
782 Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
783 Error visit(Visitor *V) const override {
784 return V->visitCharacteristicsStmt(this);
785 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000786};
787
788// VERSION optional statement.
789//
790// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
791class VersionStmt : public OptionalStmt {
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000792public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000793 uint32_t Value;
794
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000795 VersionStmt(uint32_t Version) : Value(Version) {}
796 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000797
798 Twine getResourceTypeName() const override { return "VERSION"; }
799 Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000800};
801
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000802// CAPTION optional statement.
803//
804// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
805class CaptionStmt : public OptionalStmt {
Zachary Turner420090a2017-10-06 20:51:20 +0000806public:
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000807 StringRef Value;
808
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000809 CaptionStmt(StringRef Caption) : Value(Caption) {}
810 raw_ostream &log(raw_ostream &) const override;
Zachary Turner420090a2017-10-06 20:51:20 +0000811 Twine getResourceTypeName() const override { return "CAPTION"; }
812 Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000813};
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
821class FontStmt : public OptionalStmt {
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000822public:
Zachary Turner420090a2017-10-06 20:51:20 +0000823 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) {}
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000831 raw_ostream &log(raw_ostream &) const override;
Zachary Turner420090a2017-10-06 20:51:20 +0000832 Twine getResourceTypeName() const override { return "FONT"; }
833 Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000834};
835
836// STYLE optional statement.
837//
838// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
839class StyleStmt : public OptionalStmt {
Zachary Turner420090a2017-10-06 20:51:20 +0000840public:
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000841 uint32_t Value;
842
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000843 StyleStmt(uint32_t Style) : Value(Style) {}
844 raw_ostream &log(raw_ostream &) const override;
Zachary Turner420090a2017-10-06 20:51:20 +0000845 Twine getResourceTypeName() const override { return "STYLE"; }
846 Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000847};
848
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000849} // namespace rc
850} // namespace llvm
851
852#endif