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