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