1 /*******************************************************************************
2  *
3  * Copyright (c) 2000-2003 Intel Corporation
4  * All rights reserved.
5  * Copyright (c) 2012 France Telecom All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * - Neither name of Intel Corporation nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  ******************************************************************************/
32 
33 
34 /*!
35  * \file
36  */
37 
38 #include "autoconfig.h"
39 
40 #include "ixmlparser.h"
41 
42 
43 #include "ixmldebug.h"
44 
45 
46 #include <assert.h>
47 #include <stddef.h> /* for ptrdiff_t */
48 #include <stdio.h>
49 #include <stdlib.h> /* for free(), malloc() */
50 #include <string.h>
51 
52 
53 #ifdef _WIN32
54 	#define strncasecmp strnicmp
55 #endif
56 
57 
58 static char g_error_char = '\0';
59 #ifdef IXML_HAVE_SCRIPTSUPPORT
60 static IXML_BeforeFreeNode_t Before_Free_callback;
61 #endif
62 
63 
64 static const char LESSTHAN = '<';
65 static const char GREATERTHAN = '>';
66 static const char SLASH = '/';
67 static const char EQUALS = '=';
68 static const char QUOTE = '\"';
69 static const char SINGLEQUOTE = '\'';
70 
71 
72 static const char *WHITESPACE = "\n\t\r ";
73 static const char *COMPLETETAG = "/>";
74 static const char *ENDTAG = "</";
75 static const char *XMLDECL = "<?xml ";
76 static const char *XMLDECL2 = "<?xml?";
77 static const char *BEGIN_COMMENT = "<!--";
78 static const char *END_COMMENT = "-->";
79 static const char *BEGIN_PI = "<?";
80 static const char *END_PI = "?>";
81 static const char *BEGIN_DOCTYPE = "<!DOCTYPE";
82 static const char *CDSTART = "<![CDATA[";
83 static const char *CDEND = "]]>";
84 static const char *DEC_NUMBERS = "0123456789";
85 static const char *HEX_NUMBERS = "0123456789ABCDEFabcdef";
86 
87 
88 typedef struct char_info {
89 	unsigned short l;
90 	unsigned short h;
91 } char_info_t;
92 
93 
94 typedef char utf8char[8];
95 
96 
97 /*!
98  * \brief The letter table contains all characters in XML 1.0 plus ":", "_" and
99  * ideographic.
100  *
101  * This table contains all the characters that an element name can start with.
102  * See XML 1.0 (2nd Edition) for more details.
103  */
104 static char_info_t Letter[] = {
105     {0x003A, 0x003A},           /* character ":" */
106     {0x0041, 0x005A},
107     {0x005F, 0x005F},           /* character "_" */
108     {0x0061, 0x007A}, {0x00C0, 0x00D6}, {0x00D8, 0x00F6}, {0x00F8, 0x00FF},
109     {0x0100, 0x0131}, {0x0134, 0x013E}, {0x0141, 0x0148}, {0x014A, 0x017E},
110     {0x0180, 0x01C3}, {0x01CD, 0x01F0}, {0x01F4, 0x01F5}, {0x01FA, 0x0217},
111     {0x0250, 0x02A8}, {0x02BB, 0x02C1}, {0x0386, 0x0386}, {0x0388, 0x038A},
112     {0x038C, 0x038C}, {0x038E, 0x03A1}, {0x03A3, 0x03CE}, {0x03D0, 0x03D6},
113     {0x03DA, 0x03DA},
114     {0x03DC, 0x03DC}, {0x03DE, 0x03DE}, {0x03E0, 0x03E0}, {0x03E2, 0x03F3},
115     {0x0401, 0x040C}, {0x040E, 0x044F}, {0x0451, 0x045C}, {0x045E, 0x0481},
116     {0x0490, 0x04C4}, {0x04C7, 0x04C8}, {0x04CB, 0x04CC}, {0x04D0, 0x04EB},
117     {0x04EE, 0x04F5}, {0x04F8, 0x04F9}, {0x0531, 0x0556}, {0x0559, 0x0559},
118     {0x0561, 0x0586}, {0x05D0, 0x05EA}, {0x05F0, 0x05F2}, {0x0621, 0x063A},
119     {0x0641, 0x064A}, {0x0671, 0x06B7}, {0x06BA, 0x06BE}, {0x06C0, 0x06CE},
120     {0x06D0, 0x06D3}, {0x06D5, 0x06D5}, {0x06E5, 0x06E6}, {0x0905, 0x0939},
121     {0x093D, 0x093D}, {0x0958, 0x0961}, {0x0985, 0x098C}, {0x098F, 0x0990},
122     {0x0993, 0x09A8}, {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9},
123     {0x09DC, 0x09DD}, {0x09DF, 0x09E1}, {0x09F0, 0x09F1}, {0x0A05, 0x0A0A},
124     {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, {0x0A2A, 0x0A30}, {0x0A32, 0x0A33},
125     {0x0A35, 0x0A36}, {0x0A38, 0x0A39}, {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E},
126     {0x0A72, 0x0A74}, {0x0A85, 0x0A8B}, {0x0A8D, 0x0A8D}, {0x0A8F, 0x0A91},
127     {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9},
128     {0x0ABD, 0x0ABD}, {0x0AE0, 0x0AE0}, {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10},
129     {0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, {0x0B32, 0x0B33}, {0x0B36, 0x0B39},
130     {0x0B3D, 0x0B3D}, {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B61}, {0x0B85, 0x0B8A},
131     {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, {0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C},
132     {0x0B9E, 0x0B9F}, {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB5},
133     {0x0BB7, 0x0BB9}, {0x0C05, 0x0C0C}, {0x0C0E, 0x0C10}, {0x0C12, 0x0C28},
134     {0x0C2A, 0x0C33}, {0x0C35, 0x0C39}, {0x0C60, 0x0C61}, {0x0C85, 0x0C8C},
135     {0x0C8E, 0x0C90}, {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9},
136     {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE1}, {0x0D05, 0x0D0C}, {0x0D0E, 0x0D10},
137     {0x0D12, 0x0D28}, {0x0D2A, 0x0D39}, {0x0D60, 0x0D61}, {0x0E01, 0x0E2E},
138     {0x0E30, 0x0E30}, {0x0E32, 0x0E33}, {0x0E40, 0x0E45}, {0x0E81, 0x0E82},
139     {0x0E84, 0x0E84}, {0x0E87, 0x0E88}, {0x0E8A, 0x0E8A}, {0x0E8D, 0x0E8D},
140     {0x0E94, 0x0E97}, {0x0E99, 0x0E9F}, {0x0EA1, 0x0EA3}, {0x0EA5, 0x0EA5},
141     {0x0EA7, 0x0EA7}, {0x0EAA, 0x0EAB}, {0x0EAD, 0x0EAE}, {0x0EB0, 0x0EB0},
142     {0x0EB2, 0x0EB3}, {0x0EBD, 0x0EBD}, {0x0EC0, 0x0EC4}, {0x0F40, 0x0F47},
143     {0x0F49, 0x0F69}, {0x10A0, 0x10C5}, {0x10D0, 0x10F6}, {0x1100, 0x1100},
144     {0x1102, 0x1103}, {0x1105, 0x1107}, {0x1109, 0x1109}, {0x110B, 0x110C},
145     {0x110E, 0x1112}, {0x113C, 0x113C}, {0x113E, 0x113E}, {0x1140, 0x1140},
146     {0x114C, 0x114C}, {0x114E, 0x114E}, {0x1150, 0x1150}, {0x1154, 0x1155},
147     {0x1159, 0x1159}, {0x115F, 0x1161}, {0x1163, 0x1163}, {0x1165, 0x1165},
148     {0x1167, 0x1167}, {0x1169, 0x1169}, {0x116D, 0x116E}, {0x1172, 0x1173},
149     {0x1175, 0x1175}, {0x119E, 0x119E}, {0x11A8, 0x11A8}, {0x11AB, 0x11AB},
150     {0x11AE, 0x11AF}, {0x11B7, 0x11B8}, {0x11BA, 0x11BA}, {0x11BC, 0x11C2},
151     {0x11EB, 0x11EB}, {0x11F0, 0x11F0}, {0x11F9, 0x11F9}, {0x1E00, 0x1E9B},
152     {0x1EA0, 0x1EF9}, {0x1F00, 0x1F15}, {0x1F18, 0x1F1D}, {0x1F20, 0x1F45},
153     {0x1F48, 0x1F4D}, {0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B},
154     {0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, {0x1FB6, 0x1FBC},
155     {0x1FBE, 0x1FBE}, {0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC}, {0x1FD0, 0x1FD3},
156     {0x1FD6, 0x1FDB}, {0x1FE0, 0x1FEC}, {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC},
157     {0x2126, 0x2126}, {0x212A, 0x212B}, {0x212E, 0x212E}, {0x2180, 0x2182},
158     {0x3007, 0x3007}, {0x3021, 0x3029}, /* these two are ideographic */
159     {0x3041, 0x3094}, {0x30A1, 0x30FA}, {0x3105, 0x312C},
160     {0x4E00, 0x9FA5},           /* ideographic */
161     {0xAC00, 0xD7A3}
162 };
163 
164 
165 /*!
166  * \brief The size of the letter table array.
167  */
168 #define LETTERTABLESIZE (sizeof(Letter)/sizeof(Letter[0]))
169 
170 
171 /*!
172  * \brief The NameChar table contains CombiningChar, Extender, Digit,
173  * '-', '.', less '_', ':'
174  *
175  * NameChar ::= Digit | '-' | '.' | CombiningChar | Extender
176  * See XML 1.0 2nd Edition
177  */
178 static char_info_t NameChar[] = {
179     {0x002D, 0x002D},           /* character "-" */
180     {0x002E, 0x002E},           /* character "." */
181     {0x0030, 0x0039},           /* digit */
182     {0x00B7, 0x00B7}, {0x02D0, 0x02D0}, {0x02D1, 0x02D1},   /* extended */
183     {0x0300, 0x0345}, {0x0360, 0x0361},
184     {0x0387, 0x0387},           /* extended */
185     {0x0483, 0x0486}, {0x0591, 0x05A1}, {0x05A3, 0x05B9},
186     {0x05BB, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C4},
187     {0x0640, 0x0640},           /* extended */
188     {0x064B, 0x0652},
189     {0x0660, 0x0669},           /* digit */
190     {0x0670, 0x0670},
191     {0x06D6, 0x06DC}, {0x06DD, 0x06DF}, {0x06E0, 0x06E4}, {0x06E7, 0x06E8},
192     {0x06EA, 0x06ED},
193     {0x06F0, 0x06F9},           /* digit */
194     {0x0901, 0x0903}, {0x093C, 0x093C},
195     {0x093E, 0x094C}, {0x094D, 0x094D}, {0x0951, 0x0954}, {0x0962, 0x0963},
196     {0x0966, 0x096F},           /* digit */
197     {0x0981, 0x0983}, {0x09BC, 0x09BC}, {0x09BE, 0x09BE},
198     {0x09BF, 0x09BF}, {0x09C0, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CD},
199     {0x09D7, 0x09D7}, {0x09E2, 0x09E3},
200     {0x09E6, 0x09EF},           /* digit */
201     {0x0A02, 0x0A02},
202     {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A3E}, {0x0A3F, 0x0A3F}, {0x0A40, 0x0A42},
203     {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D},
204     {0x0A66, 0x0A6F},           /* digit */
205     {0x0A70, 0x0A71},
206     {0x0A81, 0x0A83}, {0x0ABC, 0x0ABC}, {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9},
207     {0x0ACB, 0x0ACD},
208     {0x0AE6, 0x0AEF},           /* digit */
209     {0x0B01, 0x0B03}, {0x0B3C, 0x0B3C},
210     {0x0B3E, 0x0B43}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D}, {0x0B56, 0x0B57},
211     {0x0B66, 0x0B6F},           /* digit */
212     {0x0B82, 0x0B83}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8},
213     {0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7},
214     {0x0BE7, 0x0BEF},           /* digit */
215     {0x0C01, 0x0C03},
216     {0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56},
217     {0x0C66, 0x0C6F},           /* digit */
218     {0x0C82, 0x0C83}, {0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8},
219     {0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6},
220     {0x0CE6, 0x0CEF},           /* digit */
221     {0x0D02, 0x0D03},
222     {0x0D3E, 0x0D43}, {0x0D46, 0x0D48}, {0x0D4A, 0x0D4D}, {0x0D57, 0x0D57},
223     {0x0D66, 0x0D6F},           /* digit */
224     {0x0E31, 0x0E31}, {0x0E34, 0x0E3A},
225     {0x0E46, 0x0E46},           /* extended */
226     {0x0E47, 0x0E4E},
227     {0x0E50, 0x0E59},           /* digit */
228     {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9},
229     {0x0EBB, 0x0EBC},
230     {0x0EC6, 0x0EC6},           /* extended */
231     {0x0EC8, 0x0ECD},
232     {0x0ED0, 0x0ED9},           /* digit */
233     {0x0F18, 0x0F19},
234     {0x0F20, 0x0F29},           /* digit */
235     {0x0F35, 0x0F35}, {0x0F37, 0x0F37},
236     {0x0F39, 0x0F39}, {0x0F3E, 0x0F3E}, {0x0F3F, 0x0F3F}, {0x0F71, 0x0F84},
237     {0x0F86, 0x0F8B}, {0x0F90, 0x0F95}, {0x0F97, 0x0F97}, {0x0F99, 0x0FAD},
238     {0x0FB1, 0x0FB7}, {0x0FB9, 0x0FB9}, {0x20D0, 0x20DC}, {0x20E1, 0x20E1},
239     {0x3005, 0x3005},           /* extended */
240     {0x302A, 0x302F},
241     {0x3031, 0x3035},           /* extended */
242     {0x3099, 0x3099}, {0x309A, 0x309A}, /* combining char */
243     {0x309D, 0x309E}, {0x30FC, 0x30FE}  /* extended */
244 };
245 
246 
247 /*!
248  * \brief The name char table array size.
249  */
250 #define NAMECHARTABLESIZE   (sizeof(NameChar)/sizeof(NameChar[0]))
251 
252 
253 /*!
254  * \brief Frees one ElementStack item.
255  */
Parser_freeElementStackItem(IXML_ElementStack * pItem)256 static void Parser_freeElementStackItem(
257 	/*! [in] The element stack item to free. */
258 	IXML_ElementStack *pItem)
259 {
260     assert( pItem != NULL );
261     if( pItem->element != NULL ) {
262         free( pItem->element );
263         pItem->element = NULL;
264     }
265     if( pItem->namespaceUri != NULL ) {
266         free( pItem->namespaceUri );
267         pItem->namespaceUri = NULL;
268     }
269     if( pItem->prefix != NULL ) {
270         free( pItem->prefix );
271         pItem->prefix = NULL;
272     }
273 }
274 
275 
276 /*!
277  * \brief Frees namespaceURI item.
278  */
Parser_freeNsURI(IXML_NamespaceURI * pNsURI)279 static void Parser_freeNsURI(
280 	/*! [in] The name space URI item to free. */
281 	IXML_NamespaceURI *pNsURI)
282 {
283     assert( pNsURI != NULL );
284     if( pNsURI->nsURI != NULL ) {
285         free( pNsURI->nsURI );
286     }
287     if( pNsURI->prefix != NULL ) {
288         free( pNsURI->prefix );
289     }
290 }
291 
292 
293 /*!
294  * \brief Frees all temporary memory allocated by xmlparser.
295  */
Parser_free(Parser * xmlParser)296 static void Parser_free(
297 	/*! [in] The XML parser. */
298 	Parser *xmlParser)
299 {
300     IXML_ElementStack *pElement;
301     IXML_ElementStack *pNextElement;
302     IXML_NamespaceURI *pNsURI;
303     IXML_NamespaceURI *pNextNsURI;
304 
305     if( xmlParser == NULL ) {
306         return;
307     }
308 
309     if( xmlParser->dataBuffer != NULL ) {
310         free( xmlParser->dataBuffer );
311     }
312 
313     ixml_membuf_destroy( &( xmlParser->tokenBuf ) );
314     ixml_membuf_destroy( &( xmlParser->lastElem ) );
315 
316     pElement = xmlParser->pCurElement;
317     while( pElement != NULL ) {
318         Parser_freeElementStackItem( pElement );
319 
320         pNsURI = pElement->pNsURI;
321         while( pNsURI != NULL ) {
322             pNextNsURI = pNsURI->nextNsURI;
323             Parser_freeNsURI( pNsURI );
324             free( pNsURI );
325             pNsURI = pNextNsURI;
326         }
327 
328         pNextElement = pElement->nextElement;
329         free( pElement );
330         pElement = pNextElement;
331     }
332 
333     free( xmlParser );
334 }
335 
336 
337 /*!
338  * \brief Skips document type declaration
339  */
Parser_skipDocType(char ** pstr)340 static int Parser_skipDocType(
341 	/*! [in,out] The pointer to the skipped point. */
342 	char **pstr)
343 {
344     char *pCur = *pstr;
345     /* default there is no nested < */
346     char *pNext = NULL;
347     int num = 1;
348 
349     assert( ( *pstr ) != NULL );
350     if( *pstr == NULL ) {
351         return IXML_FAILED;
352     }
353 
354     while( ( pCur != NULL ) && ( num != 0 ) && ( *pCur != 0 ) ) {
355         if( *pCur == '<' ) {
356             num++;
357         } else if( *pCur == '>' ) {
358             num--;
359         } else if( *pCur == '"' ) {
360             pNext = strchr( pCur + 1, '"' );
361             if( pNext == NULL ) {
362                 return IXML_SYNTAX_ERR;
363             }
364 
365             pCur = pNext;
366         }
367 
368         pCur++;
369     }
370 
371     if( num == 0 ) {
372         *pstr = pCur;
373         return IXML_SUCCESS;
374     } else {
375         return IXML_SYNTAX_ERR;
376     }
377 }
378 
379 
380 /*!
381  * \brief Skips all characters in the string until it finds the skip key.
382  * Then it skips the skip key and returns.
383  */
Parser_skipString(char ** pstrSrc,const char * strSkipKey)384 static int Parser_skipString(
385 	/*! [in,out] The pointer to the skipped point. */
386 	char **pstrSrc,
387 	/*! [in] The skip key. */
388 	const char *strSkipKey)
389 {
390     if( !( *pstrSrc ) || !strSkipKey ) {
391         return IXML_FAILED;
392     }
393 
394     while( ( **pstrSrc )
395            && strncmp( *pstrSrc, strSkipKey,
396                        strlen( strSkipKey ) ) != 0 ) {
397         ( *pstrSrc )++;
398     }
399 
400     if( **pstrSrc == '\0' ) {
401         return IXML_SYNTAX_ERR;
402     }
403     *pstrSrc = *pstrSrc + strlen( strSkipKey );
404 
405     return IXML_SUCCESS;
406 }
407 
408 
409 /*!
410  * \brief Skip white spaces.
411  */
Parser_skipWhiteSpaces(Parser * xmlParser)412 static void Parser_skipWhiteSpaces(
413 	/*! [in] The XML parser. */
414 	Parser *xmlParser)
415 {
416     while( ( *( xmlParser->curPtr ) != 0 ) &&
417            ( strchr( WHITESPACE, ( int ) *( xmlParser->curPtr ) ) != NULL ) ) {
418         xmlParser->curPtr++;
419     }
420 }
421 
422 
423 /*!
424  * \brief Skips XML declarations.
425  */
Parser_skipXMLDecl(Parser * xmlParser)426 static int Parser_skipXMLDecl(
427 	/*! [in,out] The XML parser. */
428 	Parser *xmlParser)
429 {
430     int rc = IXML_FAILED;
431 
432     assert( xmlParser );
433     if( xmlParser == NULL ) {
434         return rc;
435     }
436 
437     rc = Parser_skipString( &( xmlParser->curPtr ), END_PI );
438     Parser_skipWhiteSpaces( xmlParser );
439     return rc;
440 }
441 
442 
443 /*!
444  * \brief Skips all characters in the string until it finds the skip key.
445  * Then it skips the skip key and returns.
446  */
Parser_skipComment(char ** pstrSrc)447 static int Parser_skipComment(
448 	/*! [in,out] The pointer to the skipped point. */
449 	char **pstrSrc)
450 {
451     char *pStrFound = NULL;
452 
453     assert( ( *pstrSrc ) != NULL );
454     if( *pstrSrc == NULL ) {
455         return IXML_FAILED;
456     }
457 
458     pStrFound = strstr( *pstrSrc, END_COMMENT );
459     if( ( pStrFound != NULL ) && ( pStrFound != *pstrSrc ) &&
460         ( *( pStrFound - 1 ) != '-' ) ) {
461         *pstrSrc = pStrFound + strlen( END_COMMENT );
462     } else {
463         return IXML_SYNTAX_ERR;
464     }
465 
466     return IXML_SUCCESS;
467 }
468 
469 
470 /*!
471  * \brief Skip comment, PI and white space.
472  */
Parser_skipMisc(Parser * xmlParser)473 static int Parser_skipMisc(
474 	/*! [in] The XML parser. */
475 	Parser *xmlParser)
476 {
477     int rc = IXML_SUCCESS;
478     int done = 0;
479 
480     while( ( done == 0 ) && ( rc == IXML_SUCCESS ) ) {
481         if( strncasecmp( xmlParser->curPtr, ( char * )BEGIN_COMMENT, strlen( BEGIN_COMMENT ) ) == 0 ) {
482             /* <!-- */
483             rc = Parser_skipComment( &( xmlParser->curPtr ) );
484 
485         } else if (strncasecmp(xmlParser->curPtr, (char *)XMLDECL , strlen(XMLDECL )) == 0 ||
486                    strncasecmp(xmlParser->curPtr, (char *)XMLDECL2, strlen(XMLDECL2)) == 0) {
487             /* <?xml or <?xml? */
488             rc = IXML_SYNTAX_ERR;
489         } else if (strncasecmp(xmlParser->curPtr, (char *)BEGIN_PI, strlen(BEGIN_PI)) == 0) {
490             /* <? */
491             rc = Parser_skipString(&xmlParser->curPtr, END_PI);
492         } else {
493             done = 1;
494         }
495         Parser_skipWhiteSpaces(xmlParser);
496     }
497 
498     return rc;
499 }
500 
501 
502 /*!
503  * \brief Skip prolog.
504  */
Parser_skipProlog(Parser * xmlParser)505 static int Parser_skipProlog(
506 	/*! [in,out] The XML parser. */
507 	Parser *xmlParser)
508 {
509     int rc = IXML_SUCCESS;
510 
511     assert( xmlParser != NULL );
512     if( xmlParser == NULL ) {
513         return IXML_FAILED;
514     }
515 
516     Parser_skipWhiteSpaces( xmlParser );
517 
518     if( strncmp( xmlParser->curPtr, ( char * )XMLDECL, strlen( XMLDECL ) ) == 0 ) {
519         /* <?xml */
520         rc = Parser_skipXMLDecl( xmlParser );
521         if( rc != IXML_SUCCESS ) {
522             return rc;
523         }
524     }
525 
526     rc = Parser_skipMisc( xmlParser );
527     if( ( rc == IXML_SUCCESS ) &&
528         strncmp( xmlParser->curPtr, ( char * )BEGIN_DOCTYPE, strlen( BEGIN_DOCTYPE ) ) == 0 ) {
529         /* <! DOCTYPE */
530         xmlParser->curPtr++;
531         rc = Parser_skipDocType( &( xmlParser->curPtr ) );
532     }
533 
534     if( rc == IXML_SUCCESS ) {
535         rc = Parser_skipMisc( xmlParser );
536     }
537 
538     return rc;
539 }
540 
541 
542 /*!
543  * \brief Set the last element to be the given string.
544  */
Parser_setLastElem(Parser * xmlParser,const char * s)545 static int Parser_setLastElem(
546 	/*! [in] The XML parser. */
547 	Parser *xmlParser,
548 	/*! [in] The string to copy from. */
549 	const char *s)
550 {
551     int rc;
552 
553     if( ( xmlParser == NULL ) || ( s == NULL ) ) {
554         return IXML_FAILED;
555     }
556 
557     rc = ixml_membuf_assign_str( &( xmlParser->lastElem ), s );
558     return rc;
559 }
560 
561 
562 /*!
563  * \brief Clear token buffer.
564  */
Parser_clearTokenBuf(Parser * xmlParser)565 static void Parser_clearTokenBuf(
566 	/*! [in] The XML parser. */
567 	Parser *xmlParser)
568 {
569     ixml_membuf_destroy( &( xmlParser->tokenBuf ) );
570 }
571 
572 
573 /*!
574  * \brief In UTF-8, characters are encoded using sequences of 1 to 6 octets.
575  * This functions will return a UTF-8 character value and its octets number.
576  *
577  * \return The UTF-8 character converted to an int (32 bits).
578  */
Parser_UTF8ToInt(const char * ss,ptrdiff_t * len)579 static int Parser_UTF8ToInt(
580 	/*! [in] The pointer to the character to encode. */
581 	const char *ss,
582 	/*! [out] The number of octets of the UTF-8 encoding of this character. */
583 	ptrdiff_t *len)
584 {
585 	const unsigned char *s = (const unsigned char *)ss;
586 	int c = *s;
587 
588 	if (c <= 127) {
589 		/* if c<=127, c is just the character. */
590 		*len = 1;
591 		return c;
592 	} else if ((c    & 0xE0) == 0xC0 &&
593 	           (s[1] & 0xc0) == 0x80) {
594 		/* a sequence of 110xxxxx and 10xxxxxx? */
595 		*len = 2;
596 		return	((c    & 0x1f) <<  6) |
597 			 (s[1] & 0x3f);
598 	} else if ((c    & 0xF0) == 0xE0 &&
599 	           (s[1] & 0xc0) == 0x80 &&
600 	           (s[2] & 0xc0) == 0x80) {
601 		/* a sequence of 1110xxxx,10xxxxxx and 10xxxxxx ? */
602 		*len = 3;
603 		return	((c    & 0x0f) << 12) |
604 			((s[1] & 0x3f) <<  6) |
605 			 (s[2] & 0x3f);
606 	} else if ((c    & 0xf8) == 0xf0 &&
607 	           (s[1] & 0xc0) == 0x80 &&
608 	           (s[2] & 0xc0) == 0x80 &&
609 	           (s[3] & 0xc0) == 0x80) {
610 		/* a sequence of 11110xxx,10xxxxxx,10xxxxxx and 10xxxxxx ? */
611 		*len = 4;
612 		return	((c    & 0x07) << 18) |
613 			((s[1] & 0x3f) << 12) |
614 			((s[2] & 0x3f) <<  6) |
615 			 (s[3] & 0x3f);
616 	} else if ((c    & 0xfc) == 0xf8 &&
617 	           (s[1] & 0xc0) == 0x80 &&
618 	           (s[2] & 0xc0) == 0x80 &&
619 	           (s[3] & 0xc0) == 0x80 &&
620 	           (s[4] & 0xc0) == 0x80) {
621 		/* a sequence of 111110xx,10xxxxxx,10xxxxxx,10xxxxxx,10xxxxxx ? */
622 		*len = 5;
623 		return	((c    & 0x03) << 24) |
624 			((s[1] & 0x3f) << 18) |
625 			((s[2] & 0x3f) << 12) |
626 			((s[3] & 0x3f) <<  6) |
627 			 (s[4] & 0x3f);
628 	} else if ((c    & 0xfe) == 0xfc &&
629 	           (s[1] & 0xc0) == 0x80 &&
630 	           (s[2] & 0xc0) == 0x80 &&
631 	           (s[3] & 0xc0) == 0x80 &&
632 	           (s[4] & 0xc0) == 0x80 &&
633 	           (s[5] & 0xc0) == 0x80) {
634 		/* a sequence of 1111110x,10xxxxxx,10xxxxxx,10xxxxxx,10xxxxxx and 10xxxxxx ? */
635 		*len = 6;
636 		return	((c    & 0x01) << 30) |
637 			((s[1] & 0x3f) << 24) |
638 			((s[2] & 0x3f) << 18) |
639 			((s[3] & 0x3f) << 12) |
640 			((s[4] & 0x3f) <<  6) |
641 			 (s[5] & 0x3f);
642 	} else {
643 		/* none of above, error */
644 		int ret = 0;
645 		int line = __LINE__;
646 		if (g_error_char) {
647 			*len = 1;
648 			ret = g_error_char;
649 		} else {
650 			*len = 0;
651 			ret = -1;
652 		}
653 		IxmlPrintf(__FILE__, line, "Parser_UTF8ToInt", "Error %d\n", ret);
654 		return ret;
655 	}
656 }
657 
658 
659 /*!
660  * \brief Will determine whether character c is in the table of tbl (either
661  * Letter table or NameChar table).
662  *
663  * \return 1 or 0.
664  */
Parser_isCharInTable(int c,char_info_t * tbl,int sz)665 static int Parser_isCharInTable(
666 	/*! [in] Character to check. */
667 	int c,
668 	/*! [in] Table to use. */
669 	char_info_t *tbl,
670 	/*! [in] Size of the table. */
671 	int sz)
672 {
673 	int t = 0;
674 	int b = sz - 1;
675 	int m;
676 
677 	while (t <= b) {
678 		m = ( t + b ) / 2;
679 		if (c < tbl[m].l) {
680 			b = m - 1;
681 		} else if (c > tbl[m].h) {
682 			t = m + 1;
683 		} else {
684 			return 1;
685 		}
686 	}
687 
688 	return 0;
689 }
690 
691 
692 /*!
693  * \brief Check whether c (int) is in LetterTable or NameCharTable.
694  */
Parser_isNameChar(int c,int bNameChar)695 static int Parser_isNameChar(
696 	/*! [in] The character to check. */
697 	int c,
698 	/*! [in] 1 if you also want to check in the NameChar table. */
699 	int bNameChar)
700 {
701 	if (Parser_isCharInTable(c, Letter, (int)LETTERTABLESIZE)) {
702 		return 1;
703 	}
704 
705 	if (bNameChar &&
706 	    Parser_isCharInTable(c, NameChar, (int)NAMECHARTABLESIZE)) {
707 		return 1;
708 	}
709 
710 	return 0;
711 }
712 
713 
714 /*!
715  * \brief see XML 1.0 (2nd Edition) 2.2.
716  */
Parser_isXmlChar(int c)717 static int Parser_isXmlChar(
718 	/*! [in] The character to check. */
719 	int c)
720 {
721 	return
722 		c == 0x9 || c == 0xA || c == 0xD ||
723 		(c >= 0x20 && c <= 0xD7FF) ||
724 		(c >= 0xE000 && c <= 0xFFFD) ||
725 		(c >= 0x10000 && c <= 0x10FFFF);
726 }
727 
728 
729 /*!
730  * \brief Returns next char value and its length.
731  */
Parser_getChar(const char * src,ptrdiff_t * cLen)732 static int Parser_getChar(
733 	/*! [in] . */
734 	const char *src,
735 	/*! [in,out] . */
736 	ptrdiff_t *cLen)
737 {
738 	int ret = -1;
739 	int line = 0;
740 	const char *pnum;
741 	int sum;
742 	char c;
743 	int i;
744 
745 	if( src == NULL || cLen == NULL ) {
746 		line = __LINE__;
747 		ret = -1;
748 		goto ExitFunction;
749 	}
750 
751 	*cLen = 0;
752 	if (*src != '&') {
753 		if (*src > 0 && Parser_isXmlChar((int)*src)) {
754 			*cLen = 1;
755 			ret = *src;
756 			goto ExitFunction;
757 		}
758 
759 		i = Parser_UTF8ToInt(src, cLen);
760 		if (!Parser_isXmlChar(i)) {
761 			line = __LINE__;
762 			ret = g_error_char ? g_error_char : -1;
763 			goto ExitFunction;
764 		}
765 
766 		line = __LINE__;
767 		ret = i;
768 		goto ExitFunction;
769 	} else if (strncasecmp(src, QUOT, strlen(QUOT)) == 0) {
770 		*cLen = (int)strlen(QUOT);
771 		ret = '"';
772 		goto ExitFunction;
773 	} else if (strncasecmp(src, LT, strlen(LT)) == 0) {
774 		*cLen = (int)strlen(LT);
775 		ret = '<';
776 		goto ExitFunction;
777 	} else if (strncasecmp(src, GT, strlen(GT)) == 0) {
778 		*cLen = (int)strlen(GT);
779 		ret = '>';
780 		goto ExitFunction;
781 	} else if (strncasecmp(src, APOS, strlen(APOS)) == 0) {
782 		*cLen = (int)strlen(APOS);
783 		ret = '\'';
784 		goto ExitFunction;
785 	} else if (strncasecmp(src, AMP, strlen(AMP)) == 0) {
786 		*cLen = (int)strlen(AMP);
787 		ret = '&';
788 		goto ExitFunction;
789 	} else if (strncasecmp(src, ESC_HEX, strlen(ESC_HEX)) == 0) {
790 		/* Read in escape characters of type &#xnn where nn is a hexadecimal value */
791 		pnum = src + strlen( ESC_HEX );
792 		sum = 0;
793 		while (strchr(HEX_NUMBERS, (int)*pnum) != 0) {
794 			c = *pnum;
795 			if (c <= '9') {
796 				sum = sum * 16 + ( c - '0' );
797 			} else if( c <= 'F' ) {
798 				sum = sum * 16 + ( c - 'A' + 10 );
799 			} else {
800 				sum = sum * 16 + ( c - 'a' + 10 );
801 			}
802 			pnum++;
803 		}
804 		if (pnum == src || *pnum != ';' || !Parser_isXmlChar(sum)) {
805 			line = __LINE__;
806 			goto fail_entity;
807 		}
808 		*cLen = pnum - src + 1;
809 		ret = sum;
810 		goto ExitFunction;
811 	} else if (strncasecmp(src, ESC_DEC, strlen(ESC_DEC)) == 0) {
812 		/* Read in escape characters of type &#nn where nn is a decimal value */
813 		pnum = src + strlen(ESC_DEC);
814 		sum = 0;
815 		while (strchr(DEC_NUMBERS, (int)*pnum) != 0) {
816 			sum = sum * 10 + ( *pnum - '0' );
817 			pnum++;
818 		}
819 		if( ( pnum == src ) || *pnum != ';' || !Parser_isXmlChar( sum ) ) {
820 			line = __LINE__;
821 			goto fail_entity;
822 		}
823 		*cLen = pnum - src + 1;
824 		ret = sum;
825 		goto ExitFunction;
826 	}
827 
828 fail_entity:
829 	if (g_error_char) {
830 		*cLen = 1;
831 		ret = '&';
832 		goto ExitFunction;
833 	}
834 	ret = -1;
835 
836 ExitFunction:
837 	if (ret == -1 || (g_error_char && ret == g_error_char)) {
838 		IxmlPrintf(__FILE__, line, "Parser_getChar", "Error %d\n", ret);
839 	}
840 
841 	return ret;
842 }
843 
844 
845 /*!
846  * \brief Appends c to token buffer.
847  */
Parser_appendTokBufChar(Parser * xmlParser,char c)848 static int Parser_appendTokBufChar(
849 	/*! [in] The XML parser. */
850 	Parser *xmlParser,
851 	/*! [in] The character to append. */
852 	char c)
853 {
854     int rc;
855 
856     rc = ixml_membuf_append( &( xmlParser->tokenBuf ), &c );
857     return rc;
858 }
859 
860 
861 /*!
862  * \brief Encodes a character to its UTF-8 character string, and return its length.
863  *
864  * \return The length of the encoded string in bytes.
865  */
Parser_intToUTF8(int c,utf8char s)866 static int Parser_intToUTF8(
867 	/*! [in] The character to encode. */
868 	int c,
869 	/*! [out] The resultant UTF-8 encoded string. */
870 	utf8char s)
871 {
872 	if (c < 0)
873 		return 0;
874 
875 	if (c <= 127) {
876 		s[0] = (char)c;
877 		s[1] = (char)0;
878 		return 1;
879 	} else if (c <= 0x07FF) {
880 		/* 0x0080 < c <= 0x07FF */
881 		s[0] = (char)(0xC0 |  (c >> 6 )        );
882 		s[1] = (char)(0x80 | ( c        & 0x3f));
883 		s[2] = (char)0;
884 		return 2;
885 	} else if (c <= 0xFFFF) {
886 		/* 0x0800 < c <= 0xFFFF */
887 		s[0] = (char)(0xE0 |  (c >> 12)        );
888 		s[1] = (char)(0x80 | ((c >> 6 ) & 0x3f));
889 		s[2] = (char)(0x80 | ( c        & 0x3f));
890 		s[3] = (char)0;
891 		return 3;
892 	} else if (c <= 0x1FFFFF) {
893 		/* 0x10000 < c <= 0x1FFFFF */
894 		s[0] = (char)(0xF0 |  (c >> 18)        );
895 		s[1] = (char)(0x80 | ((c >> 12) & 0x3f));
896 		s[2] = (char)(0x80 | ((c >> 6 ) & 0x3f));
897 		s[3] = (char)(0x80 | ( c        & 0x3f));
898 		s[4] = (char)0;
899 		return 4;
900 	} else if (c <= 0x3FFFFFF) {
901 		/* 0x200000 < c <= 3FFFFFF */
902 		s[0] = (char)(0xF8 |  (c >> 24)        );
903 		s[1] = (char)(0x80 | ((c >> 18) & 0x3f));
904 		s[2] = (char)(0x80 | ((c >> 12) & 0x3f));
905 		s[3] = (char)(0x80 | ((c >> 6 ) & 0x3f));
906 		s[4] = (char)(0x80 | ( c        & 0x3f));
907 		s[5] = (char)0;
908 		return 5;
909 	} else if (c <= 0x7FFFFFFF) {
910 		/* 0x4000000 < c <= 7FFFFFFF */
911 		s[0] = (char)(0xFC |  (c >> 30)        );
912 		s[1] = (char)(0x80 | ((c >> 24) & 0x3f));
913 		s[2] = (char)(0x80 | ((c >> 18) & 0x3f));
914 		s[3] = (char)(0x80 | ((c >> 12) & 0x3f));
915 		s[4] = (char)(0x80 | ((c >> 6 ) & 0x3f));
916 		s[5] = (char)(0x80 | ( c        & 0x3f));
917 		s[6] = (char)0;
918 		return 6;
919 	} else {
920 		/* illegal */
921 		return 0;
922 	}
923 }
924 
925 
926 /*!
927  * \brief Appends string s to token buffer.
928  */
Parser_appendTokBufStr(Parser * xmlParser,const char * s)929 static int Parser_appendTokBufStr(
930 	/*! [in] The XML parser. */
931 	Parser *xmlParser,
932 	/*! [in] The string to append. */
933 	const char *s)
934 {
935     int rc = IXML_SUCCESS;
936 
937     if( s != NULL ) {
938         rc = ixml_membuf_append_str( &( xmlParser->tokenBuf ), s );
939     }
940 
941     return rc;
942 }
943 
944 
945 /*!
946  * \brief Copy string in src into xml parser token buffer
947  */
Parser_copyToken(Parser * xmlParser,const char * src,ptrdiff_t len)948 static int Parser_copyToken(
949 	/*! [in] The XML parser. */
950 	Parser *xmlParser,
951 	/*! [in] The string to copy from. */
952 	const char *src,
953 	/*! [in] The lenght to copy. */
954 	ptrdiff_t len)
955 {
956 	int ret = IXML_SUCCESS;
957 	int line = 0;
958 	int i;
959 	int c;
960 	ptrdiff_t cl;
961 	const char *psrc;
962 	const char *pend;
963 	utf8char uch;
964 
965 	if (!src || len <= 0) {
966 		line = __LINE__;
967 		ret = IXML_FAILED;
968 		goto ExitFunction;
969 	}
970 
971 	psrc = src;
972 	pend = src + len;
973 
974 	while (psrc < pend) {
975 		c = Parser_getChar(psrc, &cl);
976 		if (c <= 0) {
977 			line = __LINE__;
978 			ret = IXML_FAILED;
979 			goto ExitFunction;
980 		}
981 
982 		if (cl == 1) {
983 			Parser_appendTokBufChar(xmlParser, (char)c);
984 			psrc++;
985 		} else {
986 			i = Parser_intToUTF8(c, uch);
987 			if (i == 0) {
988 				line = __LINE__;
989 				ret = IXML_FAILED;
990 				goto ExitFunction;
991 			}
992 			Parser_appendTokBufStr(xmlParser, uch);
993 			psrc += cl;
994 		}
995 	}
996 
997 	if (psrc > pend) {
998 		line = __LINE__;
999 		ret = IXML_FAILED;
1000 		goto ExitFunction;
1001 	}
1002 
1003 ExitFunction:
1004 	if (ret != IXML_SUCCESS) {
1005 		IxmlPrintf(__FILE__, line, "Parser_copyToken", "Error %d\n", ret);
1006 	}
1007 
1008 	return ret;
1009 }
1010 
1011 
1012 /*!
1013  * \brief Return the length of next token in tokenBuff.
1014  */
Parser_getNextToken(Parser * xmlParser)1015 static ptrdiff_t Parser_getNextToken(
1016 	/*! [in] The XML parser. */
1017 	Parser *xmlParser)
1018 {
1019     ptrdiff_t tokenLength = 0;
1020     int temp;
1021     ptrdiff_t tlen;
1022     int rc;
1023 
1024     Parser_clearTokenBuf( xmlParser );
1025 
1026     if( *( xmlParser->curPtr ) == '\0' ) {
1027         return 0;
1028     }
1029     /* skip XML instructions */
1030     rc = Parser_skipMisc( xmlParser );
1031     if( rc != IXML_SUCCESS ) {
1032         return 0;
1033     }
1034     /* Attribute value logic must come first, since all text untokenized until
1035      * end-quote */
1036     if( *( xmlParser->curPtr ) == QUOTE ) {
1037         tokenLength = 1;
1038     } else if( *( xmlParser->curPtr ) == SINGLEQUOTE ) {
1039         tokenLength = 1;
1040     } else if( *( xmlParser->curPtr ) == LESSTHAN ) {
1041 	/* Check for start tags */
1042         temp = Parser_UTF8ToInt( xmlParser->curPtr + 1, &tlen );
1043         if( temp == '/' ) {
1044 	    /* token is '</' end tag */
1045             tokenLength = 2;
1046         } else if( Parser_isNameChar( temp, 0 ) ) {
1047 	    /* '<' found, so return '<' token */
1048             tokenLength = 1;
1049         } else {
1050  	    /* error */
1051             return 0;
1052         }
1053     } else if( *( xmlParser->curPtr ) == EQUALS ) {
1054 	/* Check for '=' token, return it as a token */
1055         tokenLength = 1;
1056     } else if( *( xmlParser->curPtr ) == SLASH ) {
1057         if( *( xmlParser->curPtr + 1 ) == GREATERTHAN ) {
1058 	    /* token '/>' found */
1059             tokenLength = 2;
1060 	    /* fix */
1061             xmlParser->savePtr = xmlParser->curPtr;
1062         }
1063     } else if( *( xmlParser->curPtr ) == GREATERTHAN ) {
1064 	/* > found, so return it as a token */
1065         tokenLength = 1;
1066     } else if( Parser_isNameChar( Parser_UTF8ToInt( xmlParser->curPtr, &tlen ), 0 ) ) {
1067 	/* Check for name tokens, name found, so find out how long it is */
1068         ptrdiff_t iIndex = tlen;
1069 
1070         while( Parser_isNameChar
1071                ( Parser_UTF8ToInt( xmlParser->curPtr + iIndex, &tlen ),
1072                  1 ) ) {
1073             iIndex += tlen;
1074         }
1075         tokenLength = iIndex;
1076     } else {
1077         return 0;
1078     }
1079 
1080     /* Copy the token to the return string */
1081     if( Parser_copyToken( xmlParser, xmlParser->curPtr, tokenLength ) !=
1082         IXML_SUCCESS ) {
1083         return 0;
1084     }
1085 
1086     xmlParser->curPtr += tokenLength;
1087     return tokenLength;
1088 }
1089 
1090 
1091 /*!
1092  * \brief Version of strdup() that handles NULL input.
1093  *
1094  * \return The same as strdup().
1095  */
safe_strdup(const char * s)1096 static char *safe_strdup(
1097 	/*! [in] String to be duplicated. */
1098 	const char *s)
1099 {
1100 	assert(s != NULL);
1101 
1102 	if (s == NULL) {
1103 		return strdup((const char*)"");
1104 	}
1105 	return strdup(s);
1106 }
1107 
1108 
1109 /*!
1110  * \brief Processes the STag as defined by XML spec.
1111  */
Parser_processSTag(Parser * xmlParser,IXML_Node * node)1112 static int Parser_processSTag(
1113 	/*! [in] The XML parser. */
1114 	Parser *xmlParser,
1115 	/*! [in] The Node to process. */
1116 	IXML_Node *node)
1117 {
1118     char *pCurToken = NULL;
1119     int rc;
1120 
1121     if( Parser_getNextToken( xmlParser ) == 0 ) {
1122         return IXML_SYNTAX_ERR;
1123     }
1124 
1125     pCurToken = ( xmlParser->tokenBuf ).buf;
1126     if( pCurToken != NULL ) {
1127         node->nodeName = safe_strdup( pCurToken );
1128         if( node->nodeName == NULL ) {
1129             return IXML_INSUFFICIENT_MEMORY;
1130         }
1131     } else {
1132         return IXML_SYNTAX_ERR;
1133     }
1134 
1135     rc = Parser_setLastElem( xmlParser, node->nodeName );
1136     if( rc != IXML_SUCCESS ) {
1137 	/* no need to free node->nodeName, main loop will free it */
1138         return IXML_FAILED;
1139     }
1140 
1141     rc = Parser_setNodePrefixAndLocalName( node );
1142     if( rc != IXML_SUCCESS ) {
1143 	/* no need to free node->nodeName, main loop will free it */
1144         return IXML_FAILED;
1145     }
1146 
1147     node->nodeValue = NULL;
1148     node->nodeType = eELEMENT_NODE;
1149 
1150     xmlParser->savePtr = xmlParser->curPtr;
1151     if( Parser_getNextToken( xmlParser ) == 0 ) {
1152 	/* no need to free node->nodeName, main loop will free it */
1153         return IXML_SYNTAX_ERR;
1154     }
1155 
1156     pCurToken = ( xmlParser->tokenBuf ).buf;
1157     /* check to see what is the next token */
1158     if( strcmp( pCurToken, "/>" ) == 0 )
1159     {
1160 	/* empty element */
1161         xmlParser->state = eELEMENT;
1162 	/* backup to /> */
1163         xmlParser->curPtr = xmlParser->savePtr;
1164     } else if( strcmp( pCurToken, ">" ) == 0 )
1165     {
1166 	/* expecting text node */
1167         xmlParser->state = eCONTENT;
1168     } else {
1169         xmlParser->state = eATTRIBUTE;
1170         xmlParser->curPtr = xmlParser->savePtr;
1171     }
1172 
1173     return IXML_SUCCESS;
1174 }
1175 
1176 
1177 /*!
1178  * \brief
1179  */
Parser_skipPI(char ** pSrc)1180 static int Parser_skipPI(
1181 	/*! [in,out] The pointer to the skipped point. */
1182 	char **pSrc)
1183 {
1184     char *pEnd = NULL;
1185 
1186     assert( *pSrc );
1187     if( *pSrc == NULL ) {
1188         return IXML_FAILED;
1189     }
1190 
1191     if ((strncasecmp(*pSrc, (char *)XMLDECL , strlen(XMLDECL )) == 0) ||
1192         (strncasecmp(*pSrc, (char *)XMLDECL2, strlen(XMLDECL2)) == 0)) {
1193         /* not allowed */
1194         return IXML_SYNTAX_ERR;
1195     }
1196 
1197     if (strncasecmp(*pSrc, (char *)BEGIN_PI, strlen(BEGIN_PI)) == 0) {
1198         pEnd = strstr( *pSrc, END_PI );
1199         if( ( pEnd != NULL ) && ( pEnd != *pSrc ) ) {
1200             *pSrc = pEnd + strlen( BEGIN_PI );
1201         } else {
1202             return IXML_SYNTAX_ERR;
1203         }
1204     }
1205 
1206     return IXML_SUCCESS;
1207 }
1208 
1209 
1210 /*!
1211  * \brief Processes CDSection as defined by XML spec.
1212  *
1213  * \return
1214  */
Parser_processCDSect(char ** pSrc,IXML_Node * node)1215 static int Parser_processCDSect(
1216 	/*! [in] . */
1217 	char **pSrc,
1218 	/*! [in] The Node to process. */
1219 	IXML_Node *node)
1220 {
1221     char *pEnd;
1222     size_t tokenLength = (size_t)0;
1223     char *pCDataStart;
1224 
1225     if( *pSrc == NULL ) {
1226         return IXML_FAILED;
1227     }
1228 
1229     pCDataStart = *pSrc + strlen( CDSTART );
1230     pEnd = pCDataStart;
1231     while( ( Parser_isXmlChar( (int)*pEnd ) ) && ( *pEnd != '\0' ) ) {
1232         if( strncmp( pEnd, CDEND, strlen( CDEND ) ) == 0 ) {
1233             break;
1234         } else {
1235             pEnd++;
1236         }
1237     }
1238 
1239     if( ( pEnd - pCDataStart > 0 ) && ( *pEnd != '\0' ) ) {
1240         tokenLength = (size_t)pEnd - (size_t)pCDataStart;
1241         node->nodeValue = (char *)malloc(tokenLength + (size_t)1);
1242         if( node->nodeValue == NULL ) {
1243             return IXML_INSUFFICIENT_MEMORY;
1244         }
1245         strncpy(node->nodeValue, pCDataStart, tokenLength);
1246         node->nodeValue[tokenLength] = '\0';
1247 
1248         node->nodeName = safe_strdup( CDATANODENAME );
1249         if( node->nodeName == NULL ) {
1250             /* no need to free node->nodeValue at all, bacause node contents
1251 	     * will be freed by the main loop. */
1252             return IXML_INSUFFICIENT_MEMORY;
1253         }
1254 
1255         node->nodeType = eCDATA_SECTION_NODE;
1256         *pSrc = pEnd + strlen( CDEND );
1257         return IXML_SUCCESS;
1258     } else {
1259         return IXML_SYNTAX_ERR;
1260     }
1261 }
1262 
1263 
1264 /*!
1265  * \brief Processes the CONTENT as defined in XML spec.
1266  */
Parser_processContent(Parser * xmlParser,IXML_Node * node)1267 static int Parser_processContent(
1268 	/*! [in] The XML parser. */
1269 	Parser *xmlParser,
1270 	/*! [in] The Node to process. */
1271 	IXML_Node *node)
1272 {
1273 	int ret = IXML_SUCCESS;
1274 	int line = 0;
1275 	char *pEndContent;
1276 	ptrdiff_t tokenLength;
1277 	const char *notAllowed = "]]>";
1278 	char *pCurToken = NULL;
1279 
1280 	/* save pointer for backup */
1281 	xmlParser->savePtr = xmlParser->curPtr;
1282 	Parser_skipWhiteSpaces( xmlParser );
1283 
1284 	if (*(xmlParser->curPtr) == '\0' ) {
1285 		/* end of file is reached */
1286 		ret = IXML_SUCCESS;
1287 		goto ExitFunction;
1288 	}
1289 
1290 	pEndContent = xmlParser->curPtr;
1291 	if (*pEndContent == LESSTHAN) {
1292 		if (strncmp(pEndContent, (char *)CDSTART, strlen(CDSTART)) == 0) {
1293 			if (Parser_processCDSect(&pEndContent, node) != IXML_SUCCESS) {
1294 				line = __LINE__;
1295 				ret = IXML_SYNTAX_ERR;
1296 				goto ExitFunction;
1297 			} else {
1298 				xmlParser->curPtr = pEndContent;
1299 			}
1300 		} else if(strncmp(pEndContent, (char *)BEGIN_COMMENT, strlen(BEGIN_COMMENT)) == 0) {
1301 			if (Parser_skipComment(&pEndContent) != IXML_SUCCESS) {
1302 				line = __LINE__;
1303 				ret = IXML_SYNTAX_ERR;
1304 				goto ExitFunction;
1305 			} else {
1306 				xmlParser->curPtr = pEndContent;
1307 			}
1308 		} else if(strncmp(pEndContent, (char *)BEGIN_PI, strlen(BEGIN_PI)) == 0) {
1309 			if (Parser_skipPI(&pEndContent) != IXML_SUCCESS) {
1310 				line = __LINE__;
1311 				ret = IXML_SYNTAX_ERR;
1312 				goto ExitFunction;
1313 			} else {
1314 				xmlParser->curPtr = pEndContent;
1315 			}
1316 		} else {
1317 			/* empty content */
1318 			xmlParser->state = eELEMENT;
1319 		}
1320 	} else {
1321 		/* backup */
1322 		xmlParser->curPtr = xmlParser->savePtr;
1323 		pEndContent = xmlParser->curPtr;
1324 
1325 		while ((*pEndContent != LESSTHAN) &&
1326 		       ( strncmp(pEndContent, (const char *)notAllowed, strlen(notAllowed)) != 0) &&
1327 		       *pEndContent) {
1328 			pEndContent++;
1329 		}
1330 
1331 		if (strncmp(pEndContent, (const char *)notAllowed, strlen(notAllowed)) == 0) {
1332 			line = __LINE__;
1333 			ret = IXML_SYNTAX_ERR;
1334 			goto ExitFunction;
1335 		}
1336 
1337 		tokenLength = pEndContent - xmlParser->curPtr;
1338 		Parser_clearTokenBuf( xmlParser );
1339 
1340 		if (Parser_copyToken(xmlParser, xmlParser->curPtr, tokenLength) != IXML_SUCCESS) {
1341 			line = __LINE__;
1342 			ret = IXML_SYNTAX_ERR;
1343 			goto ExitFunction;
1344 		}
1345 
1346 		pCurToken = (xmlParser->tokenBuf).buf;
1347 		if (pCurToken != NULL) {
1348 			node->nodeValue = safe_strdup(pCurToken);
1349 			if (node->nodeValue == NULL) {
1350 				line = __LINE__;
1351 				ret = IXML_INSUFFICIENT_MEMORY;
1352 				goto ExitFunction;
1353 			}
1354 		} else {
1355 			line = __LINE__;
1356 			ret = IXML_SYNTAX_ERR;
1357 			goto ExitFunction;
1358 		}
1359 
1360 		node->nodeName = safe_strdup( TEXTNODENAME );
1361 		if (node->nodeName == NULL) {
1362 			line = __LINE__;
1363 			ret = IXML_SYNTAX_ERR;
1364 			goto ExitFunction;
1365 		}
1366 		node->nodeType = eTEXT_NODE;
1367 
1368 		/* adjust curPtr */
1369 		xmlParser->curPtr += tokenLength;
1370 	}
1371 
1372 ExitFunction:
1373 	if (ret != IXML_SUCCESS) {
1374 		IxmlPrintf(__FILE__, line, "Parser_processContent", "Error %d\n", ret);
1375 	}
1376 
1377 	return ret;
1378 }
1379 
1380 
1381 /*!
1382  * \brief Process ETag as defined by XML spec.
1383  */
Parser_processETag(Parser * xmlParser,IXML_Node * node,int * bETag)1384 static int Parser_processETag(
1385 	/*! [in] The XML parser. */
1386 	Parser *xmlParser,
1387 	/*! [in] The Node to process. */
1388 	IXML_Node *node,
1389 	/*! [out] . */
1390 	int *bETag)
1391 {
1392 	int ret = IXML_SUCCESS;
1393 	int line = 0;
1394 	char *pCurToken = NULL;
1395 
1396 	assert( xmlParser != NULL );
1397 	if( Parser_getNextToken( xmlParser ) == 0 ) {
1398 		line = __LINE__;
1399 		ret = IXML_SYNTAX_ERR;
1400 		goto ExitFunction;
1401 	}
1402 
1403 	pCurToken = ( xmlParser->tokenBuf ).buf;
1404 	if( pCurToken == NULL ) {
1405 		line = __LINE__;
1406 		ret = IXML_SYNTAX_ERR;
1407 		goto ExitFunction;
1408 	}
1409 	node->nodeName = safe_strdup( pCurToken );
1410 	if( node->nodeName == NULL ) {
1411 		line = __LINE__;
1412 		ret = IXML_INSUFFICIENT_MEMORY;
1413 		goto ExitFunction;
1414 	}
1415 
1416 	node->nodeValue = NULL;
1417 	node->nodeType = eELEMENT_NODE;
1418 
1419 	Parser_skipWhiteSpaces( xmlParser );
1420 
1421 	/* read the >  */
1422 	if( Parser_getNextToken( xmlParser ) == 0 ) {
1423 		line = __LINE__;
1424 		ret = IXML_SYNTAX_ERR;
1425 		goto ExitFunction;
1426 	}
1427 
1428 	pCurToken = ( xmlParser->tokenBuf ).buf;
1429 	if( pCurToken == NULL ) {
1430 		/* no need to free node->nodeName, it is freed by main loop */
1431 		line = __LINE__;
1432 		ret = IXML_SYNTAX_ERR;
1433 		goto ExitFunction;
1434 	}
1435 
1436 	if( strcmp( pCurToken, ">" ) != 0 ) {
1437 		line = __LINE__;
1438 		ret = IXML_SYNTAX_ERR;
1439 		goto ExitFunction;
1440 	}
1441 
1442 	*bETag = 1;
1443 
1444 ExitFunction:
1445 	if (ret != IXML_SUCCESS) {
1446 		IxmlPrintf(__FILE__, line, "Parser_processETag", "Error %d\n", ret);
1447 	}
1448 
1449 	return ret;
1450 }
1451 
1452 
1453 /*!
1454  * \brief Unimplemented function.
1455  *
1456  * \return IXML_SUCCESS.
1457  */
1458 #if 0
1459 static int Parser_parseReference(
1460 	/*! [in] Currently unused. */
1461 	char *pStr)
1462 {
1463 	/* place holder for future implementation */
1464 	return IXML_SUCCESS;
1465 	pStr = pStr;
1466 }
1467 #endif
1468 
1469 
1470 /*!
1471  * \brief Return the namespce as defined as prefix.
1472  */
Parser_getNameSpace(Parser * xmlParser,const char * prefix)1473 static char *Parser_getNameSpace(
1474 	/*! [in] The XML parser. */
1475 	Parser *xmlParser,
1476 	/*! [in] The prefix. */
1477 	const char *prefix)
1478 {
1479     IXML_ElementStack *pCur;
1480     IXML_NamespaceURI *pNsUri;
1481 
1482     pCur = xmlParser->pCurElement;
1483     if( strcmp( pCur->prefix, prefix ) != 0 ) {
1484         pNsUri = pCur->pNsURI;
1485         while( pNsUri != NULL ) {
1486             if( strcmp( pNsUri->prefix, prefix ) == 0 ) {
1487                 return pNsUri->nsURI;
1488             }
1489             pNsUri = pNsUri->nextNsURI;
1490         }
1491     } else {
1492         return pCur->namespaceUri;
1493     }
1494 
1495     return NULL;
1496 
1497 }
1498 
1499 
1500 /*!
1501  * \brief Add a namespace definition.
1502  */
Parser_addNamespace(Parser * xmlParser)1503 static int Parser_addNamespace(
1504 	/*! [in] The XML parser. */
1505 	Parser *xmlParser)
1506 {
1507 	IXML_Node *pNode;
1508 	IXML_ElementStack *pCur;
1509 	const char *namespaceUri;
1510 
1511 	pNode = xmlParser->pNeedPrefixNode;
1512 	pCur = xmlParser->pCurElement;
1513 	if (!pNode->prefix) {
1514 		/* element does not have prefix */
1515 		if (strcmp(pNode->nodeName, pCur->element) != 0)
1516 			return IXML_FAILED;
1517 		if (pCur->namespaceUri) {
1518 			/* it would be wrong that pNode->namespace != NULL. */
1519 			assert(pNode->namespaceURI == NULL);
1520 			pNode->namespaceURI = safe_strdup(pCur->namespaceUri);
1521 			if (!pNode->namespaceURI)
1522 				return IXML_INSUFFICIENT_MEMORY;
1523 		}
1524 		xmlParser->pNeedPrefixNode = NULL;
1525 	} else {
1526 		if (!pCur->prefix ||
1527 		    ((strcmp(pNode->nodeName, pCur->element) != 0) &&
1528 		     (strcmp(pNode->prefix, pCur->prefix) != 0)))
1529 			return IXML_FAILED;
1530 		namespaceUri = Parser_getNameSpace(xmlParser, pCur->prefix);
1531 		if (namespaceUri) {
1532 			pNode->namespaceURI = safe_strdup(namespaceUri);
1533 			if (!pNode->namespaceURI)
1534 				return IXML_INSUFFICIENT_MEMORY;
1535 			xmlParser->pNeedPrefixNode = NULL;
1536 		}
1537 	}
1538 
1539 	return IXML_SUCCESS;
1540 }
1541 
1542 
1543 /*!
1544  * \brief Add namespace definition.
1545  */
Parser_xmlNamespace(Parser * xmlParser,IXML_Node * newNode)1546 static int Parser_xmlNamespace(
1547 	/*! [in] The XML parser. */
1548 	Parser *xmlParser,
1549 	/*! [in] The Node to process. */
1550 	IXML_Node *newNode)
1551 {
1552 	IXML_ElementStack *pCur = xmlParser->pCurElement;
1553 	IXML_NamespaceURI *pNewNs = NULL;
1554 	IXML_NamespaceURI *pNs = NULL;
1555 	IXML_NamespaceURI *pPrevNs = NULL;
1556 	int ret = IXML_SUCCESS;
1557 	int line = 0;
1558 
1559 	/* if the newNode contains a namespace definition */
1560 	assert(newNode->nodeName != NULL);
1561 
1562 	if (strcmp(newNode->nodeName, "xmlns") == 0) {
1563 		/* default namespace def. */
1564 		if (pCur->namespaceUri != NULL) {
1565 			free(pCur->namespaceUri);
1566 		}
1567 		pCur->namespaceUri = safe_strdup(newNode->nodeValue);
1568 		if (pCur->namespaceUri == NULL) {
1569 			ret = IXML_INSUFFICIENT_MEMORY;
1570 			line = __LINE__;
1571 			goto ExitFunction;
1572 		}
1573 	} else if (strncmp(newNode->nodeName, "xmlns:", strlen("xmlns:")) == 0) {
1574 		/* namespace definition */
1575 		ret = Parser_setNodePrefixAndLocalName(newNode);
1576 		if (ret != IXML_SUCCESS) {
1577 			line = __LINE__;
1578 			goto ExitFunction;
1579 		}
1580 
1581 		assert(newNode->localName != NULL);
1582 
1583 		if (pCur == NULL) {
1584 			ret = IXML_FAILED;
1585 			line = __LINE__;
1586 			goto ExitFunction;
1587 		}
1588 		if (pCur->prefix != NULL &&
1589 		    strcmp(pCur->prefix, newNode->localName) == 0) {
1590 			if (pCur->namespaceUri != NULL) {
1591 				free(pCur->namespaceUri);
1592 			}
1593 			pCur->namespaceUri = safe_strdup(newNode->nodeValue);
1594 			if (pCur->namespaceUri == NULL) {
1595 				ret = IXML_INSUFFICIENT_MEMORY;
1596 				line = __LINE__;
1597 				goto ExitFunction;
1598 			}
1599 		} else {
1600 			pPrevNs = pCur->pNsURI;
1601 			pNs = pPrevNs;
1602 			while (pNs != NULL) {
1603 				if (pNs->prefix != NULL &&
1604 				    strcmp(pNs->prefix, newNode->localName) == 0) {
1605 					/* replace namespace definition */
1606 					break;
1607 				} else {
1608 					pPrevNs = pNs;
1609 					pNs = pNs->nextNsURI;
1610 				}
1611 			}
1612 			if (pNs == NULL) {
1613 				/* a new definition */
1614 				pNewNs = (IXML_NamespaceURI *)
1615 					malloc(sizeof (IXML_NamespaceURI));
1616 				if (pNewNs == NULL) {
1617 					ret = IXML_INSUFFICIENT_MEMORY;
1618 					line = __LINE__;
1619 					goto ExitFunction;
1620 				}
1621 				memset(pNewNs, 0, sizeof (IXML_NamespaceURI));
1622 				pNewNs->prefix = safe_strdup(newNode->localName);
1623 				if (pNewNs->prefix == NULL) {
1624 					free(pNewNs);
1625 					ret = IXML_INSUFFICIENT_MEMORY;
1626 					line = __LINE__;
1627 					goto ExitFunction;
1628 				}
1629 				pNewNs->nsURI = safe_strdup(newNode->nodeValue);
1630 				if (pNewNs->nsURI == NULL) {
1631 					Parser_freeNsURI(pNewNs);
1632 					free(pNewNs);
1633 					ret = IXML_INSUFFICIENT_MEMORY;
1634 					line = __LINE__;
1635 					goto ExitFunction;
1636 				}
1637 				if (pCur->pNsURI == NULL) {
1638 					pCur->pNsURI = pNewNs;
1639 				} else {
1640 					pPrevNs->nextNsURI = pNewNs;
1641 				}
1642 			} else {
1643 				/* udpate the namespace */
1644 				if (pNs->nsURI != NULL) {
1645 					free(pNs->nsURI);
1646 				}
1647 				pNs->nsURI = safe_strdup(newNode->nodeValue);
1648 				if (pNs->nsURI == NULL) {
1649 					ret = IXML_INSUFFICIENT_MEMORY;
1650 					line = __LINE__;
1651 					goto ExitFunction;
1652 				}
1653 			}
1654 		}
1655 	}
1656 	if (xmlParser->pNeedPrefixNode != NULL) {
1657 		ret = Parser_addNamespace(xmlParser);
1658 		line = __LINE__;
1659 		goto ExitFunction;
1660 	}
1661 
1662 ExitFunction:
1663 	if (ret != IXML_SUCCESS && ret != IXML_FILE_DONE) {
1664 		IxmlPrintf(__FILE__, line, "Parser_xmlNamespace", "Error %d\n", ret);
1665 	}
1666 
1667 	return ret;
1668 }
1669 
1670 
1671 /*!
1672  * \brief Processes attribute.
1673  *
1674  * \return IXML_SUCCESS or failure code.
1675  */
Parser_processAttribute(Parser * xmlParser,IXML_Node * node)1676 static int Parser_processAttribute(
1677 	/*! [in] The XML parser. */
1678 	Parser *xmlParser,
1679 	/*! [in] The Node to process. */
1680 	IXML_Node *node)
1681 {
1682 	int ret = IXML_SUCCESS;
1683 	int line = 0;
1684 	ptrdiff_t tlen = 0;
1685 	char *strEndQuote = NULL;
1686 	char *pCur = NULL;
1687 	char *pCurToken = NULL;
1688 
1689 	assert(xmlParser);
1690 
1691 	if (xmlParser == NULL) {
1692 		ret = IXML_FAILED;
1693 		line = __LINE__;
1694 		goto ExitFunction;
1695 	}
1696 	pCurToken = xmlParser->tokenBuf.buf;
1697 	if (pCurToken == NULL) {
1698 		ret = IXML_SYNTAX_ERR;
1699 		line = __LINE__;
1700 		goto ExitFunction;
1701 	}
1702 	if (Parser_isNameChar(Parser_UTF8ToInt(pCurToken, &tlen), 0) == 0) {
1703 		ret = IXML_SYNTAX_ERR;
1704 		line = __LINE__;
1705 		goto ExitFunction;
1706 	}
1707 	/* copy in the attribute name */
1708 	node->nodeName = safe_strdup(pCurToken);
1709 	if (node->nodeName == NULL) {
1710 		ret = IXML_INSUFFICIENT_MEMORY;
1711 		line = __LINE__;
1712 		goto ExitFunction;
1713 	}
1714 	/* read in the "=" sign */
1715 	if (Parser_getNextToken(xmlParser) == 0) {
1716 		ret = IXML_SYNTAX_ERR;
1717 		line = __LINE__;
1718 		goto ExitFunction;
1719 	}
1720 
1721 	pCurToken = xmlParser->tokenBuf.buf;
1722 	if (*pCurToken != EQUALS) {
1723 		ret = IXML_SYNTAX_ERR;
1724 		line = __LINE__;
1725 		goto ExitFunction;
1726 	}
1727 	/* read in the single quote or double quote */
1728 	if (Parser_getNextToken(xmlParser) == 0) {
1729 		ret = IXML_SYNTAX_ERR;
1730 		line = __LINE__;
1731 		goto ExitFunction;
1732 	}
1733 	/* pCurToken is either quote or single quote */
1734 	pCurToken = ( xmlParser->tokenBuf ).buf;
1735 	if (*pCurToken != QUOTE && *pCurToken != SINGLEQUOTE) {
1736 		ret = IXML_SYNTAX_ERR;
1737 		line = __LINE__;
1738 		goto ExitFunction;
1739 	}
1740 	strEndQuote = strstr(xmlParser->curPtr, pCurToken);
1741 	if (strEndQuote == NULL) {
1742 		ret = IXML_SYNTAX_ERR;
1743 		line = __LINE__;
1744 		goto ExitFunction;
1745 	}
1746 	/* check between curPtr and strEndQuote,
1747 	 * whether there are illegal chars. */
1748 	pCur = xmlParser->curPtr;
1749 	while (pCur < strEndQuote) {
1750 		if (*pCur == '<') {
1751 			ret = IXML_SYNTAX_ERR;
1752 			line = __LINE__;
1753 			goto ExitFunction;
1754 		}
1755 		/*if (*pCur == '&') {
1756 			Parser_parseReference(++pCur);
1757 		}*/
1758 		pCur++;
1759 	}
1760 	/* clear token buffer */
1761 	Parser_clearTokenBuf(xmlParser);
1762 	if (strEndQuote != xmlParser->curPtr) {
1763 		ret = Parser_copyToken(
1764 			xmlParser,
1765 			xmlParser->curPtr,
1766 			strEndQuote - xmlParser->curPtr);
1767 		if(ret  != IXML_SUCCESS) {
1768 			ret = IXML_SYNTAX_ERR;
1769 			line = __LINE__;
1770 			goto ExitFunction;
1771 		}
1772 	}
1773 	/* skip the ending quote */
1774 	xmlParser->curPtr = strEndQuote + 1;
1775 	pCurToken = xmlParser->tokenBuf.buf;
1776 	if (pCurToken != NULL) {
1777 		/* attribute has value, like a="c" */
1778 		node->nodeValue = safe_strdup(pCurToken);
1779 		if (node->nodeValue == NULL) {
1780 			ret = IXML_INSUFFICIENT_MEMORY;
1781 			line = __LINE__;
1782 			goto ExitFunction;
1783 		}
1784 	} else {
1785 		/* if attribute doesn't have value, like a=""
1786 		 * somewhere on other places is this copied */
1787 		node->nodeValue = malloc(sizeof (char));
1788 		*(node->nodeValue) = '\0';
1789 	}
1790 	node->nodeType = eATTRIBUTE_NODE;
1791 
1792 	/* check whether this is a new namespace definition */
1793 	ret = Parser_xmlNamespace(xmlParser, node);
1794 	if (ret != IXML_SUCCESS) {
1795 		line = __LINE__;
1796 		goto ExitFunction;
1797 	}
1798 	/* read ahead to see whether we have more attributes */
1799 	xmlParser->savePtr = xmlParser->curPtr;
1800 	if (Parser_getNextToken(xmlParser) == 0) {
1801 		ret = IXML_SYNTAX_ERR;
1802 		line = __LINE__;
1803 		goto ExitFunction;
1804 	}
1805 
1806 	pCurToken = xmlParser->tokenBuf.buf;
1807 	if (strcmp(pCurToken, "<") == 0) {
1808 		ret = IXML_FAILED;
1809 		line = __LINE__;
1810 		goto ExitFunction;
1811 	} else if(strcmp(pCurToken, ">") != 0) {
1812 		/* more attribute? */
1813 		/* backup */
1814 		xmlParser->curPtr = xmlParser->savePtr;
1815 	} else {
1816 		xmlParser->state = eCONTENT;
1817 	}
1818 
1819 ExitFunction:
1820 	if (ret != IXML_SUCCESS && ret != IXML_FILE_DONE) {
1821 		IxmlPrintf(__FILE__, line, "Parser_processAttribute", "Error %d\n", ret);
1822 	}
1823 
1824 	return ret;
1825 }
1826 
1827 
1828 /*!
1829  * \brief Get the next node.
1830  *
1831  * \return IXML_SUCCESS and the next node or IXML_FILE_DONE or an error.
1832  */
Parser_getNextNode(Parser * xmlParser,IXML_Node * node,int * bETag)1833 static int Parser_getNextNode(
1834 	/*! [in] The XML parser. */
1835 	Parser *xmlParser,
1836 	/*! [out] The XML parser. */
1837 	IXML_Node *node,
1838 	/*! [out] The XML parser. */
1839 	int *bETag)
1840 {
1841 	char *pCurToken = NULL;
1842 	char *lastElement = NULL;
1843 	int ret = IXML_SUCCESS;
1844 	int line = 0;
1845 	ptrdiff_t tokenLen = 0;
1846 
1847 	/* endof file reached? */
1848 	if (*(xmlParser->curPtr) == '\0') {
1849 		*bETag = 1;
1850 		line = __LINE__;
1851 		ret = IXML_FILE_DONE;
1852 		goto ExitFunction;
1853 	}
1854 
1855 	switch (xmlParser->state) {
1856 	case eCONTENT:
1857 		line = __LINE__;
1858 		ret = Parser_processContent(xmlParser, node);
1859 		goto ExitFunction;
1860 	default:
1861 		Parser_skipWhiteSpaces(xmlParser);
1862 		tokenLen = Parser_getNextToken(xmlParser);
1863 		if (tokenLen == 0 &&
1864 		    xmlParser->pCurElement == NULL &&
1865 		    *(xmlParser->curPtr) == '\0') {
1866 			/* comments after the xml doc */
1867 			line = __LINE__;
1868 			ret = IXML_SUCCESS;
1869 			goto ExitFunction;
1870 		} else if ((xmlParser->tokenBuf).length == (size_t)0) {
1871 			line = __LINE__;
1872 			ret = IXML_SYNTAX_ERR;
1873 			goto ExitFunction;
1874 		}
1875 
1876 		pCurToken = (xmlParser->tokenBuf).buf;
1877 		if (*pCurToken == GREATERTHAN) {
1878 			line = __LINE__;
1879 			ret = IXML_SUCCESS;
1880 			goto ExitFunction;
1881 		} else if (strcmp(pCurToken, ENDTAG) == 0) {
1882 			/* we got </, read next element */
1883 			line = __LINE__;
1884 			ret = Parser_processETag(xmlParser, node, bETag);
1885 			goto ExitFunction;
1886 		} else if (*pCurToken == LESSTHAN) {
1887 			line = __LINE__;
1888 			ret = Parser_processSTag(xmlParser, node);
1889 			goto ExitFunction;
1890 		} else if (strcmp(pCurToken, COMPLETETAG) == 0) {
1891 			lastElement = (xmlParser->lastElem).buf;
1892 			if (lastElement == NULL) {
1893 				line = __LINE__;
1894 				ret = IXML_SYNTAX_ERR;
1895 				goto ExitFunction;
1896 			}
1897 
1898 			node->nodeName = safe_strdup(lastElement);
1899 			if (node->nodeName == NULL) {
1900 				line = __LINE__;
1901 				ret = IXML_INSUFFICIENT_MEMORY;
1902 				goto ExitFunction;
1903 			}
1904 			node->nodeType = eELEMENT_NODE;
1905 			*bETag = 1;
1906 
1907 			line = __LINE__;
1908 			ret = IXML_SUCCESS;
1909 			goto ExitFunction;
1910 		} else if (xmlParser->pCurElement != NULL) {
1911 			switch (xmlParser->state) {
1912 			case eATTRIBUTE:
1913 				if (Parser_processAttribute(xmlParser, node) != IXML_SUCCESS) {
1914 					line = __LINE__;
1915 					ret = IXML_SYNTAX_ERR;
1916 					goto ExitFunction;
1917 				}
1918 				break;
1919 			default:
1920 				line = __LINE__;
1921 				ret = IXML_SYNTAX_ERR;
1922 				goto ExitFunction;
1923 			}
1924 		} else {
1925 			line = __LINE__;
1926 			ret = IXML_SYNTAX_ERR;
1927 			goto ExitFunction;
1928 		}
1929 	}
1930 
1931 ExitFunction:
1932 	if (ret != IXML_SUCCESS && ret != IXML_FILE_DONE) {
1933 		IxmlPrintf(__FILE__, line, "Parser_getNextNode", "Error %d\n", ret);
1934 	}
1935 
1936 	return ret;
1937 }
1938 
1939 
1940 /*!
1941  * \brief Decides whether element's prefix is already defined.
1942  */
Parser_ElementPrefixDefined(Parser * xmlParser,IXML_Node * newNode,char ** nsURI)1943 static int Parser_ElementPrefixDefined(
1944 	/*! [in] The XML parser. */
1945 	Parser *xmlParser,
1946 	/*! [in] The Node to process. */
1947 	IXML_Node *newNode,
1948 	/*! [in,out] The name space URI. */
1949 	char **nsURI )
1950 {
1951     IXML_ElementStack *pCur = xmlParser->pCurElement;
1952     IXML_NamespaceURI *pNsUri;
1953 
1954     while( pCur != NULL ) {
1955         if( ( pCur->prefix != NULL )
1956             && ( strcmp( pCur->prefix, newNode->prefix ) == 0 ) ) {
1957             *nsURI = pCur->namespaceUri;
1958             return 1;
1959         } else {
1960             pNsUri = pCur->pNsURI;
1961 
1962             while( pNsUri != NULL ) {
1963                 if( strcmp( pNsUri->prefix, newNode->prefix ) == 0 ) {
1964                     *nsURI = pNsUri->nsURI;
1965                     return 1;
1966                 } else {
1967                     pNsUri = pNsUri->nextNsURI;
1968                 }
1969             }
1970         }
1971 
1972         pCur = pCur->nextElement;
1973 
1974     }
1975 
1976     return 0;
1977 }
1978 
1979 
1980 /*!
1981  * \brief Set element's namespace.
1982  */
Parser_setElementNamespace(IXML_Element * newElement,const char * nsURI)1983 static int Parser_setElementNamespace(
1984 	/*! [in] The Element Node to process. */
1985 	IXML_Element *newElement,
1986 	/*! [in] The name space string. */
1987 	const char *nsURI)
1988 {
1989     if( newElement != NULL ) {
1990         if( newElement->n.namespaceURI != NULL ) {
1991             return IXML_SYNTAX_ERR;
1992         } else {
1993             ( newElement->n ).namespaceURI = safe_strdup( nsURI );
1994             if( ( newElement->n ).namespaceURI == NULL ) {
1995                 return IXML_INSUFFICIENT_MEMORY;
1996             }
1997         }
1998     }
1999 
2000     return IXML_SUCCESS;
2001 }
2002 
2003 
2004 /*!
2005  * \brief Reports whether the new attribute is the same as an existing one.
2006  *
2007  * \return 1 if the new attribute is the same as an existing one.
2008  */
isDuplicateAttribute(Parser * xmlParser,IXML_Node * newAttrNode)2009 static int isDuplicateAttribute(
2010 	/*! [in] The XML parser. */
2011 	Parser *xmlParser,
2012 	/*! [in] The node attribute to compare. */
2013 	IXML_Node *newAttrNode)
2014 {
2015     IXML_Node *elementNode = NULL;
2016     IXML_Node *attrNode = NULL;
2017 
2018     elementNode = xmlParser->currentNodePtr;
2019     attrNode = elementNode->firstAttr;
2020     while( attrNode != NULL ) {
2021         if( strcmp( attrNode->nodeName, newAttrNode->nodeName ) == 0 ) {
2022             return 1;
2023         }
2024 
2025         attrNode = attrNode->nextSibling;
2026     }
2027 
2028     return 0;
2029 }
2030 
2031 
2032 /*!
2033  * \brief Processes the attribute name.
2034  *
2035  * \return IXML_SUCCESS if successful, otherwise or an error code.
2036  */
Parser_processAttributeName(IXML_Document * rootDoc,Parser * xmlParser,IXML_Node * newNode)2037 static int Parser_processAttributeName(
2038 	/*! [in] The XML document. */
2039 	IXML_Document *rootDoc,
2040 	/*! [in] The XML parser. */
2041 	Parser *xmlParser,
2042 	/*! [in] The Node to process. */
2043 	IXML_Node *newNode)
2044 {
2045     IXML_Attr *attr = NULL;
2046     int rc = IXML_SUCCESS;
2047 
2048     if( isDuplicateAttribute( xmlParser, newNode ) ) {
2049         return IXML_SYNTAX_ERR;
2050     }
2051 
2052     rc = ixmlDocument_createAttributeEx( rootDoc, newNode->nodeName, &attr );
2053     if( rc != IXML_SUCCESS ) {
2054         return rc;
2055     }
2056 
2057     rc = ixmlNode_setNodeProperties( ( IXML_Node * ) attr, newNode );
2058     if( rc != IXML_SUCCESS ) {
2059         ixmlAttr_free( attr );
2060         return rc;
2061     }
2062 
2063     rc = ixmlElement_setAttributeNode(
2064 	(IXML_Element *)xmlParser->currentNodePtr, attr, NULL );
2065     if( rc != IXML_SUCCESS ) {
2066         ixmlAttr_free( attr );
2067     }
2068     return rc;
2069 }
2070 
2071 
2072 /*!
2073  * \brief Push a new element onto element stack.
2074  *
2075  * \return
2076  */
Parser_pushElement(Parser * xmlParser,IXML_Node * newElement)2077 static int Parser_pushElement(
2078 	/*! [in] The XML parser. */
2079 	Parser *xmlParser,
2080 	/*! [in] The element node to push. */
2081 	IXML_Node *newElement)
2082 {
2083     IXML_ElementStack *pCurElement = NULL;
2084     IXML_ElementStack *pNewStackElement = NULL;
2085 
2086     assert( newElement );
2087     if( newElement != NULL ) {
2088         /* push new element */
2089         pNewStackElement =
2090             ( IXML_ElementStack * ) malloc( sizeof( IXML_ElementStack ) );
2091         if( pNewStackElement == NULL ) {
2092             return IXML_INSUFFICIENT_MEMORY;
2093         }
2094 
2095         memset( pNewStackElement, 0, sizeof( IXML_ElementStack ) );
2096         /* the element member includes both prefix and name */
2097 
2098         pNewStackElement->element = safe_strdup( newElement->nodeName );
2099         if( pNewStackElement->element == NULL ) {
2100             free( pNewStackElement );
2101             return IXML_INSUFFICIENT_MEMORY;
2102         }
2103 
2104         if( newElement->prefix != 0 ) {
2105             pNewStackElement->prefix = safe_strdup( newElement->prefix );
2106             if( pNewStackElement->prefix == NULL ) {
2107                 Parser_freeElementStackItem( pNewStackElement );
2108                 free( pNewStackElement );
2109                 return IXML_INSUFFICIENT_MEMORY;
2110             }
2111         }
2112 
2113         if( newElement->namespaceURI != 0 ) {
2114             pNewStackElement->namespaceUri =
2115                 safe_strdup( newElement->namespaceURI );
2116             if( pNewStackElement->namespaceUri == NULL ) {
2117                 Parser_freeElementStackItem( pNewStackElement );
2118                 free( pNewStackElement );
2119                 return IXML_INSUFFICIENT_MEMORY;
2120             }
2121         }
2122 
2123         pCurElement = xmlParser->pCurElement;
2124 
2125         /* insert the new element into the top of the stack */
2126         pNewStackElement->nextElement = pCurElement;
2127         xmlParser->pCurElement = pNewStackElement;
2128 
2129     }
2130 
2131     return IXML_SUCCESS;
2132 }
2133 
2134 
2135 /*!
2136  * \brief Reports whether there is a top level element in the parser.
2137  *
2138  * \return 1 if there is a top level element in the parser.
2139  */
isTopLevelElement(Parser * xmlParser)2140 static int isTopLevelElement(
2141 	/*! [in] The XML parser. */
2142 	Parser *xmlParser)
2143 {
2144     assert(xmlParser);
2145     return xmlParser->pCurElement == NULL;
2146 }
2147 
2148 
2149 /*!
2150  * \brief Decide whether the current element has default namespace
2151  */
Parser_hasDefaultNamespace(Parser * xmlParser,char ** nsURI)2152 static int Parser_hasDefaultNamespace(
2153 	/*! [in] The XML parser. */
2154 	Parser *xmlParser,
2155 	/*! [in,out] The name space URI. */
2156 	char **nsURI )
2157 {
2158     IXML_ElementStack *pCur = xmlParser->pCurElement;
2159 
2160     while( pCur != NULL ) {
2161         if( ( pCur->prefix == NULL ) && ( pCur->namespaceUri != NULL ) ) {
2162             *nsURI = pCur->namespaceUri;
2163             return 1;
2164         } else {
2165             pCur = pCur->nextElement;
2166         }
2167     }
2168 
2169     return 0;
2170 }
2171 
2172 
2173 /*!
2174  * \brief Processes element name.
2175  *
2176  * \return IXML_SUCCESS if successful, otherwise or an error code.
2177  */
Parser_processElementName(IXML_Document * rootDoc,Parser * xmlParser,IXML_Node * newNode)2178 static int Parser_processElementName(
2179 	/*! [in] The XML document. */
2180 	IXML_Document *rootDoc,
2181 	/*! [in] The XML parser. */
2182 	Parser *xmlParser,
2183 	/*! [in] The Node to process. */
2184 	IXML_Node *newNode )
2185 {
2186     IXML_Element *newElement = NULL;
2187     char *nsURI = NULL;
2188     int rc = IXML_SUCCESS;
2189 
2190     if( xmlParser->bHasTopLevel ) {
2191         if( isTopLevelElement( xmlParser ) ) {
2192             return IXML_SYNTAX_ERR;
2193         }
2194     } else {
2195         xmlParser->bHasTopLevel = 1;
2196     }
2197 
2198     xmlParser->savePtr = xmlParser->curPtr;
2199     rc = ixmlDocument_createElementEx( rootDoc, newNode->nodeName, &newElement );
2200     if( rc != IXML_SUCCESS ) {
2201         return rc;
2202     }
2203 
2204     rc = ixmlNode_setNodeProperties( ( IXML_Node * ) newElement, newNode );
2205     if( rc != IXML_SUCCESS ) {
2206         ixmlElement_free( newElement );
2207         return rc;
2208     }
2209 
2210     if (newNode->prefix) {
2211 	/* element has namespace prefix */
2212         if (!Parser_ElementPrefixDefined(xmlParser, newNode, &nsURI)) {
2213             /* read next node to see whether it includes namespace definition */
2214             xmlParser->pNeedPrefixNode = (IXML_Node *)newElement;
2215         } else {
2216 	    /* fill in the namespace */
2217             Parser_setElementNamespace( newElement, nsURI );
2218         }
2219     } else {
2220 	/* does element has default namespace */
2221         /* the node may have default namespace definition */
2222         if (Parser_hasDefaultNamespace(xmlParser, &nsURI)) {
2223             Parser_setElementNamespace(newElement, nsURI);
2224         } else {
2225             switch (xmlParser->state) {
2226             case eATTRIBUTE:
2227                 /* the default namespace maybe defined later */
2228                 xmlParser->pNeedPrefixNode = (IXML_Node *)newElement;
2229                 break;
2230             default:
2231                 break;
2232             }
2233         }
2234     }
2235 
2236     rc = ixmlNode_appendChild(xmlParser->currentNodePtr, (IXML_Node *)newElement);
2237     if (rc != IXML_SUCCESS) {
2238         ixmlElement_free(newElement);
2239         return rc;
2240     }
2241 
2242     xmlParser->currentNodePtr = ( IXML_Node * ) newElement;
2243 
2244     /* push element to stack */
2245     rc = Parser_pushElement( xmlParser, ( IXML_Node * ) newElement );
2246     return rc;
2247 }
2248 
2249 
2250 /*!
2251  * \brief Check if a new node->nodeName matches top of element stack.
2252  *
2253  * \return 1 if matches.
2254  */
Parser_isValidEndElement(Parser * xmlParser,IXML_Node * newNode)2255 static int Parser_isValidEndElement(
2256 	/*! [in] The XML parser. */
2257 	Parser *xmlParser,
2258 	/*! [in] The node. */
2259 	IXML_Node *newNode)
2260 {
2261 	assert(xmlParser);
2262 
2263 	if (xmlParser->pCurElement == NULL) {
2264 		return 0;
2265 	}
2266 
2267 	assert(xmlParser->pCurElement->element);
2268 	assert(newNode);
2269 	assert(newNode->nodeName);
2270 	return strcmp(xmlParser->pCurElement->element, newNode->nodeName) == 0;
2271 }
2272 
2273 
2274 /*!
2275  * \brief Remove element from element stack.
2276  */
Parser_popElement(Parser * xmlParser)2277 static void Parser_popElement(
2278 	/*! [in] The XML parser. */
2279 	Parser *xmlParser)
2280 {
2281 	IXML_ElementStack *pCur = NULL;
2282 	IXML_NamespaceURI *pnsUri = NULL;
2283 	IXML_NamespaceURI *pNextNS = NULL;
2284 
2285 	pCur = xmlParser->pCurElement;
2286 	if (pCur != NULL) {
2287 		xmlParser->pCurElement = pCur->nextElement;
2288 		Parser_freeElementStackItem(pCur);
2289 		pnsUri = pCur->pNsURI;
2290 		while (pnsUri != NULL) {
2291 			pNextNS = pnsUri->nextNsURI;
2292 			Parser_freeNsURI(pnsUri);
2293 			free(pnsUri);
2294 			pnsUri = pNextNS;
2295 		}
2296 		free(pCur);
2297 	}
2298 }
2299 
2300 
2301 /*!
2302  * \brief Verifies endof element tag is the same as the openning element tag.
2303  */
Parser_eTagVerification(Parser * xmlParser,IXML_Node * newNode)2304 static int Parser_eTagVerification(
2305 	/*! [in] The XML parser. */
2306 	Parser *xmlParser,
2307 	/*! [in] The Node to process. */
2308 	IXML_Node *newNode)
2309 {
2310     assert( newNode->nodeName );
2311     assert( xmlParser->currentNodePtr );
2312 
2313     switch( newNode->nodeType ) {
2314     case eELEMENT_NODE:
2315         if( Parser_isValidEndElement( xmlParser, newNode ) ) {
2316             Parser_popElement( xmlParser );
2317         } else {
2318 	    /* syntax error */
2319             return IXML_SYNTAX_ERR;
2320         }
2321         break;
2322     default:
2323        break;
2324     }
2325 
2326     if( strcmp( newNode->nodeName, xmlParser->currentNodePtr->nodeName ) ==
2327         0 ) {
2328         xmlParser->currentNodePtr = xmlParser->currentNodePtr->parentNode;
2329     } else {
2330         return IXML_SYNTAX_ERR;
2331     }
2332 
2333     return IXML_SUCCESS;
2334 }
2335 
2336 
2337 /*!
2338  * \brief Parses the xml file and returns the DOM document tree.
2339  *
2340  * \return
2341  */
Parser_parseDocument(IXML_Document ** retDoc,Parser * xmlParser)2342 static int Parser_parseDocument(
2343 	/*! [out] The XML document. */
2344 	IXML_Document **retDoc,
2345 	/*! [in] The XML parser. */
2346 	Parser *xmlParser)
2347 {
2348     IXML_Document *gRootDoc = NULL;
2349     IXML_Node newNode;
2350     int bETag = 0;
2351     IXML_Node *tempNode = NULL;
2352     int rc = IXML_SUCCESS;
2353     IXML_CDATASection *cdataSecNode = NULL;
2354 
2355     /* It is important that the node gets initialized here, otherwise things
2356      * can go wrong on the error handler. */
2357     ixmlNode_init( &newNode );
2358 
2359     rc = ixmlDocument_createDocumentEx( &gRootDoc );
2360     if( rc != IXML_SUCCESS ) {
2361         goto ErrorHandler;
2362     }
2363 
2364     xmlParser->currentNodePtr = ( IXML_Node * ) gRootDoc;
2365 
2366     rc = Parser_skipProlog( xmlParser );
2367     if( rc != IXML_SUCCESS ) {
2368         goto ErrorHandler;
2369     }
2370 
2371     while( bETag == 0 ) {
2372         /* clear the newNode contents. Redundant on the first iteration,
2373 	 * but nonetheless, necessary due to the possible calls to
2374 	 * ErrorHandler above. Currently, this is just a memset to zero. */
2375         ixmlNode_init( &newNode );
2376 
2377         if( Parser_getNextNode( xmlParser, &newNode, &bETag ) ==
2378             IXML_SUCCESS ) {
2379             if( bETag == 0 ) {
2380                 switch ( newNode.nodeType ) {
2381                     case eELEMENT_NODE:
2382                         rc = Parser_processElementName( gRootDoc,
2383                                                         xmlParser,
2384                                                         &newNode );
2385                         if( rc != IXML_SUCCESS ) {
2386                             goto ErrorHandler;
2387                         }
2388                         break;
2389 
2390                     case eTEXT_NODE:
2391                         rc = ixmlDocument_createTextNodeEx( gRootDoc,
2392                                                             newNode.
2393                                                             nodeValue,
2394                                                             &tempNode );
2395                         if( rc != IXML_SUCCESS ) {
2396                             goto ErrorHandler;
2397                         }
2398 
2399                         rc = ixmlNode_appendChild( xmlParser->
2400                                                    currentNodePtr,
2401                                                    tempNode );
2402                         if( rc != IXML_SUCCESS ) {
2403                             goto ErrorHandler;
2404                         }
2405 
2406                         break;
2407 
2408                     case eCDATA_SECTION_NODE:
2409                         rc = ixmlDocument_createCDATASectionEx( gRootDoc,
2410                                                                 newNode.
2411                                                                 nodeValue,
2412                                                                 &cdataSecNode );
2413                         if( rc != IXML_SUCCESS ) {
2414                             goto ErrorHandler;
2415                         }
2416 
2417                         rc = ixmlNode_appendChild( xmlParser->
2418                                                    currentNodePtr,
2419                                                    &( cdataSecNode->n ) );
2420                         if( rc != IXML_SUCCESS ) {
2421                             goto ErrorHandler;
2422                         }
2423                         break;
2424 
2425                     case eATTRIBUTE_NODE:
2426                         rc = Parser_processAttributeName( gRootDoc,
2427                                                           xmlParser,
2428                                                           &newNode );
2429                         if( rc != IXML_SUCCESS ) {
2430                             goto ErrorHandler;
2431                         }
2432                         break;
2433 
2434                     default:
2435                         break;
2436                 }
2437             } else {
2438                 /* ETag==1, endof element tag. */
2439                 rc = Parser_eTagVerification( xmlParser, &newNode );
2440                 if( rc != IXML_SUCCESS ) {
2441                     goto ErrorHandler;
2442                 }
2443                 xmlParser->state = eCONTENT;
2444             }
2445 
2446             /* reset bETag flag */
2447             bETag = 0;
2448 
2449         } else if( bETag ) {
2450 	    /* file is done */
2451             break;
2452         } else {
2453             rc = IXML_FAILED;
2454             goto ErrorHandler;
2455         }
2456         Parser_freeNodeContent( &newNode );
2457 
2458     }
2459 
2460     if( xmlParser->pCurElement != NULL ) {
2461         rc = IXML_SYNTAX_ERR;
2462         goto ErrorHandler;
2463     }
2464 
2465     *retDoc = ( IXML_Document * ) gRootDoc;
2466     Parser_free( xmlParser );
2467     return rc;
2468 
2469 ErrorHandler:
2470     Parser_freeNodeContent( &newNode );
2471     ixmlDocument_free( gRootDoc );
2472     Parser_free( xmlParser );
2473     return rc;
2474 }
2475 
2476 
Parser_isValidXmlName(const DOMString name)2477 int Parser_isValidXmlName(const DOMString name)
2478 {
2479 	const char *pstr = NULL;
2480 	size_t i = (size_t)0;
2481 	size_t nameLen = (size_t)0;
2482 
2483 	assert(name != NULL);
2484 
2485 	nameLen = strlen(name);
2486 	pstr = name;
2487 	if (Parser_isNameChar((int)*pstr, 0)) {
2488 		for (i = (size_t)1; i < nameLen; ++i) {
2489 			if (Parser_isNameChar((int)*(pstr + i), 1) == 0) {
2490 				/* illegal char */
2491 				return 0;
2492 			}
2493 		}
2494 	}
2495 
2496 	return 1;
2497 }
2498 
2499 
Parser_setErrorChar(char c)2500 void Parser_setErrorChar(char c)
2501 {
2502 	g_error_char = c;
2503 }
2504 
2505 #ifdef IXML_HAVE_SCRIPTSUPPORT
Parser_setBeforeFree(IXML_BeforeFreeNode_t hndlr)2506 void Parser_setBeforeFree(IXML_BeforeFreeNode_t hndlr)
2507 {
2508 	Before_Free_callback = hndlr;
2509 }
2510 
Parser_getBeforeFree()2511 IXML_BeforeFreeNode_t Parser_getBeforeFree()
2512 {
2513 	return Before_Free_callback;
2514 }
2515 #endif
2516 
2517 /*!
2518  * \brief Initializes a xml parser.
2519  *
2520  * \return The parser object or \b NULL if there is not enough memory.
2521  */
Parser_init()2522 static Parser *Parser_init()
2523 {
2524 	Parser *newParser = NULL;
2525 
2526 	newParser = (Parser *)malloc(sizeof (Parser));
2527 	if (newParser == NULL) {
2528 		return NULL;
2529 	}
2530 
2531 	memset(newParser, 0, sizeof (Parser));
2532 	ixml_membuf_init(&(newParser->tokenBuf));
2533 	ixml_membuf_init(&(newParser->lastElem));
2534 
2535 	return newParser;
2536 }
2537 
2538 
2539 /*!
2540  * \brief Read a xml file or buffer contents into xml parser.
2541  */
Parser_readFileOrBuffer(Parser * xmlParser,const char * xmlFileName,int file)2542 static int Parser_readFileOrBuffer(
2543 	/*! [in] The XML parser. */
2544 	Parser *xmlParser,
2545 	/*! [in] The file name or the buffer to copy, according to the
2546 	 * parameter "file". */
2547 	const char *xmlFileName,
2548 	/*! [in] 1 if you want to read from a file, 0 if xmlFileName is
2549 	 * the buffer to copy to the parser. */
2550 	int file)
2551 {
2552     long fileSize = 0;
2553     size_t bytesRead = (size_t)0;
2554     FILE *xmlFilePtr = NULL;
2555 
2556     if( file ) {
2557         xmlFilePtr = fopen( xmlFileName, "rb" );
2558         if( xmlFilePtr == NULL ) {
2559             return IXML_NO_SUCH_FILE;
2560         } else {
2561             fseek( xmlFilePtr, 0, SEEK_END );
2562             fileSize = ftell( xmlFilePtr );
2563             if( fileSize <= 0 ) {
2564                 fclose( xmlFilePtr );
2565                 return IXML_SYNTAX_ERR;
2566             }
2567 
2568             xmlParser->dataBuffer = (char *)malloc((size_t)fileSize + (size_t)1);
2569             if( xmlParser->dataBuffer == NULL ) {
2570                 fclose( xmlFilePtr );
2571                 return IXML_INSUFFICIENT_MEMORY;
2572             }
2573 
2574             fseek( xmlFilePtr, 0, SEEK_SET );
2575             bytesRead =
2576                 fread(xmlParser->dataBuffer, (size_t)1, (size_t)fileSize, xmlFilePtr);
2577 	    /* append null */
2578             xmlParser->dataBuffer[bytesRead] = '\0';
2579             fclose( xmlFilePtr );
2580         }
2581     } else {
2582         xmlParser->dataBuffer = safe_strdup( xmlFileName );
2583         if( xmlParser->dataBuffer == NULL ) {
2584             return IXML_INSUFFICIENT_MEMORY;
2585         }
2586     }
2587 
2588     return IXML_SUCCESS;
2589 }
2590 
2591 
2592 /*!
2593  * \brief Parses a xml file and return the DOM tree.
2594  */
Parser_LoadDocument(IXML_Document ** retDoc,const char * xmlFileName,int file)2595 int Parser_LoadDocument(
2596 	/*! [out] The output document tree. */
2597 	IXML_Document **retDoc,
2598 	/*! [in] The file name or the buffer to copy, according to the
2599 	 * parameter "file". */
2600 	const char *xmlFileName,
2601 	/*! [in] 1 if you want to read from a file, 0 if xmlFileName is
2602 	 * the buffer to copy to the parser. */
2603 	int file)
2604 {
2605     int rc = IXML_SUCCESS;
2606     Parser *xmlParser = NULL;
2607 
2608     xmlParser = Parser_init();
2609     if( xmlParser == NULL ) {
2610         return IXML_INSUFFICIENT_MEMORY;
2611     }
2612 
2613     rc = Parser_readFileOrBuffer( xmlParser, xmlFileName, file );
2614     if( rc != IXML_SUCCESS ) {
2615         Parser_free( xmlParser );
2616         return rc;
2617     }
2618 
2619     xmlParser->curPtr = xmlParser->dataBuffer;
2620     rc = Parser_parseDocument( retDoc, xmlParser );
2621     return rc;
2622 
2623 }
2624 
2625 
Parser_freeNodeContent(IXML_Node * nodeptr)2626 void Parser_freeNodeContent(IXML_Node *nodeptr)
2627 {
2628     if( nodeptr == NULL ) {
2629         return;
2630     }
2631 
2632     if( nodeptr->nodeName != NULL ) {
2633         free( nodeptr->nodeName );
2634     }
2635 
2636     if( nodeptr->nodeValue != NULL ) {
2637         free( nodeptr->nodeValue );
2638     }
2639 
2640     if( nodeptr->namespaceURI != NULL ) {
2641         free( nodeptr->namespaceURI );
2642     }
2643 
2644     if( nodeptr->prefix != NULL ) {
2645         free( nodeptr->prefix );
2646     }
2647 
2648     if( nodeptr->localName != NULL ) {
2649         free( nodeptr->localName );
2650     }
2651 }
2652 
2653 
2654 /*!
2655  * \brief Set the node prefix and localName as defined by the nodeName in the
2656  * form of ns:name.
2657  */
Parser_setNodePrefixAndLocalName(IXML_Node * node)2658 int Parser_setNodePrefixAndLocalName(
2659 	/*! [in,out] The Node to process. */
2660 	IXML_Node *node)
2661 {
2662     char *pStrPrefix = NULL;
2663     char *pLocalName;
2664     ptrdiff_t nPrefix;
2665 
2666     assert( node != NULL );
2667     if( node == NULL ) {
2668         return IXML_FAILED;
2669     }
2670 
2671     pStrPrefix = strchr( node->nodeName, ':' );
2672     if( pStrPrefix == NULL ) {
2673         node->prefix = NULL;
2674         node->localName = safe_strdup( node->nodeName );
2675         if( node->localName == NULL ) {
2676             return IXML_INSUFFICIENT_MEMORY;
2677         }
2678 
2679     } else {
2680         /* fill in the local name and prefix */
2681         pLocalName = ( char * )pStrPrefix + 1;
2682         nPrefix = pStrPrefix - node->nodeName;
2683         node->prefix = malloc((size_t)nPrefix + (size_t)1);
2684         if (!node->prefix) {
2685             return IXML_INSUFFICIENT_MEMORY;
2686         }
2687 
2688         memset(node->prefix, 0, (size_t)nPrefix + (size_t)1);
2689         strncpy(node->prefix, node->nodeName, (size_t)nPrefix);
2690 
2691         node->localName = safe_strdup( pLocalName );
2692         if( node->localName == NULL ) {
2693             free( node->prefix );
2694 	    /* no need to free really, main loop will frees it
2695 	     * when return code is not success */
2696             node->prefix = NULL;
2697             return IXML_INSUFFICIENT_MEMORY;
2698         }
2699     }
2700 
2701     return IXML_SUCCESS;
2702 }
2703 
2704