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