[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