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) 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)
17extern "C" {
18static void StartElementHandler(void* closure, const XML_Char* name, const XML_Char** atts) {
19 ((XmlReader*) closure)->StartElement(name, atts);
20}
21
22static void EndElementHandler(void* closure, const XML_Char* name) {
23 ((XmlReader*) closure)->EndElement(name);
24}
25
26static void CharacterDataHandler(void* closure, const XML_Char* s, int len) {
27 ((XmlReader*) closure)->CharacterData(s, len);
28}
29}
30#endif
31
32XmlReader::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
55bool XmlReader::IsOk() const {
56 return (stream.good() && parser != NULL);
57}
58
59void 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
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 <class T>
182void 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
198template <>
199void XmlReader::Read<std::vector<int32_t>>(std::vector<int32_t>& val, const std::string& data) {
200 ReadVector<int32_t>(val, data);
201}
202
203template <>
204void XmlReader::Read<std::vector<bool>>(std::vector<bool>& val, const std::string& data) {
205 ReadVector<bool>(val, data);
206}
207
208template <>
209void XmlReader::Read<std::vector<uint8_t>>(std::vector<uint8_t>& val, const std::string& data) {
210 ReadVector<uint8_t>(val, data);
211}
212
213template <>
214void XmlReader::Read<std::vector<int16_t>>(std::vector<int16_t>& val, const std::string& data) {
215 ReadVector<int16_t>(val, data);
216}
217
218template <>
219void XmlReader::Read<std::vector<uint32_t>>(std::vector<uint32_t>& val, const std::string& data) {
220 ReadVector<uint32_t>(val, data);
221}
222
223template <>
224void XmlReader::Read<std::vector<double>>(std::vector<double>& val, const std::string& data) {
225 ReadVector<double>(val, data);
226}
virtual void CharacterData(XmlReader &, const std::string &)
Definition: reader_xml.h:120
void StartElement(const char *name, const char **atts)
Definition: reader_xml.cpp:84
void SetHandler(XmlHandler *handler)
Definition: reader_xml.cpp:80
XmlReader(std::istream &filestream)
Definition: reader_xml.cpp:32
void CharacterData(const char *s, int len)
Definition: reader_xml.cpp:91
bool IsOk() const
Definition: reader_xml.cpp:55
void EndElement(const char *name)
Definition: reader_xml.cpp:95
std::string buffer
Definition: reader_xml.h:109
static void ReadVector(std::vector< T > &ref, const std::string &data)
Definition: reader_xml.cpp:182
std::istream & stream
Definition: reader_xml.h:97
void Parse()
Definition: reader_xml.cpp:67
std::vector< XmlHandler * > handlers
Definition: reader_xml.h:107
void * parser
Definition: reader_xml.h:102
void Error(const char *fmt,...)
Definition: reader_xml.cpp:59