liblcf
Loading...
Searching...
No Matches
reader_xml.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 <sstream>
11#include <cstdarg>
12#include "lcf/reader_lcf.h"
13#include "lcf/reader_xml.h"
14#include "lcf/dbstring.h"
15#include "log.h"
16
17// Expat callbacks
18#if LCF_SUPPORT_XML
19extern "C" {
20static void StartElementHandler(void* closure, const XML_Char* name, const XML_Char** atts) {
21 ((lcf::XmlReader*) closure)->StartElement(name, atts);
22}
23
24static void EndElementHandler(void* closure, const XML_Char* name) {
25 ((lcf::XmlReader*) closure)->EndElement(name);
26}
27
28static void CharacterDataHandler(void* closure, const XML_Char* s, int len) {
29 ((lcf::XmlReader*) closure)->CharacterData(s, len);
30}
31}
32#endif
33
34namespace lcf {
35
36XmlReader::XmlReader(std::istream& filestream) :
37 stream(filestream),
38 parser(NULL)
39{
40#if LCF_SUPPORT_XML
41 parser = XML_ParserCreate("UTF-8");
42
43 XML_SetUserData(parser, (void*) this);
44 XML_SetElementHandler(parser, StartElementHandler, EndElementHandler);
45 XML_SetCharacterDataHandler(parser, CharacterDataHandler);
46
47 handlers.push_back(NULL);
48#endif
49}
50
51XmlReader::~XmlReader() {
52#if LCF_SUPPORT_XML
53 if (parser != NULL)
54 XML_ParserFree(parser);
55 parser = NULL;
56
57 if (!handlers.empty()) {
58 delete(handlers.back());
59 }
60#endif
61}
62
63bool XmlReader::IsOk() const {
64 return (stream.good() && parser != NULL);
65}
66
67void XmlReader::Parse() {
68#if LCF_SUPPORT_XML
69 static const int bufsize = 4096;
70 while (IsOk() && !stream.eof()) {
71 void* buffer = XML_GetBuffer(parser, bufsize);
72 int len = stream.read(reinterpret_cast<char*>(buffer),bufsize).gcount();
73 int result = XML_ParseBuffer(parser, len, len <= 0);
74 if (result == 0)
75 Log::Error("XML: %s", XML_ErrorString(XML_GetErrorCode(parser)));
76 }
77#endif
78}
79
80void XmlReader::SetHandler(XmlHandler* handler) {
81 handlers.back() = handler;
82}
83
84void XmlReader::StartElement(const char* name, const char** atts) {
85 XmlHandler* handler = handlers.back();
86 handlers.push_back(handler);
87 handlers.back()->StartElement(*this, name, atts);
88 buffer.clear();
89}
90
91void XmlReader::CharacterData(const char* s, int len) {
92 buffer.append(s, len);
93}
94
95void XmlReader::EndElement(const char* name) {
96 XmlHandler* handler = handlers.back();
97 handler->CharacterData(*this, buffer);
98 handlers.pop_back();
99 if (handler != handlers.back())
100 delete handler;
101 handlers.back()->EndElement(*this, name);
102}
103
104// Primitive type readers
105
106template <>
107void XmlReader::Read<bool>(bool& val, const std::string& data) {
108 std::istringstream s(data);
109 std::string str;
110 s >> str;
111 val = str == "T";
112}
113
114template <>
115void XmlReader::Read<int32_t>(int32_t& val, const std::string& data) {
116 std::istringstream s(data);
117 s >> val;
118}
119
120template <>
121void XmlReader::Read<int8_t>(int8_t& val, const std::string& data) {
122 std::istringstream s(data);
123 int x;
124 s >> x;
125 val = x;
126}
127
128template <>
129void XmlReader::Read<uint8_t>(uint8_t& val, const std::string& data) {
130 std::istringstream s(data);
131 int x;
132 s >> x;
133 val = x;
134}
135
136template <>
137void XmlReader::Read<int16_t>(int16_t& val, const std::string& data) {
138 std::istringstream s(data);
139 s >> val;
140}
141
142template <>
143void XmlReader::Read<uint32_t>(uint32_t& val, const std::string& data) {
144 std::istringstream s(data);
145 s >> val;
146}
147
148template <>
149void XmlReader::Read<double>(double& val, const std::string& data) {
150 std::istringstream s(data);
151 s >> val;
152}
153
154template <>
155void XmlReader::Read<std::string>(std::string& val, const std::string& data) {
156 static const std::string prefix("\xee\x80");
157
158 if (data.find(prefix) == std::string::npos) {
159 val = data;
160 return;
161 }
162
163 // XML doesn't allow most C0 control codes, so they're re-mapped
164 // to the private-use area at U+E000. The following code restores
165 // re-mapped codes to their original value.
166
167 val.clear();
168
169 for (size_t pos = 0; ; ) {
170 size_t next = data.find(prefix, pos);
171 if (next > pos)
172 val.append(data, pos, next - pos);
173 if (next == std::string::npos)
174 return;
175 pos = next + 2;
176 val.append(1, data[pos] - '\x80');
177 pos++;
178 }
179}
180
181template <>
182void XmlReader::Read<DBString>(DBString& val, const std::string& data) {
183 std::string sval;
184 Read(sval, data);
185 val = DBString(sval);
186}
187
188template <>
189void XmlReader::Read<DBBitArray>(DBBitArray& val, const std::string& data) {
190 // FIXME: Adds copies
191 std::vector<bool> tmp;
192 ReadVector(tmp, data);
193 val = DBBitArray(tmp.begin(), tmp.end());
194}
195
196template <class T>
197void XmlReader::ReadVector(std::vector<T>& val, const std::string& data) {
198 val.clear();
199 std::istringstream s(data);
200 for (;;) {
201 std::string str;
202 s >> str;
203 if (!s.fail()) {
204 T x;
205 XmlReader::Read<T>(x, str);
206 val.push_back(x);
207 }
208 if (!s.good())
209 break;
210 }
211}
212
213template <class T>
214void XmlReader::ReadVector(DBArray<T>& val, const std::string& data) {
215 // FIXME: Adds copies
216 std::vector<T> tmp;
217 ReadVector(tmp, data);
218 val = DBArray<T>(tmp.begin(), tmp.end());
219}
220
221template <>
222void XmlReader::Read<std::vector<int32_t>>(std::vector<int32_t>& val, const std::string& data) {
224}
225
226template <>
227void XmlReader::Read<std::vector<bool>>(std::vector<bool>& val, const std::string& data) {
229}
230
231template <>
232void XmlReader::Read<std::vector<uint8_t>>(std::vector<uint8_t>& val, const std::string& data) {
234}
235
236template <>
237void XmlReader::Read<std::vector<int16_t>>(std::vector<int16_t>& val, const std::string& data) {
239}
240
241template <>
242void XmlReader::Read<std::vector<uint32_t>>(std::vector<uint32_t>& val, const std::string& data) {
244}
245
246template <>
247void XmlReader::Read<std::vector<double>>(std::vector<double>& val, const std::string& data) {
249}
250
251template <>
252void XmlReader::Read<DBArray<int32_t>>(DBArray<int32_t>& val, const std::string& data) {
253 ReadVector<int32_t>(val, data);
254}
255
256template <>
257void XmlReader::Read<DBArray<bool>>(DBArray<bool>& val, const std::string& data) {
258 ReadVector<bool>(val, data);
259}
260
261template <>
262void XmlReader::Read<DBArray<uint8_t>>(DBArray<uint8_t>& val, const std::string& data) {
263 ReadVector<uint8_t>(val, data);
264}
265
266template <>
267void XmlReader::Read<DBArray<int16_t>>(DBArray<int16_t>& val, const std::string& data) {
268 ReadVector<int16_t>(val, data);
269}
270
271template <>
272void XmlReader::Read<DBArray<uint32_t>>(DBArray<uint32_t>& val, const std::string& data) {
273 ReadVector<uint32_t>(val, data);
274}
275
276template <>
277void XmlReader::Read<DBArray<double>>(DBArray<double>& val, const std::string& data) {
278 ReadVector<double>(val, data);
279}
280
281
282} //namespace lcf