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
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@314478
91177308-0d34-0410-b5e6-
96231b3b80d8
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"}
--- /dev/null
+MYNAME MYTYPE
+BEGIN
+ 1, 2, InvalidToken
+END
; 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"
+
; 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
; 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
else if (TypeToken->equalsLower("VERSIONINFO"))
Result = parseVersionInfoResource();
else
- return getExpectedError("resource type", /* IsAlreadyRead = */ true);
+ Result = parseUserDefinedResource(*TypeToken);
if (Result)
(*Result)->setName(*NameToken);
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()));
ParseType parseHTMLResource();
ParseType parseMenuResource();
ParseType parseStringTableResource();
+ ParseType parseUserDefinedResource(IntOrString Type);
ParseType parseVersionInfoResource();
// Helper DIALOG parser - a single control.
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";
}
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.