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