[llvm-rc] Serialize VERSIONINFO resources to .res files.

This is now able to dump VERSIONINFO resources.

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

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

llvm-svn: 315110
diff --git a/llvm/tools/llvm-rc/ResourceScriptStmt.h b/llvm/tools/llvm-rc/ResourceScriptStmt.h
index 9addca9..2457d83 100644
--- a/llvm/tools/llvm-rc/ResourceScriptStmt.h
+++ b/llvm/tools/llvm-rc/ResourceScriptStmt.h
@@ -22,17 +22,62 @@
 namespace llvm {
 namespace rc {
 
+// Integer wrapper that also holds information whether the user declared
+// the integer to be long (by appending L to the end of the integer) or not.
+// It allows to be implicitly cast from and to uint32_t in order
+// to be compatible with the parts of code that don't care about the integers
+// being marked long.
+class RCInt {
+  uint32_t Val;
+  bool Long;
+
+public:
+  RCInt(const RCToken &Token)
+      : Val(Token.intValue()), Long(Token.isLongInt()) {}
+  RCInt(uint32_t Value) : Val(Value), Long(false) {}
+  RCInt(uint32_t Value, bool IsLong) : Val(Value), Long(IsLong) {}
+  operator uint32_t() const { return Val; }
+  bool isLong() const { return Long; }
+
+  RCInt &operator+=(const RCInt &Rhs) {
+    std::tie(Val, Long) = std::make_pair(Val + Rhs.Val, Long | Rhs.Long);
+    return *this;
+  }
+
+  RCInt &operator-=(const RCInt &Rhs) {
+    std::tie(Val, Long) = std::make_pair(Val - Rhs.Val, Long | Rhs.Long);
+    return *this;
+  }
+
+  RCInt &operator|=(const RCInt &Rhs) {
+    std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long);
+    return *this;
+  }
+
+  RCInt &operator&=(const RCInt &Rhs) {
+    std::tie(Val, Long) = std::make_pair(Val & Rhs.Val, Long | Rhs.Long);
+    return *this;
+  }
+
+  RCInt operator-() const { return {-Val, Long}; }
+  RCInt operator~() const { return {~Val, Long}; }
+
+  friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) {
+    return OS << Int.Val << (Int.Long ? "L" : "");
+  }
+};
+
 // A class holding a name - either an integer or a reference to the string.
 class IntOrString {
 private:
   union Data {
-    uint32_t Int;
+    RCInt Int;
     StringRef String;
-    Data(uint32_t Value) : Int(Value) {}
+    Data(RCInt Value) : Int(Value) {}
     Data(const StringRef Value) : String(Value) {}
     Data(const RCToken &Token) {
       if (Token.kind() == RCToken::Kind::Int)
-        Int = Token.intValue();
+        Int = RCInt(Token);
       else
         String = Token.value();
     }
@@ -40,8 +85,9 @@
   bool IsInt;
 
 public:
-  IntOrString() : IntOrString(0) {}
+  IntOrString() : IntOrString(RCInt(0)) {}
   IntOrString(uint32_t Value) : Data(Value), IsInt(1) {}
+  IntOrString(RCInt Value) : Data(Value), IsInt(1) {}
   IntOrString(StringRef Value) : Data(Value), IsInt(0) {}
   IntOrString(const RCToken &Token)
       : Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {}
@@ -52,7 +98,7 @@
 
   bool isInt() const { return IsInt; }
 
-  uint32_t getInt() const {
+  RCInt getInt() const {
     assert(IsInt);
     return Data.Int;
   }
@@ -570,8 +616,15 @@
 // A single VERSIONINFO statement;
 class VersionInfoStmt {
 public:
+  enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
+
   virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
   virtual ~VersionInfoStmt() {}
+
+  virtual StmtKind getKind() const { return StBase; }
+  static bool classof(const VersionInfoStmt *S) {
+    return S->getKind() == StBase;
+  }
 };
 
 // BLOCK definition; also the main VERSIONINFO declaration is considered a
@@ -579,25 +632,38 @@
 // The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
 // care about them at the parsing phase.
 class VersionInfoBlock : public VersionInfoStmt {
+public:
   std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
   StringRef Name;
 
-public:
   VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
   void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
     Stmts.push_back(std::move(Stmt));
   }
   raw_ostream &log(raw_ostream &) const override;
+
+  StmtKind getKind() const override { return StBlock; }
+  static bool classof(const VersionInfoStmt *S) {
+    return S->getKind() == StBlock;
+  }
 };
 
 class VersionInfoValue : public VersionInfoStmt {
+public:
   StringRef Key;
   std::vector<IntOrString> Values;
+  std::vector<bool> HasPrecedingComma;
 
-public:
-  VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals)
-      : Key(InfoKey), Values(std::move(Vals)) {}
+  VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
+                   std::vector<bool> &&CommasBeforeVals)
+      : Key(InfoKey), Values(std::move(Vals)),
+        HasPrecedingComma(std::move(CommasBeforeVals)) {}
   raw_ostream &log(raw_ostream &) const override;
+
+  StmtKind getKind() const override { return StValue; }
+  static bool classof(const VersionInfoStmt *S) {
+    return S->getKind() == StValue;
+  }
 };
 
 class VersionInfoResource : public RCResource {
@@ -641,16 +707,24 @@
     raw_ostream &log(raw_ostream &) const;
   };
 
-private:
   VersionInfoBlock MainBlock;
   VersionInfoFixed FixedData;
 
-public:
   VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
                       VersionInfoFixed &&FixedInfo)
       : MainBlock(std::move(TopLevelBlock)), FixedData(std::move(FixedInfo)) {}
 
   raw_ostream &log(raw_ostream &) const override;
+  IntOrString getResourceType() const override { return RkVersionInfo; }
+  uint16_t getMemoryFlags() const override { return MfMoveable | MfPure; }
+  Twine getResourceTypeName() const override { return "VERSIONINFO"; }
+  Error visit(Visitor *V) const override {
+    return V->visitVersionInfoResource(this);
+  }
+  ResourceKind getKind() const override { return RkVersionInfo; }
+  static bool classof(const RCResource *Res) {
+    return Res->getKind() == RkVersionInfo;
+  }
 };
 
 // CHARACTERISTICS optional statement.