blob: 22a569c34f5c0690299e379a0f4d685a6b9aa940 [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,
Martin Storsjo7bc3c582018-05-09 18:20:56 +0000130 RkRcData = 10,
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000131 RkCursorGroup = 12,
132 RkIconGroup = 14,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000133 RkVersionInfo = 16,
134 RkHTML = 23,
135
136 // These kinds don't have assigned type IDs (they might be the resources
137 // of invalid kind, expand to many resource structures in .res files,
138 // or have variable type ID). In order to avoid ID clashes with IDs above,
139 // we assign the kinds the values 256 and larger.
140 RkInvalid = 256,
141 RkBase,
142 RkCursor,
143 RkIcon,
Zachary Turnerda366692017-10-06 21:30:55 +0000144 RkStringTable,
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000145 RkUser,
146 RkSingleCursorOrIconRes,
Zachary Turnerda366692017-10-06 21:30:55 +0000147 RkCursorOrIconGroupRes,
Marek Sokolowski8f193432017-09-29 17:14:09 +0000148};
149
150// Non-zero memory flags.
151// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
152enum MemoryFlags {
153 MfMoveable = 0x10,
154 MfPure = 0x20,
155 MfPreload = 0x40,
156 MfDiscardable = 0x1000
157};
158
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000159// Base resource. All the resources should derive from this base.
160class RCResource {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000161public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000162 IntOrString ResName;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000163 void setName(const IntOrString &Name) { ResName = Name; }
164 virtual raw_ostream &log(raw_ostream &OS) const {
165 return OS << "Base statement\n";
166 };
167 virtual ~RCResource() {}
Marek Sokolowski8f193432017-09-29 17:14:09 +0000168
169 virtual Error visit(Visitor *) const {
170 llvm_unreachable("This is unable to call methods from Visitor base");
171 }
172
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000173 // Apply the statements attached to this resource. Generic resources
174 // don't have any.
175 virtual Error applyStmts(Visitor *) const { return Error::success(); }
176
Marek Sokolowski8f193432017-09-29 17:14:09 +0000177 // By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
178 virtual uint16_t getMemoryFlags() const {
179 return MfDiscardable | MfPure | MfMoveable;
180 }
181 virtual ResourceKind getKind() const { return RkBase; }
182 static bool classof(const RCResource *Res) { return true; }
183
184 virtual IntOrString getResourceType() const {
185 llvm_unreachable("This cannot be called on objects without types.");
186 }
187 virtual Twine getResourceTypeName() const {
188 llvm_unreachable("This cannot be called on objects without types.");
189 };
190};
191
192// An empty resource. It has no content, type 0, ID 0 and all of its
193// characteristics are equal to 0.
194class NullResource : public RCResource {
195public:
196 raw_ostream &log(raw_ostream &OS) const override {
197 return OS << "Null resource\n";
198 }
199 Error visit(Visitor *V) const override { return V->visitNullResource(this); }
200 IntOrString getResourceType() const override { return 0; }
201 Twine getResourceTypeName() const override { return "(NULL)"; }
202 uint16_t getMemoryFlags() const override { return 0; }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000203};
204
205// Optional statement base. All such statements should derive from this base.
206class OptionalStmt : public RCResource {};
207
208class OptionalStmtList : public OptionalStmt {
209 std::vector<std::unique_ptr<OptionalStmt>> Statements;
210
211public:
212 OptionalStmtList() {}
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000213 raw_ostream &log(raw_ostream &OS) const override;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000214
215 void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
216 Statements.push_back(std::move(Stmt));
217 }
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000218
219 Error visit(Visitor *V) const override {
220 for (auto &StmtPtr : Statements)
221 if (auto Err = StmtPtr->visit(V))
222 return Err;
223 return Error::success();
224 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000225};
226
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000227class OptStatementsRCResource : public RCResource {
228public:
229 std::unique_ptr<OptionalStmtList> OptStatements;
230
231 OptStatementsRCResource(OptionalStmtList &&Stmts)
232 : OptStatements(llvm::make_unique<OptionalStmtList>(std::move(Stmts))) {}
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000233
234 virtual Error applyStmts(Visitor *V) const { return OptStatements->visit(V); }
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000235};
236
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000237// LANGUAGE statement. It can occur both as a top-level statement (in such
238// a situation, it changes the default language until the end of the file)
239// and as an optional resource statement (then it changes the language
240// of a single resource).
241//
242// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx
243class LanguageResource : public OptionalStmt {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000244public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000245 uint32_t Lang, SubLang;
246
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000247 LanguageResource(uint32_t LangId, uint32_t SubLangId)
248 : Lang(LangId), SubLang(SubLangId) {}
249 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski8f193432017-09-29 17:14:09 +0000250
251 // This is not a regular top-level statement; when it occurs, it just
252 // modifies the language context.
253 Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
254 Twine getResourceTypeName() const override { return "LANGUAGE"; }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000255};
256
Marek Sokolowski7f110522017-08-28 22:58:31 +0000257// ACCELERATORS resource. Defines a named table of accelerators for the app.
258//
259// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000260class AcceleratorsResource : public OptStatementsRCResource {
Marek Sokolowski7f110522017-08-28 22:58:31 +0000261public:
262 class Accelerator {
263 public:
264 IntOrString Event;
265 uint32_t Id;
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000266 uint16_t Flags;
Marek Sokolowski7f110522017-08-28 22:58:31 +0000267
268 enum Options {
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000269 // This is actually 0x0000 (accelerator is assumed to be ASCII if it's
270 // not VIRTKEY). However, rc.exe behavior is different in situations
271 // "only ASCII defined" and "neither ASCII nor VIRTKEY defined".
272 // Therefore, we include ASCII as another flag. This must be zeroed
273 // when serialized.
274 ASCII = 0x8000,
275 VIRTKEY = 0x0001,
276 NOINVERT = 0x0002,
277 ALT = 0x0010,
278 SHIFT = 0x0004,
279 CONTROL = 0x0008
Marek Sokolowski7f110522017-08-28 22:58:31 +0000280 };
281
282 static constexpr size_t NumFlags = 6;
283 static StringRef OptionsStr[NumFlags];
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000284 static uint32_t OptionsFlags[NumFlags];
Marek Sokolowski7f110522017-08-28 22:58:31 +0000285 };
286
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000287 std::vector<Accelerator> Accelerators;
288
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000289 using OptStatementsRCResource::OptStatementsRCResource;
290 void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
Marek Sokolowski7f110522017-08-28 22:58:31 +0000291 Accelerators.push_back(Accelerator{Event, Id, Flags});
292 }
293 raw_ostream &log(raw_ostream &) const override;
294
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000295 IntOrString getResourceType() const override { return RkAccelerators; }
296 uint16_t getMemoryFlags() const override {
297 return MfPure | MfMoveable;
298 }
299 Twine getResourceTypeName() const override { return "ACCELERATORS"; }
300
301 Error visit(Visitor *V) const override {
302 return V->visitAcceleratorsResource(this);
303 }
304 ResourceKind getKind() const override { return RkAccelerators; }
305 static bool classof(const RCResource *Res) {
306 return Res->getKind() == RkAccelerators;
307 }
Marek Sokolowski7f110522017-08-28 22:58:31 +0000308};
309
Martin Storsjo577b9812018-05-07 20:27:37 +0000310// BITMAP resource. Represents a bitmap (".bmp") file.
311//
312// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx
313class BitmapResource : public RCResource {
314public:
315 StringRef BitmapLoc;
316
317 BitmapResource(StringRef Location) : BitmapLoc(Location) {}
318 raw_ostream &log(raw_ostream &) const override;
319
320 IntOrString getResourceType() const override { return RkBitmap; }
321 uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; }
322
323 Twine getResourceTypeName() const override { return "BITMAP"; }
324 Error visit(Visitor *V) const override {
325 return V->visitBitmapResource(this);
326 }
327 ResourceKind getKind() const override { return RkBitmap; }
328 static bool classof(const RCResource *Res) {
329 return Res->getKind() == RkBitmap;
330 }
331};
332
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000333// CURSOR resource. Represents a single cursor (".cur") file.
334//
335// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
336class CursorResource : public RCResource {
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000337public:
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000338 StringRef CursorLoc;
339
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000340 CursorResource(StringRef Location) : CursorLoc(Location) {}
341 raw_ostream &log(raw_ostream &) const override;
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000342
343 Twine getResourceTypeName() const override { return "CURSOR"; }
344 Error visit(Visitor *V) const override {
345 return V->visitCursorResource(this);
346 }
347 ResourceKind getKind() const override { return RkCursor; }
348 static bool classof(const RCResource *Res) {
349 return Res->getKind() == RkCursor;
350 }
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000351};
352
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000353// ICON resource. Represents a single ".ico" file containing a group of icons.
354//
355// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
356class IconResource : public RCResource {
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000357public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000358 StringRef IconLoc;
359
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000360 IconResource(StringRef Location) : IconLoc(Location) {}
361 raw_ostream &log(raw_ostream &) const override;
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000362
363 Twine getResourceTypeName() const override { return "ICON"; }
364 Error visit(Visitor *V) const override { return V->visitIconResource(this); }
365 ResourceKind getKind() const override { return RkIcon; }
366 static bool classof(const RCResource *Res) {
367 return Res->getKind() == RkIcon;
368 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000369};
370
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000371// HTML resource. Represents a local webpage that is to be embedded into the
372// resulting resource file. It embeds a file only - no additional resources
373// (images etc.) are included with this resource.
374//
375// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx
376class HTMLResource : public RCResource {
Marek Sokolowski8f193432017-09-29 17:14:09 +0000377public:
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000378 StringRef HTMLLoc;
379
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000380 HTMLResource(StringRef Location) : HTMLLoc(Location) {}
381 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski8f193432017-09-29 17:14:09 +0000382
383 Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
384
385 // Curiously, file resources don't have DISCARDABLE flag set.
386 uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; }
387 IntOrString getResourceType() const override { return RkHTML; }
388 Twine getResourceTypeName() const override { return "HTML"; }
389 ResourceKind getKind() const override { return RkHTML; }
390 static bool classof(const RCResource *Res) {
391 return Res->getKind() == RkHTML;
392 }
Marek Sokolowski72aa9372017-08-28 21:59:54 +0000393};
394
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000395// -- MENU resource and its helper classes --
396// This resource describes the contents of an application menu
397// (usually located in the upper part of the dialog.)
398//
399// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx
400
401// Description of a single submenu item.
402class MenuDefinition {
403public:
404 enum Options {
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000405 CHECKED = 0x0008,
406 GRAYED = 0x0001,
407 HELP = 0x4000,
408 INACTIVE = 0x0002,
409 MENUBARBREAK = 0x0020,
410 MENUBREAK = 0x0040
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000411 };
412
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000413 enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
414
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000415 static constexpr size_t NumFlags = 6;
416 static StringRef OptionsStr[NumFlags];
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000417 static uint32_t OptionsFlags[NumFlags];
418 static raw_ostream &logFlags(raw_ostream &, uint16_t Flags);
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000419 virtual raw_ostream &log(raw_ostream &OS) const {
420 return OS << "Base menu definition\n";
421 }
422 virtual ~MenuDefinition() {}
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000423
424 virtual uint16_t getResFlags() const { return 0; }
425 virtual MenuDefKind getKind() const { return MkBase; }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000426};
427
428// Recursive description of a whole submenu.
429class MenuDefinitionList : public MenuDefinition {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000430public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000431 std::vector<std::unique_ptr<MenuDefinition>> Definitions;
432
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000433 void addDefinition(std::unique_ptr<MenuDefinition> Def) {
434 Definitions.push_back(std::move(Def));
435 }
436 raw_ostream &log(raw_ostream &) const override;
437};
438
439// Separator in MENU definition (MENUITEM SEPARATOR).
440//
441// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
442class MenuSeparator : public MenuDefinition {
443public:
444 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000445
446 MenuDefKind getKind() const override { return MkSeparator; }
447 static bool classof(const MenuDefinition *D) {
448 return D->getKind() == MkSeparator;
449 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000450};
451
452// MENUITEM statement definition.
453//
454// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
455class MenuItem : public MenuDefinition {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000456public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000457 StringRef Name;
458 uint32_t Id;
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000459 uint16_t Flags;
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000460
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000461 MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000462 : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
463 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000464
465 uint16_t getResFlags() const override { return Flags; }
466 MenuDefKind getKind() const override { return MkMenuItem; }
467 static bool classof(const MenuDefinition *D) {
468 return D->getKind() == MkMenuItem;
469 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000470};
471
472// POPUP statement definition.
473//
474// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
475class PopupItem : public MenuDefinition {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000476public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000477 StringRef Name;
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000478 uint16_t Flags;
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000479 MenuDefinitionList SubItems;
480
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000481 PopupItem(StringRef Caption, uint16_t ItemFlags,
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000482 MenuDefinitionList &&SubItemsList)
483 : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
484 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000485
486 // This has an additional (0x10) flag. It doesn't match with documented
487 // 0x01 flag, though.
488 uint16_t getResFlags() const override { return Flags | 0x10; }
489 MenuDefKind getKind() const override { return MkPopup; }
490 static bool classof(const MenuDefinition *D) {
491 return D->getKind() == MkPopup;
492 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000493};
494
495// Menu resource definition.
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000496class MenuResource : public OptStatementsRCResource {
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000497public:
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000498 MenuDefinitionList Elements;
499
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000500 MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items)
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000501 : OptStatementsRCResource(std::move(OptStmts)),
502 Elements(std::move(Items)) {}
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000503 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000504
505 IntOrString getResourceType() const override { return RkMenu; }
506 Twine getResourceTypeName() const override { return "MENU"; }
507 Error visit(Visitor *V) const override { return V->visitMenuResource(this); }
508 ResourceKind getKind() const override { return RkMenu; }
509 static bool classof(const RCResource *Res) {
510 return Res->getKind() == RkMenu;
511 }
Marek Sokolowski99ecb0e2017-08-28 23:46:30 +0000512};
513
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000514// STRINGTABLE resource. Contains a list of strings, each having its unique ID.
515//
516// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000517class StringTableResource : public OptStatementsRCResource {
Zachary Turnerda366692017-10-06 21:30:55 +0000518public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000519 std::vector<std::pair<uint32_t, StringRef>> Table;
520
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000521 using OptStatementsRCResource::OptStatementsRCResource;
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000522 void addString(uint32_t ID, StringRef String) {
523 Table.emplace_back(ID, String);
524 }
525 raw_ostream &log(raw_ostream &) const override;
Zachary Turnerda366692017-10-06 21:30:55 +0000526 Twine getResourceTypeName() const override { return "STRINGTABLE"; }
527 Error visit(Visitor *V) const override {
528 return V->visitStringTableResource(this);
529 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000530};
531
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000532// -- DIALOG(EX) resource and its helper classes --
533//
534// This resource describes dialog boxes and controls residing inside them.
535//
536// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx
537// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
538
539// Single control definition.
540class Control {
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000541public:
542 StringRef Type;
543 IntOrString Title;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000544 uint32_t ID, X, Y, Width, Height;
545 Optional<uint32_t> Style, ExtStyle, HelpID;
Martin Storsjo818bd562018-05-08 20:55:58 +0000546 IntOrString Class;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000547
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000548 // Control classes as described in DLGITEMTEMPLATEEX documentation.
549 //
550 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx
551 enum CtlClasses {
552 ClsButton = 0x80,
553 ClsEdit = 0x81,
554 ClsStatic = 0x82,
555 ClsListBox = 0x83,
556 ClsScrollBar = 0x84,
557 ClsComboBox = 0x85
558 };
559
560 // Simple information about a single control type.
561 struct CtlInfo {
562 uint32_t Style;
563 uint16_t CtlClass;
564 bool HasTitle;
565 };
566
567 Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
568 uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000569 Optional<uint32_t> ItemStyle, Optional<uint32_t> ExtItemStyle,
Martin Storsjo818bd562018-05-08 20:55:58 +0000570 Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000571 : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
572 Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
Martin Storsjo818bd562018-05-08 20:55:58 +0000573 ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000574
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000575 static const StringMap<CtlInfo> SupportedCtls;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000576
577 raw_ostream &log(raw_ostream &) const;
578};
579
580// Single dialog definition. We don't create distinct classes for DIALOG and
581// DIALOGEX because of their being too similar to each other. We only have a
582// flag determining the type of the dialog box.
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000583class DialogResource : public OptStatementsRCResource {
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000584public:
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000585 uint32_t X, Y, Width, Height, HelpID;
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000586 std::vector<Control> Controls;
587 bool IsExtended;
588
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000589 DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
590 uint32_t DlgHeight, uint32_t DlgHelpID,
591 OptionalStmtList &&OptStmts, bool IsDialogEx)
Marek Sokolowskic75a0872017-09-29 17:46:32 +0000592 : OptStatementsRCResource(std::move(OptStmts)), X(PosX), Y(PosY),
593 Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
594 IsExtended(IsDialogEx) {}
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000595
596 void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
597
598 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000599
600 // It was a weird design decision to assign the same resource type number
601 // both for DIALOG and DIALOGEX (and the same structure version number).
602 // It makes it possible for DIALOG to be mistaken for DIALOGEX.
603 IntOrString getResourceType() const override { return RkDialog; }
604 Twine getResourceTypeName() const override {
605 return "DIALOG" + Twine(IsExtended ? "EX" : "");
606 }
607 Error visit(Visitor *V) const override {
608 return V->visitDialogResource(this);
609 }
610 ResourceKind getKind() const override { return RkDialog; }
611 static bool classof(const RCResource *Res) {
612 return Res->getKind() == RkDialog;
613 }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000614};
615
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000616// User-defined resource. It is either:
617// * a link to the file, e.g. NAME TYPE "filename",
618// * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}.
619class UserDefinedResource : public RCResource {
Zachary Turner9d8b3582017-10-06 21:52:15 +0000620public:
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000621 IntOrString Type;
622 StringRef FileLoc;
623 std::vector<IntOrString> Contents;
624 bool IsFileResource;
625
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000626 UserDefinedResource(IntOrString ResourceType, StringRef FileLocation)
627 : Type(ResourceType), FileLoc(FileLocation), IsFileResource(true) {}
628 UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data)
629 : Type(ResourceType), Contents(std::move(Data)), IsFileResource(false) {}
630
631 raw_ostream &log(raw_ostream &) const override;
Zachary Turner9d8b3582017-10-06 21:52:15 +0000632 IntOrString getResourceType() const override { return Type; }
633 Twine getResourceTypeName() const override { return Type; }
634 uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; }
635
636 Error visit(Visitor *V) const override {
637 return V->visitUserDefinedResource(this);
638 }
639 ResourceKind getKind() const override { return RkUser; }
640 static bool classof(const RCResource *Res) {
641 return Res->getKind() == RkUser;
642 }
Marek Sokolowskib5f39a02017-09-29 00:14:18 +0000643};
644
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000645// -- VERSIONINFO resource and its helper classes --
646//
647// This resource lists the version information on the executable/library.
648// The declaration consists of the following items:
649// * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS)
650// * BEGIN
651// * A number of BLOCK and/or VALUE statements. BLOCK recursively defines
652// another block of version information, whereas VALUE defines a
653// key -> value correspondence. There might be more than one value
654// corresponding to the single key.
655// * END
656//
657// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
658
659// A single VERSIONINFO statement;
660class VersionInfoStmt {
661public:
Zachary Turner07bc04f2017-10-06 21:26:06 +0000662 enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
663
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000664 virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
665 virtual ~VersionInfoStmt() {}
Zachary Turner07bc04f2017-10-06 21:26:06 +0000666
667 virtual StmtKind getKind() const { return StBase; }
668 static bool classof(const VersionInfoStmt *S) {
669 return S->getKind() == StBase;
670 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000671};
672
673// BLOCK definition; also the main VERSIONINFO declaration is considered a
674// BLOCK, although it has no name.
675// The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
676// care about them at the parsing phase.
677class VersionInfoBlock : public VersionInfoStmt {
Zachary Turner07bc04f2017-10-06 21:26:06 +0000678public:
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000679 std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
680 StringRef Name;
681
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000682 VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
683 void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
684 Stmts.push_back(std::move(Stmt));
685 }
686 raw_ostream &log(raw_ostream &) const override;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000687
688 StmtKind getKind() const override { return StBlock; }
689 static bool classof(const VersionInfoStmt *S) {
690 return S->getKind() == StBlock;
691 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000692};
693
694class VersionInfoValue : public VersionInfoStmt {
Zachary Turner07bc04f2017-10-06 21:26:06 +0000695public:
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000696 StringRef Key;
697 std::vector<IntOrString> Values;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000698 std::vector<bool> HasPrecedingComma;
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000699
Zachary Turner07bc04f2017-10-06 21:26:06 +0000700 VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
701 std::vector<bool> &&CommasBeforeVals)
702 : Key(InfoKey), Values(std::move(Vals)),
703 HasPrecedingComma(std::move(CommasBeforeVals)) {}
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000704 raw_ostream &log(raw_ostream &) const override;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000705
706 StmtKind getKind() const override { return StValue; }
707 static bool classof(const VersionInfoStmt *S) {
708 return S->getKind() == StValue;
709 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000710};
711
712class VersionInfoResource : public RCResource {
713public:
714 // A class listing fixed VERSIONINFO statements (occuring before main BEGIN).
715 // If any of these is not specified, it is assumed by the original tool to
716 // be equal to 0.
717 class VersionInfoFixed {
718 public:
719 enum VersionInfoFixedType {
720 FtUnknown,
721 FtFileVersion,
722 FtProductVersion,
723 FtFileFlagsMask,
724 FtFileFlags,
725 FtFileOS,
726 FtFileType,
727 FtFileSubtype,
728 FtNumTypes
729 };
730
731 private:
732 static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
733 static const StringRef FixedFieldsNames[FtNumTypes];
734
735 public:
736 SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
737 SmallVector<bool, FtNumTypes> IsTypePresent;
738
739 static VersionInfoFixedType getFixedType(StringRef Type);
740 static bool isTypeSupported(VersionInfoFixedType Type);
741 static bool isVersionType(VersionInfoFixedType Type);
742
743 VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
744
745 void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
746 FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end());
747 IsTypePresent[Type] = true;
748 }
749
750 raw_ostream &log(raw_ostream &) const;
751 };
752
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000753 VersionInfoBlock MainBlock;
754 VersionInfoFixed FixedData;
755
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000756 VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
757 VersionInfoFixed &&FixedInfo)
758 : MainBlock(std::move(TopLevelBlock)), FixedData(std::move(FixedInfo)) {}
759
760 raw_ostream &log(raw_ostream &) const override;
Zachary Turner07bc04f2017-10-06 21:26:06 +0000761 IntOrString getResourceType() const override { return RkVersionInfo; }
762 uint16_t getMemoryFlags() const override { return MfMoveable | MfPure; }
763 Twine getResourceTypeName() const override { return "VERSIONINFO"; }
764 Error visit(Visitor *V) const override {
765 return V->visitVersionInfoResource(this);
766 }
767 ResourceKind getKind() const override { return RkVersionInfo; }
768 static bool classof(const RCResource *Res) {
769 return Res->getKind() == RkVersionInfo;
770 }
Marek Sokolowskifb74cb12017-09-28 22:41:38 +0000771};
772
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000773// CHARACTERISTICS optional statement.
774//
775// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
776class CharacteristicsStmt : public OptionalStmt {
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000777public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000778 uint32_t Value;
779
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000780 CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
781 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000782
783 Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
784 Error visit(Visitor *V) const override {
785 return V->visitCharacteristicsStmt(this);
786 }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000787};
788
789// VERSION optional statement.
790//
791// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
792class VersionStmt : public OptionalStmt {
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000793public:
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000794 uint32_t Value;
795
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000796 VersionStmt(uint32_t Version) : Value(Version) {}
797 raw_ostream &log(raw_ostream &) const override;
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000798
799 Twine getResourceTypeName() const override { return "VERSION"; }
800 Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000801};
802
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000803// CAPTION optional statement.
804//
805// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
806class CaptionStmt : public OptionalStmt {
Zachary Turner420090a2017-10-06 20:51:20 +0000807public:
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000808 StringRef Value;
809
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000810 CaptionStmt(StringRef Caption) : Value(Caption) {}
811 raw_ostream &log(raw_ostream &) const override;
Zachary Turner420090a2017-10-06 20:51:20 +0000812 Twine getResourceTypeName() const override { return "CAPTION"; }
813 Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000814};
815
816// FONT optional statement.
817// Note that the documentation is inaccurate: it expects five arguments to be
818// given, however the example provides only two. In fact, the original tool
819// expects two arguments - point size and name of the typeface.
820//
821// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx
822class FontStmt : public OptionalStmt {
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000823public:
Zachary Turner420090a2017-10-06 20:51:20 +0000824 uint32_t Size, Weight, Charset;
825 StringRef Name;
826 bool Italic;
827
828 FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
829 bool FontItalic, uint32_t FontCharset)
830 : Size(FontSize), Weight(FontWeight), Charset(FontCharset),
831 Name(FontName), Italic(FontItalic) {}
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000832 raw_ostream &log(raw_ostream &) const override;
Zachary Turner420090a2017-10-06 20:51:20 +0000833 Twine getResourceTypeName() const override { return "FONT"; }
834 Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000835};
836
837// STYLE optional statement.
838//
839// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
840class StyleStmt : public OptionalStmt {
Zachary Turner420090a2017-10-06 20:51:20 +0000841public:
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000842 uint32_t Value;
843
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000844 StyleStmt(uint32_t Style) : Value(Style) {}
845 raw_ostream &log(raw_ostream &) const override;
Zachary Turner420090a2017-10-06 20:51:20 +0000846 Twine getResourceTypeName() const override { return "STYLE"; }
847 Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
Marek Sokolowski4ac54d92017-08-29 16:49:59 +0000848};
849
Marek Sokolowski5cd3d5c2017-08-18 18:24:17 +0000850} // namespace rc
851} // namespace llvm
852
853#endif