OSDN Git Service

[llvm-rc] Add user-defined resources parsing ability. [8/8]
authorMarek Sokolowski <mnbvmar@gmail.com>
Fri, 29 Sep 2017 00:14:18 +0000 (00:14 +0000)
committerMarek Sokolowski <mnbvmar@gmail.com>
Fri, 29 Sep 2017 00:14:18 +0000 (00:14 +0000)
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

test/tools/llvm-rc/Inputs/parser-correct-everything.rc
test/tools/llvm-rc/Inputs/parser-user-invalid-contents.rc [new file with mode: 0644]
test/tools/llvm-rc/parser.test
tools/llvm-rc/ResourceScriptParser.cpp
tools/llvm-rc/ResourceScriptParser.h
tools/llvm-rc/ResourceScriptStmt.cpp
tools/llvm-rc/ResourceScriptStmt.h

index ec5286c..5f15bcc 100644 (file)
@@ -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 (file)
index 0000000..bf8f714
--- /dev/null
@@ -0,0 +1,4 @@
+MYNAME MYTYPE
+BEGIN
+  1, 2, InvalidToken
+END
index e1477a8..a9395dc 100644 (file)
 ; 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
index ee7de6b..211d9e7 100644 (file)
@@ -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()));
index 56042f7..7509b8e 100644 (file)
@@ -139,6 +139,7 @@ private:
   ParseType parseHTMLResource();
   ParseType parseMenuResource();
   ParseType parseStringTableResource();
+  ParseType parseUserDefinedResource(IntOrString Type);
   ParseType parseVersionInfoResource();
 
   // Helper DIALOG parser - a single control.
index eb123e5..792ac40 100644 (file)
@@ -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";
 }
index b090be4..95890fe 100644 (file)
@@ -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.