diff options
author | Marek Sokolowski <mnbvmar@gmail.com> | 2017-08-29 16:49:59 +0000 |
---|---|---|
committer | Marek Sokolowski <mnbvmar@gmail.com> | 2017-08-29 16:49:59 +0000 |
commit | 7ca5fcca7f11b917b1af2c1ea7462a81436eae6e (patch) | |
tree | bac234e4651dd94d2be8025c3269d6fd7775c0f5 /tools/llvm-rc | |
parent | e99d47fe84f61cf9ad5826522ae9315f1009c4d6 (diff) |
[llvm-rc] Add DIALOG(EX) parsing ability (parser, pt 5/8).
This extends the set of resources parsed by llvm-rc by DIALOG and
DIALOGEX.
Additionally, three optional resource statements specific to these two
resources are added: CAPTION, FONT, and STYLE.
Thanks for Nico Weber for his original work in this area.
Differential Revision: https://reviews.llvm.org/D36905
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@312009 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvm-rc')
-rw-r--r-- | tools/llvm-rc/ResourceScriptParser.cpp | 104 | ||||
-rw-r--r-- | tools/llvm-rc/ResourceScriptParser.h | 7 | ||||
-rw-r--r-- | tools/llvm-rc/ResourceScriptStmt.cpp | 41 | ||||
-rw-r--r-- | tools/llvm-rc/ResourceScriptStmt.h | 89 |
4 files changed, 235 insertions, 6 deletions
diff --git a/tools/llvm-rc/ResourceScriptParser.cpp b/tools/llvm-rc/ResourceScriptParser.cpp index 5cc171c49af..499d0af83ad 100644 --- a/tools/llvm-rc/ResourceScriptParser.cpp +++ b/tools/llvm-rc/ResourceScriptParser.cpp @@ -67,6 +67,10 @@ RCParser::ParseType RCParser::parseSingleResource() { Result = parseAcceleratorsResource(); else if (TypeToken->equalsLower("CURSOR")) Result = parseCursorResource(); + else if (TypeToken->equalsLower("DIALOG")) + Result = parseDialogResource(false); + else if (TypeToken->equalsLower("DIALOGEX")) + Result = parseDialogResource(true); else if (TypeToken->equalsLower("ICON")) Result = parseIconResource(); else if (TypeToken->equalsLower("HTML")) @@ -235,17 +239,26 @@ Expected<OptionalStmtList> RCParser::parseOptionalStatements(bool IsExtended) { } Expected<std::unique_ptr<OptionalStmt>> -RCParser::parseSingleOptionalStatement(bool) { +RCParser::parseSingleOptionalStatement(bool IsExtended) { ASSIGN_OR_RETURN(TypeToken, readIdentifier()); if (TypeToken->equals_lower("CHARACTERISTICS")) return parseCharacteristicsStmt(); - else if (TypeToken->equals_lower("LANGUAGE")) + if (TypeToken->equals_lower("LANGUAGE")) return parseLanguageStmt(); - else if (TypeToken->equals_lower("VERSION")) + if (TypeToken->equals_lower("VERSION")) return parseVersionStmt(); - else - return getExpectedError("optional statement type, BEGIN or '{'", - /* IsAlreadyRead = */ true); + + if (IsExtended) { + if (TypeToken->equals_lower("CAPTION")) + return parseCaptionStmt(); + if (TypeToken->equals_lower("FONT")) + return parseFontStmt(); + if (TypeToken->equals_lower("STYLE")) + return parseStyleStmt(); + } + + return getExpectedError("optional statement type, BEGIN or '{'", + /* IsAlreadyRead = */ true); } RCParser::ParseType RCParser::parseLanguageResource() { @@ -277,6 +290,68 @@ RCParser::ParseType RCParser::parseCursorResource() { return make_unique<CursorResource>(*Arg); } +RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) { + // Dialog resources have the following format of the arguments: + // DIALOG: x, y, width, height [opt stmts...] {controls...} + // DIALOGEX: x, y, width, height [, helpID] [opt stmts...] {controls...} + // These are very similar, so we parse them together. + ASSIGN_OR_RETURN(LocResult, readIntsWithCommas(4, 4)); + + uint32_t HelpID = 0; // When HelpID is unset, it's assumed to be 0. + if (IsExtended && consumeOptionalType(Kind::Comma)) { + ASSIGN_OR_RETURN(HelpIDResult, readInt()); + HelpID = *HelpIDResult; + } + + ASSIGN_OR_RETURN(OptStatements, + parseOptionalStatements(/*UseExtendedStmts = */ true)); + + assert(isNextTokenKind(Kind::BlockBegin) && + "parseOptionalStatements, when successful, halts on BlockBegin."); + consume(); + + auto Dialog = make_unique<DialogResource>( + (*LocResult)[0], (*LocResult)[1], (*LocResult)[2], (*LocResult)[3], + HelpID, std::move(*OptStatements), IsExtended); + + while (!consumeOptionalType(Kind::BlockEnd)) { + ASSIGN_OR_RETURN(ControlDefResult, parseControl()); + Dialog->addControl(std::move(*ControlDefResult)); + } + + return std::move(Dialog); +} + +Expected<Control> RCParser::parseControl() { + // Each control definition (except CONTROL) follows one of the schemes below + // depending on the control class: + // [class] text, id, x, y, width, height [, style] [, exstyle] [, helpID] + // [class] id, x, y, width, height [, style] [, exstyle] [, helpID] + // Note that control ids must be integers. + ASSIGN_OR_RETURN(ClassResult, readIdentifier()); + StringRef ClassUpper = ClassResult->upper(); + if (Control::SupportedCtls.find(ClassUpper) == Control::SupportedCtls.end()) + return getExpectedError("control type, END or '}'", true); + + // Read caption if necessary. + StringRef Caption; + if (Control::CtlsWithTitle.find(ClassUpper) != Control::CtlsWithTitle.end()) { + ASSIGN_OR_RETURN(CaptionResult, readString()); + RETURN_IF_ERROR(consumeType(Kind::Comma)); + Caption = *CaptionResult; + } + + ASSIGN_OR_RETURN(Args, readIntsWithCommas(5, 8)); + + auto TakeOptArg = [&Args](size_t Id) -> Optional<uint32_t> { + return Args->size() > Id ? (*Args)[Id] : Optional<uint32_t>(); + }; + + return Control(*ClassResult, Caption, (*Args)[0], (*Args)[1], (*Args)[2], + (*Args)[3], (*Args)[4], TakeOptArg(5), TakeOptArg(6), + TakeOptArg(7)); +} + RCParser::ParseType RCParser::parseIconResource() { ASSIGN_OR_RETURN(Arg, readString()); return make_unique<IconResource>(*Arg); @@ -386,6 +461,23 @@ RCParser::ParseOptionType RCParser::parseVersionStmt() { return make_unique<VersionStmt>(*Arg); } +RCParser::ParseOptionType RCParser::parseCaptionStmt() { + ASSIGN_OR_RETURN(Arg, readString()); + return make_unique<CaptionStmt>(*Arg); +} + +RCParser::ParseOptionType RCParser::parseFontStmt() { + ASSIGN_OR_RETURN(SizeResult, readInt()); + RETURN_IF_ERROR(consumeType(Kind::Comma)); + ASSIGN_OR_RETURN(NameResult, readString()); + return make_unique<FontStmt>(*SizeResult, *NameResult); +} + +RCParser::ParseOptionType RCParser::parseStyleStmt() { + ASSIGN_OR_RETURN(Arg, readInt()); + return make_unique<StyleStmt>(*Arg); +} + Error RCParser::getExpectedError(const Twine Message, bool IsAlreadyRead) { return make_error<ParserError>( Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End); diff --git a/tools/llvm-rc/ResourceScriptParser.h b/tools/llvm-rc/ResourceScriptParser.h index 3fd1c27d928..bce2e0b544e 100644 --- a/tools/llvm-rc/ResourceScriptParser.h +++ b/tools/llvm-rc/ResourceScriptParser.h @@ -128,11 +128,15 @@ private: ParseType parseLanguageResource(); ParseType parseAcceleratorsResource(); ParseType parseCursorResource(); + ParseType parseDialogResource(bool IsExtended); ParseType parseIconResource(); ParseType parseHTMLResource(); ParseType parseMenuResource(); ParseType parseStringTableResource(); + // Helper DIALOG parser - a single control. + Expected<Control> parseControl(); + // Helper MENU parser. Expected<MenuDefinitionList> parseMenuItemsList(); @@ -140,6 +144,9 @@ private: ParseOptionType parseLanguageStmt(); ParseOptionType parseCharacteristicsStmt(); ParseOptionType parseVersionStmt(); + ParseOptionType parseCaptionStmt(); + ParseOptionType parseFontStmt(); + ParseOptionType parseStyleStmt(); // Raises an error. If IsAlreadyRead = false (default), this complains about // the token that couldn't be parsed. If the flag is on, this complains about diff --git a/tools/llvm-rc/ResourceScriptStmt.cpp b/tools/llvm-rc/ResourceScriptStmt.cpp index 9f61ce451de..cfbd2f8f7a3 100644 --- a/tools/llvm-rc/ResourceScriptStmt.cpp +++ b/tools/llvm-rc/ResourceScriptStmt.cpp @@ -113,6 +113,35 @@ raw_ostream &StringTableResource::log(raw_ostream &OS) const { return OS; } +const StringSet<> Control::SupportedCtls = { + "LTEXT", "RTEXT", "CTEXT", "PUSHBUTTON", "DEFPUSHBUTTON", "EDITTEXT"}; + +const StringSet<> Control::CtlsWithTitle = {"LTEXT", "RTEXT", "CTEXT", + "PUSHBUTTON", "DEFPUSHBUTTON"}; + +raw_ostream &Control::log(raw_ostream &OS) const { + OS << " Control (" << ID << "): " << Type << ", title: " << Title + << ", loc: (" << X << ", " << Y << "), size: [" << Width << ", " << Height + << "]"; + if (Style) + OS << ", style: " << *Style; + if (ExtStyle) + OS << ", ext. style: " << *ExtStyle; + if (HelpID) + OS << ", help ID: " << *HelpID; + return OS << "\n"; +} + +raw_ostream &DialogResource::log(raw_ostream &OS) const { + OS << "Dialog" << (IsExtended ? "Ex" : "") << " (" << ResName << "): loc: (" + << X << ", " << Y << "), size: [" << Width << ", " << Height + << "], help ID: " << HelpID << "\n"; + OptStatements.log(OS); + for (auto &Ctl : Controls) + Ctl.log(OS); + return OS; +} + raw_ostream &CharacteristicsStmt::log(raw_ostream &OS) const { return OS << "Characteristics: " << Value << "\n"; } @@ -121,5 +150,17 @@ raw_ostream &VersionStmt::log(raw_ostream &OS) const { return OS << "Version: " << Value << "\n"; } +raw_ostream &CaptionStmt::log(raw_ostream &OS) const { + return OS << "Caption: " << Value << "\n"; +} + +raw_ostream &FontStmt::log(raw_ostream &OS) const { + return OS << "Font: size = " << Size << ", face = " << Typeface << "\n"; +} + +raw_ostream &StyleStmt::log(raw_ostream &OS) const { + return OS << "Style: " << Value << "\n"; +} + } // namespace rc } // namespace llvm diff --git a/tools/llvm-rc/ResourceScriptStmt.h b/tools/llvm-rc/ResourceScriptStmt.h index 7166138a517..0812c263b98 100644 --- a/tools/llvm-rc/ResourceScriptStmt.h +++ b/tools/llvm-rc/ResourceScriptStmt.h @@ -16,6 +16,8 @@ #include "ResourceScriptToken.h" +#include "llvm/ADT/StringSet.h" + namespace llvm { namespace rc { @@ -268,6 +270,55 @@ public: raw_ostream &log(raw_ostream &) const override; }; +// -- DIALOG(EX) resource and its helper classes -- +// +// This resource describes dialog boxes and controls residing inside them. +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381003(v=vs.85).aspx +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx + +// Single control definition. +class Control { + StringRef Type, Title; + uint32_t ID, X, Y, Width, Height; + Optional<uint32_t> Style, ExtStyle, HelpID; + +public: + Control(StringRef CtlType, StringRef CtlTitle, uint32_t CtlID, uint32_t PosX, + uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight, + Optional<uint32_t> ItemStyle, Optional<uint32_t> ExtItemStyle, + Optional<uint32_t> CtlHelpID) + : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY), + Width(ItemWidth), Height(ItemHeight), Style(ItemStyle), + ExtStyle(ExtItemStyle), HelpID(CtlHelpID) {} + + static const StringSet<> SupportedCtls; + static const StringSet<> CtlsWithTitle; + + raw_ostream &log(raw_ostream &) const; +}; + +// 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 { + uint32_t X, Y, Width, Height, HelpID; + OptionalStmtList OptStatements; + std::vector<Control> Controls; + bool IsExtended; + +public: + 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) {} + + void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); } + + raw_ostream &log(raw_ostream &) const override; +}; + // CHARACTERISTICS optional statement. // // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx @@ -290,6 +341,44 @@ public: raw_ostream &log(raw_ostream &) const override; }; +// CAPTION optional statement. +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx +class CaptionStmt : public OptionalStmt { + StringRef Value; + +public: + CaptionStmt(StringRef Caption) : Value(Caption) {} + raw_ostream &log(raw_ostream &) const override; +}; + +// FONT optional statement. +// Note that the documentation is inaccurate: it expects five arguments to be +// given, however the example provides only two. In fact, the original tool +// expects two arguments - point size and name of the typeface. +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381013(v=vs.85).aspx +class FontStmt : public OptionalStmt { + uint32_t Size; + StringRef Typeface; + +public: + FontStmt(uint32_t FontSize, StringRef FontName) + : Size(FontSize), Typeface(FontName) {} + raw_ostream &log(raw_ostream &) const override; +}; + +// STYLE optional statement. +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx +class StyleStmt : public OptionalStmt { + uint32_t Value; + +public: + StyleStmt(uint32_t Style) : Value(Style) {} + raw_ostream &log(raw_ostream &) const override; +}; + } // namespace rc } // namespace llvm |