1 //===-- ResourceSerializator.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 defines a visitor serializing resources to a .res stream. 10 // 11 //===---------------------------------------------------------------------===// 12 13 #ifndef LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H 14 #define LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H 15 16 #include "ResourceScriptStmt.h" 17 #include "ResourceVisitor.h" 18 19 #include "llvm/Support/Endian.h" 20 21 namespace llvm { 22 23 class MemoryBuffer; 24 25 namespace rc { 26 27 enum CodePage { 28 CpAcp = 0, // The current used codepage. Since there's no such 29 // notion in LLVM what codepage it actually means, 30 // this only allows ASCII. 31 CpWin1252 = 1252, // A codepage where most 8 bit values correspond to 32 // unicode code points with the same value. 33 CpUtf8 = 65001, // UTF-8. 34 }; 35 36 struct WriterParams { 37 std::vector<std::string> Include; // Additional folders to search for files. 38 std::vector<std::string> NoInclude; // Folders to exclude from file search. 39 StringRef InputFilePath; // The full path of the input file. 40 int CodePage = CpAcp; // The codepage for interpreting characters. 41 }; 42 43 class ResourceFileWriter : public Visitor { 44 public: ResourceFileWriter(const WriterParams & Params,std::unique_ptr<raw_fd_ostream> Stream)45 ResourceFileWriter(const WriterParams &Params, 46 std::unique_ptr<raw_fd_ostream> Stream) 47 : Params(Params), FS(std::move(Stream)), IconCursorID(1) { 48 assert(FS && "Output stream needs to be provided to the serializator"); 49 } 50 51 Error visitNullResource(const RCResource *) override; 52 Error visitAcceleratorsResource(const RCResource *) override; 53 Error visitCursorResource(const RCResource *) override; 54 Error visitDialogResource(const RCResource *) override; 55 Error visitHTMLResource(const RCResource *) override; 56 Error visitIconResource(const RCResource *) override; 57 Error visitMenuResource(const RCResource *) override; 58 Error visitVersionInfoResource(const RCResource *) override; 59 Error visitStringTableResource(const RCResource *) override; 60 Error visitUserDefinedResource(const RCResource *) override; 61 62 Error visitCaptionStmt(const CaptionStmt *) override; 63 Error visitCharacteristicsStmt(const CharacteristicsStmt *) override; 64 Error visitClassStmt(const ClassStmt *) override; 65 Error visitExStyleStmt(const ExStyleStmt *) override; 66 Error visitFontStmt(const FontStmt *) override; 67 Error visitLanguageStmt(const LanguageResource *) override; 68 Error visitStyleStmt(const StyleStmt *) override; 69 Error visitVersionStmt(const VersionStmt *) override; 70 71 // Stringtables are output at the end of .res file. We need a separate 72 // function to do it. 73 Error dumpAllStringTables(); 74 75 bool AppendNull = false; // Append '\0' to each existing STRINGTABLE element? 76 77 struct ObjectInfo { 78 uint16_t LanguageInfo; 79 uint32_t Characteristics; 80 uint32_t VersionInfo; 81 82 Optional<uint32_t> Style; 83 Optional<uint32_t> ExStyle; 84 StringRef Caption; 85 struct FontInfo { 86 uint32_t Size; 87 StringRef Typeface; 88 uint32_t Weight; 89 bool IsItalic; 90 uint32_t Charset; 91 }; 92 Optional<FontInfo> Font; 93 IntOrString Class; 94 ObjectInfoObjectInfo95 ObjectInfo() 96 : LanguageInfo(0), Characteristics(0), VersionInfo(0), 97 Class(StringRef()) {} 98 } ObjectData; 99 100 struct StringTableInfo { 101 // Each STRINGTABLE bundle depends on ID of the bundle and language 102 // description. 103 using BundleKey = std::pair<uint16_t, uint16_t>; 104 // Each bundle is in fact an array of 16 strings. 105 struct Bundle { 106 std::array<Optional<std::vector<StringRef>>, 16> Data; 107 ObjectInfo DeclTimeInfo; 108 uint16_t MemoryFlags; BundleStringTableInfo::Bundle109 Bundle(const ObjectInfo &Info, uint16_t Flags) 110 : DeclTimeInfo(Info), MemoryFlags(Flags) {} 111 }; 112 std::map<BundleKey, Bundle> BundleData; 113 // Bundles are listed in the order of their first occurrence. 114 std::vector<BundleKey> BundleList; 115 } StringTableData; 116 117 private: 118 Error handleError(Error Err, const RCResource *Res); 119 120 Error 121 writeResource(const RCResource *Res, 122 Error (ResourceFileWriter::*BodyWriter)(const RCResource *)); 123 124 // NullResource 125 Error writeNullBody(const RCResource *); 126 127 // AcceleratorsResource 128 Error writeSingleAccelerator(const AcceleratorsResource::Accelerator &, 129 bool IsLastItem); 130 Error writeAcceleratorsBody(const RCResource *); 131 132 // BitmapResource 133 Error visitBitmapResource(const RCResource *) override; 134 Error writeBitmapBody(const RCResource *); 135 136 // CursorResource and IconResource 137 Error visitIconOrCursorResource(const RCResource *); 138 Error visitIconOrCursorGroup(const RCResource *); 139 Error visitSingleIconOrCursor(const RCResource *); 140 Error writeSingleIconOrCursorBody(const RCResource *); 141 Error writeIconOrCursorGroupBody(const RCResource *); 142 143 // DialogResource 144 Error writeSingleDialogControl(const Control &, bool IsExtended); 145 Error writeDialogBody(const RCResource *); 146 147 // HTMLResource 148 Error writeHTMLBody(const RCResource *); 149 150 // MenuResource 151 Error writeMenuDefinition(const std::unique_ptr<MenuDefinition> &, 152 uint16_t Flags); 153 Error writeMenuDefinitionList(const MenuDefinitionList &List); 154 Error writeMenuBody(const RCResource *); 155 156 // StringTableResource 157 Error visitStringTableBundle(const RCResource *); 158 Error writeStringTableBundleBody(const RCResource *); 159 Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle, 160 uint16_t StringID, 161 const std::vector<StringRef> &String); 162 163 // User defined resource 164 Error writeUserDefinedBody(const RCResource *); 165 166 // VersionInfoResource 167 Error writeVersionInfoBody(const RCResource *); 168 Error writeVersionInfoBlock(const VersionInfoBlock &); 169 Error writeVersionInfoValue(const VersionInfoValue &); 170 171 const WriterParams &Params; 172 173 // Output stream handling. 174 std::unique_ptr<raw_fd_ostream> FS; 175 tell()176 uint64_t tell() const { return FS->tell(); } 177 178 uint64_t writeObject(const ArrayRef<uint8_t> Data); 179 writeInt(const T & Value)180 template <typename T> uint64_t writeInt(const T &Value) { 181 support::detail::packed_endian_specific_integral<T, support::little, 182 support::unaligned> 183 Object(Value); 184 return writeObject(Object); 185 } 186 writeObject(const T & Value)187 template <typename T> uint64_t writeObject(const T &Value) { 188 return writeObject(ArrayRef<uint8_t>( 189 reinterpret_cast<const uint8_t *>(&Value), sizeof(T))); 190 } 191 writeObjectAt(const T & Value,uint64_t Position)192 template <typename T> void writeObjectAt(const T &Value, uint64_t Position) { 193 FS->pwrite((const char *)&Value, sizeof(T), Position); 194 } 195 196 Error writeCString(StringRef Str, bool WriteTerminator = true); 197 198 Error writeIdentifier(const IntOrString &Ident); 199 Error writeIntOrString(const IntOrString &Data); 200 201 void writeRCInt(RCInt); 202 203 Error appendFile(StringRef Filename); 204 205 void padStream(uint64_t Length); 206 207 Expected<std::unique_ptr<MemoryBuffer>> loadFile(StringRef File) const; 208 209 // Icon and cursor IDs are allocated starting from 1 and increasing for 210 // each icon/cursor dumped. This maintains the current ID to be allocated. 211 uint16_t IconCursorID; 212 }; 213 214 } // namespace rc 215 } // namespace llvm 216 217 #endif 218