[llvm-rc] Add user-defined resources parsing ability. [8/8]

This allows llvm-rc to parse user-defined resources (ref:
msdn.microsoft.com/en-us/library/windows/desktop/aa381054.aspx).
These statements either import files, or put the specified raw data in
the resulting resource file.

Thanks to Nico Weber for his original work in this area.

Differential Revision: https://reviews.llvm.org/D37033

llvm-svn: 314478
This commit is contained in:
Marek Sokolowski 2017-09-29 00:14:18 +00:00
parent 7e89ee7fdc
commit b5f39a05a3
7 changed files with 81 additions and 2 deletions

View File

@ -111,3 +111,13 @@ BEGIN
END
END
MYNAME MYTYPE "filename"
500 600 "other filename"
HELLO INTEGERS {1, 2, 3, 4}
HELLO STRINGS {"1", "2", "3", "4"}
4 MIXED {1, "2", 3, "4"}

View File

@ -0,0 +1,4 @@
MYNAME MYTYPE
BEGIN
1, 2, InvalidToken
END

View File

@ -91,6 +91,12 @@
; PGOOD-NEXT: "Translation" => 1033 1252
; PGOOD-NEXT: End of block
; PGOOD-NEXT: End of block
; PGOOD-NEXT: User-defined (type: MYTYPE, name: MYNAME): "filename"
; PGOOD-NEXT: User-defined (type: 600, name: 500): "other filename"
; PGOOD-NEXT: User-defined (type: INTEGERS, name: HELLO): data = 1 2 3 4
; PGOOD-NEXT: User-defined (type: STRINGS, name: HELLO): data = "1" "2" "3" "4"
; PGOOD-NEXT: User-defined (type: MIXED, name: 4): data = 1 "2" 3 "4"
@ -121,7 +127,7 @@
; RUN: not llvm-rc /V %p/Inputs/parser-nonsense-type.rc 2>&1 | FileCheck %s --check-prefix PNONSENSE2
; PNONSENSE2: llvm-rc: Error parsing file: expected resource type, got WORLD
; PNONSENSE2: llvm-rc: Error parsing file: expected filename, '{' or BEGIN, got <EOF>
; RUN: not llvm-rc /V %p/Inputs/parser-nonsense-type-eof.rc 2>&1 | FileCheck %s --check-prefix PNONSENSE3
@ -242,3 +248,8 @@
; RUN: not llvm-rc /V %p/Inputs/parser-versioninfo-repeated-fixed.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO6
; PVERSIONINFO6: llvm-rc: Error parsing file: expected yet unread fixed VERSIONINFO statement type, got FILEVERSION
; RUN: not llvm-rc /V %p/Inputs/parser-user-invalid-contents.rc 2>&1 | FileCheck %s --check-prefix PUSER1
; PUSER1: llvm-rc: Error parsing file: expected int or string, got InvalidToken

View File

@ -80,7 +80,7 @@ RCParser::ParseType RCParser::parseSingleResource() {
else if (TypeToken->equalsLower("VERSIONINFO"))
Result = parseVersionInfoResource();
else
return getExpectedError("resource type", /* IsAlreadyRead = */ true);
Result = parseUserDefinedResource(*TypeToken);
if (Result)
(*Result)->setName(*NameToken);
@ -416,6 +416,31 @@ RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
return std::move(Dialog);
}
RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
if (isEof())
return getExpectedError("filename, '{' or BEGIN");
// Check if this is a file resource.
if (look().kind() == Kind::String)
return make_unique<UserDefinedResource>(Type, read().value());
RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
std::vector<IntOrString> Data;
// Consume comma before each consecutive token except the first one.
bool ConsumeComma = false;
while (!consumeOptionalType(Kind::BlockEnd)) {
if (ConsumeComma)
RETURN_IF_ERROR(consumeType(Kind::Comma));
ConsumeComma = true;
ASSIGN_OR_RETURN(Item, readIntOrString());
Data.push_back(*Item);
}
return make_unique<UserDefinedResource>(Type, std::move(Data));
}
RCParser::ParseType RCParser::parseVersionInfoResource() {
ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed());
ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef()));

View File

@ -139,6 +139,7 @@ private:
ParseType parseHTMLResource();
ParseType parseMenuResource();
ParseType parseStringTableResource();
ParseType parseUserDefinedResource(IntOrString Type);
ParseType parseVersionInfoResource();
// Helper DIALOG parser - a single control.

View File

@ -214,6 +214,16 @@ raw_ostream &VersionInfoResource::log(raw_ostream &OS) const {
return MainBlock.log(OS);
}
raw_ostream &UserDefinedResource::log(raw_ostream &OS) const {
OS << "User-defined (type: " << Type << ", name: " << ResName << "): ";
if (IsFileResource)
return OS << FileLoc << "\n";
OS << "data = ";
for (auto &Item : Contents)
OS << Item << " ";
return OS << "\n";
}
raw_ostream &CharacteristicsStmt::log(raw_ostream &OS) const {
return OS << "Characteristics: " << Value << "\n";
}

View File

@ -319,6 +319,24 @@ public:
raw_ostream &log(raw_ostream &) const override;
};
// 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 {
IntOrString Type;
StringRef FileLoc;
std::vector<IntOrString> Contents;
bool IsFileResource;
public:
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) {}
raw_ostream &log(raw_ostream &) const override;
};
// -- VERSIONINFO resource and its helper classes --
//
// This resource lists the version information on the executable/library.