|  | //===-- ResourceSerializator.h ----------------------------------*- C++-*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===---------------------------------------------------------------------===// | 
|  | // | 
|  | // This defines a visitor serializing resources to a .res stream. | 
|  | // | 
|  | //===---------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H | 
|  | #define LLVM_TOOLS_LLVMRC_RESOURCESERIALIZATOR_H | 
|  |  | 
|  | #include "ResourceScriptStmt.h" | 
|  | #include "ResourceVisitor.h" | 
|  |  | 
|  | #include "llvm/Support/Endian.h" | 
|  |  | 
|  | namespace llvm { | 
|  |  | 
|  | class MemoryBuffer; | 
|  |  | 
|  | namespace rc { | 
|  |  | 
|  | enum CodePage { | 
|  | CpAcp = 0,        // The current used codepage. Since there's no such | 
|  | // notion in LLVM what codepage it actually means, | 
|  | // this only allows ASCII. | 
|  | CpWin1252 = 1252, // A codepage where most 8 bit values correspond to | 
|  | // unicode code points with the same value. | 
|  | CpUtf8 = 65001,   // UTF-8. | 
|  | }; | 
|  |  | 
|  | struct WriterParams { | 
|  | std::vector<std::string> Include;   // Additional folders to search for files. | 
|  | bool NoInclude;                     // Ignore the INCLUDE variable. | 
|  | StringRef InputFilePath;            // The full path of the input file. | 
|  | int CodePage = CpAcp;               // The codepage for interpreting characters. | 
|  | }; | 
|  |  | 
|  | class ResourceFileWriter : public Visitor { | 
|  | public: | 
|  | ResourceFileWriter(const WriterParams &Params, | 
|  | std::unique_ptr<raw_fd_ostream> Stream) | 
|  | : Params(Params), FS(std::move(Stream)), IconCursorID(1) { | 
|  | assert(FS && "Output stream needs to be provided to the serializator"); | 
|  | } | 
|  |  | 
|  | Error visitNullResource(const RCResource *) override; | 
|  | Error visitAcceleratorsResource(const RCResource *) override; | 
|  | Error visitCursorResource(const RCResource *) override; | 
|  | Error visitDialogResource(const RCResource *) override; | 
|  | Error visitHTMLResource(const RCResource *) override; | 
|  | Error visitIconResource(const RCResource *) override; | 
|  | Error visitMenuResource(const RCResource *) override; | 
|  | Error visitMenuExResource(const RCResource *) override; | 
|  | Error visitVersionInfoResource(const RCResource *) override; | 
|  | Error visitStringTableResource(const RCResource *) override; | 
|  | Error visitUserDefinedResource(const RCResource *) override; | 
|  |  | 
|  | Error visitCaptionStmt(const CaptionStmt *) override; | 
|  | Error visitCharacteristicsStmt(const CharacteristicsStmt *) override; | 
|  | Error visitClassStmt(const ClassStmt *) override; | 
|  | Error visitExStyleStmt(const ExStyleStmt *) override; | 
|  | Error visitFontStmt(const FontStmt *) override; | 
|  | Error visitLanguageStmt(const LanguageResource *) override; | 
|  | Error visitStyleStmt(const StyleStmt *) override; | 
|  | Error visitVersionStmt(const VersionStmt *) override; | 
|  |  | 
|  | // Stringtables are output at the end of .res file. We need a separate | 
|  | // function to do it. | 
|  | Error dumpAllStringTables(); | 
|  |  | 
|  | bool AppendNull = false; // Append '\0' to each existing STRINGTABLE element? | 
|  |  | 
|  | struct ObjectInfo { | 
|  | uint16_t LanguageInfo; | 
|  | uint32_t Characteristics; | 
|  | uint32_t VersionInfo; | 
|  |  | 
|  | std::optional<uint32_t> Style; | 
|  | std::optional<uint32_t> ExStyle; | 
|  | StringRef Caption; | 
|  | struct FontInfo { | 
|  | uint32_t Size; | 
|  | StringRef Typeface; | 
|  | uint32_t Weight; | 
|  | bool IsItalic; | 
|  | uint32_t Charset; | 
|  | }; | 
|  | std::optional<FontInfo> Font; | 
|  | IntOrString Class; | 
|  |  | 
|  | ObjectInfo() | 
|  | : LanguageInfo(0), Characteristics(0), VersionInfo(0), | 
|  | Class(StringRef()) {} | 
|  | } ObjectData; | 
|  |  | 
|  | struct StringTableInfo { | 
|  | // Each STRINGTABLE bundle depends on ID of the bundle and language | 
|  | // description. | 
|  | using BundleKey = std::pair<uint16_t, uint16_t>; | 
|  | // Each bundle is in fact an array of 16 strings. | 
|  | struct Bundle { | 
|  | std::array<std::optional<std::vector<StringRef>>, 16> Data; | 
|  | ObjectInfo DeclTimeInfo; | 
|  | uint16_t MemoryFlags; | 
|  | Bundle(const ObjectInfo &Info, uint16_t Flags) | 
|  | : DeclTimeInfo(Info), MemoryFlags(Flags) {} | 
|  | }; | 
|  | std::map<BundleKey, Bundle> BundleData; | 
|  | // Bundles are listed in the order of their first occurrence. | 
|  | std::vector<BundleKey> BundleList; | 
|  | } StringTableData; | 
|  |  | 
|  | private: | 
|  | Error handleError(Error Err, const RCResource *Res); | 
|  |  | 
|  | Error | 
|  | writeResource(const RCResource *Res, | 
|  | Error (ResourceFileWriter::*BodyWriter)(const RCResource *)); | 
|  |  | 
|  | // NullResource | 
|  | Error writeNullBody(const RCResource *); | 
|  |  | 
|  | // AcceleratorsResource | 
|  | Error writeSingleAccelerator(const AcceleratorsResource::Accelerator &, | 
|  | bool IsLastItem); | 
|  | Error writeAcceleratorsBody(const RCResource *); | 
|  |  | 
|  | // BitmapResource | 
|  | Error visitBitmapResource(const RCResource *) override; | 
|  | Error writeBitmapBody(const RCResource *); | 
|  |  | 
|  | // CursorResource and IconResource | 
|  | Error visitIconOrCursorResource(const RCResource *); | 
|  | Error visitIconOrCursorGroup(const RCResource *); | 
|  | Error visitSingleIconOrCursor(const RCResource *); | 
|  | Error writeSingleIconOrCursorBody(const RCResource *); | 
|  | Error writeIconOrCursorGroupBody(const RCResource *); | 
|  |  | 
|  | // DialogResource | 
|  | Error writeSingleDialogControl(const Control &, bool IsExtended); | 
|  | Error writeDialogBody(const RCResource *); | 
|  |  | 
|  | // HTMLResource | 
|  | Error writeHTMLBody(const RCResource *); | 
|  |  | 
|  | // MenuResource | 
|  | Error writeMenuDefinition(const std::unique_ptr<MenuDefinition> &, | 
|  | uint16_t Flags); | 
|  | Error writeMenuExDefinition(const std::unique_ptr<MenuDefinition> &, | 
|  | uint16_t Flags); | 
|  | Error writeMenuDefinitionList(const MenuDefinitionList &List); | 
|  | Error writeMenuExDefinitionList(const MenuDefinitionList &List); | 
|  | Error writeMenuBody(const RCResource *); | 
|  | Error writeMenuExBody(const RCResource *); | 
|  |  | 
|  | // StringTableResource | 
|  | Error visitStringTableBundle(const RCResource *); | 
|  | Error writeStringTableBundleBody(const RCResource *); | 
|  | Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle, | 
|  | uint16_t StringID, | 
|  | const std::vector<StringRef> &String); | 
|  |  | 
|  | // User defined resource | 
|  | Error writeUserDefinedBody(const RCResource *); | 
|  |  | 
|  | // VersionInfoResource | 
|  | Error writeVersionInfoBody(const RCResource *); | 
|  | Error writeVersionInfoBlock(const VersionInfoBlock &); | 
|  | Error writeVersionInfoValue(const VersionInfoValue &); | 
|  |  | 
|  | const WriterParams &Params; | 
|  |  | 
|  | // Output stream handling. | 
|  | std::unique_ptr<raw_fd_ostream> FS; | 
|  |  | 
|  | uint64_t tell() const { return FS->tell(); } | 
|  |  | 
|  | uint64_t writeObject(const ArrayRef<uint8_t> Data); | 
|  |  | 
|  | template <typename T> uint64_t writeInt(const T &Value) { | 
|  | support::detail::packed_endian_specific_integral< | 
|  | T, llvm::endianness::little, support::unaligned> | 
|  | Object(Value); | 
|  | return writeObject(Object); | 
|  | } | 
|  |  | 
|  | template <typename T> uint64_t writeObject(const T &Value) { | 
|  | return writeObject(ArrayRef<uint8_t>( | 
|  | reinterpret_cast<const uint8_t *>(&Value), sizeof(T))); | 
|  | } | 
|  |  | 
|  | template <typename T> void writeObjectAt(const T &Value, uint64_t Position) { | 
|  | FS->pwrite((const char *)&Value, sizeof(T), Position); | 
|  | } | 
|  |  | 
|  | Error writeCString(StringRef Str, bool WriteTerminator = true); | 
|  |  | 
|  | Error writeIdentifier(const IntOrString &Ident); | 
|  | Error writeIntOrString(const IntOrString &Data); | 
|  |  | 
|  | void writeRCInt(RCInt); | 
|  |  | 
|  | Error appendFile(StringRef Filename); | 
|  |  | 
|  | void padStream(uint64_t Length); | 
|  |  | 
|  | Expected<std::unique_ptr<MemoryBuffer>> loadFile(StringRef File) const; | 
|  |  | 
|  | // Icon and cursor IDs are allocated starting from 1 and increasing for | 
|  | // each icon/cursor dumped. This maintains the current ID to be allocated. | 
|  | uint16_t IconCursorID; | 
|  | }; | 
|  |  | 
|  | } // namespace rc | 
|  | } // namespace llvm | 
|  |  | 
|  | #endif |