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