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