mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[llvm-rc] Add VERSIONINFO parsing ability. [6/8]
This extends the set of llvm-rc parser's available resources by another one, VERSIONINFO. Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058.aspx Thanks to Nico Weber for his original work in this area. Differential Revision: https://reviews.llvm.org/D37021 llvm-svn: 314468
This commit is contained in:
parent
dffcfd6adb
commit
7414d53a94
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-bad-type.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-bad-type.rc
Normal file
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-named-main-block.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-named-main-block.rc
Normal file
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-repeated-fixed.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-repeated-fixed.rc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-unnamed-value.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-unnamed-value.rc
Normal file
Binary file not shown.
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-wrong-fixed.rc
Normal file
BIN
test/tools/llvm-rc/Inputs/parser-versioninfo-wrong-fixed.rc
Normal file
Binary file not shown.
@ -64,6 +64,34 @@
|
||||
; PGOOD-NEXT: Control (5): EDITTEXT, title: , loc: (1, 2), size: [4, 7], style: 8
|
||||
; PGOOD-NEXT: Dialog (25): loc: (1, 2), size: [3, 4], help ID: 0
|
||||
; PGOOD-NEXT: DialogEx (26): loc: (1, 2), size: [3, 4], help ID: 0
|
||||
; PGOOD-NEXT: VersionInfo (1):
|
||||
; PGOOD-NEXT: Fixed: FILEVERSION: 1 2 3 4
|
||||
; PGOOD-NEXT: Fixed: PRODUCTVERSION: 5 6 7 8
|
||||
; PGOOD-NEXT: Fixed: FILEFLAGSMASK: 50
|
||||
; PGOOD-NEXT: Fixed: FILEFLAGS: 555
|
||||
; PGOOD-NEXT: Fixed: FILEOS: 110
|
||||
; PGOOD-NEXT: Fixed: FILETYPE: 555555
|
||||
; PGOOD-NEXT: Fixed: FILESUBTYPE: 14
|
||||
; PGOOD-NEXT: Start of block (name: )
|
||||
; PGOOD-NEXT: Start of block (name: "StringFileInfo")
|
||||
; PGOOD-NEXT: Start of block (name: "040904E4")
|
||||
; PGOOD-NEXT: "CompanyName" => "a"
|
||||
; PGOOD-NEXT: "FileDescription" => "b"
|
||||
; PGOOD-NEXT: "FileVersion" => "c"
|
||||
; PGOOD-NEXT: "InternalName" => "d"
|
||||
; PGOOD-NEXT: "LegalCopyright" => "e"
|
||||
; PGOOD-NEXT: "LegalTrademarks1" => "f"
|
||||
; PGOOD-NEXT: "LegalTrademarks2" => "g"
|
||||
; PGOOD-NEXT: "OriginalFilename" => L"h"
|
||||
; PGOOD-NEXT: "ProductName" => "ii" 2 3
|
||||
; PGOOD-NEXT: "ProductVersion" =>
|
||||
; PGOOD-NEXT: End of block
|
||||
; PGOOD-NEXT: End of block
|
||||
; PGOOD-NEXT: Start of block (name: "VarFileInfo")
|
||||
; PGOOD-NEXT: "Translation" => 1033 1252
|
||||
; PGOOD-NEXT: End of block
|
||||
; PGOOD-NEXT: End of block
|
||||
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-stringtable-no-string.rc 2>&1 | FileCheck %s --check-prefix PSTRINGTABLE1
|
||||
@ -184,3 +212,33 @@
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-dialog-unnecessary-string.rc 2>&1 | FileCheck %s --check-prefix PDIALOG5
|
||||
|
||||
; PDIALOG5: llvm-rc: Error parsing file: expected integer, got "This shouldn't be here"
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-versioninfo-wrong-fixed.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO1
|
||||
|
||||
; PVERSIONINFO1: llvm-rc: Error parsing file: expected fixed VERSIONINFO statement type, got WEIRDFIXED
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-versioninfo-named-main-block.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO2
|
||||
|
||||
; PVERSIONINFO2: llvm-rc: Error parsing file: expected fixed VERSIONINFO statement type, got BLOCK
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-versioninfo-unnamed-inner-block.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO3
|
||||
|
||||
; PVERSIONINFO3: llvm-rc: Error parsing file: expected string, got {
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-versioninfo-unnamed-value.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO4
|
||||
|
||||
; PVERSIONINFO4: llvm-rc: Error parsing file: expected string, got END
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-versioninfo-bad-type.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO5
|
||||
|
||||
; PVERSIONINFO5: llvm-rc: Error parsing file: expected BLOCK or VALUE, got INCORRECT
|
||||
|
||||
|
||||
; 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
|
||||
|
@ -77,6 +77,8 @@ RCParser::ParseType RCParser::parseSingleResource() {
|
||||
Result = parseHTMLResource();
|
||||
else if (TypeToken->equalsLower("MENU"))
|
||||
Result = parseMenuResource();
|
||||
else if (TypeToken->equalsLower("VERSIONINFO"))
|
||||
Result = parseVersionInfoResource();
|
||||
else
|
||||
return getExpectedError("resource type", /* IsAlreadyRead = */ true);
|
||||
|
||||
@ -322,6 +324,13 @@ RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
|
||||
return std::move(Dialog);
|
||||
}
|
||||
|
||||
RCParser::ParseType RCParser::parseVersionInfoResource() {
|
||||
ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed());
|
||||
ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef()));
|
||||
return make_unique<VersionInfoResource>(std::move(**BlockResult),
|
||||
std::move(*FixedResult));
|
||||
}
|
||||
|
||||
Expected<Control> RCParser::parseControl() {
|
||||
// Each control definition (except CONTROL) follows one of the schemes below
|
||||
// depending on the control class:
|
||||
@ -446,6 +455,72 @@ RCParser::ParseType RCParser::parseStringTableResource() {
|
||||
return std::move(Table);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<VersionInfoBlock>>
|
||||
RCParser::parseVersionInfoBlockContents(StringRef BlockName) {
|
||||
RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
|
||||
|
||||
auto Contents = make_unique<VersionInfoBlock>(BlockName);
|
||||
|
||||
while (!isNextTokenKind(Kind::BlockEnd)) {
|
||||
ASSIGN_OR_RETURN(Stmt, parseVersionInfoStmt());
|
||||
Contents->addStmt(std::move(*Stmt));
|
||||
}
|
||||
|
||||
consume(); // Consume BlockEnd.
|
||||
|
||||
return std::move(Contents);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<VersionInfoStmt>> RCParser::parseVersionInfoStmt() {
|
||||
// Expect either BLOCK or VALUE, then a name or a key (a string).
|
||||
ASSIGN_OR_RETURN(TypeResult, readIdentifier());
|
||||
|
||||
if (TypeResult->equals_lower("BLOCK")) {
|
||||
ASSIGN_OR_RETURN(NameResult, readString());
|
||||
return parseVersionInfoBlockContents(*NameResult);
|
||||
}
|
||||
|
||||
if (TypeResult->equals_lower("VALUE")) {
|
||||
ASSIGN_OR_RETURN(KeyResult, readString());
|
||||
// Read a (possibly empty) list of strings and/or ints, each preceded by
|
||||
// a comma.
|
||||
std::vector<IntOrString> Values;
|
||||
|
||||
while (consumeOptionalType(Kind::Comma)) {
|
||||
ASSIGN_OR_RETURN(ValueResult, readIntOrString());
|
||||
Values.push_back(*ValueResult);
|
||||
}
|
||||
return make_unique<VersionInfoValue>(*KeyResult, std::move(Values));
|
||||
}
|
||||
|
||||
return getExpectedError("BLOCK or VALUE", true);
|
||||
}
|
||||
|
||||
Expected<VersionInfoResource::VersionInfoFixed>
|
||||
RCParser::parseVersionInfoFixed() {
|
||||
using RetType = VersionInfoResource::VersionInfoFixed;
|
||||
RetType Result;
|
||||
|
||||
// Read until the beginning of the block.
|
||||
while (!isNextTokenKind(Kind::BlockBegin)) {
|
||||
ASSIGN_OR_RETURN(TypeResult, readIdentifier());
|
||||
auto FixedType = RetType::getFixedType(*TypeResult);
|
||||
|
||||
if (!RetType::isTypeSupported(FixedType))
|
||||
return getExpectedError("fixed VERSIONINFO statement type", true);
|
||||
if (Result.IsTypePresent[FixedType])
|
||||
return getExpectedError("yet unread fixed VERSIONINFO statement type",
|
||||
true);
|
||||
|
||||
// VERSION variations take multiple integers.
|
||||
size_t NumInts = RetType::isVersionType(FixedType) ? 4 : 1;
|
||||
ASSIGN_OR_RETURN(ArgsResult, readIntsWithCommas(NumInts, NumInts));
|
||||
Result.setValue(FixedType, *ArgsResult);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
RCParser::ParseOptionType RCParser::parseLanguageStmt() {
|
||||
ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2));
|
||||
return make_unique<LanguageResource>((*Args)[0], (*Args)[1]);
|
||||
|
@ -133,6 +133,7 @@ private:
|
||||
ParseType parseHTMLResource();
|
||||
ParseType parseMenuResource();
|
||||
ParseType parseStringTableResource();
|
||||
ParseType parseVersionInfoResource();
|
||||
|
||||
// Helper DIALOG parser - a single control.
|
||||
Expected<Control> parseControl();
|
||||
@ -140,6 +141,15 @@ private:
|
||||
// Helper MENU parser.
|
||||
Expected<MenuDefinitionList> parseMenuItemsList();
|
||||
|
||||
// Helper VERSIONINFO parser - read the contents of a single BLOCK statement,
|
||||
// from BEGIN to END.
|
||||
Expected<std::unique_ptr<VersionInfoBlock>>
|
||||
parseVersionInfoBlockContents(StringRef BlockName);
|
||||
// Helper VERSIONINFO parser - read either VALUE or BLOCK statement.
|
||||
Expected<std::unique_ptr<VersionInfoStmt>> parseVersionInfoStmt();
|
||||
// Helper VERSIONINFO parser - read fixed VERSIONINFO statements.
|
||||
Expected<VersionInfoResource::VersionInfoFixed> parseVersionInfoFixed();
|
||||
|
||||
// Optional statement parsers.
|
||||
ParseOptionType parseLanguageStmt();
|
||||
ParseOptionType parseCharacteristicsStmt();
|
||||
|
@ -142,6 +142,78 @@ raw_ostream &DialogResource::log(raw_ostream &OS) const {
|
||||
return OS;
|
||||
}
|
||||
|
||||
raw_ostream &VersionInfoBlock::log(raw_ostream &OS) const {
|
||||
OS << " Start of block (name: " << Name << ")\n";
|
||||
for (auto &Stmt : Stmts)
|
||||
Stmt->log(OS);
|
||||
return OS << " End of block\n";
|
||||
}
|
||||
|
||||
raw_ostream &VersionInfoValue::log(raw_ostream &OS) const {
|
||||
OS << " " << Key << " =>";
|
||||
for (auto &Value : Values)
|
||||
OS << " " << Value;
|
||||
return OS << "\n";
|
||||
}
|
||||
|
||||
using VersionInfoFixed = VersionInfoResource::VersionInfoFixed;
|
||||
using VersionInfoFixedType = VersionInfoFixed::VersionInfoFixedType;
|
||||
|
||||
const StringRef
|
||||
VersionInfoFixed::FixedFieldsNames[VersionInfoFixed::FtNumTypes] = {
|
||||
"", "FILEVERSION", "PRODUCTVERSION", "FILEFLAGSMASK",
|
||||
"FILEFLAGS", "FILEOS", "FILETYPE", "FILESUBTYPE"};
|
||||
|
||||
const StringMap<VersionInfoFixedType> VersionInfoFixed::FixedFieldsInfoMap = {
|
||||
{FixedFieldsNames[FtFileVersion], FtFileVersion},
|
||||
{FixedFieldsNames[FtProductVersion], FtProductVersion},
|
||||
{FixedFieldsNames[FtFileFlagsMask], FtFileFlagsMask},
|
||||
{FixedFieldsNames[FtFileFlags], FtFileFlags},
|
||||
{FixedFieldsNames[FtFileOS], FtFileOS},
|
||||
{FixedFieldsNames[FtFileType], FtFileType},
|
||||
{FixedFieldsNames[FtFileSubtype], FtFileSubtype}};
|
||||
|
||||
VersionInfoFixedType VersionInfoFixed::getFixedType(StringRef Type) {
|
||||
auto UpperType = Type.upper();
|
||||
auto Iter = FixedFieldsInfoMap.find(UpperType);
|
||||
if (Iter != FixedFieldsInfoMap.end())
|
||||
return Iter->getValue();
|
||||
return FtUnknown;
|
||||
}
|
||||
|
||||
bool VersionInfoFixed::isTypeSupported(VersionInfoFixedType Type) {
|
||||
return FtUnknown < Type && Type < FtNumTypes;
|
||||
}
|
||||
|
||||
bool VersionInfoFixed::isVersionType(VersionInfoFixedType Type) {
|
||||
switch (Type) {
|
||||
case FtFileVersion:
|
||||
case FtProductVersion:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
raw_ostream &VersionInfoFixed::log(raw_ostream &OS) const {
|
||||
for (int Type = FtUnknown; Type < FtNumTypes; ++Type) {
|
||||
if (!isTypeSupported((VersionInfoFixedType)Type))
|
||||
continue;
|
||||
OS << " Fixed: " << FixedFieldsNames[Type] << ":";
|
||||
for (uint32_t Val : FixedInfo[Type])
|
||||
OS << " " << Val;
|
||||
OS << "\n";
|
||||
}
|
||||
return OS;
|
||||
}
|
||||
|
||||
raw_ostream &VersionInfoResource::log(raw_ostream &OS) const {
|
||||
OS << "VersionInfo (" << ResName << "):\n";
|
||||
FixedData.log(OS);
|
||||
return MainBlock.log(OS);
|
||||
}
|
||||
|
||||
raw_ostream &CharacteristicsStmt::log(raw_ostream &OS) const {
|
||||
return OS << "Characteristics: " << Value << "\n";
|
||||
}
|
||||
|
@ -319,6 +319,106 @@ public:
|
||||
raw_ostream &log(raw_ostream &) const override;
|
||||
};
|
||||
|
||||
// -- 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:
|
||||
virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
|
||||
virtual ~VersionInfoStmt() {}
|
||||
};
|
||||
|
||||
// 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 {
|
||||
std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
|
||||
StringRef Name;
|
||||
|
||||
public:
|
||||
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;
|
||||
};
|
||||
|
||||
class VersionInfoValue : public VersionInfoStmt {
|
||||
StringRef Key;
|
||||
std::vector<IntOrString> Values;
|
||||
|
||||
public:
|
||||
VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals)
|
||||
: Key(InfoKey), Values(std::move(Vals)) {}
|
||||
raw_ostream &log(raw_ostream &) const override;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
private:
|
||||
VersionInfoBlock MainBlock;
|
||||
VersionInfoFixed FixedData;
|
||||
|
||||
public:
|
||||
VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
|
||||
VersionInfoFixed &&FixedInfo)
|
||||
: MainBlock(std::move(TopLevelBlock)), FixedData(std::move(FixedInfo)) {}
|
||||
|
||||
raw_ostream &log(raw_ostream &) const override;
|
||||
};
|
||||
|
||||
// CHARACTERISTICS optional statement.
|
||||
//
|
||||
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
|
||||
|
Loading…
Reference in New Issue
Block a user