summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-rc/ResourceFileWriter.cpp
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2017-10-06 21:30:55 +0000
committerZachary Turner <zturner@google.com>2017-10-06 21:30:55 +0000
commitda366693bf6060805686b282392e7e92b77e784c (patch)
treeb20ee17320e4d3d6dee24f42fd203fb4a61fcd65 /llvm/tools/llvm-rc/ResourceFileWriter.cpp
parentebaf772204ef76d560b2975277ba33a9c970de1a (diff)
downloadbcm5719-llvm-da366693bf6060805686b282392e7e92b77e784c.tar.gz
bcm5719-llvm-da366693bf6060805686b282392e7e92b77e784c.zip
[llvm-rc] Serialize STRINGTABLE statements to .res file.
This allows llvm-rc to serialize STRINGTABLE resources. These are output in an unusual way: we locate them at the end of the file, and strings are merged into bundles of max 16 strings, depending on their IDs, language, and characteristics. Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050.aspx Patch by: Marek Sokolowski Differential Revision: https://reviews.llvm.org/D38420 llvm-svn: 315112
Diffstat (limited to 'llvm/tools/llvm-rc/ResourceFileWriter.cpp')
-rw-r--r--llvm/tools/llvm-rc/ResourceFileWriter.cpp123
1 files changed, 116 insertions, 7 deletions
diff --git a/llvm/tools/llvm-rc/ResourceFileWriter.cpp b/llvm/tools/llvm-rc/ResourceFileWriter.cpp
index e6480f126ef..f41ffcc8ac5 100644
--- a/llvm/tools/llvm-rc/ResourceFileWriter.cpp
+++ b/llvm/tools/llvm-rc/ResourceFileWriter.cpp
@@ -129,8 +129,6 @@ enum class NullHandlingMethod {
// For identifiers, this is no-op.
static Error processString(StringRef Str, NullHandlingMethod NullHandler,
bool &IsLongString, SmallVectorImpl<UTF16> &Result) {
- assert(NullHandler == NullHandlingMethod::CutAtNull);
-
bool IsString = stripQuotes(Str, IsLongString);
convertUTF8ToUTF16String(Str, Result);
@@ -143,11 +141,24 @@ static Error processString(StringRef Str, NullHandlingMethod NullHandler,
return Error::success();
}
- // We don't process the string contents. Only cut at '\0'.
-
- for (size_t Pos = 0; Pos < Result.size(); ++Pos)
- if (Result[Pos] == '\0')
- Result.resize(Pos);
+ 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();
}
@@ -258,6 +269,35 @@ 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));
+ 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::visitVersionInfoResource(const RCResource *Res) {
return writeResource(Res, &ResourceFileWriter::writeVersionInfoBody);
}
@@ -939,6 +979,75 @@ Error ResourceFileWriter::writeMenuBody(const RCResource *Base) {
return writeMenuDefinitionList(cast<MenuResource>(Base)->Elements);
}
+// --- StringTableResource helpers. --- //
+
+class BundleResource : public RCResource {
+public:
+ using BundleType = ResourceFileWriter::StringTableInfo::Bundle;
+ BundleType Bundle;
+
+ BundleResource(const BundleType &StrBundle) : Bundle(StrBundle) {}
+ IntOrString getResourceType() const override { return 6; }
+
+ ResourceKind getKind() const override { return RkStringTableBundle; }
+ static bool classof(const RCResource *Res) {
+ return Res->getKind() == RkStringTableBundle;
+ }
+};
+
+Error ResourceFileWriter::visitStringTableBundle(const RCResource *Res) {
+ return writeResource(Res, &ResourceFileWriter::writeStringTableBundleBody);
+}
+
+Error ResourceFileWriter::insertStringIntoBundle(
+ StringTableInfo::Bundle &Bundle, uint16_t StringID, 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).
+ bool IsLongString;
+ SmallVector<UTF16, 128> Data;
+ RETURN_IF_ERROR(processString(Res->Bundle.Data[ID].getValueOr(StringRef()),
+ NullHandlingMethod::CutAtDoubleNull,
+ IsLongString, Data));
+ if (AppendNull && Res->Bundle.Data[ID])
+ Data.push_back('\0');
+ RETURN_IF_ERROR(
+ checkNumberFits<uint16_t>(Data.size(), "STRINGTABLE string size"));
+ writeObject(ulittle16_t(Data.size()));
+ for (auto Char : Data)
+ writeObject(ulittle16_t(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();
+}
+
// --- VersionInfoResourceResource helpers. --- //
Error ResourceFileWriter::writeVersionInfoBlock(const VersionInfoBlock &Blk) {
OpenPOWER on IntegriCloud