1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 04:32:44 +01:00
llvm-mirror/tools/llvm-rc/ResourceScriptStmt.h
Martin Storsjö b52b24c898 [llvm-rc] Allow string table values split into multiple string literals
This can practically easily be a product of combining strings with
macros in resource files.

This fixes https://github.com/mstorsjo/llvm-mingw/issues/140.

As string literals within llvm-rc are handled as StringRefs, each
referencing an uninterpreted slice of the input file, with actual
interpretation of the input string (codepage handling, unescaping etc)
done only right before writing them out to disk, it's hard to
concatenate them other than just bundling them up in a vector,
without rearchitecting a large part of llvm-rc.

This matches how the same already is supported in VersionInfoValue,
with a std::vector<IntOrString> Values.

MS rc.exe only supports concatenated string literals in version info
values (already supported), string tables (implemented in this patch)
and user data resources (easily implemented in a separate patch, but
hasn't been requested by any end user yet), while GNU windres supports
string immediates split into multiple strings anywhere (e.g. like
(100 ICON "myicon" ".ico"). Not sure if concatenation in other
statements actually is used in the wild though, in resource files
normally built by GNU windres.

Differential Revision: https://reviews.llvm.org/D85183
2020-08-05 08:59:32 +03:00

954 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(std::make_unique<OptionalStmtList>(std::move(Stmts))) {}
Error applyStmts(Visitor *V) const override {
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, std::vector<StringRef>>> Table;
StringTableResource(OptionalStmtList &&List, uint16_t Flags)
: OptStatementsRCResource(std::move(List), Flags) {}
void addStrings(uint32_t ID, std::vector<StringRef> &&Strings) {
Table.emplace_back(ID, Strings);
}
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