From 0bce04127f10c4f0dc32a7d04029817101ac2f4c Mon Sep 17 00:00:00 2001 From: Marek Sokolowski Date: Fri, 29 Sep 2017 00:14:18 +0000 Subject: [PATCH] [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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@314478 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../llvm-rc/Inputs/parser-correct-everything.rc | 10 ++++++++ .../llvm-rc/Inputs/parser-user-invalid-contents.rc | 4 ++++ test/tools/llvm-rc/parser.test | 13 ++++++++++- tools/llvm-rc/ResourceScriptParser.cpp | 27 +++++++++++++++++++++- tools/llvm-rc/ResourceScriptParser.h | 1 + tools/llvm-rc/ResourceScriptStmt.cpp | 10 ++++++++ tools/llvm-rc/ResourceScriptStmt.h | 18 +++++++++++++++ 7 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 test/tools/llvm-rc/Inputs/parser-user-invalid-contents.rc diff --git a/test/tools/llvm-rc/Inputs/parser-correct-everything.rc b/test/tools/llvm-rc/Inputs/parser-correct-everything.rc index ec5286c0393..5f15bcc0944 100644 --- a/test/tools/llvm-rc/Inputs/parser-correct-everything.rc +++ b/test/tools/llvm-rc/Inputs/parser-correct-everything.rc @@ -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"} diff --git a/test/tools/llvm-rc/Inputs/parser-user-invalid-contents.rc b/test/tools/llvm-rc/Inputs/parser-user-invalid-contents.rc new file mode 100644 index 00000000000..bf8f71486e3 --- /dev/null +++ b/test/tools/llvm-rc/Inputs/parser-user-invalid-contents.rc @@ -0,0 +1,4 @@ +MYNAME MYTYPE +BEGIN + 1, 2, InvalidToken +END diff --git a/test/tools/llvm-rc/parser.test b/test/tools/llvm-rc/parser.test index e1477a822a3..a9395dc5cba 100644 --- a/test/tools/llvm-rc/parser.test +++ b/test/tools/llvm-rc/parser.test @@ -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 ; 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 diff --git a/tools/llvm-rc/ResourceScriptParser.cpp b/tools/llvm-rc/ResourceScriptParser.cpp index ee7de6b937a..211d9e7e954 100644 --- a/tools/llvm-rc/ResourceScriptParser.cpp +++ b/tools/llvm-rc/ResourceScriptParser.cpp @@ -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(Type, read().value()); + + RETURN_IF_ERROR(consumeType(Kind::BlockBegin)); + std::vector 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(Type, std::move(Data)); +} + RCParser::ParseType RCParser::parseVersionInfoResource() { ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed()); ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef())); diff --git a/tools/llvm-rc/ResourceScriptParser.h b/tools/llvm-rc/ResourceScriptParser.h index 56042f79d5f..7509b8e9066 100644 --- a/tools/llvm-rc/ResourceScriptParser.h +++ b/tools/llvm-rc/ResourceScriptParser.h @@ -139,6 +139,7 @@ private: ParseType parseHTMLResource(); ParseType parseMenuResource(); ParseType parseStringTableResource(); + ParseType parseUserDefinedResource(IntOrString Type); ParseType parseVersionInfoResource(); // Helper DIALOG parser - a single control. diff --git a/tools/llvm-rc/ResourceScriptStmt.cpp b/tools/llvm-rc/ResourceScriptStmt.cpp index eb123e543f0..792ac40e55d 100644 --- a/tools/llvm-rc/ResourceScriptStmt.cpp +++ b/tools/llvm-rc/ResourceScriptStmt.cpp @@ -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"; } diff --git a/tools/llvm-rc/ResourceScriptStmt.h b/tools/llvm-rc/ResourceScriptStmt.h index b090be4b700..95890fe6669 100644 --- a/tools/llvm-rc/ResourceScriptStmt.h +++ b/tools/llvm-rc/ResourceScriptStmt.h @@ -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 Contents; + bool IsFileResource; + +public: + UserDefinedResource(IntOrString ResourceType, StringRef FileLocation) + : Type(ResourceType), FileLoc(FileLocation), IsFileResource(true) {} + UserDefinedResource(IntOrString ResourceType, std::vector &&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. -- 2.11.0