liblcf
dbstring_struct.cpp
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 "lcf/dbstring.h"
11 #include "reader_struct.h"
12 #include <iostream>
13 
14 namespace lcf {
15 
16 /*
17 DBString has the structure of a Pascal String (Length + Data).
18 It could be a primitive type but vector<DBString> needs special handling.
19 
20 Vector<DBString> is Maniac Patch and is sparse:
21 When size is > 0xFFFFFFFF there is a gap of "0x800000000 - size"
22 In other cases it is as above: Size Data ... Size Data
23 */
24 
25 template <>
26 struct RawStruct<DBString> {
27  static void ReadLcf(DBString& ref, LcfReader& stream, uint32_t length);
28  static void WriteLcf(const DBString& ref, LcfWriter& stream);
29  static int LcfSize(const DBString& ref, LcfWriter& stream);
30  static void WriteXml(const DBString& ref, XmlWriter& stream);
31  static void BeginXml(DBString& ref, XmlReader& stream);
32 };
33 
34 template <>
35 struct RawStruct<std::vector<DBString> > {
36  static void ReadLcf(std::vector<DBString>& ref, LcfReader& stream, uint32_t length);
37  static void WriteLcf(const std::vector<DBString>& ref, LcfWriter& stream);
38  static int LcfSize(const std::vector<DBString>& ref, LcfWriter& stream);
39  static void WriteXml(const std::vector<DBString>& ref, XmlWriter& stream);
40  static void BeginXml(std::vector<DBString>& ref, XmlReader& stream);
41 };
42 
43 void RawStruct<DBString>::ReadLcf(DBString& ref, LcfReader& stream, uint32_t length) {
44  stream.ReadString(ref, length);
45 #ifdef LCF_DEBUG_TRACE
46  printf(" %s\n", ref.c_str());
47 #endif
48 }
49 
50 void RawStruct<DBString>::WriteLcf(const DBString& ref, LcfWriter& stream) {
51  stream.Write(ref);
52 }
53 
54 int RawStruct<DBString>::LcfSize(const DBString& ref, LcfWriter& stream) {
55  return stream.Decode(ref).size();
56 }
57 
58 void RawStruct<DBString>::WriteXml(const DBString& ref, XmlWriter& stream) {
59  stream.Write(ref);
60 }
61 
62 class DbStringXmlHandler : public XmlHandler {
63 private:
64  DBString& ref;
65 public:
66  DbStringXmlHandler(DBString& ref) :
67  ref(ref) {}
68  void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
69  // no-op
70  }
71  void EndElement(XmlReader& /* stream */, const char* /* name */) {
72  // no-op
73  }
74  void CharacterData(XmlReader& /* stream */, const std::string& data) {
75  ref = DBString(data);
76  }
77 };
78 
79 void RawStruct<DBString>::BeginXml(DBString& /* ref */, XmlReader& /* stream */) {
80  // no-op
81 }
82 
83 void RawStruct<std::vector<DBString>>::ReadLcf(std::vector<DBString>& ref, LcfReader& stream, uint32_t length) {
84  int index = 0;
85  DBString string_var;
86 
87  uint32_t startpos = stream.Tell();
88  uint32_t endpos = startpos + length;
89  while (stream.Tell() < endpos) {
90  // If size is bigger than 4 bytes, size indicates the gap size
91  // Otherwise it indicates the size of the next string
92  auto size = stream.ReadUInt64();
93  if (size > std::numeric_limits<uint32_t>::max()) {
94  index += static_cast<uint32_t>(0x800000000 - size);
95 
96  ref.resize(index);
97  } else {
98  stream.ReadString(string_var, size);
99 #ifdef LCF_DEBUG_TRACE
100  fprintf(stderr, "t[%d]: %s\n", index + 1, string_var.c_str());
101 #endif
102  ref.push_back(string_var);
103 
104  ++index;
105  }
106  }
107 
108  if (stream.Tell() != endpos) {
109 #ifdef LCF_DEBUG_TRACE
110  fprintf(stderr, "Misaligned!\n");
111 #endif
112  stream.Seek(endpos);
113  }
114 }
115 
116 void RawStruct<std::vector<DBString>>::WriteLcf(const std::vector<DBString>& ref, LcfWriter& stream) {
117  int gap_size = 0;
118 
119  for (size_t i = 0; i < ref.size(); ++i) {
120  const auto& e = ref[i];
121  if (e.empty()) {
122  ++gap_size;
123  continue;
124  }
125 
126  if (gap_size > 0) {
127  stream.WriteUInt64(0x800000000 - static_cast<uint64_t>(gap_size));
128  gap_size = 0;
129  }
130 
131  auto len = RawStruct<DBString>::LcfSize(e, stream);
132  stream.WriteInt(len);
134  }
135 }
136 
137 int RawStruct<std::vector<DBString>>::LcfSize(const std::vector<DBString>& ref, LcfWriter& stream) {
138  int result = 0;
139  int gap_size = 0;
140 
141  for (size_t i = 0; i < ref.size(); ++i) {
142  const auto& e = ref[i];
143  if (e.empty()) {
144  ++gap_size;
145  continue;
146  }
147 
148  if (gap_size > 0) {
149  result += LcfReader::UInt64Size(0x800000000 - static_cast<uint64_t>(gap_size));
150  gap_size = 0;
151  }
152 
153  int size = RawStruct<DBString>::LcfSize(e, stream);
154  result += LcfReader::IntSize(size);
155  result += size;
156  }
157 
158  return result;
159 }
160 
161 void RawStruct<std::vector<DBString>>::WriteXml(const std::vector<DBString>& ref, XmlWriter& stream) {
162  for (size_t i = 0; i < ref.size(); ++i) {
163  const auto& e = ref[i];
164  if (e.empty()) {
165  continue;
166  }
167 
168  stream.BeginElement("item", i + 1);
170  stream.EndElement("item");
171  }
172 }
173 
174 class DbStringVectorXmlHandler : public XmlHandler {
175 public:
176  DbStringVectorXmlHandler(std::vector<DBString>& ref) : ref(ref) {}
177 
178  void StartElement(XmlReader& stream, const char* name, const char** atts) {
179  if (strcmp(name, "item") != 0) {
180  stream.Error("Expecting %s but got %s", "item", name);
181  return;
182  }
183 
184  int last_id = -1;
185  int id = -1;
186  for (int i = 0; atts[i] != NULL && atts[i + 1] != NULL; i += 2) {
187  if (strcmp(atts[i], "id") == 0) {
188  id = atoi(atts[i + 1]);
189  break;
190  }
191  }
192 
193  if (id <= last_id || id < -1) {
194  stream.Error("Bad Id %d / %d", id, last_id);
195  return;
196  }
197 
198  ref.resize(id);
199  DBString& obj = ref.back();
200 
201  stream.SetHandler(new DbStringXmlHandler(obj));
202  }
203 private:
204  std::vector<DBString>& ref;
205 };
206 
207 void RawStruct<std::vector<DBString>>::BeginXml(std::vector<DBString>& obj, XmlReader& stream) {
208  stream.SetHandler(new DbStringVectorXmlHandler(obj));
209 }
210 
211 } //namspace lcf
std::vector< DBString > & ref
DbStringVectorXmlHandler(std::vector< DBString > &ref)
void StartElement(XmlReader &stream, const char *name, const char **atts)
void StartElement(XmlReader &stream, const char *name, const char **)
void CharacterData(XmlReader &, const std::string &data)
DbStringXmlHandler(DBString &ref)
void EndElement(XmlReader &, const char *)
Definition: dbarray.cpp:13
static void WriteXml(const T &ref, XmlWriter &stream)
static void BeginXml(T &ref, XmlReader &stream)
static void ReadLcf(T &ref, LcfReader &stream, uint32_t length)
static void WriteLcf(const T &ref, LcfWriter &stream)
static int LcfSize(const T &ref, LcfWriter &stream)