diff options
author | Marek Sokolowski <mnbvmar@gmail.com> | 2017-08-28 23:46:30 +0000 |
---|---|---|
committer | Marek Sokolowski <mnbvmar@gmail.com> | 2017-08-28 23:46:30 +0000 |
commit | 233d2b81e8b307be4294df5540f4f21c0a3696fb (patch) | |
tree | e50506ad2cd81385e38dc95a22b222ba262b7cb8 /tools/llvm-rc | |
parent | cc308a061570ca2c8cca83a9b6527892588d5638 (diff) |
[llvm-rc] Add MENU parsing ability (parser, pt 4/8).
This extends llvm-rc parsing tool by MENU resource
(msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx).
As for now, MENUEX
(msdn.microsoft.com/en-us/library/windows/desktop/aa381023(v=vs.85).aspx)
seems unnecessary.
Thanks for Nico Weber for his original work in this area.
Differential Revision: https://reviews.llvm.org/D36898
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311956 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvm-rc')
-rw-r--r-- | tools/llvm-rc/ResourceScriptParser.cpp | 67 | ||||
-rw-r--r-- | tools/llvm-rc/ResourceScriptParser.h | 4 | ||||
-rw-r--r-- | tools/llvm-rc/ResourceScriptStmt.cpp | 40 | ||||
-rw-r--r-- | tools/llvm-rc/ResourceScriptStmt.h | 86 |
4 files changed, 197 insertions, 0 deletions
diff --git a/tools/llvm-rc/ResourceScriptParser.cpp b/tools/llvm-rc/ResourceScriptParser.cpp index 8d08396e615..5cc171c49af 100644 --- a/tools/llvm-rc/ResourceScriptParser.cpp +++ b/tools/llvm-rc/ResourceScriptParser.cpp @@ -71,6 +71,8 @@ RCParser::ParseType RCParser::parseSingleResource() { Result = parseIconResource(); else if (TypeToken->equalsLower("HTML")) Result = parseHTMLResource(); + else if (TypeToken->equalsLower("MENU")) + Result = parseMenuResource(); else return getExpectedError("resource type", /* IsAlreadyRead = */ true); @@ -285,6 +287,71 @@ RCParser::ParseType RCParser::parseHTMLResource() { return make_unique<HTMLResource>(*Arg); } +RCParser::ParseType RCParser::parseMenuResource() { + ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements()); + ASSIGN_OR_RETURN(Items, parseMenuItemsList()); + return make_unique<MenuResource>(std::move(*OptStatements), + std::move(*Items)); +} + +Expected<MenuDefinitionList> RCParser::parseMenuItemsList() { + RETURN_IF_ERROR(consumeType(Kind::BlockBegin)); + + MenuDefinitionList List; + + // Read a set of items. Each item is of one of three kinds: + // MENUITEM SEPARATOR + // MENUITEM caption:String, result:Int [, menu flags]... + // POPUP caption:String [, menu flags]... { items... } + while (!consumeOptionalType(Kind::BlockEnd)) { + ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier()); + + bool IsMenuItem = ItemTypeResult->equals_lower("MENUITEM"); + bool IsPopup = ItemTypeResult->equals_lower("POPUP"); + if (!IsMenuItem && !IsPopup) + return getExpectedError("MENUITEM, POPUP, END or '}'", true); + + if (IsMenuItem && isNextTokenKind(Kind::Identifier)) { + // Now, expecting SEPARATOR. + ASSIGN_OR_RETURN(SeparatorResult, readIdentifier()); + if (SeparatorResult->equals_lower("SEPARATOR")) { + List.addDefinition(make_unique<MenuSeparator>()); + continue; + } + + return getExpectedError("SEPARATOR or string", true); + } + + // Not a separator. Read the caption. + ASSIGN_OR_RETURN(CaptionResult, readString()); + + // If MENUITEM, expect also a comma and an integer. + uint32_t MenuResult = -1; + + if (IsMenuItem) { + RETURN_IF_ERROR(consumeType(Kind::Comma)); + ASSIGN_OR_RETURN(IntResult, readInt()); + MenuResult = *IntResult; + } + + ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr)); + + if (IsPopup) { + // If POPUP, read submenu items recursively. + ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList()); + List.addDefinition(make_unique<PopupItem>(*CaptionResult, *FlagsResult, + std::move(*SubMenuResult))); + continue; + } + + assert(IsMenuItem); + List.addDefinition( + make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult)); + } + + return std::move(List); +} + RCParser::ParseType RCParser::parseStringTableResource() { ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements()); RETURN_IF_ERROR(consumeType(Kind::BlockBegin)); diff --git a/tools/llvm-rc/ResourceScriptParser.h b/tools/llvm-rc/ResourceScriptParser.h index e286f83160c..3fd1c27d928 100644 --- a/tools/llvm-rc/ResourceScriptParser.h +++ b/tools/llvm-rc/ResourceScriptParser.h @@ -130,8 +130,12 @@ private: ParseType parseCursorResource(); ParseType parseIconResource(); ParseType parseHTMLResource(); + ParseType parseMenuResource(); ParseType parseStringTableResource(); + // Helper MENU parser. + Expected<MenuDefinitionList> parseMenuItemsList(); + // Optional statement parsers. ParseOptionType parseLanguageStmt(); ParseOptionType parseCharacteristicsStmt(); diff --git a/tools/llvm-rc/ResourceScriptStmt.cpp b/tools/llvm-rc/ResourceScriptStmt.cpp index 150b668bd91..9f61ce451de 100644 --- a/tools/llvm-rc/ResourceScriptStmt.cpp +++ b/tools/llvm-rc/ResourceScriptStmt.cpp @@ -65,6 +65,46 @@ raw_ostream &HTMLResource::log(raw_ostream &OS) const { return OS << "HTML (" << ResName << "): " << HTMLLoc << "\n"; } +StringRef MenuDefinition::OptionsStr[MenuDefinition::NumFlags] = { + "CHECKED", "GRAYED", "HELP", "INACTIVE", "MENUBARBREAK", "MENUBREAK"}; + +raw_ostream &MenuDefinition::logFlags(raw_ostream &OS, uint8_t Flags) { + for (size_t i = 0; i < NumFlags; ++i) + if (Flags & (1U << i)) + OS << " " << OptionsStr[i]; + return OS; +} + +raw_ostream &MenuDefinitionList::log(raw_ostream &OS) const { + OS << " Menu list starts\n"; + for (auto &Item : Definitions) + Item->log(OS); + return OS << " Menu list ends\n"; +} + +raw_ostream &MenuItem::log(raw_ostream &OS) const { + OS << " MenuItem (" << Name << "), ID = " << Id; + logFlags(OS, Flags); + return OS << "\n"; +} + +raw_ostream &MenuSeparator::log(raw_ostream &OS) const { + return OS << " Menu separator\n"; +} + +raw_ostream &PopupItem::log(raw_ostream &OS) const { + OS << " Popup (" << Name << ")"; + logFlags(OS, Flags); + OS << ":\n"; + return SubItems.log(OS); +} + +raw_ostream &MenuResource::log(raw_ostream &OS) const { + OS << "Menu (" << ResName << "):\n"; + OptStatements.log(OS); + return Elements.log(OS); +} + raw_ostream &StringTableResource::log(raw_ostream &OS) const { OS << "StringTable:\n"; OptStatements.log(OS); diff --git a/tools/llvm-rc/ResourceScriptStmt.h b/tools/llvm-rc/ResourceScriptStmt.h index cf1406e043f..7166138a517 100644 --- a/tools/llvm-rc/ResourceScriptStmt.h +++ b/tools/llvm-rc/ResourceScriptStmt.h @@ -166,6 +166,92 @@ public: raw_ostream &log(raw_ostream &) const override; }; +// -- MENU resource and its helper classes -- +// This resource describes the contents of an application menu +// (usually located in the upper part of the dialog.) +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx + +// Description of a single submenu item. +class MenuDefinition { +public: + enum Options { + CHECKED = (1 << 0), + GRAYED = (1 << 1), + HELP = (1 << 2), + INACTIVE = (1 << 3), + MENUBARBREAK = (1 << 4), + MENUBREAK = (1 << 5) + }; + + static constexpr size_t NumFlags = 6; + static StringRef OptionsStr[NumFlags]; + static raw_ostream &logFlags(raw_ostream &, uint8_t Flags); + virtual raw_ostream &log(raw_ostream &OS) const { + return OS << "Base menu definition\n"; + } + virtual ~MenuDefinition() {} +}; + +// Recursive description of a whole submenu. +class MenuDefinitionList : public MenuDefinition { + std::vector<std::unique_ptr<MenuDefinition>> Definitions; + +public: + void addDefinition(std::unique_ptr<MenuDefinition> Def) { + Definitions.push_back(std::move(Def)); + } + raw_ostream &log(raw_ostream &) const override; +}; + +// Separator in MENU definition (MENUITEM SEPARATOR). +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx +class MenuSeparator : public MenuDefinition { +public: + raw_ostream &log(raw_ostream &) const override; +}; + +// MENUITEM statement definition. +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx +class MenuItem : public MenuDefinition { + StringRef Name; + uint32_t Id; + uint8_t Flags; + +public: + MenuItem(StringRef Caption, uint32_t ItemId, uint8_t ItemFlags) + : Name(Caption), Id(ItemId), Flags(ItemFlags) {} + raw_ostream &log(raw_ostream &) const override; +}; + +// POPUP statement definition. +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx +class PopupItem : public MenuDefinition { + StringRef Name; + uint8_t Flags; + MenuDefinitionList SubItems; + +public: + PopupItem(StringRef Caption, uint8_t ItemFlags, + MenuDefinitionList &&SubItemsList) + : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {} + raw_ostream &log(raw_ostream &) const override; +}; + +// Menu resource definition. +class MenuResource : public RCResource { + OptionalStmtList OptStatements; + MenuDefinitionList Elements; + +public: + MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items) + : OptStatements(std::move(OptStmts)), Elements(std::move(Items)) {} + raw_ostream &log(raw_ostream &) const override; +}; + // STRINGTABLE resource. Contains a list of strings, each having its unique ID. // // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx |