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