1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4
5 #include "../lib/vstguibase.h"
6
7 /// @cond ignore
8 #if VSTGUI_USE_SYSTEM_EXPAT
9 #include <expat.h>
10 #else
11 #define XML_STATIC 1
12 #define XML_NS 0
13 #define XML_DTD 0
14 #define XML_CONTEXT_BYTES 1024
15 #define XML_LARGE_SIZE 1
16
17 #ifdef BYTEORDER
18 #define OLD_BYTEORDER = BYTEORDER
19 #undef BYTEORDER
20 #endif
21
22 #if MAC && defined (__BIG_ENDIAN__)
23 #define BYTEORDER 4321
24 #else
25 #define BYTEORDER 1234
26 #endif
27 #define HAVE_MEMMOVE
28
29 namespace VSTGUI {
30 namespace Xml {
31 #include "expat/expat.h"
32 }}
33 #endif // VSTGUI_USE_SYSTEM_EXPAT
34
35 #include "xmlparser.h"
36 #include <algorithm>
37
38 namespace VSTGUI {
39 namespace Xml {
40
41 //------------------------------------------------------------------------
42 struct Parser::Impl
43 {
44 XML_ParserStruct* parser {nullptr};
45 IHandler* handler {nullptr};
46 };
47
48 //------------------------------------------------------------------------
gStartElementHandler(void * userData,const char * name,const char ** atts)49 static void XMLCALL gStartElementHandler (void* userData, const char* name, const char** atts)
50 {
51 auto parser = static_cast<Parser*> (userData);
52 IHandler* handler = parser ? parser->getHandler () : nullptr;
53 if (handler)
54 handler->startXmlElement (parser, name, atts);
55 }
56
57 //------------------------------------------------------------------------
gEndElementHandler(void * userData,const char * name)58 static void XMLCALL gEndElementHandler (void* userData, const char* name)
59 {
60 auto parser = static_cast<Parser*> (userData);
61 IHandler* handler = parser ? parser->getHandler () : nullptr;
62 if (handler)
63 handler->endXmlElement (parser, name);
64 }
65
66 //------------------------------------------------------------------------
gCharacterDataHandler(void * userData,const char * s,int len)67 static void XMLCALL gCharacterDataHandler (void* userData, const char* s, int len)
68 {
69 auto parser = static_cast<Parser*> (userData);
70 IHandler* handler = parser ? parser->getHandler () : nullptr;
71 if (handler)
72 handler->xmlCharData (parser, (const int8_t*)s, len);
73 }
74
75 //------------------------------------------------------------------------
gCommentHandler(void * userData,const char * string)76 static void XMLCALL gCommentHandler (void* userData, const char* string)
77 {
78 auto parser = static_cast<Parser*> (userData);
79 IHandler* handler = parser ? parser->getHandler () : nullptr;
80 if (handler)
81 handler->xmlComment (parser, string);
82 }
83
84 //-----------------------------------------------------------------------------
Parser()85 Parser::Parser ()
86 {
87 pImpl = std::unique_ptr<Impl> (new Impl ());
88 pImpl->parser = XML_ParserCreate ("UTF-8");
89 }
90
91 //-----------------------------------------------------------------------------
~Parser()92 Parser::~Parser () noexcept
93 {
94 if (pImpl->parser)
95 XML_ParserFree (pImpl->parser);
96 }
97
98 //-----------------------------------------------------------------------------
getHandler() const99 IHandler* Parser::getHandler () const
100 {
101 return pImpl->handler;
102 }
103
104 //-----------------------------------------------------------------------------
parse(IContentProvider * provider,IHandler * handler)105 bool Parser::parse (IContentProvider* provider, IHandler* handler)
106 {
107 if (provider == nullptr || handler == nullptr)
108 return false;
109
110 pImpl->handler = handler;
111 XML_SetUserData (pImpl->parser, this);
112 XML_SetStartElementHandler (pImpl->parser, gStartElementHandler);
113 XML_SetEndElementHandler (pImpl->parser, gEndElementHandler);
114 XML_SetCharacterDataHandler (pImpl->parser, gCharacterDataHandler);
115 XML_SetCommentHandler (pImpl->parser, gCommentHandler);
116
117 static const uint32_t kBufferSize = 0x8000;
118
119 provider->rewind ();
120
121 while (true)
122 {
123 void* buffer = XML_GetBuffer (pImpl->parser, kBufferSize);
124 if (buffer == nullptr)
125 {
126 pImpl->handler = nullptr;
127 return false;
128 }
129
130 uint32_t bytesRead = provider->readRawXmlData ((int8_t*)buffer, kBufferSize);
131 if (bytesRead == kStreamIOError)
132 bytesRead = 0;
133 XML_Status status = XML_ParseBuffer (pImpl->parser, static_cast<int> (bytesRead), bytesRead == 0);
134 switch (status)
135 {
136 case XML_STATUS_ERROR:
137 {
138 XML_Error error = XML_GetErrorCode (pImpl->parser);
139 if (error == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) // that's ok
140 {
141 pImpl->handler = nullptr;
142 return true;
143 }
144 #if DEBUG
145 XML_Size currentLineNumber = XML_GetCurrentLineNumber (pImpl->parser);
146 DebugPrint ("XML Parser Error on line: %d\n", currentLineNumber);
147 DebugPrint ("%s\n", XML_ErrorString (XML_GetErrorCode (pImpl->parser)));
148 int offset, size;
149 const char* inputContext = XML_GetInputContext (pImpl->parser, &offset, &size);
150 if (inputContext)
151 {
152 int pos = offset;
153 while (offset > 0 && pos - offset < 20)
154 {
155 if (inputContext[offset] == '\n')
156 {
157 offset++;
158 break;
159 }
160 offset--;
161 }
162 for (int i = offset; i < size && i - offset < 40; i++)
163 {
164 if (inputContext[i] == '\n')
165 break;
166 if (inputContext[i] == '\t')
167 DebugPrint (" ");
168 else
169 DebugPrint ("%c", inputContext[i]);
170 }
171 DebugPrint ("\n");
172 for (int i = offset; i < pos; i++)
173 {
174 DebugPrint (" ");
175 }
176 DebugPrint ("^\n");
177 }
178 #endif
179 pImpl->handler = nullptr;
180 return false;
181 }
182 case XML_STATUS_SUSPENDED:
183 {
184 pImpl->handler = nullptr;
185 return true;
186 }
187 default:
188 break;
189 }
190
191 if (bytesRead == 0)
192 break;
193 }
194 pImpl->handler = nullptr;
195 return true;
196 }
197
198 //-----------------------------------------------------------------------------
stop()199 bool Parser::stop ()
200 {
201 XML_StopParser (pImpl->parser, false);
202 return true;
203 }
204
205 //------------------------------------------------------------------------
206 //------------------------------------------------------------------------
207 //------------------------------------------------------------------------
MemoryContentProvider(const void * data,uint32_t dataSize)208 MemoryContentProvider::MemoryContentProvider (const void* data, uint32_t dataSize)
209 : CMemoryStream ((const int8_t*)data, dataSize, false)
210 {
211 }
212
213 //------------------------------------------------------------------------
readRawXmlData(int8_t * buffer,uint32_t size)214 uint32_t MemoryContentProvider::readRawXmlData (int8_t* buffer, uint32_t size)
215 {
216 return readRaw (buffer, size);
217 }
218
219 //------------------------------------------------------------------------
rewind()220 void MemoryContentProvider::rewind ()
221 {
222 CMemoryStream::rewind ();
223 }
224
225 //------------------------------------------------------------------------
226 //------------------------------------------------------------------------
227 //------------------------------------------------------------------------
InputStreamContentProvider(InputStream & stream)228 InputStreamContentProvider::InputStreamContentProvider (InputStream& stream)
229 : stream (stream)
230 , startPos (0)
231 {
232 SeekableStream* seekStream = dynamic_cast<SeekableStream*> (&stream);
233 if (seekStream)
234 startPos = seekStream->tell ();
235 }
236
237 //------------------------------------------------------------------------
readRawXmlData(int8_t * buffer,uint32_t size)238 uint32_t InputStreamContentProvider::readRawXmlData (int8_t* buffer, uint32_t size)
239 {
240 return stream.readRaw (buffer, size);
241 }
242
243 //------------------------------------------------------------------------
rewind()244 void InputStreamContentProvider::rewind ()
245 {
246 SeekableStream* seekStream = dynamic_cast<SeekableStream*> (&stream);
247 if (seekStream)
248 seekStream->seek (startPos, SeekableStream::kSeekSet);
249 }
250
251 //------------------------------------------------------------------------
252 #ifdef __clang__
253 #pragma clang diagnostic ignored "-Wconversion"
254 #endif
255
256 }} // namespaces
257
258 #if !VSTGUI_USE_SYSTEM_EXPAT
259
260 namespace VSTGUI {
261 namespace Xml {
262 #include "./expat/xmltok.c"
263 #include "./expat/xmlrole.c"
264 #include "./expat/xmlparse.c"
265 }}
266
267 #ifdef OLD_BYTEORDER
268 #undef BYTEORDER
269 #define BYTEORDER = OLD_BYTEORDER
270 #endif
271
272 #endif
273
274 /// @endcond
275