xref: /llvm-project/llvm/tools/llvm-rc/ResourceFileWriter.h (revision b35bdb1d7b31c2267af14ee7e097c78d89c3ddb0)
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 namespace llvm {
23 
24 class MemoryBuffer;
25 
26 namespace rc {
27 
28 enum 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 
37 struct 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 
44 class ResourceFileWriter : public Visitor {
45 public:
ResourceFileWriter(const WriterParams & Params,std::unique_ptr<raw_fd_ostream> Stream)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 
ObjectInfoObjectInfo99     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;
BundleStringTableInfo::Bundle113       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 
121 private:
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 
tell()184   uint64_t tell() const { return FS->tell(); }
185 
186   uint64_t writeObject(const ArrayRef<uint8_t> Data);
187 
writeInt(const T & Value)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 
writeObject(const T & Value)195   template <typename T> uint64_t writeObject(const T &Value) {
196     return writeObject(ArrayRef<uint8_t>(
197         reinterpret_cast<const uint8_t *>(&Value), sizeof(T)));
198   }
199 
writeObjectAt(const T & Value,uint64_t Position)200   template <typename T> void writeObjectAt(const T &Value, uint64_t Position) {
201     FS->pwrite((const char *)&Value, sizeof(T), 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