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

source code of llvm/tools/llvm-rc/ResourceFileWriter.h