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