Index: llvm/trunk/tools/llvm-rc/ResourceScriptParser.h =================================================================== --- llvm/trunk/tools/llvm-rc/ResourceScriptParser.h +++ llvm/trunk/tools/llvm-rc/ResourceScriptParser.h @@ -106,10 +106,11 @@ // Read an unknown number of flags preceded by commas. Each correct flag // has an entry in FlagDesc array of length NumFlags. In case i-th - // flag (0-based) has been read, the i-th bit of the result is set. + // flag (0-based) has been read, the result is OR-ed with FlagValues[i]. // As long as parser has a comma to read, it expects to be fed with // a correct flag afterwards. - Expected parseFlags(ArrayRef FlagDesc); + Expected parseFlags(ArrayRef FlagDesc, + ArrayRef FlagValues); // Reads a set of optional statements. These can change the behavior of // a number of resource types (e.g. STRINGTABLE, MENU or DIALOG) if provided Index: llvm/trunk/tools/llvm-rc/ResourceScriptParser.cpp =================================================================== --- llvm/trunk/tools/llvm-rc/ResourceScriptParser.cpp +++ llvm/trunk/tools/llvm-rc/ResourceScriptParser.cpp @@ -293,9 +293,10 @@ return std::move(Result); } -Expected RCParser::parseFlags(ArrayRef FlagDesc) { - assert(FlagDesc.size() <= 32 && "More than 32 flags won't fit in result."); +Expected RCParser::parseFlags(ArrayRef FlagDesc, + ArrayRef FlagValues) { assert(!FlagDesc.empty()); + assert(FlagDesc.size() == FlagValues.size()); uint32_t Result = 0; while (isNextTokenKind(Kind::Comma)) { @@ -307,7 +308,7 @@ if (!FlagResult->equals_lower(FlagDesc[FlagId])) continue; - Result |= (1U << FlagId); + Result |= FlagValues[FlagId]; FoundFlag = true; break; } @@ -372,8 +373,10 @@ ASSIGN_OR_RETURN(EventResult, readIntOrString()); RETURN_IF_ERROR(consumeType(Kind::Comma)); ASSIGN_OR_RETURN(IDResult, readInt()); - ASSIGN_OR_RETURN(FlagsResult, - parseFlags(AcceleratorsResource::Accelerator::OptionsStr)); + ASSIGN_OR_RETURN( + FlagsResult, + parseFlags(AcceleratorsResource::Accelerator::OptionsStr, + AcceleratorsResource::Accelerator::OptionsFlags)); Accels->addAccelerator(*EventResult, *IDResult, *FlagsResult); } @@ -536,7 +539,8 @@ MenuResult = *IntResult; } - ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr)); + ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr, + MenuDefinition::OptionsFlags)); if (IsPopup) { // If POPUP, read submenu items recursively. Index: llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h =================================================================== --- llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h +++ llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h @@ -160,6 +160,14 @@ } }; +class OptStatementsRCResource : public RCResource { +public: + std::unique_ptr OptStatements; + + OptStatementsRCResource(OptionalStmtList &&Stmts) + : OptStatements(llvm::make_unique(std::move(Stmts))) {} +}; + // LANGUAGE statement. It can occur both as a top-level statement (in such // a situation, it changes the default language until the end of the file) // and as an optional resource statement (then it changes the language @@ -183,37 +191,41 @@ // ACCELERATORS resource. Defines a named table of accelerators for the app. // // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx -class AcceleratorsResource : public RCResource { +class AcceleratorsResource : public OptStatementsRCResource { public: class Accelerator { public: IntOrString Event; uint32_t Id; - uint8_t Flags; + uint16_t Flags; enum Options { - ASCII = (1 << 0), - VIRTKEY = (1 << 1), - NOINVERT = (1 << 2), - ALT = (1 << 3), - SHIFT = (1 << 4), - CONTROL = (1 << 5) + // This is actually 0x0000 (accelerator is assumed to be ASCII if it's + // not VIRTKEY). However, rc.exe behavior is different in situations + // "only ASCII defined" and "neither ASCII nor VIRTKEY defined". + // Therefore, we include ASCII as another flag. This must be zeroed + // when serialized. + ASCII = 0x8000, + VIRTKEY = 0x0001, + NOINVERT = 0x0002, + ALT = 0x0010, + SHIFT = 0x0004, + CONTROL = 0x0008 }; static constexpr size_t NumFlags = 6; static StringRef OptionsStr[NumFlags]; + static uint32_t OptionsFlags[NumFlags]; }; - AcceleratorsResource(OptionalStmtList &&OptStmts) - : OptStatements(std::move(OptStmts)) {} - void addAccelerator(IntOrString Event, uint32_t Id, uint8_t Flags) { + using OptStatementsRCResource::OptStatementsRCResource; + void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) { Accelerators.push_back(Accelerator{Event, Id, Flags}); } raw_ostream &log(raw_ostream &) const override; private: std::vector Accelerators; - OptionalStmtList OptStatements; }; // CURSOR resource. Represents a single cursor (".cur") file. @@ -272,17 +284,18 @@ class MenuDefinition { public: enum Options { - CHECKED = (1 << 0), - GRAYED = (1 << 1), - HELP = (1 << 2), - INACTIVE = (1 << 3), - MENUBARBREAK = (1 << 4), - MENUBREAK = (1 << 5) + CHECKED = 0x0008, + GRAYED = 0x0001, + HELP = 0x4000, + INACTIVE = 0x0002, + MENUBARBREAK = 0x0020, + MENUBREAK = 0x0040 }; static constexpr size_t NumFlags = 6; static StringRef OptionsStr[NumFlags]; - static raw_ostream &logFlags(raw_ostream &, uint8_t Flags); + static uint32_t OptionsFlags[NumFlags]; + static raw_ostream &logFlags(raw_ostream &, uint16_t Flags); virtual raw_ostream &log(raw_ostream &OS) const { return OS << "Base menu definition\n"; } @@ -314,10 +327,10 @@ class MenuItem : public MenuDefinition { StringRef Name; uint32_t Id; - uint8_t Flags; + uint16_t Flags; public: - MenuItem(StringRef Caption, uint32_t ItemId, uint8_t ItemFlags) + MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags) : Name(Caption), Id(ItemId), Flags(ItemFlags) {} raw_ostream &log(raw_ostream &) const override; }; @@ -327,37 +340,35 @@ // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx class PopupItem : public MenuDefinition { StringRef Name; - uint8_t Flags; + uint16_t Flags; MenuDefinitionList SubItems; public: - PopupItem(StringRef Caption, uint8_t ItemFlags, + PopupItem(StringRef Caption, uint16_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; +class MenuResource : public OptStatementsRCResource { MenuDefinitionList Elements; public: MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items) - : OptStatements(std::move(OptStmts)), Elements(std::move(Items)) {} + : OptStatementsRCResource(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 -class StringTableResource : public RCResource { - OptionalStmtList OptStatements; +class StringTableResource : public OptStatementsRCResource { std::vector> Table; public: - StringTableResource(OptionalStmtList &&OptStmts) - : OptStatements(std::move(OptStmts)) {} + using OptStatementsRCResource::OptStatementsRCResource; void addString(uint32_t ID, StringRef String) { Table.emplace_back(ID, String); } @@ -395,9 +406,8 @@ // Single dialog definition. We don't create distinct classes for DIALOG and // DIALOGEX because of their being too similar to each other. We only have a // flag determining the type of the dialog box. -class DialogResource : public RCResource { +class DialogResource : public OptStatementsRCResource { uint32_t X, Y, Width, Height, HelpID; - OptionalStmtList OptStatements; std::vector Controls; bool IsExtended; @@ -405,8 +415,9 @@ DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth, uint32_t DlgHeight, uint32_t DlgHelpID, OptionalStmtList &&OptStmts, bool IsDialogEx) - : X(PosX), Y(PosY), Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID), - OptStatements(std::move(OptStmts)), IsExtended(IsDialogEx) {} + : OptStatementsRCResource(std::move(OptStmts)), X(PosX), Y(PosY), + Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID), + IsExtended(IsDialogEx) {} void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); } Index: llvm/trunk/tools/llvm-rc/ResourceScriptStmt.cpp =================================================================== --- llvm/trunk/tools/llvm-rc/ResourceScriptStmt.cpp +++ llvm/trunk/tools/llvm-rc/ResourceScriptStmt.cpp @@ -40,13 +40,17 @@ [AcceleratorsResource::Accelerator::NumFlags] = { "ASCII", "VIRTKEY", "NOINVERT", "ALT", "SHIFT", "CONTROL"}; +uint32_t AcceleratorsResource::Accelerator::OptionsFlags + [AcceleratorsResource::Accelerator::NumFlags] = {ASCII, VIRTKEY, NOINVERT, + ALT, SHIFT, CONTROL}; + raw_ostream &AcceleratorsResource::log(raw_ostream &OS) const { OS << "Accelerators (" << ResName << "): \n"; - OptStatements.log(OS); + OptStatements->log(OS); for (const auto &Acc : Accelerators) { OS << " Accelerator: " << Acc.Event << " " << Acc.Id; for (size_t i = 0; i < Accelerator::NumFlags; ++i) - if (Acc.Flags & (1U << i)) + if (Acc.Flags & Accelerator::OptionsFlags[i]) OS << " " << Accelerator::OptionsStr[i]; OS << "\n"; } @@ -68,9 +72,12 @@ StringRef MenuDefinition::OptionsStr[MenuDefinition::NumFlags] = { "CHECKED", "GRAYED", "HELP", "INACTIVE", "MENUBARBREAK", "MENUBREAK"}; -raw_ostream &MenuDefinition::logFlags(raw_ostream &OS, uint8_t Flags) { +uint32_t MenuDefinition::OptionsFlags[MenuDefinition::NumFlags] = { + CHECKED, GRAYED, HELP, INACTIVE, MENUBARBREAK, MENUBREAK}; + +raw_ostream &MenuDefinition::logFlags(raw_ostream &OS, uint16_t Flags) { for (size_t i = 0; i < NumFlags; ++i) - if (Flags & (1U << i)) + if (Flags & OptionsFlags[i]) OS << " " << OptionsStr[i]; return OS; } @@ -101,13 +108,13 @@ raw_ostream &MenuResource::log(raw_ostream &OS) const { OS << "Menu (" << ResName << "):\n"; - OptStatements.log(OS); + OptStatements->log(OS); return Elements.log(OS); } raw_ostream &StringTableResource::log(raw_ostream &OS) const { OS << "StringTable:\n"; - OptStatements.log(OS); + OptStatements->log(OS); for (const auto &String : Table) OS << " " << String.first << " => " << String.second << "\n"; return OS; @@ -136,7 +143,7 @@ OS << "Dialog" << (IsExtended ? "Ex" : "") << " (" << ResName << "): loc: (" << X << ", " << Y << "), size: [" << Width << ", " << Height << "], help ID: " << HelpID << "\n"; - OptStatements.log(OS); + OptStatements->log(OS); for (auto &Ctl : Controls) Ctl.log(OS); return OS;