//===-- 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 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 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 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; Optional Style; Optional ExStyle; StringRef Caption; struct FontInfo { uint32_t Size; StringRef Typeface; uint32_t Weight; bool IsItalic; uint32_t Charset; }; Optional 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; // Each bundle is in fact an array of 16 strings. struct Bundle { std::array>, 16> Data; ObjectInfo DeclTimeInfo; uint16_t MemoryFlags; Bundle(const ObjectInfo &Info, uint16_t Flags) : DeclTimeInfo(Info), MemoryFlags(Flags) {} }; std::map BundleData; // Bundles are listed in the order of their first occurrence. std::vector 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 &, uint16_t Flags); Error writeMenuDefinitionList(const MenuDefinitionList &List); Error writeMenuBody(const RCResource *); // StringTableResource Error visitStringTableBundle(const RCResource *); Error writeStringTableBundleBody(const RCResource *); Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle, uint16_t StringID, const std::vector &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 FS; uint64_t tell() const { return FS->tell(); } uint64_t writeObject(const ArrayRef Data); template uint64_t writeInt(const T &Value) { support::detail::packed_endian_specific_integral Object(Value); return writeObject(Object); } template uint64_t writeObject(const T &Value) { return writeObject(ArrayRef( reinterpret_cast(&Value), sizeof(T))); } template 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> 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