]> granicus.if.org Git - llvm/commitdiff
[llvm-rc] Serialize user-defined resources to .res files.
authorZachary Turner <zturner@google.com>
Fri, 6 Oct 2017 21:52:15 +0000 (21:52 +0000)
committerZachary Turner <zturner@google.com>
Fri, 6 Oct 2017 21:52:15 +0000 (21:52 +0000)
This allows rc to serialize user-defined resources, as
documented at:

msdn.microsoft.com/en-us/library/windows/desktop/aa381054.aspx

Escape sequences are yet unavailable, and are to be added in one of
child patches.

Patch by: Marek Sokolowski

Differential Revision: https://reviews.llvm.org/D38423

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@315117 91177308-0d34-0410-b5e6-96231b3b80d8

test/tools/llvm-rc/Inputs/bitmap.bmp [new file with mode: 0644]
test/tools/llvm-rc/Inputs/tag-user.rc [new file with mode: 0644]
test/tools/llvm-rc/tag-user.test [new file with mode: 0644]
tools/llvm-rc/ResourceFileWriter.cpp
tools/llvm-rc/ResourceFileWriter.h
tools/llvm-rc/ResourceScriptStmt.h
tools/llvm-rc/ResourceVisitor.h

diff --git a/test/tools/llvm-rc/Inputs/bitmap.bmp b/test/tools/llvm-rc/Inputs/bitmap.bmp
new file mode 100644 (file)
index 0000000..5d5a00d
Binary files /dev/null and b/test/tools/llvm-rc/Inputs/bitmap.bmp differ
diff --git a/test/tools/llvm-rc/Inputs/tag-user.rc b/test/tools/llvm-rc/Inputs/tag-user.rc
new file mode 100644 (file)
index 0000000..7043cca
--- /dev/null
@@ -0,0 +1,8 @@
+500 500 {
+  1, 2, 3, 4, 5, "data", L"wide data", 0xABCD, 0xABCDEF01L
+}
+
+NAME1 NAME2 {}
+
+600 600 "bitmap.bmp"
+
diff --git a/test/tools/llvm-rc/tag-user.test b/test/tools/llvm-rc/tag-user.test
new file mode 100644 (file)
index 0000000..89fdc4f
--- /dev/null
@@ -0,0 +1,53 @@
+; RUN: rm -rf %t
+; RUN: mkdir %t
+; RUN: cd %t
+; RUN: cp %p/Inputs/bitmap.bmp .
+; RUN: llvm-rc /FO %t/tag-user.res %p/Inputs/tag-user.rc
+; RUN: llvm-readobj %t/tag-user.res | FileCheck %s
+
+; CHECK:      Resource type (int): 500
+; CHECK-NEXT: Resource name (int): 500
+; CHECK-NEXT: Data version: 0
+; CHECK-NEXT: Memory flags: 0x30
+; CHECK-NEXT: Language ID: 1033
+; CHECK-NEXT: Version (major): 0
+; CHECK-NEXT: Version (minor): 0
+; CHECK-NEXT: Characteristics: 0
+; CHECK-NEXT: Data size: 38
+; CHECK-NEXT: Data: (
+; CHECK-NEXT:   0000: 01000200 03000400 05006461 74617700  |..........dataw.|
+; CHECK-NEXT:   0010: 69006400 65002000 64006100 74006100  |i.d.e. .d.a.t.a.|
+; CHECK-NEXT:   0020: CDAB01EF CDAB                        |......|
+; CHECK-NEXT: )
+
+; CHECK-DAG:  Resource type (string): NAME2
+; CHECK-NEXT: Resource name (string): NAME1
+; CHECK-NEXT: Data version: 0
+; CHECK-NEXT: Memory flags: 0x30
+; CHECK-NEXT: Language ID: 1033
+; CHECK-NEXT: Version (major): 0
+; CHECK-NEXT: Version (minor): 0
+; CHECK-NEXT: Characteristics: 0
+; CHECK-NEXT: Data size: 0
+; CHECK-NEXT: Data:: ()
+
+; CHECK-DAG:  Resource type (int): 600
+; CHECK-NEXT: Resource name (int): 600
+; CHECK-NEXT: Data version: 0
+; CHECK-NEXT: Memory flags: 0x30
+; CHECK-NEXT: Language ID: 1033
+; CHECK-NEXT: Version (major): 0
+; CHECK-NEXT: Version (minor): 0
+; CHECK-NEXT: Characteristics: 0
+; CHECK-NEXT: Data size: 110
+; CHECK-NEXT: Data: (
+; CHECK-NEXT:   0000: 424D6E00 00000000 00003600 00002800  |BMn.......6...(.|
+; CHECK-NEXT:   0010: 00000200 00000700 00000100 18000000  |................|
+; CHECK-NEXT:   0020: 00003800 00000000 00000000 00000000  |..8.............|
+; CHECK-NEXT:   0030: 00000000 00005BB3 855BB385 0000FFFF  |......[..[......|
+; CHECK-NEXT:   0040: FFFFFFFF 0000FFFF FFFFFFFF 0000FFFF  |................|
+; CHECK-NEXT:   0050: FFFFFFFF 00005BB3 85FFFFFF 0000FFFF  |......[.........|
+; CHECK-NEXT:   0060: FF0EC9FF 0000241C EDFFFFFF 0000      |......$.......|
+; CHECK-NEXT: )
+
+
index f41ffcc8ac54f2c97b1d5bb4993cba6ea4d83008..1d23fb966f61e98966c0be95bcebe91a3a94b03e 100644 (file)
@@ -298,6 +298,10 @@ Error ResourceFileWriter::visitStringTableResource(const RCResource *Base) {
   return Error::success();
 }
 
+Error ResourceFileWriter::visitUserDefinedResource(const RCResource *Res) {
+  return writeResource(Res, &ResourceFileWriter::writeUserDefinedBody);
+}
+
 Error ResourceFileWriter::visitVersionInfoResource(const RCResource *Res) {
   return writeResource(Res, &ResourceFileWriter::writeVersionInfoBody);
 }
@@ -1048,6 +1052,43 @@ Error ResourceFileWriter::dumpAllStringTables() {
   return Error::success();
 }
 
+// --- UserDefinedResource helpers. --- //
+
+Error ResourceFileWriter::writeUserDefinedBody(const RCResource *Base) {
+  auto *Res = cast<UserDefinedResource>(Base);
+
+  if (Res->IsFileResource)
+    return appendFile(Res->FileLoc);
+
+  for (auto &Elem : Res->Contents) {
+    if (Elem.isInt()) {
+      RETURN_IF_ERROR(
+          checkRCInt(Elem.getInt(), "Number in user-defined resource"));
+      writeRCInt(Elem.getInt());
+      continue;
+    }
+
+    SmallVector<UTF16, 128> ProcessedString;
+    bool IsLongString;
+    RETURN_IF_ERROR(processString(Elem.getString(),
+                                  NullHandlingMethod::UserResource,
+                                  IsLongString, ProcessedString));
+
+    for (auto Ch : ProcessedString) {
+      if (IsLongString) {
+        writeObject(ulittle16_t(Ch));
+        continue;
+      }
+
+      RETURN_IF_ERROR(checkNumberFits<uint8_t>(
+          Ch, "Character in narrow string in user-defined resoutce"));
+      writeObject(uint8_t(Ch));
+    }
+  }
+
+  return Error::success();
+}
+
 // --- VersionInfoResourceResource helpers. --- //
 
 Error ResourceFileWriter::writeVersionInfoBlock(const VersionInfoBlock &Blk) {
index 905f56f5381fd70fa8646270dcf98018f331bd75..b44271607112ff83b54bbdb8ef6c7652254ace72 100644 (file)
@@ -38,6 +38,7 @@ public:
   Error visitMenuResource(const RCResource *) override;
   Error visitVersionInfoResource(const RCResource *) override;
   Error visitStringTableResource(const RCResource *) override;
+  Error visitUserDefinedResource(const RCResource *) override;
 
   Error visitCaptionStmt(const CaptionStmt *) override;
   Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
@@ -127,6 +128,9 @@ private:
   Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle,
                                uint16_t StringID, StringRef String);
 
+  // User defined resource
+  Error writeUserDefinedBody(const RCResource *);
+
   // VersionInfoResource
   Error writeVersionInfoBody(const RCResource *);
   Error writeVersionInfoBlock(const VersionInfoBlock &);
index 915d4f108b5dad63157cbfaafd64244dee177ae6..e44120b770f35694a358b23618518b73d850f6e7 100644 (file)
@@ -591,18 +591,29 @@ public:
 //   * 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 {
+public:
   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;
+  IntOrString getResourceType() const override { return Type; }
+  Twine getResourceTypeName() const override { return Type; }
+  uint16_t getMemoryFlags() const override { return MfPure | MfMoveable; }
+
+  Error visit(Visitor *V) const override {
+    return V->visitUserDefinedResource(this);
+  }
+  ResourceKind getKind() const override { return RkUser; }
+  static bool classof(const RCResource *Res) {
+    return Res->getKind() == RkUser;
+  }
 };
 
 // -- VERSIONINFO resource and its helper classes --
index 328200bc00fa85205ba9f688d3a0766e7cf87647..530b4a8add2c3540cdde64f3c89fecfb5b388e86 100644 (file)
@@ -38,6 +38,7 @@ public:
   virtual Error visitIconResource(const RCResource *) = 0;
   virtual Error visitMenuResource(const RCResource *) = 0;
   virtual Error visitStringTableResource(const RCResource *) = 0;
+  virtual Error visitUserDefinedResource(const RCResource *) = 0;
   virtual Error visitVersionInfoResource(const RCResource *) = 0;
 
   virtual Error visitCaptionStmt(const CaptionStmt *) = 0;