aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/tools/llvm-rc
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:45:01 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:01 +0300
commit2d37894b1b037cf24231090eda8589bbb44fb6fc (patch)
treebe835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/llvm12/tools/llvm-rc
parent718c552901d703c502ccbefdfc3c9028d608b947 (diff)
downloadydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/tools/llvm-rc')
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/Opts.td66
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp3098
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h434
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp222
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h68
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp1708
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h384
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp588
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h1900
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp734
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h162
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def78
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h122
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp406
-rw-r--r--contrib/libs/llvm12/tools/llvm-rc/ya.make52
15 files changed, 5011 insertions, 5011 deletions
diff --git a/contrib/libs/llvm12/tools/llvm-rc/Opts.td b/contrib/libs/llvm12/tools/llvm-rc/Opts.td
index 27b4f182a2..613f0a0db3 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/Opts.td
+++ b/contrib/libs/llvm12/tools/llvm-rc/Opts.td
@@ -1,55 +1,55 @@
-include "llvm/Option/OptParser.td"
-
-// All the switches can be preceded by either '/' or '-'.
-// These options seem to be important for the tool
-// and should be implemented.
-
+include "llvm/Option/OptParser.td"
+
+// All the switches can be preceded by either '/' or '-'.
+// These options seem to be important for the tool
+// and should be implemented.
+
def fileout : JoinedOrSeparate<[ "/", "-" ], "FO">,
- HelpText<"Change the output file location.">;
-
+ HelpText<"Change the output file location.">;
+
def define : Separate<[ "/", "-" ], "D">,
- HelpText<"Define a symbol for the C preprocessor.">;
+ HelpText<"Define a symbol for the C preprocessor.">;
def undef : Separate<[ "/", "-" ], "U">,
- HelpText<"Undefine a symbol for the C preprocessor.">;
-
+ HelpText<"Undefine a symbol for the C preprocessor.">;
+
def lang_id : JoinedOrSeparate<[ "/", "-" ], "L">,
- HelpText<"Set the default language identifier.">;
+ HelpText<"Set the default language identifier.">;
def lang_name : Separate<[ "/", "-" ], "LN">,
- HelpText<"Set the default language name.">;
-
+ HelpText<"Set the default language name.">;
+
def includepath : Separate<[ "/", "-" ], "I">, HelpText<"Add an include path.">;
def noinclude : Flag<[ "/", "-" ], "X">, HelpText<"Ignore 'include' variable.">;
-
+
def add_null : Flag<[ "/", "-" ], "N">,
- HelpText<"Null-terminate all strings in the string table.">;
-
+ HelpText<"Null-terminate all strings in the string table.">;
+
def dupid_nowarn : Flag<[ "/", "-" ], "Y">,
- HelpText<"Suppress warnings on duplicate resource IDs.">;
-
+ HelpText<"Suppress warnings on duplicate resource IDs.">;
+
def verbose : Flag<[ "/", "-" ], "V">, HelpText<"Be verbose.">;
def help : Flag<[ "/", "-" ], "?">, HelpText<"Display this help and exit.">;
def h : Flag<[ "/", "-" ], "H">,
Alias<help>,
- HelpText<"Display this help and exit.">;
-
+ HelpText<"Display this help and exit.">;
+
def dry_run : Flag<[ "/", "-" ], "dry-run">,
- HelpText<"Don't compile the input; only try to parse it.">;
-
+ HelpText<"Don't compile the input; only try to parse it.">;
+
def codepage : JoinedOrSeparate<[ "/", "-" ], "C">,
- HelpText<"Set the codepage used for input strings.">;
-
-// Unused switches (at least for now). These will stay unimplemented
-// in an early stage of development and can be ignored. However, we need to
-// parse them in order to preserve the compatibility with the original tool.
-
+ HelpText<"Set the codepage used for input strings.">;
+
+// Unused switches (at least for now). These will stay unimplemented
+// in an early stage of development and can be ignored. However, we need to
+// parse them in order to preserve the compatibility with the original tool.
+
def nologo : Flag<[ "/", "-" ], "NOLOGO">;
def r : Flag<[ "/", "-" ], "R">;
def sl : Flag<[ "/", "-" ], "SL">;
-
-// (Codepages support.)
+
+// (Codepages support.)
def w : Flag<[ "/", "-" ], "W">;
-
-// (Support of MUI and similar.)
+
+// (Support of MUI and similar.)
def fm : Separate<[ "/", "-" ], "FM">;
def q : Separate<[ "/", "-" ], "Q">;
def g : Flag<[ "/", "-" ], "G">;
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp
index a7418ba2f1..553bb754ae 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.cpp
@@ -1,1519 +1,1519 @@
-//===-- ResourceFileWriter.cpp --------------------------------*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This implements the visitor serializing resources to a .res stream.
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceFileWriter.h"
-#include "llvm/Object/WindowsResource.h"
-#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/EndianStream.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-
-using namespace llvm::support;
-
-// Take an expression returning llvm::Error and forward the error if it exists.
-#define RETURN_IF_ERROR(Expr) \
- if (auto Err = (Expr)) \
- return Err;
-
-namespace llvm {
-namespace rc {
-
-// Class that employs RAII to save the current FileWriter object state
-// and revert to it as soon as we leave the scope. This is useful if resources
-// declare their own resource-local statements.
-class ContextKeeper {
- ResourceFileWriter *FileWriter;
- ResourceFileWriter::ObjectInfo SavedInfo;
-
-public:
- ContextKeeper(ResourceFileWriter *V)
- : FileWriter(V), SavedInfo(V->ObjectData) {}
- ~ContextKeeper() { FileWriter->ObjectData = SavedInfo; }
-};
-
-static Error createError(const Twine &Message,
- std::errc Type = std::errc::invalid_argument) {
- return make_error<StringError>(Message, std::make_error_code(Type));
-}
-
-static Error checkNumberFits(uint32_t Number, size_t MaxBits,
- const Twine &FieldName) {
- assert(1 <= MaxBits && MaxBits <= 32);
- if (!(Number >> MaxBits))
- return Error::success();
- return createError(FieldName + " (" + Twine(Number) + ") does not fit in " +
- Twine(MaxBits) + " bits.",
- std::errc::value_too_large);
-}
-
-template <typename FitType>
-static Error checkNumberFits(uint32_t Number, const Twine &FieldName) {
- return checkNumberFits(Number, sizeof(FitType) * 8, FieldName);
-}
-
-// A similar function for signed integers.
-template <typename FitType>
-static Error checkSignedNumberFits(uint32_t Number, const Twine &FieldName,
- bool CanBeNegative) {
- int32_t SignedNum = Number;
- if (SignedNum < std::numeric_limits<FitType>::min() ||
- SignedNum > std::numeric_limits<FitType>::max())
- return createError(FieldName + " (" + Twine(SignedNum) +
- ") does not fit in " + Twine(sizeof(FitType) * 8) +
- "-bit signed integer type.",
- std::errc::value_too_large);
-
- if (!CanBeNegative && SignedNum < 0)
- return createError(FieldName + " (" + Twine(SignedNum) +
- ") cannot be negative.");
-
- return Error::success();
-}
-
-static Error checkRCInt(RCInt Number, const Twine &FieldName) {
- if (Number.isLong())
- return Error::success();
- return checkNumberFits<uint16_t>(Number, FieldName);
-}
-
-static Error checkIntOrString(IntOrString Value, const Twine &FieldName) {
- if (!Value.isInt())
- return Error::success();
- return checkNumberFits<uint16_t>(Value.getInt(), FieldName);
-}
-
-static bool stripQuotes(StringRef &Str, bool &IsLongString) {
- if (!Str.contains('"'))
- return false;
-
- // Just take the contents of the string, checking if it's been marked long.
- IsLongString = Str.startswith_lower("L");
- if (IsLongString)
- Str = Str.drop_front();
-
- bool StripSuccess = Str.consume_front("\"") && Str.consume_back("\"");
- (void)StripSuccess;
- assert(StripSuccess && "Strings should be enclosed in quotes.");
- return true;
-}
-
-static UTF16 cp1252ToUnicode(unsigned char C) {
- static const UTF16 Map80[] = {
- 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
- 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
- 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
- 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178,
- };
- if (C >= 0x80 && C <= 0x9F)
- return Map80[C - 0x80];
- return C;
-}
-
-// Describes a way to handle '\0' characters when processing the string.
-// rc.exe tool sometimes behaves in a weird way in postprocessing.
-// If the string to be output is equivalent to a C-string (e.g. in MENU
-// titles), string is (predictably) truncated after first 0-byte.
-// When outputting a string table, the behavior is equivalent to appending
-// '\0\0' at the end of the string, and then stripping the string
-// before the first '\0\0' occurrence.
-// Finally, when handling strings in user-defined resources, 0-bytes
-// aren't stripped, nor do they terminate the string.
-
-enum class NullHandlingMethod {
- UserResource, // Don't terminate string on '\0'.
- CutAtNull, // Terminate string on '\0'.
- CutAtDoubleNull // Terminate string on '\0\0'; strip final '\0'.
-};
-
-// Parses an identifier or string and returns a processed version of it:
+//===-- ResourceFileWriter.cpp --------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This implements the visitor serializing resources to a .res stream.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceFileWriter.h"
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+
+using namespace llvm::support;
+
+// Take an expression returning llvm::Error and forward the error if it exists.
+#define RETURN_IF_ERROR(Expr) \
+ if (auto Err = (Expr)) \
+ return Err;
+
+namespace llvm {
+namespace rc {
+
+// Class that employs RAII to save the current FileWriter object state
+// and revert to it as soon as we leave the scope. This is useful if resources
+// declare their own resource-local statements.
+class ContextKeeper {
+ ResourceFileWriter *FileWriter;
+ ResourceFileWriter::ObjectInfo SavedInfo;
+
+public:
+ ContextKeeper(ResourceFileWriter *V)
+ : FileWriter(V), SavedInfo(V->ObjectData) {}
+ ~ContextKeeper() { FileWriter->ObjectData = SavedInfo; }
+};
+
+static Error createError(const Twine &Message,
+ std::errc Type = std::errc::invalid_argument) {
+ return make_error<StringError>(Message, std::make_error_code(Type));
+}
+
+static Error checkNumberFits(uint32_t Number, size_t MaxBits,
+ const Twine &FieldName) {
+ assert(1 <= MaxBits && MaxBits <= 32);
+ if (!(Number >> MaxBits))
+ return Error::success();
+ return createError(FieldName + " (" + Twine(Number) + ") does not fit in " +
+ Twine(MaxBits) + " bits.",
+ std::errc::value_too_large);
+}
+
+template <typename FitType>
+static Error checkNumberFits(uint32_t Number, const Twine &FieldName) {
+ return checkNumberFits(Number, sizeof(FitType) * 8, FieldName);
+}
+
+// A similar function for signed integers.
+template <typename FitType>
+static Error checkSignedNumberFits(uint32_t Number, const Twine &FieldName,
+ bool CanBeNegative) {
+ int32_t SignedNum = Number;
+ if (SignedNum < std::numeric_limits<FitType>::min() ||
+ SignedNum > std::numeric_limits<FitType>::max())
+ return createError(FieldName + " (" + Twine(SignedNum) +
+ ") does not fit in " + Twine(sizeof(FitType) * 8) +
+ "-bit signed integer type.",
+ std::errc::value_too_large);
+
+ if (!CanBeNegative && SignedNum < 0)
+ return createError(FieldName + " (" + Twine(SignedNum) +
+ ") cannot be negative.");
+
+ return Error::success();
+}
+
+static Error checkRCInt(RCInt Number, const Twine &FieldName) {
+ if (Number.isLong())
+ return Error::success();
+ return checkNumberFits<uint16_t>(Number, FieldName);
+}
+
+static Error checkIntOrString(IntOrString Value, const Twine &FieldName) {
+ if (!Value.isInt())
+ return Error::success();
+ return checkNumberFits<uint16_t>(Value.getInt(), FieldName);
+}
+
+static bool stripQuotes(StringRef &Str, bool &IsLongString) {
+ if (!Str.contains('"'))
+ return false;
+
+ // Just take the contents of the string, checking if it's been marked long.
+ IsLongString = Str.startswith_lower("L");
+ if (IsLongString)
+ Str = Str.drop_front();
+
+ bool StripSuccess = Str.consume_front("\"") && Str.consume_back("\"");
+ (void)StripSuccess;
+ assert(StripSuccess && "Strings should be enclosed in quotes.");
+ return true;
+}
+
+static UTF16 cp1252ToUnicode(unsigned char C) {
+ static const UTF16 Map80[] = {
+ 0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
+ 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
+ 0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
+ 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178,
+ };
+ if (C >= 0x80 && C <= 0x9F)
+ return Map80[C - 0x80];
+ return C;
+}
+
+// Describes a way to handle '\0' characters when processing the string.
+// rc.exe tool sometimes behaves in a weird way in postprocessing.
+// If the string to be output is equivalent to a C-string (e.g. in MENU
+// titles), string is (predictably) truncated after first 0-byte.
+// When outputting a string table, the behavior is equivalent to appending
+// '\0\0' at the end of the string, and then stripping the string
+// before the first '\0\0' occurrence.
+// Finally, when handling strings in user-defined resources, 0-bytes
+// aren't stripped, nor do they terminate the string.
+
+enum class NullHandlingMethod {
+ UserResource, // Don't terminate string on '\0'.
+ CutAtNull, // Terminate string on '\0'.
+ CutAtDoubleNull // Terminate string on '\0\0'; strip final '\0'.
+};
+
+// Parses an identifier or string and returns a processed version of it:
// * Strip the string boundary quotes.
// * Convert the input code page characters to UTF16.
-// * Squash "" to a single ".
-// * Replace the escape sequences with their processed version.
-// For identifiers, this is no-op.
-static Error processString(StringRef Str, NullHandlingMethod NullHandler,
- bool &IsLongString, SmallVectorImpl<UTF16> &Result,
- int CodePage) {
- bool IsString = stripQuotes(Str, IsLongString);
- SmallVector<UTF16, 128> Chars;
-
- // Convert the input bytes according to the chosen codepage.
- if (CodePage == CpUtf8) {
- convertUTF8ToUTF16String(Str, Chars);
- } else if (CodePage == CpWin1252) {
- for (char C : Str)
- Chars.push_back(cp1252ToUnicode((unsigned char)C));
- } else {
- // For other, unknown codepages, only allow plain ASCII input.
- for (char C : Str) {
- if ((unsigned char)C > 0x7F)
- return createError("Non-ASCII 8-bit codepoint (" + Twine(C) +
- ") can't be interpreted in the current codepage");
- Chars.push_back((unsigned char)C);
- }
- }
-
- if (!IsString) {
- // It's an identifier if it's not a string. Make all characters uppercase.
- for (UTF16 &Ch : Chars) {
- assert(Ch <= 0x7F && "We didn't allow identifiers to be non-ASCII");
- Ch = toupper(Ch);
- }
- Result.swap(Chars);
- return Error::success();
- }
- Result.reserve(Chars.size());
- size_t Pos = 0;
-
- auto AddRes = [&Result, NullHandler, IsLongString](UTF16 Char) -> Error {
- if (!IsLongString) {
- if (NullHandler == NullHandlingMethod::UserResource) {
- // Narrow strings in user-defined resources are *not* output in
- // UTF-16 format.
- if (Char > 0xFF)
- return createError("Non-8-bit codepoint (" + Twine(Char) +
- ") can't occur in a user-defined narrow string");
- }
- }
-
- Result.push_back(Char);
- return Error::success();
- };
- auto AddEscapedChar = [AddRes, IsLongString, CodePage](UTF16 Char) -> Error {
- if (!IsLongString) {
- // Escaped chars in narrow strings have to be interpreted according to
- // the chosen code page.
- if (Char > 0xFF)
- return createError("Non-8-bit escaped char (" + Twine(Char) +
- ") can't occur in narrow string");
- if (CodePage == CpUtf8) {
- if (Char >= 0x80)
- return createError("Unable to interpret single byte (" + Twine(Char) +
- ") as UTF-8");
- } else if (CodePage == CpWin1252) {
- Char = cp1252ToUnicode(Char);
- } else {
- // Unknown/unsupported codepage, only allow ASCII input.
- if (Char > 0x7F)
- return createError("Non-ASCII 8-bit codepoint (" + Twine(Char) +
- ") can't "
- "occur in a non-Unicode string");
- }
- }
-
- return AddRes(Char);
- };
-
- while (Pos < Chars.size()) {
- UTF16 CurChar = Chars[Pos];
- ++Pos;
-
- // Strip double "".
- if (CurChar == '"') {
- if (Pos == Chars.size() || Chars[Pos] != '"')
- return createError("Expected \"\"");
- ++Pos;
- RETURN_IF_ERROR(AddRes('"'));
- continue;
- }
-
- if (CurChar == '\\') {
- UTF16 TypeChar = Chars[Pos];
- ++Pos;
-
- if (TypeChar == 'x' || TypeChar == 'X') {
- // Read a hex number. Max number of characters to read differs between
- // narrow and wide strings.
- UTF16 ReadInt = 0;
- size_t RemainingChars = IsLongString ? 4 : 2;
- // We don't want to read non-ASCII hex digits. std:: functions past
- // 0xFF invoke UB.
- //
- // FIXME: actually, Microsoft version probably doesn't check this
- // condition and uses their Unicode version of 'isxdigit'. However,
- // there are some hex-digit Unicode character outside of ASCII, and
- // some of these are actually accepted by rc.exe, the notable example
- // being fullwidth forms (U+FF10..U+FF19 etc.) These can be written
- // instead of ASCII digits in \x... escape sequence and get accepted.
- // However, the resulting hexcodes seem totally unpredictable.
- // We think it's infeasible to try to reproduce this behavior, nor to
- // put effort in order to detect it.
- while (RemainingChars && Pos < Chars.size() && Chars[Pos] < 0x80) {
- if (!isxdigit(Chars[Pos]))
- break;
- char Digit = tolower(Chars[Pos]);
- ++Pos;
-
- ReadInt <<= 4;
- if (isdigit(Digit))
- ReadInt |= Digit - '0';
- else
- ReadInt |= Digit - 'a' + 10;
-
- --RemainingChars;
- }
-
- RETURN_IF_ERROR(AddEscapedChar(ReadInt));
- continue;
- }
-
- if (TypeChar >= '0' && TypeChar < '8') {
- // Read an octal number. Note that we've already read the first digit.
- UTF16 ReadInt = TypeChar - '0';
- size_t RemainingChars = IsLongString ? 6 : 2;
-
- while (RemainingChars && Pos < Chars.size() && Chars[Pos] >= '0' &&
- Chars[Pos] < '8') {
- ReadInt <<= 3;
- ReadInt |= Chars[Pos] - '0';
- --RemainingChars;
- ++Pos;
- }
-
- RETURN_IF_ERROR(AddEscapedChar(ReadInt));
-
- continue;
- }
-
- switch (TypeChar) {
- case 'A':
- case 'a':
- // Windows '\a' translates into '\b' (Backspace).
- RETURN_IF_ERROR(AddRes('\b'));
- break;
-
- case 'n': // Somehow, RC doesn't recognize '\N' and '\R'.
- RETURN_IF_ERROR(AddRes('\n'));
- break;
-
- case 'r':
- RETURN_IF_ERROR(AddRes('\r'));
- break;
-
- case 'T':
- case 't':
- RETURN_IF_ERROR(AddRes('\t'));
- break;
-
- case '\\':
- RETURN_IF_ERROR(AddRes('\\'));
- break;
-
- case '"':
- // RC accepts \" only if another " comes afterwards; then, \"" means
- // a single ".
- if (Pos == Chars.size() || Chars[Pos] != '"')
- return createError("Expected \\\"\"");
- ++Pos;
- RETURN_IF_ERROR(AddRes('"'));
- break;
-
- default:
- // If TypeChar means nothing, \ is should be output to stdout with
- // following char. However, rc.exe consumes these characters when
- // dealing with wide strings.
- if (!IsLongString) {
- RETURN_IF_ERROR(AddRes('\\'));
- RETURN_IF_ERROR(AddRes(TypeChar));
- }
- break;
- }
-
- continue;
- }
-
- // If nothing interesting happens, just output the character.
- RETURN_IF_ERROR(AddRes(CurChar));
- }
-
- switch (NullHandler) {
- case NullHandlingMethod::CutAtNull:
- for (size_t Pos = 0; Pos < Result.size(); ++Pos)
- if (Result[Pos] == '\0')
- Result.resize(Pos);
- break;
-
- case NullHandlingMethod::CutAtDoubleNull:
- for (size_t Pos = 0; Pos + 1 < Result.size(); ++Pos)
- if (Result[Pos] == '\0' && Result[Pos + 1] == '\0')
- Result.resize(Pos);
- if (Result.size() > 0 && Result.back() == '\0')
- Result.pop_back();
- break;
-
- case NullHandlingMethod::UserResource:
- break;
- }
-
- return Error::success();
-}
-
-uint64_t ResourceFileWriter::writeObject(const ArrayRef<uint8_t> Data) {
- uint64_t Result = tell();
- FS->write((const char *)Data.begin(), Data.size());
- return Result;
-}
-
-Error ResourceFileWriter::writeCString(StringRef Str, bool WriteTerminator) {
- SmallVector<UTF16, 128> ProcessedString;
- bool IsLongString;
- RETURN_IF_ERROR(processString(Str, NullHandlingMethod::CutAtNull,
- IsLongString, ProcessedString,
- Params.CodePage));
- for (auto Ch : ProcessedString)
- writeInt<uint16_t>(Ch);
- if (WriteTerminator)
- writeInt<uint16_t>(0);
- return Error::success();
-}
-
-Error ResourceFileWriter::writeIdentifier(const IntOrString &Ident) {
- return writeIntOrString(Ident);
-}
-
-Error ResourceFileWriter::writeIntOrString(const IntOrString &Value) {
- if (!Value.isInt())
- return writeCString(Value.getString());
-
- writeInt<uint16_t>(0xFFFF);
- writeInt<uint16_t>(Value.getInt());
- return Error::success();
-}
-
-void ResourceFileWriter::writeRCInt(RCInt Value) {
- if (Value.isLong())
- writeInt<uint32_t>(Value);
- else
- writeInt<uint16_t>(Value);
-}
-
-Error ResourceFileWriter::appendFile(StringRef Filename) {
- bool IsLong;
- stripQuotes(Filename, IsLong);
-
- auto File = loadFile(Filename);
- if (!File)
- return File.takeError();
-
- *FS << (*File)->getBuffer();
- return Error::success();
-}
-
-void ResourceFileWriter::padStream(uint64_t Length) {
- assert(Length > 0);
- uint64_t Location = tell();
- Location %= Length;
- uint64_t Pad = (Length - Location) % Length;
- for (uint64_t i = 0; i < Pad; ++i)
- writeInt<uint8_t>(0);
-}
-
-Error ResourceFileWriter::handleError(Error Err, const RCResource *Res) {
- if (Err)
- return joinErrors(createError("Error in " + Res->getResourceTypeName() +
- " statement (ID " + Twine(Res->ResName) +
- "): "),
- std::move(Err));
- return Error::success();
-}
-
-Error ResourceFileWriter::visitNullResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeNullBody);
-}
-
-Error ResourceFileWriter::visitAcceleratorsResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeAcceleratorsBody);
-}
-
-Error ResourceFileWriter::visitBitmapResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeBitmapBody);
-}
-
-Error ResourceFileWriter::visitCursorResource(const RCResource *Res) {
- return handleError(visitIconOrCursorResource(Res), Res);
-}
-
-Error ResourceFileWriter::visitDialogResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeDialogBody);
-}
-
-Error ResourceFileWriter::visitIconResource(const RCResource *Res) {
- return handleError(visitIconOrCursorResource(Res), Res);
-}
-
-Error ResourceFileWriter::visitCaptionStmt(const CaptionStmt *Stmt) {
- ObjectData.Caption = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitClassStmt(const ClassStmt *Stmt) {
- ObjectData.Class = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitHTMLResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeHTMLBody);
-}
-
-Error ResourceFileWriter::visitMenuResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeMenuBody);
-}
-
-Error ResourceFileWriter::visitStringTableResource(const RCResource *Base) {
- const auto *Res = cast<StringTableResource>(Base);
-
- ContextKeeper RAII(this);
- RETURN_IF_ERROR(Res->applyStmts(this));
-
- for (auto &String : Res->Table) {
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(String.first, "String ID"));
- uint16_t BundleID = String.first >> 4;
- StringTableInfo::BundleKey Key(BundleID, ObjectData.LanguageInfo);
- auto &BundleData = StringTableData.BundleData;
- auto Iter = BundleData.find(Key);
-
- if (Iter == BundleData.end()) {
- // Need to create a bundle.
- StringTableData.BundleList.push_back(Key);
- auto EmplaceResult = BundleData.emplace(
- Key, StringTableInfo::Bundle(ObjectData, Res->MemoryFlags));
- assert(EmplaceResult.second && "Could not create a bundle");
- Iter = EmplaceResult.first;
- }
-
- RETURN_IF_ERROR(
- insertStringIntoBundle(Iter->second, String.first, String.second));
- }
-
- return Error::success();
-}
-
-Error ResourceFileWriter::visitUserDefinedResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeUserDefinedBody);
-}
-
-Error ResourceFileWriter::visitVersionInfoResource(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeVersionInfoBody);
-}
-
-Error ResourceFileWriter::visitCharacteristicsStmt(
- const CharacteristicsStmt *Stmt) {
- ObjectData.Characteristics = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitExStyleStmt(const ExStyleStmt *Stmt) {
- ObjectData.ExStyle = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitFontStmt(const FontStmt *Stmt) {
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Size, "Font size"));
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Weight, "Font weight"));
- RETURN_IF_ERROR(checkNumberFits<uint8_t>(Stmt->Charset, "Font charset"));
- ObjectInfo::FontInfo Font{Stmt->Size, Stmt->Name, Stmt->Weight, Stmt->Italic,
- Stmt->Charset};
- ObjectData.Font.emplace(Font);
- return Error::success();
-}
-
-Error ResourceFileWriter::visitLanguageStmt(const LanguageResource *Stmt) {
- RETURN_IF_ERROR(checkNumberFits(Stmt->Lang, 10, "Primary language ID"));
- RETURN_IF_ERROR(checkNumberFits(Stmt->SubLang, 6, "Sublanguage ID"));
- ObjectData.LanguageInfo = Stmt->Lang | (Stmt->SubLang << 10);
- return Error::success();
-}
-
-Error ResourceFileWriter::visitStyleStmt(const StyleStmt *Stmt) {
- ObjectData.Style = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::visitVersionStmt(const VersionStmt *Stmt) {
- ObjectData.VersionInfo = Stmt->Value;
- return Error::success();
-}
-
-Error ResourceFileWriter::writeResource(
- const RCResource *Res,
- Error (ResourceFileWriter::*BodyWriter)(const RCResource *)) {
- // We don't know the sizes yet.
- object::WinResHeaderPrefix HeaderPrefix{ulittle32_t(0U), ulittle32_t(0U)};
- uint64_t HeaderLoc = writeObject(HeaderPrefix);
-
- auto ResType = Res->getResourceType();
- RETURN_IF_ERROR(checkIntOrString(ResType, "Resource type"));
- RETURN_IF_ERROR(checkIntOrString(Res->ResName, "Resource ID"));
- RETURN_IF_ERROR(handleError(writeIdentifier(ResType), Res));
- RETURN_IF_ERROR(handleError(writeIdentifier(Res->ResName), Res));
-
- // Apply the resource-local optional statements.
- ContextKeeper RAII(this);
- RETURN_IF_ERROR(handleError(Res->applyStmts(this), Res));
-
- padStream(sizeof(uint32_t));
- object::WinResHeaderSuffix HeaderSuffix{
- ulittle32_t(0), // DataVersion; seems to always be 0
- ulittle16_t(Res->MemoryFlags), ulittle16_t(ObjectData.LanguageInfo),
- ulittle32_t(ObjectData.VersionInfo),
- ulittle32_t(ObjectData.Characteristics)};
- writeObject(HeaderSuffix);
-
- uint64_t DataLoc = tell();
- RETURN_IF_ERROR(handleError((this->*BodyWriter)(Res), Res));
- // RETURN_IF_ERROR(handleError(dumpResource(Ctx)));
-
- // Update the sizes.
- HeaderPrefix.DataSize = tell() - DataLoc;
- HeaderPrefix.HeaderSize = DataLoc - HeaderLoc;
- writeObjectAt(HeaderPrefix, HeaderLoc);
- padStream(sizeof(uint32_t));
-
- return Error::success();
-}
-
-// --- NullResource helpers. --- //
-
-Error ResourceFileWriter::writeNullBody(const RCResource *) {
- return Error::success();
-}
-
-// --- AcceleratorsResource helpers. --- //
-
-Error ResourceFileWriter::writeSingleAccelerator(
- const AcceleratorsResource::Accelerator &Obj, bool IsLastItem) {
- using Accelerator = AcceleratorsResource::Accelerator;
- using Opt = Accelerator::Options;
-
- struct AccelTableEntry {
- ulittle16_t Flags;
- ulittle16_t ANSICode;
- ulittle16_t Id;
- uint16_t Padding;
- } Entry{ulittle16_t(0), ulittle16_t(0), ulittle16_t(0), 0};
-
- bool IsASCII = Obj.Flags & Opt::ASCII, IsVirtKey = Obj.Flags & Opt::VIRTKEY;
-
- // Remove ASCII flags (which doesn't occur in .res files).
- Entry.Flags = Obj.Flags & ~Opt::ASCII;
-
- if (IsLastItem)
- Entry.Flags |= 0x80;
-
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(Obj.Id, "ACCELERATORS entry ID"));
- Entry.Id = ulittle16_t(Obj.Id);
-
- auto createAccError = [&Obj](const char *Msg) {
- return createError("Accelerator ID " + Twine(Obj.Id) + ": " + Msg);
- };
-
- if (IsASCII && IsVirtKey)
- return createAccError("Accelerator can't be both ASCII and VIRTKEY");
-
- if (!IsVirtKey && (Obj.Flags & (Opt::ALT | Opt::SHIFT | Opt::CONTROL)))
- return createAccError("Can only apply ALT, SHIFT or CONTROL to VIRTKEY"
- " accelerators");
-
- if (Obj.Event.isInt()) {
- if (!IsASCII && !IsVirtKey)
- return createAccError(
- "Accelerator with a numeric event must be either ASCII"
- " or VIRTKEY");
-
- uint32_t EventVal = Obj.Event.getInt();
- RETURN_IF_ERROR(
- checkNumberFits<uint16_t>(EventVal, "Numeric event key ID"));
- Entry.ANSICode = ulittle16_t(EventVal);
- writeObject(Entry);
- return Error::success();
- }
-
- StringRef Str = Obj.Event.getString();
- bool IsWide;
- stripQuotes(Str, IsWide);
-
- if (Str.size() == 0 || Str.size() > 2)
- return createAccError(
- "Accelerator string events should have length 1 or 2");
-
- if (Str[0] == '^') {
- if (Str.size() == 1)
- return createAccError("No character following '^' in accelerator event");
- if (IsVirtKey)
- return createAccError(
- "VIRTKEY accelerator events can't be preceded by '^'");
-
- char Ch = Str[1];
- if (Ch >= 'a' && Ch <= 'z')
- Entry.ANSICode = ulittle16_t(Ch - 'a' + 1);
- else if (Ch >= 'A' && Ch <= 'Z')
- Entry.ANSICode = ulittle16_t(Ch - 'A' + 1);
- else
- return createAccError("Control character accelerator event should be"
- " alphabetic");
-
- writeObject(Entry);
- return Error::success();
- }
-
- if (Str.size() == 2)
- return createAccError("Event string should be one-character, possibly"
- " preceded by '^'");
-
- uint8_t EventCh = Str[0];
- // The original tool just warns in this situation. We chose to fail.
- if (IsVirtKey && !isalnum(EventCh))
- return createAccError("Non-alphanumeric characters cannot describe virtual"
- " keys");
- if (EventCh > 0x7F)
- return createAccError("Non-ASCII description of accelerator");
-
- if (IsVirtKey)
- EventCh = toupper(EventCh);
- Entry.ANSICode = ulittle16_t(EventCh);
- writeObject(Entry);
- return Error::success();
-}
-
-Error ResourceFileWriter::writeAcceleratorsBody(const RCResource *Base) {
- auto *Res = cast<AcceleratorsResource>(Base);
- size_t AcceleratorId = 0;
- for (auto &Acc : Res->Accelerators) {
- ++AcceleratorId;
- RETURN_IF_ERROR(
- writeSingleAccelerator(Acc, AcceleratorId == Res->Accelerators.size()));
- }
- return Error::success();
-}
-
-// --- BitmapResource helpers. --- //
-
-Error ResourceFileWriter::writeBitmapBody(const RCResource *Base) {
- StringRef Filename = cast<BitmapResource>(Base)->BitmapLoc;
- bool IsLong;
- stripQuotes(Filename, IsLong);
-
- auto File = loadFile(Filename);
- if (!File)
- return File.takeError();
-
- StringRef Buffer = (*File)->getBuffer();
-
- // Skip the 14 byte BITMAPFILEHEADER.
- constexpr size_t BITMAPFILEHEADER_size = 14;
- if (Buffer.size() < BITMAPFILEHEADER_size || Buffer[0] != 'B' ||
- Buffer[1] != 'M')
- return createError("Incorrect bitmap file.");
-
- *FS << Buffer.substr(BITMAPFILEHEADER_size);
- return Error::success();
-}
-
-// --- CursorResource and IconResource helpers. --- //
-
-// ICONRESDIR structure. Describes a single icon in resource group.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648016.aspx
-struct IconResDir {
- uint8_t Width;
- uint8_t Height;
- uint8_t ColorCount;
- uint8_t Reserved;
-};
-
-// CURSORDIR structure. Describes a single cursor in resource group.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648011(v=vs.85).aspx
-struct CursorDir {
- ulittle16_t Width;
- ulittle16_t Height;
-};
-
-// RESDIRENTRY structure, stripped from the last item. Stripping made
-// for compatibility with RESDIR.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026(v=vs.85).aspx
-struct ResourceDirEntryStart {
- union {
- CursorDir Cursor; // Used in CURSOR resources.
- IconResDir Icon; // Used in .ico and .cur files, and ICON resources.
- };
- ulittle16_t Planes; // HotspotX (.cur files but not CURSOR resource).
- ulittle16_t BitCount; // HotspotY (.cur files but not CURSOR resource).
- ulittle32_t Size;
- // ulittle32_t ImageOffset; // Offset to image data (ICONDIRENTRY only).
- // ulittle16_t IconID; // Resource icon ID (RESDIR only).
-};
-
-// BITMAPINFOHEADER structure. Describes basic information about the bitmap
-// being read.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
-struct BitmapInfoHeader {
- ulittle32_t Size;
- ulittle32_t Width;
- ulittle32_t Height;
- ulittle16_t Planes;
- ulittle16_t BitCount;
- ulittle32_t Compression;
- ulittle32_t SizeImage;
- ulittle32_t XPelsPerMeter;
- ulittle32_t YPelsPerMeter;
- ulittle32_t ClrUsed;
- ulittle32_t ClrImportant;
-};
-
-// Group icon directory header. Called ICONDIR in .ico/.cur files and
-// NEWHEADER in .res files.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648023(v=vs.85).aspx
-struct GroupIconDir {
- ulittle16_t Reserved; // Always 0.
- ulittle16_t ResType; // 1 for icons, 2 for cursors.
- ulittle16_t ResCount; // Number of items.
-};
-
-enum class IconCursorGroupType { Icon, Cursor };
-
-class SingleIconCursorResource : public RCResource {
-public:
- IconCursorGroupType Type;
- const ResourceDirEntryStart &Header;
- ArrayRef<uint8_t> Image;
-
- SingleIconCursorResource(IconCursorGroupType ResourceType,
- const ResourceDirEntryStart &HeaderEntry,
- ArrayRef<uint8_t> ImageData, uint16_t Flags)
- : RCResource(Flags), Type(ResourceType), Header(HeaderEntry),
- Image(ImageData) {}
-
- Twine getResourceTypeName() const override { return "Icon/cursor image"; }
- IntOrString getResourceType() const override {
- return Type == IconCursorGroupType::Icon ? RkSingleIcon : RkSingleCursor;
- }
- ResourceKind getKind() const override { return RkSingleCursorOrIconRes; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkSingleCursorOrIconRes;
- }
-};
-
-class IconCursorGroupResource : public RCResource {
-public:
- IconCursorGroupType Type;
- GroupIconDir Header;
- std::vector<ResourceDirEntryStart> ItemEntries;
-
- IconCursorGroupResource(IconCursorGroupType ResourceType,
- const GroupIconDir &HeaderData,
- std::vector<ResourceDirEntryStart> &&Entries)
- : Type(ResourceType), Header(HeaderData),
- ItemEntries(std::move(Entries)) {}
-
- Twine getResourceTypeName() const override { return "Icon/cursor group"; }
- IntOrString getResourceType() const override {
- return Type == IconCursorGroupType::Icon ? RkIconGroup : RkCursorGroup;
- }
- ResourceKind getKind() const override { return RkCursorOrIconGroupRes; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkCursorOrIconGroupRes;
- }
-};
-
-Error ResourceFileWriter::writeSingleIconOrCursorBody(const RCResource *Base) {
- auto *Res = cast<SingleIconCursorResource>(Base);
- if (Res->Type == IconCursorGroupType::Cursor) {
- // In case of cursors, two WORDS are appended to the beginning
- // of the resource: HotspotX (Planes in RESDIRENTRY),
- // and HotspotY (BitCount).
- //
- // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026.aspx
- // (Remarks section).
- writeObject(Res->Header.Planes);
- writeObject(Res->Header.BitCount);
- }
-
- writeObject(Res->Image);
- return Error::success();
-}
-
-Error ResourceFileWriter::writeIconOrCursorGroupBody(const RCResource *Base) {
- auto *Res = cast<IconCursorGroupResource>(Base);
- writeObject(Res->Header);
- for (auto Item : Res->ItemEntries) {
- writeObject(Item);
- writeInt(IconCursorID++);
- }
- return Error::success();
-}
-
-Error ResourceFileWriter::visitSingleIconOrCursor(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeSingleIconOrCursorBody);
-}
-
-Error ResourceFileWriter::visitIconOrCursorGroup(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeIconOrCursorGroupBody);
-}
-
-Error ResourceFileWriter::visitIconOrCursorResource(const RCResource *Base) {
- IconCursorGroupType Type;
- StringRef FileStr;
- IntOrString ResName = Base->ResName;
-
- if (auto *IconRes = dyn_cast<IconResource>(Base)) {
- FileStr = IconRes->IconLoc;
- Type = IconCursorGroupType::Icon;
- } else {
- auto *CursorRes = dyn_cast<CursorResource>(Base);
- FileStr = CursorRes->CursorLoc;
- Type = IconCursorGroupType::Cursor;
- }
-
- bool IsLong;
- stripQuotes(FileStr, IsLong);
- auto File = loadFile(FileStr);
-
- if (!File)
- return File.takeError();
-
- BinaryStreamReader Reader((*File)->getBuffer(), support::little);
-
- // Read the file headers.
- // - At the beginning, ICONDIR/NEWHEADER header.
- // - Then, a number of RESDIR headers follow. These contain offsets
- // to data.
- const GroupIconDir *Header;
-
- RETURN_IF_ERROR(Reader.readObject(Header));
- if (Header->Reserved != 0)
- return createError("Incorrect icon/cursor Reserved field; should be 0.");
- uint16_t NeededType = Type == IconCursorGroupType::Icon ? 1 : 2;
- if (Header->ResType != NeededType)
- return createError("Incorrect icon/cursor ResType field; should be " +
- Twine(NeededType) + ".");
-
- uint16_t NumItems = Header->ResCount;
-
- // Read single ico/cur headers.
- std::vector<ResourceDirEntryStart> ItemEntries;
- ItemEntries.reserve(NumItems);
- std::vector<uint32_t> ItemOffsets(NumItems);
- for (size_t ID = 0; ID < NumItems; ++ID) {
- const ResourceDirEntryStart *Object;
- RETURN_IF_ERROR(Reader.readObject(Object));
- ItemEntries.push_back(*Object);
- RETURN_IF_ERROR(Reader.readInteger(ItemOffsets[ID]));
- }
-
- // Now write each icon/cursors one by one. At first, all the contents
- // without ICO/CUR header. This is described by SingleIconCursorResource.
- for (size_t ID = 0; ID < NumItems; ++ID) {
- // Load the fragment of file.
- Reader.setOffset(ItemOffsets[ID]);
- ArrayRef<uint8_t> Image;
- RETURN_IF_ERROR(Reader.readArray(Image, ItemEntries[ID].Size));
- SingleIconCursorResource SingleRes(Type, ItemEntries[ID], Image,
- Base->MemoryFlags);
- SingleRes.setName(IconCursorID + ID);
- RETURN_IF_ERROR(visitSingleIconOrCursor(&SingleRes));
- }
-
- // Now, write all the headers concatenated into a separate resource.
- for (size_t ID = 0; ID < NumItems; ++ID) {
- // We need to rewrite the cursor headers, and fetch actual values
- // for Planes/BitCount.
- const auto &OldHeader = ItemEntries[ID];
- ResourceDirEntryStart NewHeader = OldHeader;
-
- if (Type == IconCursorGroupType::Cursor) {
- NewHeader.Cursor.Width = OldHeader.Icon.Width;
- // Each cursor in fact stores two bitmaps, one under another.
- // Height provided in cursor definition describes the height of the
- // cursor, whereas the value existing in resource definition describes
- // the height of the bitmap. Therefore, we need to double this height.
- NewHeader.Cursor.Height = OldHeader.Icon.Height * 2;
-
- // Two WORDs were written at the beginning of the resource (hotspot
- // location). This is reflected in Size field.
- NewHeader.Size += 2 * sizeof(uint16_t);
- }
-
- // Now, we actually need to read the bitmap header to find
- // the number of planes and the number of bits per pixel.
- Reader.setOffset(ItemOffsets[ID]);
- const BitmapInfoHeader *BMPHeader;
- RETURN_IF_ERROR(Reader.readObject(BMPHeader));
- if (BMPHeader->Size == sizeof(BitmapInfoHeader)) {
- NewHeader.Planes = BMPHeader->Planes;
- NewHeader.BitCount = BMPHeader->BitCount;
- } else {
- // A PNG .ico file.
- // https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473
- // "The image must be in 32bpp"
- NewHeader.Planes = 1;
- NewHeader.BitCount = 32;
- }
-
- ItemEntries[ID] = NewHeader;
- }
-
- IconCursorGroupResource HeaderRes(Type, *Header, std::move(ItemEntries));
- HeaderRes.setName(ResName);
- if (Base->MemoryFlags & MfPreload) {
- HeaderRes.MemoryFlags |= MfPreload;
- HeaderRes.MemoryFlags &= ~MfPure;
- }
- RETURN_IF_ERROR(visitIconOrCursorGroup(&HeaderRes));
-
- return Error::success();
-}
-
-// --- DialogResource helpers. --- //
-
-Error ResourceFileWriter::writeSingleDialogControl(const Control &Ctl,
- bool IsExtended) {
- // Each control should be aligned to DWORD.
- padStream(sizeof(uint32_t));
-
- auto TypeInfo = Control::SupportedCtls.lookup(Ctl.Type);
- IntWithNotMask CtlStyle(TypeInfo.Style);
- CtlStyle |= Ctl.Style.getValueOr(RCInt(0));
- uint32_t CtlExtStyle = Ctl.ExtStyle.getValueOr(0);
-
- // DIALOG(EX) item header prefix.
- if (!IsExtended) {
- struct {
- ulittle32_t Style;
- ulittle32_t ExtStyle;
- } Prefix{ulittle32_t(CtlStyle.getValue()), ulittle32_t(CtlExtStyle)};
- writeObject(Prefix);
- } else {
- struct {
- ulittle32_t HelpID;
- ulittle32_t ExtStyle;
- ulittle32_t Style;
- } Prefix{ulittle32_t(Ctl.HelpID.getValueOr(0)), ulittle32_t(CtlExtStyle),
- ulittle32_t(CtlStyle.getValue())};
- writeObject(Prefix);
- }
-
- // Common fixed-length part.
- RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
- Ctl.X, "Dialog control x-coordinate", true));
- RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
- Ctl.Y, "Dialog control y-coordinate", true));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Ctl.Width, "Dialog control width", false));
- RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
- Ctl.Height, "Dialog control height", false));
- struct {
- ulittle16_t X;
- ulittle16_t Y;
- ulittle16_t Width;
- ulittle16_t Height;
- } Middle{ulittle16_t(Ctl.X), ulittle16_t(Ctl.Y), ulittle16_t(Ctl.Width),
- ulittle16_t(Ctl.Height)};
- writeObject(Middle);
-
- // ID; it's 16-bit in DIALOG and 32-bit in DIALOGEX.
- if (!IsExtended) {
- // It's common to use -1, i.e. UINT32_MAX, for controls one doesn't
- // want to refer to later.
- if (Ctl.ID != static_cast<uint32_t>(-1))
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(
- Ctl.ID, "Control ID in simple DIALOG resource"));
- writeInt<uint16_t>(Ctl.ID);
- } else {
- writeInt<uint32_t>(Ctl.ID);
- }
-
- // Window class - either 0xFFFF + 16-bit integer or a string.
- RETURN_IF_ERROR(writeIntOrString(Ctl.Class));
-
- // Element caption/reference ID. ID is preceded by 0xFFFF.
- RETURN_IF_ERROR(checkIntOrString(Ctl.Title, "Control reference ID"));
- RETURN_IF_ERROR(writeIntOrString(Ctl.Title));
-
- // # bytes of extra creation data count. Don't pass any.
- writeInt<uint16_t>(0);
-
- return Error::success();
-}
-
-Error ResourceFileWriter::writeDialogBody(const RCResource *Base) {
- auto *Res = cast<DialogResource>(Base);
-
- // Default style: WS_POPUP | WS_BORDER | WS_SYSMENU.
- const uint32_t DefaultStyle = 0x80880000;
- const uint32_t StyleFontFlag = 0x40;
- const uint32_t StyleCaptionFlag = 0x00C00000;
-
- uint32_t UsedStyle = ObjectData.Style.getValueOr(DefaultStyle);
- if (ObjectData.Font)
- UsedStyle |= StyleFontFlag;
- else
- UsedStyle &= ~StyleFontFlag;
-
- // Actually, in case of empty (but existent) caption, the examined field
- // is equal to "\"\"". That's why empty captions are still noticed.
- if (ObjectData.Caption != "")
- UsedStyle |= StyleCaptionFlag;
-
- const uint16_t DialogExMagic = 0xFFFF;
- uint32_t ExStyle = ObjectData.ExStyle.getValueOr(0);
-
- // Write DIALOG(EX) header prefix. These are pretty different.
- if (!Res->IsExtended) {
- // We cannot let the higher word of DefaultStyle be equal to 0xFFFF.
- // In such a case, whole object (in .res file) is equivalent to a
- // DIALOGEX. It might lead to access violation/segmentation fault in
- // resource readers. For example,
- // 1 DIALOG 0, 0, 0, 65432
- // STYLE 0xFFFF0001 {}
- // would be compiled to a DIALOGEX with 65432 controls.
- if ((UsedStyle >> 16) == DialogExMagic)
- return createError("16 higher bits of DIALOG resource style cannot be"
- " equal to 0xFFFF");
-
- struct {
- ulittle32_t Style;
- ulittle32_t ExtStyle;
- } Prefix{ulittle32_t(UsedStyle),
- ulittle32_t(ExStyle)};
-
- writeObject(Prefix);
- } else {
- struct {
- ulittle16_t Version;
- ulittle16_t Magic;
- ulittle32_t HelpID;
- ulittle32_t ExtStyle;
- ulittle32_t Style;
- } Prefix{ulittle16_t(1), ulittle16_t(DialogExMagic),
- ulittle32_t(Res->HelpID), ulittle32_t(ExStyle), ulittle32_t(UsedStyle)};
-
- writeObject(Prefix);
- }
-
- // Now, a common part. First, fixed-length fields.
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(Res->Controls.size(),
- "Number of dialog controls"));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Res->X, "Dialog x-coordinate", true));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Res->Y, "Dialog y-coordinate", true));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Res->Width, "Dialog width", false));
- RETURN_IF_ERROR(
- checkSignedNumberFits<int16_t>(Res->Height, "Dialog height", false));
- struct {
- ulittle16_t Count;
- ulittle16_t PosX;
- ulittle16_t PosY;
- ulittle16_t DialogWidth;
- ulittle16_t DialogHeight;
- } Middle{ulittle16_t(Res->Controls.size()), ulittle16_t(Res->X),
- ulittle16_t(Res->Y), ulittle16_t(Res->Width),
- ulittle16_t(Res->Height)};
- writeObject(Middle);
-
- // MENU field. As of now, we don't keep them in the state and can peacefully
- // think there is no menu attached to the dialog.
- writeInt<uint16_t>(0);
-
- // Window CLASS field.
- RETURN_IF_ERROR(writeIntOrString(ObjectData.Class));
-
- // Window title or a single word equal to 0.
- RETURN_IF_ERROR(writeCString(ObjectData.Caption));
-
- // If there *is* a window font declared, output its data.
- auto &Font = ObjectData.Font;
- if (Font) {
- writeInt<uint16_t>(Font->Size);
- // Additional description occurs only in DIALOGEX.
- if (Res->IsExtended) {
- writeInt<uint16_t>(Font->Weight);
- writeInt<uint8_t>(Font->IsItalic);
- writeInt<uint8_t>(Font->Charset);
- }
- RETURN_IF_ERROR(writeCString(Font->Typeface));
- }
-
- auto handleCtlError = [&](Error &&Err, const Control &Ctl) -> Error {
- if (!Err)
- return Error::success();
- return joinErrors(createError("Error in " + Twine(Ctl.Type) +
- " control (ID " + Twine(Ctl.ID) + "):"),
- std::move(Err));
- };
-
- for (auto &Ctl : Res->Controls)
- RETURN_IF_ERROR(
- handleCtlError(writeSingleDialogControl(Ctl, Res->IsExtended), Ctl));
-
- return Error::success();
-}
-
-// --- HTMLResource helpers. --- //
-
-Error ResourceFileWriter::writeHTMLBody(const RCResource *Base) {
- 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);
- // Some resource files use -1, i.e. UINT32_MAX, for empty menu items.
- if (MenuItemPtr->Id != static_cast<uint32_t>(-1))
- 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
- writeInt<uint32_t>(0);
-
- return writeMenuDefinitionList(cast<MenuResource>(Base)->Elements);
-}
-
-// --- StringTableResource helpers. --- //
-
-class BundleResource : public RCResource {
-public:
- using BundleType = ResourceFileWriter::StringTableInfo::Bundle;
- BundleType Bundle;
-
- BundleResource(const BundleType &StrBundle)
- : RCResource(StrBundle.MemoryFlags), Bundle(StrBundle) {}
- IntOrString getResourceType() const override { return 6; }
-
- ResourceKind getKind() const override { return RkStringTableBundle; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkStringTableBundle;
- }
- Twine getResourceTypeName() const override { return "STRINGTABLE"; }
-};
-
-Error ResourceFileWriter::visitStringTableBundle(const RCResource *Res) {
- return writeResource(Res, &ResourceFileWriter::writeStringTableBundleBody);
-}
-
-Error ResourceFileWriter::insertStringIntoBundle(
- StringTableInfo::Bundle &Bundle, uint16_t StringID,
- const std::vector<StringRef> &String) {
- uint16_t StringLoc = StringID & 15;
- if (Bundle.Data[StringLoc])
- return createError("Multiple STRINGTABLE strings located under ID " +
- Twine(StringID));
- Bundle.Data[StringLoc] = String;
- return Error::success();
-}
-
-Error ResourceFileWriter::writeStringTableBundleBody(const RCResource *Base) {
- auto *Res = cast<BundleResource>(Base);
- for (size_t ID = 0; ID < Res->Bundle.Data.size(); ++ID) {
- // The string format is a tiny bit different here. We
- // first output the size of the string, and then the string itself
- // (which is not null-terminated).
- SmallVector<UTF16, 128> Data;
- if (Res->Bundle.Data[ID]) {
- bool IsLongString;
- for (StringRef S : *Res->Bundle.Data[ID])
- RETURN_IF_ERROR(processString(S, NullHandlingMethod::CutAtDoubleNull,
- IsLongString, Data, Params.CodePage));
- if (AppendNull)
- Data.push_back('\0');
- }
- RETURN_IF_ERROR(
- checkNumberFits<uint16_t>(Data.size(), "STRINGTABLE string size"));
- writeInt<uint16_t>(Data.size());
- for (auto Char : Data)
- writeInt(Char);
- }
- return Error::success();
-}
-
-Error ResourceFileWriter::dumpAllStringTables() {
- for (auto Key : StringTableData.BundleList) {
- auto Iter = StringTableData.BundleData.find(Key);
- assert(Iter != StringTableData.BundleData.end());
-
- // For a moment, revert the context info to moment of bundle declaration.
- ContextKeeper RAII(this);
- ObjectData = Iter->second.DeclTimeInfo;
-
- BundleResource Res(Iter->second);
- // Bundle #(k+1) contains keys [16k, 16k + 15].
- Res.setName(Key.first + 1);
- RETURN_IF_ERROR(visitStringTableBundle(&Res));
- }
- return Error::success();
-}
-
-// --- UserDefinedResource helpers. --- //
-
-Error ResourceFileWriter::writeUserDefinedBody(const RCResource *Base) {
- auto *Res = cast<UserDefinedResource>(Base);
-
- if (Res->IsFileResource)
- return appendFile(Res->FileLoc);
-
- for (auto &Elem : Res->Contents) {
- if (Elem.isInt()) {
- RETURN_IF_ERROR(
- checkRCInt(Elem.getInt(), "Number in user-defined resource"));
- writeRCInt(Elem.getInt());
- continue;
- }
-
- SmallVector<UTF16, 128> ProcessedString;
- bool IsLongString;
- RETURN_IF_ERROR(
- processString(Elem.getString(), NullHandlingMethod::UserResource,
- IsLongString, ProcessedString, Params.CodePage));
-
- for (auto Ch : ProcessedString) {
- if (IsLongString) {
- writeInt(Ch);
- continue;
- }
-
- RETURN_IF_ERROR(checkNumberFits<uint8_t>(
- Ch, "Character in narrow string in user-defined resource"));
- writeInt<uint8_t>(Ch);
- }
- }
-
- return Error::success();
-}
-
-// --- VersionInfoResourceResource helpers. --- //
-
-Error ResourceFileWriter::writeVersionInfoBlock(const VersionInfoBlock &Blk) {
- // Output the header if the block has name.
- bool OutputHeader = Blk.Name != "";
- uint64_t LengthLoc;
-
- padStream(sizeof(uint32_t));
- if (OutputHeader) {
- LengthLoc = writeInt<uint16_t>(0);
- writeInt<uint16_t>(0);
- writeInt<uint16_t>(1); // true
- RETURN_IF_ERROR(writeCString(Blk.Name));
- padStream(sizeof(uint32_t));
- }
-
- for (const std::unique_ptr<VersionInfoStmt> &Item : Blk.Stmts) {
- VersionInfoStmt *ItemPtr = Item.get();
-
- if (auto *BlockPtr = dyn_cast<VersionInfoBlock>(ItemPtr)) {
- RETURN_IF_ERROR(writeVersionInfoBlock(*BlockPtr));
- continue;
- }
-
- auto *ValuePtr = cast<VersionInfoValue>(ItemPtr);
- RETURN_IF_ERROR(writeVersionInfoValue(*ValuePtr));
- }
-
- if (OutputHeader) {
- uint64_t CurLoc = tell();
- writeObjectAt(ulittle16_t(CurLoc - LengthLoc), LengthLoc);
- }
-
- return Error::success();
-}
-
-Error ResourceFileWriter::writeVersionInfoValue(const VersionInfoValue &Val) {
- // rc has a peculiar algorithm to output VERSIONINFO VALUEs. Each VALUE
- // is a mapping from the key (string) to the value (a sequence of ints or
- // a sequence of strings).
- //
- // If integers are to be written: width of each integer written depends on
- // whether it's been declared 'long' (it's DWORD then) or not (it's WORD).
- // ValueLength defined in structure referenced below is then the total
- // number of bytes taken by these integers.
- //
- // If strings are to be written: characters are always WORDs.
- // Moreover, '\0' character is written after the last string, and between
- // every two strings separated by comma (if strings are not comma-separated,
- // they're simply concatenated). ValueLength is equal to the number of WORDs
- // written (that is, half of the bytes written).
- //
- // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms646994.aspx
- bool HasStrings = false, HasInts = false;
- for (auto &Item : Val.Values)
- (Item.isInt() ? HasInts : HasStrings) = true;
-
- assert((HasStrings || HasInts) && "VALUE must have at least one argument");
- if (HasStrings && HasInts)
- return createError(Twine("VALUE ") + Val.Key +
- " cannot contain both strings and integers");
-
- padStream(sizeof(uint32_t));
- auto LengthLoc = writeInt<uint16_t>(0);
- auto ValLengthLoc = writeInt<uint16_t>(0);
- writeInt<uint16_t>(HasStrings);
- RETURN_IF_ERROR(writeCString(Val.Key));
- padStream(sizeof(uint32_t));
-
- auto DataLoc = tell();
- for (size_t Id = 0; Id < Val.Values.size(); ++Id) {
- auto &Item = Val.Values[Id];
- if (Item.isInt()) {
- auto Value = Item.getInt();
- RETURN_IF_ERROR(checkRCInt(Value, "VERSIONINFO integer value"));
- writeRCInt(Value);
- continue;
- }
-
- bool WriteTerminator =
- Id == Val.Values.size() - 1 || Val.HasPrecedingComma[Id + 1];
- RETURN_IF_ERROR(writeCString(Item.getString(), WriteTerminator));
- }
-
- auto CurLoc = tell();
- auto ValueLength = CurLoc - DataLoc;
- if (HasStrings) {
- assert(ValueLength % 2 == 0);
- ValueLength /= 2;
- }
- writeObjectAt(ulittle16_t(CurLoc - LengthLoc), LengthLoc);
- writeObjectAt(ulittle16_t(ValueLength), ValLengthLoc);
- return Error::success();
-}
-
-template <typename Ty>
-static Ty getWithDefault(const StringMap<Ty> &Map, StringRef Key,
- const Ty &Default) {
- auto Iter = Map.find(Key);
- if (Iter != Map.end())
- return Iter->getValue();
- return Default;
-}
-
-Error ResourceFileWriter::writeVersionInfoBody(const RCResource *Base) {
- auto *Res = cast<VersionInfoResource>(Base);
-
- const auto &FixedData = Res->FixedData;
-
- struct /* VS_FIXEDFILEINFO */ {
- ulittle32_t Signature = ulittle32_t(0xFEEF04BD);
- ulittle32_t StructVersion = ulittle32_t(0x10000);
- // It's weird to have most-significant DWORD first on the little-endian
- // machines, but let it be this way.
- ulittle32_t FileVersionMS;
- ulittle32_t FileVersionLS;
- ulittle32_t ProductVersionMS;
- ulittle32_t ProductVersionLS;
- ulittle32_t FileFlagsMask;
- ulittle32_t FileFlags;
- ulittle32_t FileOS;
- ulittle32_t FileType;
- ulittle32_t FileSubtype;
- // MS implementation seems to always set these fields to 0.
- ulittle32_t FileDateMS = ulittle32_t(0);
- ulittle32_t FileDateLS = ulittle32_t(0);
- } FixedInfo;
-
- // First, VS_VERSIONINFO.
- auto LengthLoc = writeInt<uint16_t>(0);
- writeInt<uint16_t>(sizeof(FixedInfo));
- writeInt<uint16_t>(0);
- cantFail(writeCString("VS_VERSION_INFO"));
- padStream(sizeof(uint32_t));
-
- using VersionInfoFixed = VersionInfoResource::VersionInfoFixed;
- auto GetField = [&](VersionInfoFixed::VersionInfoFixedType Type) {
- static const SmallVector<uint32_t, 4> DefaultOut{0, 0, 0, 0};
- if (!FixedData.IsTypePresent[(int)Type])
- return DefaultOut;
- return FixedData.FixedInfo[(int)Type];
- };
-
- auto FileVer = GetField(VersionInfoFixed::FtFileVersion);
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(
- *std::max_element(FileVer.begin(), FileVer.end()), "FILEVERSION fields"));
- FixedInfo.FileVersionMS = (FileVer[0] << 16) | FileVer[1];
- FixedInfo.FileVersionLS = (FileVer[2] << 16) | FileVer[3];
-
- auto ProdVer = GetField(VersionInfoFixed::FtProductVersion);
- RETURN_IF_ERROR(checkNumberFits<uint16_t>(
- *std::max_element(ProdVer.begin(), ProdVer.end()),
- "PRODUCTVERSION fields"));
- FixedInfo.ProductVersionMS = (ProdVer[0] << 16) | ProdVer[1];
- FixedInfo.ProductVersionLS = (ProdVer[2] << 16) | ProdVer[3];
-
- FixedInfo.FileFlagsMask = GetField(VersionInfoFixed::FtFileFlagsMask)[0];
- FixedInfo.FileFlags = GetField(VersionInfoFixed::FtFileFlags)[0];
- FixedInfo.FileOS = GetField(VersionInfoFixed::FtFileOS)[0];
- FixedInfo.FileType = GetField(VersionInfoFixed::FtFileType)[0];
- FixedInfo.FileSubtype = GetField(VersionInfoFixed::FtFileSubtype)[0];
-
- writeObject(FixedInfo);
- padStream(sizeof(uint32_t));
-
- RETURN_IF_ERROR(writeVersionInfoBlock(Res->MainBlock));
-
- // FIXME: check overflow?
- writeObjectAt(ulittle16_t(tell() - LengthLoc), LengthLoc);
-
- return Error::success();
-}
-
-Expected<std::unique_ptr<MemoryBuffer>>
-ResourceFileWriter::loadFile(StringRef File) const {
- SmallString<128> Path;
- SmallString<128> Cwd;
- std::unique_ptr<MemoryBuffer> Result;
-
+// * Squash "" to a single ".
+// * Replace the escape sequences with their processed version.
+// For identifiers, this is no-op.
+static Error processString(StringRef Str, NullHandlingMethod NullHandler,
+ bool &IsLongString, SmallVectorImpl<UTF16> &Result,
+ int CodePage) {
+ bool IsString = stripQuotes(Str, IsLongString);
+ SmallVector<UTF16, 128> Chars;
+
+ // Convert the input bytes according to the chosen codepage.
+ if (CodePage == CpUtf8) {
+ convertUTF8ToUTF16String(Str, Chars);
+ } else if (CodePage == CpWin1252) {
+ for (char C : Str)
+ Chars.push_back(cp1252ToUnicode((unsigned char)C));
+ } else {
+ // For other, unknown codepages, only allow plain ASCII input.
+ for (char C : Str) {
+ if ((unsigned char)C > 0x7F)
+ return createError("Non-ASCII 8-bit codepoint (" + Twine(C) +
+ ") can't be interpreted in the current codepage");
+ Chars.push_back((unsigned char)C);
+ }
+ }
+
+ if (!IsString) {
+ // It's an identifier if it's not a string. Make all characters uppercase.
+ for (UTF16 &Ch : Chars) {
+ assert(Ch <= 0x7F && "We didn't allow identifiers to be non-ASCII");
+ Ch = toupper(Ch);
+ }
+ Result.swap(Chars);
+ return Error::success();
+ }
+ Result.reserve(Chars.size());
+ size_t Pos = 0;
+
+ auto AddRes = [&Result, NullHandler, IsLongString](UTF16 Char) -> Error {
+ if (!IsLongString) {
+ if (NullHandler == NullHandlingMethod::UserResource) {
+ // Narrow strings in user-defined resources are *not* output in
+ // UTF-16 format.
+ if (Char > 0xFF)
+ return createError("Non-8-bit codepoint (" + Twine(Char) +
+ ") can't occur in a user-defined narrow string");
+ }
+ }
+
+ Result.push_back(Char);
+ return Error::success();
+ };
+ auto AddEscapedChar = [AddRes, IsLongString, CodePage](UTF16 Char) -> Error {
+ if (!IsLongString) {
+ // Escaped chars in narrow strings have to be interpreted according to
+ // the chosen code page.
+ if (Char > 0xFF)
+ return createError("Non-8-bit escaped char (" + Twine(Char) +
+ ") can't occur in narrow string");
+ if (CodePage == CpUtf8) {
+ if (Char >= 0x80)
+ return createError("Unable to interpret single byte (" + Twine(Char) +
+ ") as UTF-8");
+ } else if (CodePage == CpWin1252) {
+ Char = cp1252ToUnicode(Char);
+ } else {
+ // Unknown/unsupported codepage, only allow ASCII input.
+ if (Char > 0x7F)
+ return createError("Non-ASCII 8-bit codepoint (" + Twine(Char) +
+ ") can't "
+ "occur in a non-Unicode string");
+ }
+ }
+
+ return AddRes(Char);
+ };
+
+ while (Pos < Chars.size()) {
+ UTF16 CurChar = Chars[Pos];
+ ++Pos;
+
+ // Strip double "".
+ if (CurChar == '"') {
+ if (Pos == Chars.size() || Chars[Pos] != '"')
+ return createError("Expected \"\"");
+ ++Pos;
+ RETURN_IF_ERROR(AddRes('"'));
+ continue;
+ }
+
+ if (CurChar == '\\') {
+ UTF16 TypeChar = Chars[Pos];
+ ++Pos;
+
+ if (TypeChar == 'x' || TypeChar == 'X') {
+ // Read a hex number. Max number of characters to read differs between
+ // narrow and wide strings.
+ UTF16 ReadInt = 0;
+ size_t RemainingChars = IsLongString ? 4 : 2;
+ // We don't want to read non-ASCII hex digits. std:: functions past
+ // 0xFF invoke UB.
+ //
+ // FIXME: actually, Microsoft version probably doesn't check this
+ // condition and uses their Unicode version of 'isxdigit'. However,
+ // there are some hex-digit Unicode character outside of ASCII, and
+ // some of these are actually accepted by rc.exe, the notable example
+ // being fullwidth forms (U+FF10..U+FF19 etc.) These can be written
+ // instead of ASCII digits in \x... escape sequence and get accepted.
+ // However, the resulting hexcodes seem totally unpredictable.
+ // We think it's infeasible to try to reproduce this behavior, nor to
+ // put effort in order to detect it.
+ while (RemainingChars && Pos < Chars.size() && Chars[Pos] < 0x80) {
+ if (!isxdigit(Chars[Pos]))
+ break;
+ char Digit = tolower(Chars[Pos]);
+ ++Pos;
+
+ ReadInt <<= 4;
+ if (isdigit(Digit))
+ ReadInt |= Digit - '0';
+ else
+ ReadInt |= Digit - 'a' + 10;
+
+ --RemainingChars;
+ }
+
+ RETURN_IF_ERROR(AddEscapedChar(ReadInt));
+ continue;
+ }
+
+ if (TypeChar >= '0' && TypeChar < '8') {
+ // Read an octal number. Note that we've already read the first digit.
+ UTF16 ReadInt = TypeChar - '0';
+ size_t RemainingChars = IsLongString ? 6 : 2;
+
+ while (RemainingChars && Pos < Chars.size() && Chars[Pos] >= '0' &&
+ Chars[Pos] < '8') {
+ ReadInt <<= 3;
+ ReadInt |= Chars[Pos] - '0';
+ --RemainingChars;
+ ++Pos;
+ }
+
+ RETURN_IF_ERROR(AddEscapedChar(ReadInt));
+
+ continue;
+ }
+
+ switch (TypeChar) {
+ case 'A':
+ case 'a':
+ // Windows '\a' translates into '\b' (Backspace).
+ RETURN_IF_ERROR(AddRes('\b'));
+ break;
+
+ case 'n': // Somehow, RC doesn't recognize '\N' and '\R'.
+ RETURN_IF_ERROR(AddRes('\n'));
+ break;
+
+ case 'r':
+ RETURN_IF_ERROR(AddRes('\r'));
+ break;
+
+ case 'T':
+ case 't':
+ RETURN_IF_ERROR(AddRes('\t'));
+ break;
+
+ case '\\':
+ RETURN_IF_ERROR(AddRes('\\'));
+ break;
+
+ case '"':
+ // RC accepts \" only if another " comes afterwards; then, \"" means
+ // a single ".
+ if (Pos == Chars.size() || Chars[Pos] != '"')
+ return createError("Expected \\\"\"");
+ ++Pos;
+ RETURN_IF_ERROR(AddRes('"'));
+ break;
+
+ default:
+ // If TypeChar means nothing, \ is should be output to stdout with
+ // following char. However, rc.exe consumes these characters when
+ // dealing with wide strings.
+ if (!IsLongString) {
+ RETURN_IF_ERROR(AddRes('\\'));
+ RETURN_IF_ERROR(AddRes(TypeChar));
+ }
+ break;
+ }
+
+ continue;
+ }
+
+ // If nothing interesting happens, just output the character.
+ RETURN_IF_ERROR(AddRes(CurChar));
+ }
+
+ switch (NullHandler) {
+ case NullHandlingMethod::CutAtNull:
+ for (size_t Pos = 0; Pos < Result.size(); ++Pos)
+ if (Result[Pos] == '\0')
+ Result.resize(Pos);
+ break;
+
+ case NullHandlingMethod::CutAtDoubleNull:
+ for (size_t Pos = 0; Pos + 1 < Result.size(); ++Pos)
+ if (Result[Pos] == '\0' && Result[Pos + 1] == '\0')
+ Result.resize(Pos);
+ if (Result.size() > 0 && Result.back() == '\0')
+ Result.pop_back();
+ break;
+
+ case NullHandlingMethod::UserResource:
+ break;
+ }
+
+ return Error::success();
+}
+
+uint64_t ResourceFileWriter::writeObject(const ArrayRef<uint8_t> Data) {
+ uint64_t Result = tell();
+ FS->write((const char *)Data.begin(), Data.size());
+ return Result;
+}
+
+Error ResourceFileWriter::writeCString(StringRef Str, bool WriteTerminator) {
+ SmallVector<UTF16, 128> ProcessedString;
+ bool IsLongString;
+ RETURN_IF_ERROR(processString(Str, NullHandlingMethod::CutAtNull,
+ IsLongString, ProcessedString,
+ Params.CodePage));
+ for (auto Ch : ProcessedString)
+ writeInt<uint16_t>(Ch);
+ if (WriteTerminator)
+ writeInt<uint16_t>(0);
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeIdentifier(const IntOrString &Ident) {
+ return writeIntOrString(Ident);
+}
+
+Error ResourceFileWriter::writeIntOrString(const IntOrString &Value) {
+ if (!Value.isInt())
+ return writeCString(Value.getString());
+
+ writeInt<uint16_t>(0xFFFF);
+ writeInt<uint16_t>(Value.getInt());
+ return Error::success();
+}
+
+void ResourceFileWriter::writeRCInt(RCInt Value) {
+ if (Value.isLong())
+ writeInt<uint32_t>(Value);
+ else
+ writeInt<uint16_t>(Value);
+}
+
+Error ResourceFileWriter::appendFile(StringRef Filename) {
+ bool IsLong;
+ stripQuotes(Filename, IsLong);
+
+ auto File = loadFile(Filename);
+ if (!File)
+ return File.takeError();
+
+ *FS << (*File)->getBuffer();
+ return Error::success();
+}
+
+void ResourceFileWriter::padStream(uint64_t Length) {
+ assert(Length > 0);
+ uint64_t Location = tell();
+ Location %= Length;
+ uint64_t Pad = (Length - Location) % Length;
+ for (uint64_t i = 0; i < Pad; ++i)
+ writeInt<uint8_t>(0);
+}
+
+Error ResourceFileWriter::handleError(Error Err, const RCResource *Res) {
+ if (Err)
+ return joinErrors(createError("Error in " + Res->getResourceTypeName() +
+ " statement (ID " + Twine(Res->ResName) +
+ "): "),
+ std::move(Err));
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitNullResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeNullBody);
+}
+
+Error ResourceFileWriter::visitAcceleratorsResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeAcceleratorsBody);
+}
+
+Error ResourceFileWriter::visitBitmapResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeBitmapBody);
+}
+
+Error ResourceFileWriter::visitCursorResource(const RCResource *Res) {
+ return handleError(visitIconOrCursorResource(Res), Res);
+}
+
+Error ResourceFileWriter::visitDialogResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeDialogBody);
+}
+
+Error ResourceFileWriter::visitIconResource(const RCResource *Res) {
+ return handleError(visitIconOrCursorResource(Res), Res);
+}
+
+Error ResourceFileWriter::visitCaptionStmt(const CaptionStmt *Stmt) {
+ ObjectData.Caption = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitClassStmt(const ClassStmt *Stmt) {
+ ObjectData.Class = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitHTMLResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeHTMLBody);
+}
+
+Error ResourceFileWriter::visitMenuResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeMenuBody);
+}
+
+Error ResourceFileWriter::visitStringTableResource(const RCResource *Base) {
+ const auto *Res = cast<StringTableResource>(Base);
+
+ ContextKeeper RAII(this);
+ RETURN_IF_ERROR(Res->applyStmts(this));
+
+ for (auto &String : Res->Table) {
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(String.first, "String ID"));
+ uint16_t BundleID = String.first >> 4;
+ StringTableInfo::BundleKey Key(BundleID, ObjectData.LanguageInfo);
+ auto &BundleData = StringTableData.BundleData;
+ auto Iter = BundleData.find(Key);
+
+ if (Iter == BundleData.end()) {
+ // Need to create a bundle.
+ StringTableData.BundleList.push_back(Key);
+ auto EmplaceResult = BundleData.emplace(
+ Key, StringTableInfo::Bundle(ObjectData, Res->MemoryFlags));
+ assert(EmplaceResult.second && "Could not create a bundle");
+ Iter = EmplaceResult.first;
+ }
+
+ RETURN_IF_ERROR(
+ insertStringIntoBundle(Iter->second, String.first, String.second));
+ }
+
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitUserDefinedResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeUserDefinedBody);
+}
+
+Error ResourceFileWriter::visitVersionInfoResource(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeVersionInfoBody);
+}
+
+Error ResourceFileWriter::visitCharacteristicsStmt(
+ const CharacteristicsStmt *Stmt) {
+ ObjectData.Characteristics = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitExStyleStmt(const ExStyleStmt *Stmt) {
+ ObjectData.ExStyle = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitFontStmt(const FontStmt *Stmt) {
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Size, "Font size"));
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(Stmt->Weight, "Font weight"));
+ RETURN_IF_ERROR(checkNumberFits<uint8_t>(Stmt->Charset, "Font charset"));
+ ObjectInfo::FontInfo Font{Stmt->Size, Stmt->Name, Stmt->Weight, Stmt->Italic,
+ Stmt->Charset};
+ ObjectData.Font.emplace(Font);
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitLanguageStmt(const LanguageResource *Stmt) {
+ RETURN_IF_ERROR(checkNumberFits(Stmt->Lang, 10, "Primary language ID"));
+ RETURN_IF_ERROR(checkNumberFits(Stmt->SubLang, 6, "Sublanguage ID"));
+ ObjectData.LanguageInfo = Stmt->Lang | (Stmt->SubLang << 10);
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitStyleStmt(const StyleStmt *Stmt) {
+ ObjectData.Style = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitVersionStmt(const VersionStmt *Stmt) {
+ ObjectData.VersionInfo = Stmt->Value;
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeResource(
+ const RCResource *Res,
+ Error (ResourceFileWriter::*BodyWriter)(const RCResource *)) {
+ // We don't know the sizes yet.
+ object::WinResHeaderPrefix HeaderPrefix{ulittle32_t(0U), ulittle32_t(0U)};
+ uint64_t HeaderLoc = writeObject(HeaderPrefix);
+
+ auto ResType = Res->getResourceType();
+ RETURN_IF_ERROR(checkIntOrString(ResType, "Resource type"));
+ RETURN_IF_ERROR(checkIntOrString(Res->ResName, "Resource ID"));
+ RETURN_IF_ERROR(handleError(writeIdentifier(ResType), Res));
+ RETURN_IF_ERROR(handleError(writeIdentifier(Res->ResName), Res));
+
+ // Apply the resource-local optional statements.
+ ContextKeeper RAII(this);
+ RETURN_IF_ERROR(handleError(Res->applyStmts(this), Res));
+
+ padStream(sizeof(uint32_t));
+ object::WinResHeaderSuffix HeaderSuffix{
+ ulittle32_t(0), // DataVersion; seems to always be 0
+ ulittle16_t(Res->MemoryFlags), ulittle16_t(ObjectData.LanguageInfo),
+ ulittle32_t(ObjectData.VersionInfo),
+ ulittle32_t(ObjectData.Characteristics)};
+ writeObject(HeaderSuffix);
+
+ uint64_t DataLoc = tell();
+ RETURN_IF_ERROR(handleError((this->*BodyWriter)(Res), Res));
+ // RETURN_IF_ERROR(handleError(dumpResource(Ctx)));
+
+ // Update the sizes.
+ HeaderPrefix.DataSize = tell() - DataLoc;
+ HeaderPrefix.HeaderSize = DataLoc - HeaderLoc;
+ writeObjectAt(HeaderPrefix, HeaderLoc);
+ padStream(sizeof(uint32_t));
+
+ return Error::success();
+}
+
+// --- NullResource helpers. --- //
+
+Error ResourceFileWriter::writeNullBody(const RCResource *) {
+ return Error::success();
+}
+
+// --- AcceleratorsResource helpers. --- //
+
+Error ResourceFileWriter::writeSingleAccelerator(
+ const AcceleratorsResource::Accelerator &Obj, bool IsLastItem) {
+ using Accelerator = AcceleratorsResource::Accelerator;
+ using Opt = Accelerator::Options;
+
+ struct AccelTableEntry {
+ ulittle16_t Flags;
+ ulittle16_t ANSICode;
+ ulittle16_t Id;
+ uint16_t Padding;
+ } Entry{ulittle16_t(0), ulittle16_t(0), ulittle16_t(0), 0};
+
+ bool IsASCII = Obj.Flags & Opt::ASCII, IsVirtKey = Obj.Flags & Opt::VIRTKEY;
+
+ // Remove ASCII flags (which doesn't occur in .res files).
+ Entry.Flags = Obj.Flags & ~Opt::ASCII;
+
+ if (IsLastItem)
+ Entry.Flags |= 0x80;
+
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(Obj.Id, "ACCELERATORS entry ID"));
+ Entry.Id = ulittle16_t(Obj.Id);
+
+ auto createAccError = [&Obj](const char *Msg) {
+ return createError("Accelerator ID " + Twine(Obj.Id) + ": " + Msg);
+ };
+
+ if (IsASCII && IsVirtKey)
+ return createAccError("Accelerator can't be both ASCII and VIRTKEY");
+
+ if (!IsVirtKey && (Obj.Flags & (Opt::ALT | Opt::SHIFT | Opt::CONTROL)))
+ return createAccError("Can only apply ALT, SHIFT or CONTROL to VIRTKEY"
+ " accelerators");
+
+ if (Obj.Event.isInt()) {
+ if (!IsASCII && !IsVirtKey)
+ return createAccError(
+ "Accelerator with a numeric event must be either ASCII"
+ " or VIRTKEY");
+
+ uint32_t EventVal = Obj.Event.getInt();
+ RETURN_IF_ERROR(
+ checkNumberFits<uint16_t>(EventVal, "Numeric event key ID"));
+ Entry.ANSICode = ulittle16_t(EventVal);
+ writeObject(Entry);
+ return Error::success();
+ }
+
+ StringRef Str = Obj.Event.getString();
+ bool IsWide;
+ stripQuotes(Str, IsWide);
+
+ if (Str.size() == 0 || Str.size() > 2)
+ return createAccError(
+ "Accelerator string events should have length 1 or 2");
+
+ if (Str[0] == '^') {
+ if (Str.size() == 1)
+ return createAccError("No character following '^' in accelerator event");
+ if (IsVirtKey)
+ return createAccError(
+ "VIRTKEY accelerator events can't be preceded by '^'");
+
+ char Ch = Str[1];
+ if (Ch >= 'a' && Ch <= 'z')
+ Entry.ANSICode = ulittle16_t(Ch - 'a' + 1);
+ else if (Ch >= 'A' && Ch <= 'Z')
+ Entry.ANSICode = ulittle16_t(Ch - 'A' + 1);
+ else
+ return createAccError("Control character accelerator event should be"
+ " alphabetic");
+
+ writeObject(Entry);
+ return Error::success();
+ }
+
+ if (Str.size() == 2)
+ return createAccError("Event string should be one-character, possibly"
+ " preceded by '^'");
+
+ uint8_t EventCh = Str[0];
+ // The original tool just warns in this situation. We chose to fail.
+ if (IsVirtKey && !isalnum(EventCh))
+ return createAccError("Non-alphanumeric characters cannot describe virtual"
+ " keys");
+ if (EventCh > 0x7F)
+ return createAccError("Non-ASCII description of accelerator");
+
+ if (IsVirtKey)
+ EventCh = toupper(EventCh);
+ Entry.ANSICode = ulittle16_t(EventCh);
+ writeObject(Entry);
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeAcceleratorsBody(const RCResource *Base) {
+ auto *Res = cast<AcceleratorsResource>(Base);
+ size_t AcceleratorId = 0;
+ for (auto &Acc : Res->Accelerators) {
+ ++AcceleratorId;
+ RETURN_IF_ERROR(
+ writeSingleAccelerator(Acc, AcceleratorId == Res->Accelerators.size()));
+ }
+ return Error::success();
+}
+
+// --- BitmapResource helpers. --- //
+
+Error ResourceFileWriter::writeBitmapBody(const RCResource *Base) {
+ StringRef Filename = cast<BitmapResource>(Base)->BitmapLoc;
+ bool IsLong;
+ stripQuotes(Filename, IsLong);
+
+ auto File = loadFile(Filename);
+ if (!File)
+ return File.takeError();
+
+ StringRef Buffer = (*File)->getBuffer();
+
+ // Skip the 14 byte BITMAPFILEHEADER.
+ constexpr size_t BITMAPFILEHEADER_size = 14;
+ if (Buffer.size() < BITMAPFILEHEADER_size || Buffer[0] != 'B' ||
+ Buffer[1] != 'M')
+ return createError("Incorrect bitmap file.");
+
+ *FS << Buffer.substr(BITMAPFILEHEADER_size);
+ return Error::success();
+}
+
+// --- CursorResource and IconResource helpers. --- //
+
+// ICONRESDIR structure. Describes a single icon in resource group.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648016.aspx
+struct IconResDir {
+ uint8_t Width;
+ uint8_t Height;
+ uint8_t ColorCount;
+ uint8_t Reserved;
+};
+
+// CURSORDIR structure. Describes a single cursor in resource group.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648011(v=vs.85).aspx
+struct CursorDir {
+ ulittle16_t Width;
+ ulittle16_t Height;
+};
+
+// RESDIRENTRY structure, stripped from the last item. Stripping made
+// for compatibility with RESDIR.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026(v=vs.85).aspx
+struct ResourceDirEntryStart {
+ union {
+ CursorDir Cursor; // Used in CURSOR resources.
+ IconResDir Icon; // Used in .ico and .cur files, and ICON resources.
+ };
+ ulittle16_t Planes; // HotspotX (.cur files but not CURSOR resource).
+ ulittle16_t BitCount; // HotspotY (.cur files but not CURSOR resource).
+ ulittle32_t Size;
+ // ulittle32_t ImageOffset; // Offset to image data (ICONDIRENTRY only).
+ // ulittle16_t IconID; // Resource icon ID (RESDIR only).
+};
+
+// BITMAPINFOHEADER structure. Describes basic information about the bitmap
+// being read.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
+struct BitmapInfoHeader {
+ ulittle32_t Size;
+ ulittle32_t Width;
+ ulittle32_t Height;
+ ulittle16_t Planes;
+ ulittle16_t BitCount;
+ ulittle32_t Compression;
+ ulittle32_t SizeImage;
+ ulittle32_t XPelsPerMeter;
+ ulittle32_t YPelsPerMeter;
+ ulittle32_t ClrUsed;
+ ulittle32_t ClrImportant;
+};
+
+// Group icon directory header. Called ICONDIR in .ico/.cur files and
+// NEWHEADER in .res files.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648023(v=vs.85).aspx
+struct GroupIconDir {
+ ulittle16_t Reserved; // Always 0.
+ ulittle16_t ResType; // 1 for icons, 2 for cursors.
+ ulittle16_t ResCount; // Number of items.
+};
+
+enum class IconCursorGroupType { Icon, Cursor };
+
+class SingleIconCursorResource : public RCResource {
+public:
+ IconCursorGroupType Type;
+ const ResourceDirEntryStart &Header;
+ ArrayRef<uint8_t> Image;
+
+ SingleIconCursorResource(IconCursorGroupType ResourceType,
+ const ResourceDirEntryStart &HeaderEntry,
+ ArrayRef<uint8_t> ImageData, uint16_t Flags)
+ : RCResource(Flags), Type(ResourceType), Header(HeaderEntry),
+ Image(ImageData) {}
+
+ Twine getResourceTypeName() const override { return "Icon/cursor image"; }
+ IntOrString getResourceType() const override {
+ return Type == IconCursorGroupType::Icon ? RkSingleIcon : RkSingleCursor;
+ }
+ ResourceKind getKind() const override { return RkSingleCursorOrIconRes; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkSingleCursorOrIconRes;
+ }
+};
+
+class IconCursorGroupResource : public RCResource {
+public:
+ IconCursorGroupType Type;
+ GroupIconDir Header;
+ std::vector<ResourceDirEntryStart> ItemEntries;
+
+ IconCursorGroupResource(IconCursorGroupType ResourceType,
+ const GroupIconDir &HeaderData,
+ std::vector<ResourceDirEntryStart> &&Entries)
+ : Type(ResourceType), Header(HeaderData),
+ ItemEntries(std::move(Entries)) {}
+
+ Twine getResourceTypeName() const override { return "Icon/cursor group"; }
+ IntOrString getResourceType() const override {
+ return Type == IconCursorGroupType::Icon ? RkIconGroup : RkCursorGroup;
+ }
+ ResourceKind getKind() const override { return RkCursorOrIconGroupRes; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkCursorOrIconGroupRes;
+ }
+};
+
+Error ResourceFileWriter::writeSingleIconOrCursorBody(const RCResource *Base) {
+ auto *Res = cast<SingleIconCursorResource>(Base);
+ if (Res->Type == IconCursorGroupType::Cursor) {
+ // In case of cursors, two WORDS are appended to the beginning
+ // of the resource: HotspotX (Planes in RESDIRENTRY),
+ // and HotspotY (BitCount).
+ //
+ // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648026.aspx
+ // (Remarks section).
+ writeObject(Res->Header.Planes);
+ writeObject(Res->Header.BitCount);
+ }
+
+ writeObject(Res->Image);
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeIconOrCursorGroupBody(const RCResource *Base) {
+ auto *Res = cast<IconCursorGroupResource>(Base);
+ writeObject(Res->Header);
+ for (auto Item : Res->ItemEntries) {
+ writeObject(Item);
+ writeInt(IconCursorID++);
+ }
+ return Error::success();
+}
+
+Error ResourceFileWriter::visitSingleIconOrCursor(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeSingleIconOrCursorBody);
+}
+
+Error ResourceFileWriter::visitIconOrCursorGroup(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeIconOrCursorGroupBody);
+}
+
+Error ResourceFileWriter::visitIconOrCursorResource(const RCResource *Base) {
+ IconCursorGroupType Type;
+ StringRef FileStr;
+ IntOrString ResName = Base->ResName;
+
+ if (auto *IconRes = dyn_cast<IconResource>(Base)) {
+ FileStr = IconRes->IconLoc;
+ Type = IconCursorGroupType::Icon;
+ } else {
+ auto *CursorRes = dyn_cast<CursorResource>(Base);
+ FileStr = CursorRes->CursorLoc;
+ Type = IconCursorGroupType::Cursor;
+ }
+
+ bool IsLong;
+ stripQuotes(FileStr, IsLong);
+ auto File = loadFile(FileStr);
+
+ if (!File)
+ return File.takeError();
+
+ BinaryStreamReader Reader((*File)->getBuffer(), support::little);
+
+ // Read the file headers.
+ // - At the beginning, ICONDIR/NEWHEADER header.
+ // - Then, a number of RESDIR headers follow. These contain offsets
+ // to data.
+ const GroupIconDir *Header;
+
+ RETURN_IF_ERROR(Reader.readObject(Header));
+ if (Header->Reserved != 0)
+ return createError("Incorrect icon/cursor Reserved field; should be 0.");
+ uint16_t NeededType = Type == IconCursorGroupType::Icon ? 1 : 2;
+ if (Header->ResType != NeededType)
+ return createError("Incorrect icon/cursor ResType field; should be " +
+ Twine(NeededType) + ".");
+
+ uint16_t NumItems = Header->ResCount;
+
+ // Read single ico/cur headers.
+ std::vector<ResourceDirEntryStart> ItemEntries;
+ ItemEntries.reserve(NumItems);
+ std::vector<uint32_t> ItemOffsets(NumItems);
+ for (size_t ID = 0; ID < NumItems; ++ID) {
+ const ResourceDirEntryStart *Object;
+ RETURN_IF_ERROR(Reader.readObject(Object));
+ ItemEntries.push_back(*Object);
+ RETURN_IF_ERROR(Reader.readInteger(ItemOffsets[ID]));
+ }
+
+ // Now write each icon/cursors one by one. At first, all the contents
+ // without ICO/CUR header. This is described by SingleIconCursorResource.
+ for (size_t ID = 0; ID < NumItems; ++ID) {
+ // Load the fragment of file.
+ Reader.setOffset(ItemOffsets[ID]);
+ ArrayRef<uint8_t> Image;
+ RETURN_IF_ERROR(Reader.readArray(Image, ItemEntries[ID].Size));
+ SingleIconCursorResource SingleRes(Type, ItemEntries[ID], Image,
+ Base->MemoryFlags);
+ SingleRes.setName(IconCursorID + ID);
+ RETURN_IF_ERROR(visitSingleIconOrCursor(&SingleRes));
+ }
+
+ // Now, write all the headers concatenated into a separate resource.
+ for (size_t ID = 0; ID < NumItems; ++ID) {
+ // We need to rewrite the cursor headers, and fetch actual values
+ // for Planes/BitCount.
+ const auto &OldHeader = ItemEntries[ID];
+ ResourceDirEntryStart NewHeader = OldHeader;
+
+ if (Type == IconCursorGroupType::Cursor) {
+ NewHeader.Cursor.Width = OldHeader.Icon.Width;
+ // Each cursor in fact stores two bitmaps, one under another.
+ // Height provided in cursor definition describes the height of the
+ // cursor, whereas the value existing in resource definition describes
+ // the height of the bitmap. Therefore, we need to double this height.
+ NewHeader.Cursor.Height = OldHeader.Icon.Height * 2;
+
+ // Two WORDs were written at the beginning of the resource (hotspot
+ // location). This is reflected in Size field.
+ NewHeader.Size += 2 * sizeof(uint16_t);
+ }
+
+ // Now, we actually need to read the bitmap header to find
+ // the number of planes and the number of bits per pixel.
+ Reader.setOffset(ItemOffsets[ID]);
+ const BitmapInfoHeader *BMPHeader;
+ RETURN_IF_ERROR(Reader.readObject(BMPHeader));
+ if (BMPHeader->Size == sizeof(BitmapInfoHeader)) {
+ NewHeader.Planes = BMPHeader->Planes;
+ NewHeader.BitCount = BMPHeader->BitCount;
+ } else {
+ // A PNG .ico file.
+ // https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473
+ // "The image must be in 32bpp"
+ NewHeader.Planes = 1;
+ NewHeader.BitCount = 32;
+ }
+
+ ItemEntries[ID] = NewHeader;
+ }
+
+ IconCursorGroupResource HeaderRes(Type, *Header, std::move(ItemEntries));
+ HeaderRes.setName(ResName);
+ if (Base->MemoryFlags & MfPreload) {
+ HeaderRes.MemoryFlags |= MfPreload;
+ HeaderRes.MemoryFlags &= ~MfPure;
+ }
+ RETURN_IF_ERROR(visitIconOrCursorGroup(&HeaderRes));
+
+ return Error::success();
+}
+
+// --- DialogResource helpers. --- //
+
+Error ResourceFileWriter::writeSingleDialogControl(const Control &Ctl,
+ bool IsExtended) {
+ // Each control should be aligned to DWORD.
+ padStream(sizeof(uint32_t));
+
+ auto TypeInfo = Control::SupportedCtls.lookup(Ctl.Type);
+ IntWithNotMask CtlStyle(TypeInfo.Style);
+ CtlStyle |= Ctl.Style.getValueOr(RCInt(0));
+ uint32_t CtlExtStyle = Ctl.ExtStyle.getValueOr(0);
+
+ // DIALOG(EX) item header prefix.
+ if (!IsExtended) {
+ struct {
+ ulittle32_t Style;
+ ulittle32_t ExtStyle;
+ } Prefix{ulittle32_t(CtlStyle.getValue()), ulittle32_t(CtlExtStyle)};
+ writeObject(Prefix);
+ } else {
+ struct {
+ ulittle32_t HelpID;
+ ulittle32_t ExtStyle;
+ ulittle32_t Style;
+ } Prefix{ulittle32_t(Ctl.HelpID.getValueOr(0)), ulittle32_t(CtlExtStyle),
+ ulittle32_t(CtlStyle.getValue())};
+ writeObject(Prefix);
+ }
+
+ // Common fixed-length part.
+ RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
+ Ctl.X, "Dialog control x-coordinate", true));
+ RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
+ Ctl.Y, "Dialog control y-coordinate", true));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Ctl.Width, "Dialog control width", false));
+ RETURN_IF_ERROR(checkSignedNumberFits<int16_t>(
+ Ctl.Height, "Dialog control height", false));
+ struct {
+ ulittle16_t X;
+ ulittle16_t Y;
+ ulittle16_t Width;
+ ulittle16_t Height;
+ } Middle{ulittle16_t(Ctl.X), ulittle16_t(Ctl.Y), ulittle16_t(Ctl.Width),
+ ulittle16_t(Ctl.Height)};
+ writeObject(Middle);
+
+ // ID; it's 16-bit in DIALOG and 32-bit in DIALOGEX.
+ if (!IsExtended) {
+ // It's common to use -1, i.e. UINT32_MAX, for controls one doesn't
+ // want to refer to later.
+ if (Ctl.ID != static_cast<uint32_t>(-1))
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(
+ Ctl.ID, "Control ID in simple DIALOG resource"));
+ writeInt<uint16_t>(Ctl.ID);
+ } else {
+ writeInt<uint32_t>(Ctl.ID);
+ }
+
+ // Window class - either 0xFFFF + 16-bit integer or a string.
+ RETURN_IF_ERROR(writeIntOrString(Ctl.Class));
+
+ // Element caption/reference ID. ID is preceded by 0xFFFF.
+ RETURN_IF_ERROR(checkIntOrString(Ctl.Title, "Control reference ID"));
+ RETURN_IF_ERROR(writeIntOrString(Ctl.Title));
+
+ // # bytes of extra creation data count. Don't pass any.
+ writeInt<uint16_t>(0);
+
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeDialogBody(const RCResource *Base) {
+ auto *Res = cast<DialogResource>(Base);
+
+ // Default style: WS_POPUP | WS_BORDER | WS_SYSMENU.
+ const uint32_t DefaultStyle = 0x80880000;
+ const uint32_t StyleFontFlag = 0x40;
+ const uint32_t StyleCaptionFlag = 0x00C00000;
+
+ uint32_t UsedStyle = ObjectData.Style.getValueOr(DefaultStyle);
+ if (ObjectData.Font)
+ UsedStyle |= StyleFontFlag;
+ else
+ UsedStyle &= ~StyleFontFlag;
+
+ // Actually, in case of empty (but existent) caption, the examined field
+ // is equal to "\"\"". That's why empty captions are still noticed.
+ if (ObjectData.Caption != "")
+ UsedStyle |= StyleCaptionFlag;
+
+ const uint16_t DialogExMagic = 0xFFFF;
+ uint32_t ExStyle = ObjectData.ExStyle.getValueOr(0);
+
+ // Write DIALOG(EX) header prefix. These are pretty different.
+ if (!Res->IsExtended) {
+ // We cannot let the higher word of DefaultStyle be equal to 0xFFFF.
+ // In such a case, whole object (in .res file) is equivalent to a
+ // DIALOGEX. It might lead to access violation/segmentation fault in
+ // resource readers. For example,
+ // 1 DIALOG 0, 0, 0, 65432
+ // STYLE 0xFFFF0001 {}
+ // would be compiled to a DIALOGEX with 65432 controls.
+ if ((UsedStyle >> 16) == DialogExMagic)
+ return createError("16 higher bits of DIALOG resource style cannot be"
+ " equal to 0xFFFF");
+
+ struct {
+ ulittle32_t Style;
+ ulittle32_t ExtStyle;
+ } Prefix{ulittle32_t(UsedStyle),
+ ulittle32_t(ExStyle)};
+
+ writeObject(Prefix);
+ } else {
+ struct {
+ ulittle16_t Version;
+ ulittle16_t Magic;
+ ulittle32_t HelpID;
+ ulittle32_t ExtStyle;
+ ulittle32_t Style;
+ } Prefix{ulittle16_t(1), ulittle16_t(DialogExMagic),
+ ulittle32_t(Res->HelpID), ulittle32_t(ExStyle), ulittle32_t(UsedStyle)};
+
+ writeObject(Prefix);
+ }
+
+ // Now, a common part. First, fixed-length fields.
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(Res->Controls.size(),
+ "Number of dialog controls"));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Res->X, "Dialog x-coordinate", true));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Res->Y, "Dialog y-coordinate", true));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Res->Width, "Dialog width", false));
+ RETURN_IF_ERROR(
+ checkSignedNumberFits<int16_t>(Res->Height, "Dialog height", false));
+ struct {
+ ulittle16_t Count;
+ ulittle16_t PosX;
+ ulittle16_t PosY;
+ ulittle16_t DialogWidth;
+ ulittle16_t DialogHeight;
+ } Middle{ulittle16_t(Res->Controls.size()), ulittle16_t(Res->X),
+ ulittle16_t(Res->Y), ulittle16_t(Res->Width),
+ ulittle16_t(Res->Height)};
+ writeObject(Middle);
+
+ // MENU field. As of now, we don't keep them in the state and can peacefully
+ // think there is no menu attached to the dialog.
+ writeInt<uint16_t>(0);
+
+ // Window CLASS field.
+ RETURN_IF_ERROR(writeIntOrString(ObjectData.Class));
+
+ // Window title or a single word equal to 0.
+ RETURN_IF_ERROR(writeCString(ObjectData.Caption));
+
+ // If there *is* a window font declared, output its data.
+ auto &Font = ObjectData.Font;
+ if (Font) {
+ writeInt<uint16_t>(Font->Size);
+ // Additional description occurs only in DIALOGEX.
+ if (Res->IsExtended) {
+ writeInt<uint16_t>(Font->Weight);
+ writeInt<uint8_t>(Font->IsItalic);
+ writeInt<uint8_t>(Font->Charset);
+ }
+ RETURN_IF_ERROR(writeCString(Font->Typeface));
+ }
+
+ auto handleCtlError = [&](Error &&Err, const Control &Ctl) -> Error {
+ if (!Err)
+ return Error::success();
+ return joinErrors(createError("Error in " + Twine(Ctl.Type) +
+ " control (ID " + Twine(Ctl.ID) + "):"),
+ std::move(Err));
+ };
+
+ for (auto &Ctl : Res->Controls)
+ RETURN_IF_ERROR(
+ handleCtlError(writeSingleDialogControl(Ctl, Res->IsExtended), Ctl));
+
+ return Error::success();
+}
+
+// --- HTMLResource helpers. --- //
+
+Error ResourceFileWriter::writeHTMLBody(const RCResource *Base) {
+ 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);
+ // Some resource files use -1, i.e. UINT32_MAX, for empty menu items.
+ if (MenuItemPtr->Id != static_cast<uint32_t>(-1))
+ 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
+ writeInt<uint32_t>(0);
+
+ return writeMenuDefinitionList(cast<MenuResource>(Base)->Elements);
+}
+
+// --- StringTableResource helpers. --- //
+
+class BundleResource : public RCResource {
+public:
+ using BundleType = ResourceFileWriter::StringTableInfo::Bundle;
+ BundleType Bundle;
+
+ BundleResource(const BundleType &StrBundle)
+ : RCResource(StrBundle.MemoryFlags), Bundle(StrBundle) {}
+ IntOrString getResourceType() const override { return 6; }
+
+ ResourceKind getKind() const override { return RkStringTableBundle; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkStringTableBundle;
+ }
+ Twine getResourceTypeName() const override { return "STRINGTABLE"; }
+};
+
+Error ResourceFileWriter::visitStringTableBundle(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeStringTableBundleBody);
+}
+
+Error ResourceFileWriter::insertStringIntoBundle(
+ StringTableInfo::Bundle &Bundle, uint16_t StringID,
+ const std::vector<StringRef> &String) {
+ uint16_t StringLoc = StringID & 15;
+ if (Bundle.Data[StringLoc])
+ return createError("Multiple STRINGTABLE strings located under ID " +
+ Twine(StringID));
+ Bundle.Data[StringLoc] = String;
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeStringTableBundleBody(const RCResource *Base) {
+ auto *Res = cast<BundleResource>(Base);
+ for (size_t ID = 0; ID < Res->Bundle.Data.size(); ++ID) {
+ // The string format is a tiny bit different here. We
+ // first output the size of the string, and then the string itself
+ // (which is not null-terminated).
+ SmallVector<UTF16, 128> Data;
+ if (Res->Bundle.Data[ID]) {
+ bool IsLongString;
+ for (StringRef S : *Res->Bundle.Data[ID])
+ RETURN_IF_ERROR(processString(S, NullHandlingMethod::CutAtDoubleNull,
+ IsLongString, Data, Params.CodePage));
+ if (AppendNull)
+ Data.push_back('\0');
+ }
+ RETURN_IF_ERROR(
+ checkNumberFits<uint16_t>(Data.size(), "STRINGTABLE string size"));
+ writeInt<uint16_t>(Data.size());
+ for (auto Char : Data)
+ writeInt(Char);
+ }
+ return Error::success();
+}
+
+Error ResourceFileWriter::dumpAllStringTables() {
+ for (auto Key : StringTableData.BundleList) {
+ auto Iter = StringTableData.BundleData.find(Key);
+ assert(Iter != StringTableData.BundleData.end());
+
+ // For a moment, revert the context info to moment of bundle declaration.
+ ContextKeeper RAII(this);
+ ObjectData = Iter->second.DeclTimeInfo;
+
+ BundleResource Res(Iter->second);
+ // Bundle #(k+1) contains keys [16k, 16k + 15].
+ Res.setName(Key.first + 1);
+ RETURN_IF_ERROR(visitStringTableBundle(&Res));
+ }
+ return Error::success();
+}
+
+// --- UserDefinedResource helpers. --- //
+
+Error ResourceFileWriter::writeUserDefinedBody(const RCResource *Base) {
+ auto *Res = cast<UserDefinedResource>(Base);
+
+ if (Res->IsFileResource)
+ return appendFile(Res->FileLoc);
+
+ for (auto &Elem : Res->Contents) {
+ if (Elem.isInt()) {
+ RETURN_IF_ERROR(
+ checkRCInt(Elem.getInt(), "Number in user-defined resource"));
+ writeRCInt(Elem.getInt());
+ continue;
+ }
+
+ SmallVector<UTF16, 128> ProcessedString;
+ bool IsLongString;
+ RETURN_IF_ERROR(
+ processString(Elem.getString(), NullHandlingMethod::UserResource,
+ IsLongString, ProcessedString, Params.CodePage));
+
+ for (auto Ch : ProcessedString) {
+ if (IsLongString) {
+ writeInt(Ch);
+ continue;
+ }
+
+ RETURN_IF_ERROR(checkNumberFits<uint8_t>(
+ Ch, "Character in narrow string in user-defined resource"));
+ writeInt<uint8_t>(Ch);
+ }
+ }
+
+ return Error::success();
+}
+
+// --- VersionInfoResourceResource helpers. --- //
+
+Error ResourceFileWriter::writeVersionInfoBlock(const VersionInfoBlock &Blk) {
+ // Output the header if the block has name.
+ bool OutputHeader = Blk.Name != "";
+ uint64_t LengthLoc;
+
+ padStream(sizeof(uint32_t));
+ if (OutputHeader) {
+ LengthLoc = writeInt<uint16_t>(0);
+ writeInt<uint16_t>(0);
+ writeInt<uint16_t>(1); // true
+ RETURN_IF_ERROR(writeCString(Blk.Name));
+ padStream(sizeof(uint32_t));
+ }
+
+ for (const std::unique_ptr<VersionInfoStmt> &Item : Blk.Stmts) {
+ VersionInfoStmt *ItemPtr = Item.get();
+
+ if (auto *BlockPtr = dyn_cast<VersionInfoBlock>(ItemPtr)) {
+ RETURN_IF_ERROR(writeVersionInfoBlock(*BlockPtr));
+ continue;
+ }
+
+ auto *ValuePtr = cast<VersionInfoValue>(ItemPtr);
+ RETURN_IF_ERROR(writeVersionInfoValue(*ValuePtr));
+ }
+
+ if (OutputHeader) {
+ uint64_t CurLoc = tell();
+ writeObjectAt(ulittle16_t(CurLoc - LengthLoc), LengthLoc);
+ }
+
+ return Error::success();
+}
+
+Error ResourceFileWriter::writeVersionInfoValue(const VersionInfoValue &Val) {
+ // rc has a peculiar algorithm to output VERSIONINFO VALUEs. Each VALUE
+ // is a mapping from the key (string) to the value (a sequence of ints or
+ // a sequence of strings).
+ //
+ // If integers are to be written: width of each integer written depends on
+ // whether it's been declared 'long' (it's DWORD then) or not (it's WORD).
+ // ValueLength defined in structure referenced below is then the total
+ // number of bytes taken by these integers.
+ //
+ // If strings are to be written: characters are always WORDs.
+ // Moreover, '\0' character is written after the last string, and between
+ // every two strings separated by comma (if strings are not comma-separated,
+ // they're simply concatenated). ValueLength is equal to the number of WORDs
+ // written (that is, half of the bytes written).
+ //
+ // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms646994.aspx
+ bool HasStrings = false, HasInts = false;
+ for (auto &Item : Val.Values)
+ (Item.isInt() ? HasInts : HasStrings) = true;
+
+ assert((HasStrings || HasInts) && "VALUE must have at least one argument");
+ if (HasStrings && HasInts)
+ return createError(Twine("VALUE ") + Val.Key +
+ " cannot contain both strings and integers");
+
+ padStream(sizeof(uint32_t));
+ auto LengthLoc = writeInt<uint16_t>(0);
+ auto ValLengthLoc = writeInt<uint16_t>(0);
+ writeInt<uint16_t>(HasStrings);
+ RETURN_IF_ERROR(writeCString(Val.Key));
+ padStream(sizeof(uint32_t));
+
+ auto DataLoc = tell();
+ for (size_t Id = 0; Id < Val.Values.size(); ++Id) {
+ auto &Item = Val.Values[Id];
+ if (Item.isInt()) {
+ auto Value = Item.getInt();
+ RETURN_IF_ERROR(checkRCInt(Value, "VERSIONINFO integer value"));
+ writeRCInt(Value);
+ continue;
+ }
+
+ bool WriteTerminator =
+ Id == Val.Values.size() - 1 || Val.HasPrecedingComma[Id + 1];
+ RETURN_IF_ERROR(writeCString(Item.getString(), WriteTerminator));
+ }
+
+ auto CurLoc = tell();
+ auto ValueLength = CurLoc - DataLoc;
+ if (HasStrings) {
+ assert(ValueLength % 2 == 0);
+ ValueLength /= 2;
+ }
+ writeObjectAt(ulittle16_t(CurLoc - LengthLoc), LengthLoc);
+ writeObjectAt(ulittle16_t(ValueLength), ValLengthLoc);
+ return Error::success();
+}
+
+template <typename Ty>
+static Ty getWithDefault(const StringMap<Ty> &Map, StringRef Key,
+ const Ty &Default) {
+ auto Iter = Map.find(Key);
+ if (Iter != Map.end())
+ return Iter->getValue();
+ return Default;
+}
+
+Error ResourceFileWriter::writeVersionInfoBody(const RCResource *Base) {
+ auto *Res = cast<VersionInfoResource>(Base);
+
+ const auto &FixedData = Res->FixedData;
+
+ struct /* VS_FIXEDFILEINFO */ {
+ ulittle32_t Signature = ulittle32_t(0xFEEF04BD);
+ ulittle32_t StructVersion = ulittle32_t(0x10000);
+ // It's weird to have most-significant DWORD first on the little-endian
+ // machines, but let it be this way.
+ ulittle32_t FileVersionMS;
+ ulittle32_t FileVersionLS;
+ ulittle32_t ProductVersionMS;
+ ulittle32_t ProductVersionLS;
+ ulittle32_t FileFlagsMask;
+ ulittle32_t FileFlags;
+ ulittle32_t FileOS;
+ ulittle32_t FileType;
+ ulittle32_t FileSubtype;
+ // MS implementation seems to always set these fields to 0.
+ ulittle32_t FileDateMS = ulittle32_t(0);
+ ulittle32_t FileDateLS = ulittle32_t(0);
+ } FixedInfo;
+
+ // First, VS_VERSIONINFO.
+ auto LengthLoc = writeInt<uint16_t>(0);
+ writeInt<uint16_t>(sizeof(FixedInfo));
+ writeInt<uint16_t>(0);
+ cantFail(writeCString("VS_VERSION_INFO"));
+ padStream(sizeof(uint32_t));
+
+ using VersionInfoFixed = VersionInfoResource::VersionInfoFixed;
+ auto GetField = [&](VersionInfoFixed::VersionInfoFixedType Type) {
+ static const SmallVector<uint32_t, 4> DefaultOut{0, 0, 0, 0};
+ if (!FixedData.IsTypePresent[(int)Type])
+ return DefaultOut;
+ return FixedData.FixedInfo[(int)Type];
+ };
+
+ auto FileVer = GetField(VersionInfoFixed::FtFileVersion);
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(
+ *std::max_element(FileVer.begin(), FileVer.end()), "FILEVERSION fields"));
+ FixedInfo.FileVersionMS = (FileVer[0] << 16) | FileVer[1];
+ FixedInfo.FileVersionLS = (FileVer[2] << 16) | FileVer[3];
+
+ auto ProdVer = GetField(VersionInfoFixed::FtProductVersion);
+ RETURN_IF_ERROR(checkNumberFits<uint16_t>(
+ *std::max_element(ProdVer.begin(), ProdVer.end()),
+ "PRODUCTVERSION fields"));
+ FixedInfo.ProductVersionMS = (ProdVer[0] << 16) | ProdVer[1];
+ FixedInfo.ProductVersionLS = (ProdVer[2] << 16) | ProdVer[3];
+
+ FixedInfo.FileFlagsMask = GetField(VersionInfoFixed::FtFileFlagsMask)[0];
+ FixedInfo.FileFlags = GetField(VersionInfoFixed::FtFileFlags)[0];
+ FixedInfo.FileOS = GetField(VersionInfoFixed::FtFileOS)[0];
+ FixedInfo.FileType = GetField(VersionInfoFixed::FtFileType)[0];
+ FixedInfo.FileSubtype = GetField(VersionInfoFixed::FtFileSubtype)[0];
+
+ writeObject(FixedInfo);
+ padStream(sizeof(uint32_t));
+
+ RETURN_IF_ERROR(writeVersionInfoBlock(Res->MainBlock));
+
+ // FIXME: check overflow?
+ writeObjectAt(ulittle16_t(tell() - LengthLoc), LengthLoc);
+
+ return Error::success();
+}
+
+Expected<std::unique_ptr<MemoryBuffer>>
+ResourceFileWriter::loadFile(StringRef File) const {
+ SmallString<128> Path;
+ SmallString<128> Cwd;
+ std::unique_ptr<MemoryBuffer> Result;
+
// 0. The file path is absolute or has a root directory, so we shouldn't
// try to append it on top of other base directories. (An absolute path
// must have a root directory, but e.g. the path "\dir\file" on windows
@@ -1524,38 +1524,38 @@ ResourceFileWriter::loadFile(StringRef File) const {
// properly though, so if using that to append paths below, this early
// exception case could be removed.)
if (sys::path::has_root_directory(File))
- return errorOrToExpected(MemoryBuffer::getFile(File, -1, false));
-
- // 1. The current working directory.
- sys::fs::current_path(Cwd);
- Path.assign(Cwd.begin(), Cwd.end());
- sys::path::append(Path, File);
- if (sys::fs::exists(Path))
- return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
-
- // 2. The directory of the input resource file, if it is different from the
- // current working directory.
- StringRef InputFileDir = sys::path::parent_path(Params.InputFilePath);
- Path.assign(InputFileDir.begin(), InputFileDir.end());
- sys::path::append(Path, File);
- if (sys::fs::exists(Path))
- return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
-
- // 3. All of the include directories specified on the command line.
- for (StringRef ForceInclude : Params.Include) {
- Path.assign(ForceInclude.begin(), ForceInclude.end());
- sys::path::append(Path, File);
- if (sys::fs::exists(Path))
- return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
- }
-
- if (auto Result =
- llvm::sys::Process::FindInEnvPath("INCLUDE", File, Params.NoInclude))
- return errorOrToExpected(MemoryBuffer::getFile(*Result, -1, false));
-
- return make_error<StringError>("error : file not found : " + Twine(File),
- inconvertibleErrorCode());
-}
-
-} // namespace rc
-} // namespace llvm
+ return errorOrToExpected(MemoryBuffer::getFile(File, -1, false));
+
+ // 1. The current working directory.
+ sys::fs::current_path(Cwd);
+ Path.assign(Cwd.begin(), Cwd.end());
+ sys::path::append(Path, File);
+ if (sys::fs::exists(Path))
+ return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
+
+ // 2. The directory of the input resource file, if it is different from the
+ // current working directory.
+ StringRef InputFileDir = sys::path::parent_path(Params.InputFilePath);
+ Path.assign(InputFileDir.begin(), InputFileDir.end());
+ sys::path::append(Path, File);
+ if (sys::fs::exists(Path))
+ return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
+
+ // 3. All of the include directories specified on the command line.
+ for (StringRef ForceInclude : Params.Include) {
+ Path.assign(ForceInclude.begin(), ForceInclude.end());
+ sys::path::append(Path, File);
+ if (sys::fs::exists(Path))
+ return errorOrToExpected(MemoryBuffer::getFile(Path, -1, false));
+ }
+
+ if (auto Result =
+ llvm::sys::Process::FindInEnvPath("INCLUDE", File, Params.NoInclude))
+ return errorOrToExpected(MemoryBuffer::getFile(*Result, -1, false));
+
+ return make_error<StringError>("error : file not found : " + Twine(File),
+ inconvertibleErrorCode());
+}
+
+} // namespace rc
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h
index a8802d2220..d545a7a9ca 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceFileWriter.h
@@ -1,217 +1,217 @@
-//===-- ResourceSerializator.h ----------------------------------*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This defines a visitor serializing resources to a .res stream.
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H
-
-#include "ResourceScriptStmt.h"
-#include "ResourceVisitor.h"
-
-#include "llvm/Support/Endian.h"
-
-namespace llvm {
-
-class MemoryBuffer;
-
-namespace rc {
-
-enum CodePage {
- CpAcp = 0, // The current used codepage. Since there's no such
- // notion in LLVM what codepage it actually means,
- // this only allows ASCII.
- CpWin1252 = 1252, // A codepage where most 8 bit values correspond to
- // unicode code points with the same value.
- CpUtf8 = 65001, // UTF-8.
-};
-
-struct WriterParams {
- std::vector<std::string> Include; // Additional folders to search for files.
- std::vector<std::string> NoInclude; // Folders to exclude from file search.
- StringRef InputFilePath; // The full path of the input file.
- int CodePage = CpAcp; // The codepage for interpreting characters.
-};
-
-class ResourceFileWriter : public Visitor {
-public:
- ResourceFileWriter(const WriterParams &Params,
- std::unique_ptr<raw_fd_ostream> Stream)
- : Params(Params), FS(std::move(Stream)), IconCursorID(1) {
- assert(FS && "Output stream needs to be provided to the serializator");
- }
-
- Error visitNullResource(const RCResource *) override;
- Error visitAcceleratorsResource(const RCResource *) override;
- Error visitCursorResource(const RCResource *) override;
- Error visitDialogResource(const RCResource *) override;
- Error visitHTMLResource(const RCResource *) override;
- Error visitIconResource(const RCResource *) override;
- Error visitMenuResource(const RCResource *) override;
- Error visitVersionInfoResource(const RCResource *) override;
- Error visitStringTableResource(const RCResource *) override;
- Error visitUserDefinedResource(const RCResource *) override;
-
- Error visitCaptionStmt(const CaptionStmt *) override;
- Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
- Error visitClassStmt(const ClassStmt *) override;
- Error visitExStyleStmt(const ExStyleStmt *) override;
- Error visitFontStmt(const FontStmt *) override;
- Error visitLanguageStmt(const LanguageResource *) override;
- Error visitStyleStmt(const StyleStmt *) override;
- Error visitVersionStmt(const VersionStmt *) override;
-
- // Stringtables are output at the end of .res file. We need a separate
- // function to do it.
- Error dumpAllStringTables();
-
- bool AppendNull = false; // Append '\0' to each existing STRINGTABLE element?
-
- struct ObjectInfo {
- uint16_t LanguageInfo;
- uint32_t Characteristics;
- uint32_t VersionInfo;
-
- Optional<uint32_t> Style;
- Optional<uint32_t> ExStyle;
- StringRef Caption;
- struct FontInfo {
- uint32_t Size;
- StringRef Typeface;
- uint32_t Weight;
- bool IsItalic;
- uint32_t Charset;
- };
- Optional<FontInfo> Font;
- IntOrString Class;
-
- ObjectInfo()
- : LanguageInfo(0), Characteristics(0), VersionInfo(0),
- Class(StringRef()) {}
- } ObjectData;
-
- struct StringTableInfo {
- // Each STRINGTABLE bundle depends on ID of the bundle and language
- // description.
- using BundleKey = std::pair<uint16_t, uint16_t>;
- // Each bundle is in fact an array of 16 strings.
- struct Bundle {
- std::array<Optional<std::vector<StringRef>>, 16> Data;
- ObjectInfo DeclTimeInfo;
- uint16_t MemoryFlags;
- Bundle(const ObjectInfo &Info, uint16_t Flags)
- : DeclTimeInfo(Info), MemoryFlags(Flags) {}
- };
- std::map<BundleKey, Bundle> BundleData;
- // Bundles are listed in the order of their first occurrence.
- std::vector<BundleKey> BundleList;
- } StringTableData;
-
-private:
- Error handleError(Error Err, const RCResource *Res);
-
- Error
- writeResource(const RCResource *Res,
- Error (ResourceFileWriter::*BodyWriter)(const RCResource *));
-
- // NullResource
- Error writeNullBody(const RCResource *);
-
- // AcceleratorsResource
- Error writeSingleAccelerator(const AcceleratorsResource::Accelerator &,
- bool IsLastItem);
- Error writeAcceleratorsBody(const RCResource *);
-
- // BitmapResource
- Error visitBitmapResource(const RCResource *) override;
- Error writeBitmapBody(const RCResource *);
-
- // CursorResource and IconResource
- Error visitIconOrCursorResource(const RCResource *);
- Error visitIconOrCursorGroup(const RCResource *);
- Error visitSingleIconOrCursor(const RCResource *);
- Error writeSingleIconOrCursorBody(const RCResource *);
- Error writeIconOrCursorGroupBody(const RCResource *);
-
- // DialogResource
- Error writeSingleDialogControl(const Control &, bool IsExtended);
- Error writeDialogBody(const RCResource *);
-
- // 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 *);
-
- // StringTableResource
- Error visitStringTableBundle(const RCResource *);
- Error writeStringTableBundleBody(const RCResource *);
- Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle,
- uint16_t StringID,
- const std::vector<StringRef> &String);
-
- // User defined resource
- Error writeUserDefinedBody(const RCResource *);
-
- // VersionInfoResource
- Error writeVersionInfoBody(const RCResource *);
- Error writeVersionInfoBlock(const VersionInfoBlock &);
- Error writeVersionInfoValue(const VersionInfoValue &);
-
- const WriterParams &Params;
-
- // Output stream handling.
- std::unique_ptr<raw_fd_ostream> FS;
-
- uint64_t tell() const { return FS->tell(); }
-
- uint64_t writeObject(const ArrayRef<uint8_t> Data);
-
- template <typename T> uint64_t writeInt(const T &Value) {
- support::detail::packed_endian_specific_integral<T, support::little,
- support::unaligned>
- Object(Value);
- return writeObject(Object);
- }
-
- template <typename T> uint64_t writeObject(const T &Value) {
- return writeObject(ArrayRef<uint8_t>(
- reinterpret_cast<const uint8_t *>(&Value), sizeof(T)));
- }
-
- template <typename T> void writeObjectAt(const T &Value, uint64_t Position) {
- FS->pwrite((const char *)&Value, sizeof(T), Position);
- }
-
- Error writeCString(StringRef Str, bool WriteTerminator = true);
-
- Error writeIdentifier(const IntOrString &Ident);
- Error writeIntOrString(const IntOrString &Data);
-
- void writeRCInt(RCInt);
-
- Error appendFile(StringRef Filename);
-
- void padStream(uint64_t Length);
-
- Expected<std::unique_ptr<MemoryBuffer>> loadFile(StringRef File) const;
-
- // Icon and cursor IDs are allocated starting from 1 and increasing for
- // each icon/cursor dumped. This maintains the current ID to be allocated.
- uint16_t IconCursorID;
-};
-
-} // namespace rc
-} // namespace llvm
-
-#endif
+//===-- ResourceSerializator.h ----------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This defines a visitor serializing resources to a .res stream.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H
+
+#include "ResourceScriptStmt.h"
+#include "ResourceVisitor.h"
+
+#include "llvm/Support/Endian.h"
+
+namespace llvm {
+
+class MemoryBuffer;
+
+namespace rc {
+
+enum CodePage {
+ CpAcp = 0, // The current used codepage. Since there's no such
+ // notion in LLVM what codepage it actually means,
+ // this only allows ASCII.
+ CpWin1252 = 1252, // A codepage where most 8 bit values correspond to
+ // unicode code points with the same value.
+ CpUtf8 = 65001, // UTF-8.
+};
+
+struct WriterParams {
+ std::vector<std::string> Include; // Additional folders to search for files.
+ std::vector<std::string> NoInclude; // Folders to exclude from file search.
+ StringRef InputFilePath; // The full path of the input file.
+ int CodePage = CpAcp; // The codepage for interpreting characters.
+};
+
+class ResourceFileWriter : public Visitor {
+public:
+ ResourceFileWriter(const WriterParams &Params,
+ std::unique_ptr<raw_fd_ostream> Stream)
+ : Params(Params), FS(std::move(Stream)), IconCursorID(1) {
+ assert(FS && "Output stream needs to be provided to the serializator");
+ }
+
+ Error visitNullResource(const RCResource *) override;
+ Error visitAcceleratorsResource(const RCResource *) override;
+ Error visitCursorResource(const RCResource *) override;
+ Error visitDialogResource(const RCResource *) override;
+ Error visitHTMLResource(const RCResource *) override;
+ Error visitIconResource(const RCResource *) override;
+ Error visitMenuResource(const RCResource *) override;
+ Error visitVersionInfoResource(const RCResource *) override;
+ Error visitStringTableResource(const RCResource *) override;
+ Error visitUserDefinedResource(const RCResource *) override;
+
+ Error visitCaptionStmt(const CaptionStmt *) override;
+ Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
+ Error visitClassStmt(const ClassStmt *) override;
+ Error visitExStyleStmt(const ExStyleStmt *) override;
+ Error visitFontStmt(const FontStmt *) override;
+ Error visitLanguageStmt(const LanguageResource *) override;
+ Error visitStyleStmt(const StyleStmt *) override;
+ Error visitVersionStmt(const VersionStmt *) override;
+
+ // Stringtables are output at the end of .res file. We need a separate
+ // function to do it.
+ Error dumpAllStringTables();
+
+ bool AppendNull = false; // Append '\0' to each existing STRINGTABLE element?
+
+ struct ObjectInfo {
+ uint16_t LanguageInfo;
+ uint32_t Characteristics;
+ uint32_t VersionInfo;
+
+ Optional<uint32_t> Style;
+ Optional<uint32_t> ExStyle;
+ StringRef Caption;
+ struct FontInfo {
+ uint32_t Size;
+ StringRef Typeface;
+ uint32_t Weight;
+ bool IsItalic;
+ uint32_t Charset;
+ };
+ Optional<FontInfo> Font;
+ IntOrString Class;
+
+ ObjectInfo()
+ : LanguageInfo(0), Characteristics(0), VersionInfo(0),
+ Class(StringRef()) {}
+ } ObjectData;
+
+ struct StringTableInfo {
+ // Each STRINGTABLE bundle depends on ID of the bundle and language
+ // description.
+ using BundleKey = std::pair<uint16_t, uint16_t>;
+ // Each bundle is in fact an array of 16 strings.
+ struct Bundle {
+ std::array<Optional<std::vector<StringRef>>, 16> Data;
+ ObjectInfo DeclTimeInfo;
+ uint16_t MemoryFlags;
+ Bundle(const ObjectInfo &Info, uint16_t Flags)
+ : DeclTimeInfo(Info), MemoryFlags(Flags) {}
+ };
+ std::map<BundleKey, Bundle> BundleData;
+ // Bundles are listed in the order of their first occurrence.
+ std::vector<BundleKey> BundleList;
+ } StringTableData;
+
+private:
+ Error handleError(Error Err, const RCResource *Res);
+
+ Error
+ writeResource(const RCResource *Res,
+ Error (ResourceFileWriter::*BodyWriter)(const RCResource *));
+
+ // NullResource
+ Error writeNullBody(const RCResource *);
+
+ // AcceleratorsResource
+ Error writeSingleAccelerator(const AcceleratorsResource::Accelerator &,
+ bool IsLastItem);
+ Error writeAcceleratorsBody(const RCResource *);
+
+ // BitmapResource
+ Error visitBitmapResource(const RCResource *) override;
+ Error writeBitmapBody(const RCResource *);
+
+ // CursorResource and IconResource
+ Error visitIconOrCursorResource(const RCResource *);
+ Error visitIconOrCursorGroup(const RCResource *);
+ Error visitSingleIconOrCursor(const RCResource *);
+ Error writeSingleIconOrCursorBody(const RCResource *);
+ Error writeIconOrCursorGroupBody(const RCResource *);
+
+ // DialogResource
+ Error writeSingleDialogControl(const Control &, bool IsExtended);
+ Error writeDialogBody(const RCResource *);
+
+ // 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 *);
+
+ // StringTableResource
+ Error visitStringTableBundle(const RCResource *);
+ Error writeStringTableBundleBody(const RCResource *);
+ Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle,
+ uint16_t StringID,
+ const std::vector<StringRef> &String);
+
+ // User defined resource
+ Error writeUserDefinedBody(const RCResource *);
+
+ // VersionInfoResource
+ Error writeVersionInfoBody(const RCResource *);
+ Error writeVersionInfoBlock(const VersionInfoBlock &);
+ Error writeVersionInfoValue(const VersionInfoValue &);
+
+ const WriterParams &Params;
+
+ // Output stream handling.
+ std::unique_ptr<raw_fd_ostream> FS;
+
+ uint64_t tell() const { return FS->tell(); }
+
+ uint64_t writeObject(const ArrayRef<uint8_t> Data);
+
+ template <typename T> uint64_t writeInt(const T &Value) {
+ support::detail::packed_endian_specific_integral<T, support::little,
+ support::unaligned>
+ Object(Value);
+ return writeObject(Object);
+ }
+
+ template <typename T> uint64_t writeObject(const T &Value) {
+ return writeObject(ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(&Value), sizeof(T)));
+ }
+
+ template <typename T> void writeObjectAt(const T &Value, uint64_t Position) {
+ FS->pwrite((const char *)&Value, sizeof(T), Position);
+ }
+
+ Error writeCString(StringRef Str, bool WriteTerminator = true);
+
+ Error writeIdentifier(const IntOrString &Ident);
+ Error writeIntOrString(const IntOrString &Data);
+
+ void writeRCInt(RCInt);
+
+ Error appendFile(StringRef Filename);
+
+ void padStream(uint64_t Length);
+
+ Expected<std::unique_ptr<MemoryBuffer>> loadFile(StringRef File) const;
+
+ // Icon and cursor IDs are allocated starting from 1 and increasing for
+ // each icon/cursor dumped. This maintains the current ID to be allocated.
+ uint16_t IconCursorID;
+};
+
+} // namespace rc
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp
index 826b212db9..e610be99df 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.cpp
@@ -1,111 +1,111 @@
-//===-- ResourceScriptCppFilter.cpp ----------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This file implements an interface defined in ResourceScriptCppFilter.h.
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceScriptCppFilter.h"
-#include "llvm/ADT/StringExtras.h"
-
-#include <vector>
-
-using namespace llvm;
-
-namespace {
-
-class Filter {
-public:
- explicit Filter(StringRef Input) : Data(Input), DataLength(Input.size()) {}
-
- std::string run();
-
-private:
- // Parse the line, returning whether the line should be included in
- // the output.
- bool parseLine(StringRef Line);
-
- bool streamEof() const;
-
- StringRef Data;
- size_t DataLength;
-
- size_t Pos = 0;
- bool Outputting = true;
-};
-
-std::string Filter::run() {
- std::vector<StringRef> Output;
-
- while (!streamEof() && Pos != StringRef::npos) {
- size_t LineStart = Pos;
- Pos = Data.find_first_of("\r\n", Pos);
- Pos = Data.find_first_not_of("\r\n", Pos);
- StringRef Line = Data.take_front(Pos).drop_front(LineStart);
-
- if (parseLine(Line))
- Output.push_back(Line);
- }
-
- return llvm::join(Output, "");
-}
-
-bool Filter::parseLine(StringRef Line) {
- Line = Line.ltrim();
-
- if (!Line.consume_front("#")) {
- // A normal content line, filtered according to the current mode.
- return Outputting;
- }
-
- // Found a preprocessing directive line. From here on, we always return
- // false since the preprocessing directives should be filtered out.
-
- Line.consume_front("line");
- if (!Line.startswith(" "))
- return false; // Not a line directive (pragma etc).
-
- // #line 123 "path/file.h"
- // # 123 "path/file.h" 1
-
- Line =
- Line.ltrim(); // There could be multiple spaces after the #line directive
-
- size_t N;
- if (Line.consumeInteger(10, N)) // Returns true to signify an error
- return false;
-
- Line = Line.ltrim();
-
- if (!Line.consume_front("\""))
- return false; // Malformed line, no quote found.
-
- // Split the string at the last quote (in case the path name had
- // escaped quotes as well).
- Line = Line.rsplit('"').first;
-
- StringRef Ext = Line.rsplit('.').second;
-
- if (Ext.equals_lower("h") || Ext.equals_lower("c")) {
- Outputting = false;
- } else {
- Outputting = true;
- }
-
- return false;
-}
-
-bool Filter::streamEof() const { return Pos == DataLength; }
-
-} // anonymous namespace
-
-namespace llvm {
-
-std::string filterCppOutput(StringRef Input) { return Filter(Input).run(); }
-
-} // namespace llvm
+//===-- ResourceScriptCppFilter.cpp ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file implements an interface defined in ResourceScriptCppFilter.h.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceScriptCppFilter.h"
+#include "llvm/ADT/StringExtras.h"
+
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+class Filter {
+public:
+ explicit Filter(StringRef Input) : Data(Input), DataLength(Input.size()) {}
+
+ std::string run();
+
+private:
+ // Parse the line, returning whether the line should be included in
+ // the output.
+ bool parseLine(StringRef Line);
+
+ bool streamEof() const;
+
+ StringRef Data;
+ size_t DataLength;
+
+ size_t Pos = 0;
+ bool Outputting = true;
+};
+
+std::string Filter::run() {
+ std::vector<StringRef> Output;
+
+ while (!streamEof() && Pos != StringRef::npos) {
+ size_t LineStart = Pos;
+ Pos = Data.find_first_of("\r\n", Pos);
+ Pos = Data.find_first_not_of("\r\n", Pos);
+ StringRef Line = Data.take_front(Pos).drop_front(LineStart);
+
+ if (parseLine(Line))
+ Output.push_back(Line);
+ }
+
+ return llvm::join(Output, "");
+}
+
+bool Filter::parseLine(StringRef Line) {
+ Line = Line.ltrim();
+
+ if (!Line.consume_front("#")) {
+ // A normal content line, filtered according to the current mode.
+ return Outputting;
+ }
+
+ // Found a preprocessing directive line. From here on, we always return
+ // false since the preprocessing directives should be filtered out.
+
+ Line.consume_front("line");
+ if (!Line.startswith(" "))
+ return false; // Not a line directive (pragma etc).
+
+ // #line 123 "path/file.h"
+ // # 123 "path/file.h" 1
+
+ Line =
+ Line.ltrim(); // There could be multiple spaces after the #line directive
+
+ size_t N;
+ if (Line.consumeInteger(10, N)) // Returns true to signify an error
+ return false;
+
+ Line = Line.ltrim();
+
+ if (!Line.consume_front("\""))
+ return false; // Malformed line, no quote found.
+
+ // Split the string at the last quote (in case the path name had
+ // escaped quotes as well).
+ Line = Line.rsplit('"').first;
+
+ StringRef Ext = Line.rsplit('.').second;
+
+ if (Ext.equals_lower("h") || Ext.equals_lower("c")) {
+ Outputting = false;
+ } else {
+ Outputting = true;
+ }
+
+ return false;
+}
+
+bool Filter::streamEof() const { return Pos == DataLength; }
+
+} // anonymous namespace
+
+namespace llvm {
+
+std::string filterCppOutput(StringRef Input) { return Filter(Input).run(); }
+
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h
index 754dace070..780db317c9 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptCppFilter.h
@@ -1,34 +1,34 @@
-//===-- ResourceScriptCppFilter.h ------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This filters the input to llvm-rc for preprocessor markers, removing
-// preprocessing directives that a preprocessor can output or leave behind.
-//
-// It also filters out any contribution from files named *.h or *.c, based
-// on preprocessor line markers. When preprocessing RC files, the included
-// headers can leave behind C declarations, that RC doesn't understand.
-// Rc.exe simply discards anything that comes from files named *.h or *.h.
-//
-// https://msdn.microsoft.com/en-us/library/windows/desktop/aa381033(v=vs.85).aspx
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTCPPFILTER_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTCPPFILTER_H
-
-#include "llvm/ADT/StringRef.h"
-
-#include <string>
-
-namespace llvm {
-
-std::string filterCppOutput(StringRef Input);
-
-} // namespace llvm
-
-#endif
+//===-- ResourceScriptCppFilter.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This filters the input to llvm-rc for preprocessor markers, removing
+// preprocessing directives that a preprocessor can output or leave behind.
+//
+// It also filters out any contribution from files named *.h or *.c, based
+// on preprocessor line markers. When preprocessing RC files, the included
+// headers can leave behind C declarations, that RC doesn't understand.
+// Rc.exe simply discards anything that comes from files named *.h or *.h.
+//
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa381033(v=vs.85).aspx
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTCPPFILTER_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTCPPFILTER_H
+
+#include "llvm/ADT/StringRef.h"
+
+#include <string>
+
+namespace llvm {
+
+std::string filterCppOutput(StringRef Input);
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp
index 1dbfc5e8bf..5141ac0c38 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.cpp
@@ -1,857 +1,857 @@
-//===-- ResourceScriptParser.cpp --------------------------------*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This implements the parser defined in ResourceScriptParser.h.
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceScriptParser.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-
-// Take an expression returning llvm::Error and forward the error if it exists.
-#define RETURN_IF_ERROR(Expr) \
- if (auto Err = (Expr)) \
- return std::move(Err);
-
-// Take an expression returning llvm::Expected<T> and assign it to Var or
-// forward the error out of the function.
-#define ASSIGN_OR_RETURN(Var, Expr) \
- auto Var = (Expr); \
- if (!Var) \
- return Var.takeError();
-
-namespace llvm {
-namespace rc {
-
-RCParser::ParserError::ParserError(const Twine &Expected, const LocIter CurLoc,
- const LocIter End)
- : ErrorLoc(CurLoc), FileEnd(End) {
- CurMessage = "Error parsing file: expected " + Expected.str() + ", got " +
- (CurLoc == End ? "<EOF>" : CurLoc->value()).str();
-}
-
-char RCParser::ParserError::ID = 0;
-
-RCParser::RCParser(std::vector<RCToken> TokenList)
- : Tokens(std::move(TokenList)), CurLoc(Tokens.begin()), End(Tokens.end()) {}
-
-bool RCParser::isEof() const { return CurLoc == End; }
-
-RCParser::ParseType RCParser::parseSingleResource() {
- // The first thing we read is usually a resource's name. However, in some
- // cases (LANGUAGE and STRINGTABLE) the resources don't have their names
- // and the first token to be read is the type.
- ASSIGN_OR_RETURN(NameToken, readTypeOrName());
-
- if (NameToken->equalsLower("LANGUAGE"))
- return parseLanguageResource();
- else if (NameToken->equalsLower("STRINGTABLE"))
- return parseStringTableResource();
-
- // If it's not an unnamed resource, what we've just read is a name. Now,
- // read resource type;
- ASSIGN_OR_RETURN(TypeToken, readTypeOrName());
-
- ParseType Result = std::unique_ptr<RCResource>();
- (void)!Result;
-
- if (TypeToken->equalsLower("ACCELERATORS"))
- Result = parseAcceleratorsResource();
- else if (TypeToken->equalsLower("BITMAP"))
- Result = parseBitmapResource();
- 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("HTML"))
- Result = parseHTMLResource();
- else if (TypeToken->equalsLower("ICON"))
- Result = parseIconResource();
- else if (TypeToken->equalsLower("MENU"))
- Result = parseMenuResource();
- else if (TypeToken->equalsLower("RCDATA"))
- Result = parseUserDefinedResource(RkRcData);
- else if (TypeToken->equalsLower("VERSIONINFO"))
- Result = parseVersionInfoResource();
- else
- Result = parseUserDefinedResource(*TypeToken);
-
- if (Result)
- (*Result)->setName(*NameToken);
-
- return Result;
-}
-
-bool RCParser::isNextTokenKind(Kind TokenKind) const {
- return !isEof() && look().kind() == TokenKind;
-}
-
-const RCToken &RCParser::look() const {
- assert(!isEof());
- return *CurLoc;
-}
-
-const RCToken &RCParser::read() {
- assert(!isEof());
- return *CurLoc++;
-}
-
-void RCParser::consume() {
- assert(!isEof());
- CurLoc++;
-}
-
-// An integer description might consist of a single integer or
-// an arithmetic expression evaluating to the integer. The expressions
-// can contain the following tokens: <int> ( ) + - | & ~ not. Their meaning
-// is the same as in C++ except for 'not' expression.
-// The operators in the original RC implementation have the following
-// precedence:
-// 1) Unary operators (- ~ not),
-// 2) Binary operators (+ - & |), with no precedence.
-//
-// 'not' expression is mostly useful for style values. It evaluates to 0,
-// but value given to the operator is stored separately from integer value.
-// It's mostly useful for control style expressions and causes bits from
-// default control style to be excluded from generated style. For binary
-// operators the mask from the right operand is applied to the left operand
-// and masks from both operands are combined in operator result.
-//
-// The following grammar is used to parse the expressions Exp1:
-// Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2
-// Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
-// (More conveniently, Exp1 is a non-empty sequence of Exp2 expressions,
-// separated by binary operators.)
-//
-// Expressions of type Exp1 are read by parseIntExpr1(Inner) method, while Exp2
-// is read by parseIntExpr2().
-//
-// The original Microsoft tool handles multiple unary operators incorrectly.
-// For example, in 16-bit little-endian integers:
-// 1 => 01 00, -1 => ff ff, --1 => ff ff, ---1 => 01 00;
-// 1 => 01 00, ~1 => fe ff, ~~1 => fd ff, ~~~1 => fc ff.
-// Our implementation differs from the original one and handles these
-// operators correctly:
-// 1 => 01 00, -1 => ff ff, --1 => 01 00, ---1 => ff ff;
-// 1 => 01 00, ~1 => fe ff, ~~1 => 01 00, ~~~1 => fe ff.
-
-Expected<RCInt> RCParser::readInt() {
- ASSIGN_OR_RETURN(Value, parseIntExpr1());
- return (*Value).getValue();
-}
-
-Expected<IntWithNotMask> RCParser::parseIntExpr1() {
- // Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2.
- ASSIGN_OR_RETURN(FirstResult, parseIntExpr2());
- IntWithNotMask Result = *FirstResult;
-
- while (!isEof() && look().isBinaryOp()) {
- auto OpToken = read();
- ASSIGN_OR_RETURN(NextResult, parseIntExpr2());
-
- switch (OpToken.kind()) {
- case Kind::Plus:
- Result += *NextResult;
- break;
-
- case Kind::Minus:
- Result -= *NextResult;
- break;
-
- case Kind::Pipe:
- Result |= *NextResult;
- break;
-
- case Kind::Amp:
- Result &= *NextResult;
- break;
-
- default:
- llvm_unreachable("Already processed all binary ops.");
- }
- }
-
- return Result;
-}
-
-Expected<IntWithNotMask> RCParser::parseIntExpr2() {
- // Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
- static const char ErrorMsg[] = "'-', '~', integer or '('";
-
- if (isEof())
- return getExpectedError(ErrorMsg);
-
- switch (look().kind()) {
- case Kind::Minus: {
- consume();
- ASSIGN_OR_RETURN(Result, parseIntExpr2());
- return -(*Result);
- }
-
- case Kind::Tilde: {
- consume();
- ASSIGN_OR_RETURN(Result, parseIntExpr2());
- return ~(*Result);
- }
-
- case Kind::Int:
- return RCInt(read());
-
- case Kind::LeftParen: {
- consume();
- ASSIGN_OR_RETURN(Result, parseIntExpr1());
- RETURN_IF_ERROR(consumeType(Kind::RightParen));
- return *Result;
- }
-
- case Kind::Identifier: {
- if (!read().value().equals_lower("not"))
- return getExpectedError(ErrorMsg, true);
- ASSIGN_OR_RETURN(Result, parseIntExpr2());
- return IntWithNotMask(0, (*Result).getValue());
- }
-
- default:
- return getExpectedError(ErrorMsg);
- }
-}
-
-Expected<StringRef> RCParser::readString() {
- if (!isNextTokenKind(Kind::String))
- return getExpectedError("string");
- return read().value();
-}
-
-Expected<StringRef> RCParser::readFilename() {
- if (!isNextTokenKind(Kind::String) && !isNextTokenKind(Kind::Identifier))
- return getExpectedError("string");
- return read().value();
-}
-
-Expected<StringRef> RCParser::readIdentifier() {
- if (!isNextTokenKind(Kind::Identifier))
- return getExpectedError("identifier");
- return read().value();
-}
-
-Expected<IntOrString> RCParser::readIntOrString() {
- if (!isNextTokenKind(Kind::Int) && !isNextTokenKind(Kind::String))
- return getExpectedError("int or string");
- return IntOrString(read());
-}
-
-Expected<IntOrString> RCParser::readTypeOrName() {
- // We suggest that the correct resource name or type should be either an
- // identifier or an integer. The original RC tool is much more liberal.
- if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int))
- return getExpectedError("int or identifier");
- return IntOrString(read());
-}
-
-Error RCParser::consumeType(Kind TokenKind) {
- if (isNextTokenKind(TokenKind)) {
- consume();
- return Error::success();
- }
-
- switch (TokenKind) {
-#define TOKEN(TokenName) \
- case Kind::TokenName: \
- return getExpectedError(#TokenName);
-#define SHORT_TOKEN(TokenName, TokenCh) \
- case Kind::TokenName: \
- return getExpectedError(#TokenCh);
-#include "ResourceScriptTokenList.def"
- }
-
- llvm_unreachable("All case options exhausted.");
-}
-
-bool RCParser::consumeOptionalType(Kind TokenKind) {
- if (isNextTokenKind(TokenKind)) {
- consume();
- return true;
- }
-
- return false;
-}
-
-Expected<SmallVector<RCInt, 8>> RCParser::readIntsWithCommas(size_t MinCount,
- size_t MaxCount) {
- assert(MinCount <= MaxCount);
-
- SmallVector<RCInt, 8> Result;
-
- auto FailureHandler =
- [&](llvm::Error Err) -> Expected<SmallVector<RCInt, 8>> {
- if (Result.size() < MinCount)
- return std::move(Err);
- consumeError(std::move(Err));
- return Result;
- };
-
- for (size_t i = 0; i < MaxCount; ++i) {
- // Try to read a comma unless we read the first token.
- // Sometimes RC tool requires them and sometimes not. We decide to
- // always require them.
- if (i >= 1) {
- if (auto CommaError = consumeType(Kind::Comma))
- return FailureHandler(std::move(CommaError));
- }
-
- if (auto IntResult = readInt())
- Result.push_back(*IntResult);
- else
- return FailureHandler(IntResult.takeError());
- }
-
- return std::move(Result);
-}
-
-Expected<uint32_t> RCParser::parseFlags(ArrayRef<StringRef> FlagDesc,
- ArrayRef<uint32_t> FlagValues) {
- assert(!FlagDesc.empty());
- assert(FlagDesc.size() == FlagValues.size());
-
- uint32_t Result = 0;
- while (isNextTokenKind(Kind::Comma)) {
- consume();
- ASSIGN_OR_RETURN(FlagResult, readIdentifier());
- bool FoundFlag = false;
-
- for (size_t FlagId = 0; FlagId < FlagDesc.size(); ++FlagId) {
- if (!FlagResult->equals_lower(FlagDesc[FlagId]))
- continue;
-
- Result |= FlagValues[FlagId];
- FoundFlag = true;
- break;
- }
-
- if (!FoundFlag)
- return getExpectedError(join(FlagDesc, "/"), true);
- }
-
- return Result;
-}
-
-uint16_t RCParser::parseMemoryFlags(uint16_t Flags) {
- while (!isEof()) {
- const RCToken &Token = look();
- if (Token.kind() != Kind::Identifier)
- return Flags;
- const StringRef Ident = Token.value();
- if (Ident.equals_lower("PRELOAD"))
- Flags |= MfPreload;
- else if (Ident.equals_lower("LOADONCALL"))
- Flags &= ~MfPreload;
- else if (Ident.equals_lower("FIXED"))
- Flags &= ~(MfMoveable | MfDiscardable);
- else if (Ident.equals_lower("MOVEABLE"))
- Flags |= MfMoveable;
- else if (Ident.equals_lower("DISCARDABLE"))
- Flags |= MfDiscardable | MfMoveable | MfPure;
- else if (Ident.equals_lower("PURE"))
- Flags |= MfPure;
- else if (Ident.equals_lower("IMPURE"))
- Flags &= ~(MfPure | MfDiscardable);
- else if (Ident.equals_lower("SHARED"))
- Flags |= MfPure;
- else if (Ident.equals_lower("NONSHARED"))
- Flags &= ~(MfPure | MfDiscardable);
- else
- return Flags;
- consume();
- }
- return Flags;
-}
-
-Expected<OptionalStmtList>
-RCParser::parseOptionalStatements(OptStmtType StmtsType) {
- OptionalStmtList Result;
-
- // The last statement is always followed by the start of the block.
- while (!isNextTokenKind(Kind::BlockBegin)) {
- ASSIGN_OR_RETURN(SingleParse, parseSingleOptionalStatement(StmtsType));
- Result.addStmt(std::move(*SingleParse));
- }
-
- return std::move(Result);
-}
-
-Expected<std::unique_ptr<OptionalStmt>>
-RCParser::parseSingleOptionalStatement(OptStmtType StmtsType) {
- ASSIGN_OR_RETURN(TypeToken, readIdentifier());
- if (TypeToken->equals_lower("CHARACTERISTICS"))
- return parseCharacteristicsStmt();
- if (TypeToken->equals_lower("LANGUAGE"))
- return parseLanguageStmt();
- if (TypeToken->equals_lower("VERSION"))
- return parseVersionStmt();
-
- if (StmtsType != OptStmtType::BasicStmt) {
- if (TypeToken->equals_lower("CAPTION"))
- return parseCaptionStmt();
- if (TypeToken->equals_lower("CLASS"))
- return parseClassStmt();
- if (TypeToken->equals_lower("EXSTYLE"))
- return parseExStyleStmt();
- if (TypeToken->equals_lower("FONT"))
- return parseFontStmt(StmtsType);
- if (TypeToken->equals_lower("STYLE"))
- return parseStyleStmt();
- }
-
- return getExpectedError("optional statement type, BEGIN or '{'",
- /* IsAlreadyRead = */ true);
-}
-
-RCParser::ParseType RCParser::parseLanguageResource() {
- // Read LANGUAGE as an optional statement. If it's read correctly, we can
- // upcast it to RCResource.
- return parseLanguageStmt();
-}
-
-RCParser::ParseType RCParser::parseAcceleratorsResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(AcceleratorsResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
- RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
-
- auto Accels = std::make_unique<AcceleratorsResource>(
- std::move(*OptStatements), MemoryFlags);
-
- while (!consumeOptionalType(Kind::BlockEnd)) {
- ASSIGN_OR_RETURN(EventResult, readIntOrString());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- ASSIGN_OR_RETURN(IDResult, readInt());
- ASSIGN_OR_RETURN(
- FlagsResult,
- parseFlags(AcceleratorsResource::Accelerator::OptionsStr,
- AcceleratorsResource::Accelerator::OptionsFlags));
- Accels->addAccelerator(*EventResult, *IDResult, *FlagsResult);
- }
-
- return std::move(Accels);
-}
-
-RCParser::ParseType RCParser::parseCursorResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(CursorResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(Arg, readFilename());
- return std::make_unique<CursorResource>(*Arg, MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
- uint16_t MemoryFlags =
- parseMemoryFlags(DialogResource::getDefaultMemoryFlags());
- // 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(
- IsExtended ? OptStmtType::DialogExStmt
- : OptStmtType::DialogStmt));
-
- assert(isNextTokenKind(Kind::BlockBegin) &&
- "parseOptionalStatements, when successful, halts on BlockBegin.");
- consume();
-
- auto Dialog = std::make_unique<DialogResource>(
- (*LocResult)[0], (*LocResult)[1], (*LocResult)[2], (*LocResult)[3],
- HelpID, std::move(*OptStatements), IsExtended, MemoryFlags);
-
- while (!consumeOptionalType(Kind::BlockEnd)) {
- ASSIGN_OR_RETURN(ControlDefResult, parseControl());
- Dialog->addControl(std::move(*ControlDefResult));
- }
-
- return std::move(Dialog);
-}
-
-RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
- uint16_t MemoryFlags =
- parseMemoryFlags(UserDefinedResource::getDefaultMemoryFlags());
- if (isEof())
- return getExpectedError("filename, '{' or BEGIN");
-
- // Check if this is a file resource.
- switch (look().kind()) {
- case Kind::String:
- case Kind::Identifier:
- return std::make_unique<UserDefinedResource>(Type, read().value(),
- MemoryFlags);
- default:
- break;
- }
-
- RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
- std::vector<IntOrString> Data;
-
- // Consume comma before each consecutive token except the first one.
- bool ConsumeComma = false;
- while (!consumeOptionalType(Kind::BlockEnd)) {
- if (ConsumeComma)
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- ConsumeComma = true;
-
- ASSIGN_OR_RETURN(Item, readIntOrString());
- Data.push_back(*Item);
- }
-
- return std::make_unique<UserDefinedResource>(Type, std::move(Data),
- MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseVersionInfoResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(VersionInfoResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed());
- ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef()));
- return std::make_unique<VersionInfoResource>(
- std::move(**BlockResult), std::move(*FixedResult), MemoryFlags);
-}
-
-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.
- // Text might be either a string or an integer pointing to resource ID.
- ASSIGN_OR_RETURN(ClassResult, readIdentifier());
- std::string ClassUpper = ClassResult->upper();
- auto CtlInfo = Control::SupportedCtls.find(ClassUpper);
- if (CtlInfo == Control::SupportedCtls.end())
- return getExpectedError("control type, END or '}'", true);
-
- // Read caption if necessary.
- IntOrString Caption{StringRef()};
- if (CtlInfo->getValue().HasTitle) {
- ASSIGN_OR_RETURN(CaptionResult, readIntOrString());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- Caption = *CaptionResult;
- }
-
- ASSIGN_OR_RETURN(ID, readInt());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
-
- IntOrString Class;
- Optional<IntWithNotMask> Style;
- if (ClassUpper == "CONTROL") {
- // CONTROL text, id, class, style, x, y, width, height [, exstyle] [, helpID]
- ASSIGN_OR_RETURN(ClassStr, readString());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- Class = *ClassStr;
- ASSIGN_OR_RETURN(StyleVal, parseIntExpr1());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- Style = *StyleVal;
- } else {
- Class = CtlInfo->getValue().CtlClass;
- }
-
- // x, y, width, height
- ASSIGN_OR_RETURN(Args, readIntsWithCommas(4, 4));
-
- if (ClassUpper != "CONTROL") {
- if (consumeOptionalType(Kind::Comma)) {
- ASSIGN_OR_RETURN(Val, parseIntExpr1());
- Style = *Val;
- }
- }
-
- Optional<uint32_t> ExStyle;
- if (consumeOptionalType(Kind::Comma)) {
- ASSIGN_OR_RETURN(Val, readInt());
- ExStyle = *Val;
- }
- Optional<uint32_t> HelpID;
- if (consumeOptionalType(Kind::Comma)) {
- ASSIGN_OR_RETURN(Val, readInt());
- HelpID = *Val;
- }
-
- return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1],
- (*Args)[2], (*Args)[3], Style, ExStyle, HelpID, Class);
-}
-
-RCParser::ParseType RCParser::parseBitmapResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(BitmapResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(Arg, readFilename());
- return std::make_unique<BitmapResource>(*Arg, MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseIconResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(IconResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(Arg, readFilename());
- return std::make_unique<IconResource>(*Arg, MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseHTMLResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(HTMLResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(Arg, readFilename());
- return std::make_unique<HTMLResource>(*Arg, MemoryFlags);
-}
-
-RCParser::ParseType RCParser::parseMenuResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(MenuResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
- ASSIGN_OR_RETURN(Items, parseMenuItemsList());
- return std::make_unique<MenuResource>(std::move(*OptStatements),
- std::move(*Items), MemoryFlags);
-}
-
-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(std::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,
- MenuDefinition::OptionsFlags));
-
- if (IsPopup) {
- // If POPUP, read submenu items recursively.
- ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList());
- List.addDefinition(std::make_unique<PopupItem>(
- *CaptionResult, *FlagsResult, std::move(*SubMenuResult)));
- continue;
- }
-
- assert(IsMenuItem);
- List.addDefinition(
- std::make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult));
- }
-
- return std::move(List);
-}
-
-RCParser::ParseType RCParser::parseStringTableResource() {
- uint16_t MemoryFlags =
- parseMemoryFlags(StringTableResource::getDefaultMemoryFlags());
- ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
- RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
-
- auto Table = std::make_unique<StringTableResource>(std::move(*OptStatements),
- MemoryFlags);
-
- // Read strings until we reach the end of the block.
- while (!consumeOptionalType(Kind::BlockEnd)) {
- // Each definition consists of string's ID (an integer) and a string.
- // Some examples in documentation suggest that there might be a comma in
- // between, however we strictly adhere to the single statement definition.
- ASSIGN_OR_RETURN(IDResult, readInt());
- consumeOptionalType(Kind::Comma);
-
- std::vector<StringRef> Strings;
- ASSIGN_OR_RETURN(StrResult, readString());
- Strings.push_back(*StrResult);
- while (isNextTokenKind(Kind::String))
- Strings.push_back(read().value());
-
- Table->addStrings(*IDResult, std::move(Strings));
- }
-
- return std::move(Table);
-}
-
-Expected<std::unique_ptr<VersionInfoBlock>>
-RCParser::parseVersionInfoBlockContents(StringRef BlockName) {
- RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
-
- auto Contents = std::make_unique<VersionInfoBlock>(BlockName);
-
- while (!isNextTokenKind(Kind::BlockEnd)) {
- ASSIGN_OR_RETURN(Stmt, parseVersionInfoStmt());
- Contents->addStmt(std::move(*Stmt));
- }
-
- consume(); // Consume BlockEnd.
-
- return std::move(Contents);
-}
-
-Expected<std::unique_ptr<VersionInfoStmt>> RCParser::parseVersionInfoStmt() {
- // Expect either BLOCK or VALUE, then a name or a key (a string).
- ASSIGN_OR_RETURN(TypeResult, readIdentifier());
-
- if (TypeResult->equals_lower("BLOCK")) {
- ASSIGN_OR_RETURN(NameResult, readString());
- return parseVersionInfoBlockContents(*NameResult);
- }
-
- if (TypeResult->equals_lower("VALUE")) {
- ASSIGN_OR_RETURN(KeyResult, readString());
- // Read a non-empty list of strings and/or ints, each
- // possibly preceded by a comma. Unfortunately, the tool behavior depends
- // on them existing or not, so we need to memorize where we found them.
- std::vector<IntOrString> Values;
- std::vector<bool> PrecedingCommas;
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- while (!isNextTokenKind(Kind::Identifier) &&
- !isNextTokenKind(Kind::BlockEnd)) {
- // Try to eat a comma if it's not the first statement.
- bool HadComma = Values.size() > 0 && consumeOptionalType(Kind::Comma);
- ASSIGN_OR_RETURN(ValueResult, readIntOrString());
- Values.push_back(*ValueResult);
- PrecedingCommas.push_back(HadComma);
- }
- return std::make_unique<VersionInfoValue>(*KeyResult, std::move(Values),
- std::move(PrecedingCommas));
- }
-
- return getExpectedError("BLOCK or VALUE", true);
-}
-
-Expected<VersionInfoResource::VersionInfoFixed>
-RCParser::parseVersionInfoFixed() {
- using RetType = VersionInfoResource::VersionInfoFixed;
- RetType Result;
-
- // Read until the beginning of the block.
- while (!isNextTokenKind(Kind::BlockBegin)) {
- ASSIGN_OR_RETURN(TypeResult, readIdentifier());
- auto FixedType = RetType::getFixedType(*TypeResult);
-
- if (!RetType::isTypeSupported(FixedType))
- return getExpectedError("fixed VERSIONINFO statement type", true);
- if (Result.IsTypePresent[FixedType])
- return getExpectedError("yet unread fixed VERSIONINFO statement type",
- true);
-
- // VERSION variations take multiple integers.
- size_t NumInts = RetType::isVersionType(FixedType) ? 4 : 1;
+//===-- ResourceScriptParser.cpp --------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This implements the parser defined in ResourceScriptParser.h.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceScriptParser.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+
+// Take an expression returning llvm::Error and forward the error if it exists.
+#define RETURN_IF_ERROR(Expr) \
+ if (auto Err = (Expr)) \
+ return std::move(Err);
+
+// Take an expression returning llvm::Expected<T> and assign it to Var or
+// forward the error out of the function.
+#define ASSIGN_OR_RETURN(Var, Expr) \
+ auto Var = (Expr); \
+ if (!Var) \
+ return Var.takeError();
+
+namespace llvm {
+namespace rc {
+
+RCParser::ParserError::ParserError(const Twine &Expected, const LocIter CurLoc,
+ const LocIter End)
+ : ErrorLoc(CurLoc), FileEnd(End) {
+ CurMessage = "Error parsing file: expected " + Expected.str() + ", got " +
+ (CurLoc == End ? "<EOF>" : CurLoc->value()).str();
+}
+
+char RCParser::ParserError::ID = 0;
+
+RCParser::RCParser(std::vector<RCToken> TokenList)
+ : Tokens(std::move(TokenList)), CurLoc(Tokens.begin()), End(Tokens.end()) {}
+
+bool RCParser::isEof() const { return CurLoc == End; }
+
+RCParser::ParseType RCParser::parseSingleResource() {
+ // The first thing we read is usually a resource's name. However, in some
+ // cases (LANGUAGE and STRINGTABLE) the resources don't have their names
+ // and the first token to be read is the type.
+ ASSIGN_OR_RETURN(NameToken, readTypeOrName());
+
+ if (NameToken->equalsLower("LANGUAGE"))
+ return parseLanguageResource();
+ else if (NameToken->equalsLower("STRINGTABLE"))
+ return parseStringTableResource();
+
+ // If it's not an unnamed resource, what we've just read is a name. Now,
+ // read resource type;
+ ASSIGN_OR_RETURN(TypeToken, readTypeOrName());
+
+ ParseType Result = std::unique_ptr<RCResource>();
+ (void)!Result;
+
+ if (TypeToken->equalsLower("ACCELERATORS"))
+ Result = parseAcceleratorsResource();
+ else if (TypeToken->equalsLower("BITMAP"))
+ Result = parseBitmapResource();
+ 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("HTML"))
+ Result = parseHTMLResource();
+ else if (TypeToken->equalsLower("ICON"))
+ Result = parseIconResource();
+ else if (TypeToken->equalsLower("MENU"))
+ Result = parseMenuResource();
+ else if (TypeToken->equalsLower("RCDATA"))
+ Result = parseUserDefinedResource(RkRcData);
+ else if (TypeToken->equalsLower("VERSIONINFO"))
+ Result = parseVersionInfoResource();
+ else
+ Result = parseUserDefinedResource(*TypeToken);
+
+ if (Result)
+ (*Result)->setName(*NameToken);
+
+ return Result;
+}
+
+bool RCParser::isNextTokenKind(Kind TokenKind) const {
+ return !isEof() && look().kind() == TokenKind;
+}
+
+const RCToken &RCParser::look() const {
+ assert(!isEof());
+ return *CurLoc;
+}
+
+const RCToken &RCParser::read() {
+ assert(!isEof());
+ return *CurLoc++;
+}
+
+void RCParser::consume() {
+ assert(!isEof());
+ CurLoc++;
+}
+
+// An integer description might consist of a single integer or
+// an arithmetic expression evaluating to the integer. The expressions
+// can contain the following tokens: <int> ( ) + - | & ~ not. Their meaning
+// is the same as in C++ except for 'not' expression.
+// The operators in the original RC implementation have the following
+// precedence:
+// 1) Unary operators (- ~ not),
+// 2) Binary operators (+ - & |), with no precedence.
+//
+// 'not' expression is mostly useful for style values. It evaluates to 0,
+// but value given to the operator is stored separately from integer value.
+// It's mostly useful for control style expressions and causes bits from
+// default control style to be excluded from generated style. For binary
+// operators the mask from the right operand is applied to the left operand
+// and masks from both operands are combined in operator result.
+//
+// The following grammar is used to parse the expressions Exp1:
+// Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2
+// Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
+// (More conveniently, Exp1 is a non-empty sequence of Exp2 expressions,
+// separated by binary operators.)
+//
+// Expressions of type Exp1 are read by parseIntExpr1(Inner) method, while Exp2
+// is read by parseIntExpr2().
+//
+// The original Microsoft tool handles multiple unary operators incorrectly.
+// For example, in 16-bit little-endian integers:
+// 1 => 01 00, -1 => ff ff, --1 => ff ff, ---1 => 01 00;
+// 1 => 01 00, ~1 => fe ff, ~~1 => fd ff, ~~~1 => fc ff.
+// Our implementation differs from the original one and handles these
+// operators correctly:
+// 1 => 01 00, -1 => ff ff, --1 => 01 00, ---1 => ff ff;
+// 1 => 01 00, ~1 => fe ff, ~~1 => 01 00, ~~~1 => fe ff.
+
+Expected<RCInt> RCParser::readInt() {
+ ASSIGN_OR_RETURN(Value, parseIntExpr1());
+ return (*Value).getValue();
+}
+
+Expected<IntWithNotMask> RCParser::parseIntExpr1() {
+ // Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2.
+ ASSIGN_OR_RETURN(FirstResult, parseIntExpr2());
+ IntWithNotMask Result = *FirstResult;
+
+ while (!isEof() && look().isBinaryOp()) {
+ auto OpToken = read();
+ ASSIGN_OR_RETURN(NextResult, parseIntExpr2());
+
+ switch (OpToken.kind()) {
+ case Kind::Plus:
+ Result += *NextResult;
+ break;
+
+ case Kind::Minus:
+ Result -= *NextResult;
+ break;
+
+ case Kind::Pipe:
+ Result |= *NextResult;
+ break;
+
+ case Kind::Amp:
+ Result &= *NextResult;
+ break;
+
+ default:
+ llvm_unreachable("Already processed all binary ops.");
+ }
+ }
+
+ return Result;
+}
+
+Expected<IntWithNotMask> RCParser::parseIntExpr2() {
+ // Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
+ static const char ErrorMsg[] = "'-', '~', integer or '('";
+
+ if (isEof())
+ return getExpectedError(ErrorMsg);
+
+ switch (look().kind()) {
+ case Kind::Minus: {
+ consume();
+ ASSIGN_OR_RETURN(Result, parseIntExpr2());
+ return -(*Result);
+ }
+
+ case Kind::Tilde: {
+ consume();
+ ASSIGN_OR_RETURN(Result, parseIntExpr2());
+ return ~(*Result);
+ }
+
+ case Kind::Int:
+ return RCInt(read());
+
+ case Kind::LeftParen: {
+ consume();
+ ASSIGN_OR_RETURN(Result, parseIntExpr1());
+ RETURN_IF_ERROR(consumeType(Kind::RightParen));
+ return *Result;
+ }
+
+ case Kind::Identifier: {
+ if (!read().value().equals_lower("not"))
+ return getExpectedError(ErrorMsg, true);
+ ASSIGN_OR_RETURN(Result, parseIntExpr2());
+ return IntWithNotMask(0, (*Result).getValue());
+ }
+
+ default:
+ return getExpectedError(ErrorMsg);
+ }
+}
+
+Expected<StringRef> RCParser::readString() {
+ if (!isNextTokenKind(Kind::String))
+ return getExpectedError("string");
+ return read().value();
+}
+
+Expected<StringRef> RCParser::readFilename() {
+ if (!isNextTokenKind(Kind::String) && !isNextTokenKind(Kind::Identifier))
+ return getExpectedError("string");
+ return read().value();
+}
+
+Expected<StringRef> RCParser::readIdentifier() {
+ if (!isNextTokenKind(Kind::Identifier))
+ return getExpectedError("identifier");
+ return read().value();
+}
+
+Expected<IntOrString> RCParser::readIntOrString() {
+ if (!isNextTokenKind(Kind::Int) && !isNextTokenKind(Kind::String))
+ return getExpectedError("int or string");
+ return IntOrString(read());
+}
+
+Expected<IntOrString> RCParser::readTypeOrName() {
+ // We suggest that the correct resource name or type should be either an
+ // identifier or an integer. The original RC tool is much more liberal.
+ if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int))
+ return getExpectedError("int or identifier");
+ return IntOrString(read());
+}
+
+Error RCParser::consumeType(Kind TokenKind) {
+ if (isNextTokenKind(TokenKind)) {
+ consume();
+ return Error::success();
+ }
+
+ switch (TokenKind) {
+#define TOKEN(TokenName) \
+ case Kind::TokenName: \
+ return getExpectedError(#TokenName);
+#define SHORT_TOKEN(TokenName, TokenCh) \
+ case Kind::TokenName: \
+ return getExpectedError(#TokenCh);
+#include "ResourceScriptTokenList.def"
+ }
+
+ llvm_unreachable("All case options exhausted.");
+}
+
+bool RCParser::consumeOptionalType(Kind TokenKind) {
+ if (isNextTokenKind(TokenKind)) {
+ consume();
+ return true;
+ }
+
+ return false;
+}
+
+Expected<SmallVector<RCInt, 8>> RCParser::readIntsWithCommas(size_t MinCount,
+ size_t MaxCount) {
+ assert(MinCount <= MaxCount);
+
+ SmallVector<RCInt, 8> Result;
+
+ auto FailureHandler =
+ [&](llvm::Error Err) -> Expected<SmallVector<RCInt, 8>> {
+ if (Result.size() < MinCount)
+ return std::move(Err);
+ consumeError(std::move(Err));
+ return Result;
+ };
+
+ for (size_t i = 0; i < MaxCount; ++i) {
+ // Try to read a comma unless we read the first token.
+ // Sometimes RC tool requires them and sometimes not. We decide to
+ // always require them.
+ if (i >= 1) {
+ if (auto CommaError = consumeType(Kind::Comma))
+ return FailureHandler(std::move(CommaError));
+ }
+
+ if (auto IntResult = readInt())
+ Result.push_back(*IntResult);
+ else
+ return FailureHandler(IntResult.takeError());
+ }
+
+ return std::move(Result);
+}
+
+Expected<uint32_t> RCParser::parseFlags(ArrayRef<StringRef> FlagDesc,
+ ArrayRef<uint32_t> FlagValues) {
+ assert(!FlagDesc.empty());
+ assert(FlagDesc.size() == FlagValues.size());
+
+ uint32_t Result = 0;
+ while (isNextTokenKind(Kind::Comma)) {
+ consume();
+ ASSIGN_OR_RETURN(FlagResult, readIdentifier());
+ bool FoundFlag = false;
+
+ for (size_t FlagId = 0; FlagId < FlagDesc.size(); ++FlagId) {
+ if (!FlagResult->equals_lower(FlagDesc[FlagId]))
+ continue;
+
+ Result |= FlagValues[FlagId];
+ FoundFlag = true;
+ break;
+ }
+
+ if (!FoundFlag)
+ return getExpectedError(join(FlagDesc, "/"), true);
+ }
+
+ return Result;
+}
+
+uint16_t RCParser::parseMemoryFlags(uint16_t Flags) {
+ while (!isEof()) {
+ const RCToken &Token = look();
+ if (Token.kind() != Kind::Identifier)
+ return Flags;
+ const StringRef Ident = Token.value();
+ if (Ident.equals_lower("PRELOAD"))
+ Flags |= MfPreload;
+ else if (Ident.equals_lower("LOADONCALL"))
+ Flags &= ~MfPreload;
+ else if (Ident.equals_lower("FIXED"))
+ Flags &= ~(MfMoveable | MfDiscardable);
+ else if (Ident.equals_lower("MOVEABLE"))
+ Flags |= MfMoveable;
+ else if (Ident.equals_lower("DISCARDABLE"))
+ Flags |= MfDiscardable | MfMoveable | MfPure;
+ else if (Ident.equals_lower("PURE"))
+ Flags |= MfPure;
+ else if (Ident.equals_lower("IMPURE"))
+ Flags &= ~(MfPure | MfDiscardable);
+ else if (Ident.equals_lower("SHARED"))
+ Flags |= MfPure;
+ else if (Ident.equals_lower("NONSHARED"))
+ Flags &= ~(MfPure | MfDiscardable);
+ else
+ return Flags;
+ consume();
+ }
+ return Flags;
+}
+
+Expected<OptionalStmtList>
+RCParser::parseOptionalStatements(OptStmtType StmtsType) {
+ OptionalStmtList Result;
+
+ // The last statement is always followed by the start of the block.
+ while (!isNextTokenKind(Kind::BlockBegin)) {
+ ASSIGN_OR_RETURN(SingleParse, parseSingleOptionalStatement(StmtsType));
+ Result.addStmt(std::move(*SingleParse));
+ }
+
+ return std::move(Result);
+}
+
+Expected<std::unique_ptr<OptionalStmt>>
+RCParser::parseSingleOptionalStatement(OptStmtType StmtsType) {
+ ASSIGN_OR_RETURN(TypeToken, readIdentifier());
+ if (TypeToken->equals_lower("CHARACTERISTICS"))
+ return parseCharacteristicsStmt();
+ if (TypeToken->equals_lower("LANGUAGE"))
+ return parseLanguageStmt();
+ if (TypeToken->equals_lower("VERSION"))
+ return parseVersionStmt();
+
+ if (StmtsType != OptStmtType::BasicStmt) {
+ if (TypeToken->equals_lower("CAPTION"))
+ return parseCaptionStmt();
+ if (TypeToken->equals_lower("CLASS"))
+ return parseClassStmt();
+ if (TypeToken->equals_lower("EXSTYLE"))
+ return parseExStyleStmt();
+ if (TypeToken->equals_lower("FONT"))
+ return parseFontStmt(StmtsType);
+ if (TypeToken->equals_lower("STYLE"))
+ return parseStyleStmt();
+ }
+
+ return getExpectedError("optional statement type, BEGIN or '{'",
+ /* IsAlreadyRead = */ true);
+}
+
+RCParser::ParseType RCParser::parseLanguageResource() {
+ // Read LANGUAGE as an optional statement. If it's read correctly, we can
+ // upcast it to RCResource.
+ return parseLanguageStmt();
+}
+
+RCParser::ParseType RCParser::parseAcceleratorsResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(AcceleratorsResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+ auto Accels = std::make_unique<AcceleratorsResource>(
+ std::move(*OptStatements), MemoryFlags);
+
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ ASSIGN_OR_RETURN(EventResult, readIntOrString());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ ASSIGN_OR_RETURN(IDResult, readInt());
+ ASSIGN_OR_RETURN(
+ FlagsResult,
+ parseFlags(AcceleratorsResource::Accelerator::OptionsStr,
+ AcceleratorsResource::Accelerator::OptionsFlags));
+ Accels->addAccelerator(*EventResult, *IDResult, *FlagsResult);
+ }
+
+ return std::move(Accels);
+}
+
+RCParser::ParseType RCParser::parseCursorResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(CursorResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(Arg, readFilename());
+ return std::make_unique<CursorResource>(*Arg, MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(DialogResource::getDefaultMemoryFlags());
+ // 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(
+ IsExtended ? OptStmtType::DialogExStmt
+ : OptStmtType::DialogStmt));
+
+ assert(isNextTokenKind(Kind::BlockBegin) &&
+ "parseOptionalStatements, when successful, halts on BlockBegin.");
+ consume();
+
+ auto Dialog = std::make_unique<DialogResource>(
+ (*LocResult)[0], (*LocResult)[1], (*LocResult)[2], (*LocResult)[3],
+ HelpID, std::move(*OptStatements), IsExtended, MemoryFlags);
+
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ ASSIGN_OR_RETURN(ControlDefResult, parseControl());
+ Dialog->addControl(std::move(*ControlDefResult));
+ }
+
+ return std::move(Dialog);
+}
+
+RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(UserDefinedResource::getDefaultMemoryFlags());
+ if (isEof())
+ return getExpectedError("filename, '{' or BEGIN");
+
+ // Check if this is a file resource.
+ switch (look().kind()) {
+ case Kind::String:
+ case Kind::Identifier:
+ return std::make_unique<UserDefinedResource>(Type, read().value(),
+ MemoryFlags);
+ default:
+ break;
+ }
+
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+ std::vector<IntOrString> Data;
+
+ // Consume comma before each consecutive token except the first one.
+ bool ConsumeComma = false;
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ if (ConsumeComma)
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ ConsumeComma = true;
+
+ ASSIGN_OR_RETURN(Item, readIntOrString());
+ Data.push_back(*Item);
+ }
+
+ return std::make_unique<UserDefinedResource>(Type, std::move(Data),
+ MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseVersionInfoResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(VersionInfoResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed());
+ ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef()));
+ return std::make_unique<VersionInfoResource>(
+ std::move(**BlockResult), std::move(*FixedResult), MemoryFlags);
+}
+
+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.
+ // Text might be either a string or an integer pointing to resource ID.
+ ASSIGN_OR_RETURN(ClassResult, readIdentifier());
+ std::string ClassUpper = ClassResult->upper();
+ auto CtlInfo = Control::SupportedCtls.find(ClassUpper);
+ if (CtlInfo == Control::SupportedCtls.end())
+ return getExpectedError("control type, END or '}'", true);
+
+ // Read caption if necessary.
+ IntOrString Caption{StringRef()};
+ if (CtlInfo->getValue().HasTitle) {
+ ASSIGN_OR_RETURN(CaptionResult, readIntOrString());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ Caption = *CaptionResult;
+ }
+
+ ASSIGN_OR_RETURN(ID, readInt());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+
+ IntOrString Class;
+ Optional<IntWithNotMask> Style;
+ if (ClassUpper == "CONTROL") {
+ // CONTROL text, id, class, style, x, y, width, height [, exstyle] [, helpID]
+ ASSIGN_OR_RETURN(ClassStr, readString());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ Class = *ClassStr;
+ ASSIGN_OR_RETURN(StyleVal, parseIntExpr1());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ Style = *StyleVal;
+ } else {
+ Class = CtlInfo->getValue().CtlClass;
+ }
+
+ // x, y, width, height
+ ASSIGN_OR_RETURN(Args, readIntsWithCommas(4, 4));
+
+ if (ClassUpper != "CONTROL") {
+ if (consumeOptionalType(Kind::Comma)) {
+ ASSIGN_OR_RETURN(Val, parseIntExpr1());
+ Style = *Val;
+ }
+ }
+
+ Optional<uint32_t> ExStyle;
+ if (consumeOptionalType(Kind::Comma)) {
+ ASSIGN_OR_RETURN(Val, readInt());
+ ExStyle = *Val;
+ }
+ Optional<uint32_t> HelpID;
+ if (consumeOptionalType(Kind::Comma)) {
+ ASSIGN_OR_RETURN(Val, readInt());
+ HelpID = *Val;
+ }
+
+ return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1],
+ (*Args)[2], (*Args)[3], Style, ExStyle, HelpID, Class);
+}
+
+RCParser::ParseType RCParser::parseBitmapResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(BitmapResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(Arg, readFilename());
+ return std::make_unique<BitmapResource>(*Arg, MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseIconResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(IconResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(Arg, readFilename());
+ return std::make_unique<IconResource>(*Arg, MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseHTMLResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(HTMLResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(Arg, readFilename());
+ return std::make_unique<HTMLResource>(*Arg, MemoryFlags);
+}
+
+RCParser::ParseType RCParser::parseMenuResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(MenuResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
+ ASSIGN_OR_RETURN(Items, parseMenuItemsList());
+ return std::make_unique<MenuResource>(std::move(*OptStatements),
+ std::move(*Items), MemoryFlags);
+}
+
+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(std::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,
+ MenuDefinition::OptionsFlags));
+
+ if (IsPopup) {
+ // If POPUP, read submenu items recursively.
+ ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList());
+ List.addDefinition(std::make_unique<PopupItem>(
+ *CaptionResult, *FlagsResult, std::move(*SubMenuResult)));
+ continue;
+ }
+
+ assert(IsMenuItem);
+ List.addDefinition(
+ std::make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult));
+ }
+
+ return std::move(List);
+}
+
+RCParser::ParseType RCParser::parseStringTableResource() {
+ uint16_t MemoryFlags =
+ parseMemoryFlags(StringTableResource::getDefaultMemoryFlags());
+ ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+ auto Table = std::make_unique<StringTableResource>(std::move(*OptStatements),
+ MemoryFlags);
+
+ // Read strings until we reach the end of the block.
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ // Each definition consists of string's ID (an integer) and a string.
+ // Some examples in documentation suggest that there might be a comma in
+ // between, however we strictly adhere to the single statement definition.
+ ASSIGN_OR_RETURN(IDResult, readInt());
+ consumeOptionalType(Kind::Comma);
+
+ std::vector<StringRef> Strings;
+ ASSIGN_OR_RETURN(StrResult, readString());
+ Strings.push_back(*StrResult);
+ while (isNextTokenKind(Kind::String))
+ Strings.push_back(read().value());
+
+ Table->addStrings(*IDResult, std::move(Strings));
+ }
+
+ return std::move(Table);
+}
+
+Expected<std::unique_ptr<VersionInfoBlock>>
+RCParser::parseVersionInfoBlockContents(StringRef BlockName) {
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+ auto Contents = std::make_unique<VersionInfoBlock>(BlockName);
+
+ while (!isNextTokenKind(Kind::BlockEnd)) {
+ ASSIGN_OR_RETURN(Stmt, parseVersionInfoStmt());
+ Contents->addStmt(std::move(*Stmt));
+ }
+
+ consume(); // Consume BlockEnd.
+
+ return std::move(Contents);
+}
+
+Expected<std::unique_ptr<VersionInfoStmt>> RCParser::parseVersionInfoStmt() {
+ // Expect either BLOCK or VALUE, then a name or a key (a string).
+ ASSIGN_OR_RETURN(TypeResult, readIdentifier());
+
+ if (TypeResult->equals_lower("BLOCK")) {
+ ASSIGN_OR_RETURN(NameResult, readString());
+ return parseVersionInfoBlockContents(*NameResult);
+ }
+
+ if (TypeResult->equals_lower("VALUE")) {
+ ASSIGN_OR_RETURN(KeyResult, readString());
+ // Read a non-empty list of strings and/or ints, each
+ // possibly preceded by a comma. Unfortunately, the tool behavior depends
+ // on them existing or not, so we need to memorize where we found them.
+ std::vector<IntOrString> Values;
+ std::vector<bool> PrecedingCommas;
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ while (!isNextTokenKind(Kind::Identifier) &&
+ !isNextTokenKind(Kind::BlockEnd)) {
+ // Try to eat a comma if it's not the first statement.
+ bool HadComma = Values.size() > 0 && consumeOptionalType(Kind::Comma);
+ ASSIGN_OR_RETURN(ValueResult, readIntOrString());
+ Values.push_back(*ValueResult);
+ PrecedingCommas.push_back(HadComma);
+ }
+ return std::make_unique<VersionInfoValue>(*KeyResult, std::move(Values),
+ std::move(PrecedingCommas));
+ }
+
+ return getExpectedError("BLOCK or VALUE", true);
+}
+
+Expected<VersionInfoResource::VersionInfoFixed>
+RCParser::parseVersionInfoFixed() {
+ using RetType = VersionInfoResource::VersionInfoFixed;
+ RetType Result;
+
+ // Read until the beginning of the block.
+ while (!isNextTokenKind(Kind::BlockBegin)) {
+ ASSIGN_OR_RETURN(TypeResult, readIdentifier());
+ auto FixedType = RetType::getFixedType(*TypeResult);
+
+ if (!RetType::isTypeSupported(FixedType))
+ return getExpectedError("fixed VERSIONINFO statement type", true);
+ if (Result.IsTypePresent[FixedType])
+ return getExpectedError("yet unread fixed VERSIONINFO statement type",
+ true);
+
+ // VERSION variations take multiple integers.
+ size_t NumInts = RetType::isVersionType(FixedType) ? 4 : 1;
ASSIGN_OR_RETURN(ArgsResult, readIntsWithCommas(1, NumInts));
- SmallVector<uint32_t, 4> ArgInts(ArgsResult->begin(), ArgsResult->end());
+ SmallVector<uint32_t, 4> ArgInts(ArgsResult->begin(), ArgsResult->end());
while (ArgInts.size() < NumInts)
ArgInts.push_back(0);
- Result.setValue(FixedType, ArgInts);
- }
-
- return Result;
-}
-
-RCParser::ParseOptionType RCParser::parseLanguageStmt() {
- ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2));
- return std::make_unique<LanguageResource>((*Args)[0], (*Args)[1]);
-}
-
-RCParser::ParseOptionType RCParser::parseCharacteristicsStmt() {
- ASSIGN_OR_RETURN(Arg, readInt());
- return std::make_unique<CharacteristicsStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseVersionStmt() {
- ASSIGN_OR_RETURN(Arg, readInt());
- return std::make_unique<VersionStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseCaptionStmt() {
- ASSIGN_OR_RETURN(Arg, readString());
- return std::make_unique<CaptionStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseClassStmt() {
- ASSIGN_OR_RETURN(Arg, readIntOrString());
- return std::make_unique<ClassStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseFontStmt(OptStmtType DialogType) {
- assert(DialogType != OptStmtType::BasicStmt);
-
- ASSIGN_OR_RETURN(SizeResult, readInt());
- RETURN_IF_ERROR(consumeType(Kind::Comma));
- ASSIGN_OR_RETURN(NameResult, readString());
-
- // Default values for the optional arguments.
- uint32_t FontWeight = 0;
- bool FontItalic = false;
- uint32_t FontCharset = 1;
- if (DialogType == OptStmtType::DialogExStmt) {
- if (consumeOptionalType(Kind::Comma)) {
- ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 0, /* max = */ 3));
- if (Args->size() >= 1)
- FontWeight = (*Args)[0];
- if (Args->size() >= 2)
- FontItalic = (*Args)[1] != 0;
- if (Args->size() >= 3)
- FontCharset = (*Args)[2];
- }
- }
- return std::make_unique<FontStmt>(*SizeResult, *NameResult, FontWeight,
- FontItalic, FontCharset);
-}
-
-RCParser::ParseOptionType RCParser::parseStyleStmt() {
- ASSIGN_OR_RETURN(Arg, readInt());
- return std::make_unique<StyleStmt>(*Arg);
-}
-
-RCParser::ParseOptionType RCParser::parseExStyleStmt() {
- ASSIGN_OR_RETURN(Arg, readInt());
- return std::make_unique<ExStyleStmt>(*Arg);
-}
-
-Error RCParser::getExpectedError(const Twine &Message, bool IsAlreadyRead) {
- return make_error<ParserError>(
- Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End);
-}
-
-} // namespace rc
-} // namespace llvm
+ Result.setValue(FixedType, ArgInts);
+ }
+
+ return Result;
+}
+
+RCParser::ParseOptionType RCParser::parseLanguageStmt() {
+ ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2));
+ return std::make_unique<LanguageResource>((*Args)[0], (*Args)[1]);
+}
+
+RCParser::ParseOptionType RCParser::parseCharacteristicsStmt() {
+ ASSIGN_OR_RETURN(Arg, readInt());
+ return std::make_unique<CharacteristicsStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseVersionStmt() {
+ ASSIGN_OR_RETURN(Arg, readInt());
+ return std::make_unique<VersionStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseCaptionStmt() {
+ ASSIGN_OR_RETURN(Arg, readString());
+ return std::make_unique<CaptionStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseClassStmt() {
+ ASSIGN_OR_RETURN(Arg, readIntOrString());
+ return std::make_unique<ClassStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseFontStmt(OptStmtType DialogType) {
+ assert(DialogType != OptStmtType::BasicStmt);
+
+ ASSIGN_OR_RETURN(SizeResult, readInt());
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ ASSIGN_OR_RETURN(NameResult, readString());
+
+ // Default values for the optional arguments.
+ uint32_t FontWeight = 0;
+ bool FontItalic = false;
+ uint32_t FontCharset = 1;
+ if (DialogType == OptStmtType::DialogExStmt) {
+ if (consumeOptionalType(Kind::Comma)) {
+ ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 0, /* max = */ 3));
+ if (Args->size() >= 1)
+ FontWeight = (*Args)[0];
+ if (Args->size() >= 2)
+ FontItalic = (*Args)[1] != 0;
+ if (Args->size() >= 3)
+ FontCharset = (*Args)[2];
+ }
+ }
+ return std::make_unique<FontStmt>(*SizeResult, *NameResult, FontWeight,
+ FontItalic, FontCharset);
+}
+
+RCParser::ParseOptionType RCParser::parseStyleStmt() {
+ ASSIGN_OR_RETURN(Arg, readInt());
+ return std::make_unique<StyleStmt>(*Arg);
+}
+
+RCParser::ParseOptionType RCParser::parseExStyleStmt() {
+ ASSIGN_OR_RETURN(Arg, readInt());
+ return std::make_unique<ExStyleStmt>(*Arg);
+}
+
+Error RCParser::getExpectedError(const Twine &Message, bool IsAlreadyRead) {
+ return make_error<ParserError>(
+ Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End);
+}
+
+} // namespace rc
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h
index 4887b0d5db..fe202073b6 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptParser.h
@@ -1,192 +1,192 @@
-//===-- ResourceScriptParser.h ----------------------------------*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This defines the RC scripts parser. It takes a sequence of RC tokens
-// and then provides the method to parse the resources one by one.
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H
-
-#include "ResourceScriptStmt.h"
-#include "ResourceScriptToken.h"
-
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <system_error>
-#include <vector>
-
-namespace llvm {
-namespace opt {
-class InputArgList;
-}
-namespace rc {
-
-class RCParser {
-public:
- using LocIter = std::vector<RCToken>::iterator;
- using ParseType = Expected<std::unique_ptr<RCResource>>;
- using ParseOptionType = Expected<std::unique_ptr<OptionalStmt>>;
-
- // Class describing a single failure of parser.
- class ParserError : public ErrorInfo<ParserError> {
- public:
- ParserError(const Twine &Expected, const LocIter CurLoc, const LocIter End);
-
- void log(raw_ostream &OS) const override { OS << CurMessage; }
- std::error_code convertToErrorCode() const override {
- return std::make_error_code(std::errc::invalid_argument);
- }
- const std::string &getMessage() const { return CurMessage; }
-
- static char ID; // Keep llvm::Error happy.
-
- private:
- std::string CurMessage;
- LocIter ErrorLoc, FileEnd;
- };
-
- explicit RCParser(std::vector<RCToken> TokenList);
-
- // Reads and returns a single resource definition, or error message if any
- // occurred.
- ParseType parseSingleResource();
-
- bool isEof() const;
-
-private:
- using Kind = RCToken::Kind;
-
- // Checks if the current parser state points to the token of type TokenKind.
- bool isNextTokenKind(Kind TokenKind) const;
-
- // These methods assume that the parser is not in EOF state.
-
- // Take a look at the current token. Do not fetch it.
- const RCToken &look() const;
- // Read the current token and advance the state by one token.
- const RCToken &read();
- // Advance the state by one token, discarding the current token.
- void consume();
-
- // The following methods try to read a single token, check if it has the
- // correct type and then parse it.
- // Each integer can be written as an arithmetic expression producing an
- // unsigned 32-bit integer.
- Expected<RCInt> readInt(); // Parse an integer.
- Expected<StringRef> readString(); // Parse a string.
- Expected<StringRef> readIdentifier(); // Parse an identifier.
- Expected<StringRef> readFilename(); // Parse a filename.
- Expected<IntOrString> readIntOrString(); // Parse an integer or a string.
- Expected<IntOrString> readTypeOrName(); // Parse an integer or an identifier.
-
- // Helper integer expression parsing methods.
- Expected<IntWithNotMask> parseIntExpr1();
- Expected<IntWithNotMask> parseIntExpr2();
-
- // Advance the state by one, discarding the current token.
- // If the discarded token had an incorrect type, fail.
- Error consumeType(Kind TokenKind);
-
- // Check the current token type. If it's TokenKind, discard it.
- // Return true if the parser consumed this token successfully.
- bool consumeOptionalType(Kind TokenKind);
-
- // Read at least MinCount, and at most MaxCount integers separated by
- // commas. The parser stops reading after fetching MaxCount integers
- // or after an error occurs. Whenever the parser reads a comma, it
- // expects an integer to follow.
- Expected<SmallVector<RCInt, 8>> readIntsWithCommas(size_t MinCount,
- size_t MaxCount);
-
- // 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 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<uint32_t> parseFlags(ArrayRef<StringRef> FlagDesc,
- ArrayRef<uint32_t> 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
- // before the main block with the contents of the resource.
- // Usually, resources use a basic set of optional statements:
- // CHARACTERISTICS, LANGUAGE, VERSION
- // However, DIALOG and DIALOGEX extend this list by the following items:
- // CAPTION, CLASS, EXSTYLE, FONT, MENU, STYLE
- // UseExtendedStatements flag (off by default) allows the parser to read
- // the additional types of statements.
- //
- // Ref (to the list of all optional statements):
- // msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
- enum class OptStmtType { BasicStmt, DialogStmt, DialogExStmt };
-
- uint16_t parseMemoryFlags(uint16_t DefaultFlags);
-
- Expected<OptionalStmtList>
- parseOptionalStatements(OptStmtType StmtsType = OptStmtType::BasicStmt);
-
- // Read a single optional statement.
- Expected<std::unique_ptr<OptionalStmt>>
- parseSingleOptionalStatement(OptStmtType StmtsType = OptStmtType::BasicStmt);
-
- // Top-level resource parsers.
- ParseType parseLanguageResource();
- ParseType parseAcceleratorsResource();
- ParseType parseBitmapResource();
- ParseType parseCursorResource();
- ParseType parseDialogResource(bool IsExtended);
- ParseType parseIconResource();
- ParseType parseHTMLResource();
- ParseType parseMenuResource();
- ParseType parseStringTableResource();
- ParseType parseUserDefinedResource(IntOrString Type);
- ParseType parseVersionInfoResource();
-
- // Helper DIALOG parser - a single control.
- Expected<Control> parseControl();
-
- // Helper MENU parser.
- Expected<MenuDefinitionList> parseMenuItemsList();
-
- // Helper VERSIONINFO parser - read the contents of a single BLOCK statement,
- // from BEGIN to END.
- Expected<std::unique_ptr<VersionInfoBlock>>
- parseVersionInfoBlockContents(StringRef BlockName);
- // Helper VERSIONINFO parser - read either VALUE or BLOCK statement.
- Expected<std::unique_ptr<VersionInfoStmt>> parseVersionInfoStmt();
- // Helper VERSIONINFO parser - read fixed VERSIONINFO statements.
- Expected<VersionInfoResource::VersionInfoFixed> parseVersionInfoFixed();
-
- // Optional statement parsers.
- ParseOptionType parseLanguageStmt();
- ParseOptionType parseCharacteristicsStmt();
- ParseOptionType parseVersionStmt();
- ParseOptionType parseCaptionStmt();
- ParseOptionType parseClassStmt();
- ParseOptionType parseExStyleStmt();
- ParseOptionType parseFontStmt(OptStmtType DialogType);
- 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
- // the correctly read token that makes no sense (that is, the current parser
- // state is beyond the erroneous token.)
- Error getExpectedError(const Twine &Message, bool IsAlreadyRead = false);
-
- std::vector<RCToken> Tokens;
- LocIter CurLoc;
- const LocIter End;
-};
-
-} // namespace rc
-} // namespace llvm
-
-#endif
+//===-- ResourceScriptParser.h ----------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This defines the RC scripts parser. It takes a sequence of RC tokens
+// and then provides the method to parse the resources one by one.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H
+
+#include "ResourceScriptStmt.h"
+#include "ResourceScriptToken.h"
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <system_error>
+#include <vector>
+
+namespace llvm {
+namespace opt {
+class InputArgList;
+}
+namespace rc {
+
+class RCParser {
+public:
+ using LocIter = std::vector<RCToken>::iterator;
+ using ParseType = Expected<std::unique_ptr<RCResource>>;
+ using ParseOptionType = Expected<std::unique_ptr<OptionalStmt>>;
+
+ // Class describing a single failure of parser.
+ class ParserError : public ErrorInfo<ParserError> {
+ public:
+ ParserError(const Twine &Expected, const LocIter CurLoc, const LocIter End);
+
+ void log(raw_ostream &OS) const override { OS << CurMessage; }
+ std::error_code convertToErrorCode() const override {
+ return std::make_error_code(std::errc::invalid_argument);
+ }
+ const std::string &getMessage() const { return CurMessage; }
+
+ static char ID; // Keep llvm::Error happy.
+
+ private:
+ std::string CurMessage;
+ LocIter ErrorLoc, FileEnd;
+ };
+
+ explicit RCParser(std::vector<RCToken> TokenList);
+
+ // Reads and returns a single resource definition, or error message if any
+ // occurred.
+ ParseType parseSingleResource();
+
+ bool isEof() const;
+
+private:
+ using Kind = RCToken::Kind;
+
+ // Checks if the current parser state points to the token of type TokenKind.
+ bool isNextTokenKind(Kind TokenKind) const;
+
+ // These methods assume that the parser is not in EOF state.
+
+ // Take a look at the current token. Do not fetch it.
+ const RCToken &look() const;
+ // Read the current token and advance the state by one token.
+ const RCToken &read();
+ // Advance the state by one token, discarding the current token.
+ void consume();
+
+ // The following methods try to read a single token, check if it has the
+ // correct type and then parse it.
+ // Each integer can be written as an arithmetic expression producing an
+ // unsigned 32-bit integer.
+ Expected<RCInt> readInt(); // Parse an integer.
+ Expected<StringRef> readString(); // Parse a string.
+ Expected<StringRef> readIdentifier(); // Parse an identifier.
+ Expected<StringRef> readFilename(); // Parse a filename.
+ Expected<IntOrString> readIntOrString(); // Parse an integer or a string.
+ Expected<IntOrString> readTypeOrName(); // Parse an integer or an identifier.
+
+ // Helper integer expression parsing methods.
+ Expected<IntWithNotMask> parseIntExpr1();
+ Expected<IntWithNotMask> parseIntExpr2();
+
+ // Advance the state by one, discarding the current token.
+ // If the discarded token had an incorrect type, fail.
+ Error consumeType(Kind TokenKind);
+
+ // Check the current token type. If it's TokenKind, discard it.
+ // Return true if the parser consumed this token successfully.
+ bool consumeOptionalType(Kind TokenKind);
+
+ // Read at least MinCount, and at most MaxCount integers separated by
+ // commas. The parser stops reading after fetching MaxCount integers
+ // or after an error occurs. Whenever the parser reads a comma, it
+ // expects an integer to follow.
+ Expected<SmallVector<RCInt, 8>> readIntsWithCommas(size_t MinCount,
+ size_t MaxCount);
+
+ // 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 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<uint32_t> parseFlags(ArrayRef<StringRef> FlagDesc,
+ ArrayRef<uint32_t> 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
+ // before the main block with the contents of the resource.
+ // Usually, resources use a basic set of optional statements:
+ // CHARACTERISTICS, LANGUAGE, VERSION
+ // However, DIALOG and DIALOGEX extend this list by the following items:
+ // CAPTION, CLASS, EXSTYLE, FONT, MENU, STYLE
+ // UseExtendedStatements flag (off by default) allows the parser to read
+ // the additional types of statements.
+ //
+ // Ref (to the list of all optional statements):
+ // msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx
+ enum class OptStmtType { BasicStmt, DialogStmt, DialogExStmt };
+
+ uint16_t parseMemoryFlags(uint16_t DefaultFlags);
+
+ Expected<OptionalStmtList>
+ parseOptionalStatements(OptStmtType StmtsType = OptStmtType::BasicStmt);
+
+ // Read a single optional statement.
+ Expected<std::unique_ptr<OptionalStmt>>
+ parseSingleOptionalStatement(OptStmtType StmtsType = OptStmtType::BasicStmt);
+
+ // Top-level resource parsers.
+ ParseType parseLanguageResource();
+ ParseType parseAcceleratorsResource();
+ ParseType parseBitmapResource();
+ ParseType parseCursorResource();
+ ParseType parseDialogResource(bool IsExtended);
+ ParseType parseIconResource();
+ ParseType parseHTMLResource();
+ ParseType parseMenuResource();
+ ParseType parseStringTableResource();
+ ParseType parseUserDefinedResource(IntOrString Type);
+ ParseType parseVersionInfoResource();
+
+ // Helper DIALOG parser - a single control.
+ Expected<Control> parseControl();
+
+ // Helper MENU parser.
+ Expected<MenuDefinitionList> parseMenuItemsList();
+
+ // Helper VERSIONINFO parser - read the contents of a single BLOCK statement,
+ // from BEGIN to END.
+ Expected<std::unique_ptr<VersionInfoBlock>>
+ parseVersionInfoBlockContents(StringRef BlockName);
+ // Helper VERSIONINFO parser - read either VALUE or BLOCK statement.
+ Expected<std::unique_ptr<VersionInfoStmt>> parseVersionInfoStmt();
+ // Helper VERSIONINFO parser - read fixed VERSIONINFO statements.
+ Expected<VersionInfoResource::VersionInfoFixed> parseVersionInfoFixed();
+
+ // Optional statement parsers.
+ ParseOptionType parseLanguageStmt();
+ ParseOptionType parseCharacteristicsStmt();
+ ParseOptionType parseVersionStmt();
+ ParseOptionType parseCaptionStmt();
+ ParseOptionType parseClassStmt();
+ ParseOptionType parseExStyleStmt();
+ ParseOptionType parseFontStmt(OptStmtType DialogType);
+ 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
+ // the correctly read token that makes no sense (that is, the current parser
+ // state is beyond the erroneous token.)
+ Error getExpectedError(const Twine &Message, bool IsAlreadyRead = false);
+
+ std::vector<RCToken> Tokens;
+ LocIter CurLoc;
+ const LocIter End;
+};
+
+} // namespace rc
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp
index eaf9711af6..ef8c345418 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.cpp
@@ -1,294 +1,294 @@
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This implements methods defined in ResourceScriptStmt.h.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380599(v=vs.85).aspx
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceScriptStmt.h"
-
-namespace llvm {
-namespace rc {
-
-raw_ostream &operator<<(raw_ostream &OS, const IntOrString &Item) {
- if (Item.IsInt)
- return OS << Item.Data.Int;
- else
- return OS << Item.Data.String;
-}
-
-raw_ostream &OptionalStmtList::log(raw_ostream &OS) const {
- for (const auto &Stmt : Statements) {
- OS << " Option: ";
- Stmt->log(OS);
- }
- return OS;
-}
-
-raw_ostream &LanguageResource::log(raw_ostream &OS) const {
- return OS << "Language: " << Lang << ", Sublanguage: " << SubLang << "\n";
-}
-
-StringRef AcceleratorsResource::Accelerator::OptionsStr
- [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);
- for (const auto &Acc : Accelerators) {
- OS << " Accelerator: " << Acc.Event << " " << Acc.Id;
- for (size_t i = 0; i < Accelerator::NumFlags; ++i)
- if (Acc.Flags & Accelerator::OptionsFlags[i])
- OS << " " << Accelerator::OptionsStr[i];
- OS << "\n";
- }
- return OS;
-}
-
-raw_ostream &BitmapResource::log(raw_ostream &OS) const {
- return OS << "Bitmap (" << ResName << "): " << BitmapLoc << "\n";
-}
-
-raw_ostream &CursorResource::log(raw_ostream &OS) const {
- return OS << "Cursor (" << ResName << "): " << CursorLoc << "\n";
-}
-
-raw_ostream &IconResource::log(raw_ostream &OS) const {
- return OS << "Icon (" << ResName << "): " << IconLoc << "\n";
-}
-
-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"};
-
-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 & OptionsFlags[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);
- for (const auto &String : Table) {
- OS << " " << String.first << " =>";
- for (const auto &S : String.second)
- OS << " " << S;
- OS << "\n";
- }
- return OS;
-}
-
-const StringMap<Control::CtlInfo> Control::SupportedCtls = {
- {"LTEXT", CtlInfo{0x50020000, ClsStatic, true}},
- {"CTEXT", CtlInfo{0x50020001, ClsStatic, true}},
- {"RTEXT", CtlInfo{0x50020002, ClsStatic, true}},
- {"ICON", CtlInfo{0x50000003, ClsStatic, true}},
- {"PUSHBUTTON", CtlInfo{0x50010000, ClsButton, true}},
- {"DEFPUSHBUTTON", CtlInfo{0x50010001, ClsButton, true}},
- {"AUTO3STATE", CtlInfo{0x50010006, ClsButton, true}},
- {"AUTOCHECKBOX", CtlInfo{0x50010003, ClsButton, true}},
- {"AUTORADIOBUTTON", CtlInfo{0x50000009, ClsButton, true}},
- {"CHECKBOX", CtlInfo{0x50010002, ClsButton, true}},
- {"GROUPBOX", CtlInfo{0x50000007, ClsButton, true}},
- {"RADIOBUTTON", CtlInfo{0x50000004, ClsButton, true}},
- {"STATE3", CtlInfo{0x50010005, ClsButton, true}},
- {"PUSHBOX", CtlInfo{0x5001000A, ClsButton, true}},
- {"EDITTEXT", CtlInfo{0x50810000, ClsEdit, false}},
- {"COMBOBOX", CtlInfo{0x50000000, ClsComboBox, false}},
- {"LISTBOX", CtlInfo{0x50800001, ClsListBox, false}},
- {"SCROLLBAR", CtlInfo{0x50000000, ClsScrollBar, false}},
- {"CONTROL", CtlInfo{0x50000000, 0, true}},
-};
-
-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).getValue();
- 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 &VersionInfoBlock::log(raw_ostream &OS) const {
- OS << " Start of block (name: " << Name << ")\n";
- for (auto &Stmt : Stmts)
- Stmt->log(OS);
- return OS << " End of block\n";
-}
-
-raw_ostream &VersionInfoValue::log(raw_ostream &OS) const {
- OS << " " << Key << " =>";
- size_t NumValues = Values.size();
- for (size_t Id = 0; Id < NumValues; ++Id) {
- if (Id > 0 && HasPrecedingComma[Id])
- OS << ",";
- OS << " " << Values[Id];
- }
- return OS << "\n";
-}
-
-using VersionInfoFixed = VersionInfoResource::VersionInfoFixed;
-using VersionInfoFixedType = VersionInfoFixed::VersionInfoFixedType;
-
-const StringRef
- VersionInfoFixed::FixedFieldsNames[VersionInfoFixed::FtNumTypes] = {
- "", "FILEVERSION", "PRODUCTVERSION", "FILEFLAGSMASK",
- "FILEFLAGS", "FILEOS", "FILETYPE", "FILESUBTYPE"};
-
-const StringMap<VersionInfoFixedType> VersionInfoFixed::FixedFieldsInfoMap = {
- {FixedFieldsNames[FtFileVersion], FtFileVersion},
- {FixedFieldsNames[FtProductVersion], FtProductVersion},
- {FixedFieldsNames[FtFileFlagsMask], FtFileFlagsMask},
- {FixedFieldsNames[FtFileFlags], FtFileFlags},
- {FixedFieldsNames[FtFileOS], FtFileOS},
- {FixedFieldsNames[FtFileType], FtFileType},
- {FixedFieldsNames[FtFileSubtype], FtFileSubtype}};
-
-VersionInfoFixedType VersionInfoFixed::getFixedType(StringRef Type) {
- auto UpperType = Type.upper();
- auto Iter = FixedFieldsInfoMap.find(UpperType);
- if (Iter != FixedFieldsInfoMap.end())
- return Iter->getValue();
- return FtUnknown;
-}
-
-bool VersionInfoFixed::isTypeSupported(VersionInfoFixedType Type) {
- return FtUnknown < Type && Type < FtNumTypes;
-}
-
-bool VersionInfoFixed::isVersionType(VersionInfoFixedType Type) {
- switch (Type) {
- case FtFileVersion:
- case FtProductVersion:
- return true;
-
- default:
- return false;
- }
-}
-
-raw_ostream &VersionInfoFixed::log(raw_ostream &OS) const {
- for (int Type = FtUnknown; Type < FtNumTypes; ++Type) {
- if (!isTypeSupported((VersionInfoFixedType)Type))
- continue;
- OS << " Fixed: " << FixedFieldsNames[Type] << ":";
- for (uint32_t Val : FixedInfo[Type])
- OS << " " << Val;
- OS << "\n";
- }
- return OS;
-}
-
-raw_ostream &VersionInfoResource::log(raw_ostream &OS) const {
- OS << "VersionInfo (" << ResName << "):\n";
- FixedData.log(OS);
- return MainBlock.log(OS);
-}
-
-raw_ostream &UserDefinedResource::log(raw_ostream &OS) const {
- OS << "User-defined (type: " << Type << ", name: " << ResName << "): ";
- if (IsFileResource)
- return OS << FileLoc << "\n";
- OS << "data = ";
- for (auto &Item : Contents)
- OS << Item << " ";
- return OS << "\n";
-}
-
-raw_ostream &CharacteristicsStmt::log(raw_ostream &OS) const {
- return OS << "Characteristics: " << Value << "\n";
-}
-
-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 &ClassStmt::log(raw_ostream &OS) const {
- return OS << "Class: " << Value << "\n";
-}
-
-raw_ostream &FontStmt::log(raw_ostream &OS) const {
- OS << "Font: size = " << Size << ", face = " << Name
- << ", weight = " << Weight;
- if (Italic)
- OS << ", italic";
- return OS << ", charset = " << Charset << "\n";
-}
-
-raw_ostream &StyleStmt::log(raw_ostream &OS) const {
- return OS << "Style: " << Value << "\n";
-}
-
-raw_ostream &ExStyleStmt::log(raw_ostream &OS) const {
- return OS << "ExStyle: " << Value << "\n";
-}
-
-} // namespace rc
-} // namespace llvm
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This implements methods defined in ResourceScriptStmt.h.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380599(v=vs.85).aspx
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceScriptStmt.h"
+
+namespace llvm {
+namespace rc {
+
+raw_ostream &operator<<(raw_ostream &OS, const IntOrString &Item) {
+ if (Item.IsInt)
+ return OS << Item.Data.Int;
+ else
+ return OS << Item.Data.String;
+}
+
+raw_ostream &OptionalStmtList::log(raw_ostream &OS) const {
+ for (const auto &Stmt : Statements) {
+ OS << " Option: ";
+ Stmt->log(OS);
+ }
+ return OS;
+}
+
+raw_ostream &LanguageResource::log(raw_ostream &OS) const {
+ return OS << "Language: " << Lang << ", Sublanguage: " << SubLang << "\n";
+}
+
+StringRef AcceleratorsResource::Accelerator::OptionsStr
+ [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);
+ for (const auto &Acc : Accelerators) {
+ OS << " Accelerator: " << Acc.Event << " " << Acc.Id;
+ for (size_t i = 0; i < Accelerator::NumFlags; ++i)
+ if (Acc.Flags & Accelerator::OptionsFlags[i])
+ OS << " " << Accelerator::OptionsStr[i];
+ OS << "\n";
+ }
+ return OS;
+}
+
+raw_ostream &BitmapResource::log(raw_ostream &OS) const {
+ return OS << "Bitmap (" << ResName << "): " << BitmapLoc << "\n";
+}
+
+raw_ostream &CursorResource::log(raw_ostream &OS) const {
+ return OS << "Cursor (" << ResName << "): " << CursorLoc << "\n";
+}
+
+raw_ostream &IconResource::log(raw_ostream &OS) const {
+ return OS << "Icon (" << ResName << "): " << IconLoc << "\n";
+}
+
+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"};
+
+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 & OptionsFlags[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);
+ for (const auto &String : Table) {
+ OS << " " << String.first << " =>";
+ for (const auto &S : String.second)
+ OS << " " << S;
+ OS << "\n";
+ }
+ return OS;
+}
+
+const StringMap<Control::CtlInfo> Control::SupportedCtls = {
+ {"LTEXT", CtlInfo{0x50020000, ClsStatic, true}},
+ {"CTEXT", CtlInfo{0x50020001, ClsStatic, true}},
+ {"RTEXT", CtlInfo{0x50020002, ClsStatic, true}},
+ {"ICON", CtlInfo{0x50000003, ClsStatic, true}},
+ {"PUSHBUTTON", CtlInfo{0x50010000, ClsButton, true}},
+ {"DEFPUSHBUTTON", CtlInfo{0x50010001, ClsButton, true}},
+ {"AUTO3STATE", CtlInfo{0x50010006, ClsButton, true}},
+ {"AUTOCHECKBOX", CtlInfo{0x50010003, ClsButton, true}},
+ {"AUTORADIOBUTTON", CtlInfo{0x50000009, ClsButton, true}},
+ {"CHECKBOX", CtlInfo{0x50010002, ClsButton, true}},
+ {"GROUPBOX", CtlInfo{0x50000007, ClsButton, true}},
+ {"RADIOBUTTON", CtlInfo{0x50000004, ClsButton, true}},
+ {"STATE3", CtlInfo{0x50010005, ClsButton, true}},
+ {"PUSHBOX", CtlInfo{0x5001000A, ClsButton, true}},
+ {"EDITTEXT", CtlInfo{0x50810000, ClsEdit, false}},
+ {"COMBOBOX", CtlInfo{0x50000000, ClsComboBox, false}},
+ {"LISTBOX", CtlInfo{0x50800001, ClsListBox, false}},
+ {"SCROLLBAR", CtlInfo{0x50000000, ClsScrollBar, false}},
+ {"CONTROL", CtlInfo{0x50000000, 0, true}},
+};
+
+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).getValue();
+ 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 &VersionInfoBlock::log(raw_ostream &OS) const {
+ OS << " Start of block (name: " << Name << ")\n";
+ for (auto &Stmt : Stmts)
+ Stmt->log(OS);
+ return OS << " End of block\n";
+}
+
+raw_ostream &VersionInfoValue::log(raw_ostream &OS) const {
+ OS << " " << Key << " =>";
+ size_t NumValues = Values.size();
+ for (size_t Id = 0; Id < NumValues; ++Id) {
+ if (Id > 0 && HasPrecedingComma[Id])
+ OS << ",";
+ OS << " " << Values[Id];
+ }
+ return OS << "\n";
+}
+
+using VersionInfoFixed = VersionInfoResource::VersionInfoFixed;
+using VersionInfoFixedType = VersionInfoFixed::VersionInfoFixedType;
+
+const StringRef
+ VersionInfoFixed::FixedFieldsNames[VersionInfoFixed::FtNumTypes] = {
+ "", "FILEVERSION", "PRODUCTVERSION", "FILEFLAGSMASK",
+ "FILEFLAGS", "FILEOS", "FILETYPE", "FILESUBTYPE"};
+
+const StringMap<VersionInfoFixedType> VersionInfoFixed::FixedFieldsInfoMap = {
+ {FixedFieldsNames[FtFileVersion], FtFileVersion},
+ {FixedFieldsNames[FtProductVersion], FtProductVersion},
+ {FixedFieldsNames[FtFileFlagsMask], FtFileFlagsMask},
+ {FixedFieldsNames[FtFileFlags], FtFileFlags},
+ {FixedFieldsNames[FtFileOS], FtFileOS},
+ {FixedFieldsNames[FtFileType], FtFileType},
+ {FixedFieldsNames[FtFileSubtype], FtFileSubtype}};
+
+VersionInfoFixedType VersionInfoFixed::getFixedType(StringRef Type) {
+ auto UpperType = Type.upper();
+ auto Iter = FixedFieldsInfoMap.find(UpperType);
+ if (Iter != FixedFieldsInfoMap.end())
+ return Iter->getValue();
+ return FtUnknown;
+}
+
+bool VersionInfoFixed::isTypeSupported(VersionInfoFixedType Type) {
+ return FtUnknown < Type && Type < FtNumTypes;
+}
+
+bool VersionInfoFixed::isVersionType(VersionInfoFixedType Type) {
+ switch (Type) {
+ case FtFileVersion:
+ case FtProductVersion:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+raw_ostream &VersionInfoFixed::log(raw_ostream &OS) const {
+ for (int Type = FtUnknown; Type < FtNumTypes; ++Type) {
+ if (!isTypeSupported((VersionInfoFixedType)Type))
+ continue;
+ OS << " Fixed: " << FixedFieldsNames[Type] << ":";
+ for (uint32_t Val : FixedInfo[Type])
+ OS << " " << Val;
+ OS << "\n";
+ }
+ return OS;
+}
+
+raw_ostream &VersionInfoResource::log(raw_ostream &OS) const {
+ OS << "VersionInfo (" << ResName << "):\n";
+ FixedData.log(OS);
+ return MainBlock.log(OS);
+}
+
+raw_ostream &UserDefinedResource::log(raw_ostream &OS) const {
+ OS << "User-defined (type: " << Type << ", name: " << ResName << "): ";
+ if (IsFileResource)
+ return OS << FileLoc << "\n";
+ OS << "data = ";
+ for (auto &Item : Contents)
+ OS << Item << " ";
+ return OS << "\n";
+}
+
+raw_ostream &CharacteristicsStmt::log(raw_ostream &OS) const {
+ return OS << "Characteristics: " << Value << "\n";
+}
+
+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 &ClassStmt::log(raw_ostream &OS) const {
+ return OS << "Class: " << Value << "\n";
+}
+
+raw_ostream &FontStmt::log(raw_ostream &OS) const {
+ OS << "Font: size = " << Size << ", face = " << Name
+ << ", weight = " << Weight;
+ if (Italic)
+ OS << ", italic";
+ return OS << ", charset = " << Charset << "\n";
+}
+
+raw_ostream &StyleStmt::log(raw_ostream &OS) const {
+ return OS << "Style: " << Value << "\n";
+}
+
+raw_ostream &ExStyleStmt::log(raw_ostream &OS) const {
+ return OS << "ExStyle: " << Value << "\n";
+}
+
+} // namespace rc
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h
index 0b56f39f83..27fbea3ae8 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptStmt.h
@@ -1,953 +1,953 @@
-//===-- ResourceScriptStmt.h ------------------------------------*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This lists all the resource and statement types occurring in RC scripts.
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
-
-#include "ResourceScriptToken.h"
-#include "ResourceVisitor.h"
-
-#include "llvm/ADT/StringSet.h"
-
-namespace llvm {
-namespace rc {
-
-// Integer wrapper that also holds information whether the user declared
-// the integer to be long (by appending L to the end of the integer) or not.
-// It allows to be implicitly cast from and to uint32_t in order
-// to be compatible with the parts of code that don't care about the integers
-// being marked long.
-class RCInt {
- uint32_t Val;
- bool Long;
-
-public:
- RCInt(const RCToken &Token)
- : Val(Token.intValue()), Long(Token.isLongInt()) {}
- RCInt(uint32_t Value) : Val(Value), Long(false) {}
- RCInt(uint32_t Value, bool IsLong) : Val(Value), Long(IsLong) {}
- operator uint32_t() const { return Val; }
- bool isLong() const { return Long; }
-
- RCInt &operator+=(const RCInt &Rhs) {
- std::tie(Val, Long) = std::make_pair(Val + Rhs.Val, Long | Rhs.Long);
- return *this;
- }
-
- RCInt &operator-=(const RCInt &Rhs) {
- std::tie(Val, Long) = std::make_pair(Val - Rhs.Val, Long | Rhs.Long);
- return *this;
- }
-
- RCInt &operator|=(const RCInt &Rhs) {
- std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long);
- return *this;
- }
-
- RCInt &operator&=(const RCInt &Rhs) {
- std::tie(Val, Long) = std::make_pair(Val & Rhs.Val, Long | Rhs.Long);
- return *this;
- }
-
- RCInt operator-() const { return {-Val, Long}; }
- RCInt operator~() const { return {~Val, Long}; }
-
- friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) {
- return OS << Int.Val << (Int.Long ? "L" : "");
- }
-};
-
-class IntWithNotMask {
-private:
- RCInt Value;
- int32_t NotMask;
-
-public:
- IntWithNotMask() : IntWithNotMask(RCInt(0)) {}
- IntWithNotMask(RCInt Value, int32_t NotMask = 0) : Value(Value), NotMask(NotMask) {}
-
- RCInt getValue() const {
- return Value;
- }
-
- uint32_t getNotMask() const {
- return NotMask;
- }
-
- IntWithNotMask &operator+=(const IntWithNotMask &Rhs) {
- Value &= ~Rhs.NotMask;
- Value += Rhs.Value;
- NotMask |= Rhs.NotMask;
- return *this;
- }
-
- IntWithNotMask &operator-=(const IntWithNotMask &Rhs) {
- Value &= ~Rhs.NotMask;
- Value -= Rhs.Value;
- NotMask |= Rhs.NotMask;
- return *this;
- }
-
- IntWithNotMask &operator|=(const IntWithNotMask &Rhs) {
- Value &= ~Rhs.NotMask;
- Value |= Rhs.Value;
- NotMask |= Rhs.NotMask;
- return *this;
- }
-
- IntWithNotMask &operator&=(const IntWithNotMask &Rhs) {
- Value &= ~Rhs.NotMask;
- Value &= Rhs.Value;
- NotMask |= Rhs.NotMask;
- return *this;
- }
-
- IntWithNotMask operator-() const { return {-Value, NotMask}; }
- IntWithNotMask operator~() const { return {~Value, 0}; }
-
- friend raw_ostream &operator<<(raw_ostream &OS, const IntWithNotMask &Int) {
- return OS << Int.Value;
- }
-};
-
-// A class holding a name - either an integer or a reference to the string.
-class IntOrString {
-private:
- union Data {
- RCInt Int;
- StringRef String;
- Data(RCInt Value) : Int(Value) {}
- Data(const StringRef Value) : String(Value) {}
- Data(const RCToken &Token) {
- if (Token.kind() == RCToken::Kind::Int)
- Int = RCInt(Token);
- else
- String = Token.value();
- }
- } Data;
- bool IsInt;
-
-public:
- IntOrString() : IntOrString(RCInt(0)) {}
- IntOrString(uint32_t Value) : Data(Value), IsInt(1) {}
- IntOrString(RCInt Value) : Data(Value), IsInt(1) {}
- IntOrString(StringRef Value) : Data(Value), IsInt(0) {}
- IntOrString(const RCToken &Token)
- : Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {}
-
- bool equalsLower(const char *Str) {
- return !IsInt && Data.String.equals_lower(Str);
- }
-
- bool isInt() const { return IsInt; }
-
- RCInt getInt() const {
- assert(IsInt);
- return Data.Int;
- }
-
- const StringRef &getString() const {
- assert(!IsInt);
- return Data.String;
- }
-
- operator Twine() const {
- return isInt() ? Twine(getInt()) : Twine(getString());
- }
-
- friend raw_ostream &operator<<(raw_ostream &, const IntOrString &);
-};
-
-enum ResourceKind {
- // These resource kinds have corresponding .res resource type IDs
- // (TYPE in RESOURCEHEADER structure). The numeric value assigned to each
- // kind is equal to this type ID.
- RkNull = 0,
- RkSingleCursor = 1,
- RkBitmap = 2,
- RkSingleIcon = 3,
- RkMenu = 4,
- RkDialog = 5,
- RkStringTableBundle = 6,
- RkAccelerators = 9,
- RkRcData = 10,
- RkCursorGroup = 12,
- RkIconGroup = 14,
- RkVersionInfo = 16,
- RkHTML = 23,
-
- // These kinds don't have assigned type IDs (they might be the resources
- // of invalid kind, expand to many resource structures in .res files,
- // or have variable type ID). In order to avoid ID clashes with IDs above,
- // we assign the kinds the values 256 and larger.
- RkInvalid = 256,
- RkBase,
- RkCursor,
- RkIcon,
- RkStringTable,
- RkUser,
- RkSingleCursorOrIconRes,
- RkCursorOrIconGroupRes,
-};
-
-// Non-zero memory flags.
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
-enum MemoryFlags {
- MfMoveable = 0x10,
- MfPure = 0x20,
- MfPreload = 0x40,
- MfDiscardable = 0x1000
-};
-
-// Base resource. All the resources should derive from this base.
-class RCResource {
-public:
- IntOrString ResName;
- uint16_t MemoryFlags = getDefaultMemoryFlags();
- void setName(const IntOrString &Name) { ResName = Name; }
- virtual raw_ostream &log(raw_ostream &OS) const {
- return OS << "Base statement\n";
- };
- RCResource() {}
- RCResource(uint16_t Flags) : MemoryFlags(Flags) {}
- virtual ~RCResource() {}
-
- virtual Error visit(Visitor *) const {
- llvm_unreachable("This is unable to call methods from Visitor base");
- }
-
- // Apply the statements attached to this resource. Generic resources
- // don't have any.
- virtual Error applyStmts(Visitor *) const { return Error::success(); }
-
- // By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
- static uint16_t getDefaultMemoryFlags() {
- return MfDiscardable | MfPure | MfMoveable;
- }
-
- virtual ResourceKind getKind() const { return RkBase; }
- static bool classof(const RCResource *Res) { return true; }
-
- virtual IntOrString getResourceType() const {
- llvm_unreachable("This cannot be called on objects without types.");
- }
- virtual Twine getResourceTypeName() const {
- llvm_unreachable("This cannot be called on objects without types.");
- };
-};
-
-// An empty resource. It has no content, type 0, ID 0 and all of its
-// characteristics are equal to 0.
-class NullResource : public RCResource {
-public:
- NullResource() : RCResource(0) {}
- raw_ostream &log(raw_ostream &OS) const override {
- return OS << "Null resource\n";
- }
- Error visit(Visitor *V) const override { return V->visitNullResource(this); }
- IntOrString getResourceType() const override { return 0; }
- Twine getResourceTypeName() const override { return "(NULL)"; }
-};
-
-// Optional statement base. All such statements should derive from this base.
-class OptionalStmt : public RCResource {};
-
-class OptionalStmtList : public OptionalStmt {
- std::vector<std::unique_ptr<OptionalStmt>> Statements;
-
-public:
- OptionalStmtList() {}
- raw_ostream &log(raw_ostream &OS) const override;
-
- void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
- Statements.push_back(std::move(Stmt));
- }
-
- Error visit(Visitor *V) const override {
- for (auto &StmtPtr : Statements)
- if (auto Err = StmtPtr->visit(V))
- return Err;
- return Error::success();
- }
-};
-
-class OptStatementsRCResource : public RCResource {
-public:
- std::unique_ptr<OptionalStmtList> OptStatements;
-
- OptStatementsRCResource(OptionalStmtList &&Stmts,
- uint16_t Flags = RCResource::getDefaultMemoryFlags())
- : RCResource(Flags),
- OptStatements(std::make_unique<OptionalStmtList>(std::move(Stmts))) {}
-
+//===-- ResourceScriptStmt.h ------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This lists all the resource and statement types occurring in RC scripts.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
+
+#include "ResourceScriptToken.h"
+#include "ResourceVisitor.h"
+
+#include "llvm/ADT/StringSet.h"
+
+namespace llvm {
+namespace rc {
+
+// Integer wrapper that also holds information whether the user declared
+// the integer to be long (by appending L to the end of the integer) or not.
+// It allows to be implicitly cast from and to uint32_t in order
+// to be compatible with the parts of code that don't care about the integers
+// being marked long.
+class RCInt {
+ uint32_t Val;
+ bool Long;
+
+public:
+ RCInt(const RCToken &Token)
+ : Val(Token.intValue()), Long(Token.isLongInt()) {}
+ RCInt(uint32_t Value) : Val(Value), Long(false) {}
+ RCInt(uint32_t Value, bool IsLong) : Val(Value), Long(IsLong) {}
+ operator uint32_t() const { return Val; }
+ bool isLong() const { return Long; }
+
+ RCInt &operator+=(const RCInt &Rhs) {
+ std::tie(Val, Long) = std::make_pair(Val + Rhs.Val, Long | Rhs.Long);
+ return *this;
+ }
+
+ RCInt &operator-=(const RCInt &Rhs) {
+ std::tie(Val, Long) = std::make_pair(Val - Rhs.Val, Long | Rhs.Long);
+ return *this;
+ }
+
+ RCInt &operator|=(const RCInt &Rhs) {
+ std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long);
+ return *this;
+ }
+
+ RCInt &operator&=(const RCInt &Rhs) {
+ std::tie(Val, Long) = std::make_pair(Val & Rhs.Val, Long | Rhs.Long);
+ return *this;
+ }
+
+ RCInt operator-() const { return {-Val, Long}; }
+ RCInt operator~() const { return {~Val, Long}; }
+
+ friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) {
+ return OS << Int.Val << (Int.Long ? "L" : "");
+ }
+};
+
+class IntWithNotMask {
+private:
+ RCInt Value;
+ int32_t NotMask;
+
+public:
+ IntWithNotMask() : IntWithNotMask(RCInt(0)) {}
+ IntWithNotMask(RCInt Value, int32_t NotMask = 0) : Value(Value), NotMask(NotMask) {}
+
+ RCInt getValue() const {
+ return Value;
+ }
+
+ uint32_t getNotMask() const {
+ return NotMask;
+ }
+
+ IntWithNotMask &operator+=(const IntWithNotMask &Rhs) {
+ Value &= ~Rhs.NotMask;
+ Value += Rhs.Value;
+ NotMask |= Rhs.NotMask;
+ return *this;
+ }
+
+ IntWithNotMask &operator-=(const IntWithNotMask &Rhs) {
+ Value &= ~Rhs.NotMask;
+ Value -= Rhs.Value;
+ NotMask |= Rhs.NotMask;
+ return *this;
+ }
+
+ IntWithNotMask &operator|=(const IntWithNotMask &Rhs) {
+ Value &= ~Rhs.NotMask;
+ Value |= Rhs.Value;
+ NotMask |= Rhs.NotMask;
+ return *this;
+ }
+
+ IntWithNotMask &operator&=(const IntWithNotMask &Rhs) {
+ Value &= ~Rhs.NotMask;
+ Value &= Rhs.Value;
+ NotMask |= Rhs.NotMask;
+ return *this;
+ }
+
+ IntWithNotMask operator-() const { return {-Value, NotMask}; }
+ IntWithNotMask operator~() const { return {~Value, 0}; }
+
+ friend raw_ostream &operator<<(raw_ostream &OS, const IntWithNotMask &Int) {
+ return OS << Int.Value;
+ }
+};
+
+// A class holding a name - either an integer or a reference to the string.
+class IntOrString {
+private:
+ union Data {
+ RCInt Int;
+ StringRef String;
+ Data(RCInt Value) : Int(Value) {}
+ Data(const StringRef Value) : String(Value) {}
+ Data(const RCToken &Token) {
+ if (Token.kind() == RCToken::Kind::Int)
+ Int = RCInt(Token);
+ else
+ String = Token.value();
+ }
+ } Data;
+ bool IsInt;
+
+public:
+ IntOrString() : IntOrString(RCInt(0)) {}
+ IntOrString(uint32_t Value) : Data(Value), IsInt(1) {}
+ IntOrString(RCInt Value) : Data(Value), IsInt(1) {}
+ IntOrString(StringRef Value) : Data(Value), IsInt(0) {}
+ IntOrString(const RCToken &Token)
+ : Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {}
+
+ bool equalsLower(const char *Str) {
+ return !IsInt && Data.String.equals_lower(Str);
+ }
+
+ bool isInt() const { return IsInt; }
+
+ RCInt getInt() const {
+ assert(IsInt);
+ return Data.Int;
+ }
+
+ const StringRef &getString() const {
+ assert(!IsInt);
+ return Data.String;
+ }
+
+ operator Twine() const {
+ return isInt() ? Twine(getInt()) : Twine(getString());
+ }
+
+ friend raw_ostream &operator<<(raw_ostream &, const IntOrString &);
+};
+
+enum ResourceKind {
+ // These resource kinds have corresponding .res resource type IDs
+ // (TYPE in RESOURCEHEADER structure). The numeric value assigned to each
+ // kind is equal to this type ID.
+ RkNull = 0,
+ RkSingleCursor = 1,
+ RkBitmap = 2,
+ RkSingleIcon = 3,
+ RkMenu = 4,
+ RkDialog = 5,
+ RkStringTableBundle = 6,
+ RkAccelerators = 9,
+ RkRcData = 10,
+ RkCursorGroup = 12,
+ RkIconGroup = 14,
+ RkVersionInfo = 16,
+ RkHTML = 23,
+
+ // These kinds don't have assigned type IDs (they might be the resources
+ // of invalid kind, expand to many resource structures in .res files,
+ // or have variable type ID). In order to avoid ID clashes with IDs above,
+ // we assign the kinds the values 256 and larger.
+ RkInvalid = 256,
+ RkBase,
+ RkCursor,
+ RkIcon,
+ RkStringTable,
+ RkUser,
+ RkSingleCursorOrIconRes,
+ RkCursorOrIconGroupRes,
+};
+
+// Non-zero memory flags.
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648027(v=vs.85).aspx
+enum MemoryFlags {
+ MfMoveable = 0x10,
+ MfPure = 0x20,
+ MfPreload = 0x40,
+ MfDiscardable = 0x1000
+};
+
+// Base resource. All the resources should derive from this base.
+class RCResource {
+public:
+ IntOrString ResName;
+ uint16_t MemoryFlags = getDefaultMemoryFlags();
+ void setName(const IntOrString &Name) { ResName = Name; }
+ virtual raw_ostream &log(raw_ostream &OS) const {
+ return OS << "Base statement\n";
+ };
+ RCResource() {}
+ RCResource(uint16_t Flags) : MemoryFlags(Flags) {}
+ virtual ~RCResource() {}
+
+ virtual Error visit(Visitor *) const {
+ llvm_unreachable("This is unable to call methods from Visitor base");
+ }
+
+ // Apply the statements attached to this resource. Generic resources
+ // don't have any.
+ virtual Error applyStmts(Visitor *) const { return Error::success(); }
+
+ // By default, memory flags are DISCARDABLE | PURE | MOVEABLE.
+ static uint16_t getDefaultMemoryFlags() {
+ return MfDiscardable | MfPure | MfMoveable;
+ }
+
+ virtual ResourceKind getKind() const { return RkBase; }
+ static bool classof(const RCResource *Res) { return true; }
+
+ virtual IntOrString getResourceType() const {
+ llvm_unreachable("This cannot be called on objects without types.");
+ }
+ virtual Twine getResourceTypeName() const {
+ llvm_unreachable("This cannot be called on objects without types.");
+ };
+};
+
+// An empty resource. It has no content, type 0, ID 0 and all of its
+// characteristics are equal to 0.
+class NullResource : public RCResource {
+public:
+ NullResource() : RCResource(0) {}
+ raw_ostream &log(raw_ostream &OS) const override {
+ return OS << "Null resource\n";
+ }
+ Error visit(Visitor *V) const override { return V->visitNullResource(this); }
+ IntOrString getResourceType() const override { return 0; }
+ Twine getResourceTypeName() const override { return "(NULL)"; }
+};
+
+// Optional statement base. All such statements should derive from this base.
+class OptionalStmt : public RCResource {};
+
+class OptionalStmtList : public OptionalStmt {
+ std::vector<std::unique_ptr<OptionalStmt>> Statements;
+
+public:
+ OptionalStmtList() {}
+ raw_ostream &log(raw_ostream &OS) const override;
+
+ void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
+ Statements.push_back(std::move(Stmt));
+ }
+
+ Error visit(Visitor *V) const override {
+ for (auto &StmtPtr : Statements)
+ if (auto Err = StmtPtr->visit(V))
+ return Err;
+ return Error::success();
+ }
+};
+
+class OptStatementsRCResource : public RCResource {
+public:
+ std::unique_ptr<OptionalStmtList> OptStatements;
+
+ OptStatementsRCResource(OptionalStmtList &&Stmts,
+ uint16_t Flags = RCResource::getDefaultMemoryFlags())
+ : RCResource(Flags),
+ OptStatements(std::make_unique<OptionalStmtList>(std::move(Stmts))) {}
+
Error applyStmts(Visitor *V) const override {
return OptStatements->visit(V);
}
-};
-
-// 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
-// of a single resource).
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx
-class LanguageResource : public OptionalStmt {
-public:
- uint32_t Lang, SubLang;
-
- LanguageResource(uint32_t LangId, uint32_t SubLangId)
- : Lang(LangId), SubLang(SubLangId) {}
- raw_ostream &log(raw_ostream &) const override;
-
- // This is not a regular top-level statement; when it occurs, it just
- // modifies the language context.
- Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
- Twine getResourceTypeName() const override { return "LANGUAGE"; }
-};
-
-// 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 OptStatementsRCResource {
-public:
- class Accelerator {
- public:
- IntOrString Event;
- uint32_t Id;
- uint16_t Flags;
-
- enum Options {
- // 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 &&List, uint16_t Flags)
- : OptStatementsRCResource(std::move(List), Flags) {}
-
- std::vector<Accelerator> Accelerators;
-
- void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
- Accelerators.push_back(Accelerator{Event, Id, Flags});
- }
- raw_ostream &log(raw_ostream &) const override;
-
- IntOrString getResourceType() const override { return RkAccelerators; }
- static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
- Twine getResourceTypeName() const override { return "ACCELERATORS"; }
-
- Error visit(Visitor *V) const override {
- return V->visitAcceleratorsResource(this);
- }
- ResourceKind getKind() const override { return RkAccelerators; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkAccelerators;
- }
-};
-
-// BITMAP resource. Represents a bitmap (".bmp") file.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx
-class BitmapResource : public RCResource {
-public:
- StringRef BitmapLoc;
-
- BitmapResource(StringRef Location, uint16_t Flags)
- : RCResource(Flags), BitmapLoc(Location) {}
- raw_ostream &log(raw_ostream &) const override;
-
- IntOrString getResourceType() const override { return RkBitmap; }
- static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
-
- Twine getResourceTypeName() const override { return "BITMAP"; }
- Error visit(Visitor *V) const override {
- return V->visitBitmapResource(this);
- }
- ResourceKind getKind() const override { return RkBitmap; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkBitmap;
- }
-};
-
-// CURSOR resource. Represents a single cursor (".cur") file.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
-class CursorResource : public RCResource {
-public:
- StringRef CursorLoc;
-
- CursorResource(StringRef Location, uint16_t Flags)
- : RCResource(Flags), CursorLoc(Location) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Twine getResourceTypeName() const override { return "CURSOR"; }
- static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
- Error visit(Visitor *V) const override {
- return V->visitCursorResource(this);
- }
- ResourceKind getKind() const override { return RkCursor; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkCursor;
- }
-};
-
-// ICON resource. Represents a single ".ico" file containing a group of icons.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
-class IconResource : public RCResource {
-public:
- StringRef IconLoc;
-
- IconResource(StringRef Location, uint16_t Flags)
- : RCResource(Flags), IconLoc(Location) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Twine getResourceTypeName() const override { return "ICON"; }
- static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
- Error visit(Visitor *V) const override { return V->visitIconResource(this); }
- ResourceKind getKind() const override { return RkIcon; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkIcon;
- }
-};
-
-// HTML resource. Represents a local webpage that is to be embedded into the
-// resulting resource file. It embeds a file only - no additional resources
-// (images etc.) are included with this resource.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx
-class HTMLResource : public RCResource {
-public:
- StringRef HTMLLoc;
-
- HTMLResource(StringRef Location, uint16_t Flags)
- : RCResource(Flags), HTMLLoc(Location) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
-
- // Curiously, file resources don't have DISCARDABLE flag set.
- static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
- IntOrString getResourceType() const override { return RkHTML; }
- Twine getResourceTypeName() const override { return "HTML"; }
- ResourceKind getKind() const override { return RkHTML; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkHTML;
- }
-};
-
-// -- 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 = 0x0008,
- GRAYED = 0x0001,
- HELP = 0x4000,
- INACTIVE = 0x0002,
- MENUBARBREAK = 0x0020,
- MENUBREAK = 0x0040
- };
-
- enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
-
- static constexpr size_t NumFlags = 6;
- static StringRef OptionsStr[NumFlags];
- 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";
- }
- 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;
-
- 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;
-
- 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;
-
- 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;
-
- 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;
-
- MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
- uint16_t Flags)
- : OptStatementsRCResource(std::move(OptStmts), Flags),
- 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.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
-class StringTableResource : public OptStatementsRCResource {
-public:
- std::vector<std::pair<uint32_t, std::vector<StringRef>>> Table;
-
- StringTableResource(OptionalStmtList &&List, uint16_t Flags)
- : OptStatementsRCResource(std::move(List), Flags) {}
- void addStrings(uint32_t ID, std::vector<StringRef> &&Strings) {
- Table.emplace_back(ID, Strings);
- }
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "STRINGTABLE"; }
- Error visit(Visitor *V) const override {
- return V->visitStringTableResource(this);
- }
-};
-
-// -- 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 {
-public:
- StringRef Type;
- IntOrString Title;
- uint32_t ID, X, Y, Width, Height;
- Optional<IntWithNotMask> Style;
- Optional<uint32_t> ExtStyle, HelpID;
- IntOrString Class;
-
- // Control classes as described in DLGITEMTEMPLATEEX documentation.
- //
- // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx
- enum CtlClasses {
- ClsButton = 0x80,
- ClsEdit = 0x81,
- ClsStatic = 0x82,
- ClsListBox = 0x83,
- ClsScrollBar = 0x84,
- ClsComboBox = 0x85
- };
-
- // Simple information about a single control type.
- struct CtlInfo {
- uint32_t Style;
- uint16_t CtlClass;
- bool HasTitle;
- };
-
- Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
- uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
- Optional<IntWithNotMask> ItemStyle, Optional<uint32_t> ExtItemStyle,
- Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
- : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
- Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
- ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
-
- static const StringMap<CtlInfo> SupportedCtls;
-
- 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 OptStatementsRCResource {
-public:
- uint32_t X, Y, Width, Height, HelpID;
- std::vector<Control> Controls;
- bool IsExtended;
-
- DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
- uint32_t DlgHeight, uint32_t DlgHelpID,
- OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
- : OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
- Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
- IsExtended(IsDialogEx) {}
-
- void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
-
- raw_ostream &log(raw_ostream &) const override;
-
- // It was a weird design decision to assign the same resource type number
- // both for DIALOG and DIALOGEX (and the same structure version number).
- // It makes it possible for DIALOG to be mistaken for DIALOGEX.
- IntOrString getResourceType() const override { return RkDialog; }
- Twine getResourceTypeName() const override {
- return "DIALOG" + Twine(IsExtended ? "EX" : "");
- }
- Error visit(Visitor *V) const override {
- return V->visitDialogResource(this);
- }
- ResourceKind getKind() const override { return RkDialog; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkDialog;
- }
-};
-
-// User-defined resource. It is either:
-// * a link to the file, e.g. NAME TYPE "filename",
-// * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}.
-class UserDefinedResource : public RCResource {
-public:
- IntOrString Type;
- StringRef FileLoc;
- std::vector<IntOrString> Contents;
- bool IsFileResource;
-
- UserDefinedResource(IntOrString ResourceType, StringRef FileLocation,
- uint16_t Flags)
- : RCResource(Flags), Type(ResourceType), FileLoc(FileLocation),
- IsFileResource(true) {}
- UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data,
- uint16_t Flags)
- : RCResource(Flags), Type(ResourceType), Contents(std::move(Data)),
- IsFileResource(false) {}
-
- raw_ostream &log(raw_ostream &) const override;
- IntOrString getResourceType() const override { return Type; }
- Twine getResourceTypeName() const override { return Type; }
- static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
-
- Error visit(Visitor *V) const override {
- return V->visitUserDefinedResource(this);
- }
- ResourceKind getKind() const override { return RkUser; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkUser;
- }
-};
-
-// -- VERSIONINFO resource and its helper classes --
-//
-// This resource lists the version information on the executable/library.
-// The declaration consists of the following items:
-// * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS)
-// * BEGIN
-// * A number of BLOCK and/or VALUE statements. BLOCK recursively defines
-// another block of version information, whereas VALUE defines a
-// key -> value correspondence. There might be more than one value
-// corresponding to the single key.
-// * END
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
-
-// A single VERSIONINFO statement;
-class VersionInfoStmt {
-public:
- enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
-
- virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
- virtual ~VersionInfoStmt() {}
-
- virtual StmtKind getKind() const { return StBase; }
- static bool classof(const VersionInfoStmt *S) {
- return S->getKind() == StBase;
- }
-};
-
-// BLOCK definition; also the main VERSIONINFO declaration is considered a
-// BLOCK, although it has no name.
-// The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
-// care about them at the parsing phase.
-class VersionInfoBlock : public VersionInfoStmt {
-public:
- std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
- StringRef Name;
-
- VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
- void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
- Stmts.push_back(std::move(Stmt));
- }
- raw_ostream &log(raw_ostream &) const override;
-
- StmtKind getKind() const override { return StBlock; }
- static bool classof(const VersionInfoStmt *S) {
- return S->getKind() == StBlock;
- }
-};
-
-class VersionInfoValue : public VersionInfoStmt {
-public:
- StringRef Key;
- std::vector<IntOrString> Values;
- std::vector<bool> HasPrecedingComma;
-
- VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
- std::vector<bool> &&CommasBeforeVals)
- : Key(InfoKey), Values(std::move(Vals)),
- HasPrecedingComma(std::move(CommasBeforeVals)) {}
- raw_ostream &log(raw_ostream &) const override;
-
- StmtKind getKind() const override { return StValue; }
- static bool classof(const VersionInfoStmt *S) {
- return S->getKind() == StValue;
- }
-};
-
-class VersionInfoResource : public RCResource {
-public:
- // A class listing fixed VERSIONINFO statements (occuring before main BEGIN).
- // If any of these is not specified, it is assumed by the original tool to
- // be equal to 0.
- class VersionInfoFixed {
- public:
- enum VersionInfoFixedType {
- FtUnknown,
- FtFileVersion,
- FtProductVersion,
- FtFileFlagsMask,
- FtFileFlags,
- FtFileOS,
- FtFileType,
- FtFileSubtype,
- FtNumTypes
- };
-
- private:
- static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
- static const StringRef FixedFieldsNames[FtNumTypes];
-
- public:
- SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
- SmallVector<bool, FtNumTypes> IsTypePresent;
-
- static VersionInfoFixedType getFixedType(StringRef Type);
- static bool isTypeSupported(VersionInfoFixedType Type);
- static bool isVersionType(VersionInfoFixedType Type);
-
- VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
-
- void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
- FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end());
- IsTypePresent[Type] = true;
- }
-
- raw_ostream &log(raw_ostream &) const;
- };
-
- VersionInfoBlock MainBlock;
- VersionInfoFixed FixedData;
-
- VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
- VersionInfoFixed &&FixedInfo, uint16_t Flags)
- : RCResource(Flags), MainBlock(std::move(TopLevelBlock)),
- FixedData(std::move(FixedInfo)) {}
-
- raw_ostream &log(raw_ostream &) const override;
- IntOrString getResourceType() const override { return RkVersionInfo; }
- static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
- Twine getResourceTypeName() const override { return "VERSIONINFO"; }
- Error visit(Visitor *V) const override {
- return V->visitVersionInfoResource(this);
- }
- ResourceKind getKind() const override { return RkVersionInfo; }
- static bool classof(const RCResource *Res) {
- return Res->getKind() == RkVersionInfo;
- }
-};
-
-// CHARACTERISTICS optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
-class CharacteristicsStmt : public OptionalStmt {
-public:
- uint32_t Value;
-
- CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
- Error visit(Visitor *V) const override {
- return V->visitCharacteristicsStmt(this);
- }
-};
-
-// VERSION optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
-class VersionStmt : public OptionalStmt {
-public:
- uint32_t Value;
-
- VersionStmt(uint32_t Version) : Value(Version) {}
- raw_ostream &log(raw_ostream &) const override;
-
- Twine getResourceTypeName() const override { return "VERSION"; }
- Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
-};
-
-// CAPTION optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
-class CaptionStmt : public OptionalStmt {
-public:
- StringRef Value;
-
- CaptionStmt(StringRef Caption) : Value(Caption) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "CAPTION"; }
- Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
-};
-
-// 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 {
-public:
- uint32_t Size, Weight, Charset;
- StringRef Name;
- bool Italic;
-
- FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
- bool FontItalic, uint32_t FontCharset)
- : Size(FontSize), Weight(FontWeight), Charset(FontCharset),
- Name(FontName), Italic(FontItalic) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "FONT"; }
- Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
-};
-
-// STYLE optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
-class StyleStmt : public OptionalStmt {
-public:
- uint32_t Value;
-
- StyleStmt(uint32_t Style) : Value(Style) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "STYLE"; }
- Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
-};
-
-// EXSTYLE optional statement.
-//
-// Ref: docs.microsoft.com/en-us/windows/desktop/menurc/exstyle-statement
-class ExStyleStmt : public OptionalStmt {
-public:
- uint32_t Value;
-
- ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "EXSTYLE"; }
- Error visit(Visitor *V) const override { return V->visitExStyleStmt(this); }
-};
-
-// CLASS optional statement.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380883(v=vs.85).aspx
-class ClassStmt : public OptionalStmt {
-public:
- IntOrString Value;
-
- ClassStmt(IntOrString Class) : Value(Class) {}
- raw_ostream &log(raw_ostream &) const override;
- Twine getResourceTypeName() const override { return "CLASS"; }
- Error visit(Visitor *V) const override { return V->visitClassStmt(this); }
-};
-
-} // namespace rc
-} // namespace llvm
-
-#endif
+};
+
+// 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
+// of a single resource).
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381019(v=vs.85).aspx
+class LanguageResource : public OptionalStmt {
+public:
+ uint32_t Lang, SubLang;
+
+ LanguageResource(uint32_t LangId, uint32_t SubLangId)
+ : Lang(LangId), SubLang(SubLangId) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ // This is not a regular top-level statement; when it occurs, it just
+ // modifies the language context.
+ Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
+ Twine getResourceTypeName() const override { return "LANGUAGE"; }
+};
+
+// 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 OptStatementsRCResource {
+public:
+ class Accelerator {
+ public:
+ IntOrString Event;
+ uint32_t Id;
+ uint16_t Flags;
+
+ enum Options {
+ // 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 &&List, uint16_t Flags)
+ : OptStatementsRCResource(std::move(List), Flags) {}
+
+ std::vector<Accelerator> Accelerators;
+
+ void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
+ Accelerators.push_back(Accelerator{Event, Id, Flags});
+ }
+ raw_ostream &log(raw_ostream &) const override;
+
+ IntOrString getResourceType() const override { return RkAccelerators; }
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
+ Twine getResourceTypeName() const override { return "ACCELERATORS"; }
+
+ Error visit(Visitor *V) const override {
+ return V->visitAcceleratorsResource(this);
+ }
+ ResourceKind getKind() const override { return RkAccelerators; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkAccelerators;
+ }
+};
+
+// BITMAP resource. Represents a bitmap (".bmp") file.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380680(v=vs.85).aspx
+class BitmapResource : public RCResource {
+public:
+ StringRef BitmapLoc;
+
+ BitmapResource(StringRef Location, uint16_t Flags)
+ : RCResource(Flags), BitmapLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ IntOrString getResourceType() const override { return RkBitmap; }
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
+
+ Twine getResourceTypeName() const override { return "BITMAP"; }
+ Error visit(Visitor *V) const override {
+ return V->visitBitmapResource(this);
+ }
+ ResourceKind getKind() const override { return RkBitmap; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkBitmap;
+ }
+};
+
+// CURSOR resource. Represents a single cursor (".cur") file.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx
+class CursorResource : public RCResource {
+public:
+ StringRef CursorLoc;
+
+ CursorResource(StringRef Location, uint16_t Flags)
+ : RCResource(Flags), CursorLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "CURSOR"; }
+ static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
+ Error visit(Visitor *V) const override {
+ return V->visitCursorResource(this);
+ }
+ ResourceKind getKind() const override { return RkCursor; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkCursor;
+ }
+};
+
+// ICON resource. Represents a single ".ico" file containing a group of icons.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381018(v=vs.85).aspx
+class IconResource : public RCResource {
+public:
+ StringRef IconLoc;
+
+ IconResource(StringRef Location, uint16_t Flags)
+ : RCResource(Flags), IconLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "ICON"; }
+ static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
+ Error visit(Visitor *V) const override { return V->visitIconResource(this); }
+ ResourceKind getKind() const override { return RkIcon; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkIcon;
+ }
+};
+
+// HTML resource. Represents a local webpage that is to be embedded into the
+// resulting resource file. It embeds a file only - no additional resources
+// (images etc.) are included with this resource.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa966018(v=vs.85).aspx
+class HTMLResource : public RCResource {
+public:
+ StringRef HTMLLoc;
+
+ HTMLResource(StringRef Location, uint16_t Flags)
+ : RCResource(Flags), HTMLLoc(Location) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
+
+ // Curiously, file resources don't have DISCARDABLE flag set.
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
+ IntOrString getResourceType() const override { return RkHTML; }
+ Twine getResourceTypeName() const override { return "HTML"; }
+ ResourceKind getKind() const override { return RkHTML; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkHTML;
+ }
+};
+
+// -- 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 = 0x0008,
+ GRAYED = 0x0001,
+ HELP = 0x4000,
+ INACTIVE = 0x0002,
+ MENUBARBREAK = 0x0020,
+ MENUBREAK = 0x0040
+ };
+
+ enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
+
+ static constexpr size_t NumFlags = 6;
+ static StringRef OptionsStr[NumFlags];
+ 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";
+ }
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
+ uint16_t Flags)
+ : OptStatementsRCResource(std::move(OptStmts), Flags),
+ 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.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
+class StringTableResource : public OptStatementsRCResource {
+public:
+ std::vector<std::pair<uint32_t, std::vector<StringRef>>> Table;
+
+ StringTableResource(OptionalStmtList &&List, uint16_t Flags)
+ : OptStatementsRCResource(std::move(List), Flags) {}
+ void addStrings(uint32_t ID, std::vector<StringRef> &&Strings) {
+ Table.emplace_back(ID, Strings);
+ }
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "STRINGTABLE"; }
+ Error visit(Visitor *V) const override {
+ return V->visitStringTableResource(this);
+ }
+};
+
+// -- 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 {
+public:
+ StringRef Type;
+ IntOrString Title;
+ uint32_t ID, X, Y, Width, Height;
+ Optional<IntWithNotMask> Style;
+ Optional<uint32_t> ExtStyle, HelpID;
+ IntOrString Class;
+
+ // Control classes as described in DLGITEMTEMPLATEEX documentation.
+ //
+ // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx
+ enum CtlClasses {
+ ClsButton = 0x80,
+ ClsEdit = 0x81,
+ ClsStatic = 0x82,
+ ClsListBox = 0x83,
+ ClsScrollBar = 0x84,
+ ClsComboBox = 0x85
+ };
+
+ // Simple information about a single control type.
+ struct CtlInfo {
+ uint32_t Style;
+ uint16_t CtlClass;
+ bool HasTitle;
+ };
+
+ Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
+ uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
+ Optional<IntWithNotMask> ItemStyle, Optional<uint32_t> ExtItemStyle,
+ Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
+ : Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
+ Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
+ ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
+
+ static const StringMap<CtlInfo> SupportedCtls;
+
+ 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 OptStatementsRCResource {
+public:
+ uint32_t X, Y, Width, Height, HelpID;
+ std::vector<Control> Controls;
+ bool IsExtended;
+
+ DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
+ uint32_t DlgHeight, uint32_t DlgHelpID,
+ OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
+ : OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
+ Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
+ IsExtended(IsDialogEx) {}
+
+ void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
+
+ raw_ostream &log(raw_ostream &) const override;
+
+ // It was a weird design decision to assign the same resource type number
+ // both for DIALOG and DIALOGEX (and the same structure version number).
+ // It makes it possible for DIALOG to be mistaken for DIALOGEX.
+ IntOrString getResourceType() const override { return RkDialog; }
+ Twine getResourceTypeName() const override {
+ return "DIALOG" + Twine(IsExtended ? "EX" : "");
+ }
+ Error visit(Visitor *V) const override {
+ return V->visitDialogResource(this);
+ }
+ ResourceKind getKind() const override { return RkDialog; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkDialog;
+ }
+};
+
+// User-defined resource. It is either:
+// * a link to the file, e.g. NAME TYPE "filename",
+// * or contains a list of integers and strings, e.g. NAME TYPE {1, "a", 2}.
+class UserDefinedResource : public RCResource {
+public:
+ IntOrString Type;
+ StringRef FileLoc;
+ std::vector<IntOrString> Contents;
+ bool IsFileResource;
+
+ UserDefinedResource(IntOrString ResourceType, StringRef FileLocation,
+ uint16_t Flags)
+ : RCResource(Flags), Type(ResourceType), FileLoc(FileLocation),
+ IsFileResource(true) {}
+ UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data,
+ uint16_t Flags)
+ : RCResource(Flags), Type(ResourceType), Contents(std::move(Data)),
+ IsFileResource(false) {}
+
+ raw_ostream &log(raw_ostream &) const override;
+ IntOrString getResourceType() const override { return Type; }
+ Twine getResourceTypeName() const override { return Type; }
+ static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
+
+ Error visit(Visitor *V) const override {
+ return V->visitUserDefinedResource(this);
+ }
+ ResourceKind getKind() const override { return RkUser; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkUser;
+ }
+};
+
+// -- VERSIONINFO resource and its helper classes --
+//
+// This resource lists the version information on the executable/library.
+// The declaration consists of the following items:
+// * A number of fixed optional version statements (e.g. FILEVERSION, FILEOS)
+// * BEGIN
+// * A number of BLOCK and/or VALUE statements. BLOCK recursively defines
+// another block of version information, whereas VALUE defines a
+// key -> value correspondence. There might be more than one value
+// corresponding to the single key.
+// * END
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
+
+// A single VERSIONINFO statement;
+class VersionInfoStmt {
+public:
+ enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
+
+ virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
+ virtual ~VersionInfoStmt() {}
+
+ virtual StmtKind getKind() const { return StBase; }
+ static bool classof(const VersionInfoStmt *S) {
+ return S->getKind() == StBase;
+ }
+};
+
+// BLOCK definition; also the main VERSIONINFO declaration is considered a
+// BLOCK, although it has no name.
+// The correct top-level blocks are "VarFileInfo" and "StringFileInfo". We don't
+// care about them at the parsing phase.
+class VersionInfoBlock : public VersionInfoStmt {
+public:
+ std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
+ StringRef Name;
+
+ VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
+ void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
+ Stmts.push_back(std::move(Stmt));
+ }
+ raw_ostream &log(raw_ostream &) const override;
+
+ StmtKind getKind() const override { return StBlock; }
+ static bool classof(const VersionInfoStmt *S) {
+ return S->getKind() == StBlock;
+ }
+};
+
+class VersionInfoValue : public VersionInfoStmt {
+public:
+ StringRef Key;
+ std::vector<IntOrString> Values;
+ std::vector<bool> HasPrecedingComma;
+
+ VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
+ std::vector<bool> &&CommasBeforeVals)
+ : Key(InfoKey), Values(std::move(Vals)),
+ HasPrecedingComma(std::move(CommasBeforeVals)) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ StmtKind getKind() const override { return StValue; }
+ static bool classof(const VersionInfoStmt *S) {
+ return S->getKind() == StValue;
+ }
+};
+
+class VersionInfoResource : public RCResource {
+public:
+ // A class listing fixed VERSIONINFO statements (occuring before main BEGIN).
+ // If any of these is not specified, it is assumed by the original tool to
+ // be equal to 0.
+ class VersionInfoFixed {
+ public:
+ enum VersionInfoFixedType {
+ FtUnknown,
+ FtFileVersion,
+ FtProductVersion,
+ FtFileFlagsMask,
+ FtFileFlags,
+ FtFileOS,
+ FtFileType,
+ FtFileSubtype,
+ FtNumTypes
+ };
+
+ private:
+ static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
+ static const StringRef FixedFieldsNames[FtNumTypes];
+
+ public:
+ SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
+ SmallVector<bool, FtNumTypes> IsTypePresent;
+
+ static VersionInfoFixedType getFixedType(StringRef Type);
+ static bool isTypeSupported(VersionInfoFixedType Type);
+ static bool isVersionType(VersionInfoFixedType Type);
+
+ VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
+
+ void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
+ FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end());
+ IsTypePresent[Type] = true;
+ }
+
+ raw_ostream &log(raw_ostream &) const;
+ };
+
+ VersionInfoBlock MainBlock;
+ VersionInfoFixed FixedData;
+
+ VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
+ VersionInfoFixed &&FixedInfo, uint16_t Flags)
+ : RCResource(Flags), MainBlock(std::move(TopLevelBlock)),
+ FixedData(std::move(FixedInfo)) {}
+
+ raw_ostream &log(raw_ostream &) const override;
+ IntOrString getResourceType() const override { return RkVersionInfo; }
+ static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
+ Twine getResourceTypeName() const override { return "VERSIONINFO"; }
+ Error visit(Visitor *V) const override {
+ return V->visitVersionInfoResource(this);
+ }
+ ResourceKind getKind() const override { return RkVersionInfo; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkVersionInfo;
+ }
+};
+
+// CHARACTERISTICS optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380872(v=vs.85).aspx
+class CharacteristicsStmt : public OptionalStmt {
+public:
+ uint32_t Value;
+
+ CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
+ Error visit(Visitor *V) const override {
+ return V->visitCharacteristicsStmt(this);
+ }
+};
+
+// VERSION optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381059(v=vs.85).aspx
+class VersionStmt : public OptionalStmt {
+public:
+ uint32_t Value;
+
+ VersionStmt(uint32_t Version) : Value(Version) {}
+ raw_ostream &log(raw_ostream &) const override;
+
+ Twine getResourceTypeName() const override { return "VERSION"; }
+ Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
+};
+
+// CAPTION optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380778(v=vs.85).aspx
+class CaptionStmt : public OptionalStmt {
+public:
+ StringRef Value;
+
+ CaptionStmt(StringRef Caption) : Value(Caption) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "CAPTION"; }
+ Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
+};
+
+// 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 {
+public:
+ uint32_t Size, Weight, Charset;
+ StringRef Name;
+ bool Italic;
+
+ FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
+ bool FontItalic, uint32_t FontCharset)
+ : Size(FontSize), Weight(FontWeight), Charset(FontCharset),
+ Name(FontName), Italic(FontItalic) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "FONT"; }
+ Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
+};
+
+// STYLE optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381051(v=vs.85).aspx
+class StyleStmt : public OptionalStmt {
+public:
+ uint32_t Value;
+
+ StyleStmt(uint32_t Style) : Value(Style) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "STYLE"; }
+ Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
+};
+
+// EXSTYLE optional statement.
+//
+// Ref: docs.microsoft.com/en-us/windows/desktop/menurc/exstyle-statement
+class ExStyleStmt : public OptionalStmt {
+public:
+ uint32_t Value;
+
+ ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "EXSTYLE"; }
+ Error visit(Visitor *V) const override { return V->visitExStyleStmt(this); }
+};
+
+// CLASS optional statement.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380883(v=vs.85).aspx
+class ClassStmt : public OptionalStmt {
+public:
+ IntOrString Value;
+
+ ClassStmt(IntOrString Class) : Value(Class) {}
+ raw_ostream &log(raw_ostream &) const override;
+ Twine getResourceTypeName() const override { return "CLASS"; }
+ Error visit(Visitor *V) const override { return V->visitClassStmt(this); }
+};
+
+} // namespace rc
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp
index b9699d2b2e..2e21f675b9 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.cpp
@@ -1,367 +1,367 @@
-//===-- ResourceScriptToken.cpp ---------------------------------*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This file implements an interface defined in ResourceScriptToken.h.
-// In particular, it defines an .rc script tokenizer.
-//
-//===---------------------------------------------------------------------===//
-
-#include "ResourceScriptToken.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <algorithm>
-#include <cassert>
-#include <cctype>
-#include <cstdlib>
-#include <utility>
-
-using namespace llvm;
-
-using Kind = RCToken::Kind;
-
-// Checks if Representation is a correct description of an RC integer.
-// It should be a 32-bit unsigned integer, either decimal, octal (0[0-7]+),
-// or hexadecimal (0x[0-9a-f]+). It might be followed by a single 'L'
-// character (that is the difference between our representation and
-// StringRef's one). If Representation is correct, 'true' is returned and
-// the return value is put back in Num.
-static bool rcGetAsInteger(StringRef Representation, uint32_t &Num) {
- size_t Length = Representation.size();
- if (Length == 0)
- return false;
- // Strip the last 'L' if unnecessary.
- if (std::toupper(Representation.back()) == 'L')
- Representation = Representation.drop_back(1);
-
- return !Representation.getAsInteger<uint32_t>(0, Num);
-}
-
-RCToken::RCToken(RCToken::Kind RCTokenKind, StringRef Value)
- : TokenKind(RCTokenKind), TokenValue(Value) {}
-
-uint32_t RCToken::intValue() const {
- assert(TokenKind == Kind::Int);
- // We assume that the token already is a correct integer (checked by
- // rcGetAsInteger).
- uint32_t Result;
- bool IsSuccess = rcGetAsInteger(TokenValue, Result);
- assert(IsSuccess);
- (void)IsSuccess; // Silence the compiler warning when -DNDEBUG flag is on.
- return Result;
-}
-
-bool RCToken::isLongInt() const {
- return TokenKind == Kind::Int && std::toupper(TokenValue.back()) == 'L';
-}
-
-StringRef RCToken::value() const { return TokenValue; }
-
-Kind RCToken::kind() const { return TokenKind; }
-
-bool RCToken::isBinaryOp() const {
- switch (TokenKind) {
- case Kind::Plus:
- case Kind::Minus:
- case Kind::Pipe:
- case Kind::Amp:
- return true;
- default:
- return false;
- }
-}
-
-static Error getStringError(const Twine &message) {
- return make_error<StringError>("Error parsing file: " + message,
- inconvertibleErrorCode());
-}
-
-namespace {
-
-class Tokenizer {
-public:
- Tokenizer(StringRef Input) : Data(Input), DataLength(Input.size()), Pos(0) {}
-
- Expected<std::vector<RCToken>> run();
-
-private:
- // All 'advancing' methods return boolean values; if they're equal to false,
- // the stream has ended or failed.
- bool advance(size_t Amount = 1);
- bool skipWhitespaces();
-
- // Consumes a token. If any problem occurred, a non-empty Error is returned.
- Error consumeToken(const Kind TokenKind);
-
- // Check if tokenizer is about to read FollowingChars.
- bool willNowRead(StringRef FollowingChars) const;
-
- // Check if tokenizer can start reading an identifier at current position.
- // The original tool did non specify the rules to determine what is a correct
- // identifier. We assume they should follow the C convention:
- // [a-zA-Z_][a-zA-Z0-9_]*.
- bool canStartIdentifier() const;
- // Check if tokenizer can continue reading an identifier.
- bool canContinueIdentifier() const;
-
- // Check if tokenizer can start reading an integer.
- // A correct integer always starts with a 0-9 digit,
- // can contain characters 0-9A-Fa-f (digits),
- // Ll (marking the integer is 32-bit), Xx (marking the representation
- // is hexadecimal). As some kind of separator should come after the
- // integer, we can consume the integer until a non-alphanumeric
- // character.
- bool canStartInt() const;
- bool canContinueInt() const;
-
- bool canStartString() const;
-
- // Check if tokenizer can start reading a single line comment (e.g. a comment
- // that begins with '//')
- bool canStartLineComment() const;
-
- // Check if tokenizer can start or finish reading a block comment (e.g. a
- // comment that begins with '/*' and ends with '*/')
- bool canStartBlockComment() const;
-
- // Throw away all remaining characters on the current line.
- void skipCurrentLine();
-
- bool streamEof() const;
-
- // Classify the token that is about to be read from the current position.
- Kind classifyCurrentToken() const;
-
- // Process the Kind::Identifier token - check if it is
- // an identifier describing a block start or end.
- void processIdentifier(RCToken &token) const;
-
- StringRef Data;
- size_t DataLength, Pos;
-};
-
-void Tokenizer::skipCurrentLine() {
- Pos = Data.find_first_of("\r\n", Pos);
- Pos = Data.find_first_not_of("\r\n", Pos);
-
- if (Pos == StringRef::npos)
- Pos = DataLength;
-}
-
-Expected<std::vector<RCToken>> Tokenizer::run() {
- Pos = 0;
- std::vector<RCToken> Result;
-
- // Consume an optional UTF-8 Byte Order Mark.
- if (willNowRead("\xef\xbb\xbf"))
- advance(3);
-
- while (!streamEof()) {
- if (!skipWhitespaces())
- break;
-
- Kind TokenKind = classifyCurrentToken();
- if (TokenKind == Kind::Invalid)
- return getStringError("Invalid token found at position " + Twine(Pos));
-
- const size_t TokenStart = Pos;
- if (Error TokenError = consumeToken(TokenKind))
- return std::move(TokenError);
-
- // Comments are just deleted, don't bother saving them.
- if (TokenKind == Kind::LineComment || TokenKind == Kind::StartComment)
- continue;
-
- RCToken Token(TokenKind, Data.take_front(Pos).drop_front(TokenStart));
- if (TokenKind == Kind::Identifier) {
- processIdentifier(Token);
- } else if (TokenKind == Kind::Int) {
- uint32_t TokenInt;
- if (!rcGetAsInteger(Token.value(), TokenInt)) {
- // The integer has incorrect format or cannot be represented in
- // a 32-bit integer.
- return getStringError("Integer invalid or too large: " +
- Token.value().str());
- }
- }
-
- Result.push_back(Token);
- }
-
- return Result;
-}
-
-bool Tokenizer::advance(size_t Amount) {
- Pos += Amount;
- return !streamEof();
-}
-
-bool Tokenizer::skipWhitespaces() {
- while (!streamEof() && isSpace(Data[Pos]))
- advance();
- return !streamEof();
-}
-
-Error Tokenizer::consumeToken(const Kind TokenKind) {
- switch (TokenKind) {
- // One-character token consumption.
-#define TOKEN(Name)
-#define SHORT_TOKEN(Name, Ch) case Kind::Name:
-#include "ResourceScriptTokenList.def"
- advance();
- return Error::success();
-
- case Kind::LineComment:
- advance(2);
- skipCurrentLine();
- return Error::success();
-
- case Kind::StartComment: {
- advance(2);
- auto EndPos = Data.find("*/", Pos);
- if (EndPos == StringRef::npos)
- return getStringError(
- "Unclosed multi-line comment beginning at position " + Twine(Pos));
- advance(EndPos - Pos);
- advance(2);
- return Error::success();
- }
- case Kind::Identifier:
- while (!streamEof() && canContinueIdentifier())
- advance();
- return Error::success();
-
- case Kind::Int:
- while (!streamEof() && canContinueInt())
- advance();
- return Error::success();
-
- case Kind::String:
- // Consume the preceding 'L', if there is any.
- if (std::toupper(Data[Pos]) == 'L')
- advance();
- // Consume the double-quote.
- advance();
-
- // Consume the characters until the end of the file, line or string.
- while (true) {
- if (streamEof()) {
- return getStringError("Unterminated string literal.");
- } else if (Data[Pos] == '"') {
- // Consume the ending double-quote.
- advance();
- // However, if another '"' follows this double-quote, the string didn't
- // end and we just included '"' into the string.
- if (!willNowRead("\""))
- return Error::success();
- } else if (Data[Pos] == '\n') {
- return getStringError("String literal not terminated in the line.");
- }
-
- advance();
- }
-
- case Kind::Invalid:
- assert(false && "Cannot consume an invalid token.");
- }
-
- llvm_unreachable("Unknown RCToken::Kind");
-}
-
-bool Tokenizer::willNowRead(StringRef FollowingChars) const {
- return Data.drop_front(Pos).startswith(FollowingChars);
-}
-
-bool Tokenizer::canStartIdentifier() const {
- assert(!streamEof());
-
- const char CurChar = Data[Pos];
- return std::isalpha(CurChar) || CurChar == '_' || CurChar == '.';
-}
-
-bool Tokenizer::canContinueIdentifier() const {
- assert(!streamEof());
- const char CurChar = Data[Pos];
- return std::isalnum(CurChar) || CurChar == '_' || CurChar == '.' ||
- CurChar == '/' || CurChar == '\\';
-}
-
-bool Tokenizer::canStartInt() const {
- assert(!streamEof());
- return std::isdigit(Data[Pos]);
-}
-
-bool Tokenizer::canStartBlockComment() const {
- assert(!streamEof());
- return Data.drop_front(Pos).startswith("/*");
-}
-
-bool Tokenizer::canStartLineComment() const {
- assert(!streamEof());
- return Data.drop_front(Pos).startswith("//");
-}
-
-bool Tokenizer::canContinueInt() const {
- assert(!streamEof());
- return std::isalnum(Data[Pos]);
-}
-
-bool Tokenizer::canStartString() const {
- return willNowRead("\"") || willNowRead("L\"") || willNowRead("l\"");
-}
-
-bool Tokenizer::streamEof() const { return Pos == DataLength; }
-
-Kind Tokenizer::classifyCurrentToken() const {
- if (canStartBlockComment())
- return Kind::StartComment;
- if (canStartLineComment())
- return Kind::LineComment;
-
- if (canStartInt())
- return Kind::Int;
- if (canStartString())
- return Kind::String;
- // BEGIN and END are at this point of lexing recognized as identifiers.
- if (canStartIdentifier())
- return Kind::Identifier;
-
- const char CurChar = Data[Pos];
-
- switch (CurChar) {
- // One-character token classification.
-#define TOKEN(Name)
-#define SHORT_TOKEN(Name, Ch) \
- case Ch: \
- return Kind::Name;
-#include "ResourceScriptTokenList.def"
-
- default:
- return Kind::Invalid;
- }
-}
-
-void Tokenizer::processIdentifier(RCToken &Token) const {
- assert(Token.kind() == Kind::Identifier);
- StringRef Name = Token.value();
-
- if (Name.equals_lower("begin"))
- Token = RCToken(Kind::BlockBegin, Name);
- else if (Name.equals_lower("end"))
- Token = RCToken(Kind::BlockEnd, Name);
-}
-
-} // anonymous namespace
-
-namespace llvm {
-
-Expected<std::vector<RCToken>> tokenizeRC(StringRef Input) {
- return Tokenizer(Input).run();
-}
-
-} // namespace llvm
+//===-- ResourceScriptToken.cpp ---------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file implements an interface defined in ResourceScriptToken.h.
+// In particular, it defines an .rc script tokenizer.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ResourceScriptToken.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cstdlib>
+#include <utility>
+
+using namespace llvm;
+
+using Kind = RCToken::Kind;
+
+// Checks if Representation is a correct description of an RC integer.
+// It should be a 32-bit unsigned integer, either decimal, octal (0[0-7]+),
+// or hexadecimal (0x[0-9a-f]+). It might be followed by a single 'L'
+// character (that is the difference between our representation and
+// StringRef's one). If Representation is correct, 'true' is returned and
+// the return value is put back in Num.
+static bool rcGetAsInteger(StringRef Representation, uint32_t &Num) {
+ size_t Length = Representation.size();
+ if (Length == 0)
+ return false;
+ // Strip the last 'L' if unnecessary.
+ if (std::toupper(Representation.back()) == 'L')
+ Representation = Representation.drop_back(1);
+
+ return !Representation.getAsInteger<uint32_t>(0, Num);
+}
+
+RCToken::RCToken(RCToken::Kind RCTokenKind, StringRef Value)
+ : TokenKind(RCTokenKind), TokenValue(Value) {}
+
+uint32_t RCToken::intValue() const {
+ assert(TokenKind == Kind::Int);
+ // We assume that the token already is a correct integer (checked by
+ // rcGetAsInteger).
+ uint32_t Result;
+ bool IsSuccess = rcGetAsInteger(TokenValue, Result);
+ assert(IsSuccess);
+ (void)IsSuccess; // Silence the compiler warning when -DNDEBUG flag is on.
+ return Result;
+}
+
+bool RCToken::isLongInt() const {
+ return TokenKind == Kind::Int && std::toupper(TokenValue.back()) == 'L';
+}
+
+StringRef RCToken::value() const { return TokenValue; }
+
+Kind RCToken::kind() const { return TokenKind; }
+
+bool RCToken::isBinaryOp() const {
+ switch (TokenKind) {
+ case Kind::Plus:
+ case Kind::Minus:
+ case Kind::Pipe:
+ case Kind::Amp:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static Error getStringError(const Twine &message) {
+ return make_error<StringError>("Error parsing file: " + message,
+ inconvertibleErrorCode());
+}
+
+namespace {
+
+class Tokenizer {
+public:
+ Tokenizer(StringRef Input) : Data(Input), DataLength(Input.size()), Pos(0) {}
+
+ Expected<std::vector<RCToken>> run();
+
+private:
+ // All 'advancing' methods return boolean values; if they're equal to false,
+ // the stream has ended or failed.
+ bool advance(size_t Amount = 1);
+ bool skipWhitespaces();
+
+ // Consumes a token. If any problem occurred, a non-empty Error is returned.
+ Error consumeToken(const Kind TokenKind);
+
+ // Check if tokenizer is about to read FollowingChars.
+ bool willNowRead(StringRef FollowingChars) const;
+
+ // Check if tokenizer can start reading an identifier at current position.
+ // The original tool did non specify the rules to determine what is a correct
+ // identifier. We assume they should follow the C convention:
+ // [a-zA-Z_][a-zA-Z0-9_]*.
+ bool canStartIdentifier() const;
+ // Check if tokenizer can continue reading an identifier.
+ bool canContinueIdentifier() const;
+
+ // Check if tokenizer can start reading an integer.
+ // A correct integer always starts with a 0-9 digit,
+ // can contain characters 0-9A-Fa-f (digits),
+ // Ll (marking the integer is 32-bit), Xx (marking the representation
+ // is hexadecimal). As some kind of separator should come after the
+ // integer, we can consume the integer until a non-alphanumeric
+ // character.
+ bool canStartInt() const;
+ bool canContinueInt() const;
+
+ bool canStartString() const;
+
+ // Check if tokenizer can start reading a single line comment (e.g. a comment
+ // that begins with '//')
+ bool canStartLineComment() const;
+
+ // Check if tokenizer can start or finish reading a block comment (e.g. a
+ // comment that begins with '/*' and ends with '*/')
+ bool canStartBlockComment() const;
+
+ // Throw away all remaining characters on the current line.
+ void skipCurrentLine();
+
+ bool streamEof() const;
+
+ // Classify the token that is about to be read from the current position.
+ Kind classifyCurrentToken() const;
+
+ // Process the Kind::Identifier token - check if it is
+ // an identifier describing a block start or end.
+ void processIdentifier(RCToken &token) const;
+
+ StringRef Data;
+ size_t DataLength, Pos;
+};
+
+void Tokenizer::skipCurrentLine() {
+ Pos = Data.find_first_of("\r\n", Pos);
+ Pos = Data.find_first_not_of("\r\n", Pos);
+
+ if (Pos == StringRef::npos)
+ Pos = DataLength;
+}
+
+Expected<std::vector<RCToken>> Tokenizer::run() {
+ Pos = 0;
+ std::vector<RCToken> Result;
+
+ // Consume an optional UTF-8 Byte Order Mark.
+ if (willNowRead("\xef\xbb\xbf"))
+ advance(3);
+
+ while (!streamEof()) {
+ if (!skipWhitespaces())
+ break;
+
+ Kind TokenKind = classifyCurrentToken();
+ if (TokenKind == Kind::Invalid)
+ return getStringError("Invalid token found at position " + Twine(Pos));
+
+ const size_t TokenStart = Pos;
+ if (Error TokenError = consumeToken(TokenKind))
+ return std::move(TokenError);
+
+ // Comments are just deleted, don't bother saving them.
+ if (TokenKind == Kind::LineComment || TokenKind == Kind::StartComment)
+ continue;
+
+ RCToken Token(TokenKind, Data.take_front(Pos).drop_front(TokenStart));
+ if (TokenKind == Kind::Identifier) {
+ processIdentifier(Token);
+ } else if (TokenKind == Kind::Int) {
+ uint32_t TokenInt;
+ if (!rcGetAsInteger(Token.value(), TokenInt)) {
+ // The integer has incorrect format or cannot be represented in
+ // a 32-bit integer.
+ return getStringError("Integer invalid or too large: " +
+ Token.value().str());
+ }
+ }
+
+ Result.push_back(Token);
+ }
+
+ return Result;
+}
+
+bool Tokenizer::advance(size_t Amount) {
+ Pos += Amount;
+ return !streamEof();
+}
+
+bool Tokenizer::skipWhitespaces() {
+ while (!streamEof() && isSpace(Data[Pos]))
+ advance();
+ return !streamEof();
+}
+
+Error Tokenizer::consumeToken(const Kind TokenKind) {
+ switch (TokenKind) {
+ // One-character token consumption.
+#define TOKEN(Name)
+#define SHORT_TOKEN(Name, Ch) case Kind::Name:
+#include "ResourceScriptTokenList.def"
+ advance();
+ return Error::success();
+
+ case Kind::LineComment:
+ advance(2);
+ skipCurrentLine();
+ return Error::success();
+
+ case Kind::StartComment: {
+ advance(2);
+ auto EndPos = Data.find("*/", Pos);
+ if (EndPos == StringRef::npos)
+ return getStringError(
+ "Unclosed multi-line comment beginning at position " + Twine(Pos));
+ advance(EndPos - Pos);
+ advance(2);
+ return Error::success();
+ }
+ case Kind::Identifier:
+ while (!streamEof() && canContinueIdentifier())
+ advance();
+ return Error::success();
+
+ case Kind::Int:
+ while (!streamEof() && canContinueInt())
+ advance();
+ return Error::success();
+
+ case Kind::String:
+ // Consume the preceding 'L', if there is any.
+ if (std::toupper(Data[Pos]) == 'L')
+ advance();
+ // Consume the double-quote.
+ advance();
+
+ // Consume the characters until the end of the file, line or string.
+ while (true) {
+ if (streamEof()) {
+ return getStringError("Unterminated string literal.");
+ } else if (Data[Pos] == '"') {
+ // Consume the ending double-quote.
+ advance();
+ // However, if another '"' follows this double-quote, the string didn't
+ // end and we just included '"' into the string.
+ if (!willNowRead("\""))
+ return Error::success();
+ } else if (Data[Pos] == '\n') {
+ return getStringError("String literal not terminated in the line.");
+ }
+
+ advance();
+ }
+
+ case Kind::Invalid:
+ assert(false && "Cannot consume an invalid token.");
+ }
+
+ llvm_unreachable("Unknown RCToken::Kind");
+}
+
+bool Tokenizer::willNowRead(StringRef FollowingChars) const {
+ return Data.drop_front(Pos).startswith(FollowingChars);
+}
+
+bool Tokenizer::canStartIdentifier() const {
+ assert(!streamEof());
+
+ const char CurChar = Data[Pos];
+ return std::isalpha(CurChar) || CurChar == '_' || CurChar == '.';
+}
+
+bool Tokenizer::canContinueIdentifier() const {
+ assert(!streamEof());
+ const char CurChar = Data[Pos];
+ return std::isalnum(CurChar) || CurChar == '_' || CurChar == '.' ||
+ CurChar == '/' || CurChar == '\\';
+}
+
+bool Tokenizer::canStartInt() const {
+ assert(!streamEof());
+ return std::isdigit(Data[Pos]);
+}
+
+bool Tokenizer::canStartBlockComment() const {
+ assert(!streamEof());
+ return Data.drop_front(Pos).startswith("/*");
+}
+
+bool Tokenizer::canStartLineComment() const {
+ assert(!streamEof());
+ return Data.drop_front(Pos).startswith("//");
+}
+
+bool Tokenizer::canContinueInt() const {
+ assert(!streamEof());
+ return std::isalnum(Data[Pos]);
+}
+
+bool Tokenizer::canStartString() const {
+ return willNowRead("\"") || willNowRead("L\"") || willNowRead("l\"");
+}
+
+bool Tokenizer::streamEof() const { return Pos == DataLength; }
+
+Kind Tokenizer::classifyCurrentToken() const {
+ if (canStartBlockComment())
+ return Kind::StartComment;
+ if (canStartLineComment())
+ return Kind::LineComment;
+
+ if (canStartInt())
+ return Kind::Int;
+ if (canStartString())
+ return Kind::String;
+ // BEGIN and END are at this point of lexing recognized as identifiers.
+ if (canStartIdentifier())
+ return Kind::Identifier;
+
+ const char CurChar = Data[Pos];
+
+ switch (CurChar) {
+ // One-character token classification.
+#define TOKEN(Name)
+#define SHORT_TOKEN(Name, Ch) \
+ case Ch: \
+ return Kind::Name;
+#include "ResourceScriptTokenList.def"
+
+ default:
+ return Kind::Invalid;
+ }
+}
+
+void Tokenizer::processIdentifier(RCToken &Token) const {
+ assert(Token.kind() == Kind::Identifier);
+ StringRef Name = Token.value();
+
+ if (Name.equals_lower("begin"))
+ Token = RCToken(Kind::BlockBegin, Name);
+ else if (Name.equals_lower("end"))
+ Token = RCToken(Kind::BlockEnd, Name);
+}
+
+} // anonymous namespace
+
+namespace llvm {
+
+Expected<std::vector<RCToken>> tokenizeRC(StringRef Input) {
+ return Tokenizer(Input).run();
+}
+
+} // namespace llvm
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h
index d821f10138..cc8ca48b49 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptToken.h
@@ -1,81 +1,81 @@
-//===-- ResourceScriptToken.h -----------------------------------*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This declares the .rc script tokens and defines an interface for tokenizing
-// the input data. The list of available tokens is located at
-// ResourceScriptTokenList.def.
-//
-// Note that the tokenizer does not support preprocessor directives. The
-// preprocessor should do its work on the .rc file before running llvm-rc.
-//
-// As for now, it is possible to parse ASCII files only (the behavior on
-// UTF files might be undefined). However, it already consumes UTF-8 BOM, if
-// there is any. Thus, ASCII-compatible UTF-8 files are tokenized correctly.
-//
-// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380599(v=vs.85).aspx
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTTOKEN_H
-#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTTOKEN_H
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-
-#include <cstdint>
-#include <map>
-#include <string>
-#include <vector>
-
-namespace llvm {
-
-// A definition of a single resource script token. Each token has its kind
-// (declared in ResourceScriptTokenList) and holds a value - a reference
-// representation of the token.
-// RCToken does not claim ownership on its value. A memory buffer containing
-// the token value should be stored in a safe place and cannot be freed
-// nor reallocated.
-class RCToken {
-public:
- enum class Kind {
-#define TOKEN(Name) Name,
-#define SHORT_TOKEN(Name, Ch) Name,
-#include "ResourceScriptTokenList.def"
- };
-
- RCToken(RCToken::Kind RCTokenKind, StringRef Value);
-
- // Get an integer value of the integer token.
- uint32_t intValue() const;
- bool isLongInt() const;
-
- StringRef value() const;
- Kind kind() const;
-
- // Check if a token describes a binary operator.
- bool isBinaryOp() const;
-
-private:
- Kind TokenKind;
- StringRef TokenValue;
-};
-
-// Tokenize Input.
-// In case no error occurred, the return value contains
-// tokens in order they were in the input file.
-// In case of any error, the return value contains
-// a textual representation of error.
-//
-// Tokens returned by this function hold only references to the parts
-// of the Input. Memory buffer containing Input cannot be freed,
-// modified or reallocated.
-Expected<std::vector<RCToken>> tokenizeRC(StringRef Input);
-
-} // namespace llvm
-
-#endif
+//===-- ResourceScriptToken.h -----------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This declares the .rc script tokens and defines an interface for tokenizing
+// the input data. The list of available tokens is located at
+// ResourceScriptTokenList.def.
+//
+// Note that the tokenizer does not support preprocessor directives. The
+// preprocessor should do its work on the .rc file before running llvm-rc.
+//
+// As for now, it is possible to parse ASCII files only (the behavior on
+// UTF files might be undefined). However, it already consumes UTF-8 BOM, if
+// there is any. Thus, ASCII-compatible UTF-8 files are tokenized correctly.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380599(v=vs.85).aspx
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTTOKEN_H
+#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTTOKEN_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+// A definition of a single resource script token. Each token has its kind
+// (declared in ResourceScriptTokenList) and holds a value - a reference
+// representation of the token.
+// RCToken does not claim ownership on its value. A memory buffer containing
+// the token value should be stored in a safe place and cannot be freed
+// nor reallocated.
+class RCToken {
+public:
+ enum class Kind {
+#define TOKEN(Name) Name,
+#define SHORT_TOKEN(Name, Ch) Name,
+#include "ResourceScriptTokenList.def"
+ };
+
+ RCToken(RCToken::Kind RCTokenKind, StringRef Value);
+
+ // Get an integer value of the integer token.
+ uint32_t intValue() const;
+ bool isLongInt() const;
+
+ StringRef value() const;
+ Kind kind() const;
+
+ // Check if a token describes a binary operator.
+ bool isBinaryOp() const;
+
+private:
+ Kind TokenKind;
+ StringRef TokenValue;
+};
+
+// Tokenize Input.
+// In case no error occurred, the return value contains
+// tokens in order they were in the input file.
+// In case of any error, the return value contains
+// a textual representation of error.
+//
+// Tokens returned by this function hold only references to the parts
+// of the Input. Memory buffer containing Input cannot be freed,
+// modified or reallocated.
+Expected<std::vector<RCToken>> tokenizeRC(StringRef Input);
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def
index e0ea32f940..a61a96461f 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceScriptTokenList.def
@@ -1,39 +1,39 @@
-//===-- ResourceScriptTokenList.h -------------------------------*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This is a part of llvm-rc tokenizer. It lists all the possible tokens
-// that might occur in a correct .rc script.
-//
-//===---------------------------------------------------------------------===//
-
-
-// Long tokens. They might consist of more than one character.
-TOKEN(Invalid) // Invalid token. Should not occur in a valid script.
-TOKEN(Int) // Integer (decimal, octal or hexadecimal).
-TOKEN(String) // String value.
-TOKEN(Identifier) // Script identifier (resource name or type).
-TOKEN(LineComment) // Beginning of single-line comment.
-TOKEN(StartComment) // Beginning of multi-line comment.
-
-// Short tokens. They usually consist of exactly one character.
-// The definitions are of the form SHORT_TOKEN(TokenName, TokenChar).
-// TokenChar is the one-character token representation occuring in the correct
-// .rc scripts.
-SHORT_TOKEN(BlockBegin, '{') // Start of the script block; can also be BEGIN.
-SHORT_TOKEN(BlockEnd, '}') // End of the block; can also be END.
-SHORT_TOKEN(Comma, ',') // Comma - resource arguments separator.
-SHORT_TOKEN(Plus, '+') // Addition operator.
-SHORT_TOKEN(Minus, '-') // Subtraction operator.
-SHORT_TOKEN(Pipe, '|') // Bitwise-OR operator.
-SHORT_TOKEN(Amp, '&') // Bitwise-AND operator.
-SHORT_TOKEN(Tilde, '~') // Bitwise-NOT operator.
-SHORT_TOKEN(LeftParen, '(') // Left parenthesis in the script expressions.
-SHORT_TOKEN(RightParen, ')') // Right parenthesis.
-
-#undef TOKEN
-#undef SHORT_TOKEN
+//===-- ResourceScriptTokenList.h -------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This is a part of llvm-rc tokenizer. It lists all the possible tokens
+// that might occur in a correct .rc script.
+//
+//===---------------------------------------------------------------------===//
+
+
+// Long tokens. They might consist of more than one character.
+TOKEN(Invalid) // Invalid token. Should not occur in a valid script.
+TOKEN(Int) // Integer (decimal, octal or hexadecimal).
+TOKEN(String) // String value.
+TOKEN(Identifier) // Script identifier (resource name or type).
+TOKEN(LineComment) // Beginning of single-line comment.
+TOKEN(StartComment) // Beginning of multi-line comment.
+
+// Short tokens. They usually consist of exactly one character.
+// The definitions are of the form SHORT_TOKEN(TokenName, TokenChar).
+// TokenChar is the one-character token representation occuring in the correct
+// .rc scripts.
+SHORT_TOKEN(BlockBegin, '{') // Start of the script block; can also be BEGIN.
+SHORT_TOKEN(BlockEnd, '}') // End of the block; can also be END.
+SHORT_TOKEN(Comma, ',') // Comma - resource arguments separator.
+SHORT_TOKEN(Plus, '+') // Addition operator.
+SHORT_TOKEN(Minus, '-') // Subtraction operator.
+SHORT_TOKEN(Pipe, '|') // Bitwise-OR operator.
+SHORT_TOKEN(Amp, '&') // Bitwise-AND operator.
+SHORT_TOKEN(Tilde, '~') // Bitwise-NOT operator.
+SHORT_TOKEN(LeftParen, '(') // Left parenthesis in the script expressions.
+SHORT_TOKEN(RightParen, ')') // Right parenthesis.
+
+#undef TOKEN
+#undef SHORT_TOKEN
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h b/contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h
index f45154ddd4..843c8d898a 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h
+++ b/contrib/libs/llvm12/tools/llvm-rc/ResourceVisitor.h
@@ -1,61 +1,61 @@
-//===-- ResourceVisitor.h ---------------------------------------*- C++-*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===---------------------------------------------------------------------===//
-//
-// This defines a base class visiting resource script resources.
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMRC_RESOURCEVISITOR_H
-#define LLVM_TOOLS_LLVMRC_RESOURCEVISITOR_H
-
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-namespace rc {
-
-class RCResource;
-
-class CaptionStmt;
-class ClassStmt;
-class CharacteristicsStmt;
-class ExStyleStmt;
-class FontStmt;
-class LanguageResource;
-class StyleStmt;
-class VersionStmt;
-
-class Visitor {
-public:
- virtual Error visitNullResource(const RCResource *) = 0;
- virtual Error visitAcceleratorsResource(const RCResource *) = 0;
- virtual Error visitBitmapResource(const RCResource *) = 0;
- virtual Error visitCursorResource(const RCResource *) = 0;
- virtual Error visitDialogResource(const RCResource *) = 0;
- virtual Error visitHTMLResource(const RCResource *) = 0;
- virtual Error visitIconResource(const RCResource *) = 0;
- virtual Error visitMenuResource(const RCResource *) = 0;
- virtual Error visitStringTableResource(const RCResource *) = 0;
- virtual Error visitUserDefinedResource(const RCResource *) = 0;
- virtual Error visitVersionInfoResource(const RCResource *) = 0;
-
- virtual Error visitCaptionStmt(const CaptionStmt *) = 0;
- virtual Error visitClassStmt(const ClassStmt *) = 0;
- virtual Error visitCharacteristicsStmt(const CharacteristicsStmt *) = 0;
- virtual Error visitExStyleStmt(const ExStyleStmt *) = 0;
- virtual Error visitFontStmt(const FontStmt *) = 0;
- virtual Error visitLanguageStmt(const LanguageResource *) = 0;
- virtual Error visitStyleStmt(const StyleStmt *) = 0;
- virtual Error visitVersionStmt(const VersionStmt *) = 0;
-
- virtual ~Visitor() {}
-};
-
-} // namespace rc
-} // namespace llvm
-
-#endif
+//===-- ResourceVisitor.h ---------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This defines a base class visiting resource script resources.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMRC_RESOURCEVISITOR_H
+#define LLVM_TOOLS_LLVMRC_RESOURCEVISITOR_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace rc {
+
+class RCResource;
+
+class CaptionStmt;
+class ClassStmt;
+class CharacteristicsStmt;
+class ExStyleStmt;
+class FontStmt;
+class LanguageResource;
+class StyleStmt;
+class VersionStmt;
+
+class Visitor {
+public:
+ virtual Error visitNullResource(const RCResource *) = 0;
+ virtual Error visitAcceleratorsResource(const RCResource *) = 0;
+ virtual Error visitBitmapResource(const RCResource *) = 0;
+ virtual Error visitCursorResource(const RCResource *) = 0;
+ virtual Error visitDialogResource(const RCResource *) = 0;
+ virtual Error visitHTMLResource(const RCResource *) = 0;
+ virtual Error visitIconResource(const RCResource *) = 0;
+ virtual Error visitMenuResource(const RCResource *) = 0;
+ virtual Error visitStringTableResource(const RCResource *) = 0;
+ virtual Error visitUserDefinedResource(const RCResource *) = 0;
+ virtual Error visitVersionInfoResource(const RCResource *) = 0;
+
+ virtual Error visitCaptionStmt(const CaptionStmt *) = 0;
+ virtual Error visitClassStmt(const ClassStmt *) = 0;
+ virtual Error visitCharacteristicsStmt(const CharacteristicsStmt *) = 0;
+ virtual Error visitExStyleStmt(const ExStyleStmt *) = 0;
+ virtual Error visitFontStmt(const FontStmt *) = 0;
+ virtual Error visitLanguageStmt(const LanguageResource *) = 0;
+ virtual Error visitStyleStmt(const StyleStmt *) = 0;
+ virtual Error visitVersionStmt(const VersionStmt *) = 0;
+
+ virtual ~Visitor() {}
+};
+
+} // namespace rc
+} // namespace llvm
+
+#endif
diff --git a/contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp b/contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp
index ced68a3727..e9027a21d4 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp
+++ b/contrib/libs/llvm12/tools/llvm-rc/llvm-rc.cpp
@@ -1,216 +1,216 @@
-//===-- llvm-rc.cpp - Compile .rc scripts into .res -------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Compile .rc scripts into .res files. This is intended to be a
-// platform-independent port of Microsoft's rc.exe tool.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ResourceFileWriter.h"
-#include "ResourceScriptCppFilter.h"
-#include "ResourceScriptParser.h"
-#include "ResourceScriptStmt.h"
-#include "ResourceScriptToken.h"
-
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <algorithm>
-#include <system_error>
-
-using namespace llvm;
-using namespace llvm::rc;
-
-namespace {
-
-// Input options tables.
-
-enum ID {
- OPT_INVALID = 0, // This is not a correct option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
-#include "Opts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#include "Opts.inc"
-#undef PREFIX
-
-static const opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
-#include "Opts.inc"
-#undef OPTION
-};
-
-class RcOptTable : public opt::OptTable {
-public:
- RcOptTable() : OptTable(InfoTable, /* IgnoreCase = */ true) {}
-};
-
-static ExitOnError ExitOnErr;
-
-LLVM_ATTRIBUTE_NORETURN static void fatalError(const Twine &Message) {
- errs() << Message << "\n";
- exit(1);
-}
-
-} // anonymous namespace
-
-int main(int Argc, const char **Argv) {
- InitLLVM X(Argc, Argv);
- ExitOnErr.setBanner("llvm-rc: ");
-
- RcOptTable T;
- unsigned MAI, MAC;
- const char **DashDash = std::find_if(
- Argv + 1, Argv + Argc, [](StringRef Str) { return Str == "--"; });
- ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, DashDash);
-
- opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
-
- // The tool prints nothing when invoked with no command-line arguments.
+//===-- llvm-rc.cpp - Compile .rc scripts into .res -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Compile .rc scripts into .res files. This is intended to be a
+// platform-independent port of Microsoft's rc.exe tool.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ResourceFileWriter.h"
+#include "ResourceScriptCppFilter.h"
+#include "ResourceScriptParser.h"
+#include "ResourceScriptStmt.h"
+#include "ResourceScriptToken.h"
+
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <system_error>
+
+using namespace llvm;
+using namespace llvm::rc;
+
+namespace {
+
+// Input options tables.
+
+enum ID {
+ OPT_INVALID = 0, // This is not a correct option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
+#include "Opts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Opts.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ { \
+ PREFIX, NAME, HELPTEXT, \
+ METAVAR, OPT_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, \
+ OPT_##ALIAS, ALIASARGS, VALUES},
+#include "Opts.inc"
+#undef OPTION
+};
+
+class RcOptTable : public opt::OptTable {
+public:
+ RcOptTable() : OptTable(InfoTable, /* IgnoreCase = */ true) {}
+};
+
+static ExitOnError ExitOnErr;
+
+LLVM_ATTRIBUTE_NORETURN static void fatalError(const Twine &Message) {
+ errs() << Message << "\n";
+ exit(1);
+}
+
+} // anonymous namespace
+
+int main(int Argc, const char **Argv) {
+ InitLLVM X(Argc, Argv);
+ ExitOnErr.setBanner("llvm-rc: ");
+
+ RcOptTable T;
+ unsigned MAI, MAC;
+ const char **DashDash = std::find_if(
+ Argv + 1, Argv + Argc, [](StringRef Str) { return Str == "--"; });
+ ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, DashDash);
+
+ opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
+
+ // The tool prints nothing when invoked with no command-line arguments.
if (InputArgs.hasArg(OPT_help)) {
- T.PrintHelp(outs(), "rc [options] file...", "Resource Converter", false);
- return 0;
- }
-
+ T.PrintHelp(outs(), "rc [options] file...", "Resource Converter", false);
+ return 0;
+ }
+
const bool BeVerbose = InputArgs.hasArg(OPT_verbose);
-
- std::vector<std::string> InArgsInfo = InputArgs.getAllArgValues(OPT_INPUT);
- if (DashDash != Argv + Argc)
- InArgsInfo.insert(InArgsInfo.end(), DashDash + 1, Argv + Argc);
- if (InArgsInfo.size() != 1) {
- fatalError("Exactly one input file should be provided.");
- }
-
- // Read and tokenize the input file.
- ErrorOr<std::unique_ptr<MemoryBuffer>> File =
- MemoryBuffer::getFile(InArgsInfo[0]);
- if (!File) {
- fatalError("Error opening file '" + Twine(InArgsInfo[0]) +
- "': " + File.getError().message());
- }
-
- std::unique_ptr<MemoryBuffer> FileContents = std::move(*File);
- StringRef Contents = FileContents->getBuffer();
-
- std::string FilteredContents = filterCppOutput(Contents);
- std::vector<RCToken> Tokens = ExitOnErr(tokenizeRC(FilteredContents));
-
- if (BeVerbose) {
- const Twine TokenNames[] = {
-#define TOKEN(Name) #Name,
-#define SHORT_TOKEN(Name, Ch) #Name,
-#include "ResourceScriptTokenList.def"
- };
-
- for (const RCToken &Token : Tokens) {
- outs() << TokenNames[static_cast<int>(Token.kind())] << ": "
- << Token.value();
- if (Token.kind() == RCToken::Kind::Int)
- outs() << "; int value = " << Token.intValue();
-
- outs() << "\n";
- }
- }
-
- WriterParams Params;
- SmallString<128> InputFile(InArgsInfo[0]);
- llvm::sys::fs::make_absolute(InputFile);
- Params.InputFilePath = InputFile;
+
+ std::vector<std::string> InArgsInfo = InputArgs.getAllArgValues(OPT_INPUT);
+ if (DashDash != Argv + Argc)
+ InArgsInfo.insert(InArgsInfo.end(), DashDash + 1, Argv + Argc);
+ if (InArgsInfo.size() != 1) {
+ fatalError("Exactly one input file should be provided.");
+ }
+
+ // Read and tokenize the input file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> File =
+ MemoryBuffer::getFile(InArgsInfo[0]);
+ if (!File) {
+ fatalError("Error opening file '" + Twine(InArgsInfo[0]) +
+ "': " + File.getError().message());
+ }
+
+ std::unique_ptr<MemoryBuffer> FileContents = std::move(*File);
+ StringRef Contents = FileContents->getBuffer();
+
+ std::string FilteredContents = filterCppOutput(Contents);
+ std::vector<RCToken> Tokens = ExitOnErr(tokenizeRC(FilteredContents));
+
+ if (BeVerbose) {
+ const Twine TokenNames[] = {
+#define TOKEN(Name) #Name,
+#define SHORT_TOKEN(Name, Ch) #Name,
+#include "ResourceScriptTokenList.def"
+ };
+
+ for (const RCToken &Token : Tokens) {
+ outs() << TokenNames[static_cast<int>(Token.kind())] << ": "
+ << Token.value();
+ if (Token.kind() == RCToken::Kind::Int)
+ outs() << "; int value = " << Token.intValue();
+
+ outs() << "\n";
+ }
+ }
+
+ WriterParams Params;
+ SmallString<128> InputFile(InArgsInfo[0]);
+ llvm::sys::fs::make_absolute(InputFile);
+ Params.InputFilePath = InputFile;
Params.Include = InputArgs.getAllArgValues(OPT_includepath);
Params.NoInclude = InputArgs.getAllArgValues(OPT_noinclude);
-
+
if (InputArgs.hasArg(OPT_codepage)) {
if (InputArgs.getLastArgValue(OPT_codepage)
- .getAsInteger(10, Params.CodePage))
- fatalError("Invalid code page: " +
+ .getAsInteger(10, Params.CodePage))
+ fatalError("Invalid code page: " +
InputArgs.getLastArgValue(OPT_codepage));
- switch (Params.CodePage) {
- case CpAcp:
- case CpWin1252:
- case CpUtf8:
- break;
- default:
- fatalError(
- "Unsupported code page, only 0, 1252 and 65001 are supported!");
- }
- }
-
- std::unique_ptr<ResourceFileWriter> Visitor;
+ switch (Params.CodePage) {
+ case CpAcp:
+ case CpWin1252:
+ case CpUtf8:
+ break;
+ default:
+ fatalError(
+ "Unsupported code page, only 0, 1252 and 65001 are supported!");
+ }
+ }
+
+ std::unique_ptr<ResourceFileWriter> Visitor;
bool IsDryRun = InputArgs.hasArg(OPT_dry_run);
-
- if (!IsDryRun) {
+
+ if (!IsDryRun) {
auto OutArgsInfo = InputArgs.getAllArgValues(OPT_fileout);
- if (OutArgsInfo.empty()) {
- SmallString<128> OutputFile = InputFile;
- llvm::sys::path::replace_extension(OutputFile, "res");
- OutArgsInfo.push_back(std::string(OutputFile.str()));
- }
-
- if (OutArgsInfo.size() != 1)
- fatalError(
- "No more than one output file should be provided (using /FO flag).");
-
- std::error_code EC;
- auto FOut = std::make_unique<raw_fd_ostream>(
- OutArgsInfo[0], EC, sys::fs::FA_Read | sys::fs::FA_Write);
- if (EC)
- fatalError("Error opening output file '" + OutArgsInfo[0] +
- "': " + EC.message());
- Visitor = std::make_unique<ResourceFileWriter>(Params, std::move(FOut));
+ if (OutArgsInfo.empty()) {
+ SmallString<128> OutputFile = InputFile;
+ llvm::sys::path::replace_extension(OutputFile, "res");
+ OutArgsInfo.push_back(std::string(OutputFile.str()));
+ }
+
+ if (OutArgsInfo.size() != 1)
+ fatalError(
+ "No more than one output file should be provided (using /FO flag).");
+
+ std::error_code EC;
+ auto FOut = std::make_unique<raw_fd_ostream>(
+ OutArgsInfo[0], EC, sys::fs::FA_Read | sys::fs::FA_Write);
+ if (EC)
+ fatalError("Error opening output file '" + OutArgsInfo[0] +
+ "': " + EC.message());
+ Visitor = std::make_unique<ResourceFileWriter>(Params, std::move(FOut));
Visitor->AppendNull = InputArgs.hasArg(OPT_add_null);
-
- ExitOnErr(NullResource().visit(Visitor.get()));
-
- // Set the default language; choose en-US arbitrarily.
- unsigned PrimaryLangId = 0x09, SubLangId = 0x01;
+
+ ExitOnErr(NullResource().visit(Visitor.get()));
+
+ // Set the default language; choose en-US arbitrarily.
+ unsigned PrimaryLangId = 0x09, SubLangId = 0x01;
if (InputArgs.hasArg(OPT_lang_id)) {
- unsigned LangId;
+ unsigned LangId;
if (InputArgs.getLastArgValue(OPT_lang_id).getAsInteger(16, LangId))
- fatalError("Invalid language id: " +
+ fatalError("Invalid language id: " +
InputArgs.getLastArgValue(OPT_lang_id));
- PrimaryLangId = LangId & 0x3ff;
- SubLangId = LangId >> 10;
- }
- ExitOnErr(LanguageResource(PrimaryLangId, SubLangId).visit(Visitor.get()));
- }
-
- rc::RCParser Parser{std::move(Tokens)};
- while (!Parser.isEof()) {
- auto Resource = ExitOnErr(Parser.parseSingleResource());
- if (BeVerbose)
- Resource->log(outs());
- if (!IsDryRun)
- ExitOnErr(Resource->visit(Visitor.get()));
- }
-
- // STRINGTABLE resources come at the very end.
- if (!IsDryRun)
- ExitOnErr(Visitor->dumpAllStringTables());
-
- return 0;
-}
+ PrimaryLangId = LangId & 0x3ff;
+ SubLangId = LangId >> 10;
+ }
+ ExitOnErr(LanguageResource(PrimaryLangId, SubLangId).visit(Visitor.get()));
+ }
+
+ rc::RCParser Parser{std::move(Tokens)};
+ while (!Parser.isEof()) {
+ auto Resource = ExitOnErr(Parser.parseSingleResource());
+ if (BeVerbose)
+ Resource->log(outs());
+ if (!IsDryRun)
+ ExitOnErr(Resource->visit(Visitor.get()));
+ }
+
+ // STRINGTABLE resources come at the very end.
+ if (!IsDryRun)
+ ExitOnErr(Visitor->dumpAllStringTables());
+
+ return 0;
+}
diff --git a/contrib/libs/llvm12/tools/llvm-rc/ya.make b/contrib/libs/llvm12/tools/llvm-rc/ya.make
index e1f1b87aec..e69f41f542 100644
--- a/contrib/libs/llvm12/tools/llvm-rc/ya.make
+++ b/contrib/libs/llvm12/tools/llvm-rc/ya.make
@@ -1,40 +1,40 @@
-# Generated by devtools/yamaker.
-
-PROGRAM()
-
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
-
+
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/Demangle
contrib/libs/llvm12/lib/Option
contrib/libs/llvm12/lib/Support
-)
-
-ADDINCL(
+)
+
+ADDINCL(
${ARCADIA_BUILD_ROOT}/contrib/libs/llvm12/tools/llvm-rc
contrib/libs/llvm12/tools/llvm-rc
-)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- ResourceFileWriter.cpp
- ResourceScriptCppFilter.cpp
- ResourceScriptParser.cpp
- ResourceScriptStmt.cpp
- ResourceScriptToken.cpp
- llvm-rc.cpp
-)
-
-END()
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ ResourceFileWriter.cpp
+ ResourceScriptCppFilter.cpp
+ ResourceScriptParser.cpp
+ ResourceScriptStmt.cpp
+ ResourceScriptToken.cpp
+ llvm-rc.cpp
+)
+
+END()