mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
ae65e281f3
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
952 lines
30 KiB
C++
952 lines
30 KiB
C++
//===-- ResourceScriptStmt.h ------------------------------------*- C++-*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===---------------------------------------------------------------------===//
|
|
//
|
|
// This lists all the resource and statement types occurring in RC scripts.
|
|
//
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
|
|
#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
|
|
|
|
#include "ResourceScriptToken.h"
|
|
#include "ResourceVisitor.h"
|
|
|
|
#include "llvm/ADT/StringSet.h"
|
|
|
|
namespace llvm {
|
|
namespace rc {
|
|
|
|
// Integer wrapper that also holds information whether the user declared
|
|
// the integer to be long (by appending L to the end of the integer) or not.
|
|
// It allows to be implicitly cast from and to uint32_t in order
|
|
// to be compatible with the parts of code that don't care about the integers
|
|
// being marked long.
|
|
class RCInt {
|
|
uint32_t Val;
|
|
bool Long;
|
|
|
|
public:
|
|
RCInt(const RCToken &Token)
|
|
: Val(Token.intValue()), Long(Token.isLongInt()) {}
|
|
RCInt(uint32_t Value) : Val(Value), Long(false) {}
|
|
RCInt(uint32_t Value, bool IsLong) : Val(Value), Long(IsLong) {}
|
|
operator uint32_t() const { return Val; }
|
|
bool isLong() const { return Long; }
|
|
|
|
RCInt &operator+=(const RCInt &Rhs) {
|
|
std::tie(Val, Long) = std::make_pair(Val + Rhs.Val, Long | Rhs.Long);
|
|
return *this;
|
|
}
|
|
|
|
RCInt &operator-=(const RCInt &Rhs) {
|
|
std::tie(Val, Long) = std::make_pair(Val - Rhs.Val, Long | Rhs.Long);
|
|
return *this;
|
|
}
|
|
|
|
RCInt &operator|=(const RCInt &Rhs) {
|
|
std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long);
|
|
return *this;
|
|
}
|
|
|
|
RCInt &operator&=(const RCInt &Rhs) {
|
|
std::tie(Val, Long) = std::make_pair(Val & Rhs.Val, Long | Rhs.Long);
|
|
return *this;
|
|
}
|
|
|
|
RCInt operator-() const { return {-Val, Long}; }
|
|
RCInt operator~() const { return {~Val, Long}; }
|
|
|
|
friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) {
|
|
return OS << Int.Val << (Int.Long ? "L" : "");
|
|
}
|
|
};
|
|
|
|
class IntWithNotMask {
|
|
private:
|
|
RCInt Value;
|
|
int32_t NotMask;
|
|
|
|
public:
|
|
IntWithNotMask() : IntWithNotMask(RCInt(0)) {}
|
|
IntWithNotMask(RCInt Value, int32_t NotMask = 0) : Value(Value), NotMask(NotMask) {}
|
|
|
|
RCInt getValue() const {
|
|
return Value;
|
|
}
|
|
|
|
uint32_t getNotMask() const {
|
|
return NotMask;
|
|
}
|
|
|
|
IntWithNotMask &operator+=(const IntWithNotMask &Rhs) {
|
|
Value &= ~Rhs.NotMask;
|
|
Value += Rhs.Value;
|
|
NotMask |= Rhs.NotMask;
|
|
return *this;
|
|
}
|
|
|
|
IntWithNotMask &operator-=(const IntWithNotMask &Rhs) {
|
|
Value &= ~Rhs.NotMask;
|
|
Value -= Rhs.Value;
|
|
NotMask |= Rhs.NotMask;
|
|
return *this;
|
|
}
|
|
|
|
IntWithNotMask &operator|=(const IntWithNotMask &Rhs) {
|
|
Value &= ~Rhs.NotMask;
|
|
Value |= Rhs.Value;
|
|
NotMask |= Rhs.NotMask;
|
|
return *this;
|
|
}
|
|
|
|
IntWithNotMask &operator&=(const IntWithNotMask &Rhs) {
|
|
Value &= ~Rhs.NotMask;
|
|
Value &= Rhs.Value;
|
|
NotMask |= Rhs.NotMask;
|
|
return *this;
|
|
}
|
|
|
|
IntWithNotMask operator-() const { return {-Value, NotMask}; }
|
|
IntWithNotMask operator~() const { return {~Value, 0}; }
|
|
|
|
friend raw_ostream &operator<<(raw_ostream &OS, const IntWithNotMask &Int) {
|
|
return OS << Int.Value;
|
|
}
|
|
};
|
|
|
|
// A class holding a name - either an integer or a reference to the string.
|
|
class IntOrString {
|
|
private:
|
|
union Data {
|
|
RCInt Int;
|
|
StringRef String;
|
|
Data(RCInt Value) : Int(Value) {}
|
|
Data(const StringRef Value) : String(Value) {}
|
|
Data(const RCToken &Token) {
|
|
if (Token.kind() == RCToken::Kind::Int)
|
|
Int = RCInt(Token);
|
|
else
|
|
String = Token.value();
|
|
}
|
|
} Data;
|
|
bool IsInt;
|
|
|
|
public:
|
|
IntOrString() : IntOrString(RCInt(0)) {}
|
|
IntOrString(uint32_t Value) : Data(Value), IsInt(1) {}
|
|
IntOrString(RCInt Value) : Data(Value), IsInt(1) {}
|
|
IntOrString(StringRef Value) : Data(Value), IsInt(0) {}
|
|
IntOrString(const RCToken &Token)
|
|
: Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {}
|
|
|
|
bool equalsLower(const char *Str) {
|
|
return !IsInt && Data.String.equals_lower(Str);
|
|
}
|
|
|
|
bool isInt() const { return IsInt; }
|
|
|
|
RCInt getInt() const {
|
|
assert(IsInt);
|
|
return Data.Int;
|
|
}
|
|
|
|
const StringRef &getString() const {
|
|
assert(!IsInt);
|
|
return Data.String;
|
|
}
|
|
|
|
operator Twine() const {
|
|
return isInt() ? Twine(getInt()) : Twine(getString());
|
|
}
|
|
|
|
friend raw_ostream &operator<<(raw_ostream &, const IntOrString &);
|
|
};
|
|
|
|
enum ResourceKind {
|
|
// These resource kinds have corresponding .res resource type IDs
|
|
// (TYPE in RESOURCEHEADER structure). The numeric value assigned to each
|
|
// kind is equal to this type ID.
|
|
RkNull = 0,
|
|
RkSingleCursor = 1,
|
|
RkBitmap = 2,
|
|
RkSingleIcon = 3,
|
|
RkMenu = 4,
|
|
RkDialog = 5,
|
|
RkStringTableBundle = 6,
|
|
RkAccelerators = 9,
|
|
RkRcData = 10,
|
|
RkCursorGroup = 12,
|
|
RkIconGroup = 14,
|
|
RkVersionInfo = 16,
|
|
RkHTML = 23,
|
|
|
|
// These kinds don't have assigned type IDs (they might be the resources
|
|
// of invalid kind, expand to many resource structures in .res files,
|
|
// or have variable type ID). In order to avoid ID clashes with IDs above,
|
|
// we assign the kinds the values 256 and larger.
|
|
RkInvalid = 256,
|
|
RkBase,
|
|
RkCursor,
|
|
RkIcon,
|
|
RkStringTable,
|
|
RkUser,
|
|
RkSingleCursorOrIconRes,
|
|
RkCursorOrIconGroupRes,
|
|
};
|
|
|
|
// Non-zero memory flags.
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
|
|
enum MemoryFlags {
|
|
MfMoveable = 0x10,
|
|
MfPure = 0x20,
|
|
MfPreload = 0x40,
|
|
MfDiscardable = 0x1000
|
|
};
|
|
|
|
// Base resource. All the resources should derive from this base.
|
|
class RCResource {
|
|
public:
|
|
IntOrString ResName;
|
|
uint16_t MemoryFlags = getDefaultMemoryFlags();
|
|
void setName(const IntOrString &Name) { ResName = Name; }
|
|
virtual raw_ostream &log(raw_ostream &OS) const {
|
|
return OS << "Base statement\n";
|
|
};
|
|
RCResource() {}
|
|
RCResource(uint16_t Flags) : MemoryFlags(Flags) {}
|
|
virtual ~RCResource() {}
|
|
|
|
virtual Error visit(Visitor *) const {
|
|
llvm_unreachable("This is unable to call methods from Visitor base");
|
|
}
|
|
|
|
// Apply the statements attached to this resource. Generic resources
|
|
// don't have any.
|
|
virtual Error applyStmts(Visitor *) const { return Error::success(); }
|
|
|
|
// By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
|
|
static uint16_t getDefaultMemoryFlags() {
|
|
return MfDiscardable | MfPure | MfMoveable;
|
|
}
|
|
|
|
virtual ResourceKind getKind() const { return RkBase; }
|
|
static bool classof(const RCResource *Res) { return true; }
|
|
|
|
virtual IntOrString getResourceType() const {
|
|
llvm_unreachable("This cannot be called on objects without types.");
|
|
}
|
|
virtual Twine getResourceTypeName() const {
|
|
llvm_unreachable("This cannot be called on objects without types.");
|
|
};
|
|
};
|
|
|
|
// An empty resource. It has no content, type 0, ID 0 and all of its
|
|
// characteristics are equal to 0.
|
|
class NullResource : public RCResource {
|
|
public:
|
|
NullResource() : RCResource(0) {}
|
|
raw_ostream &log(raw_ostream &OS) const override {
|
|
return OS << "Null resource\n";
|
|
}
|
|
Error visit(Visitor *V) const override { return V->visitNullResource(this); }
|
|
IntOrString getResourceType() const override { return 0; }
|
|
Twine getResourceTypeName() const override { return "(NULL)"; }
|
|
};
|
|
|
|
// Optional statement base. All such statements should derive from this base.
|
|
class OptionalStmt : public RCResource {};
|
|
|
|
class OptionalStmtList : public OptionalStmt {
|
|
std::vector<std::unique_ptr<OptionalStmt>> Statements;
|
|
|
|
public:
|
|
OptionalStmtList() {}
|
|
raw_ostream &log(raw_ostream &OS) const override;
|
|
|
|
void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
|
|
Statements.push_back(std::move(Stmt));
|
|
}
|
|
|
|
Error visit(Visitor *V) const override {
|
|
for (auto &StmtPtr : Statements)
|
|
if (auto Err = StmtPtr->visit(V))
|
|
return Err;
|
|
return Error::success();
|
|
}
|
|
};
|
|
|
|
class OptStatementsRCResource : public RCResource {
|
|
public:
|
|
std::unique_ptr<OptionalStmtList> OptStatements;
|
|
|
|
OptStatementsRCResource(OptionalStmtList &&Stmts,
|
|
uint16_t Flags = RCResource::getDefaultMemoryFlags())
|
|
: RCResource(Flags),
|
|
OptStatements(llvm::make_unique<OptionalStmtList>(std::move(Stmts))) {}
|
|
|
|
virtual Error applyStmts(Visitor *V) const { return OptStatements->visit(V); }
|
|
};
|
|
|
|
// LANGUAGE statement. It can occur both as a top-level statement (in such
|
|
// a situation, it changes the default language until the end of the file)
|
|
// and as an optional resource statement (then it changes the language
|
|
// of a single resource).
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx
|
|
class LanguageResource : public OptionalStmt {
|
|
public:
|
|
uint32_t Lang, SubLang;
|
|
|
|
LanguageResource(uint32_t LangId, uint32_t SubLangId)
|
|
: Lang(LangId), SubLang(SubLangId) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
// This is not a regular top-level statement; when it occurs, it just
|
|
// modifies the language context.
|
|
Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
|
|
Twine getResourceTypeName() const override { return "LANGUAGE"; }
|
|
};
|
|
|
|
// ACCELERATORS resource. Defines a named table of accelerators for the app.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx
|
|
class AcceleratorsResource : public OptStatementsRCResource {
|
|
public:
|
|
class Accelerator {
|
|
public:
|
|
IntOrString Event;
|
|
uint32_t Id;
|
|
uint16_t Flags;
|
|
|
|
enum Options {
|
|
// This is actually 0x0000 (accelerator is assumed to be ASCII if it's
|
|
// not VIRTKEY). However, rc.exe behavior is different in situations
|
|
// "only ASCII defined" and "neither ASCII nor VIRTKEY defined".
|
|
// Therefore, we include ASCII as another flag. This must be zeroed
|
|
// when serialized.
|
|
ASCII = 0x8000,
|
|
VIRTKEY = 0x0001,
|
|
NOINVERT = 0x0002,
|
|
ALT = 0x0010,
|
|
SHIFT = 0x0004,
|
|
CONTROL = 0x0008
|
|
};
|
|
|
|
static constexpr size_t NumFlags = 6;
|
|
static StringRef OptionsStr[NumFlags];
|
|
static uint32_t OptionsFlags[NumFlags];
|
|
};
|
|
|
|
AcceleratorsResource(OptionalStmtList &&List, uint16_t Flags)
|
|
: OptStatementsRCResource(std::move(List), Flags) {}
|
|
|
|
std::vector<Accelerator> Accelerators;
|
|
|
|
void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
|
|
Accelerators.push_back(Accelerator{Event, Id, Flags});
|
|
}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
IntOrString getResourceType() const override { return RkAccelerators; }
|
|
static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
|
|
Twine getResourceTypeName() const override { return "ACCELERATORS"; }
|
|
|
|
Error visit(Visitor *V) const override {
|
|
return V->visitAcceleratorsResource(this);
|
|
}
|
|
ResourceKind getKind() const override { return RkAccelerators; }
|
|
static bool classof(const RCResource *Res) {
|
|
return Res->getKind() == RkAccelerators;
|
|
}
|
|
};
|
|
|
|
// BITMAP resource. Represents a bitmap (".bmp") file.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx
|
|
class BitmapResource : public RCResource {
|
|
public:
|
|
StringRef BitmapLoc;
|
|
|
|
BitmapResource(StringRef Location, uint16_t Flags)
|
|
: RCResource(Flags), BitmapLoc(Location) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
IntOrString getResourceType() const override { return RkBitmap; }
|
|
static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
|
|
|
|
Twine getResourceTypeName() const override { return "BITMAP"; }
|
|
Error visit(Visitor *V) const override {
|
|
return V->visitBitmapResource(this);
|
|
}
|
|
ResourceKind getKind() const override { return RkBitmap; }
|
|
static bool classof(const RCResource *Res) {
|
|
return Res->getKind() == RkBitmap;
|
|
}
|
|
};
|
|
|
|
// CURSOR resource. Represents a single cursor (".cur") file.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
|
|
class CursorResource : public RCResource {
|
|
public:
|
|
StringRef CursorLoc;
|
|
|
|
CursorResource(StringRef Location, uint16_t Flags)
|
|
: RCResource(Flags), CursorLoc(Location) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
Twine getResourceTypeName() const override { return "CURSOR"; }
|
|
static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
|
|
Error visit(Visitor *V) const override {
|
|
return V->visitCursorResource(this);
|
|
}
|
|
ResourceKind getKind() const override { return RkCursor; }
|
|
static bool classof(const RCResource *Res) {
|
|
return Res->getKind() == RkCursor;
|
|
}
|
|
};
|
|
|
|
// ICON resource. Represents a single ".ico" file containing a group of icons.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
|
|
class IconResource : public RCResource {
|
|
public:
|
|
StringRef IconLoc;
|
|
|
|
IconResource(StringRef Location, uint16_t Flags)
|
|
: RCResource(Flags), IconLoc(Location) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
Twine getResourceTypeName() const override { return "ICON"; }
|
|
static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
|
|
Error visit(Visitor *V) const override { return V->visitIconResource(this); }
|
|
ResourceKind getKind() const override { return RkIcon; }
|
|
static bool classof(const RCResource *Res) {
|
|
return Res->getKind() == RkIcon;
|
|
}
|
|
};
|
|
|
|
// HTML resource. Represents a local webpage that is to be embedded into the
|
|
// resulting resource file. It embeds a file only - no additional resources
|
|
// (images etc.) are included with this resource.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx
|
|
class HTMLResource : public RCResource {
|
|
public:
|
|
StringRef HTMLLoc;
|
|
|
|
HTMLResource(StringRef Location, uint16_t Flags)
|
|
: RCResource(Flags), HTMLLoc(Location) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
|
|
|
|
// Curiously, file resources don't have DISCARDABLE flag set.
|
|
static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
|
|
IntOrString getResourceType() const override { return RkHTML; }
|
|
Twine getResourceTypeName() const override { return "HTML"; }
|
|
ResourceKind getKind() const override { return RkHTML; }
|
|
static bool classof(const RCResource *Res) {
|
|
return Res->getKind() == RkHTML;
|
|
}
|
|
};
|
|
|
|
// -- MENU resource and its helper classes --
|
|
// This resource describes the contents of an application menu
|
|
// (usually located in the upper part of the dialog.)
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx
|
|
|
|
// Description of a single submenu item.
|
|
class MenuDefinition {
|
|
public:
|
|
enum Options {
|
|
CHECKED = 0x0008,
|
|
GRAYED = 0x0001,
|
|
HELP = 0x4000,
|
|
INACTIVE = 0x0002,
|
|
MENUBARBREAK = 0x0020,
|
|
MENUBREAK = 0x0040
|
|
};
|
|
|
|
enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
|
|
|
|
static constexpr size_t NumFlags = 6;
|
|
static StringRef OptionsStr[NumFlags];
|
|
static uint32_t OptionsFlags[NumFlags];
|
|
static raw_ostream &logFlags(raw_ostream &, uint16_t Flags);
|
|
virtual raw_ostream &log(raw_ostream &OS) const {
|
|
return OS << "Base menu definition\n";
|
|
}
|
|
virtual ~MenuDefinition() {}
|
|
|
|
virtual uint16_t getResFlags() const { return 0; }
|
|
virtual MenuDefKind getKind() const { return MkBase; }
|
|
};
|
|
|
|
// Recursive description of a whole submenu.
|
|
class MenuDefinitionList : public MenuDefinition {
|
|
public:
|
|
std::vector<std::unique_ptr<MenuDefinition>> Definitions;
|
|
|
|
void addDefinition(std::unique_ptr<MenuDefinition> Def) {
|
|
Definitions.push_back(std::move(Def));
|
|
}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
};
|
|
|
|
// Separator in MENU definition (MENUITEM SEPARATOR).
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
|
|
class MenuSeparator : public MenuDefinition {
|
|
public:
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
MenuDefKind getKind() const override { return MkSeparator; }
|
|
static bool classof(const MenuDefinition *D) {
|
|
return D->getKind() == MkSeparator;
|
|
}
|
|
};
|
|
|
|
// MENUITEM statement definition.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
|
|
class MenuItem : public MenuDefinition {
|
|
public:
|
|
StringRef Name;
|
|
uint32_t Id;
|
|
uint16_t Flags;
|
|
|
|
MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
|
|
: Name(Caption), Id(ItemId), Flags(ItemFlags) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
uint16_t getResFlags() const override { return Flags; }
|
|
MenuDefKind getKind() const override { return MkMenuItem; }
|
|
static bool classof(const MenuDefinition *D) {
|
|
return D->getKind() == MkMenuItem;
|
|
}
|
|
};
|
|
|
|
// POPUP statement definition.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
|
|
class PopupItem : public MenuDefinition {
|
|
public:
|
|
StringRef Name;
|
|
uint16_t Flags;
|
|
MenuDefinitionList SubItems;
|
|
|
|
PopupItem(StringRef Caption, uint16_t ItemFlags,
|
|
MenuDefinitionList &&SubItemsList)
|
|
: Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
// This has an additional (0x10) flag. It doesn't match with documented
|
|
// 0x01 flag, though.
|
|
uint16_t getResFlags() const override { return Flags | 0x10; }
|
|
MenuDefKind getKind() const override { return MkPopup; }
|
|
static bool classof(const MenuDefinition *D) {
|
|
return D->getKind() == MkPopup;
|
|
}
|
|
};
|
|
|
|
// Menu resource definition.
|
|
class MenuResource : public OptStatementsRCResource {
|
|
public:
|
|
MenuDefinitionList Elements;
|
|
|
|
MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
|
|
uint16_t Flags)
|
|
: OptStatementsRCResource(std::move(OptStmts), Flags),
|
|
Elements(std::move(Items)) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
IntOrString getResourceType() const override { return RkMenu; }
|
|
Twine getResourceTypeName() const override { return "MENU"; }
|
|
Error visit(Visitor *V) const override { return V->visitMenuResource(this); }
|
|
ResourceKind getKind() const override { return RkMenu; }
|
|
static bool classof(const RCResource *Res) {
|
|
return Res->getKind() == RkMenu;
|
|
}
|
|
};
|
|
|
|
// STRINGTABLE resource. Contains a list of strings, each having its unique ID.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
|
|
class StringTableResource : public OptStatementsRCResource {
|
|
public:
|
|
std::vector<std::pair<uint32_t, StringRef>> Table;
|
|
|
|
StringTableResource(OptionalStmtList &&List, uint16_t Flags)
|
|
: OptStatementsRCResource(std::move(List), Flags) {}
|
|
void addString(uint32_t ID, StringRef String) {
|
|
Table.emplace_back(ID, String);
|
|
}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
Twine getResourceTypeName() const override { return "STRINGTABLE"; }
|
|
Error visit(Visitor *V) const override {
|
|
return V->visitStringTableResource(this);
|
|
}
|
|
};
|
|
|
|
// -- DIALOG(EX) resource and its helper classes --
|
|
//
|
|
// This resource describes dialog boxes and controls residing inside them.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
|
|
|
|
// Single control definition.
|
|
class Control {
|
|
public:
|
|
StringRef Type;
|
|
IntOrString Title;
|
|
uint32_t ID, X, Y, Width, Height;
|
|
Optional<IntWithNotMask> Style;
|
|
Optional<uint32_t> ExtStyle, HelpID;
|
|
IntOrString Class;
|
|
|
|
// Control classes as described in DLGITEMTEMPLATEEX documentation.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx
|
|
enum CtlClasses {
|
|
ClsButton = 0x80,
|
|
ClsEdit = 0x81,
|
|
ClsStatic = 0x82,
|
|
ClsListBox = 0x83,
|
|
ClsScrollBar = 0x84,
|
|
ClsComboBox = 0x85
|
|
};
|
|
|
|
// Simple information about a single control type.
|
|
struct CtlInfo {
|
|
uint32_t Style;
|
|
uint16_t CtlClass;
|
|
bool HasTitle;
|
|
};
|
|
|
|
Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
|
|
uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
|
|
Optional<IntWithNotMask> ItemStyle, Optional<uint32_t> ExtItemStyle,
|
|
Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
|
|
: Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
|
|
Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
|
|
ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
|
|
|
|
static const StringMap<CtlInfo> SupportedCtls;
|
|
|
|
raw_ostream &log(raw_ostream &) const;
|
|
};
|
|
|
|
// Single dialog definition. We don't create distinct classes for DIALOG and
|
|
// DIALOGEX because of their being too similar to each other. We only have a
|
|
// flag determining the type of the dialog box.
|
|
class DialogResource : public OptStatementsRCResource {
|
|
public:
|
|
uint32_t X, Y, Width, Height, HelpID;
|
|
std::vector<Control> Controls;
|
|
bool IsExtended;
|
|
|
|
DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
|
|
uint32_t DlgHeight, uint32_t DlgHelpID,
|
|
OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
|
|
: OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
|
|
Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
|
|
IsExtended(IsDialogEx) {}
|
|
|
|
void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
|
|
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
// It was a weird design decision to assign the same resource type number
|
|
// both for DIALOG and DIALOGEX (and the same structure version number).
|
|
// It makes it possible for DIALOG to be mistaken for DIALOGEX.
|
|
IntOrString getResourceType() const override { return RkDialog; }
|
|
Twine getResourceTypeName() const override {
|
|
return "DIALOG" + Twine(IsExtended ? "EX" : "");
|
|
}
|
|
Error visit(Visitor *V) const override {
|
|
return V->visitDialogResource(this);
|
|
}
|
|
ResourceKind getKind() const override { return RkDialog; }
|
|
static bool classof(const RCResource *Res) {
|
|
return Res->getKind() == RkDialog;
|
|
}
|
|
};
|
|
|
|
// User-defined resource. It is either:
|
|
// * a link to the file, e.g. NAME TYPE "filename",
|
|
// * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}.
|
|
class UserDefinedResource : public RCResource {
|
|
public:
|
|
IntOrString Type;
|
|
StringRef FileLoc;
|
|
std::vector<IntOrString> Contents;
|
|
bool IsFileResource;
|
|
|
|
UserDefinedResource(IntOrString ResourceType, StringRef FileLocation,
|
|
uint16_t Flags)
|
|
: RCResource(Flags), Type(ResourceType), FileLoc(FileLocation),
|
|
IsFileResource(true) {}
|
|
UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data,
|
|
uint16_t Flags)
|
|
: RCResource(Flags), Type(ResourceType), Contents(std::move(Data)),
|
|
IsFileResource(false) {}
|
|
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
IntOrString getResourceType() const override { return Type; }
|
|
Twine getResourceTypeName() const override { return Type; }
|
|
static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
|
|
|
|
Error visit(Visitor *V) const override {
|
|
return V->visitUserDefinedResource(this);
|
|
}
|
|
ResourceKind getKind() const override { return RkUser; }
|
|
static bool classof(const RCResource *Res) {
|
|
return Res->getKind() == RkUser;
|
|
}
|
|
};
|
|
|
|
// -- VERSIONINFO resource and its helper classes --
|
|
//
|
|
// This resource lists the version information on the executable/library.
|
|
// The declaration consists of the following items:
|
|
// * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS)
|
|
// * BEGIN
|
|
// * A number of BLOCK and/or VALUE statements. BLOCK recursively defines
|
|
// another block of version information, whereas VALUE defines a
|
|
// key -> value correspondence. There might be more than one value
|
|
// corresponding to the single key.
|
|
// * END
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
|
|
|
|
// A single VERSIONINFO statement;
|
|
class VersionInfoStmt {
|
|
public:
|
|
enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
|
|
|
|
virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
|
|
virtual ~VersionInfoStmt() {}
|
|
|
|
virtual StmtKind getKind() const { return StBase; }
|
|
static bool classof(const VersionInfoStmt *S) {
|
|
return S->getKind() == StBase;
|
|
}
|
|
};
|
|
|
|
// BLOCK definition; also the main VERSIONINFO declaration is considered a
|
|
// BLOCK, although it has no name.
|
|
// The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
|
|
// care about them at the parsing phase.
|
|
class VersionInfoBlock : public VersionInfoStmt {
|
|
public:
|
|
std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
|
|
StringRef Name;
|
|
|
|
VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
|
|
void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
|
|
Stmts.push_back(std::move(Stmt));
|
|
}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
StmtKind getKind() const override { return StBlock; }
|
|
static bool classof(const VersionInfoStmt *S) {
|
|
return S->getKind() == StBlock;
|
|
}
|
|
};
|
|
|
|
class VersionInfoValue : public VersionInfoStmt {
|
|
public:
|
|
StringRef Key;
|
|
std::vector<IntOrString> Values;
|
|
std::vector<bool> HasPrecedingComma;
|
|
|
|
VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
|
|
std::vector<bool> &&CommasBeforeVals)
|
|
: Key(InfoKey), Values(std::move(Vals)),
|
|
HasPrecedingComma(std::move(CommasBeforeVals)) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
StmtKind getKind() const override { return StValue; }
|
|
static bool classof(const VersionInfoStmt *S) {
|
|
return S->getKind() == StValue;
|
|
}
|
|
};
|
|
|
|
class VersionInfoResource : public RCResource {
|
|
public:
|
|
// A class listing fixed VERSIONINFO statements (occuring before main BEGIN).
|
|
// If any of these is not specified, it is assumed by the original tool to
|
|
// be equal to 0.
|
|
class VersionInfoFixed {
|
|
public:
|
|
enum VersionInfoFixedType {
|
|
FtUnknown,
|
|
FtFileVersion,
|
|
FtProductVersion,
|
|
FtFileFlagsMask,
|
|
FtFileFlags,
|
|
FtFileOS,
|
|
FtFileType,
|
|
FtFileSubtype,
|
|
FtNumTypes
|
|
};
|
|
|
|
private:
|
|
static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
|
|
static const StringRef FixedFieldsNames[FtNumTypes];
|
|
|
|
public:
|
|
SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
|
|
SmallVector<bool, FtNumTypes> IsTypePresent;
|
|
|
|
static VersionInfoFixedType getFixedType(StringRef Type);
|
|
static bool isTypeSupported(VersionInfoFixedType Type);
|
|
static bool isVersionType(VersionInfoFixedType Type);
|
|
|
|
VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
|
|
|
|
void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
|
|
FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end());
|
|
IsTypePresent[Type] = true;
|
|
}
|
|
|
|
raw_ostream &log(raw_ostream &) const;
|
|
};
|
|
|
|
VersionInfoBlock MainBlock;
|
|
VersionInfoFixed FixedData;
|
|
|
|
VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
|
|
VersionInfoFixed &&FixedInfo, uint16_t Flags)
|
|
: RCResource(Flags), MainBlock(std::move(TopLevelBlock)),
|
|
FixedData(std::move(FixedInfo)) {}
|
|
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
IntOrString getResourceType() const override { return RkVersionInfo; }
|
|
static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
|
|
Twine getResourceTypeName() const override { return "VERSIONINFO"; }
|
|
Error visit(Visitor *V) const override {
|
|
return V->visitVersionInfoResource(this);
|
|
}
|
|
ResourceKind getKind() const override { return RkVersionInfo; }
|
|
static bool classof(const RCResource *Res) {
|
|
return Res->getKind() == RkVersionInfo;
|
|
}
|
|
};
|
|
|
|
// CHARACTERISTICS optional statement.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
|
|
class CharacteristicsStmt : public OptionalStmt {
|
|
public:
|
|
uint32_t Value;
|
|
|
|
CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
|
|
Error visit(Visitor *V) const override {
|
|
return V->visitCharacteristicsStmt(this);
|
|
}
|
|
};
|
|
|
|
// VERSION optional statement.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
|
|
class VersionStmt : public OptionalStmt {
|
|
public:
|
|
uint32_t Value;
|
|
|
|
VersionStmt(uint32_t Version) : Value(Version) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
|
|
Twine getResourceTypeName() const override { return "VERSION"; }
|
|
Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
|
|
};
|
|
|
|
// CAPTION optional statement.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
|
|
class CaptionStmt : public OptionalStmt {
|
|
public:
|
|
StringRef Value;
|
|
|
|
CaptionStmt(StringRef Caption) : Value(Caption) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
Twine getResourceTypeName() const override { return "CAPTION"; }
|
|
Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
|
|
};
|
|
|
|
// FONT optional statement.
|
|
// Note that the documentation is inaccurate: it expects five arguments to be
|
|
// given, however the example provides only two. In fact, the original tool
|
|
// expects two arguments - point size and name of the typeface.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx
|
|
class FontStmt : public OptionalStmt {
|
|
public:
|
|
uint32_t Size, Weight, Charset;
|
|
StringRef Name;
|
|
bool Italic;
|
|
|
|
FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
|
|
bool FontItalic, uint32_t FontCharset)
|
|
: Size(FontSize), Weight(FontWeight), Charset(FontCharset),
|
|
Name(FontName), Italic(FontItalic) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
Twine getResourceTypeName() const override { return "FONT"; }
|
|
Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
|
|
};
|
|
|
|
// STYLE optional statement.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
|
|
class StyleStmt : public OptionalStmt {
|
|
public:
|
|
uint32_t Value;
|
|
|
|
StyleStmt(uint32_t Style) : Value(Style) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
Twine getResourceTypeName() const override { return "STYLE"; }
|
|
Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
|
|
};
|
|
|
|
// EXSTYLE optional statement.
|
|
//
|
|
// Ref: docs.microsoft.com/en-us/windows/desktop/menurc/exstyle-statement
|
|
class ExStyleStmt : public OptionalStmt {
|
|
public:
|
|
uint32_t Value;
|
|
|
|
ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
Twine getResourceTypeName() const override { return "EXSTYLE"; }
|
|
Error visit(Visitor *V) const override { return V->visitExStyleStmt(this); }
|
|
};
|
|
|
|
// CLASS optional statement.
|
|
//
|
|
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380883(v=vs.85).aspx
|
|
class ClassStmt : public OptionalStmt {
|
|
public:
|
|
IntOrString Value;
|
|
|
|
ClassStmt(IntOrString Class) : Value(Class) {}
|
|
raw_ostream &log(raw_ostream &) const override;
|
|
Twine getResourceTypeName() const override { return "CLASS"; }
|
|
Error visit(Visitor *V) const override { return V->visitClassStmt(this); }
|
|
};
|
|
|
|
} // namespace rc
|
|
} // namespace llvm
|
|
|
|
#endif
|