Home | History | Annotate | Line # | Download | only in llvm-rc
      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   bool NoInclude;                     // Ignore the INCLUDE variable.
     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:
     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 
     95     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;
    109       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 
    176   uint64_t tell() const { return FS->tell(); }
    177 
    178   uint64_t writeObject(const ArrayRef<uint8_t> Data);
    179 
    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 
    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 
    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