[llvm-rc] Add support for parsing memory flags
Most of the handling is pretty straightforward; fetch the default
memory flags for the specific resource type before parsing the flags
and apply them on top of that, except that some flags imply others
and some flags clear more than one flag.
For icons and cursors, the flags set get passed on to all individual
single icon/cursor resources, while only some flags affect the icon/cursor
group resource.
For stringtables, the behaviour is pretty simple; the first stringtable
resource of a bundle sets the flags for the whole bundle.
The output of these tests match rc.exe byte for byte.
The actual use of these memory flags is deprecated and they have no
effect since Win16, but some resource script files may still happen
to have them in place.
Differential Revision: https://reviews.llvm.org/D46818
llvm-svn: 332329
diff --git a/llvm/tools/llvm-rc/ResourceFileWriter.cpp b/llvm/tools/llvm-rc/ResourceFileWriter.cpp
index 70274b6..99fdb82 100644
--- a/llvm/tools/llvm-rc/ResourceFileWriter.cpp
+++ b/llvm/tools/llvm-rc/ResourceFileWriter.cpp
@@ -482,8 +482,8 @@
if (Iter == BundleData.end()) {
// Need to create a bundle.
StringTableData.BundleList.push_back(Key);
- auto EmplaceResult =
- BundleData.emplace(Key, StringTableInfo::Bundle(ObjectData));
+ auto EmplaceResult = BundleData.emplace(
+ Key, StringTableInfo::Bundle(ObjectData, Res->MemoryFlags));
assert(EmplaceResult.second && "Could not create a bundle");
Iter = EmplaceResult.first;
}
@@ -556,7 +556,7 @@
padStream(sizeof(uint32_t));
object::WinResHeaderSuffix HeaderSuffix{
ulittle32_t(0), // DataVersion; seems to always be 0
- ulittle16_t(Res->getMemoryFlags()), ulittle16_t(ObjectData.LanguageInfo),
+ ulittle16_t(Res->MemoryFlags), ulittle16_t(ObjectData.LanguageInfo),
ulittle32_t(ObjectData.VersionInfo),
ulittle32_t(ObjectData.Characteristics)};
writeObject(HeaderSuffix);
@@ -785,16 +785,14 @@
SingleIconCursorResource(IconCursorGroupType ResourceType,
const ResourceDirEntryStart &HeaderEntry,
- ArrayRef<uint8_t> ImageData)
- : Type(ResourceType), Header(HeaderEntry), Image(ImageData) {}
+ ArrayRef<uint8_t> ImageData, uint16_t Flags)
+ : RCResource(Flags), Type(ResourceType), Header(HeaderEntry),
+ Image(ImageData) {}
Twine getResourceTypeName() const override { return "Icon/cursor image"; }
IntOrString getResourceType() const override {
return Type == IconCursorGroupType::Icon ? RkSingleIcon : RkSingleCursor;
}
- uint16_t getMemoryFlags() const override {
- return MfDiscardable | MfMoveable;
- }
ResourceKind getKind() const override { return RkSingleCursorOrIconRes; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkSingleCursorOrIconRes;
@@ -915,7 +913,8 @@
Reader.setOffset(ItemOffsets[ID]);
ArrayRef<uint8_t> Image;
RETURN_IF_ERROR(Reader.readArray(Image, ItemEntries[ID].Size));
- SingleIconCursorResource SingleRes(Type, ItemEntries[ID], Image);
+ SingleIconCursorResource SingleRes(Type, ItemEntries[ID], Image,
+ Base->MemoryFlags);
SingleRes.setName(IconCursorID + ID);
RETURN_IF_ERROR(visitSingleIconOrCursor(&SingleRes));
}
@@ -961,6 +960,10 @@
IconCursorGroupResource HeaderRes(Type, *Header, std::move(ItemEntries));
HeaderRes.setName(ResName);
+ if (Base->MemoryFlags & MfPreload) {
+ HeaderRes.MemoryFlags |= MfPreload;
+ HeaderRes.MemoryFlags &= ~MfPure;
+ }
RETURN_IF_ERROR(visitIconOrCursorGroup(&HeaderRes));
return Error::success();
@@ -1214,7 +1217,8 @@
using BundleType = ResourceFileWriter::StringTableInfo::Bundle;
BundleType Bundle;
- BundleResource(const BundleType &StrBundle) : Bundle(StrBundle) {}
+ BundleResource(const BundleType &StrBundle)
+ : RCResource(StrBundle.MemoryFlags), Bundle(StrBundle) {}
IntOrString getResourceType() const override { return 6; }
ResourceKind getKind() const override { return RkStringTableBundle; }
diff --git a/llvm/tools/llvm-rc/ResourceFileWriter.h b/llvm/tools/llvm-rc/ResourceFileWriter.h
index ccec41e..695d455 100644
--- a/llvm/tools/llvm-rc/ResourceFileWriter.h
+++ b/llvm/tools/llvm-rc/ResourceFileWriter.h
@@ -100,7 +100,9 @@
struct Bundle {
std::array<Optional<StringRef>, 16> Data;
ObjectInfo DeclTimeInfo;
- Bundle(const ObjectInfo &Info) : DeclTimeInfo(Info) {}
+ uint16_t MemoryFlags;
+ Bundle(const ObjectInfo &Info, uint16_t Flags)
+ : DeclTimeInfo(Info), MemoryFlags(Flags) {}
};
std::map<BundleKey, Bundle> BundleData;
// Bundles are listed in the order of their first occurrence.
diff --git a/llvm/tools/llvm-rc/ResourceScriptParser.cpp b/llvm/tools/llvm-rc/ResourceScriptParser.cpp
index dbdb221..cdb56f4 100644
--- a/llvm/tools/llvm-rc/ResourceScriptParser.cpp
+++ b/llvm/tools/llvm-rc/ResourceScriptParser.cpp
@@ -329,6 +329,37 @@
return Result;
}
+uint16_t RCParser::parseMemoryFlags(uint16_t Flags) {
+ while (!isEof()) {
+ const RCToken &Token = look();
+ if (Token.kind() != Kind::Identifier)
+ return Flags;
+ const StringRef Ident = Token.value();
+ if (Ident.equals_lower("PRELOAD"))
+ Flags |= MfPreload;
+ else if (Ident.equals_lower("LOADONCALL"))
+ Flags &= ~MfPreload;
+ else if (Ident.equals_lower("FIXED"))
+ Flags &= ~(MfMoveable | MfDiscardable);
+ else if (Ident.equals_lower("MOVEABLE"))
+ Flags |= MfMoveable;
+ else if (Ident.equals_lower("DISCARDABLE"))
+ Flags |= MfDiscardable | MfMoveable | MfPure;
+ else if (Ident.equals_lower("PURE"))
+ Flags |= MfPure;
+ else if (Ident.equals_lower("IMPURE"))
+ Flags &= ~(MfPure | MfDiscardable);
+ else if (Ident.equals_lower("SHARED"))
+ Flags |= MfPure;
+ else if (Ident.equals_lower("NONSHARED"))
+ Flags &= ~(MfPure | MfDiscardable);
+ else
+ return Flags;
+ consume();
+ }
+ return Flags;
+}
+
Expected<OptionalStmtList>
RCParser::parseOptionalStatements(OptStmtType StmtsType) {
OptionalStmtList Result;
@@ -372,11 +403,13 @@
}
RCParser::ParseType RCParser::parseAcceleratorsResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(AcceleratorsResource::getDefaultMemoryFlags());
ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
- auto Accels =
- llvm::make_unique<AcceleratorsResource>(std::move(*OptStatements));
+ auto Accels = llvm::make_unique<AcceleratorsResource>(
+ std::move(*OptStatements), MemoryFlags);
while (!consumeOptionalType(Kind::BlockEnd)) {
ASSIGN_OR_RETURN(EventResult, readIntOrString());
@@ -393,11 +426,15 @@
}
RCParser::ParseType RCParser::parseCursorResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(CursorResource::getDefaultMemoryFlags());
ASSIGN_OR_RETURN(Arg, readFilename());
- return llvm::make_unique<CursorResource>(*Arg);
+ return llvm::make_unique<CursorResource>(*Arg, MemoryFlags);
}
RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(DialogResource::getDefaultMemoryFlags());
// Dialog resources have the following format of the arguments:
// DIALOG: x, y, width, height [opt stmts...] {controls...}
// DIALOGEX: x, y, width, height [, helpID] [opt stmts...] {controls...}
@@ -420,7 +457,7 @@
auto Dialog = llvm::make_unique<DialogResource>(
(*LocResult)[0], (*LocResult)[1], (*LocResult)[2], (*LocResult)[3],
- HelpID, std::move(*OptStatements), IsExtended);
+ HelpID, std::move(*OptStatements), IsExtended, MemoryFlags);
while (!consumeOptionalType(Kind::BlockEnd)) {
ASSIGN_OR_RETURN(ControlDefResult, parseControl());
@@ -431,6 +468,8 @@
}
RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(UserDefinedResource::getDefaultMemoryFlags());
if (isEof())
return getExpectedError("filename, '{' or BEGIN");
@@ -438,7 +477,8 @@
switch (look().kind()) {
case Kind::String:
case Kind::Identifier:
- return llvm::make_unique<UserDefinedResource>(Type, read().value());
+ return llvm::make_unique<UserDefinedResource>(Type, read().value(),
+ MemoryFlags);
default:
break;
}
@@ -457,14 +497,17 @@
Data.push_back(*Item);
}
- return llvm::make_unique<UserDefinedResource>(Type, std::move(Data));
+ return llvm::make_unique<UserDefinedResource>(Type, std::move(Data),
+ MemoryFlags);
}
RCParser::ParseType RCParser::parseVersionInfoResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(VersionInfoResource::getDefaultMemoryFlags());
ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed());
ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef()));
- return llvm::make_unique<VersionInfoResource>(std::move(**BlockResult),
- std::move(*FixedResult));
+ return llvm::make_unique<VersionInfoResource>(
+ std::move(**BlockResult), std::move(*FixedResult), MemoryFlags);
}
Expected<Control> RCParser::parseControl() {
@@ -531,25 +574,33 @@
}
RCParser::ParseType RCParser::parseBitmapResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(BitmapResource::getDefaultMemoryFlags());
ASSIGN_OR_RETURN(Arg, readFilename());
- return llvm::make_unique<BitmapResource>(*Arg);
+ return llvm::make_unique<BitmapResource>(*Arg, MemoryFlags);
}
RCParser::ParseType RCParser::parseIconResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(IconResource::getDefaultMemoryFlags());
ASSIGN_OR_RETURN(Arg, readFilename());
- return llvm::make_unique<IconResource>(*Arg);
+ return llvm::make_unique<IconResource>(*Arg, MemoryFlags);
}
RCParser::ParseType RCParser::parseHTMLResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(HTMLResource::getDefaultMemoryFlags());
ASSIGN_OR_RETURN(Arg, readFilename());
- return llvm::make_unique<HTMLResource>(*Arg);
+ return llvm::make_unique<HTMLResource>(*Arg, MemoryFlags);
}
RCParser::ParseType RCParser::parseMenuResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(MenuResource::getDefaultMemoryFlags());
ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
ASSIGN_OR_RETURN(Items, parseMenuItemsList());
return llvm::make_unique<MenuResource>(std::move(*OptStatements),
- std::move(*Items));
+ std::move(*Items), MemoryFlags);
}
Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
@@ -612,11 +663,13 @@
}
RCParser::ParseType RCParser::parseStringTableResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(StringTableResource::getDefaultMemoryFlags());
ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
- auto Table =
- llvm::make_unique<StringTableResource>(std::move(*OptStatements));
+ auto Table = llvm::make_unique<StringTableResource>(std::move(*OptStatements),
+ MemoryFlags);
// Read strings until we reach the end of the block.
while (!consumeOptionalType(Kind::BlockEnd)) {
diff --git a/llvm/tools/llvm-rc/ResourceScriptParser.h b/llvm/tools/llvm-rc/ResourceScriptParser.h
index 639ef63..8e3cc55 100644
--- a/llvm/tools/llvm-rc/ResourceScriptParser.h
+++ b/llvm/tools/llvm-rc/ResourceScriptParser.h
@@ -129,6 +129,8 @@
// msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
enum class OptStmtType { BasicStmt, DialogStmt, DialogExStmt };
+ uint16_t parseMemoryFlags(uint16_t DefaultFlags);
+
Expected<OptionalStmtList>
parseOptionalStatements(OptStmtType StmtsType = OptStmtType::BasicStmt);
diff --git a/llvm/tools/llvm-rc/ResourceScriptStmt.h b/llvm/tools/llvm-rc/ResourceScriptStmt.h
index 22a569c..c9a0de0 100644
--- a/llvm/tools/llvm-rc/ResourceScriptStmt.h
+++ b/llvm/tools/llvm-rc/ResourceScriptStmt.h
@@ -160,10 +160,13 @@
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 {
@@ -175,9 +178,10 @@
virtual Error applyStmts(Visitor *) const { return Error::success(); }
// By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
- virtual uint16_t getMemoryFlags() const {
+ static uint16_t getDefaultMemoryFlags() {
return MfDiscardable | MfPure | MfMoveable;
}
+
virtual ResourceKind getKind() const { return RkBase; }
static bool classof(const RCResource *Res) { return true; }
@@ -193,13 +197,13 @@
// 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)"; }
- uint16_t getMemoryFlags() const override { return 0; }
};
// Optional statement base. All such statements should derive from this base.
@@ -228,8 +232,10 @@
public:
std::unique_ptr<OptionalStmtList> OptStatements;
- OptStatementsRCResource(OptionalStmtList &&Stmts)
- : OptStatements(llvm::make_unique<OptionalStmtList>(std::move(Stmts))) {}
+ 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); }
};
@@ -284,18 +290,18 @@
static uint32_t OptionsFlags[NumFlags];
};
+ AcceleratorsResource(OptionalStmtList &&List, uint16_t Flags)
+ : OptStatementsRCResource(std::move(List), Flags) {}
+
std::vector<Accelerator> Accelerators;
- using OptStatementsRCResource::OptStatementsRCResource;
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; }
- uint16_t getMemoryFlags() const override {
- return MfPure | MfMoveable;
- }
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
Twine getResourceTypeName() const override { return "ACCELERATORS"; }
Error visit(Visitor *V) const override {
@@ -314,11 +320,12 @@
public:
StringRef BitmapLoc;
- BitmapResource(StringRef Location) : BitmapLoc(Location) {}
+ BitmapResource(StringRef Location, uint16_t Flags)
+ : RCResource(Flags), BitmapLoc(Location) {}
raw_ostream &log(raw_ostream &) const override;
IntOrString getResourceType() const override { return RkBitmap; }
- uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; }
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
Twine getResourceTypeName() const override { return "BITMAP"; }
Error visit(Visitor *V) const override {
@@ -337,10 +344,12 @@
public:
StringRef CursorLoc;
- CursorResource(StringRef Location) : CursorLoc(Location) {}
+ 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);
}
@@ -357,10 +366,12 @@
public:
StringRef IconLoc;
- IconResource(StringRef Location) : IconLoc(Location) {}
+ 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) {
@@ -377,13 +388,14 @@
public:
StringRef HTMLLoc;
- HTMLResource(StringRef Location) : HTMLLoc(Location) {}
+ 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.
- uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; }
+ 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; }
@@ -497,8 +509,9 @@
public:
MenuDefinitionList Elements;
- MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items)
- : OptStatementsRCResource(std::move(OptStmts)),
+ MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
+ uint16_t Flags)
+ : OptStatementsRCResource(std::move(OptStmts), Flags),
Elements(std::move(Items)) {}
raw_ostream &log(raw_ostream &) const override;
@@ -518,7 +531,8 @@
public:
std::vector<std::pair<uint32_t, StringRef>> Table;
- using OptStatementsRCResource::OptStatementsRCResource;
+ StringTableResource(OptionalStmtList &&List, uint16_t Flags)
+ : OptStatementsRCResource(std::move(List), Flags) {}
void addString(uint32_t ID, StringRef String) {
Table.emplace_back(ID, String);
}
@@ -588,8 +602,8 @@
DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
uint32_t DlgHeight, uint32_t DlgHelpID,
- OptionalStmtList &&OptStmts, bool IsDialogEx)
- : OptStatementsRCResource(std::move(OptStmts)), X(PosX), Y(PosY),
+ OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
+ : OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
IsExtended(IsDialogEx) {}
@@ -623,15 +637,19 @@
std::vector<IntOrString> Contents;
bool IsFileResource;
- UserDefinedResource(IntOrString ResourceType, StringRef FileLocation)
- : Type(ResourceType), FileLoc(FileLocation), IsFileResource(true) {}
- UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data)
- : Type(ResourceType), Contents(std::move(Data)), IsFileResource(false) {}
+ 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; }
- uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; }
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
Error visit(Visitor *V) const override {
return V->visitUserDefinedResource(this);
@@ -754,12 +772,13 @@
VersionInfoFixed FixedData;
VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
- VersionInfoFixed &&FixedInfo)
- : MainBlock(std::move(TopLevelBlock)), FixedData(std::move(FixedInfo)) {}
+ 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; }
- uint16_t getMemoryFlags() const override { return MfMoveable | MfPure; }
+ static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
Twine getResourceTypeName() const override { return "VERSIONINFO"; }
Error visit(Visitor *V) const override {
return V->visitVersionInfoResource(this);