diff options
author | Zachary Turner <zturner@google.com> | 2017-10-06 21:30:55 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2017-10-06 21:30:55 +0000 |
commit | da366693bf6060805686b282392e7e92b77e784c (patch) | |
tree | b20ee17320e4d3d6dee24f42fd203fb4a61fcd65 /llvm/tools/llvm-rc/ResourceFileWriter.cpp | |
parent | ebaf772204ef76d560b2975277ba33a9c970de1a (diff) | |
download | bcm5719-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.cpp | 123 |
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) { |