[llvm] r314562 - [llvm-rc] Serialize MENU resources to .res files (serialization, pt 3).

Marek Sokolowski via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 29 15:25:06 PDT 2017


Author: mnbvmar
Date: Fri Sep 29 15:25:05 2017
New Revision: 314562

URL: http://llvm.org/viewvc/llvm-project?rev=314562&view=rev
Log:
[llvm-rc] Serialize MENU resources to .res files (serialization, pt 3).

This allows MENU resources to be serialized.

MENU resource statement doc:
msdn.microsoft.com/en-us/library/windows/desktop/aa381025.aspx
POPUP sub-statement doc:
msdn.microsoft.com/en-us/library/windows/desktop/aa381030.aspx
MENUITEM sub-statement doc:
msdn.microsoft.com/en-us/library/windows/desktop/aa381024.aspx
MENUHEADER structure:
msdn.microsoft.com/en-us/library/windows/desktop/ms648018.aspx (and
NORMALMENUITEM, POPUPMENUITEM structs).

Thanks for Nico Weber for his original work in this area.

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

Added:
    llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu-bad-menuitem-id.rc
    llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu.rc
    llvm/trunk/test/tools/llvm-rc/tag-menu.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

Added: llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu-bad-menuitem-id.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu-bad-menuitem-id.rc?rev=314562&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu-bad-menuitem-id.rc (added)
+++ llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu-bad-menuitem-id.rc Fri Sep 29 15:25:05 2017
@@ -0,0 +1,3 @@
+1 MENU {
+  MENUITEM "Wrong", 100000, CHECKED
+}

Added: llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu.rc?rev=314562&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu.rc (added)
+++ llvm/trunk/test/tools/llvm-rc/Inputs/tag-menu.rc Fri Sep 29 15:25:05 2017
@@ -0,0 +1,60 @@
+CheckRecursion MENU {
+  POPUP "A" {
+    POPUP "B" {
+      MENUITEM "a", 1
+      MENUITEM "b", 2
+      MENUITEM "c", 3
+      POPUP "C" {
+        POPUP "D" { POPUP "E" { POPUP "F" { POPUP "G" { POPUP "H" { POPUP "I" {
+          MENUITEM "d", 57134
+        }}}}}}
+      }
+    }
+    MENUITEM "efg", 23333
+  }
+}
+
+
+CheckFlags MENU {
+  MENUITEM "a", 1, CHECKED
+  MENUITEM "b", 2, GRAYED
+  MENUITEM "c", 3, HELP
+  MENUITEM "d", 4, INACTIVE
+  MENUITEM "e", 5, MENUBARBREAK
+  MENUITEM "f", 6, MENUBREAK
+  MENUITEM "ad", 7, CHECKED, INACTIVE
+  MENUITEM SEPARATOR
+  POPUP "A", CHECKED { MENUITEM "x", 100 }
+  POPUP "B", GRAYED { MENUITEM "x", 101 }
+  POPUP "C", HELP { MENUITEM "x", 102 }
+  POPUP "D", INACTIVE { MENUITEM "x", 103 }
+  POPUP "E", MENUBARBREAK { MENUITEM "x", 104 }
+  POPUP "F", MENUBREAK { MENUITEM "x", 105 }
+  POPUP "G", HELP, MENUBARBREAK, GRAYED {
+    POPUP "H", CHECKED, MENUBREAK, HELP, INACTIVE {
+      MENUITEM SEPARATOR
+      MENUITEM "x", 106, INACTIVE, MENUBARBREAK
+      MENUITEM SEPARATOR
+    }
+  }
+  MENUITEM "abcdef", 8, help, inactive, menubarbreak, checked, grayed, menubreak
+}
+
+
+CheckOpts MENU
+CHARACTERISTICS 500
+LANGUAGE 1, 1
+VERSION 128
+BEGIN
+  POPUP "&Only separator" {
+    MENUITEM SEPARATOR
+  }
+  POPUP "O&ther things" {
+    MENUITEM "&abcde", 1
+    MENUITEM "a&bcde", 2
+    MENUITEM "ab&cde", 3
+    MENUITEM "abc&de", 4
+    MENUITEM "abcd&e", 5
+  }
+END
+

Added: llvm/trunk/test/tools/llvm-rc/tag-menu.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/tag-menu.test?rev=314562&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/tag-menu.test (added)
+++ llvm/trunk/test/tools/llvm-rc/tag-menu.test Fri Sep 29 15:25:05 2017
@@ -0,0 +1,75 @@
+; RUN: llvm-rc /FO %t %p/Inputs/tag-menu.rc
+; RUN: llvm-readobj %t | FileCheck %s --check-prefix=MENU
+
+; MENU: Resource type (int): 4
+; MENU-NEXT: Resource name (string): CHECKRECURSION
+; MENU-NEXT: Data version: 0
+; MENU-NEXT: Memory flags: 0x1030
+; MENU-NEXT: Language ID: 1033
+; MENU-NEXT: Version (major): 0
+; MENU-NEXT: Version (minor): 0
+; MENU-NEXT: Characteristics: 0
+; MENU-NEXT: Data size: 102
+; MENU-NEXT: Data: (
+; MENU-NEXT:   0000: 00000000 90004100 00001000 42000000  |......A.....B...|
+; MENU-NEXT:   0010: 00000100 61000000 00000200 62000000  |....a.......b...|
+; MENU-NEXT:   0020: 00000300 63000000 90004300 00009000  |....c.....C.....|
+; MENU-NEXT:   0030: 44000000 90004500 00009000 46000000  |D.....E.....F...|
+; MENU-NEXT:   0040: 90004700 00009000 48000000 90004900  |..G.....H.....I.|
+; MENU-NEXT:   0050: 00008000 2EDF6400 00008000 255B6500  |......d.....%[e.|
+; MENU-NEXT:   0060: 66006700 0000                        |f.g...|
+; MENU-NEXT: )
+
+; MENU-DAG: Resource type (int): 4
+; MENU-NEXT: Resource name (string): CHECKFLAGS
+; MENU-NEXT: Data version: 0
+; MENU-NEXT: Memory flags: 0x1030
+; MENU-NEXT: Language ID: 1033
+; MENU-NEXT: Version (major): 0
+; MENU-NEXT: Version (minor): 0
+; MENU-NEXT: Characteristics: 0
+; MENU-NEXT: Data size: 202
+; MENU-NEXT: Data: (
+; MENU-NEXT:   0000: 00000000 08000100 61000000 01000200  |........a.......|
+; MENU-NEXT:   0010: 62000000 00400300 63000000 02000400  |b.... at ..c.......|
+; MENU-NEXT:   0020: 64000000 20000500 65000000 40000600  |d... ...e... at ...|
+; MENU-NEXT:   0030: 66000000 0A000700 61006400 00000000  |f.......a.d.....|
+; MENU-NEXT:   0040: 00000000 18004100 00008000 64007800  |......A.....d.x.|
+; MENU-NEXT:   0050: 00001100 42000000 80006500 78000000  |....B.....e.x...|
+; MENU-NEXT:   0060: 10404300 00008000 66007800 00001200  |. at C.....f.x.....|
+; MENU-NEXT:   0070: 44000000 80006700 78000000 30004500  |D.....g.x...0.E.|
+; MENU-NEXT:   0080: 00008000 68007800 00005000 46000000  |....h.x...P.F...|
+; MENU-NEXT:   0090: 80006900 78000000 31404700 0000DA40  |..i.x...1 at G....@|
+; MENU-NEXT:   00A0: 48000000 00000000 00002200 6A007800  |H.........".j.x.|
+; MENU-NEXT:   00B0: 00008000 00000000 EB400800 61006200  |......... at ..a.b.|
+; MENU-NEXT:   00C0: 63006400 65006600 0000               |c.d.e.f...|
+; MENU-NEXT: )
+
+; MENU-DAG: Resource type (int): 4
+; MENU-NEXT: Resource name (string): CHECKOPTS
+; MENU-NEXT: Data version: 0
+; MENU-NEXT: Memory flags: 0x1030
+; MENU-NEXT: Language ID: 1025
+; MENU-NEXT: Version (major): 0
+; MENU-NEXT: Version (minor): 128
+; MENU-NEXT: Characteristics: 500
+; MENU-NEXT: Data size: 164
+; MENU-NEXT: Data: (
+; MENU-NEXT:   0000: 00000000 10002600 4F006E00 6C007900  |......&.O.n.l.y.|
+; MENU-NEXT:   0010: 20007300 65007000 61007200 61007400  | .s.e.p.a.r.a.t.|
+; MENU-NEXT:   0020: 6F007200 00008000 00000000 90004F00  |o.r...........O.|
+; MENU-NEXT:   0030: 26007400 68006500 72002000 74006800  |&.t.h.e.r. .t.h.|
+; MENU-NEXT:   0040: 69006E00 67007300 00000000 01002600  |i.n.g.s.......&.|
+; MENU-NEXT:   0050: 61006200 63006400 65000000 00000200  |a.b.c.d.e.......|
+; MENU-NEXT:   0060: 61002600 62006300 64006500 00000000  |a.&.b.c.d.e.....|
+; MENU-NEXT:   0070: 03006100 62002600 63006400 65000000  |..a.b.&.c.d.e...|
+; MENU-NEXT:   0080: 00000400 61006200 63002600 64006500  |....a.b.c.&.d.e.|
+; MENU-NEXT:   0090: 00008000 05006100 62006300 64002600  |......a.b.c.d.&.|
+; MENU-NEXT:   00A0: 65000000                             |e...|
+; MENU-NEXT: )
+
+
+; RUN: not llvm-rc /FO %t %p/Inputs/tag-menu-bad-menuitem-id.rc 2>&1 | FileCheck %s --check-prefix BADID
+
+; BADID: llvm-rc: Error in MENU statement (ID 1):
+; BADID-NEXT: MENUITEM action ID (100000) does not fit in 16 bits.

Modified: llvm/trunk/tools/llvm-rc/ResourceFileWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceFileWriter.cpp?rev=314562&r1=314561&r2=314562&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceFileWriter.cpp (original)
+++ llvm/trunk/tools/llvm-rc/ResourceFileWriter.cpp Fri Sep 29 15:25:05 2017
@@ -205,6 +205,10 @@ Error ResourceFileWriter::visitHTMLResou
   return writeResource(Res, &ResourceFileWriter::writeHTMLBody);
 }
 
+Error ResourceFileWriter::visitMenuResource(const RCResource *Res) {
+  return writeResource(Res, &ResourceFileWriter::writeMenuBody);
+}
+
 Error ResourceFileWriter::visitCharacteristicsStmt(
     const CharacteristicsStmt *Stmt) {
   ObjectData.Characteristics = Stmt->Value;
@@ -382,5 +386,55 @@ Error ResourceFileWriter::writeHTMLBody(
   return appendFile(cast<HTMLResource>(Base)->HTMLLoc);
 }
 
+// --- MenuResource helpers. --- //
+
+Error ResourceFileWriter::writeMenuDefinition(
+    const std::unique_ptr<MenuDefinition> &Def, uint16_t Flags) {
+  assert(Def);
+  const MenuDefinition *DefPtr = Def.get();
+
+  if (auto *MenuItemPtr = dyn_cast<MenuItem>(DefPtr)) {
+    writeInt<uint16_t>(Flags);
+    RETURN_IF_ERROR(
+        checkNumberFits<uint16_t>(MenuItemPtr->Id, "MENUITEM action ID"));
+    writeInt<uint16_t>(MenuItemPtr->Id);
+    RETURN_IF_ERROR(writeCString(MenuItemPtr->Name));
+    return Error::success();
+  }
+
+  if (isa<MenuSeparator>(DefPtr)) {
+    writeInt<uint16_t>(Flags);
+    writeInt<uint32_t>(0);
+    return Error::success();
+  }
+
+  auto *PopupPtr = cast<PopupItem>(DefPtr);
+  writeInt<uint16_t>(Flags);
+  RETURN_IF_ERROR(writeCString(PopupPtr->Name));
+  return writeMenuDefinitionList(PopupPtr->SubItems);
+}
+
+Error ResourceFileWriter::writeMenuDefinitionList(
+    const MenuDefinitionList &List) {
+  for (auto &Def : List.Definitions) {
+    uint16_t Flags = Def->getResFlags();
+    // Last element receives an additional 0x80 flag.
+    const uint16_t LastElementFlag = 0x0080;
+    if (&Def == &List.Definitions.back())
+      Flags |= LastElementFlag;
+
+    RETURN_IF_ERROR(writeMenuDefinition(Def, Flags));
+  }
+  return Error::success();
+}
+
+Error ResourceFileWriter::writeMenuBody(const RCResource *Base) {
+  // At first, MENUHEADER structure. In fact, these are two WORDs equal to 0.
+  // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648018.aspx
+  writeObject<uint32_t>(0);
+
+  return writeMenuDefinitionList(cast<MenuResource>(Base)->Elements);
+}
+
 } // namespace rc
 } // namespace llvm

Modified: llvm/trunk/tools/llvm-rc/ResourceFileWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceFileWriter.h?rev=314562&r1=314561&r2=314562&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceFileWriter.h (original)
+++ llvm/trunk/tools/llvm-rc/ResourceFileWriter.h Fri Sep 29 15:25:05 2017
@@ -32,6 +32,7 @@ public:
   Error visitNullResource(const RCResource *) override;
   Error visitAcceleratorsResource(const RCResource *) override;
   Error visitHTMLResource(const RCResource *) override;
+  Error visitMenuResource(const RCResource *) override;
 
   Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
   Error visitLanguageStmt(const LanguageResource *) override;
@@ -63,6 +64,12 @@ private:
   // HTMLResource
   Error writeHTMLBody(const RCResource *);
 
+  // MenuResource
+  Error writeMenuDefinition(const std::unique_ptr<MenuDefinition> &,
+                            uint16_t Flags);
+  Error writeMenuDefinitionList(const MenuDefinitionList &List);
+  Error writeMenuBody(const RCResource *);
+
   // Output stream handling.
   std::unique_ptr<raw_fd_ostream> FS;
 

Modified: llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h?rev=314562&r1=314561&r2=314562&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h (original)
+++ llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h Fri Sep 29 15:25:05 2017
@@ -315,6 +315,8 @@ public:
     MENUBREAK = 0x0040
   };
 
+  enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
+
   static constexpr size_t NumFlags = 6;
   static StringRef OptionsStr[NumFlags];
   static uint32_t OptionsFlags[NumFlags];
@@ -323,13 +325,16 @@ public:
     return OS << "Base menu definition\n";
   }
   virtual ~MenuDefinition() {}
+
+  virtual uint16_t getResFlags() const { return 0; }
+  virtual MenuDefKind getKind() const { return MkBase; }
 };
 
 // Recursive description of a whole submenu.
 class MenuDefinitionList : public MenuDefinition {
+public:
   std::vector<std::unique_ptr<MenuDefinition>> Definitions;
 
-public:
   void addDefinition(std::unique_ptr<MenuDefinition> Def) {
     Definitions.push_back(std::move(Def));
   }
@@ -342,46 +347,73 @@ public:
 class MenuSeparator : public MenuDefinition {
 public:
   raw_ostream &log(raw_ostream &) const override;
+
+  MenuDefKind getKind() const override { return MkSeparator; }
+  static bool classof(const MenuDefinition *D) {
+    return D->getKind() == MkSeparator;
+  }
 };
 
 // MENUITEM statement definition.
 //
 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
 class MenuItem : public MenuDefinition {
+public:
   StringRef Name;
   uint32_t Id;
   uint16_t Flags;
 
-public:
   MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
       : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
   raw_ostream &log(raw_ostream &) const override;
+
+  uint16_t getResFlags() const override { return Flags; }
+  MenuDefKind getKind() const override { return MkMenuItem; }
+  static bool classof(const MenuDefinition *D) {
+    return D->getKind() == MkMenuItem;
+  }
 };
 
 // POPUP statement definition.
 //
 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
 class PopupItem : public MenuDefinition {
+public:
   StringRef Name;
   uint16_t Flags;
   MenuDefinitionList SubItems;
 
-public:
   PopupItem(StringRef Caption, uint16_t ItemFlags,
             MenuDefinitionList &&SubItemsList)
       : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
   raw_ostream &log(raw_ostream &) const override;
+
+  // This has an additional (0x10) flag. It doesn't match with documented
+  // 0x01 flag, though.
+  uint16_t getResFlags() const override { return Flags | 0x10; }
+  MenuDefKind getKind() const override { return MkPopup; }
+  static bool classof(const MenuDefinition *D) {
+    return D->getKind() == MkPopup;
+  }
 };
 
 // Menu resource definition.
 class MenuResource : public OptStatementsRCResource {
+public:
   MenuDefinitionList Elements;
 
-public:
   MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items)
       : OptStatementsRCResource(std::move(OptStmts)),
         Elements(std::move(Items)) {}
   raw_ostream &log(raw_ostream &) const override;
+
+  IntOrString getResourceType() const override { return RkMenu; }
+  Twine getResourceTypeName() const override { return "MENU"; }
+  Error visit(Visitor *V) const override { return V->visitMenuResource(this); }
+  ResourceKind getKind() const override { return RkMenu; }
+  static bool classof(const RCResource *Res) {
+    return Res->getKind() == RkMenu;
+  }
 };
 
 // STRINGTABLE resource. Contains a list of strings, each having its unique ID.

Modified: llvm/trunk/tools/llvm-rc/ResourceVisitor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceVisitor.h?rev=314562&r1=314561&r2=314562&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceVisitor.h (original)
+++ llvm/trunk/tools/llvm-rc/ResourceVisitor.h Fri Sep 29 15:25:05 2017
@@ -30,6 +30,7 @@ public:
   virtual Error visitNullResource(const RCResource *) = 0;
   virtual Error visitAcceleratorsResource(const RCResource *) = 0;
   virtual Error visitHTMLResource(const RCResource *) = 0;
+  virtual Error visitMenuResource(const RCResource *) = 0;
 
   virtual Error visitCharacteristicsStmt(const CharacteristicsStmt *) = 0;
   virtual Error visitLanguageStmt(const LanguageResource *) = 0;




More information about the llvm-commits mailing list