1//===-- ResourceScriptStmt.h ------------------------------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===---------------------------------------------------------------------===//
8//
9// This lists all the resource and statement types occurring in RC scripts.
10//
11//===---------------------------------------------------------------------===//
12
13#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
14#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
15
16#include "ResourceScriptToken.h"
17#include "ResourceVisitor.h"
18
19#include "llvm/ADT/BitVector.h"
20#include "llvm/ADT/StringMap.h"
21
22namespace llvm {
23namespace rc {
24
25// Integer wrapper that also holds information whether the user declared
26// the integer to be long (by appending L to the end of the integer) or not.
27// It allows to be implicitly cast from and to uint32_t in order
28// to be compatible with the parts of code that don't care about the integers
29// being marked long.
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(args&: Val, args&: Long) = std::make_pair(x: Val + Rhs.Val, y: Long | Rhs.Long);
44 return *this;
45 }
46
47 RCInt &operator-=(const RCInt &Rhs) {
48 std::tie(args&: Val, args&: Long) = std::make_pair(x: Val - Rhs.Val, y: Long | Rhs.Long);
49 return *this;
50 }
51
52 RCInt &operator*=(const RCInt &Rhs) {
53 std::tie(args&: Val, args&: Long) = std::make_pair(x: Val * Rhs.Val, y: Long | Rhs.Long);
54 return *this;
55 }
56
57 RCInt &operator/=(const RCInt &Rhs) {
58 std::tie(args&: Val, args&: Long) = std::make_pair(x: Val / Rhs.Val, y: Long | Rhs.Long);
59 return *this;
60 }
61
62 RCInt &operator|=(const RCInt &Rhs) {
63 std::tie(args&: Val, args&: Long) = std::make_pair(x: Val | Rhs.Val, y: Long | Rhs.Long);
64 return *this;
65 }
66
67 RCInt &operator&=(const RCInt &Rhs) {
68 std::tie(args&: Val, args&: Long) = std::make_pair(x: Val & Rhs.Val, y: Long | Rhs.Long);
69 return *this;
70 }
71
72 RCInt operator-() const { return {-Val, Long}; }
73 RCInt operator~() const { return {~Val, Long}; }
74
75 friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) {
76 return OS << Int.Val << (Int.Long ? "L" : "");
77 }
78};
79
80class IntWithNotMask {
81private:
82 RCInt Value;
83 int32_t NotMask;
84
85public:
86 IntWithNotMask() : IntWithNotMask(RCInt(0)) {}
87 IntWithNotMask(RCInt Value, int32_t NotMask = 0) : Value(Value), NotMask(NotMask) {}
88
89 RCInt getValue() const {
90 return Value;
91 }
92
93 uint32_t getNotMask() const {
94 return NotMask;
95 }
96
97 IntWithNotMask &operator+=(const IntWithNotMask &Rhs) {
98 Value &= ~Rhs.NotMask;
99 Value += Rhs.Value;
100 NotMask |= Rhs.NotMask;
101 return *this;
102 }
103
104 IntWithNotMask &operator-=(const IntWithNotMask &Rhs) {
105 Value &= ~Rhs.NotMask;
106 Value -= Rhs.Value;
107 NotMask |= Rhs.NotMask;
108 return *this;
109 }
110
111 IntWithNotMask &operator*=(const IntWithNotMask &Rhs) {
112 Value &= ~Rhs.NotMask;
113 Value *= Rhs.Value;
114 NotMask |= Rhs.NotMask;
115 return *this;
116 }
117
118 IntWithNotMask &operator/=(const IntWithNotMask &Rhs) {
119 Value &= ~Rhs.NotMask;
120 Value /= Rhs.Value;
121 NotMask |= Rhs.NotMask;
122 return *this;
123 }
124
125 IntWithNotMask &operator|=(const IntWithNotMask &Rhs) {
126 Value &= ~Rhs.NotMask;
127 Value |= Rhs.Value;
128 NotMask |= Rhs.NotMask;
129 return *this;
130 }
131
132 IntWithNotMask &operator&=(const IntWithNotMask &Rhs) {
133 Value &= ~Rhs.NotMask;
134 Value &= Rhs.Value;
135 NotMask |= Rhs.NotMask;
136 return *this;
137 }
138
139 IntWithNotMask operator-() const { return {-Value, NotMask}; }
140 IntWithNotMask operator~() const { return {~Value, 0}; }
141
142 friend raw_ostream &operator<<(raw_ostream &OS, const IntWithNotMask &Int) {
143 return OS << Int.Value;
144 }
145};
146
147// A class holding a name - either an integer or a reference to the string.
148class IntOrString {
149private:
150 union Data {
151 RCInt Int;
152 StringRef String;
153 Data(RCInt Value) : Int(Value) {}
154 Data(const StringRef Value) : String(Value) {}
155 Data(const RCToken &Token) {
156 if (Token.kind() == RCToken::Kind::Int)
157 Int = RCInt(Token);
158 else
159 String = Token.value();
160 }
161 } Data;
162 bool IsInt;
163
164public:
165 IntOrString() : IntOrString(RCInt(0)) {}
166 IntOrString(uint32_t Value) : Data(Value), IsInt(true) {}
167 IntOrString(RCInt Value) : Data(Value), IsInt(true) {}
168 IntOrString(StringRef Value) : Data(Value), IsInt(false) {}
169 IntOrString(const RCToken &Token)
170 : Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {}
171
172 bool equalsLower(const char *Str) const {
173 return !IsInt && Data.String.equals_insensitive(RHS: Str);
174 }
175
176 bool isInt() const { return IsInt; }
177
178 RCInt getInt() const {
179 assert(IsInt);
180 return Data.Int;
181 }
182
183 const StringRef &getString() const {
184 assert(!IsInt);
185 return Data.String;
186 }
187
188 operator Twine() const {
189 return isInt() ? Twine(getInt()) : Twine(getString());
190 }
191
192 friend raw_ostream &operator<<(raw_ostream &, const IntOrString &);
193};
194
195enum ResourceKind {
196 // These resource kinds have corresponding .res resource type IDs
197 // (TYPE in RESOURCEHEADER structure). The numeric value assigned to each
198 // kind is equal to this type ID.
199 RkNull = 0,
200 RkSingleCursor = 1,
201 RkBitmap = 2,
202 RkSingleIcon = 3,
203 RkMenu = 4,
204 RkDialog = 5,
205 RkStringTableBundle = 6,
206 RkAccelerators = 9,
207 RkRcData = 10,
208 RkCursorGroup = 12,
209 RkIconGroup = 14,
210 RkVersionInfo = 16,
211 RkHTML = 23,
212
213 // These kinds don't have assigned type IDs (they might be the resources
214 // of invalid kind, expand to many resource structures in .res files,
215 // or have variable type ID). In order to avoid ID clashes with IDs above,
216 // we assign the kinds the values 256 and larger.
217 RkInvalid = 256,
218 RkBase,
219 RkCursor,
220 RkIcon,
221 RkStringTable,
222 RkUser,
223 RkSingleCursorOrIconRes,
224 RkCursorOrIconGroupRes,
225};
226
227// Non-zero memory flags.
228// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
229enum MemoryFlags {
230 MfMoveable = 0x10,
231 MfPure = 0x20,
232 MfPreload = 0x40,
233 MfDiscardable = 0x1000
234};
235
236// Base resource. All the resources should derive from this base.
237class RCResource {
238public:
239 IntOrString ResName;
240 uint16_t MemoryFlags = getDefaultMemoryFlags();
241 void setName(const IntOrString &Name) { ResName = Name; }
242 virtual raw_ostream &log(raw_ostream &OS) const {
243 return OS << "Base statement\n";
244 };
245 RCResource() {}
246 RCResource(uint16_t Flags) : MemoryFlags(Flags) {}
247 virtual ~RCResource() {}
248
249 virtual Error visit(Visitor *) const {
250 llvm_unreachable("This is unable to call methods from Visitor base");
251 }
252
253 // Apply the statements attached to this resource. Generic resources
254 // don't have any.
255 virtual Error applyStmts(Visitor *) const { return Error::success(); }
256
257 // By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
258 static uint16_t getDefaultMemoryFlags() {
259 return MfDiscardable | MfPure | MfMoveable;
260 }
261
262 virtual ResourceKind getKind() const { return RkBase; }
263 static bool classof(const RCResource *Res) { return true; }
264
265 virtual IntOrString getResourceType() const {
266 llvm_unreachable("This cannot be called on objects without types.");
267 }
268 virtual Twine getResourceTypeName() const {
269 llvm_unreachable("This cannot be called on objects without types.");
270 };
271};
272
273// An empty resource. It has no content, type 0, ID 0 and all of its
274// characteristics are equal to 0.
275class NullResource : public RCResource {
276public:
277 NullResource() : RCResource(0) {}
278 raw_ostream &log(raw_ostream &OS) const override {
279 return OS << "Null resource\n";
280 }
281 Error visit(Visitor *V) const override { return V->visitNullResource(this); }
282 IntOrString getResourceType() const override { return 0; }
283 Twine getResourceTypeName() const override { return "(NULL)"; }
284};
285
286// Optional statement base. All such statements should derive from this base.
287class OptionalStmt : public RCResource {};
288
289class OptionalStmtList : public OptionalStmt {
290 std::vector<std::unique_ptr<OptionalStmt>> Statements;
291
292public:
293 OptionalStmtList() {}
294 raw_ostream &log(raw_ostream &OS) const override;
295
296 void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
297 Statements.push_back(x: std::move(Stmt));
298 }
299
300 Error visit(Visitor *V) const override {
301 for (auto &StmtPtr : Statements)
302 if (auto Err = StmtPtr->visit(V))
303 return Err;
304 return Error::success();
305 }
306};
307
308class OptStatementsRCResource : public RCResource {
309public:
310 std::unique_ptr<OptionalStmtList> OptStatements;
311
312 OptStatementsRCResource(OptionalStmtList &&Stmts,
313 uint16_t Flags = RCResource::getDefaultMemoryFlags())
314 : RCResource(Flags),
315 OptStatements(std::make_unique<OptionalStmtList>(args: std::move(Stmts))) {}
316
317 Error applyStmts(Visitor *V) const override {
318 return OptStatements->visit(V);
319 }
320};
321
322// LANGUAGE statement. It can occur both as a top-level statement (in such
323// a situation, it changes the default language until the end of the file)
324// and as an optional resource statement (then it changes the language
325// of a single resource).
326//
327// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx
328class LanguageResource : public OptionalStmt {
329public:
330 uint32_t Lang, SubLang;
331
332 LanguageResource(uint32_t LangId, uint32_t SubLangId)
333 : Lang(LangId), SubLang(SubLangId) {}
334 raw_ostream &log(raw_ostream &) const override;
335
336 // This is not a regular top-level statement; when it occurs, it just
337 // modifies the language context.
338 Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
339 Twine getResourceTypeName() const override { return "LANGUAGE"; }
340};
341
342// ACCELERATORS resource. Defines a named table of accelerators for the app.
343//
344// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx
345class AcceleratorsResource : public OptStatementsRCResource {
346public:
347 class Accelerator {
348 public:
349 IntOrString Event;
350 uint32_t Id;
351 uint16_t Flags;
352
353 enum Options {
354 // This is actually 0x0000 (accelerator is assumed to be ASCII if it's
355 // not VIRTKEY). However, rc.exe behavior is different in situations
356 // "only ASCII defined" and "neither ASCII nor VIRTKEY defined".
357 // Therefore, we include ASCII as another flag. This must be zeroed
358 // when serialized.
359 ASCII = 0x8000,
360 VIRTKEY = 0x0001,
361 NOINVERT = 0x0002,
362 ALT = 0x0010,
363 SHIFT = 0x0004,
364 CONTROL = 0x0008
365 };
366
367 static constexpr size_t NumFlags = 6;
368 static StringRef OptionsStr[NumFlags];
369 static uint32_t OptionsFlags[NumFlags];
370 };
371
372 AcceleratorsResource(OptionalStmtList &&List, uint16_t Flags)
373 : OptStatementsRCResource(std::move(List), Flags) {}
374
375 std::vector<Accelerator> Accelerators;
376
377 void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
378 Accelerators.push_back(x: Accelerator{.Event: Event, .Id: Id, .Flags: Flags});
379 }
380 raw_ostream &log(raw_ostream &) const override;
381
382 IntOrString getResourceType() const override { return RkAccelerators; }
383 static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
384 Twine getResourceTypeName() const override { return "ACCELERATORS"; }
385
386 Error visit(Visitor *V) const override {
387 return V->visitAcceleratorsResource(this);
388 }
389 ResourceKind getKind() const override { return RkAccelerators; }
390 static bool classof(const RCResource *Res) {
391 return Res->getKind() == RkAccelerators;
392 }
393};
394
395// BITMAP resource. Represents a bitmap (".bmp") file.
396//
397// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx
398class BitmapResource : public RCResource {
399public:
400 StringRef BitmapLoc;
401
402 BitmapResource(StringRef Location, uint16_t Flags)
403 : RCResource(Flags), BitmapLoc(Location) {}
404 raw_ostream &log(raw_ostream &) const override;
405
406 IntOrString getResourceType() const override { return RkBitmap; }
407 static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
408
409 Twine getResourceTypeName() const override { return "BITMAP"; }
410 Error visit(Visitor *V) const override {
411 return V->visitBitmapResource(this);
412 }
413 ResourceKind getKind() const override { return RkBitmap; }
414 static bool classof(const RCResource *Res) {
415 return Res->getKind() == RkBitmap;
416 }
417};
418
419// CURSOR resource. Represents a single cursor (".cur") file.
420//
421// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
422class CursorResource : public RCResource {
423public:
424 StringRef CursorLoc;
425
426 CursorResource(StringRef Location, uint16_t Flags)
427 : RCResource(Flags), CursorLoc(Location) {}
428 raw_ostream &log(raw_ostream &) const override;
429
430 Twine getResourceTypeName() const override { return "CURSOR"; }
431 static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
432 Error visit(Visitor *V) const override {
433 return V->visitCursorResource(this);
434 }
435 ResourceKind getKind() const override { return RkCursor; }
436 static bool classof(const RCResource *Res) {
437 return Res->getKind() == RkCursor;
438 }
439};
440
441// ICON resource. Represents a single ".ico" file containing a group of icons.
442//
443// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
444class IconResource : public RCResource {
445public:
446 StringRef IconLoc;
447
448 IconResource(StringRef Location, uint16_t Flags)
449 : RCResource(Flags), IconLoc(Location) {}
450 raw_ostream &log(raw_ostream &) const override;
451
452 Twine getResourceTypeName() const override { return "ICON"; }
453 static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
454 Error visit(Visitor *V) const override { return V->visitIconResource(this); }
455 ResourceKind getKind() const override { return RkIcon; }
456 static bool classof(const RCResource *Res) {
457 return Res->getKind() == RkIcon;
458 }
459};
460
461// HTML resource. Represents a local webpage that is to be embedded into the
462// resulting resource file. It embeds a file only - no additional resources
463// (images etc.) are included with this resource.
464//
465// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx
466class HTMLResource : public RCResource {
467public:
468 StringRef HTMLLoc;
469
470 HTMLResource(StringRef Location, uint16_t Flags)
471 : RCResource(Flags), HTMLLoc(Location) {}
472 raw_ostream &log(raw_ostream &) const override;
473
474 Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
475
476 // Curiously, file resources don't have DISCARDABLE flag set.
477 static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
478 IntOrString getResourceType() const override { return RkHTML; }
479 Twine getResourceTypeName() const override { return "HTML"; }
480 ResourceKind getKind() const override { return RkHTML; }
481 static bool classof(const RCResource *Res) {
482 return Res->getKind() == RkHTML;
483 }
484};
485
486// -- MENU resource and its helper classes --
487// This resource describes the contents of an application menu
488// (usually located in the upper part of the dialog.)
489//
490// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx
491
492// Description of a single submenu item.
493class MenuDefinition {
494public:
495 enum Options {
496 CHECKED = 0x0008,
497 GRAYED = 0x0001,
498 HELP = 0x4000,
499 INACTIVE = 0x0002,
500 MENUBARBREAK = 0x0020,
501 MENUBREAK = 0x0040
502 };
503
504 enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
505
506 static constexpr size_t NumFlags = 6;
507 static StringRef OptionsStr[NumFlags];
508 static uint32_t OptionsFlags[NumFlags];
509 static raw_ostream &logFlags(raw_ostream &, uint16_t Flags);
510 virtual raw_ostream &log(raw_ostream &OS) const {
511 return OS << "Base menu definition\n";
512 }
513 virtual ~MenuDefinition() {}
514
515 virtual uint16_t getResFlags() const { return 0; }
516 virtual MenuDefKind getKind() const { return MkBase; }
517};
518
519// Recursive description of a whole submenu.
520class MenuDefinitionList : public MenuDefinition {
521public:
522 std::vector<std::unique_ptr<MenuDefinition>> Definitions;
523
524 void addDefinition(std::unique_ptr<MenuDefinition> Def) {
525 Definitions.push_back(x: std::move(Def));
526 }
527 raw_ostream &log(raw_ostream &) const override;
528};
529
530// Separator in MENU definition (MENUITEM SEPARATOR).
531//
532// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
533class MenuSeparator : public MenuDefinition {
534public:
535 raw_ostream &log(raw_ostream &) const override;
536
537 MenuDefKind getKind() const override { return MkSeparator; }
538 static bool classof(const MenuDefinition *D) {
539 return D->getKind() == MkSeparator;
540 }
541};
542
543// MENUITEM statement definition.
544//
545// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
546class MenuItem : public MenuDefinition {
547public:
548 StringRef Name;
549 uint32_t Id;
550 uint16_t Flags;
551
552 MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
553 : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
554 raw_ostream &log(raw_ostream &) const override;
555
556 uint16_t getResFlags() const override { return Flags; }
557 MenuDefKind getKind() const override { return MkMenuItem; }
558 static bool classof(const MenuDefinition *D) {
559 return D->getKind() == MkMenuItem;
560 }
561};
562
563class MenuExItem : public MenuDefinition {
564public:
565 StringRef Name;
566 uint32_t Id;
567 uint32_t Type;
568 uint32_t State;
569
570 MenuExItem(StringRef Caption, uint32_t ItemId, uint32_t Type, uint32_t State)
571 : Name(Caption), Id(ItemId), Type(Type), State(State) {}
572 raw_ostream &log(raw_ostream &) const override;
573
574 MenuDefKind getKind() const override { return MkMenuItem; }
575 static bool classof(const MenuDefinition *D) {
576 return D->getKind() == MkMenuItem;
577 }
578};
579
580// POPUP statement definition.
581//
582// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
583class PopupItem : public MenuDefinition {
584public:
585 StringRef Name;
586 uint16_t Flags;
587 MenuDefinitionList SubItems;
588
589 PopupItem(StringRef Caption, uint16_t ItemFlags,
590 MenuDefinitionList &&SubItemsList)
591 : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
592 raw_ostream &log(raw_ostream &) const override;
593
594 // This has an additional MF_POPUP (0x10) flag.
595 uint16_t getResFlags() const override { return Flags | 0x10; }
596 MenuDefKind getKind() const override { return MkPopup; }
597 static bool classof(const MenuDefinition *D) {
598 return D->getKind() == MkPopup;
599 }
600};
601
602class PopupExItem : public MenuDefinition {
603public:
604 StringRef Name;
605 uint32_t Id;
606 uint32_t Type;
607 uint32_t State;
608 uint32_t HelpId;
609 MenuDefinitionList SubItems;
610
611 PopupExItem(StringRef Caption, uint32_t Id, uint32_t Type, uint32_t State,
612 uint32_t HelpId, MenuDefinitionList &&SubItemsList)
613 : Name(Caption), Id(Id), Type(Type), State(State), HelpId(HelpId),
614 SubItems(std::move(SubItemsList)) {}
615 raw_ostream &log(raw_ostream &) const override;
616
617 uint16_t getResFlags() const override { return 0x01; }
618 MenuDefKind getKind() const override { return MkPopup; }
619 static bool classof(const MenuDefinition *D) {
620 return D->getKind() == MkPopup;
621 }
622};
623
624// Menu resource definition.
625class MenuResource : public OptStatementsRCResource {
626public:
627 MenuDefinitionList Elements;
628
629 MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
630 uint16_t Flags)
631 : OptStatementsRCResource(std::move(OptStmts), Flags),
632 Elements(std::move(Items)) {}
633 raw_ostream &log(raw_ostream &) const override;
634
635 IntOrString getResourceType() const override { return RkMenu; }
636 Twine getResourceTypeName() const override { return "MENU"; }
637 Error visit(Visitor *V) const override { return V->visitMenuResource(this); }
638 ResourceKind getKind() const override { return RkMenu; }
639 static bool classof(const RCResource *Res) {
640 return Res->getKind() == RkMenu;
641 }
642};
643
644class MenuExResource : public OptStatementsRCResource {
645public:
646 MenuDefinitionList Elements;
647
648 MenuExResource(MenuDefinitionList &&Items, uint16_t Flags)
649 : OptStatementsRCResource({}, Flags), Elements(std::move(Items)) {}
650 raw_ostream &log(raw_ostream &) const override;
651
652 IntOrString getResourceType() const override { return RkMenu; }
653 Twine getResourceTypeName() const override { return "MENUEX"; }
654 Error visit(Visitor *V) const override {
655 return V->visitMenuExResource(this);
656 }
657 ResourceKind getKind() const override { return RkMenu; }
658 static bool classof(const RCResource *Res) {
659 return Res->getKind() == RkMenu;
660 }
661};
662
663// STRINGTABLE resource. Contains a list of strings, each having its unique ID.
664//
665// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
666class StringTableResource : public OptStatementsRCResource {
667public:
668 std::vector<std::pair<uint32_t, std::vector<StringRef>>> Table;
669
670 StringTableResource(OptionalStmtList &&List, uint16_t Flags)
671 : OptStatementsRCResource(std::move(List), Flags) {}
672 void addStrings(uint32_t ID, std::vector<StringRef> &&Strings) {
673 Table.emplace_back(args&: ID, args&: Strings);
674 }
675 raw_ostream &log(raw_ostream &) const override;
676 Twine getResourceTypeName() const override { return "STRINGTABLE"; }
677 Error visit(Visitor *V) const override {
678 return V->visitStringTableResource(this);
679 }
680};
681
682// -- DIALOG(EX) resource and its helper classes --
683//
684// This resource describes dialog boxes and controls residing inside them.
685//
686// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx
687// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
688
689// Single control definition.
690class Control {
691public:
692 StringRef Type;
693 IntOrString Title;
694 uint32_t ID, X, Y, Width, Height;
695 std::optional<IntWithNotMask> Style;
696 std::optional<uint32_t> ExtStyle, HelpID;
697 IntOrString Class;
698
699 // Control classes as described in DLGITEMTEMPLATEEX documentation.
700 //
701 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx
702 enum CtlClasses {
703 ClsButton = 0x80,
704 ClsEdit = 0x81,
705 ClsStatic = 0x82,
706 ClsListBox = 0x83,
707 ClsScrollBar = 0x84,
708 ClsComboBox = 0x85
709 };
710
711 // Simple information about a single control type.
712 struct CtlInfo {
713 uint32_t Style;
714 uint16_t CtlClass;
715 bool HasTitle;
716 };
717
718 Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
719 uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
720 std::optional<IntWithNotMask> ItemStyle,
721 std::optional<uint32_t> ExtItemStyle,
722 std::optional<uint32_t> CtlHelpID, IntOrString CtlClass)
723 : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
724 Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
725 ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
726
727 static const StringMap<CtlInfo> SupportedCtls;
728
729 raw_ostream &log(raw_ostream &) const;
730};
731
732// Single dialog definition. We don't create distinct classes for DIALOG and
733// DIALOGEX because of their being too similar to each other. We only have a
734// flag determining the type of the dialog box.
735class DialogResource : public OptStatementsRCResource {
736public:
737 uint32_t X, Y, Width, Height, HelpID;
738 std::vector<Control> Controls;
739 bool IsExtended;
740
741 DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
742 uint32_t DlgHeight, uint32_t DlgHelpID,
743 OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
744 : OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
745 Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
746 IsExtended(IsDialogEx) {}
747
748 void addControl(Control &&Ctl) { Controls.push_back(x: std::move(Ctl)); }
749
750 raw_ostream &log(raw_ostream &) const override;
751
752 // It was a weird design decision to assign the same resource type number
753 // both for DIALOG and DIALOGEX (and the same structure version number).
754 // It makes it possible for DIALOG to be mistaken for DIALOGEX.
755 IntOrString getResourceType() const override { return RkDialog; }
756 Twine getResourceTypeName() const override {
757 return "DIALOG" + Twine(IsExtended ? "EX" : "");
758 }
759 Error visit(Visitor *V) const override {
760 return V->visitDialogResource(this);
761 }
762 ResourceKind getKind() const override { return RkDialog; }
763 static bool classof(const RCResource *Res) {
764 return Res->getKind() == RkDialog;
765 }
766};
767
768// User-defined resource. It is either:
769// * a link to the file, e.g. NAME TYPE "filename",
770// * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}.
771class UserDefinedResource : public RCResource {
772public:
773 IntOrString Type;
774 StringRef FileLoc;
775 std::vector<IntOrString> Contents;
776 bool IsFileResource;
777
778 UserDefinedResource(IntOrString ResourceType, StringRef FileLocation,
779 uint16_t Flags)
780 : RCResource(Flags), Type(ResourceType), FileLoc(FileLocation),
781 IsFileResource(true) {}
782 UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data,
783 uint16_t Flags)
784 : RCResource(Flags), Type(ResourceType), Contents(std::move(Data)),
785 IsFileResource(false) {}
786
787 raw_ostream &log(raw_ostream &) const override;
788 IntOrString getResourceType() const override { return Type; }
789 Twine getResourceTypeName() const override { return Type; }
790 static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
791
792 Error visit(Visitor *V) const override {
793 return V->visitUserDefinedResource(this);
794 }
795 ResourceKind getKind() const override { return RkUser; }
796 static bool classof(const RCResource *Res) {
797 return Res->getKind() == RkUser;
798 }
799};
800
801// -- VERSIONINFO resource and its helper classes --
802//
803// This resource lists the version information on the executable/library.
804// The declaration consists of the following items:
805// * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS)
806// * BEGIN
807// * A number of BLOCK and/or VALUE statements. BLOCK recursively defines
808// another block of version information, whereas VALUE defines a
809// key -> value correspondence. There might be more than one value
810// corresponding to the single key.
811// * END
812//
813// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
814
815// A single VERSIONINFO statement;
816class VersionInfoStmt {
817public:
818 enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
819
820 virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
821 virtual ~VersionInfoStmt() {}
822
823 virtual StmtKind getKind() const { return StBase; }
824 static bool classof(const VersionInfoStmt *S) {
825 return S->getKind() == StBase;
826 }
827};
828
829// BLOCK definition; also the main VERSIONINFO declaration is considered a
830// BLOCK, although it has no name.
831// The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
832// care about them at the parsing phase.
833class VersionInfoBlock : public VersionInfoStmt {
834public:
835 std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
836 StringRef Name;
837
838 VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
839 void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
840 Stmts.push_back(x: std::move(Stmt));
841 }
842 raw_ostream &log(raw_ostream &) const override;
843
844 StmtKind getKind() const override { return StBlock; }
845 static bool classof(const VersionInfoStmt *S) {
846 return S->getKind() == StBlock;
847 }
848};
849
850class VersionInfoValue : public VersionInfoStmt {
851public:
852 StringRef Key;
853 std::vector<IntOrString> Values;
854 BitVector HasPrecedingComma;
855
856 VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
857 BitVector &&CommasBeforeVals)
858 : Key(InfoKey), Values(std::move(Vals)),
859 HasPrecedingComma(std::move(CommasBeforeVals)) {}
860 raw_ostream &log(raw_ostream &) const override;
861
862 StmtKind getKind() const override { return StValue; }
863 static bool classof(const VersionInfoStmt *S) {
864 return S->getKind() == StValue;
865 }
866};
867
868class VersionInfoResource : public RCResource {
869public:
870 // A class listing fixed VERSIONINFO statements (occuring before main BEGIN).
871 // If any of these is not specified, it is assumed by the original tool to
872 // be equal to 0.
873 class VersionInfoFixed {
874 public:
875 enum VersionInfoFixedType {
876 FtUnknown,
877 FtFileVersion,
878 FtProductVersion,
879 FtFileFlagsMask,
880 FtFileFlags,
881 FtFileOS,
882 FtFileType,
883 FtFileSubtype,
884 FtNumTypes
885 };
886
887 private:
888 static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
889 static const StringRef FixedFieldsNames[FtNumTypes];
890
891 public:
892 SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
893 SmallVector<bool, FtNumTypes> IsTypePresent;
894
895 static VersionInfoFixedType getFixedType(StringRef Type);
896 static bool isTypeSupported(VersionInfoFixedType Type);
897 static bool isVersionType(VersionInfoFixedType Type);
898
899 VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
900
901 void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
902 FixedInfo[Type] = SmallVector<uint32_t, 4>(Value);
903 IsTypePresent[Type] = true;
904 }
905
906 raw_ostream &log(raw_ostream &) const;
907 };
908
909 VersionInfoBlock MainBlock;
910 VersionInfoFixed FixedData;
911
912 VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
913 VersionInfoFixed &&FixedInfo, uint16_t Flags)
914 : RCResource(Flags), MainBlock(std::move(TopLevelBlock)),
915 FixedData(std::move(FixedInfo)) {}
916
917 raw_ostream &log(raw_ostream &) const override;
918 IntOrString getResourceType() const override { return RkVersionInfo; }
919 static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
920 Twine getResourceTypeName() const override { return "VERSIONINFO"; }
921 Error visit(Visitor *V) const override {
922 return V->visitVersionInfoResource(this);
923 }
924 ResourceKind getKind() const override { return RkVersionInfo; }
925 static bool classof(const RCResource *Res) {
926 return Res->getKind() == RkVersionInfo;
927 }
928};
929
930// CHARACTERISTICS optional statement.
931//
932// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
933class CharacteristicsStmt : public OptionalStmt {
934public:
935 uint32_t Value;
936
937 CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
938 raw_ostream &log(raw_ostream &) const override;
939
940 Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
941 Error visit(Visitor *V) const override {
942 return V->visitCharacteristicsStmt(this);
943 }
944};
945
946// VERSION optional statement.
947//
948// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
949class VersionStmt : public OptionalStmt {
950public:
951 uint32_t Value;
952
953 VersionStmt(uint32_t Version) : Value(Version) {}
954 raw_ostream &log(raw_ostream &) const override;
955
956 Twine getResourceTypeName() const override { return "VERSION"; }
957 Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
958};
959
960// CAPTION optional statement.
961//
962// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
963class CaptionStmt : public OptionalStmt {
964public:
965 StringRef Value;
966
967 CaptionStmt(StringRef Caption) : Value(Caption) {}
968 raw_ostream &log(raw_ostream &) const override;
969 Twine getResourceTypeName() const override { return "CAPTION"; }
970 Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
971};
972
973// FONT optional statement.
974// Note that the documentation is inaccurate: it expects five arguments to be
975// given, however the example provides only two. In fact, the original tool
976// expects two arguments - point size and name of the typeface.
977//
978// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx
979class FontStmt : public OptionalStmt {
980public:
981 uint32_t Size, Weight, Charset;
982 StringRef Name;
983 bool Italic;
984
985 FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
986 bool FontItalic, uint32_t FontCharset)
987 : Size(FontSize), Weight(FontWeight), Charset(FontCharset),
988 Name(FontName), Italic(FontItalic) {}
989 raw_ostream &log(raw_ostream &) const override;
990 Twine getResourceTypeName() const override { return "FONT"; }
991 Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
992};
993
994// STYLE optional statement.
995//
996// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
997class StyleStmt : public OptionalStmt {
998public:
999 uint32_t Value;
1000
1001 StyleStmt(uint32_t Style) : Value(Style) {}
1002 raw_ostream &log(raw_ostream &) const override;
1003 Twine getResourceTypeName() const override { return "STYLE"; }
1004 Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
1005};
1006
1007// EXSTYLE optional statement.
1008//
1009// Ref: docs.microsoft.com/en-us/windows/desktop/menurc/exstyle-statement
1010class ExStyleStmt : public OptionalStmt {
1011public:
1012 uint32_t Value;
1013
1014 ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {}
1015 raw_ostream &log(raw_ostream &) const override;
1016 Twine getResourceTypeName() const override { return "EXSTYLE"; }
1017 Error visit(Visitor *V) const override { return V->visitExStyleStmt(this); }
1018};
1019
1020// MENU optional statement.
1021//
1022// Ref: https://learn.microsoft.com/en-us/windows/win32/menurc/menu-statement
1023class MenuStmt : public OptionalStmt {
1024public:
1025 IntOrString Value;
1026
1027 MenuStmt(IntOrString NameOrId) : Value(NameOrId) {}
1028 raw_ostream &log(raw_ostream &) const override;
1029 Twine getResourceTypeName() const override { return "MENU"; }
1030 Error visit(Visitor *V) const override { return V->visitMenuStmt(this); }
1031};
1032
1033// CLASS optional statement.
1034//
1035// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380883(v=vs.85).aspx
1036class ClassStmt : public OptionalStmt {
1037public:
1038 IntOrString Value;
1039
1040 ClassStmt(IntOrString Class) : Value(Class) {}
1041 raw_ostream &log(raw_ostream &) const override;
1042 Twine getResourceTypeName() const override { return "CLASS"; }
1043 Error visit(Visitor *V) const override { return V->visitClassStmt(this); }
1044};
1045
1046} // namespace rc
1047} // namespace llvm
1048
1049#endif
1050