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