liblcf
reader_xml.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of liblcf. Copyright (c) 2021 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
18 extern "C" {
19 static void StartElementHandler(void* closure, const XML_Char* name, const XML_Char** atts) {
20  ((lcf::XmlReader*) closure)->StartElement(name, atts);
21 }
22 
23 static void EndElementHandler(void* closure, const XML_Char* name) {
24  ((lcf::XmlReader*) closure)->EndElement(name);
25 }
26 
27 static void CharacterDataHandler(void* closure, const XML_Char* s, int len) {
28  ((lcf::XmlReader*) closure)->CharacterData(s, len);
29 }
30 }
31 #endif
32 
33 namespace lcf {
34 
35 XmlReader::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 
50 XmlReader::~XmlReader() {
51 #if LCF_SUPPORT_XML
52  if (parser != NULL)
53  XML_ParserFree(parser);
54  parser = NULL;
55 #endif
56 }
57 
58 bool XmlReader::IsOk() const {
59  return (stream.good() && parser != NULL);
60 }
61 
62 void 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 
70 void 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 
83 void XmlReader::SetHandler(XmlHandler* handler) {
84  handlers.back() = handler;
85 }
86 
87 void 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 
94 void XmlReader::CharacterData(const char* s, int len) {
95  buffer.append(s, len);
96 }
97 
98 void 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 
109 template <>
110 void 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 
117 template <>
118 void XmlReader::Read<int32_t>(int32_t& val, const std::string& data) {
119  std::istringstream s(data);
120  s >> val;
121 }
122 
123 template <>
124 void 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 
131 template <>
132 void 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 
139 template <>
140 void XmlReader::Read<int16_t>(int16_t& val, const std::string& data) {
141  std::istringstream s(data);
142  s >> val;
143 }
144 
145 template <>
146 void XmlReader::Read<uint32_t>(uint32_t& val, const std::string& data) {
147  std::istringstream s(data);
148  s >> val;
149 }
150 
151 template <>
152 void XmlReader::Read<double>(double& val, const std::string& data) {
153  std::istringstream s(data);
154  s >> val;
155 }
156 
157 template <>
158 void 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 
184 template <>
185 void XmlReader::Read<DBString>(DBString& val, const std::string& data) {
186  std::string sval;
187  Read(sval, data);
188  val = DBString(sval);
189 }
190 
191 template <>
192 void 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 
199 template <class T>
200 void 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 
216 template <class T>
217 void 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 
224 template <>
225 void XmlReader::Read<std::vector<int32_t>>(std::vector<int32_t>& val, const std::string& data) {
226  ReadVector<int32_t>(val, data);
227 }
228 
229 template <>
230 void XmlReader::Read<std::vector<bool>>(std::vector<bool>& val, const std::string& data) {
231  ReadVector<bool>(val, data);
232 }
233 
234 template <>
235 void XmlReader::Read<std::vector<uint8_t>>(std::vector<uint8_t>& val, const std::string& data) {
236  ReadVector<uint8_t>(val, data);
237 }
238 
239 template <>
240 void XmlReader::Read<std::vector<int16_t>>(std::vector<int16_t>& val, const std::string& data) {
241  ReadVector<int16_t>(val, data);
242 }
243 
244 template <>
245 void XmlReader::Read<std::vector<uint32_t>>(std::vector<uint32_t>& val, const std::string& data) {
246  ReadVector<uint32_t>(val, data);
247 }
248 
249 template <>
250 void XmlReader::Read<std::vector<double>>(std::vector<double>& val, const std::string& data) {
251  ReadVector<double>(val, data);
252 }
253 
254 template <>
255 void XmlReader::Read<DBArray<int32_t>>(DBArray<int32_t>& val, const std::string& data) {
256  ReadVector<int32_t>(val, data);
257 }
258 
259 template <>
260 void XmlReader::Read<DBArray<bool>>(DBArray<bool>& val, const std::string& data) {
261  ReadVector<bool>(val, data);
262 }
263 
264 template <>
265 void XmlReader::Read<DBArray<uint8_t>>(DBArray<uint8_t>& val, const std::string& data) {
266  ReadVector<uint8_t>(val, data);
267 }
268 
269 template <>
270 void XmlReader::Read<DBArray<int16_t>>(DBArray<int16_t>& val, const std::string& data) {
271  ReadVector<int16_t>(val, data);
272 }
273 
274 template <>
275 void XmlReader::Read<DBArray<uint32_t>>(DBArray<uint32_t>& val, const std::string& data) {
276  ReadVector<uint32_t>(val, data);
277 }
278 
279 template <>
280 void 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