forked from OSchip/llvm-project
[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:
parent
7e89ee7fdc
commit
b5f39a05a3
|
@ -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"}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
MYNAME MYTYPE
|
||||
BEGIN
|
||||
1, 2, InvalidToken
|
||||
END
|
|
@ -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
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -139,6 +139,7 @@ private:
|
|||
ParseType parseHTMLResource();
|
||||
ParseType parseMenuResource();
|
||||
ParseType parseStringTableResource();
|
||||
ParseType parseUserDefinedResource(IntOrString Type);
|
||||
ParseType parseVersionInfoResource();
|
||||
|
||||
// Helper DIALOG parser - a single control.
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue