llvm.org GIT mirror llvm / 1f0488c
Adding parsing ability for .res file. Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33566 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@304225 91177308-0d34-0410-b5e6-96231b3b80d8 Eric Beckmann 2 years ago
8 changed file(s) with 309 addition(s) and 30 deletion(s). Raw diff Collapse all Expand all
2929 #define LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H
3030
3131 #include "llvm/ADT/ArrayRef.h"
32 #include "llvm/ADT/STLExtras.h"
3233 #include "llvm/Object/Binary.h"
34 #include "llvm/Object/Error.h"
3335 #include "llvm/Support/BinaryByteStream.h"
3436 #include "llvm/Support/BinaryStreamReader.h"
37 #include "llvm/Support/COFF.h"
38 #include "llvm/Support/ConvertUTF.h"
3539 #include "llvm/Support/Endian.h"
3640 #include "llvm/Support/Error.h"
41 #include "llvm/Support/ScopedPrinter.h"
42
43 #include
3744
3845 namespace llvm {
3946 namespace object {
4350 class ResourceEntryRef {
4451 public:
4552 Error moveNext(bool &End);
53 bool checkTypeString() const { return IsStringType; }
54 ArrayRef getTypeString() const { return Type; }
55 uint16_t getTypeID() const { return TypeID; }
56 bool checkNameString() const { return IsStringName; }
57 ArrayRef getNameString() const { return Name; }
58 uint16_t getNameID() const { return NameID; }
59 uint16_t getLanguage() const { return Suffix->Language; }
4660
4761 private:
4862 friend class WindowsResource;
4963
5064 ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner,
5165 Error &Err);
66
5267 Error loadNext();
5368
69 struct HeaderSuffix {
70 support::ulittle32_t DataVersion;
71 support::ulittle16_t MemoryFlags;
72 support::ulittle16_t Language;
73 support::ulittle32_t Version;
74 support::ulittle32_t Characteristics;
75 };
76
5477 BinaryStreamReader Reader;
55 BinaryStreamRef HeaderBytes;
56 BinaryStreamRef DataBytes;
78 bool IsStringType;
79 ArrayRef Type;
80 uint16_t TypeID;
81 bool IsStringName;
82 ArrayRef Name;
83 uint16_t NameID;
84 const HeaderSuffix *Suffix = nullptr;
85 ArrayRef Data;
5786 const WindowsResource *OwningRes = nullptr;
5887 };
5988
6089 class WindowsResource : public Binary {
6190 public:
62 ~WindowsResource() override;
6391 Expected getHeadEntry();
6492
6593 static bool classof(const Binary *V) { return V->isWinRes(); }
75103 BinaryByteStream BBS;
76104 };
77105
106 class WindowsResourceParser {
107 public:
108 WindowsResourceParser();
109
110 Error parse(WindowsResource *WR);
111
112 void printTree() const;
113
114 private:
115 class TreeNode {
116 public:
117 TreeNode() = default;
118 explicit TreeNode(uint32_t ID);
119 explicit TreeNode(ArrayRef Ref);
120 void addEntry(const ResourceEntryRef &Entry);
121 void print(ScopedPrinter &Writer, StringRef Name) const;
122
123 private:
124 TreeNode &addTypeNode(const ResourceEntryRef &Entry);
125 TreeNode &addNameNode(const ResourceEntryRef &Entry);
126 TreeNode &addLanguageNode(const ResourceEntryRef &Entry);
127 TreeNode &addChild(uint32_t ID);
128 TreeNode &addChild(ArrayRef NameRef);
129 uint16_t ID;
130 std::vector Name;
131 std::map> IDChildren;
132 std::map> StringChildren;
133 };
134
135 TreeNode Root;
136 };
137
78138 } // namespace object
79139 } // namespace llvm
80140
1313 #include "llvm/ADT/STLExtras.h"
1414 #include "llvm/Support/BinaryStreamArray.h"
1515 #include "llvm/Support/BinaryStreamRef.h"
16 #include "llvm/Support/ConvertUTF.h"
1617 #include "llvm/Support/Endian.h"
1718 #include "llvm/Support/Error.h"
1819 #include "llvm/Support/type_traits.h"
103104 /// returns an appropriate error code.
104105 Error readCString(StringRef &Dest);
105106
107 /// Similar to readCString, however read a null-terminated UTF16 string
108 /// instead.
109 ///
110 /// \returns a success error code if the data was successfully read, otherwise
111 /// returns an appropriate error code.
112 Error readWideString(ArrayRef &Dest);
113
106114 /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends
107115 /// on the implementation of the underlying stream. Updates the stream's
108116 /// offset to point after the newly read data.
1111 //===----------------------------------------------------------------------===//
1212
1313 #include "llvm/Object/WindowsResource.h"
14 #include "llvm/Object/Error.h"
14 #include "llvm/Support/COFF.h"
1515 #include
1616
1717 namespace llvm {
1818 namespace object {
1919
20 static const size_t ResourceMagicSize = 16;
21
22 static const size_t NullEntrySize = 16;
23
2420 #define RETURN_IF_ERROR(X) \
2521 if (auto EC = X) \
26 return EC;
22 return std::move(EC);
23
24 const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
25
26 static const size_t ResourceMagicSize = 16;
27
28 static const size_t NullEntrySize = 16;
2729
2830 WindowsResource::WindowsResource(MemoryBufferRef Source)
2931 : Binary(Binary::ID_WinRes, Source) {
3133 BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
3234 support::little);
3335 }
34
35 WindowsResource::~WindowsResource() = default;
3636
3737 Expected>
3838 WindowsResource::createWindowsResource(MemoryBufferRef Source) {
7171 return Error::success();
7272 }
7373
74 static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
75 ArrayRef &Str, bool &IsString) {
76 uint16_t IDFlag;
77 RETURN_IF_ERROR(Reader.readInteger(IDFlag));
78 IsString = IDFlag != 0xffff;
79
80 if (IsString) {
81 Reader.setOffset(
82 Reader.getOffset() -
83 sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
84 RETURN_IF_ERROR(Reader.readWideString(Str));
85 } else
86 RETURN_IF_ERROR(Reader.readInteger(ID));
87
88 return Error::success();
89 }
90
7491 Error ResourceEntryRef::loadNext() {
7592 uint32_t DataSize;
7693 RETURN_IF_ERROR(Reader.readInteger(DataSize));
7794 uint32_t HeaderSize;
7895 RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
79 // The data and header size ints are themselves part of the header, so we must
80 // subtract them from the size.
81 RETURN_IF_ERROR(
82 Reader.readStreamRef(HeaderBytes, HeaderSize - 2 * sizeof(uint32_t)));
83 RETURN_IF_ERROR(Reader.readStreamRef(DataBytes, DataSize));
96
97 if (HeaderSize < MIN_HEADER_SIZE)
98 return make_error("Header size is too small.",
99 object_error::parse_failed);
100
101 RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
102
103 RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
104
84105 RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
85 return Error::success();
106
107 RETURN_IF_ERROR(Reader.readObject(Suffix));
108
109 RETURN_IF_ERROR(Reader.readArray(Data, DataSize));
110
111 RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
112
113 return Error::success();
114 }
115
116 WindowsResourceParser::WindowsResourceParser() {}
117
118 Error WindowsResourceParser::parse(WindowsResource *WR) {
119 auto EntryOrErr = WR->getHeadEntry();
120 if (!EntryOrErr)
121 return EntryOrErr.takeError();
122
123 ResourceEntryRef Entry = EntryOrErr.get();
124 bool End = false;
125
126 while (!End) {
127
128 Root.addEntry(Entry);
129
130 RETURN_IF_ERROR(Entry.moveNext(End));
131 }
132
133 return Error::success();
134 }
135
136 void WindowsResourceParser::printTree() const {
137 ScopedPrinter Writer(outs());
138 Root.print(Writer, "Resource Tree");
139 }
140
141 void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry) {
142 TreeNode &TypeNode = addTypeNode(Entry);
143 TreeNode &NameNode = TypeNode.addNameNode(Entry);
144 NameNode.addLanguageNode(Entry);
145 }
146
147 WindowsResourceParser::TreeNode::TreeNode(uint32_t ID) : ID(ID) {}
148
149 WindowsResourceParser::TreeNode::TreeNode(ArrayRef NameRef)
150 : Name(NameRef) {}
151
152 WindowsResourceParser::TreeNode &
153 WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry) {
154 if (Entry.checkTypeString())
155 return addChild(Entry.getTypeString());
156 else
157 return addChild(Entry.getTypeID());
158 }
159
160 WindowsResourceParser::TreeNode &
161 WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry) {
162 if (Entry.checkNameString())
163 return addChild(Entry.getNameString());
164 else
165 return addChild(Entry.getNameID());
166 }
167
168 WindowsResourceParser::TreeNode &
169 WindowsResourceParser::TreeNode::addLanguageNode(
170 const ResourceEntryRef &Entry) {
171 return addChild(Entry.getLanguage());
172 }
173
174 WindowsResourceParser::TreeNode &
175 WindowsResourceParser::TreeNode::addChild(uint32_t ID) {
176 auto Child = IDChildren.find(ID);
177 if (Child == IDChildren.end()) {
178 auto NewChild = llvm::make_unique(ID);
179 WindowsResourceParser::TreeNode &Node = *NewChild;
180 IDChildren.emplace(ID, std::move(NewChild));
181 return Node;
182 } else
183 return *(Child->second);
184 }
185
186 WindowsResourceParser::TreeNode &
187 WindowsResourceParser::TreeNode::addChild(ArrayRef NameRef) {
188 std::string NameString;
189 ArrayRef CorrectedName;
190 if (llvm::sys::IsBigEndianHost) {
191 std::vector EndianCorrectedName;
192 EndianCorrectedName.resize(NameRef.size() + 1);
193 std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1);
194 EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
195 CorrectedName = makeArrayRef(EndianCorrectedName);
196 } else
197 CorrectedName = NameRef;
198 llvm::convertUTF16ToUTF8String(CorrectedName, NameString);
199
200 auto Child = StringChildren.find(NameString);
201 if (Child == StringChildren.end()) {
202 auto NewChild = llvm::make_unique(NameRef);
203 WindowsResourceParser::TreeNode &Node = *NewChild;
204 StringChildren.emplace(NameString, std::move(NewChild));
205 return Node;
206 } else
207 return *(Child->second);
208 }
209
210 void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
211 StringRef Name) const {
212 ListScope NodeScope(Writer, Name);
213 for (auto const &Child : StringChildren) {
214 Child.second->print(Writer, Child.first);
215 }
216 for (auto const &Child : IDChildren) {
217 Child.second->print(Writer, std::to_string(Child.first));
218 }
86219 }
87220
88221 } // namespace object
6868 return Error::success();
6969 }
7070
71 Error BinaryStreamReader::readWideString(ArrayRef &Dest) {
72 uint32_t Length = 0;
73 uint32_t OriginalOffset = getOffset();
74 const UTF16 *C;
75 while (true) {
76 if (auto EC = readObject(C))
77 return EC;
78 if (*C == 0x0000)
79 break;
80 ++Length;
81 }
82 uint32_t NewOffset = getOffset();
83 setOffset(OriginalOffset);
84
85 if (auto EC = readArray(Dest, Length))
86 return EC;
87 setOffset(NewOffset);
88 return Error::success();
89 }
90
7191 Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
7292 ArrayRef Bytes;
7393 if (auto EC = readBytes(Bytes, Length))
4141 MENUITEM "salad", 101
4242 MENUITEM "duck", 102
4343 }
44
45
46 myresource stringarray {
47 "this is a user defined resource\0",
48 "it contains many strings\0",
49 }
33
44 RUN: llvm-cvtres %p/Inputs/test_resource.res | FileCheck %s
55
6 CHECK: Number of resources: 7
6 CHECK: Number of resources: 8
7 CHECK-NEXT: Resource Tree [
8 CHECK-NEXT: STRINGARRAY [
9 CHECK-NEXT: MYRESOURCE [
10 CHECK-NEXT: 1033 [
11 CHECK-NEXT: ]
12 CHECK-NEXT: ]
13 CHECK-NEXT: ]
14 CHECK-NEXT: 2 [
15 CHECK-NEXT: CURSOR [
16 CHECK-NEXT: 1033 [
17 CHECK-NEXT: ]
18 CHECK-NEXT: ]
19 CHECK-NEXT: OKAY [
20 CHECK-NEXT: 1033 [
21 CHECK-NEXT: ]
22 CHECK-NEXT: ]
23 CHECK-NEXT: ]
24 CHECK-NEXT: 4 [
25 CHECK-NEXT: "EAT" [
26 CHECK-NEXT: 3081 [
27 CHECK-NEXT: ]
28 CHECK-NEXT: ]
29 CHECK-NEXT: 14432 [
30 CHECK-NEXT: 2052 [
31 CHECK-NEXT: ]
32 CHECK-NEXT: ]
33 CHECK-NEXT: ]
34 CHECK-NEXT: 5 [
35 CHECK-NEXT: TESTDIALOG [
36 CHECK-NEXT: 1033 [
37 CHECK-NEXT: ]
38 CHECK-NEXT: ]
39 CHECK-NEXT: ]
40 CHECK-NEXT: 9 [
41 CHECK-NEXT: MYACCELERATORS [
42 CHECK-NEXT: 1033 [
43 CHECK-NEXT: ]
44 CHECK-NEXT: ]
45 CHECK-NEXT: 12 [
46 CHECK-NEXT: 1033 [
47 CHECK-NEXT: ]
48 CHECK-NEXT: ]
49 CHECK-NEXT: ]
50 CHECK-NEXT: ]
130130 std::vector InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
131131
132132 if (InputFiles.size() == 0) {
133 reportError("No input file specified");
133 reportError("No input file specified.\n");
134134 }
135135
136136 SmallString<128> OutputFile;
141141 OutputFile = StringRef(InputFiles[0]);
142142 llvm::sys::path::replace_extension(OutputFile, ".obj");
143143 }
144
145 outs() << "Machine: ";
146 switch (Machine) {
147 case machine::ARM:
148 outs() << "ARM\n";
149 break;
150 case machine::X86:
151 outs() << "X86\n";
152 break;
153 default:
154 outs() << "X64\n";
155 }
156
157 WindowsResourceParser Parser;
144158
145159 for (const auto &File : InputFiles) {
146160 Expected> BinaryOrErr =
165179 EntryNumber++;
166180 }
167181 outs() << "Number of resources: " << EntryNumber << "\n";
182
183 error(Parser.parse(RF));
168184 }
169 outs() << "Machine: ";
170 switch (Machine) {
171 case machine::ARM:
172 outs() << "ARM\n";
173 break;
174 case machine::X86:
175 outs() << "X86\n";
176 break;
177 default:
178 outs() << "X64\n";
179 }
185
186 Parser.printTree();
187
180188 return 0;
181189 }