[llvm] r315112 - [llvm-rc] Serialize STRINGTABLE statements to .res file.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 6 14:30:55 PDT 2017


Author: zturner
Date: Fri Oct  6 14:30:55 2017
New Revision: 315112

URL: http://llvm.org/viewvc/llvm-project?rev=315112&view=rev
Log:
[llvm-rc] Serialize STRINGTABLE statements to .res file.

This allows llvm-rc to serialize STRINGTABLE resources.

These are output in an unusual way: we locate them at the end of the
file, and strings are merged into bundles of max 16 strings, depending
on their IDs, language, and characteristics.

Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050.aspx

Patch by: Marek Sokolowski
Differential Revision: https://reviews.llvm.org/D38420

Added:
    llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-basic.rc
    llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-same-ids.rc
    llvm/trunk/test/tools/llvm-rc/tag-stringtable.test
Modified:
    llvm/trunk/tools/llvm-rc/ResourceFileWriter.cpp
    llvm/trunk/tools/llvm-rc/ResourceFileWriter.h
    llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h
    llvm/trunk/tools/llvm-rc/ResourceVisitor.h
    llvm/trunk/tools/llvm-rc/llvm-rc.cpp

Added: llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-basic.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-basic.rc?rev=315112&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-basic.rc (added)
+++ llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-basic.rc Fri Oct  6 14:30:55 2017
@@ -0,0 +1,45 @@
+STRINGTABLE
+VERSION 32
+CHARACTERISTICS 0x32 {
+  0 "a"
+}
+
+STRINGTABLE {
+  1 "b"
+  16 "bb"
+}
+
+STRINGTABLE
+VERSION 100
+LANGUAGE 4, 7 {
+  16 "hello"
+  17 "world"
+}
+
+STRINGTABLE
+VERSION 50
+CHARACTERISTICS 0x32 {
+  17 "cc"
+  32 "ccc"
+  2 "c"
+}
+
+STRINGTABLE {
+  3 "d"
+  4 ""
+  8 ""
+}
+
+STRINGTABLE
+VERSION 101
+LANGUAGE 4, 7 {
+  -1 & 65535 "minus one"
+}
+
+STRINGTABLE
+CHARACTERISTICS 10
+LANGUAGE 4, 7 {
+  23 "something else"
+  65529 "large number"
+}
+

Added: llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-same-ids.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-same-ids.rc?rev=315112&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-same-ids.rc (added)
+++ llvm/trunk/test/tools/llvm-rc/Inputs/tag-stringtable-same-ids.rc Fri Oct  6 14:30:55 2017
@@ -0,0 +1,5 @@
+STRINGTABLE {
+  1 "Hello"
+  2 "World"
+  1 "Repeat"
+}
\ No newline at end of file

Added: llvm/trunk/test/tools/llvm-rc/tag-stringtable.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/tag-stringtable.test?rev=315112&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/tag-stringtable.test (added)
+++ llvm/trunk/test/tools/llvm-rc/tag-stringtable.test Fri Oct  6 14:30:55 2017
@@ -0,0 +1,170 @@
+; RUN: llvm-rc /FO %t %p/Inputs/tag-stringtable-basic.rc
+; RUN: llvm-readobj %t | FileCheck %s
+
+; CHECK:      Resource type (int): 6
+; CHECK-NEXT: Resource name (int): 1
+; CHECK-NEXT: Data version: 0
+; CHECK-NEXT: Memory flags: 0x1030
+; CHECK-NEXT: Language ID: 1033
+; CHECK-NEXT: Version (major): 0
+; CHECK-NEXT: Version (minor): 32
+; CHECK-NEXT: Characteristics: 50
+; CHECK-NEXT: Data size: 40
+; CHECK-NEXT: Data: (
+; CHECK-NEXT:   0000: 01006100 01006200 01006300 01006400  |..a...b...c...d.|
+; CHECK-NEXT:   0010: 00000000 00000000 00000000 00000000  |................|
+; CHECK-NEXT:   0020: 00000000 00000000                    |........|
+; CHECK-NEXT: )
+
+; CHECK-DAG:  Resource type (int): 6
+; CHECK-NEXT: Resource name (int): 2
+; CHECK-NEXT: Data version: 0
+; CHECK-NEXT: Memory flags: 0x1030
+; CHECK-NEXT: Language ID: 1033
+; CHECK-NEXT: Version (major): 0
+; CHECK-NEXT: Version (minor): 0
+; CHECK-NEXT: Characteristics: 0
+; CHECK-NEXT: Data size: 40
+; CHECK-NEXT: Data: (
+; CHECK-NEXT:   0000: 02006200 62000200 63006300 00000000  |..b.b...c.c.....|
+; CHECK-NEXT:   0010: 00000000 00000000 00000000 00000000  |................|
+; CHECK-NEXT:   0020: 00000000 00000000                    |........|
+; CHECK-NEXT: )
+
+; CHECK-DAG:  Resource type (int): 6
+; CHECK-NEXT: Resource name (int): 2
+; CHECK-NEXT: Data version: 0
+; CHECK-NEXT: Memory flags: 0x1030
+; CHECK-NEXT: Language ID: 7172
+; CHECK-NEXT: Version (major): 0
+; CHECK-NEXT: Version (minor): 100
+; CHECK-NEXT: Characteristics: 0
+; CHECK-NEXT: Data size: 80
+; CHECK-NEXT: Data: (
+; CHECK-NEXT:   0000: 05006800 65006C00 6C006F00 05007700  |..h.e.l.l.o...w.|
+; CHECK-NEXT:   0010: 6F007200 6C006400 00000000 00000000  |o.r.l.d.........|
+; CHECK-NEXT:   0020: 00000E00 73006F00 6D006500 74006800  |....s.o.m.e.t.h.|
+; CHECK-NEXT:   0030: 69006E00 67002000 65006C00 73006500  |i.n.g. .e.l.s.e.|
+; CHECK-NEXT:   0040: 00000000 00000000 00000000 00000000  |................|
+; CHECK-NEXT: )
+
+; CHECK-DAG:  Resource type (int): 6
+; CHECK-NEXT: Resource name (int): 3
+; CHECK-NEXT: Data version: 0
+; CHECK-NEXT: Memory flags: 0x1030
+; CHECK-NEXT: Language ID: 1033
+; CHECK-NEXT: Version (major): 0
+; CHECK-NEXT: Version (minor): 50
+; CHECK-NEXT: Characteristics: 50
+; CHECK-NEXT: Data size: 38
+; CHECK-NEXT: Data: (
+; CHECK-NEXT:   0000: 03006300 63006300 00000000 00000000  |..c.c.c.........|
+; CHECK-NEXT:   0010: 00000000 00000000 00000000 00000000  |................|
+; CHECK-NEXT:   0020: 00000000 0000                        |......|
+; CHECK-NEXT: )
+
+; CHECK-DAG:  Resource type (int): 6
+; CHECK-NEXT: Resource name (int): 4096
+; CHECK-NEXT: Data version: 0
+; CHECK-NEXT: Memory flags: 0x1030
+; CHECK-NEXT: Language ID: 7172
+; CHECK-NEXT: Version (major): 0
+; CHECK-NEXT: Version (minor): 101
+; CHECK-NEXT: Characteristics: 0
+; CHECK-NEXT: Data size: 74
+; CHECK-NEXT: Data: (
+; CHECK-NEXT:   0000: 00000000 00000000 00000000 00000000  |................|
+; CHECK-NEXT:   0010: 00000C00 6C006100 72006700 65002000  |....l.a.r.g.e. .|
+; CHECK-NEXT:   0020: 6E007500 6D006200 65007200 00000000  |n.u.m.b.e.r.....|
+; CHECK-NEXT:   0030: 00000000 00000900 6D006900 6E007500  |........m.i.n.u.|
+; CHECK-NEXT:   0040: 73002000 6F006E00 6500               |s. .o.n.e.|
+; CHECK-NEXT: )
+
+
+; RUN: llvm-rc /N /FO %t0 %p/Inputs/tag-stringtable-basic.rc
+; RUN: llvm-readobj %t0 | FileCheck %s --check-prefix=NULL
+
+; NULL:      Resource type (int): 6
+; NULL-NEXT: Resource name (int): 1
+; NULL-NEXT: Data version: 0
+; NULL-NEXT: Memory flags: 0x1030
+; NULL-NEXT: Language ID: 1033
+; NULL-NEXT: Version (major): 0
+; NULL-NEXT: Version (minor): 32
+; NULL-NEXT: Characteristics: 50
+; NULL-NEXT: Data size: 52
+; NULL-NEXT: Data: (
+; NULL-NEXT:   0000: 02006100 00000200 62000000 02006300  |..a.....b.....c.|
+; NULL-NEXT:   0010: 00000200 64000000 01000000 00000000  |....d...........|
+; NULL-NEXT:   0020: 00000100 00000000 00000000 00000000  |................|
+; NULL-NEXT:   0030: 00000000                             |....|
+; NULL-NEXT: )
+
+; NULL-DAG:  Resource type (int): 6
+; NULL-NEXT: Resource name (int): 2
+; NULL-NEXT: Data version: 0
+; NULL-NEXT: Memory flags: 0x1030
+; NULL-NEXT: Language ID: 1033
+; NULL-NEXT: Version (major): 0
+; NULL-NEXT: Version (minor): 0
+; NULL-NEXT: Characteristics: 0
+; NULL-NEXT: Data size: 44
+; NULL-NEXT: Data: (
+; NULL-NEXT:   0000: 03006200 62000000 03006300 63000000  |..b.b.....c.c...|
+; NULL-NEXT:   0010: 00000000 00000000 00000000 00000000  |................|
+; NULL-NEXT:   0020: 00000000 00000000 00000000           |............|
+; NULL-NEXT: )
+
+; NULL-DAG:  Resource type (int): 6
+; NULL-NEXT: Resource name (int): 2
+; NULL-NEXT: Data version: 0
+; NULL-NEXT: Memory flags: 0x1030
+; NULL-NEXT: Language ID: 7172
+; NULL-NEXT: Version (major): 0
+; NULL-NEXT: Version (minor): 100
+; NULL-NEXT: Characteristics: 0
+; NULL-NEXT: Data size: 86
+; NULL-NEXT: Data: (
+; NULL-NEXT:   0000: 06006800 65006C00 6C006F00 00000600  |..h.e.l.l.o.....|
+; NULL-NEXT:   0010: 77006F00 72006C00 64000000 00000000  |w.o.r.l.d.......|
+; NULL-NEXT:   0020: 00000000 00000F00 73006F00 6D006500  |........s.o.m.e.|
+; NULL-NEXT:   0030: 74006800 69006E00 67002000 65006C00  |t.h.i.n.g. .e.l.|
+; NULL-NEXT:   0040: 73006500 00000000 00000000 00000000  |s.e.............|
+; NULL-NEXT:   0050: 00000000 0000                        |......|
+; NULL-NEXT: )
+
+; NULL-DAG:  Resource type (int): 6
+; NULL-NEXT: Resource name (int): 3
+; NULL-NEXT: Data version: 0
+; NULL-NEXT: Memory flags: 0x1030
+; NULL-NEXT: Language ID: 1033
+; NULL-NEXT: Version (major): 0
+; NULL-NEXT: Version (minor): 50
+; NULL-NEXT: Characteristics: 50
+; NULL-NEXT: Data size: 40
+; NULL-NEXT: Data: (
+; NULL-NEXT:   0000: 04006300 63006300 00000000 00000000  |..c.c.c.........|
+; NULL-NEXT:   0010: 00000000 00000000 00000000 00000000  |................|
+; NULL-NEXT:   0020: 00000000 00000000                    |........|
+; NULL-NEXT: )
+
+; NULL-DAG:  Resource type (int): 6
+; NULL-NEXT: Resource name (int): 4096
+; NULL-NEXT: Data version: 0
+; NULL-NEXT: Memory flags: 0x1030
+; NULL-NEXT: Language ID: 7172
+; NULL-NEXT: Version (major): 0
+; NULL-NEXT: Version (minor): 101
+; NULL-NEXT: Characteristics: 0
+; NULL-NEXT: Data size: 78
+; NULL-NEXT: Data: (
+; NULL-NEXT:   0000: 00000000 00000000 00000000 00000000  |................|
+; NULL-NEXT:   0010: 00000D00 6C006100 72006700 65002000  |....l.a.r.g.e. .|
+; NULL-NEXT:   0020: 6E007500 6D006200 65007200 00000000  |n.u.m.b.e.r.....|
+; NULL-NEXT:   0030: 00000000 00000000 0A006D00 69006E00  |..........m.i.n.|
+; NULL-NEXT:   0040: 75007300 20006F00 6E006500 0000      |u.s. .o.n.e...|
+; NULL-NEXT: )
+
+
+; RUN: not llvm-rc /FO %t %p/Inputs/tag-stringtable-same-ids.rc 2>&1 | FileCheck %s --check-prefix SAMEIDS
+; SAMEIDS: llvm-rc: Multiple STRINGTABLE strings located under ID 1

Modified: llvm/trunk/tools/llvm-rc/ResourceFileWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceFileWriter.cpp?rev=315112&r1=315111&r2=315112&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceFileWriter.cpp (original)
+++ llvm/trunk/tools/llvm-rc/ResourceFileWriter.cpp Fri Oct  6 14:30:55 2017
@@ -129,8 +129,6 @@ enum class NullHandlingMethod {
 // For identifiers, this is no-op.
 static Error processString(StringRef Str, NullHandlingMethod NullHandler,
                            bool &IsLongString, SmallVectorImpl<UTF16> &Result) {
-  assert(NullHandler == NullHandlingMethod::CutAtNull);
-
   bool IsString = stripQuotes(Str, IsLongString);
   convertUTF8ToUTF16String(Str, Result);
 
@@ -143,11 +141,24 @@ static Error processString(StringRef Str
     return Error::success();
   }
 
-  // We don't process the string contents. Only cut at '\0'.
+  switch (NullHandler) {
+  case NullHandlingMethod::CutAtNull:
+    for (size_t Pos = 0; Pos < Result.size(); ++Pos)
+      if (Result[Pos] == '\0')
+        Result.resize(Pos);
+    break;
+
+  case NullHandlingMethod::CutAtDoubleNull:
+    for (size_t Pos = 0; Pos + 1 < Result.size(); ++Pos)
+      if (Result[Pos] == '\0' && Result[Pos + 1] == '\0')
+        Result.resize(Pos);
+    if (Result.size() > 0 && Result.back() == '\0')
+      Result.pop_back();
+    break;
 
-  for (size_t Pos = 0; Pos < Result.size(); ++Pos)
-    if (Result[Pos] == '\0')
-      Result.resize(Pos);
+  case NullHandlingMethod::UserResource:
+    break;
+  }
 
   return Error::success();
 }
@@ -258,6 +269,35 @@ Error ResourceFileWriter::visitMenuResou
   return writeResource(Res, &ResourceFileWriter::writeMenuBody);
 }
 
+Error ResourceFileWriter::visitStringTableResource(const RCResource *Base) {
+  const auto *Res = cast<StringTableResource>(Base);
+
+  ContextKeeper RAII(this);
+  RETURN_IF_ERROR(Res->applyStmts(this));
+
+  for (auto &String : Res->Table) {
+    RETURN_IF_ERROR(checkNumberFits<uint16_t>(String.first, "String ID"));
+    uint16_t BundleID = String.first >> 4;
+    StringTableInfo::BundleKey Key(BundleID, ObjectData.LanguageInfo);
+    auto &BundleData = StringTableData.BundleData;
+    auto Iter = BundleData.find(Key);
+
+    if (Iter == BundleData.end()) {
+      // Need to create a bundle.
+      StringTableData.BundleList.push_back(Key);
+      auto EmplaceResult =
+          BundleData.emplace(Key, StringTableInfo::Bundle(ObjectData));
+      assert(EmplaceResult.second && "Could not create a bundle");
+      Iter = EmplaceResult.first;
+    }
+
+    RETURN_IF_ERROR(
+        insertStringIntoBundle(Iter->second, String.first, String.second));
+  }
+
+  return Error::success();
+}
+
 Error ResourceFileWriter::visitVersionInfoResource(const RCResource *Res) {
   return writeResource(Res, &ResourceFileWriter::writeVersionInfoBody);
 }
@@ -939,6 +979,75 @@ Error ResourceFileWriter::writeMenuBody(
   return writeMenuDefinitionList(cast<MenuResource>(Base)->Elements);
 }
 
+// --- StringTableResource helpers. --- //
+
+class BundleResource : public RCResource {
+public:
+  using BundleType = ResourceFileWriter::StringTableInfo::Bundle;
+  BundleType Bundle;
+
+  BundleResource(const BundleType &StrBundle) : Bundle(StrBundle) {}
+  IntOrString getResourceType() const override { return 6; }
+
+  ResourceKind getKind() const override { return RkStringTableBundle; }
+  static bool classof(const RCResource *Res) {
+    return Res->getKind() == RkStringTableBundle;
+  }
+};
+
+Error ResourceFileWriter::visitStringTableBundle(const RCResource *Res) {
+  return writeResource(Res, &ResourceFileWriter::writeStringTableBundleBody);
+}
+
+Error ResourceFileWriter::insertStringIntoBundle(
+    StringTableInfo::Bundle &Bundle, uint16_t StringID, StringRef String) {
+  uint16_t StringLoc = StringID & 15;
+  if (Bundle.Data[StringLoc])
+    return createError("Multiple STRINGTABLE strings located under ID " +
+                       Twine(StringID));
+  Bundle.Data[StringLoc] = String;
+  return Error::success();
+}
+
+Error ResourceFileWriter::writeStringTableBundleBody(const RCResource *Base) {
+  auto *Res = cast<BundleResource>(Base);
+  for (size_t ID = 0; ID < Res->Bundle.Data.size(); ++ID) {
+    // The string format is a tiny bit different here. We
+    // first output the size of the string, and then the string itself
+    // (which is not null-terminated).
+    bool IsLongString;
+    SmallVector<UTF16, 128> Data;
+    RETURN_IF_ERROR(processString(Res->Bundle.Data[ID].getValueOr(StringRef()),
+                                  NullHandlingMethod::CutAtDoubleNull,
+                                  IsLongString, Data));
+    if (AppendNull && Res->Bundle.Data[ID])
+      Data.push_back('\0');
+    RETURN_IF_ERROR(
+        checkNumberFits<uint16_t>(Data.size(), "STRINGTABLE string size"));
+    writeObject(ulittle16_t(Data.size()));
+    for (auto Char : Data)
+      writeObject(ulittle16_t(Char));
+  }
+  return Error::success();
+}
+
+Error ResourceFileWriter::dumpAllStringTables() {
+  for (auto Key : StringTableData.BundleList) {
+    auto Iter = StringTableData.BundleData.find(Key);
+    assert(Iter != StringTableData.BundleData.end());
+
+    // For a moment, revert the context info to moment of bundle declaration.
+    ContextKeeper RAII(this);
+    ObjectData = Iter->second.DeclTimeInfo;
+
+    BundleResource Res(Iter->second);
+    // Bundle #(k+1) contains keys [16k, 16k + 15].
+    Res.setName(Key.first + 1);
+    RETURN_IF_ERROR(visitStringTableBundle(&Res));
+  }
+  return Error::success();
+}
+
 // --- VersionInfoResourceResource helpers. --- //
 
 Error ResourceFileWriter::writeVersionInfoBlock(const VersionInfoBlock &Blk) {

Modified: llvm/trunk/tools/llvm-rc/ResourceFileWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceFileWriter.h?rev=315112&r1=315111&r2=315112&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceFileWriter.h (original)
+++ llvm/trunk/tools/llvm-rc/ResourceFileWriter.h Fri Oct  6 14:30:55 2017
@@ -37,6 +37,7 @@ public:
   Error visitIconResource(const RCResource *) override;
   Error visitMenuResource(const RCResource *) override;
   Error visitVersionInfoResource(const RCResource *) override;
+  Error visitStringTableResource(const RCResource *) override;
 
   Error visitCaptionStmt(const CaptionStmt *) override;
   Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
@@ -45,6 +46,12 @@ public:
   Error visitStyleStmt(const StyleStmt *) override;
   Error visitVersionStmt(const VersionStmt *) override;
 
+  // Stringtables are output at the end of .res file. We need a separate
+  // function to do it.
+  Error dumpAllStringTables();
+
+  bool AppendNull; // Append '\0' to each existing STRINGTABLE element?
+
   struct ObjectInfo {
     uint16_t LanguageInfo;
     uint32_t Characteristics;
@@ -64,6 +71,21 @@ public:
     ObjectInfo() : LanguageInfo(0), Characteristics(0), VersionInfo(0) {}
   } ObjectData;
 
+  struct StringTableInfo {
+    // Each STRINGTABLE bundle depends on ID of the bundle and language
+    // description.
+    using BundleKey = std::pair<uint16_t, uint16_t>;
+    // Each bundle is in fact an array of 16 strings.
+    struct Bundle {
+      std::array<Optional<StringRef>, 16> Data;
+      ObjectInfo DeclTimeInfo;
+      Bundle(const ObjectInfo &Info) : DeclTimeInfo(Info) {}
+    };
+    std::map<BundleKey, Bundle> BundleData;
+    // Bundles are listed in the order of their first occurence.
+    std::vector<BundleKey> BundleList;
+  } StringTableData;
+
 private:
   Error handleError(Error &&Err, const RCResource *Res);
 
@@ -99,6 +121,12 @@ private:
   Error writeMenuDefinitionList(const MenuDefinitionList &List);
   Error writeMenuBody(const RCResource *);
 
+  // StringTableResource
+  Error visitStringTableBundle(const RCResource *);
+  Error writeStringTableBundleBody(const RCResource *);
+  Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle,
+                               uint16_t StringID, StringRef String);
+
   // VersionInfoResource
   Error writeVersionInfoBody(const RCResource *);
   Error writeVersionInfoBlock(const VersionInfoBlock &);

Modified: llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h?rev=315112&r1=315111&r2=315112&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h (original)
+++ llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h Fri Oct  6 14:30:55 2017
@@ -124,6 +124,7 @@ enum ResourceKind {
   RkSingleIcon = 3,
   RkMenu = 4,
   RkDialog = 5,
+  RkStringTableBundle = 6,
   RkAccelerators = 9,
   RkCursorGroup = 12,
   RkIconGroup = 14,
@@ -138,9 +139,10 @@ enum ResourceKind {
   RkBase,
   RkCursor,
   RkIcon,
+  RkStringTable,
   RkUser,
   RkSingleCursorOrIconRes,
-  RkCursorOrIconGroupRes
+  RkCursorOrIconGroupRes,
 };
 
 // Non-zero memory flags.
@@ -488,14 +490,18 @@ public:
 //
 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
 class StringTableResource : public OptStatementsRCResource {
+public:
   std::vector<std::pair<uint32_t, StringRef>> Table;
 
-public:
   using OptStatementsRCResource::OptStatementsRCResource;
   void addString(uint32_t ID, StringRef String) {
     Table.emplace_back(ID, String);
   }
   raw_ostream &log(raw_ostream &) const override;
+  Twine getResourceTypeName() const override { return "STRINGTABLE"; }
+  Error visit(Visitor *V) const override {
+    return V->visitStringTableResource(this);
+  }
 };
 
 // -- DIALOG(EX) resource and its helper classes --

Modified: llvm/trunk/tools/llvm-rc/ResourceVisitor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceVisitor.h?rev=315112&r1=315111&r2=315112&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceVisitor.h (original)
+++ llvm/trunk/tools/llvm-rc/ResourceVisitor.h Fri Oct  6 14:30:55 2017
@@ -37,6 +37,7 @@ public:
   virtual Error visitHTMLResource(const RCResource *) = 0;
   virtual Error visitIconResource(const RCResource *) = 0;
   virtual Error visitMenuResource(const RCResource *) = 0;
+  virtual Error visitStringTableResource(const RCResource *) = 0;
   virtual Error visitVersionInfoResource(const RCResource *) = 0;
 
   virtual Error visitCaptionStmt(const CaptionStmt *) = 0;

Modified: llvm/trunk/tools/llvm-rc/llvm-rc.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/llvm-rc.cpp?rev=315112&r1=315111&r2=315112&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/llvm-rc.cpp (original)
+++ llvm/trunk/tools/llvm-rc/llvm-rc.cpp Fri Oct  6 14:30:55 2017
@@ -154,6 +154,7 @@ int main(int argc_, const char *argv_[])
       fatalError("Error opening output file '" + OutArgsInfo[0] +
                  "': " + EC.message());
     Visitor = llvm::make_unique<ResourceFileWriter>(std::move(FOut));
+    Visitor->AppendNull = InputArgs.hasArg(OPT_ADD_NULL);
 
     ExitOnErr(NullResource().visit(Visitor.get()));
 
@@ -170,5 +171,9 @@ int main(int argc_, const char *argv_[])
       ExitOnErr(Resource->visit(Visitor.get()));
   }
 
+  // STRINGTABLE resources come at the very end.
+  if (!IsDryRun)
+    ExitOnErr(Visitor->dumpAllStringTables());
+
   return 0;
 }




More information about the llvm-commits mailing list