liblcf
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
reader_xml.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 liblcf authors
3  * This file is released under the MIT License
4  * http://opensource.org/licenses/MIT
5  */
6 
7 #include <sstream>
8 #include <cstdarg>
9 #include <cstdio>
10 #include "reader_lcf.h"
11 #include "reader_xml.h"
12 
13 // Expat callbacks
14 #if defined(LCF_SUPPORT_XML)
15 extern "C" {
16 static void StartElementHandler(void* closure, const XML_Char* name, const XML_Char** atts) {
17  ((XmlReader*) closure)->StartElement(name, atts);
18 }
19 
20 static void EndElementHandler(void* closure, const XML_Char* name) {
21  ((XmlReader*) closure)->EndElement(name);
22 }
23 
24 static void CharacterDataHandler(void* closure, const XML_Char* s, int len) {
25  ((XmlReader*) closure)->CharacterData(s, len);
26 }
27 }
28 #endif
29 
30 XmlReader::XmlReader(const std::string& filename) :
31  filename(filename),
32  stream(NULL),
33  parser(NULL)
34 {
35  Open();
36 }
37 
39  Close();
40 }
41 
43 #if defined(LCF_SUPPORT_XML)
44  stream = fopen(filename.c_str(), "r");
45  parser = XML_ParserCreate("UTF-8");
46 
47  XML_SetUserData(parser, (void*) this);
48  XML_SetElementHandler(parser, StartElementHandler, EndElementHandler);
49  XML_SetCharacterDataHandler(parser, CharacterDataHandler);
50 
51  handlers.push_back(NULL);
52 #endif
53 }
54 
56 #if defined(LCF_SUPPORT_XML)
57  if (stream != NULL)
58  fclose(stream);
59  stream = NULL;
60 
61  if (parser != NULL)
62  XML_ParserFree(parser);
63  parser = NULL;
64 #endif
65 }
66 
67 bool XmlReader::IsOk() const {
68  return (stream != NULL && !ferror(stream) && parser != NULL);
69 }
70 
71 void XmlReader::Error(const char* fmt, ...) {
72  va_list ap;
73  va_start(ap, fmt);
74  vfprintf(stderr, fmt, ap);
75  fputc('\n', stderr);
76  va_end(ap);
77 }
78 
80 #if defined(LCF_SUPPORT_XML)
81  static const int bufsize = 4096;
82  while (IsOk() && !feof(stream)) {
83  void* buffer = XML_GetBuffer(parser, bufsize);
84  int len = fread(buffer, 1, bufsize, stream);
85  int result = XML_ParseBuffer(parser, len, len <= 0);
86  if (result == 0)
87  Error("%s", XML_ErrorString(XML_GetErrorCode(parser)));
88  }
89 #endif
90 }
91 
93  handlers.back() = handler;
94 }
95 
96 void XmlReader::StartElement(const char* name, const char** atts) {
97  XmlHandler* handler = handlers.back();
98  handlers.push_back(handler);
99  handlers.back()->StartElement(*this, name, atts);
100  buffer.clear();
101 }
102 
103 void XmlReader::CharacterData(const char* s, int len) {
104  buffer.append(s, len);
105 }
106 
107 void XmlReader::EndElement(const char* name) {
108  XmlHandler* handler = handlers.back();
109  handler->CharacterData(*this, buffer);
110  handlers.pop_back();
111  if (handler != handlers.back())
112  delete handler;
113  handlers.back()->EndElement(*this, name);
114 }
115 
116 // Primitive type readers
117 
118 template <>
119 void XmlReader::Read<bool>(bool& val, const std::string& data) {
120  std::istringstream s(data);
121  std::string str;
122  s >> str;
123  val = str == "T";
124 }
125 
126 template <>
127 void XmlReader::Read<int>(int& val, const std::string& data) {
128  std::istringstream s(data);
129  s >> val;
130 }
131 
132 template <>
133 void XmlReader::Read<uint8_t>(uint8_t& val, const std::string& data) {
134  std::istringstream s(data);
135  int x;
136  s >> x;
137  val = x;
138 }
139 
140 template <>
141 void XmlReader::Read<int16_t>(int16_t& val, const std::string& data) {
142  std::istringstream s(data);
143  s >> val;
144 }
145 
146 template <>
147 void XmlReader::Read<uint32_t>(uint32_t& val, const std::string& data) {
148  std::istringstream s(data);
149  s >> val;
150 }
151 
152 template <>
153 void XmlReader::Read<double>(double& val, const std::string& data) {
154  std::istringstream s(data);
155  s >> val;
156 }
157 
158 template <>
159 void XmlReader::Read<std::string>(std::string& val, const std::string& data) {
160  static const std::string prefix("\xee\x80");
161 
162  if (data.find(prefix) == std::string::npos) {
163  val = data;
164  return;
165  }
166 
167  // XML doesn't allow most C0 control codes, so they're re-mapped
168  // to the private-use area at U+E000. The following code restores
169  // re-mapped codes to their original value.
170 
171  val.clear();
172 
173  for (size_t pos = 0; ; ) {
174  size_t next = data.find(prefix, pos);
175  if (next > pos)
176  val.append(data, pos, next - pos);
177  if (next == std::string::npos)
178  return;
179  pos = next + 2;
180  val.append(1, data[pos] - '\x80');
181  pos++;
182  }
183 }
184 
185 template <class T>
186 void XmlReader::ReadVector(std::vector<T>& val, const std::string& data) {
187  val.clear();
188  std::istringstream s(data);
189  for (;;) {
190  std::string str;
191  s >> str;
192  if (!s.fail()) {
193  T x;
194  XmlReader::Read<T>(x, str);
195  val.push_back(x);
196  }
197  if (!s.good())
198  break;
199  }
200 }
201 
202 template <>
203 void XmlReader::Read<std::vector<int> >(std::vector<int>& val, const std::string& data) {
204  ReadVector<int>(val, data);
205 }
206 
207 template <>
208 void XmlReader::Read<std::vector<bool> >(std::vector<bool>& val, const std::string& data) {
209  ReadVector<bool>(val, data);
210 }
211 
212 template <>
213 void XmlReader::Read<std::vector<uint8_t> >(std::vector<uint8_t>& val, const std::string& data) {
214  ReadVector<uint8_t>(val, data);
215 }
216 
217 template <>
218 void XmlReader::Read<std::vector<int16_t> >(std::vector<int16_t>& val, const std::string& data) {
219  ReadVector<int16_t>(val, data);
220 }
221 
222 template <>
223 void XmlReader::Read<std::vector<uint32_t> >(std::vector<uint32_t>& val, const std::string& data) {
224  ReadVector<uint32_t>(val, data);
225 }
226 
227 template <>
228 void XmlReader::Read<std::vector<double> >(std::vector<double>& val, const std::string& data) {
229  ReadVector<double>(val, data);
230 }
RPG::Database data
Definition: data.cpp:11
void SetHandler(XmlHandler *handler)
Definition: reader_xml.cpp:92
FILE * stream
Definition: reader_xml.h:106
void Error(const char *fmt,...)
Definition: reader_xml.cpp:71
bool IsOk() const
Definition: reader_xml.cpp:67
virtual void CharacterData(XmlReader &, const std::string &)
Definition: reader_xml.h:129
void Open()
Definition: reader_xml.cpp:42
std::string filename
Definition: reader_xml.h:104
static void ReadVector(std::vector< T > &ref, const std::string &data)
Definition: reader_xml.cpp:186
void Close()
Definition: reader_xml.cpp:55
std::string buffer
Definition: reader_xml.h:118
void StartElement(const char *name, const char **atts)
Definition: reader_xml.cpp:96
void CharacterData(const char *s, int len)
Definition: reader_xml.cpp:103
std::vector< XmlHandler * > handlers
Definition: reader_xml.h:116
void * parser
Definition: reader_xml.h:111
void EndElement(const char *name)
Definition: reader_xml.cpp:107
void Parse()
Definition: reader_xml.cpp:79
XmlReader(const std::string &filename)
Definition: reader_xml.cpp:30