[llvm] r304225 - Adding parsing ability for .res file.
Eric Beckmann via llvm-commits
llvm-commits at lists.llvm.org
Tue May 30 11:19:07 PDT 2017
Author: ecbeckmann
Date: Tue May 30 13:19:06 2017
New Revision: 304225
URL: http://llvm.org/viewvc/llvm-project?rev=304225&view=rev
Log:
Adding parsing ability for .res file.
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D33566
Modified:
llvm/trunk/include/llvm/Object/WindowsResource.h
llvm/trunk/include/llvm/Support/BinaryStreamReader.h
llvm/trunk/lib/Object/WindowsResource.cpp
llvm/trunk/lib/Support/BinaryStreamReader.cpp
llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc
llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.res
llvm/trunk/test/tools/llvm-cvtres/resource.test
llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp
Modified: llvm/trunk/include/llvm/Object/WindowsResource.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/WindowsResource.h?rev=304225&r1=304224&r2=304225&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/WindowsResource.h (original)
+++ llvm/trunk/include/llvm/Object/WindowsResource.h Tue May 30 13:19:06 2017
@@ -30,11 +30,18 @@
#define LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/Binary.h"
+#include "llvm/Object/Error.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include <map>
namespace llvm {
namespace object {
@@ -44,23 +51,44 @@ class WindowsResource;
class ResourceEntryRef {
public:
Error moveNext(bool &End);
+ bool checkTypeString() const { return IsStringType; }
+ ArrayRef<UTF16> getTypeString() const { return Type; }
+ uint16_t getTypeID() const { return TypeID; }
+ bool checkNameString() const { return IsStringName; }
+ ArrayRef<UTF16> getNameString() const { return Name; }
+ uint16_t getNameID() const { return NameID; }
+ uint16_t getLanguage() const { return Suffix->Language; }
private:
friend class WindowsResource;
ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner,
Error &Err);
+
Error loadNext();
+ struct HeaderSuffix {
+ support::ulittle32_t DataVersion;
+ support::ulittle16_t MemoryFlags;
+ support::ulittle16_t Language;
+ support::ulittle32_t Version;
+ support::ulittle32_t Characteristics;
+ };
+
BinaryStreamReader Reader;
- BinaryStreamRef HeaderBytes;
- BinaryStreamRef DataBytes;
+ bool IsStringType;
+ ArrayRef<UTF16> Type;
+ uint16_t TypeID;
+ bool IsStringName;
+ ArrayRef<UTF16> Name;
+ uint16_t NameID;
+ const HeaderSuffix *Suffix = nullptr;
+ ArrayRef<uint8_t> Data;
const WindowsResource *OwningRes = nullptr;
};
class WindowsResource : public Binary {
public:
- ~WindowsResource() override;
Expected<ResourceEntryRef> getHeadEntry();
static bool classof(const Binary *V) { return V->isWinRes(); }
@@ -76,6 +104,38 @@ private:
BinaryByteStream BBS;
};
+class WindowsResourceParser {
+public:
+ WindowsResourceParser();
+
+ Error parse(WindowsResource *WR);
+
+ void printTree() const;
+
+private:
+ class TreeNode {
+ public:
+ TreeNode() = default;
+ explicit TreeNode(uint32_t ID);
+ explicit TreeNode(ArrayRef<UTF16> Ref);
+ void addEntry(const ResourceEntryRef &Entry);
+ void print(ScopedPrinter &Writer, StringRef Name) const;
+
+ private:
+ TreeNode &addTypeNode(const ResourceEntryRef &Entry);
+ TreeNode &addNameNode(const ResourceEntryRef &Entry);
+ TreeNode &addLanguageNode(const ResourceEntryRef &Entry);
+ TreeNode &addChild(uint32_t ID);
+ TreeNode &addChild(ArrayRef<UTF16> NameRef);
+ uint16_t ID;
+ std::vector<UTF16> Name;
+ std::map<uint32_t, std::unique_ptr<TreeNode>> IDChildren;
+ std::map<std::string, std::unique_ptr<TreeNode>> StringChildren;
+ };
+
+ TreeNode Root;
+};
+
} // namespace object
} // namespace llvm
Modified: llvm/trunk/include/llvm/Support/BinaryStreamReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/BinaryStreamReader.h?rev=304225&r1=304224&r2=304225&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/BinaryStreamReader.h (original)
+++ llvm/trunk/include/llvm/Support/BinaryStreamReader.h Tue May 30 13:19:06 2017
@@ -14,6 +14,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/BinaryStreamArray.h"
#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/type_traits.h"
@@ -104,6 +105,13 @@ public:
/// returns an appropriate error code.
Error readCString(StringRef &Dest);
+ /// Similar to readCString, however read a null-terminated UTF16 string
+ /// instead.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readWideString(ArrayRef<UTF16> &Dest);
+
/// Read a \p Length byte string into \p Dest. Whether a copy occurs depends
/// on the implementation of the underlying stream. Updates the stream's
/// offset to point after the newly read data.
Modified: llvm/trunk/lib/Object/WindowsResource.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/WindowsResource.cpp?rev=304225&r1=304224&r2=304225&view=diff
==============================================================================
--- llvm/trunk/lib/Object/WindowsResource.cpp (original)
+++ llvm/trunk/lib/Object/WindowsResource.cpp Tue May 30 13:19:06 2017
@@ -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(MemoryB
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 &E
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
Modified: llvm/trunk/lib/Support/BinaryStreamReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/BinaryStreamReader.cpp?rev=304225&r1=304224&r2=304225&view=diff
==============================================================================
--- llvm/trunk/lib/Support/BinaryStreamReader.cpp (original)
+++ llvm/trunk/lib/Support/BinaryStreamReader.cpp Tue May 30 13:19:06 2017
@@ -69,6 +69,26 @@ Error BinaryStreamReader::readCString(St
return Error::success();
}
+Error BinaryStreamReader::readWideString(ArrayRef<UTF16> &Dest) {
+ uint32_t Length = 0;
+ uint32_t OriginalOffset = getOffset();
+ const UTF16 *C;
+ while (true) {
+ if (auto EC = readObject(C))
+ return EC;
+ if (*C == 0x0000)
+ break;
+ ++Length;
+ }
+ uint32_t NewOffset = getOffset();
+ setOffset(OriginalOffset);
+
+ if (auto EC = readArray(Dest, Length))
+ return EC;
+ setOffset(NewOffset);
+ return Error::success();
+}
+
Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
ArrayRef<uint8_t> Bytes;
if (auto EC = readBytes(Bytes, Length))
Modified: llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc?rev=304225&r1=304224&r2=304225&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc (original)
+++ llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc Tue May 30 13:19:06 2017
@@ -42,3 +42,9 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_A
MENUITEM "salad", 101
MENUITEM "duck", 102
}
+
+
+myresource stringarray {
+ "this is a user defined resource\0",
+ "it contains many strings\0",
+}
\ No newline at end of file
Modified: llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.res
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.res?rev=304225&r1=304224&r2=304225&view=diff
==============================================================================
Binary files - no diff available.
Modified: llvm/trunk/test/tools/llvm-cvtres/resource.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/resource.test?rev=304225&r1=304224&r2=304225&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-cvtres/resource.test (original)
+++ llvm/trunk/test/tools/llvm-cvtres/resource.test Tue May 30 13:19:06 2017
@@ -4,4 +4,48 @@
RUN: llvm-cvtres %p/Inputs/test_resource.res | FileCheck %s
-CHECK: Number of resources: 7
+CHECK: Number of resources: 8
+CHECK-NEXT: Resource Tree [
+CHECK-NEXT: STRINGARRAY [
+CHECK-NEXT: MYRESOURCE [
+CHECK-NEXT: 1033 [
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: 2 [
+CHECK-NEXT: CURSOR [
+CHECK-NEXT: 1033 [
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: OKAY [
+CHECK-NEXT: 1033 [
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: 4 [
+CHECK-NEXT: "EAT" [
+CHECK-NEXT: 3081 [
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: 14432 [
+CHECK-NEXT: 2052 [
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: 5 [
+CHECK-NEXT: TESTDIALOG [
+CHECK-NEXT: 1033 [
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: 9 [
+CHECK-NEXT: MYACCELERATORS [
+CHECK-NEXT: 1033 [
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: 12 [
+CHECK-NEXT: 1033 [
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: ]
+CHECK-NEXT: ]
Modified: llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp?rev=304225&r1=304224&r2=304225&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp (original)
+++ llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp Tue May 30 13:19:06 2017
@@ -131,7 +131,7 @@ int main(int argc_, const char *argv_[])
std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
if (InputFiles.size() == 0) {
- reportError("No input file specified");
+ reportError("No input file specified.\n");
}
SmallString<128> OutputFile;
@@ -143,6 +143,20 @@ int main(int argc_, const char *argv_[])
llvm::sys::path::replace_extension(OutputFile, ".obj");
}
+ outs() << "Machine: ";
+ switch (Machine) {
+ case machine::ARM:
+ outs() << "ARM\n";
+ break;
+ case machine::X86:
+ outs() << "X86\n";
+ break;
+ default:
+ outs() << "X64\n";
+ }
+
+ WindowsResourceParser Parser;
+
for (const auto &File : InputFiles) {
Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
object::createBinary(File);
@@ -166,17 +180,11 @@ int main(int argc_, const char *argv_[])
EntryNumber++;
}
outs() << "Number of resources: " << EntryNumber << "\n";
+
+ error(Parser.parse(RF));
}
- outs() << "Machine: ";
- switch (Machine) {
- case machine::ARM:
- outs() << "ARM\n";
- break;
- case machine::X86:
- outs() << "X86\n";
- break;
- default:
- outs() << "X64\n";
- }
+
+ Parser.printTree();
+
return 0;
}
More information about the llvm-commits
mailing list