1 //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the .res file class.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Object/WindowsResource.h"
15 #include "llvm/Support/COFF.h"
17 #include <system_error>
22 #define RETURN_IF_ERROR(X) \
26 const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
28 static const size_t ResourceMagicSize = 16;
30 static const size_t NullEntrySize = 16;
32 WindowsResource::WindowsResource(MemoryBufferRef Source)
33 : Binary(Binary::ID_WinRes, Source) {
34 size_t LeadingSize = ResourceMagicSize + NullEntrySize;
35 BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
39 Expected<std::unique_ptr<WindowsResource>>
40 WindowsResource::createWindowsResource(MemoryBufferRef Source) {
41 if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize)
42 return make_error<GenericBinaryError>(
43 "File too small to be a resource file",
44 object_error::invalid_file_type);
45 std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
46 return std::move(Ret);
49 Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
50 Error Err = Error::success();
51 auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err);
53 return std::move(Err);
57 ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
58 const WindowsResource *Owner, Error &Err)
59 : Reader(Ref), OwningRes(Owner) {
61 Err = make_error<GenericBinaryError>("Could not read first entry.",
62 object_error::unexpected_eof);
65 Error ResourceEntryRef::moveNext(bool &End) {
66 // Reached end of all the entries.
67 if (Reader.bytesRemaining() == 0) {
69 return Error::success();
71 RETURN_IF_ERROR(loadNext());
73 return Error::success();
76 static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
77 ArrayRef<UTF16> &Str, bool &IsString) {
79 RETURN_IF_ERROR(Reader.readInteger(IDFlag));
80 IsString = IDFlag != 0xffff;
85 sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
86 RETURN_IF_ERROR(Reader.readWideString(Str));
88 RETURN_IF_ERROR(Reader.readInteger(ID));
90 return Error::success();
93 Error ResourceEntryRef::loadNext() {
95 RETURN_IF_ERROR(Reader.readInteger(DataSize));
97 RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
99 if (HeaderSize < MIN_HEADER_SIZE)
100 return make_error<GenericBinaryError>("Header size is too small.",
101 object_error::parse_failed);
103 RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
105 RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
107 RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
109 RETURN_IF_ERROR(Reader.readObject(Suffix));
111 RETURN_IF_ERROR(Reader.readArray(Data, DataSize));
113 RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
115 return Error::success();
118 WindowsResourceParser::WindowsResourceParser() {}
120 Error WindowsResourceParser::parse(WindowsResource *WR) {
121 auto EntryOrErr = WR->getHeadEntry();
123 return EntryOrErr.takeError();
125 ResourceEntryRef Entry = EntryOrErr.get();
130 Root.addEntry(Entry);
132 RETURN_IF_ERROR(Entry.moveNext(End));
135 return Error::success();
138 void WindowsResourceParser::printTree() const {
139 ScopedPrinter Writer(outs());
140 Root.print(Writer, "Resource Tree");
143 void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry) {
144 TreeNode &TypeNode = addTypeNode(Entry);
145 TreeNode &NameNode = TypeNode.addNameNode(Entry);
146 NameNode.addLanguageNode(Entry);
149 WindowsResourceParser::TreeNode::TreeNode(ArrayRef<UTF16> NameRef)
152 WindowsResourceParser::TreeNode &
153 WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry) {
154 if (Entry.checkTypeString())
155 return addChild(Entry.getTypeString());
157 return addChild(Entry.getTypeID());
160 WindowsResourceParser::TreeNode &
161 WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry) {
162 if (Entry.checkNameString())
163 return addChild(Entry.getNameString());
165 return addChild(Entry.getNameID());
168 WindowsResourceParser::TreeNode &
169 WindowsResourceParser::TreeNode::addLanguageNode(
170 const ResourceEntryRef &Entry) {
171 return addChild(Entry.getLanguage());
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<WindowsResourceParser::TreeNode>(ID);
179 WindowsResourceParser::TreeNode &Node = *NewChild;
180 IDChildren.emplace(ID, std::move(NewChild));
183 return *(Child->second);
186 WindowsResourceParser::TreeNode &
187 WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef) {
188 std::string NameString;
189 ArrayRef<UTF16> CorrectedName;
190 std::vector<UTF16> EndianCorrectedName;
191 if (llvm::sys::IsBigEndianHost) {
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);
197 CorrectedName = NameRef;
198 llvm::convertUTF16ToUTF8String(CorrectedName, NameString);
200 auto Child = StringChildren.find(NameString);
201 if (Child == StringChildren.end()) {
202 auto NewChild = llvm::make_unique<WindowsResourceParser::TreeNode>(NameRef);
203 WindowsResourceParser::TreeNode &Node = *NewChild;
204 StringChildren.emplace(NameString, std::move(NewChild));
207 return *(Child->second);
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);
216 for (auto const &Child : IDChildren) {
217 Child.second->print(Writer, to_string(Child.first));
221 } // namespace object