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