xref: /src/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1b5630dbaSDimitry Andric //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
2b5630dbaSDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b5630dbaSDimitry Andric //
7b5630dbaSDimitry Andric //===----------------------------------------------------------------------===//
8b5630dbaSDimitry Andric //
9b5630dbaSDimitry Andric // This file implements the .res file class.
10b5630dbaSDimitry Andric //
11b5630dbaSDimitry Andric //===----------------------------------------------------------------------===//
12b5630dbaSDimitry Andric 
13b5630dbaSDimitry Andric #include "llvm/Object/WindowsResource.h"
147ab83427SDimitry Andric #include "llvm/Object/COFF.h"
15ac9a064cSDimitry Andric #include "llvm/Object/WindowsMachineFlag.h"
16c7dac04cSDimitry Andric #include "llvm/Support/FormatVariadic.h"
177ab83427SDimitry Andric #include "llvm/Support/MathExtras.h"
18e6d15924SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
197ab83427SDimitry Andric #include <ctime>
207ab83427SDimitry Andric #include <queue>
21b5630dbaSDimitry Andric 
2208bbd35aSDimitry Andric using namespace llvm;
2308bbd35aSDimitry Andric using namespace object;
2408bbd35aSDimitry Andric 
25b5630dbaSDimitry Andric namespace llvm {
26b5630dbaSDimitry Andric namespace object {
27b5630dbaSDimitry Andric 
28b5630dbaSDimitry Andric #define RETURN_IF_ERROR(X)                                                     \
29b5630dbaSDimitry Andric   if (auto EC = X)                                                             \
30b5630dbaSDimitry Andric     return EC;
31b5630dbaSDimitry Andric 
321d5ae102SDimitry Andric #define UNWRAP_REF_OR_RETURN(Name, Expr)                                       \
331d5ae102SDimitry Andric   auto Name##OrErr = Expr;                                                     \
341d5ae102SDimitry Andric   if (!Name##OrErr)                                                            \
351d5ae102SDimitry Andric     return Name##OrErr.takeError();                                            \
361d5ae102SDimitry Andric   const auto &Name = *Name##OrErr;
371d5ae102SDimitry Andric 
381d5ae102SDimitry Andric #define UNWRAP_OR_RETURN(Name, Expr)                                           \
391d5ae102SDimitry Andric   auto Name##OrErr = Expr;                                                     \
401d5ae102SDimitry Andric   if (!Name##OrErr)                                                            \
411d5ae102SDimitry Andric     return Name##OrErr.takeError();                                            \
421d5ae102SDimitry Andric   auto Name = *Name##OrErr;
431d5ae102SDimitry Andric 
44f382538dSDimitry Andric const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
45f382538dSDimitry Andric 
467c7aba6eSDimitry Andric // COFF files seem to be inconsistent with alignment between sections, just use
477c7aba6eSDimitry Andric // 8-byte because it makes everyone happy.
487c7aba6eSDimitry Andric const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
497c7aba6eSDimitry Andric 
WindowsResource(MemoryBufferRef Source)50b5630dbaSDimitry Andric WindowsResource::WindowsResource(MemoryBufferRef Source)
51b5630dbaSDimitry Andric     : Binary(Binary::ID_WinRes, Source) {
5208bbd35aSDimitry Andric   size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
53b5630dbaSDimitry Andric   BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
54b1c73532SDimitry Andric                          llvm::endianness::little);
55b5630dbaSDimitry Andric }
56b5630dbaSDimitry Andric 
57e6d15924SDimitry Andric // static
58b5630dbaSDimitry Andric Expected<std::unique_ptr<WindowsResource>>
createWindowsResource(MemoryBufferRef Source)59b5630dbaSDimitry Andric WindowsResource::createWindowsResource(MemoryBufferRef Source) {
6008bbd35aSDimitry Andric   if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
61b5630dbaSDimitry Andric     return make_error<GenericBinaryError>(
62e6d15924SDimitry Andric         Source.getBufferIdentifier() + ": too small to be a resource file",
63b5630dbaSDimitry Andric         object_error::invalid_file_type);
64b5630dbaSDimitry Andric   std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
65b5630dbaSDimitry Andric   return std::move(Ret);
66b5630dbaSDimitry Andric }
67b5630dbaSDimitry Andric 
getHeadEntry()68b5630dbaSDimitry Andric Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
69044eb2f6SDimitry Andric   if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix))
70e6d15924SDimitry Andric     return make_error<EmptyResError>(getFileName() + " contains no entries",
71044eb2f6SDimitry Andric                                      object_error::unexpected_eof);
72044eb2f6SDimitry Andric   return ResourceEntryRef::create(BinaryStreamRef(BBS), this);
73b5630dbaSDimitry Andric }
74b5630dbaSDimitry Andric 
ResourceEntryRef(BinaryStreamRef Ref,const WindowsResource * Owner)75b5630dbaSDimitry Andric ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
76044eb2f6SDimitry Andric                                    const WindowsResource *Owner)
77e6d15924SDimitry Andric     : Reader(Ref), Owner(Owner) {}
78044eb2f6SDimitry Andric 
79044eb2f6SDimitry Andric Expected<ResourceEntryRef>
create(BinaryStreamRef BSR,const WindowsResource * Owner)80044eb2f6SDimitry Andric ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) {
81044eb2f6SDimitry Andric   auto Ref = ResourceEntryRef(BSR, Owner);
82044eb2f6SDimitry Andric   if (auto E = Ref.loadNext())
83ac9a064cSDimitry Andric     return E;
84044eb2f6SDimitry Andric   return Ref;
85b5630dbaSDimitry Andric }
86b5630dbaSDimitry Andric 
moveNext(bool & End)87b5630dbaSDimitry Andric Error ResourceEntryRef::moveNext(bool &End) {
88b5630dbaSDimitry Andric   // Reached end of all the entries.
89b5630dbaSDimitry Andric   if (Reader.bytesRemaining() == 0) {
90b5630dbaSDimitry Andric     End = true;
91b5630dbaSDimitry Andric     return Error::success();
92b5630dbaSDimitry Andric   }
93b5630dbaSDimitry Andric   RETURN_IF_ERROR(loadNext());
94b5630dbaSDimitry Andric 
95b5630dbaSDimitry Andric   return Error::success();
96b5630dbaSDimitry Andric }
97b5630dbaSDimitry Andric 
readStringOrId(BinaryStreamReader & Reader,uint16_t & ID,ArrayRef<UTF16> & Str,bool & IsString)98f382538dSDimitry Andric static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
99f382538dSDimitry Andric                             ArrayRef<UTF16> &Str, bool &IsString) {
100f382538dSDimitry Andric   uint16_t IDFlag;
101f382538dSDimitry Andric   RETURN_IF_ERROR(Reader.readInteger(IDFlag));
102f382538dSDimitry Andric   IsString = IDFlag != 0xffff;
103f382538dSDimitry Andric 
104f382538dSDimitry Andric   if (IsString) {
105f382538dSDimitry Andric     Reader.setOffset(
106f382538dSDimitry Andric         Reader.getOffset() -
107f382538dSDimitry Andric         sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
108f382538dSDimitry Andric     RETURN_IF_ERROR(Reader.readWideString(Str));
109f382538dSDimitry Andric   } else
110f382538dSDimitry Andric     RETURN_IF_ERROR(Reader.readInteger(ID));
111f382538dSDimitry Andric 
112f382538dSDimitry Andric   return Error::success();
113f382538dSDimitry Andric }
114f382538dSDimitry Andric 
loadNext()115b5630dbaSDimitry Andric Error ResourceEntryRef::loadNext() {
11608bbd35aSDimitry Andric   const WinResHeaderPrefix *Prefix;
11708bbd35aSDimitry Andric   RETURN_IF_ERROR(Reader.readObject(Prefix));
118f382538dSDimitry Andric 
11908bbd35aSDimitry Andric   if (Prefix->HeaderSize < MIN_HEADER_SIZE)
120e6d15924SDimitry Andric     return make_error<GenericBinaryError>(Owner->getFileName() +
121e6d15924SDimitry Andric                                               ": header size too small",
122f382538dSDimitry Andric                                           object_error::parse_failed);
123f382538dSDimitry Andric 
124f382538dSDimitry Andric   RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
125f382538dSDimitry Andric 
126f382538dSDimitry Andric   RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
127f382538dSDimitry Andric 
12808bbd35aSDimitry Andric   RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
129f382538dSDimitry Andric 
130f382538dSDimitry Andric   RETURN_IF_ERROR(Reader.readObject(Suffix));
131f382538dSDimitry Andric 
13208bbd35aSDimitry Andric   RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
133f382538dSDimitry Andric 
13408bbd35aSDimitry Andric   RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
135f382538dSDimitry Andric 
136b5630dbaSDimitry Andric   return Error::success();
137b5630dbaSDimitry Andric }
138b5630dbaSDimitry Andric 
WindowsResourceParser(bool MinGW)1391d5ae102SDimitry Andric WindowsResourceParser::WindowsResourceParser(bool MinGW)
1401d5ae102SDimitry Andric     : Root(false), MinGW(MinGW) {}
141f382538dSDimitry Andric 
printResourceTypeName(uint16_t TypeID,raw_ostream & OS)142e6d15924SDimitry Andric void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) {
143e6d15924SDimitry Andric   switch (TypeID) {
144e6d15924SDimitry Andric   case  1: OS << "CURSOR (ID 1)"; break;
145e6d15924SDimitry Andric   case  2: OS << "BITMAP (ID 2)"; break;
146e6d15924SDimitry Andric   case  3: OS << "ICON (ID 3)"; break;
147e6d15924SDimitry Andric   case  4: OS << "MENU (ID 4)"; break;
148e6d15924SDimitry Andric   case  5: OS << "DIALOG (ID 5)"; break;
149e6d15924SDimitry Andric   case  6: OS << "STRINGTABLE (ID 6)"; break;
150e6d15924SDimitry Andric   case  7: OS << "FONTDIR (ID 7)"; break;
151e6d15924SDimitry Andric   case  8: OS << "FONT (ID 8)"; break;
152e6d15924SDimitry Andric   case  9: OS << "ACCELERATOR (ID 9)"; break;
153e6d15924SDimitry Andric   case 10: OS << "RCDATA (ID 10)"; break;
154e6d15924SDimitry Andric   case 11: OS << "MESSAGETABLE (ID 11)"; break;
155e6d15924SDimitry Andric   case 12: OS << "GROUP_CURSOR (ID 12)"; break;
156e6d15924SDimitry Andric   case 14: OS << "GROUP_ICON (ID 14)"; break;
157e6d15924SDimitry Andric   case 16: OS << "VERSIONINFO (ID 16)"; break;
158e6d15924SDimitry Andric   case 17: OS << "DLGINCLUDE (ID 17)"; break;
159e6d15924SDimitry Andric   case 19: OS << "PLUGPLAY (ID 19)"; break;
160e6d15924SDimitry Andric   case 20: OS << "VXD (ID 20)"; break;
161e6d15924SDimitry Andric   case 21: OS << "ANICURSOR (ID 21)"; break;
162e6d15924SDimitry Andric   case 22: OS << "ANIICON (ID 22)"; break;
163e6d15924SDimitry Andric   case 23: OS << "HTML (ID 23)"; break;
164e6d15924SDimitry Andric   case 24: OS << "MANIFEST (ID 24)"; break;
165e6d15924SDimitry Andric   default: OS << "ID " << TypeID; break;
166e6d15924SDimitry Andric   }
167e6d15924SDimitry Andric }
168e6d15924SDimitry Andric 
convertUTF16LEToUTF8String(ArrayRef<UTF16> Src,std::string & Out)169e6d15924SDimitry Andric static bool convertUTF16LEToUTF8String(ArrayRef<UTF16> Src, std::string &Out) {
170e6d15924SDimitry Andric   if (!sys::IsBigEndianHost)
171e6d15924SDimitry Andric     return convertUTF16ToUTF8String(Src, Out);
172e6d15924SDimitry Andric 
173e6d15924SDimitry Andric   std::vector<UTF16> EndianCorrectedSrc;
174e6d15924SDimitry Andric   EndianCorrectedSrc.resize(Src.size() + 1);
175e6d15924SDimitry Andric   llvm::copy(Src, EndianCorrectedSrc.begin() + 1);
176e6d15924SDimitry Andric   EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
177e3b55780SDimitry Andric   return convertUTF16ToUTF8String(ArrayRef(EndianCorrectedSrc), Out);
178e6d15924SDimitry Andric }
179e6d15924SDimitry Andric 
makeDuplicateResourceError(const ResourceEntryRef & Entry,StringRef File1,StringRef File2)180e6d15924SDimitry Andric static std::string makeDuplicateResourceError(
181e6d15924SDimitry Andric     const ResourceEntryRef &Entry, StringRef File1, StringRef File2) {
182e6d15924SDimitry Andric   std::string Ret;
183e6d15924SDimitry Andric   raw_string_ostream OS(Ret);
184e6d15924SDimitry Andric 
185e6d15924SDimitry Andric   OS << "duplicate resource:";
186e6d15924SDimitry Andric 
187e6d15924SDimitry Andric   OS << " type ";
188e6d15924SDimitry Andric   if (Entry.checkTypeString()) {
189e6d15924SDimitry Andric     std::string UTF8;
190e6d15924SDimitry Andric     if (!convertUTF16LEToUTF8String(Entry.getTypeString(), UTF8))
191e6d15924SDimitry Andric       UTF8 = "(failed conversion from UTF16)";
192e6d15924SDimitry Andric     OS << '\"' << UTF8 << '\"';
193e6d15924SDimitry Andric   } else
194e6d15924SDimitry Andric     printResourceTypeName(Entry.getTypeID(), OS);
195e6d15924SDimitry Andric 
196e6d15924SDimitry Andric   OS << "/name ";
197e6d15924SDimitry Andric   if (Entry.checkNameString()) {
198e6d15924SDimitry Andric     std::string UTF8;
199e6d15924SDimitry Andric     if (!convertUTF16LEToUTF8String(Entry.getNameString(), UTF8))
200e6d15924SDimitry Andric       UTF8 = "(failed conversion from UTF16)";
201e6d15924SDimitry Andric     OS << '\"' << UTF8 << '\"';
202e6d15924SDimitry Andric   } else {
203e6d15924SDimitry Andric     OS << "ID " << Entry.getNameID();
204e6d15924SDimitry Andric   }
205e6d15924SDimitry Andric 
206e6d15924SDimitry Andric   OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in "
207e6d15924SDimitry Andric      << File2;
208e6d15924SDimitry Andric 
209e6d15924SDimitry Andric   return OS.str();
210e6d15924SDimitry Andric }
211e6d15924SDimitry Andric 
printStringOrID(const WindowsResourceParser::StringOrID & S,raw_string_ostream & OS,bool IsType,bool IsID)2121d5ae102SDimitry Andric static void printStringOrID(const WindowsResourceParser::StringOrID &S,
2131d5ae102SDimitry Andric                             raw_string_ostream &OS, bool IsType, bool IsID) {
2141d5ae102SDimitry Andric   if (S.IsString) {
2151d5ae102SDimitry Andric     std::string UTF8;
2161d5ae102SDimitry Andric     if (!convertUTF16LEToUTF8String(S.String, UTF8))
2171d5ae102SDimitry Andric       UTF8 = "(failed conversion from UTF16)";
2181d5ae102SDimitry Andric     OS << '\"' << UTF8 << '\"';
2191d5ae102SDimitry Andric   } else if (IsType)
2201d5ae102SDimitry Andric     printResourceTypeName(S.ID, OS);
2211d5ae102SDimitry Andric   else if (IsID)
2221d5ae102SDimitry Andric     OS << "ID " << S.ID;
2231d5ae102SDimitry Andric   else
2241d5ae102SDimitry Andric     OS << S.ID;
2251d5ae102SDimitry Andric }
2261d5ae102SDimitry Andric 
makeDuplicateResourceError(const std::vector<WindowsResourceParser::StringOrID> & Context,StringRef File1,StringRef File2)2271d5ae102SDimitry Andric static std::string makeDuplicateResourceError(
2281d5ae102SDimitry Andric     const std::vector<WindowsResourceParser::StringOrID> &Context,
2291d5ae102SDimitry Andric     StringRef File1, StringRef File2) {
2301d5ae102SDimitry Andric   std::string Ret;
2311d5ae102SDimitry Andric   raw_string_ostream OS(Ret);
2321d5ae102SDimitry Andric 
2331d5ae102SDimitry Andric   OS << "duplicate resource:";
2341d5ae102SDimitry Andric 
2351d5ae102SDimitry Andric   if (Context.size() >= 1) {
2361d5ae102SDimitry Andric     OS << " type ";
2371d5ae102SDimitry Andric     printStringOrID(Context[0], OS, /* IsType */ true, /* IsID */ true);
2381d5ae102SDimitry Andric   }
2391d5ae102SDimitry Andric 
2401d5ae102SDimitry Andric   if (Context.size() >= 2) {
2411d5ae102SDimitry Andric     OS << "/name ";
2421d5ae102SDimitry Andric     printStringOrID(Context[1], OS, /* IsType */ false, /* IsID */ true);
2431d5ae102SDimitry Andric   }
2441d5ae102SDimitry Andric 
2451d5ae102SDimitry Andric   if (Context.size() >= 3) {
2461d5ae102SDimitry Andric     OS << "/language ";
2471d5ae102SDimitry Andric     printStringOrID(Context[2], OS, /* IsType */ false, /* IsID */ false);
2481d5ae102SDimitry Andric   }
2491d5ae102SDimitry Andric   OS << ", in " << File1 << " and in " << File2;
2501d5ae102SDimitry Andric 
2511d5ae102SDimitry Andric   return OS.str();
2521d5ae102SDimitry Andric }
2531d5ae102SDimitry Andric 
2541d5ae102SDimitry Andric // MinGW specific. Remove default manifests (with language zero) if there are
2551d5ae102SDimitry Andric // other manifests present, and report an error if there are more than one
2561d5ae102SDimitry Andric // manifest with a non-zero language code.
2571d5ae102SDimitry Andric // GCC has the concept of a default manifest resource object, which gets
2581d5ae102SDimitry Andric // linked in implicitly if present. This default manifest has got language
2591d5ae102SDimitry Andric // id zero, and should be dropped silently if there's another manifest present.
2601d5ae102SDimitry Andric // If the user resources surprisignly had a manifest with language id zero,
2611d5ae102SDimitry Andric // we should also ignore the duplicate default manifest.
cleanUpManifests(std::vector<std::string> & Duplicates)2621d5ae102SDimitry Andric void WindowsResourceParser::cleanUpManifests(
2631d5ae102SDimitry Andric     std::vector<std::string> &Duplicates) {
2641d5ae102SDimitry Andric   auto TypeIt = Root.IDChildren.find(/* RT_MANIFEST */ 24);
2651d5ae102SDimitry Andric   if (TypeIt == Root.IDChildren.end())
2661d5ae102SDimitry Andric     return;
2671d5ae102SDimitry Andric 
2681d5ae102SDimitry Andric   TreeNode *TypeNode = TypeIt->second.get();
2691d5ae102SDimitry Andric   auto NameIt =
2701d5ae102SDimitry Andric       TypeNode->IDChildren.find(/* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1);
2711d5ae102SDimitry Andric   if (NameIt == TypeNode->IDChildren.end())
2721d5ae102SDimitry Andric     return;
2731d5ae102SDimitry Andric 
2741d5ae102SDimitry Andric   TreeNode *NameNode = NameIt->second.get();
2751d5ae102SDimitry Andric   if (NameNode->IDChildren.size() <= 1)
2761d5ae102SDimitry Andric     return; // None or one manifest present, all good.
2771d5ae102SDimitry Andric 
2781d5ae102SDimitry Andric   // If we have more than one manifest, drop the language zero one if present,
2791d5ae102SDimitry Andric   // and check again.
2801d5ae102SDimitry Andric   auto LangZeroIt = NameNode->IDChildren.find(0);
2811d5ae102SDimitry Andric   if (LangZeroIt != NameNode->IDChildren.end() &&
2821d5ae102SDimitry Andric       LangZeroIt->second->IsDataNode) {
2831d5ae102SDimitry Andric     uint32_t RemovedIndex = LangZeroIt->second->DataIndex;
2841d5ae102SDimitry Andric     NameNode->IDChildren.erase(LangZeroIt);
2851d5ae102SDimitry Andric     Data.erase(Data.begin() + RemovedIndex);
2861d5ae102SDimitry Andric     Root.shiftDataIndexDown(RemovedIndex);
2871d5ae102SDimitry Andric 
2881d5ae102SDimitry Andric     // If we're now down to one manifest, all is good.
2891d5ae102SDimitry Andric     if (NameNode->IDChildren.size() <= 1)
2901d5ae102SDimitry Andric       return;
2911d5ae102SDimitry Andric   }
2921d5ae102SDimitry Andric 
2931d5ae102SDimitry Andric   // More than one non-language-zero manifest
2941d5ae102SDimitry Andric   auto FirstIt = NameNode->IDChildren.begin();
2951d5ae102SDimitry Andric   uint32_t FirstLang = FirstIt->first;
2961d5ae102SDimitry Andric   TreeNode *FirstNode = FirstIt->second.get();
2971d5ae102SDimitry Andric   auto LastIt = NameNode->IDChildren.rbegin();
2981d5ae102SDimitry Andric   uint32_t LastLang = LastIt->first;
2991d5ae102SDimitry Andric   TreeNode *LastNode = LastIt->second.get();
3001d5ae102SDimitry Andric   Duplicates.push_back(
3011d5ae102SDimitry Andric       ("duplicate non-default manifests with languages " + Twine(FirstLang) +
3021d5ae102SDimitry Andric        " in " + InputFilenames[FirstNode->Origin] + " and " + Twine(LastLang) +
3031d5ae102SDimitry Andric        " in " + InputFilenames[LastNode->Origin])
3041d5ae102SDimitry Andric           .str());
3051d5ae102SDimitry Andric }
3061d5ae102SDimitry Andric 
3071d5ae102SDimitry Andric // Ignore duplicates of manifests with language zero (the default manifest),
3081d5ae102SDimitry Andric // in case the user has provided a manifest with that language id. See
3091d5ae102SDimitry Andric // the function comment above for context. Only returns true if MinGW is set
3101d5ae102SDimitry Andric // to true.
shouldIgnoreDuplicate(const ResourceEntryRef & Entry) const3111d5ae102SDimitry Andric bool WindowsResourceParser::shouldIgnoreDuplicate(
3121d5ae102SDimitry Andric     const ResourceEntryRef &Entry) const {
3131d5ae102SDimitry Andric   return MinGW && !Entry.checkTypeString() &&
3141d5ae102SDimitry Andric          Entry.getTypeID() == /* RT_MANIFEST */ 24 &&
3151d5ae102SDimitry Andric          !Entry.checkNameString() &&
3161d5ae102SDimitry Andric          Entry.getNameID() == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
3171d5ae102SDimitry Andric          Entry.getLanguage() == 0;
3181d5ae102SDimitry Andric }
3191d5ae102SDimitry Andric 
shouldIgnoreDuplicate(const std::vector<StringOrID> & Context) const3201d5ae102SDimitry Andric bool WindowsResourceParser::shouldIgnoreDuplicate(
3211d5ae102SDimitry Andric     const std::vector<StringOrID> &Context) const {
3221d5ae102SDimitry Andric   return MinGW && Context.size() == 3 && !Context[0].IsString &&
3231d5ae102SDimitry Andric          Context[0].ID == /* RT_MANIFEST */ 24 && !Context[1].IsString &&
3241d5ae102SDimitry Andric          Context[1].ID == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
3251d5ae102SDimitry Andric          !Context[2].IsString && Context[2].ID == 0;
3261d5ae102SDimitry Andric }
3271d5ae102SDimitry Andric 
parse(WindowsResource * WR,std::vector<std::string> & Duplicates)328e6d15924SDimitry Andric Error WindowsResourceParser::parse(WindowsResource *WR,
329e6d15924SDimitry Andric                                    std::vector<std::string> &Duplicates) {
330f382538dSDimitry Andric   auto EntryOrErr = WR->getHeadEntry();
331044eb2f6SDimitry Andric   if (!EntryOrErr) {
332044eb2f6SDimitry Andric     auto E = EntryOrErr.takeError();
333044eb2f6SDimitry Andric     if (E.isA<EmptyResError>()) {
334044eb2f6SDimitry Andric       // Check if the .res file contains no entries.  In this case we don't have
335044eb2f6SDimitry Andric       // to throw an error but can rather just return without parsing anything.
336044eb2f6SDimitry Andric       // This applies for files which have a valid PE header magic and the
337044eb2f6SDimitry Andric       // mandatory empty null resource entry.  Files which do not fit this
338044eb2f6SDimitry Andric       // criteria would have already been filtered out by
339044eb2f6SDimitry Andric       // WindowsResource::createWindowsResource().
340044eb2f6SDimitry Andric       consumeError(std::move(E));
341044eb2f6SDimitry Andric       return Error::success();
342044eb2f6SDimitry Andric     }
343044eb2f6SDimitry Andric     return E;
344044eb2f6SDimitry Andric   }
345f382538dSDimitry Andric 
346f382538dSDimitry Andric   ResourceEntryRef Entry = EntryOrErr.get();
3471d5ae102SDimitry Andric   uint32_t Origin = InputFilenames.size();
348cfca06d7SDimitry Andric   InputFilenames.push_back(std::string(WR->getFileName()));
349f382538dSDimitry Andric   bool End = false;
350f382538dSDimitry Andric   while (!End) {
3517c7aba6eSDimitry Andric 
352e6d15924SDimitry Andric     TreeNode *Node;
3531d5ae102SDimitry Andric     bool IsNewNode = Root.addEntry(Entry, Origin, Data, StringTable, Node);
354e6d15924SDimitry Andric     if (!IsNewNode) {
3551d5ae102SDimitry Andric       if (!shouldIgnoreDuplicate(Entry))
356e6d15924SDimitry Andric         Duplicates.push_back(makeDuplicateResourceError(
357e6d15924SDimitry Andric             Entry, InputFilenames[Node->Origin], WR->getFileName()));
358e6d15924SDimitry Andric     }
3597c7aba6eSDimitry Andric 
360f382538dSDimitry Andric     RETURN_IF_ERROR(Entry.moveNext(End));
361f382538dSDimitry Andric   }
362f382538dSDimitry Andric 
363f382538dSDimitry Andric   return Error::success();
364f382538dSDimitry Andric }
365f382538dSDimitry Andric 
parse(ResourceSectionRef & RSR,StringRef Filename,std::vector<std::string> & Duplicates)3661d5ae102SDimitry Andric Error WindowsResourceParser::parse(ResourceSectionRef &RSR, StringRef Filename,
3671d5ae102SDimitry Andric                                    std::vector<std::string> &Duplicates) {
3681d5ae102SDimitry Andric   UNWRAP_REF_OR_RETURN(BaseTable, RSR.getBaseTable());
3691d5ae102SDimitry Andric   uint32_t Origin = InputFilenames.size();
370cfca06d7SDimitry Andric   InputFilenames.push_back(std::string(Filename));
3711d5ae102SDimitry Andric   std::vector<StringOrID> Context;
3721d5ae102SDimitry Andric   return addChildren(Root, RSR, BaseTable, Origin, Context, Duplicates);
3731d5ae102SDimitry Andric }
3741d5ae102SDimitry Andric 
printTree(raw_ostream & OS) const3757c7aba6eSDimitry Andric void WindowsResourceParser::printTree(raw_ostream &OS) const {
3767c7aba6eSDimitry Andric   ScopedPrinter Writer(OS);
377f382538dSDimitry Andric   Root.print(Writer, "Resource Tree");
378f382538dSDimitry Andric }
379f382538dSDimitry Andric 
addEntry(const ResourceEntryRef & Entry,uint32_t Origin,std::vector<std::vector<uint8_t>> & Data,std::vector<std::vector<UTF16>> & StringTable,TreeNode * & Result)3801d5ae102SDimitry Andric bool WindowsResourceParser::TreeNode::addEntry(
3811d5ae102SDimitry Andric     const ResourceEntryRef &Entry, uint32_t Origin,
3821d5ae102SDimitry Andric     std::vector<std::vector<uint8_t>> &Data,
3831d5ae102SDimitry Andric     std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result) {
3841d5ae102SDimitry Andric   TreeNode &TypeNode = addTypeNode(Entry, StringTable);
3851d5ae102SDimitry Andric   TreeNode &NameNode = TypeNode.addNameNode(Entry, StringTable);
3861d5ae102SDimitry Andric   return NameNode.addLanguageNode(Entry, Origin, Data, Result);
387f382538dSDimitry Andric }
388f382538dSDimitry Andric 
addChildren(TreeNode & Node,ResourceSectionRef & RSR,const coff_resource_dir_table & Table,uint32_t Origin,std::vector<StringOrID> & Context,std::vector<std::string> & Duplicates)3891d5ae102SDimitry Andric Error WindowsResourceParser::addChildren(TreeNode &Node,
3901d5ae102SDimitry Andric                                          ResourceSectionRef &RSR,
3911d5ae102SDimitry Andric                                          const coff_resource_dir_table &Table,
3921d5ae102SDimitry Andric                                          uint32_t Origin,
3931d5ae102SDimitry Andric                                          std::vector<StringOrID> &Context,
3941d5ae102SDimitry Andric                                          std::vector<std::string> &Duplicates) {
3951d5ae102SDimitry Andric 
3961d5ae102SDimitry Andric   for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
3971d5ae102SDimitry Andric        i++) {
3981d5ae102SDimitry Andric     UNWRAP_REF_OR_RETURN(Entry, RSR.getTableEntry(Table, i));
3991d5ae102SDimitry Andric     TreeNode *Child;
4001d5ae102SDimitry Andric 
4011d5ae102SDimitry Andric     if (Entry.Offset.isSubDir()) {
4021d5ae102SDimitry Andric 
4031d5ae102SDimitry Andric       // Create a new subdirectory and recurse
4041d5ae102SDimitry Andric       if (i < Table.NumberOfNameEntries) {
4051d5ae102SDimitry Andric         UNWRAP_OR_RETURN(NameString, RSR.getEntryNameString(Entry));
4061d5ae102SDimitry Andric         Child = &Node.addNameChild(NameString, StringTable);
4071d5ae102SDimitry Andric         Context.push_back(StringOrID(NameString));
4081d5ae102SDimitry Andric       } else {
4091d5ae102SDimitry Andric         Child = &Node.addIDChild(Entry.Identifier.ID);
4101d5ae102SDimitry Andric         Context.push_back(StringOrID(Entry.Identifier.ID));
4117ab83427SDimitry Andric       }
4127ab83427SDimitry Andric 
4131d5ae102SDimitry Andric       UNWRAP_REF_OR_RETURN(NextTable, RSR.getEntrySubDir(Entry));
4141d5ae102SDimitry Andric       Error E =
4151d5ae102SDimitry Andric           addChildren(*Child, RSR, NextTable, Origin, Context, Duplicates);
4161d5ae102SDimitry Andric       if (E)
4171d5ae102SDimitry Andric         return E;
4181d5ae102SDimitry Andric       Context.pop_back();
4191d5ae102SDimitry Andric 
4201d5ae102SDimitry Andric     } else {
4211d5ae102SDimitry Andric 
4221d5ae102SDimitry Andric       // Data leaves are supposed to have a numeric ID as identifier (language).
4231d5ae102SDimitry Andric       if (Table.NumberOfNameEntries > 0)
4241d5ae102SDimitry Andric         return createStringError(object_error::parse_failed,
4251d5ae102SDimitry Andric                                  "unexpected string key for data object");
4261d5ae102SDimitry Andric 
4271d5ae102SDimitry Andric       // Try adding a data leaf
4281d5ae102SDimitry Andric       UNWRAP_REF_OR_RETURN(DataEntry, RSR.getEntryData(Entry));
4291d5ae102SDimitry Andric       TreeNode *Child;
4301d5ae102SDimitry Andric       Context.push_back(StringOrID(Entry.Identifier.ID));
4311d5ae102SDimitry Andric       bool Added = Node.addDataChild(Entry.Identifier.ID, Table.MajorVersion,
4321d5ae102SDimitry Andric                                      Table.MinorVersion, Table.Characteristics,
4331d5ae102SDimitry Andric                                      Origin, Data.size(), Child);
4341d5ae102SDimitry Andric       if (Added) {
4351d5ae102SDimitry Andric         UNWRAP_OR_RETURN(Contents, RSR.getContents(DataEntry));
4361d5ae102SDimitry Andric         Data.push_back(ArrayRef<uint8_t>(
4371d5ae102SDimitry Andric             reinterpret_cast<const uint8_t *>(Contents.data()),
4381d5ae102SDimitry Andric             Contents.size()));
4391d5ae102SDimitry Andric       } else {
4401d5ae102SDimitry Andric         if (!shouldIgnoreDuplicate(Context))
4411d5ae102SDimitry Andric           Duplicates.push_back(makeDuplicateResourceError(
4421d5ae102SDimitry Andric               Context, InputFilenames[Child->Origin], InputFilenames.back()));
4431d5ae102SDimitry Andric       }
4441d5ae102SDimitry Andric       Context.pop_back();
4451d5ae102SDimitry Andric 
4461d5ae102SDimitry Andric     }
4471d5ae102SDimitry Andric   }
4481d5ae102SDimitry Andric   return Error::success();
4491d5ae102SDimitry Andric }
4501d5ae102SDimitry Andric 
TreeNode(uint32_t StringIndex)4511d5ae102SDimitry Andric WindowsResourceParser::TreeNode::TreeNode(uint32_t StringIndex)
4521d5ae102SDimitry Andric     : StringIndex(StringIndex) {}
4531d5ae102SDimitry Andric 
TreeNode(uint16_t MajorVersion,uint16_t MinorVersion,uint32_t Characteristics,uint32_t Origin,uint32_t DataIndex)4547ab83427SDimitry Andric WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
4557ab83427SDimitry Andric                                           uint16_t MinorVersion,
456e6d15924SDimitry Andric                                           uint32_t Characteristics,
4571d5ae102SDimitry Andric                                           uint32_t Origin, uint32_t DataIndex)
4581d5ae102SDimitry Andric     : IsDataNode(true), DataIndex(DataIndex), MajorVersion(MajorVersion),
4591d5ae102SDimitry Andric       MinorVersion(MinorVersion), Characteristics(Characteristics),
4601d5ae102SDimitry Andric       Origin(Origin) {}
4617ab83427SDimitry Andric 
4627ab83427SDimitry Andric std::unique_ptr<WindowsResourceParser::TreeNode>
createStringNode(uint32_t Index)4631d5ae102SDimitry Andric WindowsResourceParser::TreeNode::createStringNode(uint32_t Index) {
4641d5ae102SDimitry Andric   return std::unique_ptr<TreeNode>(new TreeNode(Index));
4657ab83427SDimitry Andric }
4667ab83427SDimitry Andric 
4677ab83427SDimitry Andric std::unique_ptr<WindowsResourceParser::TreeNode>
createIDNode()4687ab83427SDimitry Andric WindowsResourceParser::TreeNode::createIDNode() {
4691d5ae102SDimitry Andric   return std::unique_ptr<TreeNode>(new TreeNode(0));
4707ab83427SDimitry Andric }
4717ab83427SDimitry Andric 
4727ab83427SDimitry Andric std::unique_ptr<WindowsResourceParser::TreeNode>
createDataNode(uint16_t MajorVersion,uint16_t MinorVersion,uint32_t Characteristics,uint32_t Origin,uint32_t DataIndex)4737ab83427SDimitry Andric WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
4747ab83427SDimitry Andric                                                 uint16_t MinorVersion,
475e6d15924SDimitry Andric                                                 uint32_t Characteristics,
4761d5ae102SDimitry Andric                                                 uint32_t Origin,
4771d5ae102SDimitry Andric                                                 uint32_t DataIndex) {
4781d5ae102SDimitry Andric   return std::unique_ptr<TreeNode>(new TreeNode(
4791d5ae102SDimitry Andric       MajorVersion, MinorVersion, Characteristics, Origin, DataIndex));
4807ab83427SDimitry Andric }
481f382538dSDimitry Andric 
addTypeNode(const ResourceEntryRef & Entry,std::vector<std::vector<UTF16>> & StringTable)4821d5ae102SDimitry Andric WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addTypeNode(
4831d5ae102SDimitry Andric     const ResourceEntryRef &Entry,
4841d5ae102SDimitry Andric     std::vector<std::vector<UTF16>> &StringTable) {
485f382538dSDimitry Andric   if (Entry.checkTypeString())
4861d5ae102SDimitry Andric     return addNameChild(Entry.getTypeString(), StringTable);
487f382538dSDimitry Andric   else
488e6d15924SDimitry Andric     return addIDChild(Entry.getTypeID());
489f382538dSDimitry Andric }
490f382538dSDimitry Andric 
addNameNode(const ResourceEntryRef & Entry,std::vector<std::vector<UTF16>> & StringTable)4911d5ae102SDimitry Andric WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameNode(
4921d5ae102SDimitry Andric     const ResourceEntryRef &Entry,
4931d5ae102SDimitry Andric     std::vector<std::vector<UTF16>> &StringTable) {
494f382538dSDimitry Andric   if (Entry.checkNameString())
4951d5ae102SDimitry Andric     return addNameChild(Entry.getNameString(), StringTable);
496f382538dSDimitry Andric   else
497e6d15924SDimitry Andric     return addIDChild(Entry.getNameID());
498f382538dSDimitry Andric }
499f382538dSDimitry Andric 
addLanguageNode(const ResourceEntryRef & Entry,uint32_t Origin,std::vector<std::vector<uint8_t>> & Data,TreeNode * & Result)500e6d15924SDimitry Andric bool WindowsResourceParser::TreeNode::addLanguageNode(
5011d5ae102SDimitry Andric     const ResourceEntryRef &Entry, uint32_t Origin,
5021d5ae102SDimitry Andric     std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result) {
5031d5ae102SDimitry Andric   bool Added = addDataChild(Entry.getLanguage(), Entry.getMajorVersion(),
504e6d15924SDimitry Andric                             Entry.getMinorVersion(), Entry.getCharacteristics(),
5051d5ae102SDimitry Andric                             Origin, Data.size(), Result);
5061d5ae102SDimitry Andric   if (Added)
5071d5ae102SDimitry Andric     Data.push_back(Entry.getData());
5081d5ae102SDimitry Andric   return Added;
509f382538dSDimitry Andric }
510f382538dSDimitry Andric 
addDataChild(uint32_t ID,uint16_t MajorVersion,uint16_t MinorVersion,uint32_t Characteristics,uint32_t Origin,uint32_t DataIndex,TreeNode * & Result)511e6d15924SDimitry Andric bool WindowsResourceParser::TreeNode::addDataChild(
512e6d15924SDimitry Andric     uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
5131d5ae102SDimitry Andric     uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex,
5141d5ae102SDimitry Andric     TreeNode *&Result) {
5151d5ae102SDimitry Andric   auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics,
5161d5ae102SDimitry Andric                                  Origin, DataIndex);
517e6d15924SDimitry Andric   auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild));
518e6d15924SDimitry Andric   Result = ElementInserted.first->second.get();
519e6d15924SDimitry Andric   return ElementInserted.second;
520e6d15924SDimitry Andric }
521e6d15924SDimitry Andric 
addIDChild(uint32_t ID)522e6d15924SDimitry Andric WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild(
523e6d15924SDimitry Andric     uint32_t ID) {
524f382538dSDimitry Andric   auto Child = IDChildren.find(ID);
525f382538dSDimitry Andric   if (Child == IDChildren.end()) {
526e6d15924SDimitry Andric     auto NewChild = createIDNode();
527f382538dSDimitry Andric     WindowsResourceParser::TreeNode &Node = *NewChild;
528f382538dSDimitry Andric     IDChildren.emplace(ID, std::move(NewChild));
529f382538dSDimitry Andric     return Node;
530f382538dSDimitry Andric   } else
531f382538dSDimitry Andric     return *(Child->second);
532f382538dSDimitry Andric }
533f382538dSDimitry Andric 
addNameChild(ArrayRef<UTF16> NameRef,std::vector<std::vector<UTF16>> & StringTable)5341d5ae102SDimitry Andric WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameChild(
5351d5ae102SDimitry Andric     ArrayRef<UTF16> NameRef, std::vector<std::vector<UTF16>> &StringTable) {
536f382538dSDimitry Andric   std::string NameString;
537e6d15924SDimitry Andric   convertUTF16LEToUTF8String(NameRef, NameString);
538f382538dSDimitry Andric 
539f382538dSDimitry Andric   auto Child = StringChildren.find(NameString);
540f382538dSDimitry Andric   if (Child == StringChildren.end()) {
5411d5ae102SDimitry Andric     auto NewChild = createStringNode(StringTable.size());
5421d5ae102SDimitry Andric     StringTable.push_back(NameRef);
543f382538dSDimitry Andric     WindowsResourceParser::TreeNode &Node = *NewChild;
544f382538dSDimitry Andric     StringChildren.emplace(NameString, std::move(NewChild));
545f382538dSDimitry Andric     return Node;
546f382538dSDimitry Andric   } else
547f382538dSDimitry Andric     return *(Child->second);
548f382538dSDimitry Andric }
549f382538dSDimitry Andric 
print(ScopedPrinter & Writer,StringRef Name) const550f382538dSDimitry Andric void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
551f382538dSDimitry Andric                                             StringRef Name) const {
552f382538dSDimitry Andric   ListScope NodeScope(Writer, Name);
553f382538dSDimitry Andric   for (auto const &Child : StringChildren) {
554f382538dSDimitry Andric     Child.second->print(Writer, Child.first);
555f382538dSDimitry Andric   }
556f382538dSDimitry Andric   for (auto const &Child : IDChildren) {
557f382538dSDimitry Andric     Child.second->print(Writer, to_string(Child.first));
558f382538dSDimitry Andric   }
559f382538dSDimitry Andric }
560f382538dSDimitry Andric 
5617ab83427SDimitry Andric // This function returns the size of the entire resource tree, including
5627ab83427SDimitry Andric // directory tables, directory entries, and data entries.  It does not include
5637ab83427SDimitry Andric // the directory strings or the relocations of the .rsrc section.
getTreeSize() const5647ab83427SDimitry Andric uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
5657ab83427SDimitry Andric   uint32_t Size = (IDChildren.size() + StringChildren.size()) *
56608bbd35aSDimitry Andric                   sizeof(coff_resource_dir_entry);
5677ab83427SDimitry Andric 
5687ab83427SDimitry Andric   // Reached a node pointing to a data entry.
5697ab83427SDimitry Andric   if (IsDataNode) {
57008bbd35aSDimitry Andric     Size += sizeof(coff_resource_data_entry);
5717ab83427SDimitry Andric     return Size;
5727ab83427SDimitry Andric   }
5737ab83427SDimitry Andric 
5747ab83427SDimitry Andric   // If the node does not point to data, it must have a directory table pointing
5757ab83427SDimitry Andric   // to other nodes.
57608bbd35aSDimitry Andric   Size += sizeof(coff_resource_dir_table);
5777ab83427SDimitry Andric 
5787ab83427SDimitry Andric   for (auto const &Child : StringChildren) {
5797ab83427SDimitry Andric     Size += Child.second->getTreeSize();
5807ab83427SDimitry Andric   }
5817ab83427SDimitry Andric   for (auto const &Child : IDChildren) {
5827ab83427SDimitry Andric     Size += Child.second->getTreeSize();
5837ab83427SDimitry Andric   }
5847ab83427SDimitry Andric   return Size;
5857ab83427SDimitry Andric }
5867ab83427SDimitry Andric 
5871d5ae102SDimitry Andric // Shift DataIndex of all data children with an Index greater or equal to the
5881d5ae102SDimitry Andric // given one, to fill a gap from removing an entry from the Data vector.
shiftDataIndexDown(uint32_t Index)5891d5ae102SDimitry Andric void WindowsResourceParser::TreeNode::shiftDataIndexDown(uint32_t Index) {
5901d5ae102SDimitry Andric   if (IsDataNode && DataIndex >= Index) {
5911d5ae102SDimitry Andric     DataIndex--;
5921d5ae102SDimitry Andric   } else {
5931d5ae102SDimitry Andric     for (auto &Child : IDChildren)
5941d5ae102SDimitry Andric       Child.second->shiftDataIndexDown(Index);
5951d5ae102SDimitry Andric     for (auto &Child : StringChildren)
5961d5ae102SDimitry Andric       Child.second->shiftDataIndexDown(Index);
5971d5ae102SDimitry Andric   }
5981d5ae102SDimitry Andric }
5991d5ae102SDimitry Andric 
6007ab83427SDimitry Andric class WindowsResourceCOFFWriter {
6017ab83427SDimitry Andric public:
60208bbd35aSDimitry Andric   WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,
6037ab83427SDimitry Andric                             const WindowsResourceParser &Parser, Error &E);
604e6d15924SDimitry Andric   std::unique_ptr<MemoryBuffer> write(uint32_t TimeDateStamp);
6057ab83427SDimitry Andric 
6067ab83427SDimitry Andric private:
6077ab83427SDimitry Andric   void performFileLayout();
6087ab83427SDimitry Andric   void performSectionOneLayout();
6097ab83427SDimitry Andric   void performSectionTwoLayout();
610e6d15924SDimitry Andric   void writeCOFFHeader(uint32_t TimeDateStamp);
6117ab83427SDimitry Andric   void writeFirstSectionHeader();
6127ab83427SDimitry Andric   void writeSecondSectionHeader();
6137ab83427SDimitry Andric   void writeFirstSection();
6147ab83427SDimitry Andric   void writeSecondSection();
6157ab83427SDimitry Andric   void writeSymbolTable();
6167ab83427SDimitry Andric   void writeStringTable();
6177ab83427SDimitry Andric   void writeDirectoryTree();
6187ab83427SDimitry Andric   void writeDirectoryStringTable();
6197ab83427SDimitry Andric   void writeFirstSectionRelocations();
620eb11fae6SDimitry Andric   std::unique_ptr<WritableMemoryBuffer> OutputBuffer;
62108bbd35aSDimitry Andric   char *BufferStart;
6227c7aba6eSDimitry Andric   uint64_t CurrentOffset = 0;
62308bbd35aSDimitry Andric   COFF::MachineTypes MachineType;
6247ab83427SDimitry Andric   const WindowsResourceParser::TreeNode &Resources;
6257ab83427SDimitry Andric   const ArrayRef<std::vector<uint8_t>> Data;
6267ab83427SDimitry Andric   uint64_t FileSize;
6277ab83427SDimitry Andric   uint32_t SymbolTableOffset;
6287ab83427SDimitry Andric   uint32_t SectionOneSize;
6297ab83427SDimitry Andric   uint32_t SectionOneOffset;
6307ab83427SDimitry Andric   uint32_t SectionOneRelocations;
6317ab83427SDimitry Andric   uint32_t SectionTwoSize;
6327ab83427SDimitry Andric   uint32_t SectionTwoOffset;
6337ab83427SDimitry Andric   const ArrayRef<std::vector<UTF16>> StringTable;
6347ab83427SDimitry Andric   std::vector<uint32_t> StringTableOffsets;
6357ab83427SDimitry Andric   std::vector<uint32_t> DataOffsets;
6367ab83427SDimitry Andric   std::vector<uint32_t> RelocationAddresses;
6377ab83427SDimitry Andric };
6387ab83427SDimitry Andric 
WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,const WindowsResourceParser & Parser,Error & E)6397ab83427SDimitry Andric WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
64008bbd35aSDimitry Andric     COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
64108bbd35aSDimitry Andric     Error &E)
6427ab83427SDimitry Andric     : MachineType(MachineType), Resources(Parser.getTree()),
6437ab83427SDimitry Andric       Data(Parser.getData()), StringTable(Parser.getStringTable()) {
6447ab83427SDimitry Andric   performFileLayout();
6457ab83427SDimitry Andric 
646e6d15924SDimitry Andric   OutputBuffer = WritableMemoryBuffer::getNewMemBuffer(
647e6d15924SDimitry Andric       FileSize, "internal .obj file created from .res files");
6487ab83427SDimitry Andric }
6497ab83427SDimitry Andric 
performFileLayout()6507ab83427SDimitry Andric void WindowsResourceCOFFWriter::performFileLayout() {
6517ab83427SDimitry Andric   // Add size of COFF header.
65208bbd35aSDimitry Andric   FileSize = COFF::Header16Size;
6537ab83427SDimitry Andric 
6547ab83427SDimitry Andric   // one .rsrc section header for directory tree, another for resource data.
65508bbd35aSDimitry Andric   FileSize += 2 * COFF::SectionSize;
6567ab83427SDimitry Andric 
6577ab83427SDimitry Andric   performSectionOneLayout();
6587ab83427SDimitry Andric   performSectionTwoLayout();
6597ab83427SDimitry Andric 
6607ab83427SDimitry Andric   // We have reached the address of the symbol table.
6617ab83427SDimitry Andric   SymbolTableOffset = FileSize;
6627ab83427SDimitry Andric 
66308bbd35aSDimitry Andric   FileSize += COFF::Symbol16Size;     // size of the @feat.00 symbol.
66408bbd35aSDimitry Andric   FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
66508bbd35aSDimitry Andric   FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
6667ab83427SDimitry Andric   FileSize += 4; // four null bytes for the string table.
6677ab83427SDimitry Andric }
6687ab83427SDimitry Andric 
performSectionOneLayout()6697ab83427SDimitry Andric void WindowsResourceCOFFWriter::performSectionOneLayout() {
6707ab83427SDimitry Andric   SectionOneOffset = FileSize;
6717ab83427SDimitry Andric 
6727ab83427SDimitry Andric   SectionOneSize = Resources.getTreeSize();
6737ab83427SDimitry Andric   uint32_t CurrentStringOffset = SectionOneSize;
6747ab83427SDimitry Andric   uint32_t TotalStringTableSize = 0;
6757ab83427SDimitry Andric   for (auto const &String : StringTable) {
6767ab83427SDimitry Andric     StringTableOffsets.push_back(CurrentStringOffset);
6777ab83427SDimitry Andric     uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
6787ab83427SDimitry Andric     CurrentStringOffset += StringSize;
6797ab83427SDimitry Andric     TotalStringTableSize += StringSize;
6807ab83427SDimitry Andric   }
6817ab83427SDimitry Andric   SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
6827ab83427SDimitry Andric 
6837ab83427SDimitry Andric   // account for the relocations of section one.
6847ab83427SDimitry Andric   SectionOneRelocations = FileSize + SectionOneSize;
6857ab83427SDimitry Andric   FileSize += SectionOneSize;
68608bbd35aSDimitry Andric   FileSize +=
68708bbd35aSDimitry Andric       Data.size() * COFF::RelocationSize; // one relocation for each resource.
6887c7aba6eSDimitry Andric   FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
6897ab83427SDimitry Andric }
6907ab83427SDimitry Andric 
performSectionTwoLayout()6917ab83427SDimitry Andric void WindowsResourceCOFFWriter::performSectionTwoLayout() {
6927ab83427SDimitry Andric   // add size of .rsrc$2 section, which contains all resource data on 8-byte
6937ab83427SDimitry Andric   // alignment.
6947ab83427SDimitry Andric   SectionTwoOffset = FileSize;
6957ab83427SDimitry Andric   SectionTwoSize = 0;
6967ab83427SDimitry Andric   for (auto const &Entry : Data) {
6977ab83427SDimitry Andric     DataOffsets.push_back(SectionTwoSize);
69808bbd35aSDimitry Andric     SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
6997ab83427SDimitry Andric   }
7007ab83427SDimitry Andric   FileSize += SectionTwoSize;
7017c7aba6eSDimitry Andric   FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
7027ab83427SDimitry Andric }
7037ab83427SDimitry Andric 
704e6d15924SDimitry Andric std::unique_ptr<MemoryBuffer>
write(uint32_t TimeDateStamp)705e6d15924SDimitry Andric WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) {
706eb11fae6SDimitry Andric   BufferStart = OutputBuffer->getBufferStart();
7077ab83427SDimitry Andric 
708e6d15924SDimitry Andric   writeCOFFHeader(TimeDateStamp);
7097ab83427SDimitry Andric   writeFirstSectionHeader();
7107ab83427SDimitry Andric   writeSecondSectionHeader();
7117ab83427SDimitry Andric   writeFirstSection();
7127ab83427SDimitry Andric   writeSecondSection();
7137ab83427SDimitry Andric   writeSymbolTable();
7147ab83427SDimitry Andric   writeStringTable();
7157ab83427SDimitry Andric 
71608bbd35aSDimitry Andric   return std::move(OutputBuffer);
7177ab83427SDimitry Andric }
7187ab83427SDimitry Andric 
7191d5ae102SDimitry Andric // According to COFF specification, if the Src has a size equal to Dest,
7201d5ae102SDimitry Andric // it's okay to *not* copy the trailing zero.
coffnamecpy(char (& Dest)[COFF::NameSize],StringRef Src)7211d5ae102SDimitry Andric static void coffnamecpy(char (&Dest)[COFF::NameSize], StringRef Src) {
7221d5ae102SDimitry Andric   assert(Src.size() <= COFF::NameSize &&
723cfca06d7SDimitry Andric          "Src is larger than COFF::NameSize");
724cfca06d7SDimitry Andric   assert((Src.size() == COFF::NameSize || Dest[Src.size()] == '\0') &&
725cfca06d7SDimitry Andric          "Dest not zeroed upon initialization");
726cfca06d7SDimitry Andric   memcpy(Dest, Src.data(), Src.size());
7271d5ae102SDimitry Andric }
7281d5ae102SDimitry Andric 
writeCOFFHeader(uint32_t TimeDateStamp)729e6d15924SDimitry Andric void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) {
7307ab83427SDimitry Andric   // Write the COFF header.
73108bbd35aSDimitry Andric   auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
732044eb2f6SDimitry Andric   Header->Machine = MachineType;
7337ab83427SDimitry Andric   Header->NumberOfSections = 2;
734e6d15924SDimitry Andric   Header->TimeDateStamp = TimeDateStamp;
7357ab83427SDimitry Andric   Header->PointerToSymbolTable = SymbolTableOffset;
736e6d15924SDimitry Andric   // One symbol for every resource plus 2 for each section and 1 for @feat.00
7377ab83427SDimitry Andric   Header->NumberOfSymbols = Data.size() + 5;
7387ab83427SDimitry Andric   Header->SizeOfOptionalHeader = 0;
739e6d15924SDimitry Andric   // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it.
74008bbd35aSDimitry Andric   Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
7417ab83427SDimitry Andric }
7427ab83427SDimitry Andric 
writeFirstSectionHeader()7437ab83427SDimitry Andric void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
7447ab83427SDimitry Andric   // Write the first section header.
74508bbd35aSDimitry Andric   CurrentOffset += sizeof(coff_file_header);
74608bbd35aSDimitry Andric   auto *SectionOneHeader =
74708bbd35aSDimitry Andric       reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
7481d5ae102SDimitry Andric   coffnamecpy(SectionOneHeader->Name, ".rsrc$01");
7497ab83427SDimitry Andric   SectionOneHeader->VirtualSize = 0;
7507ab83427SDimitry Andric   SectionOneHeader->VirtualAddress = 0;
7517ab83427SDimitry Andric   SectionOneHeader->SizeOfRawData = SectionOneSize;
7527ab83427SDimitry Andric   SectionOneHeader->PointerToRawData = SectionOneOffset;
7537ab83427SDimitry Andric   SectionOneHeader->PointerToRelocations = SectionOneRelocations;
7547ab83427SDimitry Andric   SectionOneHeader->PointerToLinenumbers = 0;
7557ab83427SDimitry Andric   SectionOneHeader->NumberOfRelocations = Data.size();
7567ab83427SDimitry Andric   SectionOneHeader->NumberOfLinenumbers = 0;
75708bbd35aSDimitry Andric   SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
75808bbd35aSDimitry Andric   SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
7597ab83427SDimitry Andric }
7607ab83427SDimitry Andric 
writeSecondSectionHeader()7617ab83427SDimitry Andric void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
7627ab83427SDimitry Andric   // Write the second section header.
76308bbd35aSDimitry Andric   CurrentOffset += sizeof(coff_section);
76408bbd35aSDimitry Andric   auto *SectionTwoHeader =
76508bbd35aSDimitry Andric       reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
7661d5ae102SDimitry Andric   coffnamecpy(SectionTwoHeader->Name, ".rsrc$02");
7677ab83427SDimitry Andric   SectionTwoHeader->VirtualSize = 0;
7687ab83427SDimitry Andric   SectionTwoHeader->VirtualAddress = 0;
7697ab83427SDimitry Andric   SectionTwoHeader->SizeOfRawData = SectionTwoSize;
7707ab83427SDimitry Andric   SectionTwoHeader->PointerToRawData = SectionTwoOffset;
7717ab83427SDimitry Andric   SectionTwoHeader->PointerToRelocations = 0;
7727ab83427SDimitry Andric   SectionTwoHeader->PointerToLinenumbers = 0;
7737ab83427SDimitry Andric   SectionTwoHeader->NumberOfRelocations = 0;
7747ab83427SDimitry Andric   SectionTwoHeader->NumberOfLinenumbers = 0;
77508bbd35aSDimitry Andric   SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
77608bbd35aSDimitry Andric   SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
7777ab83427SDimitry Andric }
7787ab83427SDimitry Andric 
writeFirstSection()7797ab83427SDimitry Andric void WindowsResourceCOFFWriter::writeFirstSection() {
7807ab83427SDimitry Andric   // Write section one.
78108bbd35aSDimitry Andric   CurrentOffset += sizeof(coff_section);
7827ab83427SDimitry Andric 
7837ab83427SDimitry Andric   writeDirectoryTree();
7847ab83427SDimitry Andric   writeDirectoryStringTable();
7857ab83427SDimitry Andric   writeFirstSectionRelocations();
7867c7aba6eSDimitry Andric 
7877c7aba6eSDimitry Andric   CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
7887ab83427SDimitry Andric }
7897ab83427SDimitry Andric 
writeSecondSection()7907ab83427SDimitry Andric void WindowsResourceCOFFWriter::writeSecondSection() {
7917ab83427SDimitry Andric   // Now write the .rsrc$02 section.
7927ab83427SDimitry Andric   for (auto const &RawDataEntry : Data) {
793d8e91e46SDimitry Andric     llvm::copy(RawDataEntry, BufferStart + CurrentOffset);
7947c7aba6eSDimitry Andric     CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
7957ab83427SDimitry Andric   }
7967c7aba6eSDimitry Andric 
7977c7aba6eSDimitry Andric   CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
7987ab83427SDimitry Andric }
7997ab83427SDimitry Andric 
writeSymbolTable()8007ab83427SDimitry Andric void WindowsResourceCOFFWriter::writeSymbolTable() {
8017ab83427SDimitry Andric   // Now write the symbol table.
8027ab83427SDimitry Andric   // First, the feat symbol.
80308bbd35aSDimitry Andric   auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
8041d5ae102SDimitry Andric   coffnamecpy(Symbol->Name.ShortName, "@feat.00");
8057ab83427SDimitry Andric   Symbol->Value = 0x11;
8067ab83427SDimitry Andric   Symbol->SectionNumber = 0xffff;
80708bbd35aSDimitry Andric   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
80808bbd35aSDimitry Andric   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
8097ab83427SDimitry Andric   Symbol->NumberOfAuxSymbols = 0;
81008bbd35aSDimitry Andric   CurrentOffset += sizeof(coff_symbol16);
8117ab83427SDimitry Andric 
8127ab83427SDimitry Andric   // Now write the .rsrc1 symbol + aux.
81308bbd35aSDimitry Andric   Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
8141d5ae102SDimitry Andric   coffnamecpy(Symbol->Name.ShortName, ".rsrc$01");
8157ab83427SDimitry Andric   Symbol->Value = 0;
8167ab83427SDimitry Andric   Symbol->SectionNumber = 1;
81708bbd35aSDimitry Andric   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
81808bbd35aSDimitry Andric   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
8197ab83427SDimitry Andric   Symbol->NumberOfAuxSymbols = 1;
82008bbd35aSDimitry Andric   CurrentOffset += sizeof(coff_symbol16);
82108bbd35aSDimitry Andric   auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
82208bbd35aSDimitry Andric                                                               CurrentOffset);
8237ab83427SDimitry Andric   Aux->Length = SectionOneSize;
8247ab83427SDimitry Andric   Aux->NumberOfRelocations = Data.size();
8257ab83427SDimitry Andric   Aux->NumberOfLinenumbers = 0;
8267ab83427SDimitry Andric   Aux->CheckSum = 0;
8277ab83427SDimitry Andric   Aux->NumberLowPart = 0;
8287ab83427SDimitry Andric   Aux->Selection = 0;
82908bbd35aSDimitry Andric   CurrentOffset += sizeof(coff_aux_section_definition);
8307ab83427SDimitry Andric 
8317ab83427SDimitry Andric   // Now write the .rsrc2 symbol + aux.
83208bbd35aSDimitry Andric   Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
8331d5ae102SDimitry Andric   coffnamecpy(Symbol->Name.ShortName, ".rsrc$02");
8347ab83427SDimitry Andric   Symbol->Value = 0;
8357ab83427SDimitry Andric   Symbol->SectionNumber = 2;
83608bbd35aSDimitry Andric   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
83708bbd35aSDimitry Andric   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
8387ab83427SDimitry Andric   Symbol->NumberOfAuxSymbols = 1;
83908bbd35aSDimitry Andric   CurrentOffset += sizeof(coff_symbol16);
84008bbd35aSDimitry Andric   Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
84108bbd35aSDimitry Andric                                                         CurrentOffset);
8427ab83427SDimitry Andric   Aux->Length = SectionTwoSize;
8437ab83427SDimitry Andric   Aux->NumberOfRelocations = 0;
8447ab83427SDimitry Andric   Aux->NumberOfLinenumbers = 0;
8457ab83427SDimitry Andric   Aux->CheckSum = 0;
8467ab83427SDimitry Andric   Aux->NumberLowPart = 0;
8477ab83427SDimitry Andric   Aux->Selection = 0;
84808bbd35aSDimitry Andric   CurrentOffset += sizeof(coff_aux_section_definition);
8497ab83427SDimitry Andric 
8507ab83427SDimitry Andric   // Now write a symbol for each relocation.
8517ab83427SDimitry Andric   for (unsigned i = 0; i < Data.size(); i++) {
852c7dac04cSDimitry Andric     auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
85308bbd35aSDimitry Andric     Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
8541d5ae102SDimitry Andric     coffnamecpy(Symbol->Name.ShortName, RelocationName);
8557ab83427SDimitry Andric     Symbol->Value = DataOffsets[i];
8569df3605dSDimitry Andric     Symbol->SectionNumber = 2;
85708bbd35aSDimitry Andric     Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
85808bbd35aSDimitry Andric     Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
8597ab83427SDimitry Andric     Symbol->NumberOfAuxSymbols = 0;
86008bbd35aSDimitry Andric     CurrentOffset += sizeof(coff_symbol16);
8617ab83427SDimitry Andric   }
8627ab83427SDimitry Andric }
8637ab83427SDimitry Andric 
writeStringTable()8647ab83427SDimitry Andric void WindowsResourceCOFFWriter::writeStringTable() {
8657ab83427SDimitry Andric   // Just 4 null bytes for the string table.
8667c7aba6eSDimitry Andric   auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
8677c7aba6eSDimitry Andric   memset(COFFStringTable, 0, 4);
8687ab83427SDimitry Andric }
8697ab83427SDimitry Andric 
writeDirectoryTree()8707ab83427SDimitry Andric void WindowsResourceCOFFWriter::writeDirectoryTree() {
8717ab83427SDimitry Andric   // Traverse parsed resource tree breadth-first and write the corresponding
8727ab83427SDimitry Andric   // COFF objects.
8737ab83427SDimitry Andric   std::queue<const WindowsResourceParser::TreeNode *> Queue;
8747ab83427SDimitry Andric   Queue.push(&Resources);
87508bbd35aSDimitry Andric   uint32_t NextLevelOffset =
87608bbd35aSDimitry Andric       sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() +
8777ab83427SDimitry Andric                                          Resources.getIDChildren().size()) *
87808bbd35aSDimitry Andric                                             sizeof(coff_resource_dir_entry);
8797ab83427SDimitry Andric   std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
8807ab83427SDimitry Andric   uint32_t CurrentRelativeOffset = 0;
8817ab83427SDimitry Andric 
8827ab83427SDimitry Andric   while (!Queue.empty()) {
8837ab83427SDimitry Andric     auto CurrentNode = Queue.front();
8847ab83427SDimitry Andric     Queue.pop();
88508bbd35aSDimitry Andric     auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart +
88608bbd35aSDimitry Andric                                                               CurrentOffset);
8877ab83427SDimitry Andric     Table->Characteristics = CurrentNode->getCharacteristics();
8887ab83427SDimitry Andric     Table->TimeDateStamp = 0;
8897ab83427SDimitry Andric     Table->MajorVersion = CurrentNode->getMajorVersion();
8907ab83427SDimitry Andric     Table->MinorVersion = CurrentNode->getMinorVersion();
8917ab83427SDimitry Andric     auto &IDChildren = CurrentNode->getIDChildren();
8927ab83427SDimitry Andric     auto &StringChildren = CurrentNode->getStringChildren();
8937ab83427SDimitry Andric     Table->NumberOfNameEntries = StringChildren.size();
8947ab83427SDimitry Andric     Table->NumberOfIDEntries = IDChildren.size();
89508bbd35aSDimitry Andric     CurrentOffset += sizeof(coff_resource_dir_table);
89608bbd35aSDimitry Andric     CurrentRelativeOffset += sizeof(coff_resource_dir_table);
8977ab83427SDimitry Andric 
8987ab83427SDimitry Andric     // Write the directory entries immediately following each directory table.
8997ab83427SDimitry Andric     for (auto const &Child : StringChildren) {
90008bbd35aSDimitry Andric       auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
90108bbd35aSDimitry Andric                                                                 CurrentOffset);
902ca089b24SDimitry Andric       Entry->Identifier.setNameOffset(
903ca089b24SDimitry Andric           StringTableOffsets[Child.second->getStringIndex()]);
9047ab83427SDimitry Andric       if (Child.second->checkIsDataNode()) {
9057ab83427SDimitry Andric         Entry->Offset.DataEntryOffset = NextLevelOffset;
90608bbd35aSDimitry Andric         NextLevelOffset += sizeof(coff_resource_data_entry);
9077ab83427SDimitry Andric         DataEntriesTreeOrder.push_back(Child.second.get());
9087ab83427SDimitry Andric       } else {
9097ab83427SDimitry Andric         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
91008bbd35aSDimitry Andric         NextLevelOffset += sizeof(coff_resource_dir_table) +
9117ab83427SDimitry Andric                            (Child.second->getStringChildren().size() +
9127ab83427SDimitry Andric                             Child.second->getIDChildren().size()) *
91308bbd35aSDimitry Andric                                sizeof(coff_resource_dir_entry);
9147ab83427SDimitry Andric         Queue.push(Child.second.get());
9157ab83427SDimitry Andric       }
91608bbd35aSDimitry Andric       CurrentOffset += sizeof(coff_resource_dir_entry);
91708bbd35aSDimitry Andric       CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
9187ab83427SDimitry Andric     }
9197ab83427SDimitry Andric     for (auto const &Child : IDChildren) {
92008bbd35aSDimitry Andric       auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
92108bbd35aSDimitry Andric                                                                 CurrentOffset);
9227ab83427SDimitry Andric       Entry->Identifier.ID = Child.first;
9237ab83427SDimitry Andric       if (Child.second->checkIsDataNode()) {
9247ab83427SDimitry Andric         Entry->Offset.DataEntryOffset = NextLevelOffset;
92508bbd35aSDimitry Andric         NextLevelOffset += sizeof(coff_resource_data_entry);
9267ab83427SDimitry Andric         DataEntriesTreeOrder.push_back(Child.second.get());
9277ab83427SDimitry Andric       } else {
9287ab83427SDimitry Andric         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
92908bbd35aSDimitry Andric         NextLevelOffset += sizeof(coff_resource_dir_table) +
9307ab83427SDimitry Andric                            (Child.second->getStringChildren().size() +
9317ab83427SDimitry Andric                             Child.second->getIDChildren().size()) *
93208bbd35aSDimitry Andric                                sizeof(coff_resource_dir_entry);
9337ab83427SDimitry Andric         Queue.push(Child.second.get());
9347ab83427SDimitry Andric       }
93508bbd35aSDimitry Andric       CurrentOffset += sizeof(coff_resource_dir_entry);
93608bbd35aSDimitry Andric       CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
9377ab83427SDimitry Andric     }
9387ab83427SDimitry Andric   }
9397ab83427SDimitry Andric 
9407ab83427SDimitry Andric   RelocationAddresses.resize(Data.size());
9417ab83427SDimitry Andric   // Now write all the resource data entries.
942e3b55780SDimitry Andric   for (const auto *DataNodes : DataEntriesTreeOrder) {
94308bbd35aSDimitry Andric     auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart +
94408bbd35aSDimitry Andric                                                                CurrentOffset);
9457ab83427SDimitry Andric     RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
9467ab83427SDimitry Andric     Entry->DataRVA = 0; // Set to zero because it is a relocation.
9477ab83427SDimitry Andric     Entry->DataSize = Data[DataNodes->getDataIndex()].size();
9487ab83427SDimitry Andric     Entry->Codepage = 0;
9497ab83427SDimitry Andric     Entry->Reserved = 0;
95008bbd35aSDimitry Andric     CurrentOffset += sizeof(coff_resource_data_entry);
95108bbd35aSDimitry Andric     CurrentRelativeOffset += sizeof(coff_resource_data_entry);
9527ab83427SDimitry Andric   }
9537ab83427SDimitry Andric }
9547ab83427SDimitry Andric 
writeDirectoryStringTable()9557ab83427SDimitry Andric void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
9567ab83427SDimitry Andric   // Now write the directory string table for .rsrc$01
9577ab83427SDimitry Andric   uint32_t TotalStringTableSize = 0;
9587c7aba6eSDimitry Andric   for (auto &String : StringTable) {
9597ab83427SDimitry Andric     uint16_t Length = String.size();
9607c7aba6eSDimitry Andric     support::endian::write16le(BufferStart + CurrentOffset, Length);
9617c7aba6eSDimitry Andric     CurrentOffset += sizeof(uint16_t);
9627c7aba6eSDimitry Andric     auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
963d8e91e46SDimitry Andric     llvm::copy(String, Start);
9647c7aba6eSDimitry Andric     CurrentOffset += Length * sizeof(UTF16);
9657ab83427SDimitry Andric     TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
9667ab83427SDimitry Andric   }
9677c7aba6eSDimitry Andric   CurrentOffset +=
9687ab83427SDimitry Andric       alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
9697ab83427SDimitry Andric }
9707ab83427SDimitry Andric 
writeFirstSectionRelocations()9717ab83427SDimitry Andric void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
9727ab83427SDimitry Andric 
9737ab83427SDimitry Andric   // Now write the relocations for .rsrc$01
9747ab83427SDimitry Andric   // Five symbols already in table before we start, @feat.00 and 2 for each
9757ab83427SDimitry Andric   // .rsrc section.
9767ab83427SDimitry Andric   uint32_t NextSymbolIndex = 5;
9777ab83427SDimitry Andric   for (unsigned i = 0; i < Data.size(); i++) {
97808bbd35aSDimitry Andric     auto *Reloc =
97908bbd35aSDimitry Andric         reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset);
9807ab83427SDimitry Andric     Reloc->VirtualAddress = RelocationAddresses[i];
9817ab83427SDimitry Andric     Reloc->SymbolTableIndex = NextSymbolIndex++;
982ac9a064cSDimitry Andric     switch (getMachineArchType(MachineType)) {
983ac9a064cSDimitry Andric     case Triple::thumb:
98408bbd35aSDimitry Andric       Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
9857ab83427SDimitry Andric       break;
986ac9a064cSDimitry Andric     case Triple::x86_64:
98708bbd35aSDimitry Andric       Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
9887ab83427SDimitry Andric       break;
989ac9a064cSDimitry Andric     case Triple::x86:
99008bbd35aSDimitry Andric       Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB;
9917ab83427SDimitry Andric       break;
992ac9a064cSDimitry Andric     case Triple::aarch64:
993044eb2f6SDimitry Andric       Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
994044eb2f6SDimitry Andric       break;
9957ab83427SDimitry Andric     default:
996044eb2f6SDimitry Andric       llvm_unreachable("unknown machine type");
9977ab83427SDimitry Andric     }
99808bbd35aSDimitry Andric     CurrentOffset += sizeof(coff_relocation);
9997ab83427SDimitry Andric   }
10007ab83427SDimitry Andric }
10017ab83427SDimitry Andric 
100208bbd35aSDimitry Andric Expected<std::unique_ptr<MemoryBuffer>>
writeWindowsResourceCOFF(COFF::MachineTypes MachineType,const WindowsResourceParser & Parser,uint32_t TimeDateStamp)100308bbd35aSDimitry Andric writeWindowsResourceCOFF(COFF::MachineTypes MachineType,
1004e6d15924SDimitry Andric                          const WindowsResourceParser &Parser,
1005e6d15924SDimitry Andric                          uint32_t TimeDateStamp) {
10067ab83427SDimitry Andric   Error E = Error::success();
100708bbd35aSDimitry Andric   WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
10087ab83427SDimitry Andric   if (E)
1009ac9a064cSDimitry Andric     return E;
1010e6d15924SDimitry Andric   return Writer.write(TimeDateStamp);
10117ab83427SDimitry Andric }
10127ab83427SDimitry Andric 
1013b5630dbaSDimitry Andric } // namespace object
1014b5630dbaSDimitry Andric } // namespace llvm
1015