Adding parsing ability for .res file.
Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33566 llvm-svn: 304225
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user