liblcf
Loading...
Searching...
No Matches
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
14namespace lcf {
15
16/*
17DBString has the structure of a Pascal String (Length + Data).
18It could be a primitive type but vector<DBString> needs special handling.
19
20Vector<DBString> is Maniac Patch and is sparse:
21When size is > 0xFFFFFFFF there is a gap of "0x800000000 - size"
22In other cases it is as above: Size Data ... Size Data
23*/
24
25template <>
26struct 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
34template <>
35struct 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
43void 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
50void RawStruct<DBString>::WriteLcf(const DBString& ref, LcfWriter& stream) {
51 stream.Write(ref);
52}
53
54int RawStruct<DBString>::LcfSize(const DBString& ref, LcfWriter& stream) {
55 return stream.Decode(ref).size();
56}
57
58void RawStruct<DBString>::WriteXml(const DBString& ref, XmlWriter& stream) {
59 stream.Write(ref);
60}
61
62class DbStringXmlHandler : public XmlHandler {
63private:
64 DBString& ref;
65public:
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
79void RawStruct<DBString>::BeginXml(DBString& /* ref */, XmlReader& /* stream */) {
80 // no-op
81}
82
83void 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
116void 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
137int 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
161void 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
174class DbStringVectorXmlHandler : public XmlHandler {
175public:
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 }
203private:
204 std::vector<DBString>& ref;
205};
206
207void 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 *)
static void ReadLcf(T &ref, LcfReader &stream, uint32_t length)
static void WriteXml(const T &ref, XmlWriter &stream)
static void BeginXml(T &ref, XmlReader &stream)
static void WriteLcf(const T &ref, LcfWriter &stream)
static int LcfSize(const T &ref, LcfWriter &stream)