1 //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the .res file class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/Object/WindowsResource.h"
15 #include "llvm/BinaryFormat/COFF.h"
16 #include "llvm/Object/COFF.h"
17 #include "llvm/Support/FileOutputBuffer.h"
18 #include "llvm/Support/MathExtras.h"
19 #include <ctime>
20 #include <queue>
21 #include <sstream>
22 #include <system_error>
23 
24 namespace llvm {
25 namespace object {
26 
27 #define RETURN_IF_ERROR(X)                                                     \
28   if (auto EC = X)                                                             \
29     return EC;
30 
31 const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
32 
33 static const size_t ResourceMagicSize = 16;
34 
35 static const size_t NullEntrySize = 16;
36 
37 uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
38 uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
39 
40 WindowsResource::WindowsResource(MemoryBufferRef Source)
41     : Binary(Binary::ID_WinRes, Source) {
42   size_t LeadingSize = ResourceMagicSize + NullEntrySize;
43   BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
44                          support::little);
45 }
46 
47 Expected<std::unique_ptr<WindowsResource>>
48 WindowsResource::createWindowsResource(MemoryBufferRef Source) {
49   if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize)
50     return make_error<GenericBinaryError>(
51         "File too small to be a resource file",
52         object_error::invalid_file_type);
53   std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
54   return std::move(Ret);
55 }
56 
57 Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
58   Error Err = Error::success();
59   auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err);
60   if (Err)
61     return std::move(Err);
62   return Ref;
63 }
64 
65 ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
66                                    const WindowsResource *Owner, Error &Err)
67     : Reader(Ref), OwningRes(Owner) {
68   if (loadNext())
69     Err = make_error<GenericBinaryError>("Could not read first entry.",
70                                          object_error::unexpected_eof);
71 }
72 
73 Error ResourceEntryRef::moveNext(bool &End) {
74   // Reached end of all the entries.
75   if (Reader.bytesRemaining() == 0) {
76     End = true;
77     return Error::success();
78   }
79   RETURN_IF_ERROR(loadNext());
80 
81   return Error::success();
82 }
83 
84 static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
85                             ArrayRef<UTF16> &Str, bool &IsString) {
86   uint16_t IDFlag;
87   RETURN_IF_ERROR(Reader.readInteger(IDFlag));
88   IsString = IDFlag != 0xffff;
89 
90   if (IsString) {
91     Reader.setOffset(
92         Reader.getOffset() -
93         sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
94     RETURN_IF_ERROR(Reader.readWideString(Str));
95   } else
96     RETURN_IF_ERROR(Reader.readInteger(ID));
97 
98   return Error::success();
99 }
100 
101 Error ResourceEntryRef::loadNext() {
102   uint32_t DataSize;
103   RETURN_IF_ERROR(Reader.readInteger(DataSize));
104   uint32_t HeaderSize;
105   RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
106 
107   if (HeaderSize < MIN_HEADER_SIZE)
108     return make_error<GenericBinaryError>("Header size is too small.",
109                                           object_error::parse_failed);
110 
111   RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
112 
113   RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
114 
115   RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
116 
117   RETURN_IF_ERROR(Reader.readObject(Suffix));
118 
119   RETURN_IF_ERROR(Reader.readArray(Data, DataSize));
120 
121   RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
122 
123   return Error::success();
124 }
125 
126 WindowsResourceParser::WindowsResourceParser() : Root(false) {}
127 
128 Error WindowsResourceParser::parse(WindowsResource *WR) {
129   auto EntryOrErr = WR->getHeadEntry();
130   if (!EntryOrErr)
131     return EntryOrErr.takeError();
132 
133   ResourceEntryRef Entry = EntryOrErr.get();
134   bool End = false;
135   while (!End) {
136 
137     Data.push_back(Entry.getData());
138 
139     if (Entry.checkTypeString())
140       StringTable.push_back(Entry.getTypeString());
141 
142     if (Entry.checkNameString())
143       StringTable.push_back(Entry.getNameString());
144 
145     Root.addEntry(Entry);
146 
147     RETURN_IF_ERROR(Entry.moveNext(End));
148   }
149 
150   return Error::success();
151 }
152 
153 void WindowsResourceParser::printTree() const {
154   ScopedPrinter Writer(outs());
155   Root.print(Writer, "Resource Tree");
156 }
157 
158 void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry) {
159   TreeNode &TypeNode = addTypeNode(Entry);
160   TreeNode &NameNode = TypeNode.addNameNode(Entry);
161   NameNode.addLanguageNode(Entry);
162 }
163 
164 WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
165   if (IsStringNode)
166     StringIndex = StringCount++;
167 }
168 
169 WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
170                                           uint16_t MinorVersion,
171                                           uint32_t Characteristics)
172     : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
173       Characteristics(Characteristics) {
174   if (IsDataNode)
175     DataIndex = DataCount++;
176 }
177 
178 std::unique_ptr<WindowsResourceParser::TreeNode>
179 WindowsResourceParser::TreeNode::createStringNode() {
180   return std::unique_ptr<TreeNode>(new TreeNode(true));
181 }
182 
183 std::unique_ptr<WindowsResourceParser::TreeNode>
184 WindowsResourceParser::TreeNode::createIDNode() {
185   return std::unique_ptr<TreeNode>(new TreeNode(false));
186 }
187 
188 std::unique_ptr<WindowsResourceParser::TreeNode>
189 WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
190                                                 uint16_t MinorVersion,
191                                                 uint32_t Characteristics) {
192   return std::unique_ptr<TreeNode>(
193       new TreeNode(MajorVersion, MinorVersion, Characteristics));
194 }
195 
196 WindowsResourceParser::TreeNode &
197 WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry) {
198   if (Entry.checkTypeString())
199     return addChild(Entry.getTypeString());
200   else
201     return addChild(Entry.getTypeID());
202 }
203 
204 WindowsResourceParser::TreeNode &
205 WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry) {
206   if (Entry.checkNameString())
207     return addChild(Entry.getNameString());
208   else
209     return addChild(Entry.getNameID());
210 }
211 
212 WindowsResourceParser::TreeNode &
213 WindowsResourceParser::TreeNode::addLanguageNode(
214     const ResourceEntryRef &Entry) {
215   return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(),
216                   Entry.getMinorVersion(), Entry.getCharacteristics());
217 }
218 
219 WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild(
220     uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion,
221     uint32_t Characteristics) {
222   auto Child = IDChildren.find(ID);
223   if (Child == IDChildren.end()) {
224     auto NewChild =
225         IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics)
226                    : createIDNode();
227     WindowsResourceParser::TreeNode &Node = *NewChild;
228     IDChildren.emplace(ID, std::move(NewChild));
229     return Node;
230   } else
231     return *(Child->second);
232 }
233 
234 WindowsResourceParser::TreeNode &
235 WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef) {
236   std::string NameString;
237   ArrayRef<UTF16> CorrectedName;
238   std::vector<UTF16> EndianCorrectedName;
239   if (llvm::sys::IsBigEndianHost) {
240     EndianCorrectedName.resize(NameRef.size() + 1);
241     std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1);
242     EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
243     CorrectedName = makeArrayRef(EndianCorrectedName);
244   } else
245     CorrectedName = NameRef;
246   llvm::convertUTF16ToUTF8String(CorrectedName, NameString);
247 
248   auto Child = StringChildren.find(NameString);
249   if (Child == StringChildren.end()) {
250     auto NewChild = createStringNode();
251     WindowsResourceParser::TreeNode &Node = *NewChild;
252     StringChildren.emplace(NameString, std::move(NewChild));
253     return Node;
254   } else
255     return *(Child->second);
256 }
257 
258 void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
259                                             StringRef Name) const {
260   ListScope NodeScope(Writer, Name);
261   for (auto const &Child : StringChildren) {
262     Child.second->print(Writer, Child.first);
263   }
264   for (auto const &Child : IDChildren) {
265     Child.second->print(Writer, to_string(Child.first));
266   }
267 }
268 
269 // This function returns the size of the entire resource tree, including
270 // directory tables, directory entries, and data entries.  It does not include
271 // the directory strings or the relocations of the .rsrc section.
272 uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
273   uint32_t Size = (IDChildren.size() + StringChildren.size()) *
274                   sizeof(llvm::object::coff_resource_dir_entry);
275 
276   // Reached a node pointing to a data entry.
277   if (IsDataNode) {
278     Size += sizeof(llvm::object::coff_resource_data_entry);
279     return Size;
280   }
281 
282   // If the node does not point to data, it must have a directory table pointing
283   // to other nodes.
284   Size += sizeof(llvm::object::coff_resource_dir_table);
285 
286   for (auto const &Child : StringChildren) {
287     Size += Child.second->getTreeSize();
288   }
289   for (auto const &Child : IDChildren) {
290     Size += Child.second->getTreeSize();
291   }
292   return Size;
293 }
294 
295 class WindowsResourceCOFFWriter {
296 public:
297   WindowsResourceCOFFWriter(StringRef OutputFile, Machine MachineType,
298                             const WindowsResourceParser &Parser, Error &E);
299 
300   Error write();
301 
302 private:
303   void performFileLayout();
304   void performSectionOneLayout();
305   void performSectionTwoLayout();
306   void writeCOFFHeader();
307   void writeFirstSectionHeader();
308   void writeSecondSectionHeader();
309   void writeFirstSection();
310   void writeSecondSection();
311   void writeSymbolTable();
312   void writeStringTable();
313   void writeDirectoryTree();
314   void writeDirectoryStringTable();
315   void writeFirstSectionRelocations();
316   std::unique_ptr<FileOutputBuffer> Buffer;
317   uint8_t *Current;
318   Machine MachineType;
319   const WindowsResourceParser::TreeNode &Resources;
320   const ArrayRef<std::vector<uint8_t>> Data;
321   uint64_t FileSize;
322   uint32_t SymbolTableOffset;
323   uint32_t SectionOneSize;
324   uint32_t SectionOneOffset;
325   uint32_t SectionOneRelocations;
326   uint32_t SectionTwoSize;
327   uint32_t SectionTwoOffset;
328   const ArrayRef<std::vector<UTF16>> StringTable;
329   std::vector<uint32_t> StringTableOffsets;
330   std::vector<uint32_t> DataOffsets;
331   std::vector<uint32_t> RelocationAddresses;
332 };
333 
334 WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
335     StringRef OutputFile, Machine MachineType,
336     const WindowsResourceParser &Parser, Error &E)
337     : MachineType(MachineType), Resources(Parser.getTree()),
338       Data(Parser.getData()), StringTable(Parser.getStringTable()) {
339   performFileLayout();
340 
341   ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
342       FileOutputBuffer::create(OutputFile, FileSize);
343   if (!BufferOrErr) {
344     E = errorCodeToError(BufferOrErr.getError());
345     return;
346   }
347 
348   Buffer = std::move(*BufferOrErr);
349 }
350 
351 void WindowsResourceCOFFWriter::performFileLayout() {
352   // Add size of COFF header.
353   FileSize = llvm::COFF::Header16Size;
354 
355   // one .rsrc section header for directory tree, another for resource data.
356   FileSize += 2 * llvm::COFF::SectionSize;
357 
358   performSectionOneLayout();
359   performSectionTwoLayout();
360 
361   // We have reached the address of the symbol table.
362   SymbolTableOffset = FileSize;
363 
364   FileSize += llvm::COFF::Symbol16Size;     // size of the @feat.00 symbol.
365   FileSize += 4 * llvm::COFF::Symbol16Size; // symbol + aux for each section.
366   FileSize += Data.size() * llvm::COFF::Symbol16Size; // 1 symbol per resource.
367   FileSize += 4; // four null bytes for the string table.
368 }
369 
370 void WindowsResourceCOFFWriter::performSectionOneLayout() {
371   SectionOneOffset = FileSize;
372 
373   SectionOneSize = Resources.getTreeSize();
374   uint32_t CurrentStringOffset = SectionOneSize;
375   uint32_t TotalStringTableSize = 0;
376   for (auto const &String : StringTable) {
377     StringTableOffsets.push_back(CurrentStringOffset);
378     uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
379     CurrentStringOffset += StringSize;
380     TotalStringTableSize += StringSize;
381   }
382   SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
383 
384   // account for the relocations of section one.
385   SectionOneRelocations = FileSize + SectionOneSize;
386   FileSize += SectionOneSize;
387   FileSize += Data.size() *
388               llvm::COFF::RelocationSize; // one relocation for each resource.
389 }
390 
391 void WindowsResourceCOFFWriter::performSectionTwoLayout() {
392   // add size of .rsrc$2 section, which contains all resource data on 8-byte
393   // alignment.
394   SectionTwoOffset = FileSize;
395   SectionTwoSize = 0;
396   for (auto const &Entry : Data) {
397     DataOffsets.push_back(SectionTwoSize);
398     SectionTwoSize += llvm::alignTo(Entry.size(), sizeof(uint64_t));
399   }
400   FileSize += SectionTwoSize;
401 }
402 
403 static std::time_t getTime() {
404   std::time_t Now = time(nullptr);
405   if (Now < 0 || !isUInt<32>(Now))
406     return UINT32_MAX;
407   return Now;
408 }
409 
410 Error WindowsResourceCOFFWriter::write() {
411   Current = Buffer->getBufferStart();
412 
413   writeCOFFHeader();
414   writeFirstSectionHeader();
415   writeSecondSectionHeader();
416   writeFirstSection();
417   writeSecondSection();
418   writeSymbolTable();
419   writeStringTable();
420 
421   if (auto EC = Buffer->commit()) {
422     return errorCodeToError(EC);
423   }
424 
425   return Error::success();
426 }
427 
428 void WindowsResourceCOFFWriter::writeCOFFHeader() {
429   // Write the COFF header.
430   auto *Header = reinterpret_cast<llvm::object::coff_file_header *>(Current);
431   switch (MachineType) {
432   case Machine::ARM:
433     Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
434     break;
435   case Machine::X64:
436     Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
437     break;
438   case Machine::X86:
439     Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_I386;
440     break;
441   default:
442     Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
443   }
444   Header->NumberOfSections = 2;
445   Header->TimeDateStamp = getTime();
446   Header->PointerToSymbolTable = SymbolTableOffset;
447   // One symbol for every resource plus 2 for each section and @feat.00
448   Header->NumberOfSymbols = Data.size() + 5;
449   Header->SizeOfOptionalHeader = 0;
450   Header->Characteristics = llvm::COFF::IMAGE_FILE_32BIT_MACHINE;
451 }
452 
453 void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
454   // Write the first section header.
455   Current += sizeof(llvm::object::coff_file_header);
456   auto *SectionOneHeader =
457       reinterpret_cast<llvm::object::coff_section *>(Current);
458   strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)llvm::COFF::NameSize);
459   SectionOneHeader->VirtualSize = 0;
460   SectionOneHeader->VirtualAddress = 0;
461   SectionOneHeader->SizeOfRawData = SectionOneSize;
462   SectionOneHeader->PointerToRawData = SectionOneOffset;
463   SectionOneHeader->PointerToRelocations = SectionOneRelocations;
464   SectionOneHeader->PointerToLinenumbers = 0;
465   SectionOneHeader->NumberOfRelocations = Data.size();
466   SectionOneHeader->NumberOfLinenumbers = 0;
467   SectionOneHeader->Characteristics = llvm::COFF::IMAGE_SCN_ALIGN_1BYTES;
468   SectionOneHeader->Characteristics +=
469       llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
470   SectionOneHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE;
471   SectionOneHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_READ;
472 }
473 
474 void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
475   // Write the second section header.
476   Current += sizeof(llvm::object::coff_section);
477   auto *SectionTwoHeader =
478       reinterpret_cast<llvm::object::coff_section *>(Current);
479   strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)llvm::COFF::NameSize);
480   SectionTwoHeader->VirtualSize = 0;
481   SectionTwoHeader->VirtualAddress = 0;
482   SectionTwoHeader->SizeOfRawData = SectionTwoSize;
483   SectionTwoHeader->PointerToRawData = SectionTwoOffset;
484   SectionTwoHeader->PointerToRelocations = 0;
485   SectionTwoHeader->PointerToLinenumbers = 0;
486   SectionTwoHeader->NumberOfRelocations = 0;
487   SectionTwoHeader->NumberOfLinenumbers = 0;
488   SectionTwoHeader->Characteristics =
489       llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
490   SectionTwoHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_READ;
491 }
492 
493 void WindowsResourceCOFFWriter::writeFirstSection() {
494   // Write section one.
495   Current += sizeof(llvm::object::coff_section);
496 
497   writeDirectoryTree();
498   writeDirectoryStringTable();
499   writeFirstSectionRelocations();
500 }
501 
502 void WindowsResourceCOFFWriter::writeSecondSection() {
503   // Now write the .rsrc$02 section.
504   for (auto const &RawDataEntry : Data) {
505     std::copy(RawDataEntry.begin(), RawDataEntry.end(), Current);
506     Current += alignTo(RawDataEntry.size(), sizeof(uint64_t));
507   }
508 }
509 
510 void WindowsResourceCOFFWriter::writeSymbolTable() {
511   // Now write the symbol table.
512   // First, the feat symbol.
513   auto *Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current);
514   strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)llvm::COFF::NameSize);
515   Symbol->Value = 0x11;
516   Symbol->SectionNumber = 0xffff;
517   Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
518   Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
519   Symbol->NumberOfAuxSymbols = 0;
520   Current += sizeof(llvm::object::coff_symbol16);
521 
522   // Now write the .rsrc1 symbol + aux.
523   Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current);
524   strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)llvm::COFF::NameSize);
525   Symbol->Value = 0;
526   Symbol->SectionNumber = 1;
527   Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
528   Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
529   Symbol->NumberOfAuxSymbols = 1;
530   Current += sizeof(llvm::object::coff_symbol16);
531   auto *Aux =
532       reinterpret_cast<llvm::object::coff_aux_section_definition *>(Current);
533   Aux->Length = SectionOneSize;
534   Aux->NumberOfRelocations = Data.size();
535   Aux->NumberOfLinenumbers = 0;
536   Aux->CheckSum = 0;
537   Aux->NumberLowPart = 0;
538   Aux->Selection = 0;
539   Current += sizeof(llvm::object::coff_aux_section_definition);
540 
541   // Now write the .rsrc2 symbol + aux.
542   Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current);
543   strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)llvm::COFF::NameSize);
544   Symbol->Value = 0;
545   Symbol->SectionNumber = 2;
546   Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
547   Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
548   Symbol->NumberOfAuxSymbols = 1;
549   Current += sizeof(llvm::object::coff_symbol16);
550   Aux = reinterpret_cast<llvm::object::coff_aux_section_definition *>(Current);
551   Aux->Length = SectionTwoSize;
552   Aux->NumberOfRelocations = 0;
553   Aux->NumberOfLinenumbers = 0;
554   Aux->CheckSum = 0;
555   Aux->NumberLowPart = 0;
556   Aux->Selection = 0;
557   Current += sizeof(llvm::object::coff_aux_section_definition);
558 
559   // Now write a symbol for each relocation.
560   for (unsigned i = 0; i < Data.size(); i++) {
561     char RelocationName[9];
562     sprintf(RelocationName, "$R%06X", DataOffsets[i]);
563     Symbol = reinterpret_cast<llvm::object::coff_symbol16 *>(Current);
564     strncpy(Symbol->Name.ShortName, RelocationName,
565             (size_t)llvm::COFF::NameSize);
566     Symbol->Value = DataOffsets[i];
567     Symbol->SectionNumber = 1;
568     Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL;
569     Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC;
570     Symbol->NumberOfAuxSymbols = 0;
571     Current += sizeof(llvm::object::coff_symbol16);
572   }
573 }
574 
575 void WindowsResourceCOFFWriter::writeStringTable() {
576   // Just 4 null bytes for the string table.
577   auto COFFStringTable = reinterpret_cast<uint32_t *>(Current);
578   *COFFStringTable = 0;
579 }
580 
581 void WindowsResourceCOFFWriter::writeDirectoryTree() {
582   // Traverse parsed resource tree breadth-first and write the corresponding
583   // COFF objects.
584   std::queue<const WindowsResourceParser::TreeNode *> Queue;
585   Queue.push(&Resources);
586   uint32_t NextLevelOffset = sizeof(llvm::object::coff_resource_dir_table) +
587                              (Resources.getStringChildren().size() +
588                               Resources.getIDChildren().size()) *
589                                  sizeof(llvm::object::coff_resource_dir_entry);
590   std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
591   uint32_t CurrentRelativeOffset = 0;
592 
593   while (!Queue.empty()) {
594     auto CurrentNode = Queue.front();
595     Queue.pop();
596     auto *Table =
597         reinterpret_cast<llvm::object::coff_resource_dir_table *>(Current);
598     Table->Characteristics = CurrentNode->getCharacteristics();
599     Table->TimeDateStamp = 0;
600     Table->MajorVersion = CurrentNode->getMajorVersion();
601     Table->MinorVersion = CurrentNode->getMinorVersion();
602     auto &IDChildren = CurrentNode->getIDChildren();
603     auto &StringChildren = CurrentNode->getStringChildren();
604     Table->NumberOfNameEntries = StringChildren.size();
605     Table->NumberOfIDEntries = IDChildren.size();
606     Current += sizeof(llvm::object::coff_resource_dir_table);
607     CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_table);
608 
609     // Write the directory entries immediately following each directory table.
610     for (auto const &Child : StringChildren) {
611       auto *Entry =
612           reinterpret_cast<llvm::object::coff_resource_dir_entry *>(Current);
613       Entry->Identifier.NameOffset =
614           StringTableOffsets[Child.second->getStringIndex()];
615       if (Child.second->checkIsDataNode()) {
616         Entry->Offset.DataEntryOffset = NextLevelOffset;
617         NextLevelOffset += sizeof(llvm::object::coff_resource_data_entry);
618         DataEntriesTreeOrder.push_back(Child.second.get());
619       } else {
620         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
621         NextLevelOffset += sizeof(llvm::object::coff_resource_dir_table) +
622                            (Child.second->getStringChildren().size() +
623                             Child.second->getIDChildren().size()) *
624                                sizeof(llvm::object::coff_resource_dir_entry);
625         Queue.push(Child.second.get());
626       }
627       Current += sizeof(llvm::object::coff_resource_dir_entry);
628       CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry);
629     }
630     for (auto const &Child : IDChildren) {
631       auto *Entry =
632           reinterpret_cast<llvm::object::coff_resource_dir_entry *>(Current);
633       Entry->Identifier.ID = Child.first;
634       if (Child.second->checkIsDataNode()) {
635         Entry->Offset.DataEntryOffset = NextLevelOffset;
636         NextLevelOffset += sizeof(llvm::object::coff_resource_data_entry);
637         DataEntriesTreeOrder.push_back(Child.second.get());
638       } else {
639         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
640         NextLevelOffset += sizeof(llvm::object::coff_resource_dir_table) +
641                            (Child.second->getStringChildren().size() +
642                             Child.second->getIDChildren().size()) *
643                                sizeof(llvm::object::coff_resource_dir_entry);
644         Queue.push(Child.second.get());
645       }
646       Current += sizeof(llvm::object::coff_resource_dir_entry);
647       CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry);
648     }
649   }
650 
651   RelocationAddresses.resize(Data.size());
652   // Now write all the resource data entries.
653   for (auto DataNodes : DataEntriesTreeOrder) {
654     auto *Entry =
655         reinterpret_cast<llvm::object::coff_resource_data_entry *>(Current);
656     RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
657     Entry->DataRVA = 0; // Set to zero because it is a relocation.
658     Entry->DataSize = Data[DataNodes->getDataIndex()].size();
659     Entry->Codepage = 0;
660     Entry->Reserved = 0;
661     Current += sizeof(llvm::object::coff_resource_data_entry);
662     CurrentRelativeOffset += sizeof(llvm::object::coff_resource_data_entry);
663   }
664 }
665 
666 void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
667   // Now write the directory string table for .rsrc$01
668   uint32_t TotalStringTableSize = 0;
669   for (auto String : StringTable) {
670     auto *LengthField = reinterpret_cast<uint16_t *>(Current);
671     uint16_t Length = String.size();
672     *LengthField = Length;
673     Current += sizeof(uint16_t);
674     auto *Start = reinterpret_cast<UTF16 *>(Current);
675     std::copy(String.begin(), String.end(), Start);
676     Current += Length * sizeof(UTF16);
677     TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
678   }
679   Current +=
680       alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
681 }
682 
683 void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
684 
685   // Now write the relocations for .rsrc$01
686   // Five symbols already in table before we start, @feat.00 and 2 for each
687   // .rsrc section.
688   uint32_t NextSymbolIndex = 5;
689   for (unsigned i = 0; i < Data.size(); i++) {
690     auto *Reloc = reinterpret_cast<llvm::object::coff_relocation *>(Current);
691     Reloc->VirtualAddress = RelocationAddresses[i];
692     Reloc->SymbolTableIndex = NextSymbolIndex++;
693     switch (MachineType) {
694     case Machine::ARM:
695       Reloc->Type = llvm::COFF::IMAGE_REL_ARM_ADDR32NB;
696       break;
697     case Machine::X64:
698       Reloc->Type = llvm::COFF::IMAGE_REL_AMD64_ADDR32NB;
699       break;
700     case Machine::X86:
701       Reloc->Type = llvm::COFF::IMAGE_REL_I386_DIR32NB;
702       break;
703     default:
704       Reloc->Type = 0;
705     }
706     Current += sizeof(llvm::object::coff_relocation);
707   }
708 }
709 
710 Error writeWindowsResourceCOFF(StringRef OutputFile, Machine MachineType,
711                                const WindowsResourceParser &Parser) {
712   Error E = Error::success();
713   WindowsResourceCOFFWriter Writer(OutputFile, MachineType, Parser, E);
714   if (E)
715     return E;
716   return Writer.write();
717 }
718 
719 } // namespace object
720 } // namespace llvm
721