liblcf
reader_xml.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of liblcf. Copyright (c) 2020 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 "reader_lcf.h"
13 #include "reader_xml.h"
14 
15 // Expat callbacks
16 #if defined(LCF_SUPPORT_XML)
17 extern "C" {
18 static void StartElementHandler(void* closure, const XML_Char* name, const XML_Char** atts) {
19  ((XmlReader*) closure)->StartElement(name, atts);
20 }
21 
22 static void EndElementHandler(void* closure, const XML_Char* name) {
23  ((XmlReader*) closure)->EndElement(name);
24 }
25 
26 static void CharacterDataHandler(void* closure, const XML_Char* s, int len) {
27  ((XmlReader*) closure)->CharacterData(s, len);
28 }
29 }
30 #endif
31 
32 XmlReader::XmlReader(std::istream& filestream) :
33  stream(filestream),
34  parser(NULL)
35 {
36 #if defined(LCF_SUPPORT_XML)
37  parser = XML_ParserCreate("UTF-8");
38 
39  XML_SetUserData(parser, (void*) this);
40  XML_SetElementHandler(parser, StartElementHandler, EndElementHandler);
41  XML_SetCharacterDataHandler(parser, CharacterDataHandler);
42 
43  handlers.push_back(NULL);
44 #endif
45 }
46 
48 #if defined(LCF_SUPPORT_XML)
49  if (parser != NULL)
50  XML_ParserFree(parser);
51  parser = NULL;
52 #endif
53 }
54 
55 bool XmlReader::IsOk() const {
56  return (stream.good() && parser != NULL);
57 }
58 
59 void XmlReader::Error(const char* fmt, ...) {
60  va_list ap;
61  va_start(ap, fmt);
62  vfprintf(stderr, fmt, ap);
63  fputc('\n', stderr);
64  va_end(ap);
65 }
66 
68 #if defined(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  Error("%s", XML_ErrorString(XML_GetErrorCode(parser)));
76  }
77 #endif
78 }
79 
81  handlers.back() = handler;
82 }
83 
84 void 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 
91 void XmlReader::CharacterData(const char* s, int len) {
92  buffer.append(s, len);
93 }
94 
95 void 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 
106 template <>
107 void 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 
114 template <>
115 void XmlReader::Read<int32_t>(int32_t& val, const std::string& data) {
116  std::istringstream s(data);
117  s >> val;
118 }
119 
120 template <>
121 void 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 
128 template <>
129 void 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 
136 template <>
137 void XmlReader::Read<int16_t>(int16_t& val, const std::string& data) {
138  std::istringstream s(data);
139  s >> val;
140 }
141 
142 template <>
143 void XmlReader::Read<uint32_t>(uint32_t& val, const std::string& data) {
144  std::istringstream s(data);
145  s >> val;
146 }
147 
148 template <>
149 void XmlReader::Read<double>(double& val, const std::string& data) {
150  std::istringstream s(data);
151  s >> val;
152 }
153 
154 template <>
155 void 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 
181 template <class T>
182 void XmlReader::ReadVector(std::vector<T>& val, const std::string& data) {
183  val.clear();
184  std::istringstream s(data);
185  for (;;) {
186  std::string str;
187  s >> str;
188  if (!s.fail()) {
189  T x;
190  XmlReader::Read<T>(x, str);
191  val.push_back(x);
192  }
193  if (!s.good())
194  break;
195  }
196 }
197 
198 template <>
199 void XmlReader::Read<std::vector<int32_t>>(std::vector<int32_t>& val, const std::string& data) {
200  ReadVector<int32_t>(val, data);
201 }
202 
203 template <>
204 void XmlReader::Read<std::vector<bool>>(std::vector<bool>& val, const std::string& data) {
205  ReadVector<bool>(val, data);
206 }
207 
208 template <>
209 void XmlReader::Read<std::vector<uint8_t>>(std::vector<uint8_t>& val, const std::string& data) {
210  ReadVector<uint8_t>(val, data);
211 }
212 
213 template <>
214 void XmlReader::Read<std::vector<int16_t>>(std::vector<int16_t>& val, const std::string& data) {
215  ReadVector<int16_t>(val, data);
216 }
217 
218 template <>
219 void XmlReader::Read<std::vector<uint32_t>>(std::vector<uint32_t>& val, const std::string& data) {
220  ReadVector<uint32_t>(val, data);
221 }
222 
223 template <>
224 void XmlReader::Read<std::vector<double>>(std::vector<double>& val, const std::string& data) {
225  ReadVector<double>(val, data);
226 }
XmlReader::Error
void Error(const char *fmt,...)
Definition: reader_xml.cpp:59
XmlReader::XmlReader
XmlReader(std::istream &filestream)
Definition: reader_xml.cpp:32
XmlHandler
Definition: reader_xml.h:116
XmlReader
Definition: reader_xml.h:31
XmlReader::SetHandler
void SetHandler(XmlHandler *handler)
Definition: reader_xml.cpp:80
XmlReader::stream
std::istream & stream
Definition: reader_xml.h:97
reader_lcf.h
XmlReader::~XmlReader
~XmlReader()
Definition: reader_xml.cpp:47
XmlReader::ReadVector
static void ReadVector(std::vector< T > &ref, const std::string &data)
Definition: reader_xml.cpp:182
XmlReader::buffer
std::string buffer
Definition: reader_xml.h:109
XmlReader::handlers
std::vector< XmlHandler * > handlers
Definition: reader_xml.h:107
XmlReader::StartElement
void StartElement(const char *name, const char **atts)
Definition: reader_xml.cpp:84
XmlReader::CharacterData
void CharacterData(const char *s, int len)
Definition: reader_xml.cpp:91
Data::data
RPG::Database data
Definition: data.cpp:14
XmlReader::parser
void * parser
Definition: reader_xml.h:102
reader_xml.h
XmlReader::EndElement
void EndElement(const char *name)
Definition: reader_xml.cpp:95
XmlReader::Parse
void Parse()
Definition: reader_xml.cpp:67
XmlReader::IsOk
bool IsOk() const
Definition: reader_xml.cpp:55
XmlHandler::CharacterData
virtual void CharacterData(XmlReader &, const std::string &)
Definition: reader_xml.h:120