1 //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements the .res file class. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Object/WindowsResource.h" 15 #include "llvm/BinaryFormat/COFF.h" 16 #include <sstream> 17 #include <system_error> 18 19 namespace llvm { 20 namespace object { 21 22 #define RETURN_IF_ERROR(X) \ 23 if (auto EC = X) \ 24 return EC; 25 26 const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); 27 28 static const size_t ResourceMagicSize = 16; 29 30 static const size_t NullEntrySize = 16; 31 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), 36 support::little); 37 } 38 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); 47 } 48 49 Expected<ResourceEntryRef> WindowsResource::getHeadEntry() { 50 Error Err = Error::success(); 51 auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err); 52 if (Err) 53 return std::move(Err); 54 return Ref; 55 } 56 57 ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref, 58 const WindowsResource *Owner, Error &Err) 59 : Reader(Ref), OwningRes(Owner) { 60 if (loadNext()) 61 Err = make_error<GenericBinaryError>("Could not read first entry.", 62 object_error::unexpected_eof); 63 } 64 65 Error ResourceEntryRef::moveNext(bool &End) { 66 // Reached end of all the entries. 67 if (Reader.bytesRemaining() == 0) { 68 End = true; 69 return Error::success(); 70 } 71 RETURN_IF_ERROR(loadNext()); 72 73 return Error::success(); 74 } 75 76 static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, 77 ArrayRef<UTF16> &Str, bool &IsString) { 78 uint16_t IDFlag; 79 RETURN_IF_ERROR(Reader.readInteger(IDFlag)); 80 IsString = IDFlag != 0xffff; 81 82 if (IsString) { 83 Reader.setOffset( 84 Reader.getOffset() - 85 sizeof(uint16_t)); // Re-read the bytes which we used to check the flag. 86 RETURN_IF_ERROR(Reader.readWideString(Str)); 87 } else 88 RETURN_IF_ERROR(Reader.readInteger(ID)); 89 90 return Error::success(); 91 } 92 93 Error ResourceEntryRef::loadNext() { 94 uint32_t DataSize; 95 RETURN_IF_ERROR(Reader.readInteger(DataSize)); 96 uint32_t HeaderSize; 97 RETURN_IF_ERROR(Reader.readInteger(HeaderSize)); 98 99 if (HeaderSize < MIN_HEADER_SIZE) 100 return make_error<GenericBinaryError>("Header size is too small.", 101 object_error::parse_failed); 102 103 RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType)); 104 105 RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName)); 106 107 RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); 108 109 RETURN_IF_ERROR(Reader.readObject(Suffix)); 110 111 RETURN_IF_ERROR(Reader.readArray(Data, DataSize)); 112 113 RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); 114 115 return Error::success(); 116 } 117 118 WindowsResourceParser::WindowsResourceParser() {} 119 120 Error WindowsResourceParser::parse(WindowsResource *WR) { 121 auto EntryOrErr = WR->getHeadEntry(); 122 if (!EntryOrErr) 123 return EntryOrErr.takeError(); 124 125 ResourceEntryRef Entry = EntryOrErr.get(); 126 bool End = false; 127 128 while (!End) { 129 130 Root.addEntry(Entry); 131 132 RETURN_IF_ERROR(Entry.moveNext(End)); 133 } 134 135 return Error::success(); 136 } 137 138 void WindowsResourceParser::printTree() const { 139 ScopedPrinter Writer(outs()); 140 Root.print(Writer, "Resource Tree"); 141 } 142 143 void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry) { 144 TreeNode &TypeNode = addTypeNode(Entry); 145 TreeNode &NameNode = TypeNode.addNameNode(Entry); 146 NameNode.addLanguageNode(Entry); 147 } 148 149 WindowsResourceParser::TreeNode::TreeNode(ArrayRef<UTF16> 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<WindowsResourceParser::TreeNode>(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<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); 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<WindowsResourceParser::TreeNode>(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, to_string(Child.first)); 218 } 219 } 220 221 } // namespace object 222 } // namespace llvm 223