1a6bdf751SEric Beckmann //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===// 2a6bdf751SEric Beckmann // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a6bdf751SEric Beckmann // 7a6bdf751SEric Beckmann //===----------------------------------------------------------------------===// 8a6bdf751SEric Beckmann // 9a6bdf751SEric Beckmann // This file implements the .res file class. 10a6bdf751SEric Beckmann // 11a6bdf751SEric Beckmann //===----------------------------------------------------------------------===// 12a6bdf751SEric Beckmann 13a6bdf751SEric Beckmann #include "llvm/Object/WindowsResource.h" 14d9de6389SEric Beckmann #include "llvm/Object/COFF.h" 15d9de6389SEric Beckmann #include "llvm/Support/FileOutputBuffer.h" 16ea5ff9faSBob Haarman #include "llvm/Support/FormatVariadic.h" 17d9de6389SEric Beckmann #include "llvm/Support/MathExtras.h" 1823cb79ffSNico Weber #include "llvm/Support/ScopedPrinter.h" 19d9de6389SEric Beckmann #include <ctime> 20d9de6389SEric Beckmann #include <queue> 21a6bdf751SEric Beckmann #include <system_error> 22a6bdf751SEric Beckmann 23d135e8c0SEric Beckmann using namespace llvm; 247687f046SEric Beckmann using namespace object; 25d135e8c0SEric Beckmann 26a6bdf751SEric Beckmann namespace llvm { 27a6bdf751SEric Beckmann namespace object { 28a6bdf751SEric Beckmann 2972fb6a87SEric Beckmann #define RETURN_IF_ERROR(X) \ 3072fb6a87SEric Beckmann if (auto EC = X) \ 3114ea122eSBenjamin Kramer return EC; 3272fb6a87SEric Beckmann 3372fb6a87SEric Beckmann const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); 3472fb6a87SEric Beckmann 35382eaabbSEric Beckmann // COFF files seem to be inconsistent with alignment between sections, just use 36382eaabbSEric Beckmann // 8-byte because it makes everyone happy. 37382eaabbSEric Beckmann const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t); 38382eaabbSEric Beckmann 39a6bdf751SEric Beckmann WindowsResource::WindowsResource(MemoryBufferRef Source) 40a6bdf751SEric Beckmann : Binary(Binary::ID_WinRes, Source) { 41c8dba240SEric Beckmann size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE; 42a6bdf751SEric Beckmann BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize), 43a6bdf751SEric Beckmann support::little); 44a6bdf751SEric Beckmann } 45a6bdf751SEric Beckmann 46413517ecSNico Weber // static 47a6bdf751SEric Beckmann Expected<std::unique_ptr<WindowsResource>> 48a6bdf751SEric Beckmann WindowsResource::createWindowsResource(MemoryBufferRef Source) { 49c8dba240SEric Beckmann if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE) 50a6bdf751SEric Beckmann return make_error<GenericBinaryError>( 51413517ecSNico Weber Source.getBufferIdentifier() + ": too small to be a resource file", 52a6bdf751SEric Beckmann object_error::invalid_file_type); 53a6bdf751SEric Beckmann std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source)); 54a6bdf751SEric Beckmann return std::move(Ret); 55a6bdf751SEric Beckmann } 56a6bdf751SEric Beckmann 57a6bdf751SEric Beckmann Expected<ResourceEntryRef> WindowsResource::getHeadEntry() { 58b85172f6SEric Beckmann if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix)) 59413517ecSNico Weber return make_error<EmptyResError>(getFileName() + " contains no entries", 60b85172f6SEric Beckmann object_error::unexpected_eof); 61b85172f6SEric Beckmann return ResourceEntryRef::create(BinaryStreamRef(BBS), this); 62a6bdf751SEric Beckmann } 63a6bdf751SEric Beckmann 64a6bdf751SEric Beckmann ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref, 65b85172f6SEric Beckmann const WindowsResource *Owner) 66413517ecSNico Weber : Reader(Ref), Owner(Owner) {} 67b85172f6SEric Beckmann 68b85172f6SEric Beckmann Expected<ResourceEntryRef> 69b85172f6SEric Beckmann ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) { 70b85172f6SEric Beckmann auto Ref = ResourceEntryRef(BSR, Owner); 71b85172f6SEric Beckmann if (auto E = Ref.loadNext()) 72b85172f6SEric Beckmann return std::move(E); 73b85172f6SEric Beckmann return Ref; 74a6bdf751SEric Beckmann } 75a6bdf751SEric Beckmann 76a6bdf751SEric Beckmann Error ResourceEntryRef::moveNext(bool &End) { 77a6bdf751SEric Beckmann // Reached end of all the entries. 78a6bdf751SEric Beckmann if (Reader.bytesRemaining() == 0) { 79a6bdf751SEric Beckmann End = true; 80a6bdf751SEric Beckmann return Error::success(); 81a6bdf751SEric Beckmann } 82a6bdf751SEric Beckmann RETURN_IF_ERROR(loadNext()); 83a6bdf751SEric Beckmann 84a6bdf751SEric Beckmann return Error::success(); 85a6bdf751SEric Beckmann } 86a6bdf751SEric Beckmann 8772fb6a87SEric Beckmann static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, 8872fb6a87SEric Beckmann ArrayRef<UTF16> &Str, bool &IsString) { 8972fb6a87SEric Beckmann uint16_t IDFlag; 9072fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readInteger(IDFlag)); 9172fb6a87SEric Beckmann IsString = IDFlag != 0xffff; 9272fb6a87SEric Beckmann 9372fb6a87SEric Beckmann if (IsString) { 9472fb6a87SEric Beckmann Reader.setOffset( 9572fb6a87SEric Beckmann Reader.getOffset() - 9672fb6a87SEric Beckmann sizeof(uint16_t)); // Re-read the bytes which we used to check the flag. 9772fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readWideString(Str)); 9872fb6a87SEric Beckmann } else 9972fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readInteger(ID)); 10072fb6a87SEric Beckmann 10172fb6a87SEric Beckmann return Error::success(); 10272fb6a87SEric Beckmann } 10372fb6a87SEric Beckmann 104a6bdf751SEric Beckmann Error ResourceEntryRef::loadNext() { 105c8dba240SEric Beckmann const WinResHeaderPrefix *Prefix; 106c8dba240SEric Beckmann RETURN_IF_ERROR(Reader.readObject(Prefix)); 10772fb6a87SEric Beckmann 108c8dba240SEric Beckmann if (Prefix->HeaderSize < MIN_HEADER_SIZE) 109413517ecSNico Weber return make_error<GenericBinaryError>(Owner->getFileName() + 110413517ecSNico Weber ": header size too small", 11172fb6a87SEric Beckmann object_error::parse_failed); 11272fb6a87SEric Beckmann 11372fb6a87SEric Beckmann RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType)); 11472fb6a87SEric Beckmann 11572fb6a87SEric Beckmann RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName)); 11672fb6a87SEric Beckmann 117c8dba240SEric Beckmann RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT)); 11872fb6a87SEric Beckmann 11972fb6a87SEric Beckmann RETURN_IF_ERROR(Reader.readObject(Suffix)); 12072fb6a87SEric Beckmann 121c8dba240SEric Beckmann RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize)); 12272fb6a87SEric Beckmann 123c8dba240SEric Beckmann RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT)); 12472fb6a87SEric Beckmann 125a6bdf751SEric Beckmann return Error::success(); 126a6bdf751SEric Beckmann } 127a6bdf751SEric Beckmann 128d9de6389SEric Beckmann WindowsResourceParser::WindowsResourceParser() : Root(false) {} 12972fb6a87SEric Beckmann 13023cb79ffSNico Weber void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) { 13123cb79ffSNico Weber switch (TypeID) { 13223cb79ffSNico Weber case 1: OS << "CURSOR (ID 1)"; break; 13323cb79ffSNico Weber case 2: OS << "BITMAP (ID 2)"; break; 13423cb79ffSNico Weber case 3: OS << "ICON (ID 3)"; break; 13523cb79ffSNico Weber case 4: OS << "MENU (ID 4)"; break; 13623cb79ffSNico Weber case 5: OS << "DIALOG (ID 5)"; break; 13723cb79ffSNico Weber case 6: OS << "STRINGTABLE (ID 6)"; break; 13823cb79ffSNico Weber case 7: OS << "FONTDIR (ID 7)"; break; 13923cb79ffSNico Weber case 8: OS << "FONT (ID 8)"; break; 14023cb79ffSNico Weber case 9: OS << "ACCELERATOR (ID 9)"; break; 14123cb79ffSNico Weber case 10: OS << "RCDATA (ID 10)"; break; 14223cb79ffSNico Weber case 11: OS << "MESSAGETABLE (ID 11)"; break; 14323cb79ffSNico Weber case 12: OS << "GROUP_CURSOR (ID 12)"; break; 14423cb79ffSNico Weber case 14: OS << "GROUP_ICON (ID 14)"; break; 14523cb79ffSNico Weber case 16: OS << "VERSIONINFO (ID 16)"; break; 14623cb79ffSNico Weber case 17: OS << "DLGINCLUDE (ID 17)"; break; 14723cb79ffSNico Weber case 19: OS << "PLUGPLAY (ID 19)"; break; 14823cb79ffSNico Weber case 20: OS << "VXD (ID 20)"; break; 14923cb79ffSNico Weber case 21: OS << "ANICURSOR (ID 21)"; break; 15023cb79ffSNico Weber case 22: OS << "ANIICON (ID 22)"; break; 15123cb79ffSNico Weber case 23: OS << "HTML (ID 23)"; break; 15223cb79ffSNico Weber case 24: OS << "MANIFEST (ID 24)"; break; 15323cb79ffSNico Weber default: OS << "ID " << TypeID; break; 15423cb79ffSNico Weber } 15523cb79ffSNico Weber } 15623cb79ffSNico Weber 157cf6267ceSNico Weber static bool convertUTF16LEToUTF8String(ArrayRef<UTF16> Src, std::string &Out) { 158cf6267ceSNico Weber if (!sys::IsBigEndianHost) 159cf6267ceSNico Weber return convertUTF16ToUTF8String(Src, Out); 160cf6267ceSNico Weber 161cf6267ceSNico Weber std::vector<UTF16> EndianCorrectedSrc; 162cf6267ceSNico Weber EndianCorrectedSrc.resize(Src.size() + 1); 163cf6267ceSNico Weber llvm::copy(Src, EndianCorrectedSrc.begin() + 1); 164cf6267ceSNico Weber EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; 165cf6267ceSNico Weber return convertUTF16ToUTF8String(makeArrayRef(EndianCorrectedSrc), Out); 166cf6267ceSNico Weber } 167cf6267ceSNico Weber 16881862f82SNico Weber static std::string makeDuplicateResourceError( 16981862f82SNico Weber const ResourceEntryRef &Entry, StringRef File1, StringRef File2) { 170ccf09646SNico Weber std::string Ret; 171ccf09646SNico Weber raw_string_ostream OS(Ret); 172ccf09646SNico Weber 173ccf09646SNico Weber OS << "duplicate resource:"; 174ccf09646SNico Weber 175ccf09646SNico Weber OS << " type "; 176ccf09646SNico Weber if (Entry.checkTypeString()) { 177ccf09646SNico Weber std::string UTF8; 178cf6267ceSNico Weber if (!convertUTF16LEToUTF8String(Entry.getTypeString(), UTF8)) 179ccf09646SNico Weber UTF8 = "(failed conversion from UTF16)"; 180ccf09646SNico Weber OS << '\"' << UTF8 << '\"'; 18123cb79ffSNico Weber } else 18223cb79ffSNico Weber printResourceTypeName(Entry.getTypeID(), OS); 183ccf09646SNico Weber 184ccf09646SNico Weber OS << "/name "; 185ccf09646SNico Weber if (Entry.checkNameString()) { 186ccf09646SNico Weber std::string UTF8; 187cf6267ceSNico Weber if (!convertUTF16LEToUTF8String(Entry.getNameString(), UTF8)) 188ccf09646SNico Weber UTF8 = "(failed conversion from UTF16)"; 189ccf09646SNico Weber OS << '\"' << UTF8 << '\"'; 190ccf09646SNico Weber } else { 191ccf09646SNico Weber OS << "ID " << Entry.getNameID(); 192ccf09646SNico Weber } 193ccf09646SNico Weber 194ccf09646SNico Weber OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in " 195ccf09646SNico Weber << File2; 196ccf09646SNico Weber 19781862f82SNico Weber return OS.str(); 198ccf09646SNico Weber } 199ccf09646SNico Weber 20081862f82SNico Weber Error WindowsResourceParser::parse(WindowsResource *WR, 20181862f82SNico Weber std::vector<std::string> &Duplicates) { 20272fb6a87SEric Beckmann auto EntryOrErr = WR->getHeadEntry(); 203b85172f6SEric Beckmann if (!EntryOrErr) { 204b85172f6SEric Beckmann auto E = EntryOrErr.takeError(); 205b85172f6SEric Beckmann if (E.isA<EmptyResError>()) { 206b85172f6SEric Beckmann // Check if the .res file contains no entries. In this case we don't have 207b85172f6SEric Beckmann // to throw an error but can rather just return without parsing anything. 208b85172f6SEric Beckmann // This applies for files which have a valid PE header magic and the 209b85172f6SEric Beckmann // mandatory empty null resource entry. Files which do not fit this 210b85172f6SEric Beckmann // criteria would have already been filtered out by 211b85172f6SEric Beckmann // WindowsResource::createWindowsResource(). 212b85172f6SEric Beckmann consumeError(std::move(E)); 213b85172f6SEric Beckmann return Error::success(); 214b85172f6SEric Beckmann } 215b85172f6SEric Beckmann return E; 216b85172f6SEric Beckmann } 21772fb6a87SEric Beckmann 21872fb6a87SEric Beckmann ResourceEntryRef Entry = EntryOrErr.get(); 219e62d5682SMartin Storsjo uint32_t Origin = InputFilenames.size(); 220e62d5682SMartin Storsjo InputFilenames.push_back(WR->getFileName()); 22172fb6a87SEric Beckmann bool End = false; 22272fb6a87SEric Beckmann while (!End) { 22313017597SEric Beckmann 224ccf09646SNico Weber TreeNode *Node; 225*d8d63ff2SMartin Storsjo bool IsNewNode = Root.addEntry(Entry, Origin, Data, StringTable, Node); 22681862f82SNico Weber if (!IsNewNode) { 22781862f82SNico Weber Duplicates.push_back(makeDuplicateResourceError( 22881862f82SNico Weber Entry, InputFilenames[Node->Origin], WR->getFileName())); 22981862f82SNico Weber } 23013017597SEric Beckmann 23172fb6a87SEric Beckmann RETURN_IF_ERROR(Entry.moveNext(End)); 23272fb6a87SEric Beckmann } 23372fb6a87SEric Beckmann 23472fb6a87SEric Beckmann return Error::success(); 23572fb6a87SEric Beckmann } 23672fb6a87SEric Beckmann 237907fb813SEric Beckmann void WindowsResourceParser::printTree(raw_ostream &OS) const { 238907fb813SEric Beckmann ScopedPrinter Writer(OS); 23972fb6a87SEric Beckmann Root.print(Writer, "Resource Tree"); 24072fb6a87SEric Beckmann } 24172fb6a87SEric Beckmann 242*d8d63ff2SMartin Storsjo bool WindowsResourceParser::TreeNode::addEntry( 243*d8d63ff2SMartin Storsjo const ResourceEntryRef &Entry, uint32_t Origin, 244*d8d63ff2SMartin Storsjo std::vector<std::vector<uint8_t>> &Data, 245*d8d63ff2SMartin Storsjo std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result) { 246*d8d63ff2SMartin Storsjo TreeNode &TypeNode = addTypeNode(Entry, StringTable); 247*d8d63ff2SMartin Storsjo TreeNode &NameNode = TypeNode.addNameNode(Entry, StringTable); 248*d8d63ff2SMartin Storsjo return NameNode.addLanguageNode(Entry, Origin, Data, Result); 24972fb6a87SEric Beckmann } 25072fb6a87SEric Beckmann 251*d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode::TreeNode(uint32_t StringIndex) 252*d8d63ff2SMartin Storsjo : StringIndex(StringIndex) {} 253d9de6389SEric Beckmann 254d9de6389SEric Beckmann WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion, 255d9de6389SEric Beckmann uint16_t MinorVersion, 256ccf09646SNico Weber uint32_t Characteristics, 257*d8d63ff2SMartin Storsjo uint32_t Origin, uint32_t DataIndex) 258*d8d63ff2SMartin Storsjo : IsDataNode(true), DataIndex(DataIndex), MajorVersion(MajorVersion), 259*d8d63ff2SMartin Storsjo MinorVersion(MinorVersion), Characteristics(Characteristics), 260*d8d63ff2SMartin Storsjo Origin(Origin) {} 261d9de6389SEric Beckmann 262d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode> 263*d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode::createStringNode(uint32_t Index) { 264*d8d63ff2SMartin Storsjo return std::unique_ptr<TreeNode>(new TreeNode(Index)); 265d9de6389SEric Beckmann } 266d9de6389SEric Beckmann 267d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode> 268d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createIDNode() { 269*d8d63ff2SMartin Storsjo return std::unique_ptr<TreeNode>(new TreeNode(0)); 270d9de6389SEric Beckmann } 271d9de6389SEric Beckmann 272d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode> 273d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion, 274d9de6389SEric Beckmann uint16_t MinorVersion, 275ccf09646SNico Weber uint32_t Characteristics, 276*d8d63ff2SMartin Storsjo uint32_t Origin, 277*d8d63ff2SMartin Storsjo uint32_t DataIndex) { 278*d8d63ff2SMartin Storsjo return std::unique_ptr<TreeNode>(new TreeNode( 279*d8d63ff2SMartin Storsjo MajorVersion, MinorVersion, Characteristics, Origin, DataIndex)); 280d9de6389SEric Beckmann } 28172fb6a87SEric Beckmann 282*d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addTypeNode( 283*d8d63ff2SMartin Storsjo const ResourceEntryRef &Entry, 284*d8d63ff2SMartin Storsjo std::vector<std::vector<UTF16>> &StringTable) { 28572fb6a87SEric Beckmann if (Entry.checkTypeString()) 286*d8d63ff2SMartin Storsjo return addNameChild(Entry.getTypeString(), StringTable); 28772fb6a87SEric Beckmann else 2886967da8fSNico Weber return addIDChild(Entry.getTypeID()); 28972fb6a87SEric Beckmann } 29072fb6a87SEric Beckmann 291*d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameNode( 292*d8d63ff2SMartin Storsjo const ResourceEntryRef &Entry, 293*d8d63ff2SMartin Storsjo std::vector<std::vector<UTF16>> &StringTable) { 29472fb6a87SEric Beckmann if (Entry.checkNameString()) 295*d8d63ff2SMartin Storsjo return addNameChild(Entry.getNameString(), StringTable); 29672fb6a87SEric Beckmann else 2976967da8fSNico Weber return addIDChild(Entry.getNameID()); 29872fb6a87SEric Beckmann } 29972fb6a87SEric Beckmann 300ccf09646SNico Weber bool WindowsResourceParser::TreeNode::addLanguageNode( 301*d8d63ff2SMartin Storsjo const ResourceEntryRef &Entry, uint32_t Origin, 302*d8d63ff2SMartin Storsjo std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result) { 303*d8d63ff2SMartin Storsjo bool Added = addDataChild(Entry.getLanguage(), Entry.getMajorVersion(), 304ccf09646SNico Weber Entry.getMinorVersion(), Entry.getCharacteristics(), 305*d8d63ff2SMartin Storsjo Origin, Data.size(), Result); 306*d8d63ff2SMartin Storsjo if (Added) 307*d8d63ff2SMartin Storsjo Data.push_back(Entry.getData()); 308*d8d63ff2SMartin Storsjo return Added; 30972fb6a87SEric Beckmann } 31072fb6a87SEric Beckmann 311ccf09646SNico Weber bool WindowsResourceParser::TreeNode::addDataChild( 3126967da8fSNico Weber uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion, 313*d8d63ff2SMartin Storsjo uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex, 314*d8d63ff2SMartin Storsjo TreeNode *&Result) { 315*d8d63ff2SMartin Storsjo auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics, 316*d8d63ff2SMartin Storsjo Origin, DataIndex); 317ccf09646SNico Weber auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild)); 318ccf09646SNico Weber Result = ElementInserted.first->second.get(); 319ccf09646SNico Weber return ElementInserted.second; 3206967da8fSNico Weber } 3216967da8fSNico Weber 3226967da8fSNico Weber WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild( 3236967da8fSNico Weber uint32_t ID) { 3246967da8fSNico Weber auto Child = IDChildren.find(ID); 3256967da8fSNico Weber if (Child == IDChildren.end()) { 3266967da8fSNico Weber auto NewChild = createIDNode(); 32772fb6a87SEric Beckmann WindowsResourceParser::TreeNode &Node = *NewChild; 32872fb6a87SEric Beckmann IDChildren.emplace(ID, std::move(NewChild)); 32972fb6a87SEric Beckmann return Node; 33072fb6a87SEric Beckmann } else 33172fb6a87SEric Beckmann return *(Child->second); 33272fb6a87SEric Beckmann } 33372fb6a87SEric Beckmann 334*d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameChild( 335*d8d63ff2SMartin Storsjo ArrayRef<UTF16> NameRef, std::vector<std::vector<UTF16>> &StringTable) { 33672fb6a87SEric Beckmann std::string NameString; 337cf6267ceSNico Weber convertUTF16LEToUTF8String(NameRef, NameString); 33872fb6a87SEric Beckmann 33972fb6a87SEric Beckmann auto Child = StringChildren.find(NameString); 34072fb6a87SEric Beckmann if (Child == StringChildren.end()) { 341*d8d63ff2SMartin Storsjo auto NewChild = createStringNode(StringTable.size()); 342*d8d63ff2SMartin Storsjo StringTable.push_back(NameRef); 34372fb6a87SEric Beckmann WindowsResourceParser::TreeNode &Node = *NewChild; 34472fb6a87SEric Beckmann StringChildren.emplace(NameString, std::move(NewChild)); 34572fb6a87SEric Beckmann return Node; 34672fb6a87SEric Beckmann } else 34772fb6a87SEric Beckmann return *(Child->second); 34872fb6a87SEric Beckmann } 34972fb6a87SEric Beckmann 35072fb6a87SEric Beckmann void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer, 35172fb6a87SEric Beckmann StringRef Name) const { 35272fb6a87SEric Beckmann ListScope NodeScope(Writer, Name); 35372fb6a87SEric Beckmann for (auto const &Child : StringChildren) { 35472fb6a87SEric Beckmann Child.second->print(Writer, Child.first); 35572fb6a87SEric Beckmann } 35672fb6a87SEric Beckmann for (auto const &Child : IDChildren) { 357ba395ef4SEric Beckmann Child.second->print(Writer, to_string(Child.first)); 35872fb6a87SEric Beckmann } 35972fb6a87SEric Beckmann } 36072fb6a87SEric Beckmann 361d9de6389SEric Beckmann // This function returns the size of the entire resource tree, including 362d9de6389SEric Beckmann // directory tables, directory entries, and data entries. It does not include 363d9de6389SEric Beckmann // the directory strings or the relocations of the .rsrc section. 364d9de6389SEric Beckmann uint32_t WindowsResourceParser::TreeNode::getTreeSize() const { 365d9de6389SEric Beckmann uint32_t Size = (IDChildren.size() + StringChildren.size()) * 3667687f046SEric Beckmann sizeof(coff_resource_dir_entry); 367d9de6389SEric Beckmann 368d9de6389SEric Beckmann // Reached a node pointing to a data entry. 369d9de6389SEric Beckmann if (IsDataNode) { 3707687f046SEric Beckmann Size += sizeof(coff_resource_data_entry); 371d9de6389SEric Beckmann return Size; 372d9de6389SEric Beckmann } 373d9de6389SEric Beckmann 374d9de6389SEric Beckmann // If the node does not point to data, it must have a directory table pointing 375d9de6389SEric Beckmann // to other nodes. 3767687f046SEric Beckmann Size += sizeof(coff_resource_dir_table); 377d9de6389SEric Beckmann 378d9de6389SEric Beckmann for (auto const &Child : StringChildren) { 379d9de6389SEric Beckmann Size += Child.second->getTreeSize(); 380d9de6389SEric Beckmann } 381d9de6389SEric Beckmann for (auto const &Child : IDChildren) { 382d9de6389SEric Beckmann Size += Child.second->getTreeSize(); 383d9de6389SEric Beckmann } 384d9de6389SEric Beckmann return Size; 385d9de6389SEric Beckmann } 386d9de6389SEric Beckmann 387d9de6389SEric Beckmann class WindowsResourceCOFFWriter { 388d9de6389SEric Beckmann public: 389ddcfbf7dSEric Beckmann WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, 390d9de6389SEric Beckmann const WindowsResourceParser &Parser, Error &E); 391dd601952SNico Weber std::unique_ptr<MemoryBuffer> write(uint32_t TimeDateStamp); 392d9de6389SEric Beckmann 393d9de6389SEric Beckmann private: 394d9de6389SEric Beckmann void performFileLayout(); 395d9de6389SEric Beckmann void performSectionOneLayout(); 396d9de6389SEric Beckmann void performSectionTwoLayout(); 397dd601952SNico Weber void writeCOFFHeader(uint32_t TimeDateStamp); 398d9de6389SEric Beckmann void writeFirstSectionHeader(); 399d9de6389SEric Beckmann void writeSecondSectionHeader(); 400d9de6389SEric Beckmann void writeFirstSection(); 401d9de6389SEric Beckmann void writeSecondSection(); 402d9de6389SEric Beckmann void writeSymbolTable(); 403d9de6389SEric Beckmann void writeStringTable(); 404d9de6389SEric Beckmann void writeDirectoryTree(); 405d9de6389SEric Beckmann void writeDirectoryStringTable(); 406d9de6389SEric Beckmann void writeFirstSectionRelocations(); 4079aaf5d3eSPavel Labath std::unique_ptr<WritableMemoryBuffer> OutputBuffer; 408d135e8c0SEric Beckmann char *BufferStart; 409382eaabbSEric Beckmann uint64_t CurrentOffset = 0; 4100eafa581SEric Beckmann COFF::MachineTypes MachineType; 411d9de6389SEric Beckmann const WindowsResourceParser::TreeNode &Resources; 412d9de6389SEric Beckmann const ArrayRef<std::vector<uint8_t>> Data; 413d9de6389SEric Beckmann uint64_t FileSize; 414d9de6389SEric Beckmann uint32_t SymbolTableOffset; 415d9de6389SEric Beckmann uint32_t SectionOneSize; 416d9de6389SEric Beckmann uint32_t SectionOneOffset; 417d9de6389SEric Beckmann uint32_t SectionOneRelocations; 418d9de6389SEric Beckmann uint32_t SectionTwoSize; 419d9de6389SEric Beckmann uint32_t SectionTwoOffset; 420d9de6389SEric Beckmann const ArrayRef<std::vector<UTF16>> StringTable; 421d9de6389SEric Beckmann std::vector<uint32_t> StringTableOffsets; 422d9de6389SEric Beckmann std::vector<uint32_t> DataOffsets; 423d9de6389SEric Beckmann std::vector<uint32_t> RelocationAddresses; 424d9de6389SEric Beckmann }; 425d9de6389SEric Beckmann 426d9de6389SEric Beckmann WindowsResourceCOFFWriter::WindowsResourceCOFFWriter( 427ddcfbf7dSEric Beckmann COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, 428ddcfbf7dSEric Beckmann Error &E) 429ddcfbf7dSEric Beckmann : MachineType(MachineType), Resources(Parser.getTree()), 430ddcfbf7dSEric Beckmann Data(Parser.getData()), StringTable(Parser.getStringTable()) { 431d9de6389SEric Beckmann performFileLayout(); 432c8dba240SEric Beckmann 433af6bc65dSNico Weber OutputBuffer = WritableMemoryBuffer::getNewMemBuffer( 434af6bc65dSNico Weber FileSize, "internal .obj file created from .res files"); 435d9de6389SEric Beckmann } 436d9de6389SEric Beckmann 437d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performFileLayout() { 438d9de6389SEric Beckmann // Add size of COFF header. 4397687f046SEric Beckmann FileSize = COFF::Header16Size; 440d9de6389SEric Beckmann 441d9de6389SEric Beckmann // one .rsrc section header for directory tree, another for resource data. 4427687f046SEric Beckmann FileSize += 2 * COFF::SectionSize; 443d9de6389SEric Beckmann 444d9de6389SEric Beckmann performSectionOneLayout(); 445d9de6389SEric Beckmann performSectionTwoLayout(); 446d9de6389SEric Beckmann 447d9de6389SEric Beckmann // We have reached the address of the symbol table. 448d9de6389SEric Beckmann SymbolTableOffset = FileSize; 449d9de6389SEric Beckmann 4507687f046SEric Beckmann FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol. 4517687f046SEric Beckmann FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section. 4527687f046SEric Beckmann FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource. 453d9de6389SEric Beckmann FileSize += 4; // four null bytes for the string table. 454d9de6389SEric Beckmann } 455d9de6389SEric Beckmann 456d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performSectionOneLayout() { 457d9de6389SEric Beckmann SectionOneOffset = FileSize; 458d9de6389SEric Beckmann 459d9de6389SEric Beckmann SectionOneSize = Resources.getTreeSize(); 460d9de6389SEric Beckmann uint32_t CurrentStringOffset = SectionOneSize; 461d9de6389SEric Beckmann uint32_t TotalStringTableSize = 0; 462d9de6389SEric Beckmann for (auto const &String : StringTable) { 463d9de6389SEric Beckmann StringTableOffsets.push_back(CurrentStringOffset); 464d9de6389SEric Beckmann uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t); 465d9de6389SEric Beckmann CurrentStringOffset += StringSize; 466d9de6389SEric Beckmann TotalStringTableSize += StringSize; 467d9de6389SEric Beckmann } 468d9de6389SEric Beckmann SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t)); 469d9de6389SEric Beckmann 470d9de6389SEric Beckmann // account for the relocations of section one. 471d9de6389SEric Beckmann SectionOneRelocations = FileSize + SectionOneSize; 472d9de6389SEric Beckmann FileSize += SectionOneSize; 4737687f046SEric Beckmann FileSize += 4747687f046SEric Beckmann Data.size() * COFF::RelocationSize; // one relocation for each resource. 475382eaabbSEric Beckmann FileSize = alignTo(FileSize, SECTION_ALIGNMENT); 476d9de6389SEric Beckmann } 477d9de6389SEric Beckmann 478d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performSectionTwoLayout() { 479d9de6389SEric Beckmann // add size of .rsrc$2 section, which contains all resource data on 8-byte 480d9de6389SEric Beckmann // alignment. 481d9de6389SEric Beckmann SectionTwoOffset = FileSize; 482d9de6389SEric Beckmann SectionTwoSize = 0; 483d9de6389SEric Beckmann for (auto const &Entry : Data) { 484d9de6389SEric Beckmann DataOffsets.push_back(SectionTwoSize); 4857687f046SEric Beckmann SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t)); 486d9de6389SEric Beckmann } 487d9de6389SEric Beckmann FileSize += SectionTwoSize; 488382eaabbSEric Beckmann FileSize = alignTo(FileSize, SECTION_ALIGNMENT); 489d9de6389SEric Beckmann } 490d9de6389SEric Beckmann 491dd601952SNico Weber std::unique_ptr<MemoryBuffer> 492dd601952SNico Weber WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) { 4939aaf5d3eSPavel Labath BufferStart = OutputBuffer->getBufferStart(); 494d9de6389SEric Beckmann 495dd601952SNico Weber writeCOFFHeader(TimeDateStamp); 496d9de6389SEric Beckmann writeFirstSectionHeader(); 497d9de6389SEric Beckmann writeSecondSectionHeader(); 498d9de6389SEric Beckmann writeFirstSection(); 499d9de6389SEric Beckmann writeSecondSection(); 500d9de6389SEric Beckmann writeSymbolTable(); 501d9de6389SEric Beckmann writeStringTable(); 502d9de6389SEric Beckmann 503ddcfbf7dSEric Beckmann return std::move(OutputBuffer); 504d9de6389SEric Beckmann } 505d9de6389SEric Beckmann 506d1262a6eSSerge Guelton // According to COFF specification, if the Src has a size equal to Dest, 507d1262a6eSSerge Guelton // it's okay to *not* copy the trailing zero. 508d1262a6eSSerge Guelton static void coffnamecpy(char (&Dest)[COFF::NameSize], StringRef Src) { 509d1262a6eSSerge Guelton assert(Src.size() <= COFF::NameSize && 510d1262a6eSSerge Guelton "Src is not larger than COFF::NameSize"); 511d1262a6eSSerge Guelton strncpy(Dest, Src.data(), (size_t)COFF::NameSize); 512d1262a6eSSerge Guelton } 513d1262a6eSSerge Guelton 514dd601952SNico Weber void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) { 515d9de6389SEric Beckmann // Write the COFF header. 5167687f046SEric Beckmann auto *Header = reinterpret_cast<coff_file_header *>(BufferStart); 517ba664c1dSMartin Storsjo Header->Machine = MachineType; 518d9de6389SEric Beckmann Header->NumberOfSections = 2; 519dd601952SNico Weber Header->TimeDateStamp = TimeDateStamp; 520d9de6389SEric Beckmann Header->PointerToSymbolTable = SymbolTableOffset; 521af6bc65dSNico Weber // One symbol for every resource plus 2 for each section and 1 for @feat.00 522d9de6389SEric Beckmann Header->NumberOfSymbols = Data.size() + 5; 523d9de6389SEric Beckmann Header->SizeOfOptionalHeader = 0; 524dd601952SNico Weber // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it. 5257687f046SEric Beckmann Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE; 526d9de6389SEric Beckmann } 527d9de6389SEric Beckmann 528d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSectionHeader() { 529d9de6389SEric Beckmann // Write the first section header. 5307687f046SEric Beckmann CurrentOffset += sizeof(coff_file_header); 5317687f046SEric Beckmann auto *SectionOneHeader = 5327687f046SEric Beckmann reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); 533d1262a6eSSerge Guelton coffnamecpy(SectionOneHeader->Name, ".rsrc$01"); 534d9de6389SEric Beckmann SectionOneHeader->VirtualSize = 0; 535d9de6389SEric Beckmann SectionOneHeader->VirtualAddress = 0; 536d9de6389SEric Beckmann SectionOneHeader->SizeOfRawData = SectionOneSize; 537d9de6389SEric Beckmann SectionOneHeader->PointerToRawData = SectionOneOffset; 538d9de6389SEric Beckmann SectionOneHeader->PointerToRelocations = SectionOneRelocations; 539d9de6389SEric Beckmann SectionOneHeader->PointerToLinenumbers = 0; 540d9de6389SEric Beckmann SectionOneHeader->NumberOfRelocations = Data.size(); 541d9de6389SEric Beckmann SectionOneHeader->NumberOfLinenumbers = 0; 5427687f046SEric Beckmann SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 5437687f046SEric Beckmann SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; 544d9de6389SEric Beckmann } 545d9de6389SEric Beckmann 546d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSecondSectionHeader() { 547d9de6389SEric Beckmann // Write the second section header. 5487687f046SEric Beckmann CurrentOffset += sizeof(coff_section); 5497687f046SEric Beckmann auto *SectionTwoHeader = 5507687f046SEric Beckmann reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); 551d1262a6eSSerge Guelton coffnamecpy(SectionTwoHeader->Name, ".rsrc$02"); 552d9de6389SEric Beckmann SectionTwoHeader->VirtualSize = 0; 553d9de6389SEric Beckmann SectionTwoHeader->VirtualAddress = 0; 554d9de6389SEric Beckmann SectionTwoHeader->SizeOfRawData = SectionTwoSize; 555d9de6389SEric Beckmann SectionTwoHeader->PointerToRawData = SectionTwoOffset; 556d9de6389SEric Beckmann SectionTwoHeader->PointerToRelocations = 0; 557d9de6389SEric Beckmann SectionTwoHeader->PointerToLinenumbers = 0; 558d9de6389SEric Beckmann SectionTwoHeader->NumberOfRelocations = 0; 559d9de6389SEric Beckmann SectionTwoHeader->NumberOfLinenumbers = 0; 5607687f046SEric Beckmann SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 5617687f046SEric Beckmann SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; 562d9de6389SEric Beckmann } 563d9de6389SEric Beckmann 564d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSection() { 565d9de6389SEric Beckmann // Write section one. 5667687f046SEric Beckmann CurrentOffset += sizeof(coff_section); 567d9de6389SEric Beckmann 568d9de6389SEric Beckmann writeDirectoryTree(); 569d9de6389SEric Beckmann writeDirectoryStringTable(); 570d9de6389SEric Beckmann writeFirstSectionRelocations(); 571382eaabbSEric Beckmann 572382eaabbSEric Beckmann CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); 573d9de6389SEric Beckmann } 574d9de6389SEric Beckmann 575d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSecondSection() { 576d9de6389SEric Beckmann // Now write the .rsrc$02 section. 577d9de6389SEric Beckmann for (auto const &RawDataEntry : Data) { 57875709329SFangrui Song llvm::copy(RawDataEntry, BufferStart + CurrentOffset); 579382eaabbSEric Beckmann CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t)); 580d9de6389SEric Beckmann } 581382eaabbSEric Beckmann 582382eaabbSEric Beckmann CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT); 583d9de6389SEric Beckmann } 584d9de6389SEric Beckmann 585d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSymbolTable() { 586d9de6389SEric Beckmann // Now write the symbol table. 587d9de6389SEric Beckmann // First, the feat symbol. 5887687f046SEric Beckmann auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 589d1262a6eSSerge Guelton coffnamecpy(Symbol->Name.ShortName, "@feat.00"); 590d9de6389SEric Beckmann Symbol->Value = 0x11; 591d9de6389SEric Beckmann Symbol->SectionNumber = 0xffff; 5927687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 5937687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 594d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 0; 5957687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 596d9de6389SEric Beckmann 597d9de6389SEric Beckmann // Now write the .rsrc1 symbol + aux. 5987687f046SEric Beckmann Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 599d1262a6eSSerge Guelton coffnamecpy(Symbol->Name.ShortName, ".rsrc$01"); 600d9de6389SEric Beckmann Symbol->Value = 0; 601d9de6389SEric Beckmann Symbol->SectionNumber = 1; 6027687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 6037687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 604d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 1; 6057687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 6067687f046SEric Beckmann auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart + 6077687f046SEric Beckmann CurrentOffset); 608d9de6389SEric Beckmann Aux->Length = SectionOneSize; 609d9de6389SEric Beckmann Aux->NumberOfRelocations = Data.size(); 610d9de6389SEric Beckmann Aux->NumberOfLinenumbers = 0; 611d9de6389SEric Beckmann Aux->CheckSum = 0; 612d9de6389SEric Beckmann Aux->NumberLowPart = 0; 613d9de6389SEric Beckmann Aux->Selection = 0; 6147687f046SEric Beckmann CurrentOffset += sizeof(coff_aux_section_definition); 615d9de6389SEric Beckmann 616d9de6389SEric Beckmann // Now write the .rsrc2 symbol + aux. 6177687f046SEric Beckmann Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 618d1262a6eSSerge Guelton coffnamecpy(Symbol->Name.ShortName, ".rsrc$02"); 619d9de6389SEric Beckmann Symbol->Value = 0; 620d9de6389SEric Beckmann Symbol->SectionNumber = 2; 6217687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 6227687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 623d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 1; 6247687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 6257687f046SEric Beckmann Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart + 6267687f046SEric Beckmann CurrentOffset); 627d9de6389SEric Beckmann Aux->Length = SectionTwoSize; 628d9de6389SEric Beckmann Aux->NumberOfRelocations = 0; 629d9de6389SEric Beckmann Aux->NumberOfLinenumbers = 0; 630d9de6389SEric Beckmann Aux->CheckSum = 0; 631d9de6389SEric Beckmann Aux->NumberLowPart = 0; 632d9de6389SEric Beckmann Aux->Selection = 0; 6337687f046SEric Beckmann CurrentOffset += sizeof(coff_aux_section_definition); 634d9de6389SEric Beckmann 635d9de6389SEric Beckmann // Now write a symbol for each relocation. 636d9de6389SEric Beckmann for (unsigned i = 0; i < Data.size(); i++) { 637ea5ff9faSBob Haarman auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>(); 6387687f046SEric Beckmann Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); 639d1262a6eSSerge Guelton coffnamecpy(Symbol->Name.ShortName, RelocationName); 640d9de6389SEric Beckmann Symbol->Value = DataOffsets[i]; 641e44afc4aSEric Beckmann Symbol->SectionNumber = 2; 6427687f046SEric Beckmann Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; 6437687f046SEric Beckmann Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; 644d9de6389SEric Beckmann Symbol->NumberOfAuxSymbols = 0; 6457687f046SEric Beckmann CurrentOffset += sizeof(coff_symbol16); 646d9de6389SEric Beckmann } 647d9de6389SEric Beckmann } 648d9de6389SEric Beckmann 649d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeStringTable() { 650d9de6389SEric Beckmann // Just 4 null bytes for the string table. 65133866334SEric Beckmann auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset); 65233866334SEric Beckmann memset(COFFStringTable, 0, 4); 653d9de6389SEric Beckmann } 654d9de6389SEric Beckmann 655d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeDirectoryTree() { 656d9de6389SEric Beckmann // Traverse parsed resource tree breadth-first and write the corresponding 657d9de6389SEric Beckmann // COFF objects. 658d9de6389SEric Beckmann std::queue<const WindowsResourceParser::TreeNode *> Queue; 659d9de6389SEric Beckmann Queue.push(&Resources); 6607687f046SEric Beckmann uint32_t NextLevelOffset = 6617687f046SEric Beckmann sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() + 662d9de6389SEric Beckmann Resources.getIDChildren().size()) * 6637687f046SEric Beckmann sizeof(coff_resource_dir_entry); 664d9de6389SEric Beckmann std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder; 665d9de6389SEric Beckmann uint32_t CurrentRelativeOffset = 0; 666d9de6389SEric Beckmann 667d9de6389SEric Beckmann while (!Queue.empty()) { 668d9de6389SEric Beckmann auto CurrentNode = Queue.front(); 669d9de6389SEric Beckmann Queue.pop(); 6707687f046SEric Beckmann auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart + 6717687f046SEric Beckmann CurrentOffset); 672d9de6389SEric Beckmann Table->Characteristics = CurrentNode->getCharacteristics(); 673d9de6389SEric Beckmann Table->TimeDateStamp = 0; 674d9de6389SEric Beckmann Table->MajorVersion = CurrentNode->getMajorVersion(); 675d9de6389SEric Beckmann Table->MinorVersion = CurrentNode->getMinorVersion(); 676d9de6389SEric Beckmann auto &IDChildren = CurrentNode->getIDChildren(); 677d9de6389SEric Beckmann auto &StringChildren = CurrentNode->getStringChildren(); 678d9de6389SEric Beckmann Table->NumberOfNameEntries = StringChildren.size(); 679d9de6389SEric Beckmann Table->NumberOfIDEntries = IDChildren.size(); 6807687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_dir_table); 6817687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_dir_table); 682d9de6389SEric Beckmann 683d9de6389SEric Beckmann // Write the directory entries immediately following each directory table. 684d9de6389SEric Beckmann for (auto const &Child : StringChildren) { 6857687f046SEric Beckmann auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart + 6867687f046SEric Beckmann CurrentOffset); 6877c865f00SEric Beckmann Entry->Identifier.setNameOffset( 6887c865f00SEric Beckmann StringTableOffsets[Child.second->getStringIndex()]); 689d9de6389SEric Beckmann if (Child.second->checkIsDataNode()) { 690d9de6389SEric Beckmann Entry->Offset.DataEntryOffset = NextLevelOffset; 6917687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_data_entry); 692d9de6389SEric Beckmann DataEntriesTreeOrder.push_back(Child.second.get()); 693d9de6389SEric Beckmann } else { 694d9de6389SEric Beckmann Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); 6957687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_dir_table) + 696d9de6389SEric Beckmann (Child.second->getStringChildren().size() + 697d9de6389SEric Beckmann Child.second->getIDChildren().size()) * 6987687f046SEric Beckmann sizeof(coff_resource_dir_entry); 699d9de6389SEric Beckmann Queue.push(Child.second.get()); 700d9de6389SEric Beckmann } 7017687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_dir_entry); 7027687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_dir_entry); 703d9de6389SEric Beckmann } 704d9de6389SEric Beckmann for (auto const &Child : IDChildren) { 7057687f046SEric Beckmann auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart + 7067687f046SEric Beckmann CurrentOffset); 707d9de6389SEric Beckmann Entry->Identifier.ID = Child.first; 708d9de6389SEric Beckmann if (Child.second->checkIsDataNode()) { 709d9de6389SEric Beckmann Entry->Offset.DataEntryOffset = NextLevelOffset; 7107687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_data_entry); 711d9de6389SEric Beckmann DataEntriesTreeOrder.push_back(Child.second.get()); 712d9de6389SEric Beckmann } else { 713d9de6389SEric Beckmann Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); 7147687f046SEric Beckmann NextLevelOffset += sizeof(coff_resource_dir_table) + 715d9de6389SEric Beckmann (Child.second->getStringChildren().size() + 716d9de6389SEric Beckmann Child.second->getIDChildren().size()) * 7177687f046SEric Beckmann sizeof(coff_resource_dir_entry); 718d9de6389SEric Beckmann Queue.push(Child.second.get()); 719d9de6389SEric Beckmann } 7207687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_dir_entry); 7217687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_dir_entry); 722d9de6389SEric Beckmann } 723d9de6389SEric Beckmann } 724d9de6389SEric Beckmann 725d9de6389SEric Beckmann RelocationAddresses.resize(Data.size()); 726d9de6389SEric Beckmann // Now write all the resource data entries. 727d9de6389SEric Beckmann for (auto DataNodes : DataEntriesTreeOrder) { 7287687f046SEric Beckmann auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart + 7297687f046SEric Beckmann CurrentOffset); 730d9de6389SEric Beckmann RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset; 731d9de6389SEric Beckmann Entry->DataRVA = 0; // Set to zero because it is a relocation. 732d9de6389SEric Beckmann Entry->DataSize = Data[DataNodes->getDataIndex()].size(); 733d9de6389SEric Beckmann Entry->Codepage = 0; 734d9de6389SEric Beckmann Entry->Reserved = 0; 7357687f046SEric Beckmann CurrentOffset += sizeof(coff_resource_data_entry); 7367687f046SEric Beckmann CurrentRelativeOffset += sizeof(coff_resource_data_entry); 737d9de6389SEric Beckmann } 738d9de6389SEric Beckmann } 739d9de6389SEric Beckmann 740d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeDirectoryStringTable() { 741d9de6389SEric Beckmann // Now write the directory string table for .rsrc$01 742d9de6389SEric Beckmann uint32_t TotalStringTableSize = 0; 7430096d78bSEric Beckmann for (auto &String : StringTable) { 744d9de6389SEric Beckmann uint16_t Length = String.size(); 7451f76ca5aSEric Beckmann support::endian::write16le(BufferStart + CurrentOffset, Length); 746382eaabbSEric Beckmann CurrentOffset += sizeof(uint16_t); 747382eaabbSEric Beckmann auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset); 74875709329SFangrui Song llvm::copy(String, Start); 749382eaabbSEric Beckmann CurrentOffset += Length * sizeof(UTF16); 750d9de6389SEric Beckmann TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t); 751d9de6389SEric Beckmann } 752382eaabbSEric Beckmann CurrentOffset += 753d9de6389SEric Beckmann alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize; 754d9de6389SEric Beckmann } 755d9de6389SEric Beckmann 756d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { 757d9de6389SEric Beckmann 758d9de6389SEric Beckmann // Now write the relocations for .rsrc$01 759d9de6389SEric Beckmann // Five symbols already in table before we start, @feat.00 and 2 for each 760d9de6389SEric Beckmann // .rsrc section. 761d9de6389SEric Beckmann uint32_t NextSymbolIndex = 5; 762d9de6389SEric Beckmann for (unsigned i = 0; i < Data.size(); i++) { 7637687f046SEric Beckmann auto *Reloc = 7647687f046SEric Beckmann reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset); 765d9de6389SEric Beckmann Reloc->VirtualAddress = RelocationAddresses[i]; 766d9de6389SEric Beckmann Reloc->SymbolTableIndex = NextSymbolIndex++; 767d9de6389SEric Beckmann switch (MachineType) { 768d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_ARMNT: 7697687f046SEric Beckmann Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB; 770d9de6389SEric Beckmann break; 771d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_AMD64: 7727687f046SEric Beckmann Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB; 773d9de6389SEric Beckmann break; 774d135e8c0SEric Beckmann case COFF::IMAGE_FILE_MACHINE_I386: 7757687f046SEric Beckmann Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB; 776d9de6389SEric Beckmann break; 777ba664c1dSMartin Storsjo case COFF::IMAGE_FILE_MACHINE_ARM64: 778ba664c1dSMartin Storsjo Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB; 779ba664c1dSMartin Storsjo break; 780d9de6389SEric Beckmann default: 781ba664c1dSMartin Storsjo llvm_unreachable("unknown machine type"); 782d9de6389SEric Beckmann } 7837687f046SEric Beckmann CurrentOffset += sizeof(coff_relocation); 784d9de6389SEric Beckmann } 785d9de6389SEric Beckmann } 786d9de6389SEric Beckmann 787ddcfbf7dSEric Beckmann Expected<std::unique_ptr<MemoryBuffer>> 788ddcfbf7dSEric Beckmann writeWindowsResourceCOFF(COFF::MachineTypes MachineType, 789dd601952SNico Weber const WindowsResourceParser &Parser, 790dd601952SNico Weber uint32_t TimeDateStamp) { 791d9de6389SEric Beckmann Error E = Error::success(); 792ddcfbf7dSEric Beckmann WindowsResourceCOFFWriter Writer(MachineType, Parser, E); 793d9de6389SEric Beckmann if (E) 794ddcfbf7dSEric Beckmann return std::move(E); 795dd601952SNico Weber return Writer.write(TimeDateStamp); 796d9de6389SEric Beckmann } 797d9de6389SEric Beckmann 798a6bdf751SEric Beckmann } // namespace object 799a6bdf751SEric Beckmann } // namespace llvm 800