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