Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===-- WindowsResource.h ---------------------------------------*- C++-*-===// |
2 | // |
||
3 | // 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 |
||
6 | // |
||
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_OBJECT_WINDOWSRESOURCE_H |
||
29 | #define LLVM_OBJECT_WINDOWSRESOURCE_H |
||
30 | |||
31 | #include "llvm/ADT/ArrayRef.h" |
||
32 | #include "llvm/BinaryFormat/COFF.h" |
||
33 | #include "llvm/Object/Binary.h" |
||
34 | #include "llvm/Object/Error.h" |
||
35 | #include "llvm/Support/BinaryByteStream.h" |
||
36 | #include "llvm/Support/BinaryStreamReader.h" |
||
37 | #include "llvm/Support/ConvertUTF.h" |
||
38 | #include "llvm/Support/Endian.h" |
||
39 | #include "llvm/Support/Error.h" |
||
40 | |||
41 | #include <map> |
||
42 | |||
43 | namespace llvm { |
||
44 | |||
45 | class raw_ostream; |
||
46 | class ScopedPrinter; |
||
47 | |||
48 | namespace object { |
||
49 | |||
50 | class WindowsResource; |
||
51 | class ResourceSectionRef; |
||
52 | struct coff_resource_dir_table; |
||
53 | |||
54 | const size_t WIN_RES_MAGIC_SIZE = 16; |
||
55 | const size_t WIN_RES_NULL_ENTRY_SIZE = 16; |
||
56 | const uint32_t WIN_RES_HEADER_ALIGNMENT = 4; |
||
57 | const uint32_t WIN_RES_DATA_ALIGNMENT = 4; |
||
58 | const uint16_t WIN_RES_PURE_MOVEABLE = 0x0030; |
||
59 | |||
60 | struct 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. |
||
67 | struct 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 | |||
84 | struct 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 | |||
92 | class EmptyResError : public GenericBinaryError { |
||
93 | public: |
||
94 | EmptyResError(Twine Msg, object_error ECOverride) |
||
95 | : GenericBinaryError(Msg, ECOverride) {} |
||
96 | }; |
||
97 | |||
98 | class ResourceEntryRef { |
||
99 | public: |
||
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 | |||
115 | private: |
||
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; |
||
125 | const WindowsResource *Owner; |
||
126 | 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 | |||
136 | class WindowsResource : public Binary { |
||
137 | public: |
||
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 | |||
145 | private: |
||
146 | friend class ResourceEntryRef; |
||
147 | |||
148 | WindowsResource(MemoryBufferRef Source); |
||
149 | |||
150 | BinaryByteStream BBS; |
||
151 | }; |
||
152 | |||
153 | class WindowsResourceParser { |
||
154 | public: |
||
155 | class TreeNode; |
||
156 | WindowsResourceParser(bool MinGW = false); |
||
157 | Error parse(WindowsResource *WR, std::vector<std::string> &Duplicates); |
||
158 | Error parse(ResourceSectionRef &RSR, StringRef Filename, |
||
159 | std::vector<std::string> &Duplicates); |
||
160 | void cleanUpManifests(std::vector<std::string> &Duplicates); |
||
161 | void printTree(raw_ostream &OS) const; |
||
162 | const TreeNode &getTree() const { return Root; } |
||
163 | ArrayRef<std::vector<uint8_t>> getData() const { return Data; } |
||
164 | ArrayRef<std::vector<UTF16>> getStringTable() const { return StringTable; } |
||
165 | |||
166 | class TreeNode { |
||
167 | public: |
||
168 | template <typename T> |
||
169 | using Children = std::map<T, std::unique_ptr<TreeNode>>; |
||
170 | |||
171 | void print(ScopedPrinter &Writer, StringRef Name) const; |
||
172 | uint32_t getTreeSize() const; |
||
173 | uint32_t getStringIndex() const { return StringIndex; } |
||
174 | uint32_t getDataIndex() const { return DataIndex; } |
||
175 | uint16_t getMajorVersion() const { return MajorVersion; } |
||
176 | uint16_t getMinorVersion() const { return MinorVersion; } |
||
177 | uint32_t getCharacteristics() const { return Characteristics; } |
||
178 | bool checkIsDataNode() const { return IsDataNode; } |
||
179 | const Children<uint32_t> &getIDChildren() const { return IDChildren; } |
||
180 | const Children<std::string> &getStringChildren() const { |
||
181 | return StringChildren; |
||
182 | } |
||
183 | |||
184 | private: |
||
185 | friend class WindowsResourceParser; |
||
186 | |||
187 | // Index is the StringTable vector index for this node's name. |
||
188 | static std::unique_ptr<TreeNode> createStringNode(uint32_t Index); |
||
189 | static std::unique_ptr<TreeNode> createIDNode(); |
||
190 | // DataIndex is the Data vector index that the data node points at. |
||
191 | static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion, |
||
192 | uint16_t MinorVersion, |
||
193 | uint32_t Characteristics, |
||
194 | uint32_t Origin, |
||
195 | uint32_t DataIndex); |
||
196 | |||
197 | explicit TreeNode(uint32_t StringIndex); |
||
198 | TreeNode(uint16_t MajorVersion, uint16_t MinorVersion, |
||
199 | uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex); |
||
200 | |||
201 | bool addEntry(const ResourceEntryRef &Entry, uint32_t Origin, |
||
202 | std::vector<std::vector<uint8_t>> &Data, |
||
203 | std::vector<std::vector<UTF16>> &StringTable, |
||
204 | TreeNode *&Result); |
||
205 | TreeNode &addTypeNode(const ResourceEntryRef &Entry, |
||
206 | std::vector<std::vector<UTF16>> &StringTable); |
||
207 | TreeNode &addNameNode(const ResourceEntryRef &Entry, |
||
208 | std::vector<std::vector<UTF16>> &StringTable); |
||
209 | bool addLanguageNode(const ResourceEntryRef &Entry, uint32_t Origin, |
||
210 | std::vector<std::vector<uint8_t>> &Data, |
||
211 | TreeNode *&Result); |
||
212 | bool addDataChild(uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion, |
||
213 | uint32_t Characteristics, uint32_t Origin, |
||
214 | uint32_t DataIndex, TreeNode *&Result); |
||
215 | TreeNode &addIDChild(uint32_t ID); |
||
216 | TreeNode &addNameChild(ArrayRef<UTF16> NameRef, |
||
217 | std::vector<std::vector<UTF16>> &StringTable); |
||
218 | void shiftDataIndexDown(uint32_t Index); |
||
219 | |||
220 | bool IsDataNode = false; |
||
221 | uint32_t StringIndex; |
||
222 | uint32_t DataIndex; |
||
223 | Children<uint32_t> IDChildren; |
||
224 | Children<std::string> StringChildren; |
||
225 | uint16_t MajorVersion = 0; |
||
226 | uint16_t MinorVersion = 0; |
||
227 | uint32_t Characteristics = 0; |
||
228 | |||
229 | // The .res file that defined this TreeNode, for diagnostics. |
||
230 | // Index into InputFilenames. |
||
231 | uint32_t Origin; |
||
232 | }; |
||
233 | |||
234 | struct StringOrID { |
||
235 | bool IsString; |
||
236 | ArrayRef<UTF16> String; |
||
237 | uint32_t ID; |
||
238 | |||
239 | StringOrID(uint32_t ID) : IsString(false), ID(ID) {} |
||
240 | StringOrID(ArrayRef<UTF16> String) : IsString(true), String(String) {} |
||
241 | }; |
||
242 | |||
243 | private: |
||
244 | Error addChildren(TreeNode &Node, ResourceSectionRef &RSR, |
||
245 | const coff_resource_dir_table &Table, uint32_t Origin, |
||
246 | std::vector<StringOrID> &Context, |
||
247 | std::vector<std::string> &Duplicates); |
||
248 | bool shouldIgnoreDuplicate(const ResourceEntryRef &Entry) const; |
||
249 | bool shouldIgnoreDuplicate(const std::vector<StringOrID> &Context) const; |
||
250 | |||
251 | TreeNode Root; |
||
252 | std::vector<std::vector<uint8_t>> Data; |
||
253 | std::vector<std::vector<UTF16>> StringTable; |
||
254 | |||
255 | std::vector<std::string> InputFilenames; |
||
256 | |||
257 | bool MinGW; |
||
258 | }; |
||
259 | |||
260 | Expected<std::unique_ptr<MemoryBuffer>> |
||
261 | writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType, |
||
262 | const WindowsResourceParser &Parser, |
||
263 | uint32_t TimeDateStamp); |
||
264 | |||
265 | void printResourceTypeName(uint16_t TypeID, raw_ostream &OS); |
||
266 | } // namespace object |
||
267 | } // namespace llvm |
||
268 | |||
269 | #endif |