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"
15ea5ff9faSBob Haarman #include "llvm/Support/FormatVariadic.h"
16d9de6389SEric Beckmann #include "llvm/Support/MathExtras.h"
1723cb79ffSNico Weber #include "llvm/Support/ScopedPrinter.h"
18d9de6389SEric Beckmann #include <ctime>
19d9de6389SEric Beckmann #include <queue>
20a6bdf751SEric Beckmann 
21d135e8c0SEric Beckmann using namespace llvm;
227687f046SEric Beckmann using namespace object;
23d135e8c0SEric Beckmann 
24a6bdf751SEric Beckmann namespace llvm {
25a6bdf751SEric Beckmann namespace object {
26a6bdf751SEric Beckmann 
2772fb6a87SEric Beckmann #define RETURN_IF_ERROR(X)                                                     \
2872fb6a87SEric Beckmann   if (auto EC = X)                                                             \
2914ea122eSBenjamin Kramer     return EC;
3072fb6a87SEric Beckmann 
313d3a9b3bSMartin Storsjo #define UNWRAP_REF_OR_RETURN(Name, Expr)                                       \
323d3a9b3bSMartin Storsjo   auto Name##OrErr = Expr;                                                     \
333d3a9b3bSMartin Storsjo   if (!Name##OrErr)                                                            \
343d3a9b3bSMartin Storsjo     return Name##OrErr.takeError();                                            \
353d3a9b3bSMartin Storsjo   const auto &Name = *Name##OrErr;
363d3a9b3bSMartin Storsjo 
373d3a9b3bSMartin Storsjo #define UNWRAP_OR_RETURN(Name, Expr)                                           \
383d3a9b3bSMartin Storsjo   auto Name##OrErr = Expr;                                                     \
393d3a9b3bSMartin Storsjo   if (!Name##OrErr)                                                            \
403d3a9b3bSMartin Storsjo     return Name##OrErr.takeError();                                            \
413d3a9b3bSMartin Storsjo   auto Name = *Name##OrErr;
423d3a9b3bSMartin Storsjo 
4372fb6a87SEric Beckmann const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
4472fb6a87SEric Beckmann 
45382eaabbSEric Beckmann // COFF files seem to be inconsistent with alignment between sections, just use
46382eaabbSEric Beckmann // 8-byte because it makes everyone happy.
47382eaabbSEric Beckmann const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
48382eaabbSEric Beckmann 
WindowsResource(MemoryBufferRef Source)49a6bdf751SEric Beckmann WindowsResource::WindowsResource(MemoryBufferRef Source)
50a6bdf751SEric Beckmann     : Binary(Binary::ID_WinRes, Source) {
51c8dba240SEric Beckmann   size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
52a6bdf751SEric Beckmann   BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
53a6bdf751SEric Beckmann                          support::little);
54a6bdf751SEric Beckmann }
55a6bdf751SEric Beckmann 
56413517ecSNico Weber // static
57a6bdf751SEric Beckmann Expected<std::unique_ptr<WindowsResource>>
createWindowsResource(MemoryBufferRef Source)58a6bdf751SEric Beckmann WindowsResource::createWindowsResource(MemoryBufferRef Source) {
59c8dba240SEric Beckmann   if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
60a6bdf751SEric Beckmann     return make_error<GenericBinaryError>(
61413517ecSNico Weber         Source.getBufferIdentifier() + ": too small to be a resource file",
62a6bdf751SEric Beckmann         object_error::invalid_file_type);
63a6bdf751SEric Beckmann   std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
64c55cf4afSBill Wendling   return std::move(Ret);
65a6bdf751SEric Beckmann }
66a6bdf751SEric Beckmann 
getHeadEntry()67a6bdf751SEric Beckmann Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
68b85172f6SEric Beckmann   if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix))
69413517ecSNico Weber     return make_error<EmptyResError>(getFileName() + " contains no entries",
70b85172f6SEric Beckmann                                      object_error::unexpected_eof);
71b85172f6SEric Beckmann   return ResourceEntryRef::create(BinaryStreamRef(BBS), this);
72a6bdf751SEric Beckmann }
73a6bdf751SEric Beckmann 
ResourceEntryRef(BinaryStreamRef Ref,const WindowsResource * Owner)74a6bdf751SEric Beckmann ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
75b85172f6SEric Beckmann                                    const WindowsResource *Owner)
76413517ecSNico Weber     : Reader(Ref), Owner(Owner) {}
77b85172f6SEric Beckmann 
78b85172f6SEric Beckmann Expected<ResourceEntryRef>
create(BinaryStreamRef BSR,const WindowsResource * Owner)79b85172f6SEric Beckmann ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) {
80b85172f6SEric Beckmann   auto Ref = ResourceEntryRef(BSR, Owner);
81b85172f6SEric Beckmann   if (auto E = Ref.loadNext())
82c55cf4afSBill Wendling     return std::move(E);
83b85172f6SEric Beckmann   return Ref;
84a6bdf751SEric Beckmann }
85a6bdf751SEric Beckmann 
moveNext(bool & End)86a6bdf751SEric Beckmann Error ResourceEntryRef::moveNext(bool &End) {
87a6bdf751SEric Beckmann   // Reached end of all the entries.
88a6bdf751SEric Beckmann   if (Reader.bytesRemaining() == 0) {
89a6bdf751SEric Beckmann     End = true;
90a6bdf751SEric Beckmann     return Error::success();
91a6bdf751SEric Beckmann   }
92a6bdf751SEric Beckmann   RETURN_IF_ERROR(loadNext());
93a6bdf751SEric Beckmann 
94a6bdf751SEric Beckmann   return Error::success();
95a6bdf751SEric Beckmann }
96a6bdf751SEric Beckmann 
readStringOrId(BinaryStreamReader & Reader,uint16_t & ID,ArrayRef<UTF16> & Str,bool & IsString)9772fb6a87SEric Beckmann static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
9872fb6a87SEric Beckmann                             ArrayRef<UTF16> &Str, bool &IsString) {
9972fb6a87SEric Beckmann   uint16_t IDFlag;
10072fb6a87SEric Beckmann   RETURN_IF_ERROR(Reader.readInteger(IDFlag));
10172fb6a87SEric Beckmann   IsString = IDFlag != 0xffff;
10272fb6a87SEric Beckmann 
10372fb6a87SEric Beckmann   if (IsString) {
10472fb6a87SEric Beckmann     Reader.setOffset(
10572fb6a87SEric Beckmann         Reader.getOffset() -
10672fb6a87SEric Beckmann         sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
10772fb6a87SEric Beckmann     RETURN_IF_ERROR(Reader.readWideString(Str));
10872fb6a87SEric Beckmann   } else
10972fb6a87SEric Beckmann     RETURN_IF_ERROR(Reader.readInteger(ID));
11072fb6a87SEric Beckmann 
11172fb6a87SEric Beckmann   return Error::success();
11272fb6a87SEric Beckmann }
11372fb6a87SEric Beckmann 
loadNext()114a6bdf751SEric Beckmann Error ResourceEntryRef::loadNext() {
115c8dba240SEric Beckmann   const WinResHeaderPrefix *Prefix;
116c8dba240SEric Beckmann   RETURN_IF_ERROR(Reader.readObject(Prefix));
11772fb6a87SEric Beckmann 
118c8dba240SEric Beckmann   if (Prefix->HeaderSize < MIN_HEADER_SIZE)
119413517ecSNico Weber     return make_error<GenericBinaryError>(Owner->getFileName() +
120413517ecSNico Weber                                               ": header size too small",
12172fb6a87SEric Beckmann                                           object_error::parse_failed);
12272fb6a87SEric Beckmann 
12372fb6a87SEric Beckmann   RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
12472fb6a87SEric Beckmann 
12572fb6a87SEric Beckmann   RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
12672fb6a87SEric Beckmann 
127c8dba240SEric Beckmann   RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
12872fb6a87SEric Beckmann 
12972fb6a87SEric Beckmann   RETURN_IF_ERROR(Reader.readObject(Suffix));
13072fb6a87SEric Beckmann 
131c8dba240SEric Beckmann   RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
13272fb6a87SEric Beckmann 
133c8dba240SEric Beckmann   RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
13472fb6a87SEric Beckmann 
135a6bdf751SEric Beckmann   return Error::success();
136a6bdf751SEric Beckmann }
137a6bdf751SEric Beckmann 
WindowsResourceParser(bool MinGW)138d581dd50SMartin Storsjo WindowsResourceParser::WindowsResourceParser(bool MinGW)
139d581dd50SMartin Storsjo     : Root(false), MinGW(MinGW) {}
14072fb6a87SEric Beckmann 
printResourceTypeName(uint16_t TypeID,raw_ostream & OS)14123cb79ffSNico Weber void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) {
14223cb79ffSNico Weber   switch (TypeID) {
14323cb79ffSNico Weber   case  1: OS << "CURSOR (ID 1)"; break;
14423cb79ffSNico Weber   case  2: OS << "BITMAP (ID 2)"; break;
14523cb79ffSNico Weber   case  3: OS << "ICON (ID 3)"; break;
14623cb79ffSNico Weber   case  4: OS << "MENU (ID 4)"; break;
14723cb79ffSNico Weber   case  5: OS << "DIALOG (ID 5)"; break;
14823cb79ffSNico Weber   case  6: OS << "STRINGTABLE (ID 6)"; break;
14923cb79ffSNico Weber   case  7: OS << "FONTDIR (ID 7)"; break;
15023cb79ffSNico Weber   case  8: OS << "FONT (ID 8)"; break;
15123cb79ffSNico Weber   case  9: OS << "ACCELERATOR (ID 9)"; break;
15223cb79ffSNico Weber   case 10: OS << "RCDATA (ID 10)"; break;
15323cb79ffSNico Weber   case 11: OS << "MESSAGETABLE (ID 11)"; break;
15423cb79ffSNico Weber   case 12: OS << "GROUP_CURSOR (ID 12)"; break;
15523cb79ffSNico Weber   case 14: OS << "GROUP_ICON (ID 14)"; break;
15623cb79ffSNico Weber   case 16: OS << "VERSIONINFO (ID 16)"; break;
15723cb79ffSNico Weber   case 17: OS << "DLGINCLUDE (ID 17)"; break;
15823cb79ffSNico Weber   case 19: OS << "PLUGPLAY (ID 19)"; break;
15923cb79ffSNico Weber   case 20: OS << "VXD (ID 20)"; break;
16023cb79ffSNico Weber   case 21: OS << "ANICURSOR (ID 21)"; break;
16123cb79ffSNico Weber   case 22: OS << "ANIICON (ID 22)"; break;
16223cb79ffSNico Weber   case 23: OS << "HTML (ID 23)"; break;
16323cb79ffSNico Weber   case 24: OS << "MANIFEST (ID 24)"; break;
16423cb79ffSNico Weber   default: OS << "ID " << TypeID; break;
16523cb79ffSNico Weber   }
16623cb79ffSNico Weber }
16723cb79ffSNico Weber 
convertUTF16LEToUTF8String(ArrayRef<UTF16> Src,std::string & Out)168cf6267ceSNico Weber static bool convertUTF16LEToUTF8String(ArrayRef<UTF16> Src, std::string &Out) {
169cf6267ceSNico Weber   if (!sys::IsBigEndianHost)
170cf6267ceSNico Weber     return convertUTF16ToUTF8String(Src, Out);
171cf6267ceSNico Weber 
172cf6267ceSNico Weber   std::vector<UTF16> EndianCorrectedSrc;
173cf6267ceSNico Weber   EndianCorrectedSrc.resize(Src.size() + 1);
174cf6267ceSNico Weber   llvm::copy(Src, EndianCorrectedSrc.begin() + 1);
175cf6267ceSNico Weber   EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
176cf6267ceSNico Weber   return convertUTF16ToUTF8String(makeArrayRef(EndianCorrectedSrc), Out);
177cf6267ceSNico Weber }
178cf6267ceSNico Weber 
makeDuplicateResourceError(const ResourceEntryRef & Entry,StringRef File1,StringRef File2)17981862f82SNico Weber static std::string makeDuplicateResourceError(
18081862f82SNico Weber     const ResourceEntryRef &Entry, StringRef File1, StringRef File2) {
181ccf09646SNico Weber   std::string Ret;
182ccf09646SNico Weber   raw_string_ostream OS(Ret);
183ccf09646SNico Weber 
184ccf09646SNico Weber   OS << "duplicate resource:";
185ccf09646SNico Weber 
186ccf09646SNico Weber   OS << " type ";
187ccf09646SNico Weber   if (Entry.checkTypeString()) {
188ccf09646SNico Weber     std::string UTF8;
189cf6267ceSNico Weber     if (!convertUTF16LEToUTF8String(Entry.getTypeString(), UTF8))
190ccf09646SNico Weber       UTF8 = "(failed conversion from UTF16)";
191ccf09646SNico Weber     OS << '\"' << UTF8 << '\"';
19223cb79ffSNico Weber   } else
19323cb79ffSNico Weber     printResourceTypeName(Entry.getTypeID(), OS);
194ccf09646SNico Weber 
195ccf09646SNico Weber   OS << "/name ";
196ccf09646SNico Weber   if (Entry.checkNameString()) {
197ccf09646SNico Weber     std::string UTF8;
198cf6267ceSNico Weber     if (!convertUTF16LEToUTF8String(Entry.getNameString(), UTF8))
199ccf09646SNico Weber       UTF8 = "(failed conversion from UTF16)";
200ccf09646SNico Weber     OS << '\"' << UTF8 << '\"';
201ccf09646SNico Weber   } else {
202ccf09646SNico Weber     OS << "ID " << Entry.getNameID();
203ccf09646SNico Weber   }
204ccf09646SNico Weber 
205ccf09646SNico Weber   OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in "
206ccf09646SNico Weber      << File2;
207ccf09646SNico Weber 
20881862f82SNico Weber   return OS.str();
209ccf09646SNico Weber }
210ccf09646SNico Weber 
printStringOrID(const WindowsResourceParser::StringOrID & S,raw_string_ostream & OS,bool IsType,bool IsID)2113d3a9b3bSMartin Storsjo static void printStringOrID(const WindowsResourceParser::StringOrID &S,
2123d3a9b3bSMartin Storsjo                             raw_string_ostream &OS, bool IsType, bool IsID) {
2133d3a9b3bSMartin Storsjo   if (S.IsString) {
2143d3a9b3bSMartin Storsjo     std::string UTF8;
2153d3a9b3bSMartin Storsjo     if (!convertUTF16LEToUTF8String(S.String, UTF8))
2163d3a9b3bSMartin Storsjo       UTF8 = "(failed conversion from UTF16)";
2173d3a9b3bSMartin Storsjo     OS << '\"' << UTF8 << '\"';
2183d3a9b3bSMartin Storsjo   } else if (IsType)
2193d3a9b3bSMartin Storsjo     printResourceTypeName(S.ID, OS);
2203d3a9b3bSMartin Storsjo   else if (IsID)
2213d3a9b3bSMartin Storsjo     OS << "ID " << S.ID;
2223d3a9b3bSMartin Storsjo   else
2233d3a9b3bSMartin Storsjo     OS << S.ID;
2243d3a9b3bSMartin Storsjo }
2253d3a9b3bSMartin Storsjo 
makeDuplicateResourceError(const std::vector<WindowsResourceParser::StringOrID> & Context,StringRef File1,StringRef File2)2263d3a9b3bSMartin Storsjo static std::string makeDuplicateResourceError(
2273d3a9b3bSMartin Storsjo     const std::vector<WindowsResourceParser::StringOrID> &Context,
2283d3a9b3bSMartin Storsjo     StringRef File1, StringRef File2) {
2293d3a9b3bSMartin Storsjo   std::string Ret;
2303d3a9b3bSMartin Storsjo   raw_string_ostream OS(Ret);
2313d3a9b3bSMartin Storsjo 
2323d3a9b3bSMartin Storsjo   OS << "duplicate resource:";
2333d3a9b3bSMartin Storsjo 
2343d3a9b3bSMartin Storsjo   if (Context.size() >= 1) {
2353d3a9b3bSMartin Storsjo     OS << " type ";
2363d3a9b3bSMartin Storsjo     printStringOrID(Context[0], OS, /* IsType */ true, /* IsID */ true);
2373d3a9b3bSMartin Storsjo   }
2383d3a9b3bSMartin Storsjo 
2393d3a9b3bSMartin Storsjo   if (Context.size() >= 2) {
2403d3a9b3bSMartin Storsjo     OS << "/name ";
2413d3a9b3bSMartin Storsjo     printStringOrID(Context[1], OS, /* IsType */ false, /* IsID */ true);
2423d3a9b3bSMartin Storsjo   }
2433d3a9b3bSMartin Storsjo 
2443d3a9b3bSMartin Storsjo   if (Context.size() >= 3) {
2453d3a9b3bSMartin Storsjo     OS << "/language ";
2463d3a9b3bSMartin Storsjo     printStringOrID(Context[2], OS, /* IsType */ false, /* IsID */ false);
2473d3a9b3bSMartin Storsjo   }
2483d3a9b3bSMartin Storsjo   OS << ", in " << File1 << " and in " << File2;
2493d3a9b3bSMartin Storsjo 
2503d3a9b3bSMartin Storsjo   return OS.str();
2513d3a9b3bSMartin Storsjo }
2523d3a9b3bSMartin Storsjo 
253d581dd50SMartin Storsjo // MinGW specific. Remove default manifests (with language zero) if there are
254d581dd50SMartin Storsjo // other manifests present, and report an error if there are more than one
255d581dd50SMartin Storsjo // manifest with a non-zero language code.
256d581dd50SMartin Storsjo // GCC has the concept of a default manifest resource object, which gets
257d581dd50SMartin Storsjo // linked in implicitly if present. This default manifest has got language
258d581dd50SMartin Storsjo // id zero, and should be dropped silently if there's another manifest present.
259d581dd50SMartin Storsjo // If the user resources surprisignly had a manifest with language id zero,
260d581dd50SMartin Storsjo // we should also ignore the duplicate default manifest.
cleanUpManifests(std::vector<std::string> & Duplicates)261d581dd50SMartin Storsjo void WindowsResourceParser::cleanUpManifests(
262d581dd50SMartin Storsjo     std::vector<std::string> &Duplicates) {
263d581dd50SMartin Storsjo   auto TypeIt = Root.IDChildren.find(/* RT_MANIFEST */ 24);
264d581dd50SMartin Storsjo   if (TypeIt == Root.IDChildren.end())
265d581dd50SMartin Storsjo     return;
266d581dd50SMartin Storsjo 
267d581dd50SMartin Storsjo   TreeNode *TypeNode = TypeIt->second.get();
268d581dd50SMartin Storsjo   auto NameIt =
269d581dd50SMartin Storsjo       TypeNode->IDChildren.find(/* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1);
270d581dd50SMartin Storsjo   if (NameIt == TypeNode->IDChildren.end())
271d581dd50SMartin Storsjo     return;
272d581dd50SMartin Storsjo 
273d581dd50SMartin Storsjo   TreeNode *NameNode = NameIt->second.get();
274d581dd50SMartin Storsjo   if (NameNode->IDChildren.size() <= 1)
275d581dd50SMartin Storsjo     return; // None or one manifest present, all good.
276d581dd50SMartin Storsjo 
277d581dd50SMartin Storsjo   // If we have more than one manifest, drop the language zero one if present,
278d581dd50SMartin Storsjo   // and check again.
279d581dd50SMartin Storsjo   auto LangZeroIt = NameNode->IDChildren.find(0);
280d581dd50SMartin Storsjo   if (LangZeroIt != NameNode->IDChildren.end() &&
281d581dd50SMartin Storsjo       LangZeroIt->second->IsDataNode) {
282d581dd50SMartin Storsjo     uint32_t RemovedIndex = LangZeroIt->second->DataIndex;
283d581dd50SMartin Storsjo     NameNode->IDChildren.erase(LangZeroIt);
284d581dd50SMartin Storsjo     Data.erase(Data.begin() + RemovedIndex);
285d581dd50SMartin Storsjo     Root.shiftDataIndexDown(RemovedIndex);
286d581dd50SMartin Storsjo 
287d581dd50SMartin Storsjo     // If we're now down to one manifest, all is good.
288d581dd50SMartin Storsjo     if (NameNode->IDChildren.size() <= 1)
289d581dd50SMartin Storsjo       return;
290d581dd50SMartin Storsjo   }
291d581dd50SMartin Storsjo 
292d581dd50SMartin Storsjo   // More than one non-language-zero manifest
293d581dd50SMartin Storsjo   auto FirstIt = NameNode->IDChildren.begin();
294d581dd50SMartin Storsjo   uint32_t FirstLang = FirstIt->first;
295d581dd50SMartin Storsjo   TreeNode *FirstNode = FirstIt->second.get();
296d581dd50SMartin Storsjo   auto LastIt = NameNode->IDChildren.rbegin();
297d581dd50SMartin Storsjo   uint32_t LastLang = LastIt->first;
298d581dd50SMartin Storsjo   TreeNode *LastNode = LastIt->second.get();
299d581dd50SMartin Storsjo   Duplicates.push_back(
300d581dd50SMartin Storsjo       ("duplicate non-default manifests with languages " + Twine(FirstLang) +
301d581dd50SMartin Storsjo        " in " + InputFilenames[FirstNode->Origin] + " and " + Twine(LastLang) +
302d581dd50SMartin Storsjo        " in " + InputFilenames[LastNode->Origin])
303d581dd50SMartin Storsjo           .str());
304d581dd50SMartin Storsjo }
305d581dd50SMartin Storsjo 
306d581dd50SMartin Storsjo // Ignore duplicates of manifests with language zero (the default manifest),
307d581dd50SMartin Storsjo // in case the user has provided a manifest with that language id. See
308d581dd50SMartin Storsjo // the function comment above for context. Only returns true if MinGW is set
309d581dd50SMartin Storsjo // to true.
shouldIgnoreDuplicate(const ResourceEntryRef & Entry) const310d581dd50SMartin Storsjo bool WindowsResourceParser::shouldIgnoreDuplicate(
311d581dd50SMartin Storsjo     const ResourceEntryRef &Entry) const {
312d581dd50SMartin Storsjo   return MinGW && !Entry.checkTypeString() &&
313d581dd50SMartin Storsjo          Entry.getTypeID() == /* RT_MANIFEST */ 24 &&
314d581dd50SMartin Storsjo          !Entry.checkNameString() &&
315d581dd50SMartin Storsjo          Entry.getNameID() == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
316d581dd50SMartin Storsjo          Entry.getLanguage() == 0;
317d581dd50SMartin Storsjo }
318d581dd50SMartin Storsjo 
shouldIgnoreDuplicate(const std::vector<StringOrID> & Context) const319d581dd50SMartin Storsjo bool WindowsResourceParser::shouldIgnoreDuplicate(
320d581dd50SMartin Storsjo     const std::vector<StringOrID> &Context) const {
321d581dd50SMartin Storsjo   return MinGW && Context.size() == 3 && !Context[0].IsString &&
322d581dd50SMartin Storsjo          Context[0].ID == /* RT_MANIFEST */ 24 && !Context[1].IsString &&
323d581dd50SMartin Storsjo          Context[1].ID == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
324d581dd50SMartin Storsjo          !Context[2].IsString && Context[2].ID == 0;
325d581dd50SMartin Storsjo }
326d581dd50SMartin Storsjo 
parse(WindowsResource * WR,std::vector<std::string> & Duplicates)32781862f82SNico Weber Error WindowsResourceParser::parse(WindowsResource *WR,
32881862f82SNico Weber                                    std::vector<std::string> &Duplicates) {
32972fb6a87SEric Beckmann   auto EntryOrErr = WR->getHeadEntry();
330b85172f6SEric Beckmann   if (!EntryOrErr) {
331b85172f6SEric Beckmann     auto E = EntryOrErr.takeError();
332b85172f6SEric Beckmann     if (E.isA<EmptyResError>()) {
333b85172f6SEric Beckmann       // Check if the .res file contains no entries.  In this case we don't have
334b85172f6SEric Beckmann       // to throw an error but can rather just return without parsing anything.
335b85172f6SEric Beckmann       // This applies for files which have a valid PE header magic and the
336b85172f6SEric Beckmann       // mandatory empty null resource entry.  Files which do not fit this
337b85172f6SEric Beckmann       // criteria would have already been filtered out by
338b85172f6SEric Beckmann       // WindowsResource::createWindowsResource().
339b85172f6SEric Beckmann       consumeError(std::move(E));
340b85172f6SEric Beckmann       return Error::success();
341b85172f6SEric Beckmann     }
342b85172f6SEric Beckmann     return E;
343b85172f6SEric Beckmann   }
34472fb6a87SEric Beckmann 
34572fb6a87SEric Beckmann   ResourceEntryRef Entry = EntryOrErr.get();
346e62d5682SMartin Storsjo   uint32_t Origin = InputFilenames.size();
347adcd0268SBenjamin Kramer   InputFilenames.push_back(std::string(WR->getFileName()));
34872fb6a87SEric Beckmann   bool End = false;
34972fb6a87SEric Beckmann   while (!End) {
35013017597SEric Beckmann 
351ccf09646SNico Weber     TreeNode *Node;
352d8d63ff2SMartin Storsjo     bool IsNewNode = Root.addEntry(Entry, Origin, Data, StringTable, Node);
35381862f82SNico Weber     if (!IsNewNode) {
354d581dd50SMartin Storsjo       if (!shouldIgnoreDuplicate(Entry))
35581862f82SNico Weber         Duplicates.push_back(makeDuplicateResourceError(
35681862f82SNico Weber             Entry, InputFilenames[Node->Origin], WR->getFileName()));
35781862f82SNico Weber     }
35813017597SEric Beckmann 
35972fb6a87SEric Beckmann     RETURN_IF_ERROR(Entry.moveNext(End));
36072fb6a87SEric Beckmann   }
36172fb6a87SEric Beckmann 
36272fb6a87SEric Beckmann   return Error::success();
36372fb6a87SEric Beckmann }
36472fb6a87SEric Beckmann 
parse(ResourceSectionRef & RSR,StringRef Filename,std::vector<std::string> & Duplicates)3653d3a9b3bSMartin Storsjo Error WindowsResourceParser::parse(ResourceSectionRef &RSR, StringRef Filename,
3663d3a9b3bSMartin Storsjo                                    std::vector<std::string> &Duplicates) {
3673d3a9b3bSMartin Storsjo   UNWRAP_REF_OR_RETURN(BaseTable, RSR.getBaseTable());
3683d3a9b3bSMartin Storsjo   uint32_t Origin = InputFilenames.size();
369adcd0268SBenjamin Kramer   InputFilenames.push_back(std::string(Filename));
3703d3a9b3bSMartin Storsjo   std::vector<StringOrID> Context;
3713d3a9b3bSMartin Storsjo   return addChildren(Root, RSR, BaseTable, Origin, Context, Duplicates);
3723d3a9b3bSMartin Storsjo }
3733d3a9b3bSMartin Storsjo 
printTree(raw_ostream & OS) const374907fb813SEric Beckmann void WindowsResourceParser::printTree(raw_ostream &OS) const {
375907fb813SEric Beckmann   ScopedPrinter Writer(OS);
37672fb6a87SEric Beckmann   Root.print(Writer, "Resource Tree");
37772fb6a87SEric Beckmann }
37872fb6a87SEric Beckmann 
addEntry(const ResourceEntryRef & Entry,uint32_t Origin,std::vector<std::vector<uint8_t>> & Data,std::vector<std::vector<UTF16>> & StringTable,TreeNode * & Result)379d8d63ff2SMartin Storsjo bool WindowsResourceParser::TreeNode::addEntry(
380d8d63ff2SMartin Storsjo     const ResourceEntryRef &Entry, uint32_t Origin,
381d8d63ff2SMartin Storsjo     std::vector<std::vector<uint8_t>> &Data,
382d8d63ff2SMartin Storsjo     std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result) {
383d8d63ff2SMartin Storsjo   TreeNode &TypeNode = addTypeNode(Entry, StringTable);
384d8d63ff2SMartin Storsjo   TreeNode &NameNode = TypeNode.addNameNode(Entry, StringTable);
385d8d63ff2SMartin Storsjo   return NameNode.addLanguageNode(Entry, Origin, Data, Result);
38672fb6a87SEric Beckmann }
38772fb6a87SEric Beckmann 
addChildren(TreeNode & Node,ResourceSectionRef & RSR,const coff_resource_dir_table & Table,uint32_t Origin,std::vector<StringOrID> & Context,std::vector<std::string> & Duplicates)3883d3a9b3bSMartin Storsjo Error WindowsResourceParser::addChildren(TreeNode &Node,
3893d3a9b3bSMartin Storsjo                                          ResourceSectionRef &RSR,
3903d3a9b3bSMartin Storsjo                                          const coff_resource_dir_table &Table,
3913d3a9b3bSMartin Storsjo                                          uint32_t Origin,
3923d3a9b3bSMartin Storsjo                                          std::vector<StringOrID> &Context,
3933d3a9b3bSMartin Storsjo                                          std::vector<std::string> &Duplicates) {
3943d3a9b3bSMartin Storsjo 
3953d3a9b3bSMartin Storsjo   for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
3963d3a9b3bSMartin Storsjo        i++) {
3973d3a9b3bSMartin Storsjo     UNWRAP_REF_OR_RETURN(Entry, RSR.getTableEntry(Table, i));
3983d3a9b3bSMartin Storsjo     TreeNode *Child;
3993d3a9b3bSMartin Storsjo 
4003d3a9b3bSMartin Storsjo     if (Entry.Offset.isSubDir()) {
4013d3a9b3bSMartin Storsjo 
4023d3a9b3bSMartin Storsjo       // Create a new subdirectory and recurse
4033d3a9b3bSMartin Storsjo       if (i < Table.NumberOfNameEntries) {
4043d3a9b3bSMartin Storsjo         UNWRAP_OR_RETURN(NameString, RSR.getEntryNameString(Entry));
4053d3a9b3bSMartin Storsjo         Child = &Node.addNameChild(NameString, StringTable);
4063d3a9b3bSMartin Storsjo         Context.push_back(StringOrID(NameString));
4073d3a9b3bSMartin Storsjo       } else {
4083d3a9b3bSMartin Storsjo         Child = &Node.addIDChild(Entry.Identifier.ID);
4093d3a9b3bSMartin Storsjo         Context.push_back(StringOrID(Entry.Identifier.ID));
4103d3a9b3bSMartin Storsjo       }
4113d3a9b3bSMartin Storsjo 
4123d3a9b3bSMartin Storsjo       UNWRAP_REF_OR_RETURN(NextTable, RSR.getEntrySubDir(Entry));
4133d3a9b3bSMartin Storsjo       Error E =
4143d3a9b3bSMartin Storsjo           addChildren(*Child, RSR, NextTable, Origin, Context, Duplicates);
4153d3a9b3bSMartin Storsjo       if (E)
4163d3a9b3bSMartin Storsjo         return E;
4173d3a9b3bSMartin Storsjo       Context.pop_back();
4183d3a9b3bSMartin Storsjo 
4193d3a9b3bSMartin Storsjo     } else {
4203d3a9b3bSMartin Storsjo 
4213d3a9b3bSMartin Storsjo       // Data leaves are supposed to have a numeric ID as identifier (language).
4223d3a9b3bSMartin Storsjo       if (Table.NumberOfNameEntries > 0)
4233d3a9b3bSMartin Storsjo         return createStringError(object_error::parse_failed,
4243d3a9b3bSMartin Storsjo                                  "unexpected string key for data object");
4253d3a9b3bSMartin Storsjo 
4263d3a9b3bSMartin Storsjo       // Try adding a data leaf
4273d3a9b3bSMartin Storsjo       UNWRAP_REF_OR_RETURN(DataEntry, RSR.getEntryData(Entry));
4283d3a9b3bSMartin Storsjo       TreeNode *Child;
4293d3a9b3bSMartin Storsjo       Context.push_back(StringOrID(Entry.Identifier.ID));
4303d3a9b3bSMartin Storsjo       bool Added = Node.addDataChild(Entry.Identifier.ID, Table.MajorVersion,
4313d3a9b3bSMartin Storsjo                                      Table.MinorVersion, Table.Characteristics,
4323d3a9b3bSMartin Storsjo                                      Origin, Data.size(), Child);
4333d3a9b3bSMartin Storsjo       if (Added) {
4343d3a9b3bSMartin Storsjo         UNWRAP_OR_RETURN(Contents, RSR.getContents(DataEntry));
4353d3a9b3bSMartin Storsjo         Data.push_back(ArrayRef<uint8_t>(
4363d3a9b3bSMartin Storsjo             reinterpret_cast<const uint8_t *>(Contents.data()),
4373d3a9b3bSMartin Storsjo             Contents.size()));
4383d3a9b3bSMartin Storsjo       } else {
439d581dd50SMartin Storsjo         if (!shouldIgnoreDuplicate(Context))
4403d3a9b3bSMartin Storsjo           Duplicates.push_back(makeDuplicateResourceError(
4413d3a9b3bSMartin Storsjo               Context, InputFilenames[Child->Origin], InputFilenames.back()));
4423d3a9b3bSMartin Storsjo       }
4433d3a9b3bSMartin Storsjo       Context.pop_back();
4443d3a9b3bSMartin Storsjo 
4453d3a9b3bSMartin Storsjo     }
4463d3a9b3bSMartin Storsjo   }
4473d3a9b3bSMartin Storsjo   return Error::success();
4483d3a9b3bSMartin Storsjo }
4493d3a9b3bSMartin Storsjo 
TreeNode(uint32_t StringIndex)450d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode::TreeNode(uint32_t StringIndex)
451d8d63ff2SMartin Storsjo     : StringIndex(StringIndex) {}
452d9de6389SEric Beckmann 
TreeNode(uint16_t MajorVersion,uint16_t MinorVersion,uint32_t Characteristics,uint32_t Origin,uint32_t DataIndex)453d9de6389SEric Beckmann WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
454d9de6389SEric Beckmann                                           uint16_t MinorVersion,
455ccf09646SNico Weber                                           uint32_t Characteristics,
456d8d63ff2SMartin Storsjo                                           uint32_t Origin, uint32_t DataIndex)
457d8d63ff2SMartin Storsjo     : IsDataNode(true), DataIndex(DataIndex), MajorVersion(MajorVersion),
458d8d63ff2SMartin Storsjo       MinorVersion(MinorVersion), Characteristics(Characteristics),
459d8d63ff2SMartin Storsjo       Origin(Origin) {}
460d9de6389SEric Beckmann 
461d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode>
createStringNode(uint32_t Index)462d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode::createStringNode(uint32_t Index) {
463d8d63ff2SMartin Storsjo   return std::unique_ptr<TreeNode>(new TreeNode(Index));
464d9de6389SEric Beckmann }
465d9de6389SEric Beckmann 
466d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode>
createIDNode()467d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createIDNode() {
468d8d63ff2SMartin Storsjo   return std::unique_ptr<TreeNode>(new TreeNode(0));
469d9de6389SEric Beckmann }
470d9de6389SEric Beckmann 
471d9de6389SEric Beckmann std::unique_ptr<WindowsResourceParser::TreeNode>
createDataNode(uint16_t MajorVersion,uint16_t MinorVersion,uint32_t Characteristics,uint32_t Origin,uint32_t DataIndex)472d9de6389SEric Beckmann WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
473d9de6389SEric Beckmann                                                 uint16_t MinorVersion,
474ccf09646SNico Weber                                                 uint32_t Characteristics,
475d8d63ff2SMartin Storsjo                                                 uint32_t Origin,
476d8d63ff2SMartin Storsjo                                                 uint32_t DataIndex) {
477d8d63ff2SMartin Storsjo   return std::unique_ptr<TreeNode>(new TreeNode(
478d8d63ff2SMartin Storsjo       MajorVersion, MinorVersion, Characteristics, Origin, DataIndex));
479d9de6389SEric Beckmann }
48072fb6a87SEric Beckmann 
addTypeNode(const ResourceEntryRef & Entry,std::vector<std::vector<UTF16>> & StringTable)481d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addTypeNode(
482d8d63ff2SMartin Storsjo     const ResourceEntryRef &Entry,
483d8d63ff2SMartin Storsjo     std::vector<std::vector<UTF16>> &StringTable) {
48472fb6a87SEric Beckmann   if (Entry.checkTypeString())
485d8d63ff2SMartin Storsjo     return addNameChild(Entry.getTypeString(), StringTable);
48672fb6a87SEric Beckmann   else
4876967da8fSNico Weber     return addIDChild(Entry.getTypeID());
48872fb6a87SEric Beckmann }
48972fb6a87SEric Beckmann 
addNameNode(const ResourceEntryRef & Entry,std::vector<std::vector<UTF16>> & StringTable)490d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameNode(
491d8d63ff2SMartin Storsjo     const ResourceEntryRef &Entry,
492d8d63ff2SMartin Storsjo     std::vector<std::vector<UTF16>> &StringTable) {
49372fb6a87SEric Beckmann   if (Entry.checkNameString())
494d8d63ff2SMartin Storsjo     return addNameChild(Entry.getNameString(), StringTable);
49572fb6a87SEric Beckmann   else
4966967da8fSNico Weber     return addIDChild(Entry.getNameID());
49772fb6a87SEric Beckmann }
49872fb6a87SEric Beckmann 
addLanguageNode(const ResourceEntryRef & Entry,uint32_t Origin,std::vector<std::vector<uint8_t>> & Data,TreeNode * & Result)499ccf09646SNico Weber bool WindowsResourceParser::TreeNode::addLanguageNode(
500d8d63ff2SMartin Storsjo     const ResourceEntryRef &Entry, uint32_t Origin,
501d8d63ff2SMartin Storsjo     std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result) {
502d8d63ff2SMartin Storsjo   bool Added = addDataChild(Entry.getLanguage(), Entry.getMajorVersion(),
503ccf09646SNico Weber                             Entry.getMinorVersion(), Entry.getCharacteristics(),
504d8d63ff2SMartin Storsjo                             Origin, Data.size(), Result);
505d8d63ff2SMartin Storsjo   if (Added)
506d8d63ff2SMartin Storsjo     Data.push_back(Entry.getData());
507d8d63ff2SMartin Storsjo   return Added;
50872fb6a87SEric Beckmann }
50972fb6a87SEric Beckmann 
addDataChild(uint32_t ID,uint16_t MajorVersion,uint16_t MinorVersion,uint32_t Characteristics,uint32_t Origin,uint32_t DataIndex,TreeNode * & Result)510ccf09646SNico Weber bool WindowsResourceParser::TreeNode::addDataChild(
5116967da8fSNico Weber     uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
512d8d63ff2SMartin Storsjo     uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex,
513d8d63ff2SMartin Storsjo     TreeNode *&Result) {
514d8d63ff2SMartin Storsjo   auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics,
515d8d63ff2SMartin Storsjo                                  Origin, DataIndex);
516ccf09646SNico Weber   auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild));
517ccf09646SNico Weber   Result = ElementInserted.first->second.get();
518ccf09646SNico Weber   return ElementInserted.second;
5196967da8fSNico Weber }
5206967da8fSNico Weber 
addIDChild(uint32_t ID)5216967da8fSNico Weber WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild(
5226967da8fSNico Weber     uint32_t ID) {
5236967da8fSNico Weber   auto Child = IDChildren.find(ID);
5246967da8fSNico Weber   if (Child == IDChildren.end()) {
5256967da8fSNico Weber     auto NewChild = createIDNode();
52672fb6a87SEric Beckmann     WindowsResourceParser::TreeNode &Node = *NewChild;
52772fb6a87SEric Beckmann     IDChildren.emplace(ID, std::move(NewChild));
52872fb6a87SEric Beckmann     return Node;
52972fb6a87SEric Beckmann   } else
53072fb6a87SEric Beckmann     return *(Child->second);
53172fb6a87SEric Beckmann }
53272fb6a87SEric Beckmann 
addNameChild(ArrayRef<UTF16> NameRef,std::vector<std::vector<UTF16>> & StringTable)533d8d63ff2SMartin Storsjo WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameChild(
534d8d63ff2SMartin Storsjo     ArrayRef<UTF16> NameRef, std::vector<std::vector<UTF16>> &StringTable) {
53572fb6a87SEric Beckmann   std::string NameString;
536cf6267ceSNico Weber   convertUTF16LEToUTF8String(NameRef, NameString);
53772fb6a87SEric Beckmann 
53872fb6a87SEric Beckmann   auto Child = StringChildren.find(NameString);
53972fb6a87SEric Beckmann   if (Child == StringChildren.end()) {
540d8d63ff2SMartin Storsjo     auto NewChild = createStringNode(StringTable.size());
541d8d63ff2SMartin Storsjo     StringTable.push_back(NameRef);
54272fb6a87SEric Beckmann     WindowsResourceParser::TreeNode &Node = *NewChild;
54372fb6a87SEric Beckmann     StringChildren.emplace(NameString, std::move(NewChild));
54472fb6a87SEric Beckmann     return Node;
54572fb6a87SEric Beckmann   } else
54672fb6a87SEric Beckmann     return *(Child->second);
54772fb6a87SEric Beckmann }
54872fb6a87SEric Beckmann 
print(ScopedPrinter & Writer,StringRef Name) const54972fb6a87SEric Beckmann void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
55072fb6a87SEric Beckmann                                             StringRef Name) const {
55172fb6a87SEric Beckmann   ListScope NodeScope(Writer, Name);
55272fb6a87SEric Beckmann   for (auto const &Child : StringChildren) {
55372fb6a87SEric Beckmann     Child.second->print(Writer, Child.first);
55472fb6a87SEric Beckmann   }
55572fb6a87SEric Beckmann   for (auto const &Child : IDChildren) {
556ba395ef4SEric Beckmann     Child.second->print(Writer, to_string(Child.first));
55772fb6a87SEric Beckmann   }
55872fb6a87SEric Beckmann }
55972fb6a87SEric Beckmann 
560d9de6389SEric Beckmann // This function returns the size of the entire resource tree, including
561d9de6389SEric Beckmann // directory tables, directory entries, and data entries.  It does not include
562d9de6389SEric Beckmann // the directory strings or the relocations of the .rsrc section.
getTreeSize() const563d9de6389SEric Beckmann uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
564d9de6389SEric Beckmann   uint32_t Size = (IDChildren.size() + StringChildren.size()) *
5657687f046SEric Beckmann                   sizeof(coff_resource_dir_entry);
566d9de6389SEric Beckmann 
567d9de6389SEric Beckmann   // Reached a node pointing to a data entry.
568d9de6389SEric Beckmann   if (IsDataNode) {
5697687f046SEric Beckmann     Size += sizeof(coff_resource_data_entry);
570d9de6389SEric Beckmann     return Size;
571d9de6389SEric Beckmann   }
572d9de6389SEric Beckmann 
573d9de6389SEric Beckmann   // If the node does not point to data, it must have a directory table pointing
574d9de6389SEric Beckmann   // to other nodes.
5757687f046SEric Beckmann   Size += sizeof(coff_resource_dir_table);
576d9de6389SEric Beckmann 
577d9de6389SEric Beckmann   for (auto const &Child : StringChildren) {
578d9de6389SEric Beckmann     Size += Child.second->getTreeSize();
579d9de6389SEric Beckmann   }
580d9de6389SEric Beckmann   for (auto const &Child : IDChildren) {
581d9de6389SEric Beckmann     Size += Child.second->getTreeSize();
582d9de6389SEric Beckmann   }
583d9de6389SEric Beckmann   return Size;
584d9de6389SEric Beckmann }
585d9de6389SEric Beckmann 
586d581dd50SMartin Storsjo // Shift DataIndex of all data children with an Index greater or equal to the
587d581dd50SMartin Storsjo // given one, to fill a gap from removing an entry from the Data vector.
shiftDataIndexDown(uint32_t Index)588d581dd50SMartin Storsjo void WindowsResourceParser::TreeNode::shiftDataIndexDown(uint32_t Index) {
589d581dd50SMartin Storsjo   if (IsDataNode && DataIndex >= Index) {
590d581dd50SMartin Storsjo     DataIndex--;
591d581dd50SMartin Storsjo   } else {
592d581dd50SMartin Storsjo     for (auto &Child : IDChildren)
593d581dd50SMartin Storsjo       Child.second->shiftDataIndexDown(Index);
594d581dd50SMartin Storsjo     for (auto &Child : StringChildren)
595d581dd50SMartin Storsjo       Child.second->shiftDataIndexDown(Index);
596d581dd50SMartin Storsjo   }
597d581dd50SMartin Storsjo }
598d581dd50SMartin Storsjo 
599d9de6389SEric Beckmann class WindowsResourceCOFFWriter {
600d9de6389SEric Beckmann public:
601ddcfbf7dSEric Beckmann   WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,
602d9de6389SEric Beckmann                             const WindowsResourceParser &Parser, Error &E);
603dd601952SNico Weber   std::unique_ptr<MemoryBuffer> write(uint32_t TimeDateStamp);
604d9de6389SEric Beckmann 
605d9de6389SEric Beckmann private:
606d9de6389SEric Beckmann   void performFileLayout();
607d9de6389SEric Beckmann   void performSectionOneLayout();
608d9de6389SEric Beckmann   void performSectionTwoLayout();
609dd601952SNico Weber   void writeCOFFHeader(uint32_t TimeDateStamp);
610d9de6389SEric Beckmann   void writeFirstSectionHeader();
611d9de6389SEric Beckmann   void writeSecondSectionHeader();
612d9de6389SEric Beckmann   void writeFirstSection();
613d9de6389SEric Beckmann   void writeSecondSection();
614d9de6389SEric Beckmann   void writeSymbolTable();
615d9de6389SEric Beckmann   void writeStringTable();
616d9de6389SEric Beckmann   void writeDirectoryTree();
617d9de6389SEric Beckmann   void writeDirectoryStringTable();
618d9de6389SEric Beckmann   void writeFirstSectionRelocations();
6199aaf5d3eSPavel Labath   std::unique_ptr<WritableMemoryBuffer> OutputBuffer;
620d135e8c0SEric Beckmann   char *BufferStart;
621382eaabbSEric Beckmann   uint64_t CurrentOffset = 0;
6220eafa581SEric Beckmann   COFF::MachineTypes MachineType;
623d9de6389SEric Beckmann   const WindowsResourceParser::TreeNode &Resources;
624d9de6389SEric Beckmann   const ArrayRef<std::vector<uint8_t>> Data;
625d9de6389SEric Beckmann   uint64_t FileSize;
626d9de6389SEric Beckmann   uint32_t SymbolTableOffset;
627d9de6389SEric Beckmann   uint32_t SectionOneSize;
628d9de6389SEric Beckmann   uint32_t SectionOneOffset;
629d9de6389SEric Beckmann   uint32_t SectionOneRelocations;
630d9de6389SEric Beckmann   uint32_t SectionTwoSize;
631d9de6389SEric Beckmann   uint32_t SectionTwoOffset;
632d9de6389SEric Beckmann   const ArrayRef<std::vector<UTF16>> StringTable;
633d9de6389SEric Beckmann   std::vector<uint32_t> StringTableOffsets;
634d9de6389SEric Beckmann   std::vector<uint32_t> DataOffsets;
635d9de6389SEric Beckmann   std::vector<uint32_t> RelocationAddresses;
636d9de6389SEric Beckmann };
637d9de6389SEric Beckmann 
WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,const WindowsResourceParser & Parser,Error & E)638d9de6389SEric Beckmann WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
639ddcfbf7dSEric Beckmann     COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
640ddcfbf7dSEric Beckmann     Error &E)
641ddcfbf7dSEric Beckmann     : MachineType(MachineType), Resources(Parser.getTree()),
642ddcfbf7dSEric Beckmann       Data(Parser.getData()), StringTable(Parser.getStringTable()) {
643d9de6389SEric Beckmann   performFileLayout();
644c8dba240SEric Beckmann 
645af6bc65dSNico Weber   OutputBuffer = WritableMemoryBuffer::getNewMemBuffer(
646af6bc65dSNico Weber       FileSize, "internal .obj file created from .res files");
647d9de6389SEric Beckmann }
648d9de6389SEric Beckmann 
performFileLayout()649d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performFileLayout() {
650d9de6389SEric Beckmann   // Add size of COFF header.
6517687f046SEric Beckmann   FileSize = COFF::Header16Size;
652d9de6389SEric Beckmann 
653d9de6389SEric Beckmann   // one .rsrc section header for directory tree, another for resource data.
6547687f046SEric Beckmann   FileSize += 2 * COFF::SectionSize;
655d9de6389SEric Beckmann 
656d9de6389SEric Beckmann   performSectionOneLayout();
657d9de6389SEric Beckmann   performSectionTwoLayout();
658d9de6389SEric Beckmann 
659d9de6389SEric Beckmann   // We have reached the address of the symbol table.
660d9de6389SEric Beckmann   SymbolTableOffset = FileSize;
661d9de6389SEric Beckmann 
6627687f046SEric Beckmann   FileSize += COFF::Symbol16Size;     // size of the @feat.00 symbol.
6637687f046SEric Beckmann   FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
6647687f046SEric Beckmann   FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
665d9de6389SEric Beckmann   FileSize += 4; // four null bytes for the string table.
666d9de6389SEric Beckmann }
667d9de6389SEric Beckmann 
performSectionOneLayout()668d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performSectionOneLayout() {
669d9de6389SEric Beckmann   SectionOneOffset = FileSize;
670d9de6389SEric Beckmann 
671d9de6389SEric Beckmann   SectionOneSize = Resources.getTreeSize();
672d9de6389SEric Beckmann   uint32_t CurrentStringOffset = SectionOneSize;
673d9de6389SEric Beckmann   uint32_t TotalStringTableSize = 0;
674d9de6389SEric Beckmann   for (auto const &String : StringTable) {
675d9de6389SEric Beckmann     StringTableOffsets.push_back(CurrentStringOffset);
676d9de6389SEric Beckmann     uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
677d9de6389SEric Beckmann     CurrentStringOffset += StringSize;
678d9de6389SEric Beckmann     TotalStringTableSize += StringSize;
679d9de6389SEric Beckmann   }
680d9de6389SEric Beckmann   SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
681d9de6389SEric Beckmann 
682d9de6389SEric Beckmann   // account for the relocations of section one.
683d9de6389SEric Beckmann   SectionOneRelocations = FileSize + SectionOneSize;
684d9de6389SEric Beckmann   FileSize += SectionOneSize;
6857687f046SEric Beckmann   FileSize +=
6867687f046SEric Beckmann       Data.size() * COFF::RelocationSize; // one relocation for each resource.
687382eaabbSEric Beckmann   FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
688d9de6389SEric Beckmann }
689d9de6389SEric Beckmann 
performSectionTwoLayout()690d9de6389SEric Beckmann void WindowsResourceCOFFWriter::performSectionTwoLayout() {
691d9de6389SEric Beckmann   // add size of .rsrc$2 section, which contains all resource data on 8-byte
692d9de6389SEric Beckmann   // alignment.
693d9de6389SEric Beckmann   SectionTwoOffset = FileSize;
694d9de6389SEric Beckmann   SectionTwoSize = 0;
695d9de6389SEric Beckmann   for (auto const &Entry : Data) {
696d9de6389SEric Beckmann     DataOffsets.push_back(SectionTwoSize);
6977687f046SEric Beckmann     SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
698d9de6389SEric Beckmann   }
699d9de6389SEric Beckmann   FileSize += SectionTwoSize;
700382eaabbSEric Beckmann   FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
701d9de6389SEric Beckmann }
702d9de6389SEric Beckmann 
703dd601952SNico Weber std::unique_ptr<MemoryBuffer>
write(uint32_t TimeDateStamp)704dd601952SNico Weber WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) {
7059aaf5d3eSPavel Labath   BufferStart = OutputBuffer->getBufferStart();
706d9de6389SEric Beckmann 
707dd601952SNico Weber   writeCOFFHeader(TimeDateStamp);
708d9de6389SEric Beckmann   writeFirstSectionHeader();
709d9de6389SEric Beckmann   writeSecondSectionHeader();
710d9de6389SEric Beckmann   writeFirstSection();
711d9de6389SEric Beckmann   writeSecondSection();
712d9de6389SEric Beckmann   writeSymbolTable();
713d9de6389SEric Beckmann   writeStringTable();
714d9de6389SEric Beckmann 
715ddcfbf7dSEric Beckmann   return std::move(OutputBuffer);
716d9de6389SEric Beckmann }
717d9de6389SEric Beckmann 
718d1262a6eSSerge Guelton // According to COFF specification, if the Src has a size equal to Dest,
719d1262a6eSSerge Guelton // it's okay to *not* copy the trailing zero.
coffnamecpy(char (& Dest)[COFF::NameSize],StringRef Src)720d1262a6eSSerge Guelton static void coffnamecpy(char (&Dest)[COFF::NameSize], StringRef Src) {
721d1262a6eSSerge Guelton   assert(Src.size() <= COFF::NameSize &&
722*498a6136Sserge-sans-paille          "Src is larger than COFF::NameSize");
723*498a6136Sserge-sans-paille   assert((Src.size() == COFF::NameSize || Dest[Src.size()] == '\0') &&
724*498a6136Sserge-sans-paille          "Dest not zeroed upon initialization");
725*498a6136Sserge-sans-paille   memcpy(Dest, Src.data(), Src.size());
726d1262a6eSSerge Guelton }
727d1262a6eSSerge Guelton 
writeCOFFHeader(uint32_t TimeDateStamp)728dd601952SNico Weber void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) {
729d9de6389SEric Beckmann   // Write the COFF header.
7307687f046SEric Beckmann   auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
731ba664c1dSMartin Storsjo   Header->Machine = MachineType;
732d9de6389SEric Beckmann   Header->NumberOfSections = 2;
733dd601952SNico Weber   Header->TimeDateStamp = TimeDateStamp;
734d9de6389SEric Beckmann   Header->PointerToSymbolTable = SymbolTableOffset;
735af6bc65dSNico Weber   // One symbol for every resource plus 2 for each section and 1 for @feat.00
736d9de6389SEric Beckmann   Header->NumberOfSymbols = Data.size() + 5;
737d9de6389SEric Beckmann   Header->SizeOfOptionalHeader = 0;
738dd601952SNico Weber   // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it.
7397687f046SEric Beckmann   Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
740d9de6389SEric Beckmann }
741d9de6389SEric Beckmann 
writeFirstSectionHeader()742d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
743d9de6389SEric Beckmann   // Write the first section header.
7447687f046SEric Beckmann   CurrentOffset += sizeof(coff_file_header);
7457687f046SEric Beckmann   auto *SectionOneHeader =
7467687f046SEric Beckmann       reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
747d1262a6eSSerge Guelton   coffnamecpy(SectionOneHeader->Name, ".rsrc$01");
748d9de6389SEric Beckmann   SectionOneHeader->VirtualSize = 0;
749d9de6389SEric Beckmann   SectionOneHeader->VirtualAddress = 0;
750d9de6389SEric Beckmann   SectionOneHeader->SizeOfRawData = SectionOneSize;
751d9de6389SEric Beckmann   SectionOneHeader->PointerToRawData = SectionOneOffset;
752d9de6389SEric Beckmann   SectionOneHeader->PointerToRelocations = SectionOneRelocations;
753d9de6389SEric Beckmann   SectionOneHeader->PointerToLinenumbers = 0;
754d9de6389SEric Beckmann   SectionOneHeader->NumberOfRelocations = Data.size();
755d9de6389SEric Beckmann   SectionOneHeader->NumberOfLinenumbers = 0;
7567687f046SEric Beckmann   SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
7577687f046SEric Beckmann   SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
758d9de6389SEric Beckmann }
759d9de6389SEric Beckmann 
writeSecondSectionHeader()760d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
761d9de6389SEric Beckmann   // Write the second section header.
7627687f046SEric Beckmann   CurrentOffset += sizeof(coff_section);
7637687f046SEric Beckmann   auto *SectionTwoHeader =
7647687f046SEric Beckmann       reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
765d1262a6eSSerge Guelton   coffnamecpy(SectionTwoHeader->Name, ".rsrc$02");
766d9de6389SEric Beckmann   SectionTwoHeader->VirtualSize = 0;
767d9de6389SEric Beckmann   SectionTwoHeader->VirtualAddress = 0;
768d9de6389SEric Beckmann   SectionTwoHeader->SizeOfRawData = SectionTwoSize;
769d9de6389SEric Beckmann   SectionTwoHeader->PointerToRawData = SectionTwoOffset;
770d9de6389SEric Beckmann   SectionTwoHeader->PointerToRelocations = 0;
771d9de6389SEric Beckmann   SectionTwoHeader->PointerToLinenumbers = 0;
772d9de6389SEric Beckmann   SectionTwoHeader->NumberOfRelocations = 0;
773d9de6389SEric Beckmann   SectionTwoHeader->NumberOfLinenumbers = 0;
7747687f046SEric Beckmann   SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
7757687f046SEric Beckmann   SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
776d9de6389SEric Beckmann }
777d9de6389SEric Beckmann 
writeFirstSection()778d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSection() {
779d9de6389SEric Beckmann   // Write section one.
7807687f046SEric Beckmann   CurrentOffset += sizeof(coff_section);
781d9de6389SEric Beckmann 
782d9de6389SEric Beckmann   writeDirectoryTree();
783d9de6389SEric Beckmann   writeDirectoryStringTable();
784d9de6389SEric Beckmann   writeFirstSectionRelocations();
785382eaabbSEric Beckmann 
786382eaabbSEric Beckmann   CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
787d9de6389SEric Beckmann }
788d9de6389SEric Beckmann 
writeSecondSection()789d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSecondSection() {
790d9de6389SEric Beckmann   // Now write the .rsrc$02 section.
791d9de6389SEric Beckmann   for (auto const &RawDataEntry : Data) {
79275709329SFangrui Song     llvm::copy(RawDataEntry, BufferStart + CurrentOffset);
793382eaabbSEric Beckmann     CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
794d9de6389SEric Beckmann   }
795382eaabbSEric Beckmann 
796382eaabbSEric Beckmann   CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
797d9de6389SEric Beckmann }
798d9de6389SEric Beckmann 
writeSymbolTable()799d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeSymbolTable() {
800d9de6389SEric Beckmann   // Now write the symbol table.
801d9de6389SEric Beckmann   // First, the feat symbol.
8027687f046SEric Beckmann   auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
803d1262a6eSSerge Guelton   coffnamecpy(Symbol->Name.ShortName, "@feat.00");
804d9de6389SEric Beckmann   Symbol->Value = 0x11;
805d9de6389SEric Beckmann   Symbol->SectionNumber = 0xffff;
8067687f046SEric Beckmann   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
8077687f046SEric Beckmann   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
808d9de6389SEric Beckmann   Symbol->NumberOfAuxSymbols = 0;
8097687f046SEric Beckmann   CurrentOffset += sizeof(coff_symbol16);
810d9de6389SEric Beckmann 
811d9de6389SEric Beckmann   // Now write the .rsrc1 symbol + aux.
8127687f046SEric Beckmann   Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
813d1262a6eSSerge Guelton   coffnamecpy(Symbol->Name.ShortName, ".rsrc$01");
814d9de6389SEric Beckmann   Symbol->Value = 0;
815d9de6389SEric Beckmann   Symbol->SectionNumber = 1;
8167687f046SEric Beckmann   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
8177687f046SEric Beckmann   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
818d9de6389SEric Beckmann   Symbol->NumberOfAuxSymbols = 1;
8197687f046SEric Beckmann   CurrentOffset += sizeof(coff_symbol16);
8207687f046SEric Beckmann   auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
8217687f046SEric Beckmann                                                               CurrentOffset);
822d9de6389SEric Beckmann   Aux->Length = SectionOneSize;
823d9de6389SEric Beckmann   Aux->NumberOfRelocations = Data.size();
824d9de6389SEric Beckmann   Aux->NumberOfLinenumbers = 0;
825d9de6389SEric Beckmann   Aux->CheckSum = 0;
826d9de6389SEric Beckmann   Aux->NumberLowPart = 0;
827d9de6389SEric Beckmann   Aux->Selection = 0;
8287687f046SEric Beckmann   CurrentOffset += sizeof(coff_aux_section_definition);
829d9de6389SEric Beckmann 
830d9de6389SEric Beckmann   // Now write the .rsrc2 symbol + aux.
8317687f046SEric Beckmann   Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
832d1262a6eSSerge Guelton   coffnamecpy(Symbol->Name.ShortName, ".rsrc$02");
833d9de6389SEric Beckmann   Symbol->Value = 0;
834d9de6389SEric Beckmann   Symbol->SectionNumber = 2;
8357687f046SEric Beckmann   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
8367687f046SEric Beckmann   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
837d9de6389SEric Beckmann   Symbol->NumberOfAuxSymbols = 1;
8387687f046SEric Beckmann   CurrentOffset += sizeof(coff_symbol16);
8397687f046SEric Beckmann   Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
8407687f046SEric Beckmann                                                         CurrentOffset);
841d9de6389SEric Beckmann   Aux->Length = SectionTwoSize;
842d9de6389SEric Beckmann   Aux->NumberOfRelocations = 0;
843d9de6389SEric Beckmann   Aux->NumberOfLinenumbers = 0;
844d9de6389SEric Beckmann   Aux->CheckSum = 0;
845d9de6389SEric Beckmann   Aux->NumberLowPart = 0;
846d9de6389SEric Beckmann   Aux->Selection = 0;
8477687f046SEric Beckmann   CurrentOffset += sizeof(coff_aux_section_definition);
848d9de6389SEric Beckmann 
849d9de6389SEric Beckmann   // Now write a symbol for each relocation.
850d9de6389SEric Beckmann   for (unsigned i = 0; i < Data.size(); i++) {
851ea5ff9faSBob Haarman     auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
8527687f046SEric Beckmann     Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
853d1262a6eSSerge Guelton     coffnamecpy(Symbol->Name.ShortName, RelocationName);
854d9de6389SEric Beckmann     Symbol->Value = DataOffsets[i];
855e44afc4aSEric Beckmann     Symbol->SectionNumber = 2;
8567687f046SEric Beckmann     Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
8577687f046SEric Beckmann     Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
858d9de6389SEric Beckmann     Symbol->NumberOfAuxSymbols = 0;
8597687f046SEric Beckmann     CurrentOffset += sizeof(coff_symbol16);
860d9de6389SEric Beckmann   }
861d9de6389SEric Beckmann }
862d9de6389SEric Beckmann 
writeStringTable()863d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeStringTable() {
864d9de6389SEric Beckmann   // Just 4 null bytes for the string table.
86533866334SEric Beckmann   auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
86633866334SEric Beckmann   memset(COFFStringTable, 0, 4);
867d9de6389SEric Beckmann }
868d9de6389SEric Beckmann 
writeDirectoryTree()869d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeDirectoryTree() {
870d9de6389SEric Beckmann   // Traverse parsed resource tree breadth-first and write the corresponding
871d9de6389SEric Beckmann   // COFF objects.
872d9de6389SEric Beckmann   std::queue<const WindowsResourceParser::TreeNode *> Queue;
873d9de6389SEric Beckmann   Queue.push(&Resources);
8747687f046SEric Beckmann   uint32_t NextLevelOffset =
8757687f046SEric Beckmann       sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() +
876d9de6389SEric Beckmann                                          Resources.getIDChildren().size()) *
8777687f046SEric Beckmann                                             sizeof(coff_resource_dir_entry);
878d9de6389SEric Beckmann   std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
879d9de6389SEric Beckmann   uint32_t CurrentRelativeOffset = 0;
880d9de6389SEric Beckmann 
881d9de6389SEric Beckmann   while (!Queue.empty()) {
882d9de6389SEric Beckmann     auto CurrentNode = Queue.front();
883d9de6389SEric Beckmann     Queue.pop();
8847687f046SEric Beckmann     auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart +
8857687f046SEric Beckmann                                                               CurrentOffset);
886d9de6389SEric Beckmann     Table->Characteristics = CurrentNode->getCharacteristics();
887d9de6389SEric Beckmann     Table->TimeDateStamp = 0;
888d9de6389SEric Beckmann     Table->MajorVersion = CurrentNode->getMajorVersion();
889d9de6389SEric Beckmann     Table->MinorVersion = CurrentNode->getMinorVersion();
890d9de6389SEric Beckmann     auto &IDChildren = CurrentNode->getIDChildren();
891d9de6389SEric Beckmann     auto &StringChildren = CurrentNode->getStringChildren();
892d9de6389SEric Beckmann     Table->NumberOfNameEntries = StringChildren.size();
893d9de6389SEric Beckmann     Table->NumberOfIDEntries = IDChildren.size();
8947687f046SEric Beckmann     CurrentOffset += sizeof(coff_resource_dir_table);
8957687f046SEric Beckmann     CurrentRelativeOffset += sizeof(coff_resource_dir_table);
896d9de6389SEric Beckmann 
897d9de6389SEric Beckmann     // Write the directory entries immediately following each directory table.
898d9de6389SEric Beckmann     for (auto const &Child : StringChildren) {
8997687f046SEric Beckmann       auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
9007687f046SEric Beckmann                                                                 CurrentOffset);
9017c865f00SEric Beckmann       Entry->Identifier.setNameOffset(
9027c865f00SEric Beckmann           StringTableOffsets[Child.second->getStringIndex()]);
903d9de6389SEric Beckmann       if (Child.second->checkIsDataNode()) {
904d9de6389SEric Beckmann         Entry->Offset.DataEntryOffset = NextLevelOffset;
9057687f046SEric Beckmann         NextLevelOffset += sizeof(coff_resource_data_entry);
906d9de6389SEric Beckmann         DataEntriesTreeOrder.push_back(Child.second.get());
907d9de6389SEric Beckmann       } else {
908d9de6389SEric Beckmann         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
9097687f046SEric Beckmann         NextLevelOffset += sizeof(coff_resource_dir_table) +
910d9de6389SEric Beckmann                            (Child.second->getStringChildren().size() +
911d9de6389SEric Beckmann                             Child.second->getIDChildren().size()) *
9127687f046SEric Beckmann                                sizeof(coff_resource_dir_entry);
913d9de6389SEric Beckmann         Queue.push(Child.second.get());
914d9de6389SEric Beckmann       }
9157687f046SEric Beckmann       CurrentOffset += sizeof(coff_resource_dir_entry);
9167687f046SEric Beckmann       CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
917d9de6389SEric Beckmann     }
918d9de6389SEric Beckmann     for (auto const &Child : IDChildren) {
9197687f046SEric Beckmann       auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
9207687f046SEric Beckmann                                                                 CurrentOffset);
921d9de6389SEric Beckmann       Entry->Identifier.ID = Child.first;
922d9de6389SEric Beckmann       if (Child.second->checkIsDataNode()) {
923d9de6389SEric Beckmann         Entry->Offset.DataEntryOffset = NextLevelOffset;
9247687f046SEric Beckmann         NextLevelOffset += sizeof(coff_resource_data_entry);
925d9de6389SEric Beckmann         DataEntriesTreeOrder.push_back(Child.second.get());
926d9de6389SEric Beckmann       } else {
927d9de6389SEric Beckmann         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
9287687f046SEric Beckmann         NextLevelOffset += sizeof(coff_resource_dir_table) +
929d9de6389SEric Beckmann                            (Child.second->getStringChildren().size() +
930d9de6389SEric Beckmann                             Child.second->getIDChildren().size()) *
9317687f046SEric Beckmann                                sizeof(coff_resource_dir_entry);
932d9de6389SEric Beckmann         Queue.push(Child.second.get());
933d9de6389SEric Beckmann       }
9347687f046SEric Beckmann       CurrentOffset += sizeof(coff_resource_dir_entry);
9357687f046SEric Beckmann       CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
936d9de6389SEric Beckmann     }
937d9de6389SEric Beckmann   }
938d9de6389SEric Beckmann 
939d9de6389SEric Beckmann   RelocationAddresses.resize(Data.size());
940d9de6389SEric Beckmann   // Now write all the resource data entries.
941d9de6389SEric Beckmann   for (auto DataNodes : DataEntriesTreeOrder) {
9427687f046SEric Beckmann     auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart +
9437687f046SEric Beckmann                                                                CurrentOffset);
944d9de6389SEric Beckmann     RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
945d9de6389SEric Beckmann     Entry->DataRVA = 0; // Set to zero because it is a relocation.
946d9de6389SEric Beckmann     Entry->DataSize = Data[DataNodes->getDataIndex()].size();
947d9de6389SEric Beckmann     Entry->Codepage = 0;
948d9de6389SEric Beckmann     Entry->Reserved = 0;
9497687f046SEric Beckmann     CurrentOffset += sizeof(coff_resource_data_entry);
9507687f046SEric Beckmann     CurrentRelativeOffset += sizeof(coff_resource_data_entry);
951d9de6389SEric Beckmann   }
952d9de6389SEric Beckmann }
953d9de6389SEric Beckmann 
writeDirectoryStringTable()954d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
955d9de6389SEric Beckmann   // Now write the directory string table for .rsrc$01
956d9de6389SEric Beckmann   uint32_t TotalStringTableSize = 0;
9570096d78bSEric Beckmann   for (auto &String : StringTable) {
958d9de6389SEric Beckmann     uint16_t Length = String.size();
9591f76ca5aSEric Beckmann     support::endian::write16le(BufferStart + CurrentOffset, Length);
960382eaabbSEric Beckmann     CurrentOffset += sizeof(uint16_t);
961382eaabbSEric Beckmann     auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
96275709329SFangrui Song     llvm::copy(String, Start);
963382eaabbSEric Beckmann     CurrentOffset += Length * sizeof(UTF16);
964d9de6389SEric Beckmann     TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
965d9de6389SEric Beckmann   }
966382eaabbSEric Beckmann   CurrentOffset +=
967d9de6389SEric Beckmann       alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
968d9de6389SEric Beckmann }
969d9de6389SEric Beckmann 
writeFirstSectionRelocations()970d9de6389SEric Beckmann void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
971d9de6389SEric Beckmann 
972d9de6389SEric Beckmann   // Now write the relocations for .rsrc$01
973d9de6389SEric Beckmann   // Five symbols already in table before we start, @feat.00 and 2 for each
974d9de6389SEric Beckmann   // .rsrc section.
975d9de6389SEric Beckmann   uint32_t NextSymbolIndex = 5;
976d9de6389SEric Beckmann   for (unsigned i = 0; i < Data.size(); i++) {
9777687f046SEric Beckmann     auto *Reloc =
9787687f046SEric Beckmann         reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset);
979d9de6389SEric Beckmann     Reloc->VirtualAddress = RelocationAddresses[i];
980d9de6389SEric Beckmann     Reloc->SymbolTableIndex = NextSymbolIndex++;
981d9de6389SEric Beckmann     switch (MachineType) {
982d135e8c0SEric Beckmann     case COFF::IMAGE_FILE_MACHINE_ARMNT:
9837687f046SEric Beckmann       Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
984d9de6389SEric Beckmann       break;
985d135e8c0SEric Beckmann     case COFF::IMAGE_FILE_MACHINE_AMD64:
9867687f046SEric Beckmann       Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
987d9de6389SEric Beckmann       break;
988d135e8c0SEric Beckmann     case COFF::IMAGE_FILE_MACHINE_I386:
9897687f046SEric Beckmann       Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB;
990d9de6389SEric Beckmann       break;
991ba664c1dSMartin Storsjo     case COFF::IMAGE_FILE_MACHINE_ARM64:
992ba664c1dSMartin Storsjo       Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
993ba664c1dSMartin Storsjo       break;
994d9de6389SEric Beckmann     default:
995ba664c1dSMartin Storsjo       llvm_unreachable("unknown machine type");
996d9de6389SEric Beckmann     }
9977687f046SEric Beckmann     CurrentOffset += sizeof(coff_relocation);
998d9de6389SEric Beckmann   }
999d9de6389SEric Beckmann }
1000d9de6389SEric Beckmann 
1001ddcfbf7dSEric Beckmann Expected<std::unique_ptr<MemoryBuffer>>
writeWindowsResourceCOFF(COFF::MachineTypes MachineType,const WindowsResourceParser & Parser,uint32_t TimeDateStamp)1002ddcfbf7dSEric Beckmann writeWindowsResourceCOFF(COFF::MachineTypes MachineType,
1003dd601952SNico Weber                          const WindowsResourceParser &Parser,
1004dd601952SNico Weber                          uint32_t TimeDateStamp) {
1005d9de6389SEric Beckmann   Error E = Error::success();
1006ddcfbf7dSEric Beckmann   WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
1007d9de6389SEric Beckmann   if (E)
1008c55cf4afSBill Wendling     return std::move(E);
1009dd601952SNico Weber   return Writer.write(TimeDateStamp);
1010d9de6389SEric Beckmann }
1011d9de6389SEric Beckmann 
1012a6bdf751SEric Beckmann } // namespace object
1013a6bdf751SEric Beckmann } // namespace llvm
1014