21 #include <system_error> 29 #define RETURN_IF_ERROR(X) \ 39 uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
40 uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
52 return make_error<GenericBinaryError>(
53 "File too small to be a resource file",
56 return std::move(Ret);
61 return make_error<EmptyResError>(
".res contains no entries",
73 if (
auto E = Ref.loadNext())
80 if (Reader.bytesRemaining() == 0) {
93 IsString = IDFlag != 0xffff;
106 Error ResourceEntryRef::loadNext() {
111 return make_error<GenericBinaryError>(
"Header size is too small.",
134 auto E = EntryOrErr.takeError();
151 Data.push_back(Entry.
getData());
153 bool IsNewTypeString =
false;
154 bool IsNewNameString =
false;
156 Root.addEntry(Entry, IsNewTypeString, IsNewNameString);
172 Root.
print(Writer,
"Resource Tree");
175 void WindowsResourceParser::TreeNode::addEntry(
const ResourceEntryRef &Entry,
176 bool &IsNewTypeString,
177 bool &IsNewNameString) {
178 TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString);
179 TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString);
180 NameNode.addLanguageNode(Entry);
183 WindowsResourceParser::TreeNode::TreeNode(
bool IsStringNode) {
185 StringIndex = StringCount++;
188 WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
189 uint16_t MinorVersion,
191 : IsDataNode(
true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
193 DataIndex = DataCount++;
196 std::unique_ptr<WindowsResourceParser::TreeNode>
197 WindowsResourceParser::TreeNode::createStringNode() {
198 return std::unique_ptr<TreeNode>(
new TreeNode(
true));
201 std::unique_ptr<WindowsResourceParser::TreeNode>
202 WindowsResourceParser::TreeNode::createIDNode() {
203 return std::unique_ptr<TreeNode>(
new TreeNode(
false));
206 std::unique_ptr<WindowsResourceParser::TreeNode>
207 WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
208 uint16_t MinorVersion,
210 return std::unique_ptr<TreeNode>(
211 new TreeNode(MajorVersion, MinorVersion, Characteristics));
216 bool &IsNewTypeString) {
225 bool &IsNewNameString) {
233 WindowsResourceParser::TreeNode::addLanguageNode(
240 uint32_t ID,
bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion,
242 auto Child = IDChildren.find(ID);
243 if (Child == IDChildren.end()) {
245 IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics)
248 IDChildren.emplace(ID, std::move(NewChild));
251 return *(Child->second);
257 std::string NameString;
259 std::vector<UTF16> EndianCorrectedName;
261 EndianCorrectedName.resize(NameRef.
size() + 1);
266 CorrectedName = NameRef;
269 auto Child = StringChildren.find(NameString);
270 if (Child == StringChildren.end()) {
271 auto NewChild = createStringNode();
274 StringChildren.emplace(NameString, std::move(NewChild));
277 return *(Child->second);
283 for (
auto const &Child : StringChildren) {
284 Child.second->print(Writer, Child.first);
286 for (
auto const &Child : IDChildren) {
287 Child.second->print(Writer,
to_string(Child.first));
295 uint32_t Size = (IDChildren.size() + StringChildren.size()) *
308 for (
auto const &Child : StringChildren) {
309 Size += Child.second->getTreeSize();
311 for (
auto const &Child : IDChildren) {
312 Size += Child.second->getTreeSize();
321 std::unique_ptr<MemoryBuffer>
write();
324 void performFileLayout();
325 void performSectionOneLayout();
326 void performSectionTwoLayout();
327 void writeCOFFHeader();
328 void writeFirstSectionHeader();
329 void writeSecondSectionHeader();
330 void writeFirstSection();
331 void writeSecondSection();
334 void writeDirectoryTree();
335 void writeDirectoryStringTable();
336 void writeFirstSectionRelocations();
337 std::unique_ptr<WritableMemoryBuffer> OutputBuffer;
339 uint64_t CurrentOffset = 0;
351 std::vector<uint32_t> StringTableOffsets;
352 std::vector<uint32_t> DataOffsets;
353 std::vector<uint32_t> RelocationAddresses;
359 : MachineType(MachineType), Resources(Parser.
getTree()),
366 void WindowsResourceCOFFWriter::performFileLayout() {
373 performSectionOneLayout();
374 performSectionTwoLayout();
377 SymbolTableOffset = FileSize;
385 void WindowsResourceCOFFWriter::performSectionOneLayout() {
386 SectionOneOffset = FileSize;
389 uint32_t CurrentStringOffset = SectionOneSize;
391 for (
auto const &String : StringTable) {
392 StringTableOffsets.push_back(CurrentStringOffset);
393 uint32_t StringSize = String.size() *
sizeof(
UTF16) +
sizeof(uint16_t);
394 CurrentStringOffset += StringSize;
395 TotalStringTableSize += StringSize;
400 SectionOneRelocations = FileSize + SectionOneSize;
401 FileSize += SectionOneSize;
404 FileSize =
alignTo(FileSize, SECTION_ALIGNMENT);
407 void WindowsResourceCOFFWriter::performSectionTwoLayout() {
410 SectionTwoOffset = FileSize;
412 for (
auto const &Entry : Data) {
413 DataOffsets.push_back(SectionTwoSize);
414 SectionTwoSize +=
alignTo(Entry.size(),
sizeof(uint64_t));
416 FileSize += SectionTwoSize;
417 FileSize =
alignTo(FileSize, SECTION_ALIGNMENT);
421 std::time_t Now = time(
nullptr);
428 BufferStart = OutputBuffer->getBufferStart();
431 writeFirstSectionHeader();
432 writeSecondSectionHeader();
434 writeSecondSection();
438 return std::move(OutputBuffer);
441 void WindowsResourceCOFFWriter::writeCOFFHeader() {
445 Header->NumberOfSections = 2;
446 Header->TimeDateStamp =
getTime();
447 Header->PointerToSymbolTable = SymbolTableOffset;
449 Header->NumberOfSymbols = Data.
size() + 5;
450 Header->SizeOfOptionalHeader = 0;
454 void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
457 auto *SectionOneHeader =
458 reinterpret_cast<coff_section *
>(BufferStart + CurrentOffset);
459 strncpy(SectionOneHeader->Name,
".rsrc$01", (
size_t)
COFF::NameSize);
460 SectionOneHeader->VirtualSize = 0;
461 SectionOneHeader->VirtualAddress = 0;
462 SectionOneHeader->SizeOfRawData = SectionOneSize;
463 SectionOneHeader->PointerToRawData = SectionOneOffset;
464 SectionOneHeader->PointerToRelocations = SectionOneRelocations;
465 SectionOneHeader->PointerToLinenumbers = 0;
466 SectionOneHeader->NumberOfRelocations = Data.
size();
467 SectionOneHeader->NumberOfLinenumbers = 0;
472 void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
475 auto *SectionTwoHeader =
476 reinterpret_cast<coff_section *
>(BufferStart + CurrentOffset);
477 strncpy(SectionTwoHeader->Name,
".rsrc$02", (
size_t)
COFF::NameSize);
478 SectionTwoHeader->VirtualSize = 0;
479 SectionTwoHeader->VirtualAddress = 0;
480 SectionTwoHeader->SizeOfRawData = SectionTwoSize;
481 SectionTwoHeader->PointerToRawData = SectionTwoOffset;
482 SectionTwoHeader->PointerToRelocations = 0;
483 SectionTwoHeader->PointerToLinenumbers = 0;
484 SectionTwoHeader->NumberOfRelocations = 0;
485 SectionTwoHeader->NumberOfLinenumbers = 0;
490 void WindowsResourceCOFFWriter::writeFirstSection() {
494 writeDirectoryTree();
495 writeDirectoryStringTable();
496 writeFirstSectionRelocations();
498 CurrentOffset =
alignTo(CurrentOffset, SECTION_ALIGNMENT);
501 void WindowsResourceCOFFWriter::writeSecondSection() {
503 for (
auto const &RawDataEntry : Data) {
504 llvm::copy(RawDataEntry, BufferStart + CurrentOffset);
505 CurrentOffset +=
alignTo(RawDataEntry.size(),
sizeof(uint64_t));
508 CurrentOffset =
alignTo(CurrentOffset, SECTION_ALIGNMENT);
511 void WindowsResourceCOFFWriter::writeSymbolTable() {
517 Symbol->SectionNumber = 0xffff;
520 Symbol->NumberOfAuxSymbols = 0;
525 strncpy(
Symbol->Name.ShortName,
".rsrc$01", (
size_t)COFF::NameSize);
527 Symbol->SectionNumber = 1;
530 Symbol->NumberOfAuxSymbols = 1;
534 Aux->
Length = SectionOneSize;
535 Aux->NumberOfRelocations = Data.
size();
536 Aux->NumberOfLinenumbers = 0;
538 Aux->NumberLowPart = 0;
544 strncpy(
Symbol->Name.ShortName,
".rsrc$02", (
size_t)COFF::NameSize);
546 Symbol->SectionNumber = 2;
549 Symbol->NumberOfAuxSymbols = 1;
553 Aux->
Length = SectionTwoSize;
554 Aux->NumberOfRelocations = 0;
555 Aux->NumberOfLinenumbers = 0;
557 Aux->NumberLowPart = 0;
562 for (
unsigned i = 0; i < Data.
size(); i++) {
563 auto RelocationName =
formatv(
"$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
565 memcpy(Symbol->Name.ShortName, RelocationName.data(), (size_t) COFF::NameSize);
566 Symbol->Value = DataOffsets[i];
567 Symbol->SectionNumber = 2;
570 Symbol->NumberOfAuxSymbols = 0;
575 void WindowsResourceCOFFWriter::writeStringTable() {
577 auto COFFStringTable =
reinterpret_cast<void *
>(BufferStart + CurrentOffset);
578 memset(COFFStringTable, 0, 4);
581 void WindowsResourceCOFFWriter::writeDirectoryTree() {
584 std::queue<const WindowsResourceParser::TreeNode *> Queue;
585 Queue.push(&Resources);
590 std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
593 while (!Queue.empty()) {
594 auto CurrentNode = Queue.front();
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();
610 for (
auto const &Child : StringChildren) {
613 Entry->Identifier.setNameOffset(
614 StringTableOffsets[Child.second->getStringIndex()]);
615 if (Child.second->checkIsDataNode()) {
616 Entry->Offset.DataEntryOffset = NextLevelOffset;
618 DataEntriesTreeOrder.push_back(Child.second.get());
620 Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
622 (Child.second->getStringChildren().size() +
623 Child.second->getIDChildren().size()) *
625 Queue.push(Child.second.get());
630 for (
auto const &Child : IDChildren) {
633 Entry->Identifier.ID = Child.first;
634 if (Child.second->checkIsDataNode()) {
635 Entry->Offset.DataEntryOffset = NextLevelOffset;
637 DataEntriesTreeOrder.push_back(Child.second.get());
639 Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
641 (Child.second->getStringChildren().size() +
642 Child.second->getIDChildren().size()) *
644 Queue.push(Child.second.get());
651 RelocationAddresses.resize(Data.
size());
653 for (
auto DataNodes : DataEntriesTreeOrder) {
656 RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
658 Entry->DataSize = Data[DataNodes->getDataIndex()].
size();
666 void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
669 for (
auto &String : StringTable) {
670 uint16_t Length = String.size();
672 CurrentOffset +=
sizeof(uint16_t);
673 auto *Start =
reinterpret_cast<UTF16 *
>(BufferStart + CurrentOffset);
675 CurrentOffset += Length *
sizeof(
UTF16);
676 TotalStringTableSize += Length *
sizeof(
UTF16) +
sizeof(uint16_t);
679 alignTo(TotalStringTableSize,
sizeof(
uint32_t)) - TotalStringTableSize;
682 void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
688 for (
unsigned i = 0; i < Data.
size(); i++) {
692 Reloc->SymbolTableIndex = NextSymbolIndex++;
693 switch (MachineType) {
720 return Writer.
write();
coff_symbol< support::ulittle16_t > coff_symbol16
constexpr bool isUInt< 32 >(uint64_t x)
const size_t WIN_RES_NULL_ENTRY_SIZE
An implementation of BinaryStream which holds its entire data set in a single contiguous buffer...
This class represents lattice values for constants.
Error readInteger(T &Dest)
Read an integer of the specified endianness into Dest and update the stream's offset.
Error parse(WindowsResource *WR)
bool checkNameString() const
Error readWideString(ArrayRef< UTF16 > &Dest)
Similar to readCString, however read a null-terminated UTF16 string instead.
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew=0)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
No complex type; simple scalar variable.
constexpr bool IsBigEndianHost
amdgpu Simplify well known AMD library false Value Value const Twine & Name
Machine is based on a 32bit word architecture.
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
const uint32_t SECTION_ALIGNMENT
void write16le(void *P, uint16_t V)
const Children< uint32_t > & getIDChildren() const
The access may reference the value stored in memory.
TypeID
Definitions of all of the base types for the Type system.
#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED
Tagged union holding either a T or a Error.
uint32_t getOffset() const
uint16_t getNameID() const
static std::unique_ptr< WritableMemoryBuffer > getNewMemBuffer(size_t Size, const Twine &BufferName="")
Allocate a new zero-initialized MemoryBuffer of the specified size.
static Expected< std::unique_ptr< WindowsResource > > createWindowsResource(MemoryBufferRef Source)
Expected< ResourceEntryRef > getHeadEntry()
uint16_t getMinorVersion() const
const uint32_t MIN_HEADER_SIZE
uint32_t getCharacteristics() const
size_t getBufferSize() const
WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, Error &E)
The instances of the Type class are immutable: once they are created, they are never changed...
size_t size() const
size - Get the array size.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
ArrayRef< uint8_t > getData() const
ArrayRef< UTF16 > getTypeString() const
static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, ArrayRef< UTF16 > &Str, bool &IsString)
static std::time_t getTime()
static void write(bool isBE, void *P, T V)
void printTree(raw_ostream &OS) const
void consumeError(Error Err)
Consume a Error without doing anything.
support::ulittle32_t VirtualAddress
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Error moveNext(bool &End)
void setOffset(uint32_t Off)
const ArrayRef< std::vector< UTF16 > > getStringTable() const
static ErrorSuccess success()
Create a success value.
const uint32_t WIN_RES_HEADER_ALIGNMENT
const ArrayRef< std::vector< uint8_t > > getData() const
bool checkTypeString() const
BinaryStreamRef is to BinaryStream what ArrayRef is to an Array.
std::unique_ptr< MemoryBuffer > write()
uint16_t getMajorVersion() const
bool convertUTF16ToUTF8String(ArrayRef< char > SrcBytes, std::string &Out)
Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
const size_t WIN_RES_MAGIC_SIZE
Expected< std::unique_ptr< MemoryBuffer > > writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType, const WindowsResourceParser &Parser)
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, ArrayRef< MemberData > Members, StringRef StringTable)
uint32_t getTreeSize() const
COFFYAML::WeakExternalCharacteristics Characteristics
static void writeStringTable(std::vector< uint8_t > &B, ArrayRef< const std::string > Strings)
uint32_t getLength() override
Return the number of bytes of data in this stream.
ArrayRef< UTF16 > getNameString() const
const std::string to_string(const T &Value)
uint16_t getTypeID() const
support::ulittle32_t Length
const uint32_t WIN_RES_DATA_ALIGNMENT
#define RETURN_IF_ERROR(X)
uint16_t getLanguage() const
Lightweight error class with error context and mandatory checking.
This class implements an extremely fast bulk output stream that can only output to a stream...
void print(ScopedPrinter &Writer, StringRef Name) const
Provides read only access to a subclass of BinaryStream.
StringRef - Represent a constant reference to a string, i.e.
friend class ResourceEntryRef
support::ulittle32_t Characteristics
const TreeNode & getTree() const
OutputIt copy(R &&Range, OutputIt Out)
const Children< std::string > & getStringChildren() const