liblcf
Loading...
Searching...
No Matches
reader_struct_impl.h
Go to the documentation of this file.
1/*
2 * This file is part of liblcf. Copyright (c) 2020 liblcf authors.
3 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
4 *
5 * liblcf is Free/Libre Open Source Software, released under the MIT License.
6 * For the full copyright and license information, please view the COPYING
7 * file that was distributed with this source code.
8 */
9
10#include <cstring>
11#include <iostream>
12#include <iomanip>
13#include <type_traits>
14#include "ldb_reader.h"
15#include "lmt_reader.h"
16#include "lmu_reader.h"
17#include "lsd_reader.h"
18#include "reader_struct.h"
19#include "rpg_save.h"
20#include "data.h"
21
22// Read/Write Struct
23
24template <class S>
26 if (!field_map.empty())
27 return;
28 for (int i = 0; fields[i] != NULL; i++)
29 field_map[fields[i]->id] = fields[i];
30}
31
32template <class S>
34 if (!tag_map.empty())
35 return;
36 for (int i = 0; fields[i] != NULL; i++)
37 tag_map[fields[i]->name] = fields[i];
38}
39
40template <typename T>
42 static T make() {
43 return T();
44 }
45};
46
47template <>
48struct StructDefault<RPG::Actor> {
49 static RPG::Actor make() {
50 auto actor = RPG::Actor();
51 actor.Setup();
52 return actor;
53 }
54};
55
56template <class S>
57void Struct<S>::ReadLcf(S& obj, LcfReader& stream) {
58 MakeFieldMap();
59
60 LcfReader::Chunk chunk_info;
61
62 while (!stream.Eof()) {
63 chunk_info.ID = stream.ReadInt();
64 if (chunk_info.ID == 0)
65 break;
66
67 chunk_info.length = stream.ReadInt();
68
69 auto it = field_map.find(chunk_info.ID);
70 if (it != field_map.end()) {
71#ifdef LCF_DEBUG_TRACE
72 printf("0x%02x (size: %" PRIu32 ", pos: 0x%" PRIx32 "): %s\n", chunk_info.ID, chunk_info.length, stream.Tell(), it->second->name);
73#endif
74 const uint32_t off = stream.Tell();
75 it->second->ReadLcf(obj, stream, chunk_info.length);
76 const uint32_t bytes_read = stream.Tell() - off;
77 if (bytes_read != chunk_info.length) {
78 fprintf(stderr, "Warning: Corrupted Chunk 0x%02" PRIx32 " (size: %" PRIu32 ", pos: 0x%" PRIx32 "): %s : Read %" PRIu32 " bytes! Reseting...\n",
79 chunk_info.ID, chunk_info.length, off, it->second->name, bytes_read);
80 stream.Seek(off + chunk_info.length);
81 }
82 }
83 else {
84 stream.Skip(chunk_info);
85 }
86 }
87}
88
89template<typename T>
90typename std::enable_if<std::is_same<T, RPG::Save>::value ||
91 std::is_same<T, RPG::Database>::value>::type
93 // no-op
94}
95
96template<typename T>
97typename std::enable_if<!std::is_same<T, RPG::Save>::value &&
98 !std::is_same<T, RPG::Database>::value>::type
100 stream.WriteInt(0);
101}
102
103template <class S>
104void Struct<S>::WriteLcf(const S& obj, LcfWriter& stream) {
105 const bool db_is2k3 = (Data::system.ldb_id == 2003);
106
107 auto ref = StructDefault<S>::make();
108 int last = -1;
109 for (int i = 0; fields[i] != NULL; i++) {
110 const Field<S>* field = fields[i];
111 if (!db_is2k3 && field->is2k3) {
112 continue;
113 }
114 if (field->id < last)
115 std::cerr << "field order mismatch: " << field->id
116 << " after " << last
117 << " in struct " << name
118 << std::endl;
119 if (!field->isPresentIfDefault(db_is2k3) && field->IsDefault(obj, ref)) {
120 continue;
121 }
122 stream.WriteInt(field->id);
123 auto len = field->LcfSize(obj, stream);
124 stream.WriteInt(len);
125 if (len > 0) {
126 field->WriteLcf(obj, stream);
127 }
128 }
129 // Writing a 0-byte after RPG::Database or RPG::Save breaks the parser in RPG_RT
130 conditional_zero_writer<S>(stream);
131}
132
133template <class S>
134int Struct<S>::LcfSize(const S& obj, LcfWriter& stream) {
135 const bool db_is2k3 = (Data::system.ldb_id == 2003);
136 int result = 0;
137 auto ref = StructDefault<S>::make();
138 for (int i = 0; fields[i] != NULL; i++) {
139 const Field<S>* field = fields[i];
140 if (!db_is2k3 && field->is2k3) {
141 continue;
142 }
143 //printf("%s\n", field->name);
144 if (!field->isPresentIfDefault(db_is2k3) && field->IsDefault(obj, ref)) {
145 continue;
146 }
147 result += LcfReader::IntSize(field->id);
148 int size = field->LcfSize(obj, stream);
149 result += LcfReader::IntSize(size);
150 result += size;
151 }
152 result += LcfReader::IntSize(0);
153 return result;
154}
155
156template <class S>
157void Struct<S>::WriteXml(const S& obj, XmlWriter& stream) {
158 IDReader::WriteXmlTag(obj, name, stream);
159 for (int i = 0; fields[i] != NULL; i++) {
160 const Field<S>* field = fields[i];
161 field->WriteXml(obj, stream);
162 }
163 stream.EndElement(name);
164}
165
166template <class S>
168public:
171 }
172
173 void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
175 field->BeginXml(ref, stream);
176 }
177
178 void EndElement(XmlReader& /* stream */, const char* /* name */) {
179 field = NULL;
180 }
181
182 void CharacterData(XmlReader& /* stream */, const std::string& data) {
183 if (field != NULL)
184 field->ParseXml(ref, data);
185 }
186private:
187 S& ref;
189};
190
191template <class S>
193public:
195
196 void StartElement(XmlReader& stream, const char* name, const char** atts) {
197 if (strcmp(name, Struct<S>::name) != 0)
198 stream.Error("Expecting %s but got %s", Struct<S>::name, name);
201 }
202private:
203 S& ref;
204};
205
206template <class S>
207void Struct<S>::BeginXml(S& obj, XmlReader& stream) {
208 stream.SetHandler(new StructFieldXmlHandler<S>(obj));
209}
210
211// Read/Write std::vector<Struct>
212
213template <class S>
214void Struct<S>::ReadLcf(std::vector<S>& vec, LcfReader& stream) {
215 int count = stream.ReadInt();
216 vec.resize(count);
217 for (int i = 0; i < count; i++) {
218 IDReader::ReadID(vec[i], stream);
219 TypeReader<S>::ReadLcf(vec[i], stream, 0);
220 }
221}
222
223template <class S>
224void Struct<S>::WriteLcf(const std::vector<S>& vec, LcfWriter& stream) {
225 int count = vec.size();
226 stream.WriteInt(count);
227 for (int i = 0; i < count; i++) {
228 IDReader::WriteID(vec[i], stream);
229 TypeReader<S>::WriteLcf(vec[i], stream);
230 }
231}
232
233template <class S>
234int Struct<S>::LcfSize(const std::vector<S>& vec, LcfWriter& stream) {
235 int result = 0;
236 int count = vec.size();
237 result += LcfReader::IntSize(count);
238 for (int i = 0; i < count; i++) {
239 result += IDReader::IDSize(vec[i]);
240 result += TypeReader<S>::LcfSize(vec[i], stream);
241 }
242 return result;
243}
244
245template <class S>
246void Struct<S>::WriteXml(const std::vector<S>& vec, XmlWriter& stream) {
247 int count = vec.size();
248 for (int i = 0; i < count; i++)
249 TypeReader<S>::WriteXml(vec[i], stream);
250}
251
252template <class S>
254public:
255 StructVectorXmlHandler(std::vector<S>& ref) : ref(ref) {}
256
257 void StartElement(XmlReader& stream, const char* name, const char** atts) {
258 if (strcmp(name, Struct<S>::name) != 0)
259 stream.Error("Expecting %s but got %s", Struct<S>::name, name);
260 ref.resize(ref.size() + 1);
261 S& obj = ref.back();
263 stream.SetHandler(new StructXmlHandler<S>(obj));
264 }
265private:
266 std::vector<S>& ref;
267};
268
269template <class S>
270void Struct<S>::BeginXml(std::vector<S>& obj, XmlReader& stream) {
271 stream.SetHandler(new StructVectorXmlHandler<S>(obj));
272}
273
274#include "fwd_struct_impl.h"
static int IntSize(unsigned int x)
Definition: reader_lcf.cpp:299
bool Eof() const
Definition: reader_lcf.cpp:196
void Seek(size_t pos, SeekMode mode=FromStart)
Definition: reader_lcf.cpp:200
int ReadInt()
Definition: reader_lcf.cpp:84
uint32_t Tell()
Definition: reader_lcf.cpp:228
void Skip(const struct LcfReader::Chunk &chunk_info)
Definition: reader_lcf.cpp:273
void WriteInt(int val)
Definition: writer_lcf.cpp:51
int32_t ldb_id
Definition: rpg_system.h:177
void StartElement(XmlReader &stream, const char *name, const char **atts)
static void WriteLcf(const S &obj, LcfWriter &stream)
static void MakeTagMap()
static void WriteXml(const S &obj, XmlWriter &stream)
static void ReadLcf(S &obj, LcfReader &stream)
static int LcfSize(const S &obj, LcfWriter &stream)
static void MakeFieldMap()
static void BeginXml(S &obj, XmlReader &stream)
std::vector< S > & ref
void StartElement(XmlReader &stream, const char *name, const char **atts)
StructVectorXmlHandler(std::vector< S > &ref)
void CharacterData(XmlReader &, const std::string &data)
const Field< S > * field
void EndElement(XmlReader &, const char *)
void StartElement(XmlReader &stream, const char *name, const char **)
void SetHandler(XmlHandler *handler)
Definition: reader_xml.cpp:80
void Error(const char *fmt,...)
Definition: reader_xml.cpp:59
void EndElement(const std::string &name)
Definition: writer_xml.cpp:177
RPG::System & system
Definition: data.cpp:31
Definition: rpg_actor.h:26
std::enable_if< std::is_same< T, RPG::Save >::value||std::is_same< T, RPG::Database >::value >::type conditional_zero_writer(LcfWriter &)
bool isPresentIfDefault(bool db_is2k3) const
bool is2k3
virtual void WriteXml(const S &obj, XmlWriter &stream) const =0
virtual bool IsDefault(const S &obj, const S &ref) const =0
virtual void WriteLcf(const S &obj, LcfWriter &stream) const =0
virtual int LcfSize(const S &obj, LcfWriter &stream) const =0
uint32_t length
Definition: reader_lcf.h:76