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