blob: a0d658491cb96196a3d7a8a444bc2444c2b806e6 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===-- WindowsResource.h ---------------------------------------*- C++-*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===---------------------------------------------------------------------===//
8//
9// This file declares the .res file class. .res files are intermediate
10// products of the typical resource-compilation process on Windows. This
11// process is as follows:
12//
13// .rc file(s) ---(rc.exe)---> .res file(s) ---(cvtres.exe)---> COFF file
14//
15// .rc files are human-readable scripts that list all resources a program uses.
16//
17// They are compiled into .res files, which are a list of the resources in
18// binary form.
19//
20// Finally the data stored in the .res is compiled into a COFF file, where it
21// is organized in a directory tree structure for optimized access by the
22// program during runtime.
23//
24// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648007(v=vs.85).aspx
25//
26//===---------------------------------------------------------------------===//
27
28#ifndef LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H
29#define LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H
30
31#include "llvm/ADT/ArrayRef.h"
32#include "llvm/BinaryFormat/COFF.h"
33#include "llvm/Object/Binary.h"
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020034#include "llvm/Object/COFF.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010035#include "llvm/Object/Error.h"
36#include "llvm/Support/BinaryByteStream.h"
37#include "llvm/Support/BinaryStreamReader.h"
38#include "llvm/Support/ConvertUTF.h"
39#include "llvm/Support/Endian.h"
40#include "llvm/Support/Error.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010041
42#include <map>
43
44namespace llvm {
Andrew Walbran3d2c1972020-04-07 12:24:26 +010045
46class raw_ostream;
47class ScopedPrinter;
48
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010049namespace object {
50
51class WindowsResource;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020052class ResourceSectionRef;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010053
54const size_t WIN_RES_MAGIC_SIZE = 16;
55const size_t WIN_RES_NULL_ENTRY_SIZE = 16;
56const uint32_t WIN_RES_HEADER_ALIGNMENT = 4;
57const uint32_t WIN_RES_DATA_ALIGNMENT = 4;
58const uint16_t WIN_RES_PURE_MOVEABLE = 0x0030;
59
60struct WinResHeaderPrefix {
61 support::ulittle32_t DataSize;
62 support::ulittle32_t HeaderSize;
63};
64
65// Type and Name may each either be an integer ID or a string. This struct is
66// only used in the case where they are both IDs.
67struct WinResIDs {
68 uint16_t TypeFlag;
69 support::ulittle16_t TypeID;
70 uint16_t NameFlag;
71 support::ulittle16_t NameID;
72
73 void setType(uint16_t ID) {
74 TypeFlag = 0xffff;
75 TypeID = ID;
76 }
77
78 void setName(uint16_t ID) {
79 NameFlag = 0xffff;
80 NameID = ID;
81 }
82};
83
84struct WinResHeaderSuffix {
85 support::ulittle32_t DataVersion;
86 support::ulittle16_t MemoryFlags;
87 support::ulittle16_t Language;
88 support::ulittle32_t Version;
89 support::ulittle32_t Characteristics;
90};
91
92class EmptyResError : public GenericBinaryError {
93public:
94 EmptyResError(Twine Msg, object_error ECOverride)
95 : GenericBinaryError(Msg, ECOverride) {}
96};
97
98class ResourceEntryRef {
99public:
100 Error moveNext(bool &End);
101 bool checkTypeString() const { return IsStringType; }
102 ArrayRef<UTF16> getTypeString() const { return Type; }
103 uint16_t getTypeID() const { return TypeID; }
104 bool checkNameString() const { return IsStringName; }
105 ArrayRef<UTF16> getNameString() const { return Name; }
106 uint16_t getNameID() const { return NameID; }
107 uint16_t getDataVersion() const { return Suffix->DataVersion; }
108 uint16_t getLanguage() const { return Suffix->Language; }
109 uint16_t getMemoryFlags() const { return Suffix->MemoryFlags; }
110 uint16_t getMajorVersion() const { return Suffix->Version >> 16; }
111 uint16_t getMinorVersion() const { return Suffix->Version; }
112 uint32_t getCharacteristics() const { return Suffix->Characteristics; }
113 ArrayRef<uint8_t> getData() const { return Data; }
114
115private:
116 friend class WindowsResource;
117
118 ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner);
119 Error loadNext();
120
121 static Expected<ResourceEntryRef> create(BinaryStreamRef Ref,
122 const WindowsResource *Owner);
123
124 BinaryStreamReader Reader;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100125 const WindowsResource *Owner;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100126 bool IsStringType;
127 ArrayRef<UTF16> Type;
128 uint16_t TypeID;
129 bool IsStringName;
130 ArrayRef<UTF16> Name;
131 uint16_t NameID;
132 const WinResHeaderSuffix *Suffix = nullptr;
133 ArrayRef<uint8_t> Data;
134};
135
136class WindowsResource : public Binary {
137public:
138 Expected<ResourceEntryRef> getHeadEntry();
139
140 static bool classof(const Binary *V) { return V->isWinRes(); }
141
142 static Expected<std::unique_ptr<WindowsResource>>
143 createWindowsResource(MemoryBufferRef Source);
144
145private:
146 friend class ResourceEntryRef;
147
148 WindowsResource(MemoryBufferRef Source);
149
150 BinaryByteStream BBS;
151};
152
153class WindowsResourceParser {
154public:
155 class TreeNode;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200156 WindowsResourceParser(bool MinGW = false);
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100157 Error parse(WindowsResource *WR, std::vector<std::string> &Duplicates);
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200158 Error parse(ResourceSectionRef &RSR, StringRef Filename,
159 std::vector<std::string> &Duplicates);
160 void cleanUpManifests(std::vector<std::string> &Duplicates);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100161 void printTree(raw_ostream &OS) const;
162 const TreeNode &getTree() const { return Root; }
163 const ArrayRef<std::vector<uint8_t>> getData() const { return Data; }
164 const ArrayRef<std::vector<UTF16>> getStringTable() const {
165 return StringTable;
166 }
167
168 class TreeNode {
169 public:
170 template <typename T>
171 using Children = std::map<T, std::unique_ptr<TreeNode>>;
172
173 void print(ScopedPrinter &Writer, StringRef Name) const;
174 uint32_t getTreeSize() const;
175 uint32_t getStringIndex() const { return StringIndex; }
176 uint32_t getDataIndex() const { return DataIndex; }
177 uint16_t getMajorVersion() const { return MajorVersion; }
178 uint16_t getMinorVersion() const { return MinorVersion; }
179 uint32_t getCharacteristics() const { return Characteristics; }
180 bool checkIsDataNode() const { return IsDataNode; }
181 const Children<uint32_t> &getIDChildren() const { return IDChildren; }
182 const Children<std::string> &getStringChildren() const {
183 return StringChildren;
184 }
185
186 private:
187 friend class WindowsResourceParser;
188
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200189 // Index is the StringTable vector index for this node's name.
190 static std::unique_ptr<TreeNode> createStringNode(uint32_t Index);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100191 static std::unique_ptr<TreeNode> createIDNode();
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200192 // DataIndex is the Data vector index that the data node points at.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100193 static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion,
194 uint16_t MinorVersion,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100195 uint32_t Characteristics,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200196 uint32_t Origin,
197 uint32_t DataIndex);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100198
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200199 explicit TreeNode(uint32_t StringIndex);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100200 TreeNode(uint16_t MajorVersion, uint16_t MinorVersion,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200201 uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100202
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100203 bool addEntry(const ResourceEntryRef &Entry, uint32_t Origin,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200204 std::vector<std::vector<uint8_t>> &Data,
205 std::vector<std::vector<UTF16>> &StringTable,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100206 TreeNode *&Result);
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200207 TreeNode &addTypeNode(const ResourceEntryRef &Entry,
208 std::vector<std::vector<UTF16>> &StringTable);
209 TreeNode &addNameNode(const ResourceEntryRef &Entry,
210 std::vector<std::vector<UTF16>> &StringTable);
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100211 bool addLanguageNode(const ResourceEntryRef &Entry, uint32_t Origin,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200212 std::vector<std::vector<uint8_t>> &Data,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100213 TreeNode *&Result);
214 bool addDataChild(uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
215 uint32_t Characteristics, uint32_t Origin,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200216 uint32_t DataIndex, TreeNode *&Result);
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100217 TreeNode &addIDChild(uint32_t ID);
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200218 TreeNode &addNameChild(ArrayRef<UTF16> NameRef,
219 std::vector<std::vector<UTF16>> &StringTable);
220 void shiftDataIndexDown(uint32_t Index);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100221
222 bool IsDataNode = false;
223 uint32_t StringIndex;
224 uint32_t DataIndex;
225 Children<uint32_t> IDChildren;
226 Children<std::string> StringChildren;
227 uint16_t MajorVersion = 0;
228 uint16_t MinorVersion = 0;
229 uint32_t Characteristics = 0;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100230
231 // The .res file that defined this TreeNode, for diagnostics.
232 // Index into InputFilenames.
233 uint32_t Origin;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100234 };
235
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200236 struct StringOrID {
237 bool IsString;
238 ArrayRef<UTF16> String;
239 uint32_t ID;
240
241 StringOrID(uint32_t ID) : IsString(false), ID(ID) {}
242 StringOrID(ArrayRef<UTF16> String) : IsString(true), String(String) {}
243 };
244
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100245private:
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200246 Error addChildren(TreeNode &Node, ResourceSectionRef &RSR,
247 const coff_resource_dir_table &Table, uint32_t Origin,
248 std::vector<StringOrID> &Context,
249 std::vector<std::string> &Duplicates);
250 bool shouldIgnoreDuplicate(const ResourceEntryRef &Entry) const;
251 bool shouldIgnoreDuplicate(const std::vector<StringOrID> &Context) const;
252
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100253 TreeNode Root;
254 std::vector<std::vector<uint8_t>> Data;
255 std::vector<std::vector<UTF16>> StringTable;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100256
257 std::vector<std::string> InputFilenames;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200258
259 bool MinGW;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100260};
261
262Expected<std::unique_ptr<MemoryBuffer>>
263writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100264 const WindowsResourceParser &Parser,
265 uint32_t TimeDateStamp);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100266
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100267void printResourceTypeName(uint16_t TypeID, raw_ostream &OS);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100268} // namespace object
269} // namespace llvm
270
271#endif