aboutsummaryrefslogtreecommitdiff
path: root/src/xmlreader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmlreader.cpp')
-rw-r--r--src/xmlreader.cpp412
1 files changed, 412 insertions, 0 deletions
diff --git a/src/xmlreader.cpp b/src/xmlreader.cpp
new file mode 100644
index 0000000..bb24157
--- /dev/null
+++ b/src/xmlreader.cpp
@@ -0,0 +1,412 @@
1#include "xmlreader.h"
2#include <string.h>
3
4XmlReader::XmlReader( bool bStrip )
5{
6 nError = 0;
7 this->bStrip = bStrip;
8}
9
10XmlReader::~XmlReader()
11{
12}
13
14#define gcall( x ) if( x == false ) return false;
15
16bool XmlReader::isws( char chr )
17{
18 return ( chr == ' ' || chr == '\t' || chr == '\n' || chr == '\r' );
19}
20
21bool XmlReader::ws()
22{
23 while( true )
24 {
25 char chr = getChar();
26 if( isws( chr ) )
27 {
28 usedChar();
29 }
30 else
31 {
32 return true;
33 }
34 }
35 return true;
36}
37
38bool XmlReader::buildDoc()
39{
40 // take care of initial whitespace
41 gcall( ws() );
42 gcall( node() );
43
44 return true;
45}
46
47bool XmlReader::node()
48{
49 gcall( startNode() )
50
51 // At this point, we are closing the startNode
52 char chr = getChar();
53 if( chr == '>' )
54 {
55 usedChar();
56
57 // Now we process the guts of the node.
58 gcall( content() );
59 }
60 else if( chr == '/' )
61 {
62 // This is the tricky one, one more validation, then we close the node.
63 usedChar();
64 if( getChar() == '>' )
65 {
66 closeNode();
67 usedChar();
68 }
69 else
70 {
71 reportError("Close node in singleNode malformed!");
72 return false;
73 }
74 }
75 else
76 {
77 reportError("Close node expected, but not found.");
78 return false;
79 }
80
81 return true;
82}
83
84bool XmlReader::startNode()
85{
86 if( getChar() == '<' )
87 {
88 usedChar();
89
90 if( getChar() == '/' )
91 {
92 // Heh, it's actually a close node, go figure
93 FlexBuf fbName;
94 usedChar();
95 gcall( ws() );
96
97 while( true )
98 {
99 char chr = getChar();
100 if( isws( chr ) || chr == '>' )
101 {
102 // Here we actually compare the name we got to the name
103 // we already set, they have to match exactly.
104 if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) )
105 {
106 closeNode();
107 break;
108 }
109 else
110 {
111 reportError("Got a mismatched node close tag.");
112 return false;
113 }
114 }
115 else
116 {
117 fbName.appendData( chr );
118 usedChar();
119 }
120 }
121
122 gcall( ws() );
123 if( getChar() == '>' )
124 {
125 // Everything is cool.
126 usedChar();
127 }
128 else
129 {
130 reportError("Got extra junk data instead of node close tag.");
131 return false;
132 }
133 }
134 else
135 {
136 // We're good, format is consistant
137 addNode();
138
139 // Skip extra whitespace
140 gcall( ws() );
141 gcall( name() );
142 gcall( ws() );
143 gcall( paramlist() );
144 gcall( ws() );
145 }
146 }
147 else
148 {
149 reportError("Expected to find node opening char, '<'.\n");
150 return false;
151 }
152
153 return true;
154}
155
156bool XmlReader::name()
157{
158 FlexBuf fbName;
159
160 while( true )
161 {
162 char chr = getChar();
163 if( isws( chr ) || chr == '>' || chr == '/' )
164 {
165 setName( fbName.getData() );
166 return true;
167 }
168 else
169 {
170 fbName.appendData( chr );
171 usedChar();
172 }
173 }
174
175 return true;
176}
177
178bool XmlReader::paramlist()
179{
180 while( true )
181 {
182 char chr = getChar();
183 if( chr == '/' || chr == '>' )
184 {
185 return true;
186 }
187 else
188 {
189 gcall( param() );
190 gcall( ws() );
191 }
192 }
193
194 return true;
195}
196
197char XmlReader::getEscape()
198{
199 // Right now, we just do # escapes...
200 if( getChar( 1 ) == '#' )
201 {
202 usedChar();
203 usedChar();
204 char buf[4];
205 int j = 0;
206 for( j = 0; getChar() != ';'; j++ )
207 {
208 buf[j] = getChar();
209 usedChar();
210 }
211 usedChar();
212 buf[j] = '\0';
213 return (char)atoi( buf );
214 }
215 else
216 {
217 return '\0';
218 }
219}
220
221bool XmlReader::param()
222{
223 FlexBuf fbName;
224 FlexBuf fbValue;
225
226 while( true )
227 {
228 char chr = getChar();
229 if( isws( chr ) || chr == '=' )
230 {
231 break;
232 }
233 else
234 {
235 fbName.appendData( chr );
236 usedChar();
237 }
238 }
239
240 gcall( ws() );
241
242 if( getChar() == '=' )
243 {
244 usedChar();
245
246 gcall( ws() );
247
248 char chr = getChar();
249 if( chr == '"' )
250 {
251 // Better quoted rhs
252 usedChar();
253
254 while( true )
255 {
256 chr = getChar();
257 if( chr == '"' )
258 {
259 usedChar();
260 addProperty( fbName.getData(), fbValue.getData() );
261 return true;
262 }
263 else
264 {
265 if( chr == '&' )
266 {
267 chr = getEscape();
268 if( chr == '\0' ) return false;
269 fbValue.appendData( chr );
270 }
271 else
272 {
273 fbValue.appendData( chr );
274 usedChar();
275 }
276 }
277 }
278 }
279 else
280 {
281 // Simple one-word rhs
282 while( true )
283 {
284 chr = getChar();
285 if( isws( chr ) || chr == '/' || chr == '>' )
286 {
287 addProperty( fbName.getData(), fbValue.getData() );
288 return true;
289 }
290 else
291 {
292 if( chr == '&' )
293 {
294 chr = getEscape();
295 if( chr == '\0' ) return false;
296 fbValue.appendData( chr );
297 }
298 else
299 {
300 fbValue.appendData( chr );
301 usedChar();
302 }
303 }
304 }
305 }
306 }
307 else
308 {
309 reportError("Expected an equals to seperate the params.");
310 return false;
311 }
312
313 return true;
314}
315
316bool XmlReader::content()
317{
318 FlexBuf fbContent;
319
320 if( bStrip ) gcall( ws() );
321
322 while( true )
323 {
324 char chr = getChar();
325 if( chr == '<' )
326 {
327 if( getChar(1) == '/' )
328 {
329 if( fbContent.getLength() > 0 )
330 {
331 if( bStrip )
332 {
333 int j;
334 for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- );
335 ((char *)fbContent.getData())[j+1] = '\0';
336 }
337 setContent( fbContent.getData() );
338 }
339 usedChar();
340 usedChar();
341 gcall( ws() );
342 FlexBuf fbName;
343 while( true )
344 {
345 chr = getChar();
346 if( isws( chr ) || chr == '>' )
347 {
348 if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) )
349 {
350 closeNode();
351 break;
352 }
353 else
354 {
355 reportError("Mismatched close tag found.");
356 return false;
357 }
358 }
359 else
360 {
361 fbName.appendData( chr );
362 usedChar();
363 }
364 }
365 gcall( ws() );
366 if( getChar() == '>' )
367 {
368 usedChar();
369 return true;
370 }
371 else
372 {
373 reportError("Malformed close tag.");
374 return false;
375 }
376 }
377 else
378 {
379 if( fbContent.getLength() > 0 )
380 {
381 if( bStrip )
382 {
383 int j;
384 for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- );
385 ((char *)fbContent.getData())[j+1] = '\0';
386 }
387 setContent( fbContent.getData() );
388 fbContent.clearData();
389 }
390 gcall( node() );
391 }
392
393 if( bStrip ) gcall( ws() );
394 }
395 else
396 {
397 fbContent.appendData( chr );
398 usedChar();
399 }
400 }
401}
402
403void XmlReader::reportError( const char *sError )
404{
405 printf("XmlReader error: %s\n", sError );
406}
407
408int XmlReader::getError()
409{
410 return nError;
411}
412