[llvm-rc] Support EXSTYLE statement.

Patch by Jacek Caban!

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

llvm-svn: 347858
diff --git a/llvm/test/tools/llvm-rc/Inputs/tag-dialog-headers.rc b/llvm/test/tools/llvm-rc/Inputs/tag-dialog-headers.rc
index 65bc243..3a71f23 100644
--- a/llvm/test/tools/llvm-rc/Inputs/tag-dialog-headers.rc
+++ b/llvm/test/tools/llvm-rc/Inputs/tag-dialog-headers.rc
@@ -54,3 +54,8 @@
 27 DIALOGEX 5, 5, 5, 5 CLASS "Foobar" {}
 28 DIALOG 5, 5, 5, 5 CLASS 42 {}
 
+29 DIALOGEX 0, 1, 0, 9 EXSTYLE 0x01234567 {}
+30 DIALOG 0, 1, 0, 9 EXSTYLE 0x01234567 {}
+
+31 DIALOGEX 0, 1, 0, 9 STYLE 0x76543210 EXSTYLE 0x01234567 {}
+32 DIALOG 0, 1, 0, 9 EXSTYLE 0x0123456 STYLE 0x76543210 {}
diff --git a/llvm/test/tools/llvm-rc/tag-dialog.test b/llvm/test/tools/llvm-rc/tag-dialog.test
index 36fcb6d..85a8c20 100644
--- a/llvm/test/tools/llvm-rc/tag-dialog.test
+++ b/llvm/test/tools/llvm-rc/tag-dialog.test
@@ -579,6 +579,62 @@
 ; HEADERS-NEXT:   0010: 05000000 FFFF2A00 0000               |......*...|
 ; HEADERS-NEXT: )
 
+; HEADERS-DAG: Resource type (int): 5
+; HEADERS-NEXT: Resource name (int): 29
+; HEADERS-NEXT: Data version: 0
+; HEADERS-NEXT: Memory flags: 0x1030
+; HEADERS-NEXT: Language ID: 1033
+; HEADERS-NEXT: Version (major): 0
+; HEADERS-NEXT: Version (minor): 0
+; HEADERS-NEXT: Characteristics: 0
+; HEADERS-NEXT: Data size: 32
+; HEADERS-NEXT: Data: (
+; HEADERS-NEXT:   0000: 0100FFFF 00000000 67452301 00008880  |........gE#.....|
+; HEADERS-NEXT:   0010: 00000000 01000000 09000000 00000000  |................|
+; HEADERS-NEXT: )
+
+; HEADERS-DAG: Resource type (int): 5
+; HEADERS-NEXT: Resource name (int): 30
+; HEADERS-NEXT: Data version: 0
+; HEADERS-NEXT: Memory flags: 0x1030
+; HEADERS-NEXT: Language ID: 1033
+; HEADERS-NEXT: Version (major): 0
+; HEADERS-NEXT: Version (minor): 0
+; HEADERS-NEXT: Characteristics: 0
+; HEADERS-NEXT: Data size: 24
+; HEADERS-NEXT: Data: (
+; HEADERS-NEXT:   0000: 00008880 67452301 00000000 01000000  |....gE#.........|
+; HEADERS-NEXT:   0010: 09000000 00000000                    |........|
+; HEADERS-NEXT: )
+
+; HEADERS-DAG: Resource type (int): 5
+; HEADERS-NEXT: Resource name (int): 31
+; HEADERS-NEXT: Data version: 0
+; HEADERS-NEXT: Memory flags: 0x1030
+; HEADERS-NEXT: Language ID: 1033
+; HEADERS-NEXT: Version (major): 0
+; HEADERS-NEXT: Version (minor): 0
+; HEADERS-NEXT: Characteristics: 0
+; HEADERS-NEXT: Data size: 32
+; HEADERS-NEXT: Data: (
+; HEADERS-NEXT:   0000: 0100FFFF 00000000 67452301 10325476  |........gE#..2Tv|
+; HEADERS-NEXT:   0010: 00000000 01000000 09000000 00000000  |................|
+; HEADERS-NEXT: )
+
+; HEADERS-DAG: Resource type (int): 5
+; HEADERS-NEXT: Resource name (int): 32
+; HEADERS-NEXT: Data version: 0
+; HEADERS-NEXT: Memory flags: 0x1030
+; HEADERS-NEXT: Language ID: 1033
+; HEADERS-NEXT: Version (major): 0
+; HEADERS-NEXT: Version (minor): 0
+; HEADERS-NEXT: Characteristics: 0
+; HEADERS-NEXT: Data size: 24
+; HEADERS-NEXT: Data: (
+; HEADERS-NEXT:   0000: 10325476 56341200 00000000 01000000  |.2TvV4..........|
+; HEADERS-NEXT:   0010: 09000000 00000000                    |........|
+; HEADERS-NEXT: )
+
 
 ; RUN: not llvm-rc /FO %t %p/Inputs/tag-dialog-large-coord.rc 2>&1 | FileCheck %s --check-prefix COORD1
 
diff --git a/llvm/tools/llvm-rc/ResourceFileWriter.cpp b/llvm/tools/llvm-rc/ResourceFileWriter.cpp
index 95d92a9..e69d479 100644
--- a/llvm/tools/llvm-rc/ResourceFileWriter.cpp
+++ b/llvm/tools/llvm-rc/ResourceFileWriter.cpp
@@ -514,6 +514,11 @@
   return Error::success();
 }
 
+Error ResourceFileWriter::visitExStyleStmt(const ExStyleStmt *Stmt) {
+  ObjectData.ExStyle = Stmt->Value;
+  return Error::success();
+}
+
 Error ResourceFileWriter::visitFontStmt(const FontStmt *Stmt) {
   RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Size, "Font size"));
   RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Weight, "Font weight"));
@@ -1065,6 +1070,7 @@
     UsedStyle |= StyleCaptionFlag;
 
   const uint16_t DialogExMagic = 0xFFFF;
+  uint32_t ExStyle = ObjectData.ExStyle.getValueOr(0);
 
   // Write DIALOG(EX) header prefix. These are pretty different.
   if (!Res->IsExtended) {
@@ -1083,7 +1089,7 @@
       ulittle32_t Style;
       ulittle32_t ExtStyle;
     } Prefix{ulittle32_t(UsedStyle),
-             ulittle32_t(0)}; // As of now, we don't keep EXSTYLE.
+             ulittle32_t(ExStyle)};
 
     writeObject(Prefix);
   } else {
@@ -1094,7 +1100,7 @@
       ulittle32_t ExtStyle;
       ulittle32_t Style;
     } Prefix{ulittle16_t(1), ulittle16_t(DialogExMagic),
-             ulittle32_t(Res->HelpID), ulittle32_t(0), ulittle32_t(UsedStyle)};
+             ulittle32_t(Res->HelpID), ulittle32_t(ExStyle), ulittle32_t(UsedStyle)};
 
     writeObject(Prefix);
   }
diff --git a/llvm/tools/llvm-rc/ResourceFileWriter.h b/llvm/tools/llvm-rc/ResourceFileWriter.h
index 4c31d01..36d57da 100644
--- a/llvm/tools/llvm-rc/ResourceFileWriter.h
+++ b/llvm/tools/llvm-rc/ResourceFileWriter.h
@@ -63,6 +63,7 @@
   Error visitCaptionStmt(const CaptionStmt *) override;
   Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
   Error visitClassStmt(const ClassStmt *) override;
+  Error visitExStyleStmt(const ExStyleStmt *) override;
   Error visitFontStmt(const FontStmt *) override;
   Error visitLanguageStmt(const LanguageResource *) override;
   Error visitStyleStmt(const StyleStmt *) override;
@@ -80,6 +81,7 @@
     uint32_t VersionInfo;
 
     Optional<uint32_t> Style;
+    Optional<uint32_t> ExStyle;
     StringRef Caption;
     struct FontInfo {
       uint32_t Size;
diff --git a/llvm/tools/llvm-rc/ResourceScriptParser.cpp b/llvm/tools/llvm-rc/ResourceScriptParser.cpp
index 8cc0b50..09c88ff 100644
--- a/llvm/tools/llvm-rc/ResourceScriptParser.cpp
+++ b/llvm/tools/llvm-rc/ResourceScriptParser.cpp
@@ -388,6 +388,8 @@
       return parseCaptionStmt();
     if (TypeToken->equals_lower("CLASS"))
       return parseClassStmt();
+    if (TypeToken->equals_lower("EXSTYLE"))
+      return parseExStyleStmt();
     if (TypeToken->equals_lower("FONT"))
       return parseFontStmt(StmtsType);
     if (TypeToken->equals_lower("STYLE"))
@@ -817,6 +819,11 @@
   return llvm::make_unique<StyleStmt>(*Arg);
 }
 
+RCParser::ParseOptionType RCParser::parseExStyleStmt() {
+  ASSIGN_OR_RETURN(Arg, readInt());
+  return llvm::make_unique<ExStyleStmt>(*Arg);
+}
+
 Error RCParser::getExpectedError(const Twine &Message, bool IsAlreadyRead) {
   return make_error<ParserError>(
       Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End);
diff --git a/llvm/tools/llvm-rc/ResourceScriptParser.h b/llvm/tools/llvm-rc/ResourceScriptParser.h
index 3dd110f..4f047f3 100644
--- a/llvm/tools/llvm-rc/ResourceScriptParser.h
+++ b/llvm/tools/llvm-rc/ResourceScriptParser.h
@@ -172,6 +172,7 @@
   ParseOptionType parseVersionStmt();
   ParseOptionType parseCaptionStmt();
   ParseOptionType parseClassStmt();
+  ParseOptionType parseExStyleStmt();
   ParseOptionType parseFontStmt(OptStmtType DialogType);
   ParseOptionType parseStyleStmt();
 
diff --git a/llvm/tools/llvm-rc/ResourceScriptStmt.cpp b/llvm/tools/llvm-rc/ResourceScriptStmt.cpp
index 728c24b..3257072 100644
--- a/llvm/tools/llvm-rc/ResourceScriptStmt.cpp
+++ b/llvm/tools/llvm-rc/ResourceScriptStmt.cpp
@@ -283,5 +283,9 @@
   return OS << "Style: " << Value << "\n";
 }
 
+raw_ostream &ExStyleStmt::log(raw_ostream &OS) const {
+  return OS << "ExStyle: " << Value << "\n";
+}
+
 } // namespace rc
 } // namespace llvm
diff --git a/llvm/tools/llvm-rc/ResourceScriptStmt.h b/llvm/tools/llvm-rc/ResourceScriptStmt.h
index 2071ac6..0051f83 100644
--- a/llvm/tools/llvm-rc/ResourceScriptStmt.h
+++ b/llvm/tools/llvm-rc/ResourceScriptStmt.h
@@ -866,6 +866,19 @@
   Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
 };
 
+// EXSTYLE optional statement.
+//
+// Ref: docs.microsoft.com/en-us/windows/desktop/menurc/exstyle-statement
+class ExStyleStmt : public OptionalStmt {
+public:
+  uint32_t Value;
+
+  ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {}
+  raw_ostream &log(raw_ostream &) const override;
+  Twine getResourceTypeName() const override { return "EXSTYLE"; }
+  Error visit(Visitor *V) const override { return V->visitExStyleStmt(this); }
+};
+
 // CLASS optional statement.
 //
 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380883(v=vs.85).aspx
diff --git a/llvm/tools/llvm-rc/ResourceVisitor.h b/llvm/tools/llvm-rc/ResourceVisitor.h
index 53ef3c5..2117b12 100644
--- a/llvm/tools/llvm-rc/ResourceVisitor.h
+++ b/llvm/tools/llvm-rc/ResourceVisitor.h
@@ -24,6 +24,7 @@
 class CaptionStmt;
 class ClassStmt;
 class CharacteristicsStmt;
+class ExStyleStmt;
 class FontStmt;
 class LanguageResource;
 class StyleStmt;
@@ -46,6 +47,7 @@
   virtual Error visitCaptionStmt(const CaptionStmt *) = 0;
   virtual Error visitClassStmt(const ClassStmt *) = 0;
   virtual Error visitCharacteristicsStmt(const CharacteristicsStmt *) = 0;
+  virtual Error visitExStyleStmt(const ExStyleStmt *) = 0;
   virtual Error visitFontStmt(const FontStmt *) = 0;
   virtual Error visitLanguageStmt(const LanguageResource *) = 0;
   virtual Error visitStyleStmt(const StyleStmt *) = 0;