aboutsummaryrefslogtreecommitdiff
path: root/lib/Object/WindowsResource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Object/WindowsResource.cpp')
-rw-r--r--lib/Object/WindowsResource.cpp156
1 files changed, 144 insertions, 12 deletions
diff --git a/lib/Object/WindowsResource.cpp b/lib/Object/WindowsResource.cpp
index b52563469094..e46d38e466a0 100644
--- a/lib/Object/WindowsResource.cpp
+++ b/lib/Object/WindowsResource.cpp
@@ -12,20 +12,23 @@
//===----------------------------------------------------------------------===//
#include "llvm/Object/WindowsResource.h"
-#include "llvm/Object/Error.h"
+#include "llvm/Support/COFF.h"
+#include <sstream>
#include <system_error>
namespace llvm {
namespace object {
-static const size_t ResourceMagicSize = 16;
-
-static const size_t NullEntrySize = 16;
-
#define RETURN_IF_ERROR(X) \
if (auto EC = X) \
return 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;
+
WindowsResource::WindowsResource(MemoryBufferRef Source)
: Binary(Binary::ID_WinRes, Source) {
size_t LeadingSize = ResourceMagicSize + NullEntrySize;
@@ -33,8 +36,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 +73,150 @@ 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(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;
+ std::vector<UTF16> EndianCorrectedName;
+ if (llvm::sys::IsBigEndianHost) {
+ 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, to_string(Child.first));
+ }
+}
+
} // namespace object
} // namespace llvm