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