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