liblcf
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 
24 template <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 
32 template <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 
40 template <typename T>
41 struct StructDefault {
42  static T make() {
43  return T();
44  }
45 };
46 
47 template <>
48 struct StructDefault<RPG::Actor> {
49  static RPG::Actor make() {
50  auto actor = RPG::Actor();
51  actor.Setup();
52  return actor;
53  }
54 };
55 
56 template <class S>
57 void 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 
89 template<typename T>
90 typename std::enable_if<std::is_same<T, RPG::Save>::value ||
91  std::is_same<T, RPG::Database>::value>::type
93  // no-op
94 }
95 
96 template<typename T>
97 typename 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 
103 template <class S>
104 void 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 
133 template <class S>
134 int 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 
156 template <class S>
157 void 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 
166 template <class S>
167 class StructXmlHandler : public XmlHandler {
168 public:
169  StructXmlHandler(S& ref) : ref(ref), field(NULL) {
171  }
172 
173  void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
174  field = Struct<S>::tag_map[name];
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  }
186 private:
187  S& ref;
188  const Field<S>* field;
189 };
190 
191 template <class S>
193 public:
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);
200  stream.SetHandler(new StructXmlHandler<S>(ref));
201  }
202 private:
203  S& ref;
204 };
205 
206 template <class S>
207 void Struct<S>::BeginXml(S& obj, XmlReader& stream) {
208  stream.SetHandler(new StructFieldXmlHandler<S>(obj));
209 }
210 
211 // Read/Write std::vector<Struct>
212 
213 template <class S>
214 void 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 
223 template <class S>
224 void 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 
233 template <class S>
234 int 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 
245 template <class S>
246 void 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 
252 template <class S>
254 public:
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  }
265 private:
266  std::vector<S>& ref;
267 };
268 
269 template <class S>
270 void Struct<S>::BeginXml(std::vector<S>& obj, XmlReader& stream) {
271  stream.SetHandler(new StructVectorXmlHandler<S>(obj));
272 }
273 
274 #include "fwd_struct_impl.h"
std::enable_if< std::is_same< T, RPG::Save >::value||std::is_same< T, RPG::Database >::value >::type conditional_zero_writer(LcfWriter &)
static int LcfSize(const S &obj, LcfWriter &stream)
RPG::Database data
Definition: data.cpp:14
RPG::System & system
Definition: data.cpp:31
void Seek(size_t pos, SeekMode mode=FromStart)
Definition: reader_lcf.cpp:200
void SetHandler(XmlHandler *handler)
Definition: reader_xml.cpp:80
void Skip(const struct LcfReader::Chunk &chunk_info)
Definition: reader_lcf.cpp:273
static void ReadLcf(S &obj, LcfReader &stream)
virtual void WriteLcf(const S &obj, LcfWriter &stream) const =0
void CharacterData(XmlReader &, const std::string &data)
virtual bool IsDefault(const S &obj, const S &ref) const =0
void WriteInt(int val)
Definition: writer_lcf.cpp:51
static void MakeFieldMap()
void EndElement(const std::string &name)
Definition: writer_xml.cpp:177
bool Eof() const
Definition: reader_lcf.cpp:196
void Error(const char *fmt,...)
Definition: reader_xml.cpp:59
StructVectorXmlHandler(std::vector< S > &ref)
uint32_t length
Definition: reader_lcf.h:76
static void BeginXml(S &obj, XmlReader &stream)
static void WriteXml(const S &obj, XmlWriter &stream)
int ReadInt()
Definition: reader_lcf.cpp:84
void StartElement(XmlReader &stream, const char *name, const char **atts)
std::vector< S > & ref
virtual void WriteXml(const S &obj, XmlWriter &stream) const =0
static void WriteLcf(const S &obj, LcfWriter &stream)
void StartElement(XmlReader &stream, const char *name, const char **atts)
void StartElement(XmlReader &stream, const char *name, const char **)
static int IntSize(unsigned int x)
Definition: reader_lcf.cpp:299
Definition: rpg_actor.h:26
int32_t ldb_id
Definition: rpg_system.h:177
bool isPresentIfDefault(bool db_is2k3) const
uint32_t Tell()
Definition: reader_lcf.cpp:228
virtual int LcfSize(const S &obj, LcfWriter &stream) const =0
static void MakeTagMap()
const Field< S > * field
void EndElement(XmlReader &, const char *)
bool is2k3