blob: e44120b770f35694a358b23618518b73d850f6e7 [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,
124 RkSingleIcon = 3,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000125 RkMenu = 4,
126 RkDialog = 5,
Zachary Turnerda366692017-10-06 21:30:55 +0000127 RkStringTableBundle = 6,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000128 RkAccelerators = 9,
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000129 RkCursorGroup = 12,
130 RkIconGroup = 14,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000131 RkVersionInfo = 16,
132 RkHTML = 23,
133
134 // These kinds don't have assigned type IDs (they might be the resources
135 // of invalid kind, expand to many resource structures in .res files,
136 // or have variable type ID). In order to avoid ID clashes with IDs above,
137 // we assign the kinds the values 256 and larger.
138 RkInvalid = 256,
139 RkBase,
140 RkCursor,
141 RkIcon,
Zachary Turnerda366692017-10-06 21:30:55 +0000142 RkStringTable,
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000143 RkUser,
144 RkSingleCursorOrIconRes,
Zachary Turnerda366692017-10-06 21:30:55 +0000145 RkCursorOrIconGroupRes,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000146};
147
148// Non-zero memory flags.
149// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
150enum MemoryFlags {
151 MfMoveable = 0x10,
152 MfPure = 0x20,
153 MfPreload = 0x40,
154 MfDiscardable = 0x1000
155};
156
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000157// Base resource. All the resources should derive from this base.
158class RCResource {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000159public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000160 IntOrString ResName;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000161 void setName(const IntOrString &Name) { ResName = Name; }
162 virtual raw_ostream &log(raw_ostream &OS) const {
163 return OS << "Base statement\n";
164 };
165 virtual ~RCResource() {}
Marek Sokolowski8f193432017-09-29 17:14:09 +0000166
167 virtual Error visit(Visitor *) const {
168 llvm_unreachable("This is unable to call methods from Visitor base");
169 }
170
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000171 // Apply the statements attached to this resource. Generic resources
172 // don't have any.
173 virtual Error applyStmts(Visitor *) const { return Error::success(); }
174
Marek Sokolowski8f193432017-09-29 17:14:09 +0000175 // By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
176 virtual uint16_t getMemoryFlags() const {
177 return MfDiscardable | MfPure | MfMoveable;
178 }
179 virtual ResourceKind getKind() const { return RkBase; }
180 static bool classof(const RCResource *Res) { return true; }
181
182 virtual IntOrString getResourceType() const {
183 llvm_unreachable("This cannot be called on objects without types.");
184 }
185 virtual Twine getResourceTypeName() const {
186 llvm_unreachable("This cannot be called on objects without types.");
187 };
188};
189
190// An empty resource. It has no content, type 0, ID 0 and all of its
191// characteristics are equal to 0.
192class NullResource : public RCResource {
193public:
194 raw_ostream &log(raw_ostream &OS) const override {
195 return OS << "Null resource\n";
196 }
197 Error visit(Visitor *V) const override { return V->visitNullResource(this); }
198 IntOrString getResourceType() const override { return 0; }
199 Twine getResourceTypeName() const override { return "(NULL)"; }
200 uint16_t getMemoryFlags() const override { return 0; }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000201};
202
203// Optional statement base. All such statements should derive from this base.
204class OptionalStmt : public RCResource {};
205
206class OptionalStmtList : public OptionalStmt {
207 std::vector<std::unique_ptr<OptionalStmt>> Statements;
208
209public:
210 OptionalStmtList() {}
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000211 raw_ostream &log(raw_ostream &OS) const override;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000212
213 void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
214 Statements.push_back(std::move(Stmt));
215 }
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000216
217 Error visit(Visitor *V) const override {
218 for (auto &StmtPtr : Statements)
219 if (auto Err = StmtPtr->visit(V))
220 return Err;
221 return Error::success();
222 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000223};
224
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000225class OptStatementsRCResource : public RCResource {
226public:
227 std::unique_ptr<OptionalStmtList> OptStatements;
228
229 OptStatementsRCResource(OptionalStmtList &&Stmts)
230 : OptStatements(llvm::make_unique<OptionalStmtList>(std::move(Stmts))) {}
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000231
232 virtual Error applyStmts(Visitor *V) const { return OptStatements->visit(V); }
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000233};
234
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000235// LANGUAGE statement. It can occur both as a top-level statement (in such
236// a situation, it changes the default language until the end of the file)
237// and as an optional resource statement (then it changes the language
238// of a single resource).
239//
240// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx
241class LanguageResource : public OptionalStmt {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000242public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000243 uint32_t Lang, SubLang;
244
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000245 LanguageResource(uint32_t LangId, uint32_t SubLangId)
246 : Lang(LangId), SubLang(SubLangId) {}
247 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski8f193432017-09-29 17:14:09 +0000248
249 // This is not a regular top-level statement; when it occurs, it just
250 // modifies the language context.
251 Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
252 Twine getResourceTypeName() const override { return "LANGUAGE"; }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000253};
254
Marek Sokolowski7f110522017-08-28 22:58:31 +0000255// ACCELERATORS resource. Defines a named table of accelerators for the app.
256//
257// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000258class AcceleratorsResource : public OptStatementsRCResource {
Marek Sokolowski7f110522017-08-28 22:58:31 +0000259public:
260 class Accelerator {
261 public:
262 IntOrString Event;
263 uint32_t Id;
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000264 uint16_t Flags;
Marek Sokolowski7f110522017-08-28 22:58:31 +0000265
266 enum Options {
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000267 // This is actually 0x0000 (accelerator is assumed to be ASCII if it's
268 // not VIRTKEY). However, rc.exe behavior is different in situations
269 // "only ASCII defined" and "neither ASCII nor VIRTKEY defined".
270 // Therefore, we include ASCII as another flag. This must be zeroed
271 // when serialized.
272 ASCII = 0x8000,
273 VIRTKEY = 0x0001,
274 NOINVERT = 0x0002,
275 ALT = 0x0010,
276 SHIFT = 0x0004,
277 CONTROL = 0x0008
Marek Sokolowski7f110522017-08-28 22:58:31 +0000278 };
279
280 static constexpr size_t NumFlags = 6;
281 static StringRef OptionsStr[NumFlags];
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000282 static uint32_t OptionsFlags[NumFlags];
Marek Sokolowski7f110522017-08-28 22:58:31 +0000283 };
284
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000285 std::vector<Accelerator> Accelerators;
286
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000287 using OptStatementsRCResource::OptStatementsRCResource;
288 void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
Marek Sokolowski7f110522017-08-28 22:58:31 +0000289 Accelerators.push_back(Accelerator{Event, Id, Flags});
290 }
291 raw_ostream &log(raw_ostream &) const override;
292
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000293 IntOrString getResourceType() const override { return RkAccelerators; }
294 uint16_t getMemoryFlags() const override {
295 return MfPure | MfMoveable;
296 }
297 Twine getResourceTypeName() const override { return "ACCELERATORS"; }
298
299 Error visit(Visitor *V) const override {
300 return V->visitAcceleratorsResource(this);
301 }
302 ResourceKind getKind() const override { return RkAccelerators; }
303 static bool classof(const RCResource *Res) {
304 return Res->getKind() == RkAccelerators;
305 }
Marek Sokolowski7f110522017-08-28 22:58:31 +0000306};
307
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000308// CURSOR resource. Represents a single cursor (".cur") file.
309//
310// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
311class CursorResource : public RCResource {
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000312public:
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000313 StringRef CursorLoc;
314
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000315 CursorResource(StringRef Location) : CursorLoc(Location) {}
316 raw_ostream &log(raw_ostream &) const override;
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000317
318 Twine getResourceTypeName() const override { return "CURSOR"; }
319 Error visit(Visitor *V) const override {
320 return V->visitCursorResource(this);
321 }
322 ResourceKind getKind() const override { return RkCursor; }
323 static bool classof(const RCResource *Res) {
324 return Res->getKind() == RkCursor;
325 }
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000326};
327
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000328// ICON resource. Represents a single ".ico" file containing a group of icons.
329//
330// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
331class IconResource : public RCResource {
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000332public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000333 StringRef IconLoc;
334
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000335 IconResource(StringRef Location) : IconLoc(Location) {}
336 raw_ostream &log(raw_ostream &) const override;
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000337
338 Twine getResourceTypeName() const override { return "ICON"; }
339 Error visit(Visitor *V) const override { return V->visitIconResource(this); }
340 ResourceKind getKind() const override { return RkIcon; }
341 static bool classof(const RCResource *Res) {
342 return Res->getKind() == RkIcon;
343 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000344};
345
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000346// HTML resource. Represents a local webpage that is to be embedded into the
347// resulting resource file. It embeds a file only - no additional resources
348// (images etc.) are included with this resource.
349//
350// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx
351class HTMLResource : public RCResource {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000352public:
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000353 StringRef HTMLLoc;
354
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000355 HTMLResource(StringRef Location) : HTMLLoc(Location) {}
356 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski8f193432017-09-29 17:14:09 +0000357
358 Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
359
360 // Curiously, file resources don't have DISCARDABLE flag set.
361 uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; }
362 IntOrString getResourceType() const override { return RkHTML; }
363 Twine getResourceTypeName() const override { return "HTML"; }
364 ResourceKind getKind() const override { return RkHTML; }
365 static bool classof(const RCResource *Res) {
366 return Res->getKind() == RkHTML;
367 }
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000368};
369
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000370// -- MENU resource and its helper classes --
371// This resource describes the contents of an application menu
372// (usually located in the upper part of the dialog.)
373//
374// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx
375
376// Description of a single submenu item.
377class MenuDefinition {
378public:
379 enum Options {
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000380 CHECKED = 0x0008,
381 GRAYED = 0x0001,
382 HELP = 0x4000,
383 INACTIVE = 0x0002,
384 MENUBARBREAK = 0x0020,
385 MENUBREAK = 0x0040
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000386 };
387
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000388 enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
389
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000390 static constexpr size_t NumFlags = 6;
391 static StringRef OptionsStr[NumFlags];
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000392 static uint32_t OptionsFlags[NumFlags];
393 static raw_ostream &logFlags(raw_ostream &, uint16_t Flags);
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000394 virtual raw_ostream &log(raw_ostream &OS) const {
395 return OS << "Base menu definition\n";
396 }
397 virtual ~MenuDefinition() {}
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000398
399 virtual uint16_t getResFlags() const { return 0; }
400 virtual MenuDefKind getKind() const { return MkBase; }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000401};
402
403// Recursive description of a whole submenu.
404class MenuDefinitionList : public MenuDefinition {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000405public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000406 std::vector<std::unique_ptr<MenuDefinition>> Definitions;
407
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000408 void addDefinition(std::unique_ptr<MenuDefinition> Def) {
409 Definitions.push_back(std::move(Def));
410 }
411 raw_ostream &log(raw_ostream &) const override;
412};
413
414// Separator in MENU definition (MENUITEM SEPARATOR).
415//
416// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
417class MenuSeparator : public MenuDefinition {
418public:
419 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000420
421 MenuDefKind getKind() const override { return MkSeparator; }
422 static bool classof(const MenuDefinition *D) {
423 return D->getKind() == MkSeparator;
424 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000425};
426
427// MENUITEM statement definition.
428//
429// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
430class MenuItem : public MenuDefinition {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000431public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000432 StringRef Name;
433 uint32_t Id;
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000434 uint16_t Flags;
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000435
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000436 MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000437 : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
438 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000439
440 uint16_t getResFlags() const override { return Flags; }
441 MenuDefKind getKind() const override { return MkMenuItem; }
442 static bool classof(const MenuDefinition *D) {
443 return D->getKind() == MkMenuItem;
444 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000445};
446
447// POPUP statement definition.
448//
449// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
450class PopupItem : public MenuDefinition {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000451public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000452 StringRef Name;
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000453 uint16_t Flags;
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000454 MenuDefinitionList SubItems;
455
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000456 PopupItem(StringRef Caption, uint16_t ItemFlags,
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000457 MenuDefinitionList &&SubItemsList)
458 : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
459 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000460
461 // This has an additional (0x10) flag. It doesn't match with documented
462 // 0x01 flag, though.
463 uint16_t getResFlags() const override { return Flags | 0x10; }
464 MenuDefKind getKind() const override { return MkPopup; }
465 static bool classof(const MenuDefinition *D) {
466 return D->getKind() == MkPopup;
467 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000468};
469
470// Menu resource definition.
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000471class MenuResource : public OptStatementsRCResource {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000472public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000473 MenuDefinitionList Elements;
474
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000475 MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items)
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000476 : OptStatementsRCResource(std::move(OptStmts)),
477 Elements(std::move(Items)) {}
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000478 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000479
480 IntOrString getResourceType() const override { return RkMenu; }
481 Twine getResourceTypeName() const override { return "MENU"; }
482 Error visit(Visitor *V) const override { return V->visitMenuResource(this); }
483 ResourceKind getKind() const override { return RkMenu; }
484 static bool classof(const RCResource *Res) {
485 return Res->getKind() == RkMenu;
486 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000487};
488
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000489// STRINGTABLE resource. Contains a list of strings, each having its unique ID.
490//
491// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000492class StringTableResource : public OptStatementsRCResource {
Zachary Turnerda366692017-10-06 21:30:55 +0000493public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000494 std::vector<std::pair<uint32_t, StringRef>> Table;
495
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000496 using OptStatementsRCResource::OptStatementsRCResource;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000497 void addString(uint32_t ID, StringRef String) {
498 Table.emplace_back(ID, String);
499 }
500 raw_ostream &log(raw_ostream &) const override;
Zachary Turnerda366692017-10-06 21:30:55 +0000501 Twine getResourceTypeName() const override { return "STRINGTABLE"; }
502 Error visit(Visitor *V) const override {
503 return V->visitStringTableResource(this);
504 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000505};
506
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000507// -- DIALOG(EX) resource and its helper classes --
508//
509// This resource describes dialog boxes and controls residing inside them.
510//
511// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx
512// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
513
514// Single control definition.
515class Control {
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000516public:
517 StringRef Type;
518 IntOrString Title;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000519 uint32_t ID, X, Y, Width, Height;
520 Optional<uint32_t> Style, ExtStyle, HelpID;
521
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000522 // Control classes as described in DLGITEMTEMPLATEEX documentation.
523 //
524 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx
525 enum CtlClasses {
526 ClsButton = 0x80,
527 ClsEdit = 0x81,
528 ClsStatic = 0x82,
529 ClsListBox = 0x83,
530 ClsScrollBar = 0x84,
531 ClsComboBox = 0x85
532 };
533
534 // Simple information about a single control type.
535 struct CtlInfo {
536 uint32_t Style;
537 uint16_t CtlClass;
538 bool HasTitle;
539 };
540
541 Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
542 uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000543 Optional<uint32_t> ItemStyle, Optional<uint32_t> ExtItemStyle,
544 Optional<uint32_t> CtlHelpID)
545 : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
546 Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
547 ExtStyle(ExtItemStyle), HelpID(CtlHelpID) {}
548
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000549 static const StringMap<CtlInfo> SupportedCtls;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000550
551 raw_ostream &log(raw_ostream &) const;
552};
553
554// Single dialog definition. We don't create distinct classes for DIALOG and
555// DIALOGEX because of their being too similar to each other. We only have a
556// flag determining the type of the dialog box.
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000557class DialogResource : public OptStatementsRCResource {
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000558public:
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000559 uint32_t X, Y, Width, Height, HelpID;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000560 std::vector<Control> Controls;
561 bool IsExtended;
562
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000563 DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
564 uint32_t DlgHeight, uint32_t DlgHelpID,
565 OptionalStmtList &&OptStmts, bool IsDialogEx)
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000566 : OptStatementsRCResource(std::move(OptStmts)), X(PosX), Y(PosY),
567 Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
568 IsExtended(IsDialogEx) {}
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000569
570 void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
571
572 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000573
574 // It was a weird design decision to assign the same resource type number
575 // both for DIALOG and DIALOGEX (and the same structure version number).
576 // It makes it possible for DIALOG to be mistaken for DIALOGEX.
577 IntOrString getResourceType() const override { return RkDialog; }
578 Twine getResourceTypeName() const override {
579 return "DIALOG" + Twine(IsExtended ? "EX" : "");
580 }
581 Error visit(Visitor *V) const override {
582 return V->visitDialogResource(this);
583 }
584 ResourceKind getKind() const override { return RkDialog; }
585 static bool classof(const RCResource *Res) {
586 return Res->getKind() == RkDialog;
587 }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000588};
589
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000590// User-defined resource. It is either:
591// * a link to the file, e.g. NAME TYPE "filename",
592// * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}.
593class UserDefinedResource : public RCResource {
Zachary Turner9d8b3582017-10-06 21:52:15 +0000594public:
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000595 IntOrString Type;
596 StringRef FileLoc;
597 std::vector<IntOrString> Contents;
598 bool IsFileResource;
599
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000600 UserDefinedResource(IntOrString ResourceType, StringRef FileLocation)
601 : Type(ResourceType), FileLoc(FileLocation), IsFileResource(true) {}
602 UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data)
603 : Type(ResourceType), Contents(std::move(Data)), IsFileResource(false) {}
604
605 raw_ostream &log(raw_ostream &) const override;
Zachary Turner9d8b3582017-10-06 21:52:15 +0000606 IntOrString getResourceType() const override { return Type; }
607 Twine getResourceTypeName() const override { return Type; }
608 uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; }
609
610 Error visit(Visitor *V) const override {
611 return V->visitUserDefinedResource(this);
612 }
613 ResourceKind getKind() const override { return RkUser; }
614 static bool classof(const RCResource *Res) {
615 return Res->getKind() == RkUser;
616 }
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000617};
618
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000619// -- VERSIONINFO resource and its helper classes --
620//
621// This resource lists the version information on the executable/library.
622// The declaration consists of the following items:
623// * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS)
624// * BEGIN
625// * A number of BLOCK and/or VALUE statements. BLOCK recursively defines
626// another block of version information, whereas VALUE defines a
627// key -> value correspondence. There might be more than one value
628// corresponding to the single key.
629// * END
630//
631// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
632
633// A single VERSIONINFO statement;
634class VersionInfoStmt {
635public:
Zachary Turner07bc04f2017-10-06 21:26:06 +0000636 enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
637
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000638 virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
639 virtual ~VersionInfoStmt() {}
Zachary Turner07bc04f2017-10-06 21:26:06 +0000640
641 virtual StmtKind getKind() const { return StBase; }
642 static bool classof(const VersionInfoStmt *S) {
643 return S->getKind() == StBase;
644 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000645};
646
647// BLOCK definition; also the main VERSIONINFO declaration is considered a
648// BLOCK, although it has no name.
649// The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
650// care about them at the parsing phase.
651class VersionInfoBlock : public VersionInfoStmt {
Zachary Turner07bc04f2017-10-06 21:26:06 +0000652public:
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000653 std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
654 StringRef Name;
655
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000656 VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
657 void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
658 Stmts.push_back(std::move(Stmt));
659 }
660 raw_ostream &log(raw_ostream &) const override;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000661
662 StmtKind getKind() const override { return StBlock; }
663 static bool classof(const VersionInfoStmt *S) {
664 return S->getKind() == StBlock;
665 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000666};
667
668class VersionInfoValue : public VersionInfoStmt {
Zachary Turner07bc04f2017-10-06 21:26:06 +0000669public:
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000670 StringRef Key;
671 std::vector<IntOrString> Values;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000672 std::vector<bool> HasPrecedingComma;
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000673
Zachary Turner07bc04f2017-10-06 21:26:06 +0000674 VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
675 std::vector<bool> &&CommasBeforeVals)
676 : Key(InfoKey), Values(std::move(Vals)),
677 HasPrecedingComma(std::move(CommasBeforeVals)) {}
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000678 raw_ostream &log(raw_ostream &) const override;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000679
680 StmtKind getKind() const override { return StValue; }
681 static bool classof(const VersionInfoStmt *S) {
682 return S->getKind() == StValue;
683 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000684};
685
686class VersionInfoResource : public RCResource {
687public:
688 // A class listing fixed VERSIONINFO statements (occuring before main BEGIN).
689 // If any of these is not specified, it is assumed by the original tool to
690 // be equal to 0.
691 class VersionInfoFixed {
692 public:
693 enum VersionInfoFixedType {
694 FtUnknown,
695 FtFileVersion,
696 FtProductVersion,
697 FtFileFlagsMask,
698 FtFileFlags,
699 FtFileOS,
700 FtFileType,
701 FtFileSubtype,
702 FtNumTypes
703 };
704
705 private:
706 static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
707 static const StringRef FixedFieldsNames[FtNumTypes];
708
709 public:
710 SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
711 SmallVector<bool, FtNumTypes> IsTypePresent;
712
713 static VersionInfoFixedType getFixedType(StringRef Type);
714 static bool isTypeSupported(VersionInfoFixedType Type);
715 static bool isVersionType(VersionInfoFixedType Type);
716
717 VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
718
719 void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
720 FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end());
721 IsTypePresent[Type] = true;
722 }
723
724 raw_ostream &log(raw_ostream &) const;
725 };
726
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000727 VersionInfoBlock MainBlock;
728 VersionInfoFixed FixedData;
729
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000730 VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
731 VersionInfoFixed &&FixedInfo)
732 : MainBlock(std::move(TopLevelBlock)), FixedData(std::move(FixedInfo)) {}
733
734 raw_ostream &log(raw_ostream &) const override;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000735 IntOrString getResourceType() const override { return RkVersionInfo; }
736 uint16_t getMemoryFlags() const override { return MfMoveable | MfPure; }
737 Twine getResourceTypeName() const override { return "VERSIONINFO"; }
738 Error visit(Visitor *V) const override {
739 return V->visitVersionInfoResource(this);
740 }
741 ResourceKind getKind() const override { return RkVersionInfo; }
742 static bool classof(const RCResource *Res) {
743 return Res->getKind() == RkVersionInfo;
744 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000745};
746
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000747// CHARACTERISTICS optional statement.
748//
749// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
750class CharacteristicsStmt : public OptionalStmt {
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000751public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000752 uint32_t Value;
753
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000754 CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
755 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000756
757 Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
758 Error visit(Visitor *V) const override {
759 return V->visitCharacteristicsStmt(this);
760 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000761};
762
763// VERSION optional statement.
764//
765// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
766class VersionStmt : public OptionalStmt {
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000767public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000768 uint32_t Value;
769
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000770 VersionStmt(uint32_t Version) : Value(Version) {}
771 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000772
773 Twine getResourceTypeName() const override { return "VERSION"; }
774 Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000775};
776
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000777// CAPTION optional statement.
778//
779// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
780class CaptionStmt : public OptionalStmt {
Zachary Turner420090a2017-10-06 20:51:20 +0000781public:
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000782 StringRef Value;
783
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000784 CaptionStmt(StringRef Caption) : Value(Caption) {}
785 raw_ostream &log(raw_ostream &) const override;
Zachary Turner420090a2017-10-06 20:51:20 +0000786 Twine getResourceTypeName() const override { return "CAPTION"; }
787 Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000788};
789
790// FONT optional statement.
791// Note that the documentation is inaccurate: it expects five arguments to be
792// given, however the example provides only two. In fact, the original tool
793// expects two arguments - point size and name of the typeface.
794//
795// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx
796class FontStmt : public OptionalStmt {
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000797public:
Zachary Turner420090a2017-10-06 20:51:20 +0000798 uint32_t Size, Weight, Charset;
799 StringRef Name;
800 bool Italic;
801
802 FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
803 bool FontItalic, uint32_t FontCharset)
804 : Size(FontSize), Weight(FontWeight), Charset(FontCharset),
805 Name(FontName), Italic(FontItalic) {}
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000806 raw_ostream &log(raw_ostream &) const override;
Zachary Turner420090a2017-10-06 20:51:20 +0000807 Twine getResourceTypeName() const override { return "FONT"; }
808 Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000809};
810
811// STYLE optional statement.
812//
813// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
814class StyleStmt : public OptionalStmt {
Zachary Turner420090a2017-10-06 20:51:20 +0000815public:
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000816 uint32_t Value;
817
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000818 StyleStmt(uint32_t Style) : Value(Style) {}
819 raw_ostream &log(raw_ostream &) const override;
Zachary Turner420090a2017-10-06 20:51:20 +0000820 Twine getResourceTypeName() const override { return "STYLE"; }
821 Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000822};
823
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000824} // namespace rc
825} // namespace llvm
826
827#endif