diff options
author | Eric Beckmann <ecbeckmann@google.com> | 2017-05-30 18:19:06 +0000 |
---|---|---|
committer | Eric Beckmann <ecbeckmann@google.com> | 2017-05-30 18:19:06 +0000 |
commit | 72fb6a87fb2e2f87a192aa9d80eefc484bf3e41a (patch) | |
tree | 5bc310d384fcf4991550c9a31a98ea889f6b3c02 /llvm/lib/Object/WindowsResource.cpp | |
parent | 4cec434a1bd3d30c263bdb4e07ecb4db32caee6c (diff) | |
download | bcm5719-llvm-72fb6a87fb2e2f87a192aa9d80eefc484bf3e41a.tar.gz bcm5719-llvm-72fb6a87fb2e2f87a192aa9d80eefc484bf3e41a.zip |
Adding parsing ability for .res file.
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D33566
llvm-svn: 304225
Diffstat (limited to 'llvm/lib/Object/WindowsResource.cpp')
-rw-r--r-- | llvm/lib/Object/WindowsResource.cpp | 157 |
1 files changed, 145 insertions, 12 deletions
diff --git a/llvm/lib/Object/WindowsResource.cpp b/llvm/lib/Object/WindowsResource.cpp index b5256346909..9dea5539858 100644 --- a/llvm/lib/Object/WindowsResource.cpp +++ b/llvm/lib/Object/WindowsResource.cpp @@ -12,20 +12,22 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/WindowsResource.h" -#include "llvm/Object/Error.h" +#include "llvm/Support/COFF.h" #include <system_error> namespace llvm { namespace object { +#define RETURN_IF_ERROR(X) \ + if (auto EC = X) \ + return std::move(EC); + +const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); + static const size_t ResourceMagicSize = 16; static const size_t NullEntrySize = 16; -#define RETURN_IF_ERROR(X) \ - if (auto EC = X) \ - return EC; - WindowsResource::WindowsResource(MemoryBufferRef Source) : Binary(Binary::ID_WinRes, Source) { size_t LeadingSize = ResourceMagicSize + NullEntrySize; @@ -33,8 +35,6 @@ WindowsResource::WindowsResource(MemoryBufferRef Source) support::little); } -WindowsResource::~WindowsResource() = default; - Expected<std::unique_ptr<WindowsResource>> WindowsResource::createWindowsResource(MemoryBufferRef Source) { if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize) @@ -72,19 +72,152 @@ Error ResourceEntryRef::moveNext(bool &End) { return Error::success(); } +static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, + ArrayRef<UTF16> &Str, bool &IsString) { + uint16_t IDFlag; + RETURN_IF_ERROR(Reader.readInteger(IDFlag)); + IsString = IDFlag != 0xffff; + + if (IsString) { + Reader.setOffset( + Reader.getOffset() - + sizeof(uint16_t)); // Re-read the bytes which we used to check the flag. + RETURN_IF_ERROR(Reader.readWideString(Str)); + } else + RETURN_IF_ERROR(Reader.readInteger(ID)); + + return Error::success(); +} + Error ResourceEntryRef::loadNext() { uint32_t DataSize; RETURN_IF_ERROR(Reader.readInteger(DataSize)); uint32_t HeaderSize; RETURN_IF_ERROR(Reader.readInteger(HeaderSize)); - // The data and header size ints are themselves part of the header, so we must - // subtract them from the size. - RETURN_IF_ERROR( - Reader.readStreamRef(HeaderBytes, HeaderSize - 2 * sizeof(uint32_t))); - RETURN_IF_ERROR(Reader.readStreamRef(DataBytes, DataSize)); + + if (HeaderSize < MIN_HEADER_SIZE) + return make_error<GenericBinaryError>("Header size is too small.", + object_error::parse_failed); + + RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType)); + + RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName)); + + RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); + + RETURN_IF_ERROR(Reader.readObject(Suffix)); + + RETURN_IF_ERROR(Reader.readArray(Data, DataSize)); + RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); + return Error::success(); } +WindowsResourceParser::WindowsResourceParser() {} + +Error WindowsResourceParser::parse(WindowsResource *WR) { + auto EntryOrErr = WR->getHeadEntry(); + if (!EntryOrErr) + return EntryOrErr.takeError(); + + ResourceEntryRef Entry = EntryOrErr.get(); + bool End = false; + + while (!End) { + + Root.addEntry(Entry); + + RETURN_IF_ERROR(Entry.moveNext(End)); + } + + return Error::success(); +} + +void WindowsResourceParser::printTree() const { + ScopedPrinter Writer(outs()); + Root.print(Writer, "Resource Tree"); +} + +void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry) { + TreeNode &TypeNode = addTypeNode(Entry); + TreeNode &NameNode = TypeNode.addNameNode(Entry); + NameNode.addLanguageNode(Entry); +} + +WindowsResourceParser::TreeNode::TreeNode(uint32_t ID) : ID(ID) {} + +WindowsResourceParser::TreeNode::TreeNode(ArrayRef<UTF16> NameRef) + : Name(NameRef) {} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry) { + if (Entry.checkTypeString()) + return addChild(Entry.getTypeString()); + else + return addChild(Entry.getTypeID()); +} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry) { + if (Entry.checkNameString()) + return addChild(Entry.getNameString()); + else + return addChild(Entry.getNameID()); +} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addLanguageNode( + const ResourceEntryRef &Entry) { + return addChild(Entry.getLanguage()); +} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addChild(uint32_t ID) { + auto Child = IDChildren.find(ID); + if (Child == IDChildren.end()) { + auto NewChild = llvm::make_unique<WindowsResourceParser::TreeNode>(ID); + WindowsResourceParser::TreeNode &Node = *NewChild; + IDChildren.emplace(ID, std::move(NewChild)); + return Node; + } else + return *(Child->second); +} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef) { + std::string NameString; + ArrayRef<UTF16> CorrectedName; + if (llvm::sys::IsBigEndianHost) { + std::vector<UTF16> EndianCorrectedName; + EndianCorrectedName.resize(NameRef.size() + 1); + std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1); + EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; + CorrectedName = makeArrayRef(EndianCorrectedName); + } else + CorrectedName = NameRef; + llvm::convertUTF16ToUTF8String(CorrectedName, NameString); + + auto Child = StringChildren.find(NameString); + if (Child == StringChildren.end()) { + auto NewChild = llvm::make_unique<WindowsResourceParser::TreeNode>(NameRef); + WindowsResourceParser::TreeNode &Node = *NewChild; + StringChildren.emplace(NameString, std::move(NewChild)); + return Node; + } else + return *(Child->second); +} + +void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer, + StringRef Name) const { + ListScope NodeScope(Writer, Name); + for (auto const &Child : StringChildren) { + Child.second->print(Writer, Child.first); + } + for (auto const &Child : IDChildren) { + Child.second->print(Writer, std::to_string(Child.first)); + } +} + } // namespace object } // namespace llvm |