blob: fd04e608cf5fdcc7d902ca573c0d68db7932a6c5 [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"
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#include "llvm/Support/ScopedPrinter.h"
41
42#include <map>
43
44namespace llvm {
45namespace object {
46
47class WindowsResource;
48
49const size_t WIN_RES_MAGIC_SIZE = 16;
50const size_t WIN_RES_NULL_ENTRY_SIZE = 16;
51const uint32_t WIN_RES_HEADER_ALIGNMENT = 4;
52const uint32_t WIN_RES_DATA_ALIGNMENT = 4;
53const uint16_t WIN_RES_PURE_MOVEABLE = 0x0030;
54
55struct WinResHeaderPrefix {
56 support::ulittle32_t DataSize;
57 support::ulittle32_t HeaderSize;
58};
59
60// Type and Name may each either be an integer ID or a string. This struct is
61// only used in the case where they are both IDs.
62struct WinResIDs {
63 uint16_t TypeFlag;
64 support::ulittle16_t TypeID;
65 uint16_t NameFlag;
66 support::ulittle16_t NameID;
67
68 void setType(uint16_t ID) {
69 TypeFlag = 0xffff;
70 TypeID = ID;
71 }
72
73 void setName(uint16_t ID) {
74 NameFlag = 0xffff;
75 NameID = ID;
76 }
77};
78
79struct WinResHeaderSuffix {
80 support::ulittle32_t DataVersion;
81 support::ulittle16_t MemoryFlags;
82 support::ulittle16_t Language;
83 support::ulittle32_t Version;
84 support::ulittle32_t Characteristics;
85};
86
87class EmptyResError : public GenericBinaryError {
88public:
89 EmptyResError(Twine Msg, object_error ECOverride)
90 : GenericBinaryError(Msg, ECOverride) {}
91};
92
93class ResourceEntryRef {
94public:
95 Error moveNext(bool &End);
96 bool checkTypeString() const { return IsStringType; }
97 ArrayRef<UTF16> getTypeString() const { return Type; }
98 uint16_t getTypeID() const { return TypeID; }
99 bool checkNameString() const { return IsStringName; }
100 ArrayRef<UTF16> getNameString() const { return Name; }
101 uint16_t getNameID() const { return NameID; }
102 uint16_t getDataVersion() const { return Suffix->DataVersion; }
103 uint16_t getLanguage() const { return Suffix->Language; }
104 uint16_t getMemoryFlags() const { return Suffix->MemoryFlags; }
105 uint16_t getMajorVersion() const { return Suffix->Version >> 16; }
106 uint16_t getMinorVersion() const { return Suffix->Version; }
107 uint32_t getCharacteristics() const { return Suffix->Characteristics; }
108 ArrayRef<uint8_t> getData() const { return Data; }
109
110private:
111 friend class WindowsResource;
112
113 ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner);
114 Error loadNext();
115
116 static Expected<ResourceEntryRef> create(BinaryStreamRef Ref,
117 const WindowsResource *Owner);
118
119 BinaryStreamReader Reader;
120 bool IsStringType;
121 ArrayRef<UTF16> Type;
122 uint16_t TypeID;
123 bool IsStringName;
124 ArrayRef<UTF16> Name;
125 uint16_t NameID;
126 const WinResHeaderSuffix *Suffix = nullptr;
127 ArrayRef<uint8_t> Data;
128};
129
130class WindowsResource : public Binary {
131public:
132 Expected<ResourceEntryRef> getHeadEntry();
133
134 static bool classof(const Binary *V) { return V->isWinRes(); }
135
136 static Expected<std::unique_ptr<WindowsResource>>
137 createWindowsResource(MemoryBufferRef Source);
138
139private:
140 friend class ResourceEntryRef;
141
142 WindowsResource(MemoryBufferRef Source);
143
144 BinaryByteStream BBS;
145};
146
147class WindowsResourceParser {
148public:
149 class TreeNode;
150 WindowsResourceParser();
151 Error parse(WindowsResource *WR);
152 void printTree(raw_ostream &OS) const;
153 const TreeNode &getTree() const { return Root; }
154 const ArrayRef<std::vector<uint8_t>> getData() const { return Data; }
155 const ArrayRef<std::vector<UTF16>> getStringTable() const {
156 return StringTable;
157 }
158
159 class TreeNode {
160 public:
161 template <typename T>
162 using Children = std::map<T, std::unique_ptr<TreeNode>>;
163
164 void print(ScopedPrinter &Writer, StringRef Name) const;
165 uint32_t getTreeSize() const;
166 uint32_t getStringIndex() const { return StringIndex; }
167 uint32_t getDataIndex() const { return DataIndex; }
168 uint16_t getMajorVersion() const { return MajorVersion; }
169 uint16_t getMinorVersion() const { return MinorVersion; }
170 uint32_t getCharacteristics() const { return Characteristics; }
171 bool checkIsDataNode() const { return IsDataNode; }
172 const Children<uint32_t> &getIDChildren() const { return IDChildren; }
173 const Children<std::string> &getStringChildren() const {
174 return StringChildren;
175 }
176
177 private:
178 friend class WindowsResourceParser;
179
180 static uint32_t StringCount;
181 static uint32_t DataCount;
182
183 static std::unique_ptr<TreeNode> createStringNode();
184 static std::unique_ptr<TreeNode> createIDNode();
185 static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion,
186 uint16_t MinorVersion,
187 uint32_t Characteristics);
188
189 explicit TreeNode(bool IsStringNode);
190 TreeNode(uint16_t MajorVersion, uint16_t MinorVersion,
191 uint32_t Characteristics);
192
193 void addEntry(const ResourceEntryRef &Entry, bool &IsNewTypeString,
194 bool &IsNewNameString);
195 TreeNode &addTypeNode(const ResourceEntryRef &Entry, bool &IsNewTypeString);
196 TreeNode &addNameNode(const ResourceEntryRef &Entry, bool &IsNewNameString);
197 TreeNode &addLanguageNode(const ResourceEntryRef &Entry);
198 TreeNode &addChild(uint32_t ID, bool IsDataNode = false,
199 uint16_t MajorVersion = 0, uint16_t MinorVersion = 0,
200 uint32_t Characteristics = 0);
201 TreeNode &addChild(ArrayRef<UTF16> NameRef, bool &IsNewString);
202
203 bool IsDataNode = false;
204 uint32_t StringIndex;
205 uint32_t DataIndex;
206 Children<uint32_t> IDChildren;
207 Children<std::string> StringChildren;
208 uint16_t MajorVersion = 0;
209 uint16_t MinorVersion = 0;
210 uint32_t Characteristics = 0;
211 };
212
213private:
214 TreeNode Root;
215 std::vector<std::vector<uint8_t>> Data;
216 std::vector<std::vector<UTF16>> StringTable;
217};
218
219Expected<std::unique_ptr<MemoryBuffer>>
220writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType,
221 const WindowsResourceParser &Parser);
222
223} // namespace object
224} // namespace llvm
225
226#endif