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