summaryrefslogtreecommitdiff
path: root/tools/llvm-rc
diff options
context:
space:
mode:
authorMarek Sokolowski <mnbvmar@gmail.com>2017-08-29 16:49:59 +0000
committerMarek Sokolowski <mnbvmar@gmail.com>2017-08-29 16:49:59 +0000
commit7ca5fcca7f11b917b1af2c1ea7462a81436eae6e (patch)
treebac234e4651dd94d2be8025c3269d6fd7775c0f5 /tools/llvm-rc
parente99d47fe84f61cf9ad5826522ae9315f1009c4d6 (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.cpp104
-rw-r--r--tools/llvm-rc/ResourceScriptParser.h7
-rw-r--r--tools/llvm-rc/ResourceScriptStmt.cpp41
-rw-r--r--tools/llvm-rc/ResourceScriptStmt.h89
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