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