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) 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 "lcf/ldb/reader.h"
15#include "lcf/lmt/reader.h"
16#include "lcf/lmu/reader.h"
17#include "lcf/lsd/reader.h"
18#include "reader_struct.h"
19#include "lcf/rpg/save.h"
20
21namespace lcf {
22
23// Read/Write Struct
24
25template <class S>
27 if (!field_map.empty())
28 return;
29 for (int i = 0; fields[i] != NULL; i++)
30 field_map[fields[i]->id] = fields[i];
31}
32
33template <class S>
35 if (!tag_map.empty())
36 return;
37 for (int i = 0; fields[i] != NULL; i++)
38 tag_map[fields[i]->name] = fields[i];
39}
40
41template <typename T>
43 static T make(bool) {
44 return T();
45 }
46};
47
48template <>
49struct StructDefault<rpg::Actor> {
50 static rpg::Actor make(bool is2k3) {
51 auto actor = rpg::Actor();
52 actor.Setup(is2k3);
53 return actor;
54 }
55};
56
57
58
59template <class S>
61 MakeFieldMap();
62
63 LcfReader::Chunk chunk_info;
64
65 while (!stream.Eof()) {
66 chunk_info.ID = stream.ReadInt();
67 if (chunk_info.ID == 0)
68 break;
69
70 chunk_info.length = stream.ReadInt();
71
72 auto it = field_map.find(chunk_info.ID);
73 if (it != field_map.end()) {
74#ifdef LCF_DEBUG_TRACE
75 printf("0x%02x (size: %" PRIu32 ", pos: 0x%" PRIx32 "): %s\n", chunk_info.ID, chunk_info.length, stream.Tell(), it->second->name);
76#endif
77 const uint32_t off = stream.Tell();
78 it->second->ReadLcf(obj, stream, chunk_info.length);
79 const uint32_t bytes_read = stream.Tell() - off;
80 if (bytes_read != chunk_info.length) {
81 fprintf(stderr, "%s: Corrupted Chunk 0x%02" PRIx32 " (size: %" PRIu32 ", pos: 0x%" PRIx32 "): %s : Read %" PRIu32 " bytes! Reseting...\n",
82 Struct<S>::name, chunk_info.ID, chunk_info.length, off, it->second->name, bytes_read);
83 stream.Seek(off + chunk_info.length);
84 }
85 }
86 else {
88 }
89 }
90}
91
92template<typename T>
93typename std::enable_if<std::is_same<T, rpg::Save>::value ||
94 std::is_same<T, rpg::Database>::value>::type
98
99template<typename T>
100typename std::enable_if<!std::is_same<T, rpg::Save>::value &&
101 !std::is_same<T, rpg::Database>::value>::type
105
106template <class S>
108 const bool db_is2k3 = stream.Is2k3();
109
111 int last = -1;
112 for (int i = 0; fields[i] != NULL; i++) {
113 const Field<S>* field = fields[i];
114 if (!db_is2k3 && field->is2k3) {
115 continue;
116 }
117 if (field->id < last)
118 std::cerr << "field order mismatch: " << field->id
119 << " after " << last
120 << " in struct " << name
121 << std::endl;
122 if (!field->isPresentIfDefault(db_is2k3) && field->IsDefault(obj, ref, db_is2k3)) {
123 continue;
124 }
125 stream.WriteInt(field->id);
126 auto len = field->LcfSize(obj, stream);
127 stream.WriteInt(len);
128 if (len > 0) {
129 field->WriteLcf(obj, stream);
130 }
131 }
132 // Writing a 0-byte after rpg::Database or rpg::Save breaks the parser in RPG_RT
134}
135
136template <class S>
138 const bool db_is2k3 = stream.Is2k3();
139 int result = 0;
141 for (int i = 0; fields[i] != NULL; i++) {
142 const Field<S>* field = fields[i];
143 if (!db_is2k3 && field->is2k3) {
144 continue;
145 }
146 //printf("%s\n", field->name);
147 if (!field->isPresentIfDefault(db_is2k3) && field->IsDefault(obj, ref, db_is2k3)) {
148 continue;
149 }
150 result += LcfReader::IntSize(field->id);
151 int size = field->LcfSize(obj, stream);
152 result += LcfReader::IntSize(size);
153 result += size;
154 }
155 result += LcfReader::IntSize(0);
156 return result;
157}
158
159template <class S>
161 IDReader::WriteXmlTag(obj, name, stream);
162 for (int i = 0; fields[i] != NULL; i++) {
163 const Field<S>* field = fields[i];
164 field->WriteXml(obj, stream);
165 }
166 stream.EndElement(name);
167}
168
169template <class S>
170class StructXmlHandler : public XmlHandler {
171public:
175
176 void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
178 field->BeginXml(ref, stream);
179 }
180
181 void EndElement(XmlReader& /* stream */, const char* /* name */) {
182 field = NULL;
183 }
184
185 void CharacterData(XmlReader& /* stream */, const std::string& data) {
186 if (field != NULL)
187 field->ParseXml(ref, data);
188 }
189private:
192};
193
194template <class S>
195class StructFieldXmlHandler : public XmlHandler {
196public:
198
199 void StartElement(XmlReader& stream, const char* name, const char** atts) {
200 if (strcmp(name, Struct<S>::name) != 0)
201 stream.Error("Expecting %s but got %s", Struct<S>::name, name);
203 stream.SetHandler(new StructXmlHandler<S>(ref));
204 }
205private:
207};
208
209template <class S>
211 stream.SetHandler(new StructFieldXmlHandler<S>(obj));
212}
213
214// Read/Write std::vector<Struct>
215
216template <class S>
217void Struct<S>::ReadLcf(std::vector<S>& vec, LcfReader& stream) {
218 int count = stream.ReadInt();
219 vec.resize(count);
220 for (int i = 0; i < count; i++) {
221 IDReader::ReadID(vec[i], stream);
223 }
224}
225
226template <class S>
227void Struct<S>::WriteLcf(const std::vector<S>& vec, LcfWriter& stream) {
228 int count = vec.size();
229 stream.WriteInt(count);
230 for (int i = 0; i < count; i++) {
231 IDReader::WriteID(vec[i], stream);
233 }
234}
235
236template <class S>
237int Struct<S>::LcfSize(const std::vector<S>& vec, LcfWriter& stream) {
238 int result = 0;
239 int count = vec.size();
240 result += LcfReader::IntSize(count);
241 for (int i = 0; i < count; i++) {
242 result += IDReader::IDSize(vec[i]);
244 }
245 return result;
246}
247
248template <class S>
249void Struct<S>::WriteXml(const std::vector<S>& vec, XmlWriter& stream) {
250 int count = vec.size();
251 for (int i = 0; i < count; i++)
253}
254
255template <class S>
256class StructVectorXmlHandler : public XmlHandler {
257public:
258 StructVectorXmlHandler(std::vector<S>& ref) : ref(ref) {}
259
260 void StartElement(XmlReader& stream, const char* name, const char** atts) {
261 if (strcmp(name, Struct<S>::name) != 0)
262 stream.Error("Expecting %s but got %s", Struct<S>::name, name);
263 ref.resize(ref.size() + 1);
264 S& obj = ref.back();
266 stream.SetHandler(new StructXmlHandler<S>(obj));
267 }
268private:
269 std::vector<S>& ref;
270};
271
272template <class S>
273void Struct<S>::BeginXml(std::vector<S>& obj, XmlReader& stream) {
274 stream.SetHandler(new StructVectorXmlHandler<S>(obj));
275}
276
277} //namespace lcf
278
279#include "fwd_struct_impl.h"
RootXmlHandler(S &ref, const char *const name)
const char *const name
void StartElement(XmlReader &stream, const char *name, const char **atts)
static void BeginXml(S &obj, XmlReader &stream)
static int LcfSize(const S &obj, LcfWriter &stream)
static void MakeFieldMap()
static void WriteXml(const S &obj, XmlWriter &stream)
static void MakeTagMap()
static void WriteLcf(const S &obj, LcfWriter &stream)
static void ReadLcf(S &obj, LcfReader &stream)
void StartElement(XmlReader &stream, const char *name, const char **atts)
StructVectorXmlHandler(std::vector< S > &ref)
void EndElement(XmlReader &, const char *)
const Field< S > * field
void StartElement(XmlReader &stream, const char *name, const char **)
void CharacterData(XmlReader &, const std::string &data)
std::enable_if< std::is_same< T, rpg::Save >::value||std::is_same< T, rpg::Database >::value >::type conditional_zero_writer(LcfWriter &)
static rpg::Actor make(bool is2k3)