From fb74cb1edfa64424fb5204d10a16892f972435ed Mon Sep 17 00:00:00 2001 From: Marek Sokolowski Date: Thu, 28 Sep 2017 22:41:38 +0000 Subject: [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 --- llvm/tools/llvm-rc/ResourceScriptParser.cpp | 75 +++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'llvm/tools/llvm-rc/ResourceScriptParser.cpp') diff --git a/llvm/tools/llvm-rc/ResourceScriptParser.cpp b/llvm/tools/llvm-rc/ResourceScriptParser.cpp index 41b11911b06..57a30d14371 100644 --- a/llvm/tools/llvm-rc/ResourceScriptParser.cpp +++ b/llvm/tools/llvm-rc/ResourceScriptParser.cpp @@ -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(std::move(**BlockResult), + std::move(*FixedResult)); +} + Expected 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> +RCParser::parseVersionInfoBlockContents(StringRef BlockName) { + RETURN_IF_ERROR(consumeType(Kind::BlockBegin)); + + auto Contents = make_unique(BlockName); + + while (!isNextTokenKind(Kind::BlockEnd)) { + ASSIGN_OR_RETURN(Stmt, parseVersionInfoStmt()); + Contents->addStmt(std::move(*Stmt)); + } + + consume(); // Consume BlockEnd. + + return std::move(Contents); +} + +Expected> 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 Values; + + while (consumeOptionalType(Kind::Comma)) { + ASSIGN_OR_RETURN(ValueResult, readIntOrString()); + Values.push_back(*ValueResult); + } + return make_unique(*KeyResult, std::move(Values)); + } + + return getExpectedError("BLOCK or VALUE", true); +} + +Expected +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((*Args)[0], (*Args)[1]); -- cgit v1.2.3