blob: 1d7583db1149e856768a880bd9e656c56f4f4bbc [file] [log] [blame]
Marek Sokolowski8f193432017-09-29 17:14:09 +00001//===-- ResourceSerializator.h ----------------------------------*- C++-*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Marek Sokolowski8f193432017-09-29 17:14:09 +00006//
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 {
Zachary Turnerbd159d32017-11-17 01:00:35 +000022
23class MemoryBuffer;
24
Marek Sokolowski8f193432017-09-29 17:14:09 +000025namespace rc {
26
Martin Storsjod1d046a2018-05-02 19:43:44 +000027enum 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 {
Zachary Turnerfa0ca6c2017-10-11 20:12:09 +000037 std::vector<std::string> Include; // Additional folders to search for files.
38 std::vector<std::string> NoInclude; // Folders to exclude from file search.
39 StringRef InputFilePath; // The full path of the input file.
Martin Storsjod1d046a2018-05-02 19:43:44 +000040 int CodePage = CpAcp; // The codepage for interpreting characters.
Zachary Turnerfa0ca6c2017-10-11 20:12:09 +000041};
42
Marek Sokolowski8f193432017-09-29 17:14:09 +000043class ResourceFileWriter : public Visitor {
44public:
Martin Storsjod1d046a2018-05-02 19:43:44 +000045 ResourceFileWriter(const WriterParams &Params,
Zachary Turnerfa0ca6c2017-10-11 20:12:09 +000046 std::unique_ptr<raw_fd_ostream> Stream)
47 : Params(Params), FS(std::move(Stream)), IconCursorID(1) {
Marek Sokolowski8f193432017-09-29 17:14:09 +000048 assert(FS && "Output stream needs to be provided to the serializator");
49 }
50
51 Error visitNullResource(const RCResource *) override;
Marek Sokolowski22fccd62017-09-29 19:07:44 +000052 Error visitAcceleratorsResource(const RCResource *) override;
Zachary Turnerc3ab0132017-10-06 21:25:44 +000053 Error visitCursorResource(const RCResource *) override;
Marek Sokolowski7f7745c2017-09-30 00:38:52 +000054 Error visitDialogResource(const RCResource *) override;
Marek Sokolowski8f193432017-09-29 17:14:09 +000055 Error visitHTMLResource(const RCResource *) override;
Zachary Turnerc3ab0132017-10-06 21:25:44 +000056 Error visitIconResource(const RCResource *) override;
Marek Sokolowski42f494d2017-09-29 22:25:05 +000057 Error visitMenuResource(const RCResource *) override;
Zachary Turner07bc04f2017-10-06 21:26:06 +000058 Error visitVersionInfoResource(const RCResource *) override;
Zachary Turnerda366692017-10-06 21:30:55 +000059 Error visitStringTableResource(const RCResource *) override;
Zachary Turner9d8b3582017-10-06 21:52:15 +000060 Error visitUserDefinedResource(const RCResource *) override;
Marek Sokolowski8f193432017-09-29 17:14:09 +000061
Zachary Turner420090a2017-10-06 20:51:20 +000062 Error visitCaptionStmt(const CaptionStmt *) override;
Marek Sokolowski22fccd62017-09-29 19:07:44 +000063 Error visitCharacteristicsStmt(const CharacteristicsStmt *) override;
Martin Storsjoe241ce62018-05-15 19:21:28 +000064 Error visitClassStmt(const ClassStmt *) override;
Martin Storsjoa876b5c2018-11-29 12:17:39 +000065 Error visitExStyleStmt(const ExStyleStmt *) override;
Zachary Turner420090a2017-10-06 20:51:20 +000066 Error visitFontStmt(const FontStmt *) override;
Marek Sokolowski8f193432017-09-29 17:14:09 +000067 Error visitLanguageStmt(const LanguageResource *) override;
Zachary Turner420090a2017-10-06 20:51:20 +000068 Error visitStyleStmt(const StyleStmt *) override;
Marek Sokolowski22fccd62017-09-29 19:07:44 +000069 Error visitVersionStmt(const VersionStmt *) override;
Marek Sokolowski8f193432017-09-29 17:14:09 +000070
Zachary Turnerda366692017-10-06 21:30:55 +000071 // Stringtables are output at the end of .res file. We need a separate
72 // function to do it.
73 Error dumpAllStringTables();
74
75 bool AppendNull; // Append '\0' to each existing STRINGTABLE element?
76
Marek Sokolowski8f193432017-09-29 17:14:09 +000077 struct ObjectInfo {
78 uint16_t LanguageInfo;
Marek Sokolowski22fccd62017-09-29 19:07:44 +000079 uint32_t Characteristics;
80 uint32_t VersionInfo;
Marek Sokolowski8f193432017-09-29 17:14:09 +000081
Zachary Turner420090a2017-10-06 20:51:20 +000082 Optional<uint32_t> Style;
Martin Storsjoa876b5c2018-11-29 12:17:39 +000083 Optional<uint32_t> ExStyle;
Zachary Turner420090a2017-10-06 20:51:20 +000084 StringRef Caption;
85 struct FontInfo {
86 uint32_t Size;
87 StringRef Typeface;
88 uint32_t Weight;
89 bool IsItalic;
90 uint32_t Charset;
91 };
92 Optional<FontInfo> Font;
Martin Storsjoe241ce62018-05-15 19:21:28 +000093 IntOrString Class;
Zachary Turner420090a2017-10-06 20:51:20 +000094
Martin Storsjoe241ce62018-05-15 19:21:28 +000095 ObjectInfo()
96 : LanguageInfo(0), Characteristics(0), VersionInfo(0),
97 Class(StringRef()) {}
Marek Sokolowski8f193432017-09-29 17:14:09 +000098 } ObjectData;
99
Zachary Turnerda366692017-10-06 21:30:55 +0000100 struct StringTableInfo {
101 // Each STRINGTABLE bundle depends on ID of the bundle and language
102 // description.
103 using BundleKey = std::pair<uint16_t, uint16_t>;
104 // Each bundle is in fact an array of 16 strings.
105 struct Bundle {
106 std::array<Optional<StringRef>, 16> Data;
107 ObjectInfo DeclTimeInfo;
Martin Storsjo11adbac2018-05-15 06:35:29 +0000108 uint16_t MemoryFlags;
109 Bundle(const ObjectInfo &Info, uint16_t Flags)
110 : DeclTimeInfo(Info), MemoryFlags(Flags) {}
Zachary Turnerda366692017-10-06 21:30:55 +0000111 };
112 std::map<BundleKey, Bundle> BundleData;
Malcolm Parsons21e545d2018-01-24 10:33:39 +0000113 // Bundles are listed in the order of their first occurrence.
Zachary Turnerda366692017-10-06 21:30:55 +0000114 std::vector<BundleKey> BundleList;
115 } StringTableData;
116
Marek Sokolowski8f193432017-09-29 17:14:09 +0000117private:
Zachary Turner514b7102017-10-09 18:50:29 +0000118 Error handleError(Error Err, const RCResource *Res);
Marek Sokolowski8f193432017-09-29 17:14:09 +0000119
120 Error
121 writeResource(const RCResource *Res,
122 Error (ResourceFileWriter::*BodyWriter)(const RCResource *));
123
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000124 // NullResource
Marek Sokolowski8f193432017-09-29 17:14:09 +0000125 Error writeNullBody(const RCResource *);
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000126
127 // AcceleratorsResource
128 Error writeSingleAccelerator(const AcceleratorsResource::Accelerator &,
129 bool IsLastItem);
130 Error writeAcceleratorsBody(const RCResource *);
131
Martin Storsjo577b9812018-05-07 20:27:37 +0000132 // BitmapResource
Roman Lebedeve461a0f2018-05-07 21:06:53 +0000133 Error visitBitmapResource(const RCResource *) override;
Martin Storsjo577b9812018-05-07 20:27:37 +0000134 Error writeBitmapBody(const RCResource *);
135
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000136 // CursorResource and IconResource
137 Error visitIconOrCursorResource(const RCResource *);
138 Error visitIconOrCursorGroup(const RCResource *);
139 Error visitSingleIconOrCursor(const RCResource *);
140 Error writeSingleIconOrCursorBody(const RCResource *);
141 Error writeIconOrCursorGroupBody(const RCResource *);
142
Marek Sokolowski7f7745c2017-09-30 00:38:52 +0000143 // DialogResource
144 Error writeSingleDialogControl(const Control &, bool IsExtended);
145 Error writeDialogBody(const RCResource *);
146
Marek Sokolowski22fccd62017-09-29 19:07:44 +0000147 // HTMLResource
Marek Sokolowski8f193432017-09-29 17:14:09 +0000148 Error writeHTMLBody(const RCResource *);
149
Marek Sokolowski42f494d2017-09-29 22:25:05 +0000150 // MenuResource
151 Error writeMenuDefinition(const std::unique_ptr<MenuDefinition> &,
152 uint16_t Flags);
153 Error writeMenuDefinitionList(const MenuDefinitionList &List);
154 Error writeMenuBody(const RCResource *);
155
Zachary Turnerda366692017-10-06 21:30:55 +0000156 // StringTableResource
157 Error visitStringTableBundle(const RCResource *);
158 Error writeStringTableBundleBody(const RCResource *);
159 Error insertStringIntoBundle(StringTableInfo::Bundle &Bundle,
160 uint16_t StringID, StringRef String);
161
Zachary Turner9d8b3582017-10-06 21:52:15 +0000162 // User defined resource
163 Error writeUserDefinedBody(const RCResource *);
164
Zachary Turner07bc04f2017-10-06 21:26:06 +0000165 // VersionInfoResource
166 Error writeVersionInfoBody(const RCResource *);
167 Error writeVersionInfoBlock(const VersionInfoBlock &);
168 Error writeVersionInfoValue(const VersionInfoValue &);
169
Martin Storsjod1d046a2018-05-02 19:43:44 +0000170 const WriterParams &Params;
Zachary Turnerfa0ca6c2017-10-11 20:12:09 +0000171
Marek Sokolowski8f193432017-09-29 17:14:09 +0000172 // Output stream handling.
173 std::unique_ptr<raw_fd_ostream> FS;
174
175 uint64_t tell() const { return FS->tell(); }
176
177 uint64_t writeObject(const ArrayRef<uint8_t> Data);
178
179 template <typename T> uint64_t writeInt(const T &Value) {
180 support::detail::packed_endian_specific_integral<T, support::little,
181 support::unaligned>
182 Object(Value);
183 return writeObject(Object);
184 }
185
186 template <typename T> uint64_t writeObject(const T &Value) {
187 return writeObject(ArrayRef<uint8_t>(
188 reinterpret_cast<const uint8_t *>(&Value), sizeof(T)));
189 }
190
191 template <typename T> void writeObjectAt(const T &Value, uint64_t Position) {
192 FS->pwrite((const char *)&Value, sizeof(T), Position);
193 }
194
195 Error writeCString(StringRef Str, bool WriteTerminator = true);
196
197 Error writeIdentifier(const IntOrString &Ident);
198 Error writeIntOrString(const IntOrString &Data);
199
Zachary Turner07bc04f2017-10-06 21:26:06 +0000200 void writeRCInt(RCInt);
201
Marek Sokolowski8f193432017-09-29 17:14:09 +0000202 Error appendFile(StringRef Filename);
203
204 void padStream(uint64_t Length);
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000205
Zachary Turnerfa0ca6c2017-10-11 20:12:09 +0000206 Expected<std::unique_ptr<MemoryBuffer>> loadFile(StringRef File) const;
207
Zachary Turnerc3ab0132017-10-06 21:25:44 +0000208 // Icon and cursor IDs are allocated starting from 1 and increasing for
209 // each icon/cursor dumped. This maintains the current ID to be allocated.
210 uint16_t IconCursorID;
Marek Sokolowski8f193432017-09-29 17:14:09 +0000211};
212
213} // namespace rc
214} // namespace llvm
215
216#endif