Annotation of XML/parser.c, revision 1.76
1.1 veillard 1: /*
1.3 veillard 2: * parser.c : an XML 1.0 non-verifying parser
1.15 veillard 3: *
4: * See Copyright for the status of this software.
5: *
1.60 daniel 6: * Daniel.Veillard@w3.org
1.1 veillard 7: */
8:
1.26 daniel 9: #ifdef WIN32
10: #define HAVE_FCNTL_H
11: #include <io.h>
12: #else
1.9 httpng 13: #include <config.h>
1.26 daniel 14: #endif
1.1 veillard 15: #include <stdio.h>
16: #include <ctype.h>
1.14 veillard 17: #include <string.h> /* for memset() only */
1.50 daniel 18: #include <stdlib.h>
1.9 httpng 19: #include <sys/stat.h>
20: #ifdef HAVE_FCNTL_H
21: #include <fcntl.h>
22: #endif
1.10 httpng 23: #ifdef HAVE_UNISTD_H
24: #include <unistd.h>
25: #endif
1.20 daniel 26: #ifdef HAVE_ZLIB_H
27: #include <zlib.h>
28: #endif
1.1 veillard 29:
1.14 veillard 30: #include "tree.h"
1.1 veillard 31: #include "parser.h"
1.14 veillard 32: #include "entities.h"
1.75 daniel 33: #include "encoding.h"
1.61 daniel 34: #include "valid.h"
1.69 daniel 35: #include "parserInternals.h"
1.1 veillard 36:
1.45 daniel 37: /************************************************************************
38: * *
39: * Parser stacks related functions and macros *
40: * *
41: ************************************************************************/
1.1 veillard 42: /*
1.40 daniel 43: * Generic function for accessing stacks in the Parser Context
1.1 veillard 44: */
45:
1.31 daniel 46: #define PUSH_AND_POP(type, name) \
1.72 daniel 47: extern int name##Push(xmlParserCtxtPtr ctxt, type value) { \
1.31 daniel 48: if (ctxt->name##Nr >= ctxt->name##Max) { \
49: ctxt->name##Max *= 2; \
1.40 daniel 50: ctxt->name##Tab = (void *) realloc(ctxt->name##Tab, \
51: ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
52: if (ctxt->name##Tab == NULL) { \
1.31 daniel 53: fprintf(stderr, "realloc failed !\n"); \
54: exit(1); \
55: } \
56: } \
1.40 daniel 57: ctxt->name##Tab[ctxt->name##Nr] = value; \
58: ctxt->name = value; \
59: return(ctxt->name##Nr++); \
1.31 daniel 60: } \
1.72 daniel 61: extern type name##Pop(xmlParserCtxtPtr ctxt) { \
1.69 daniel 62: type ret; \
1.40 daniel 63: if (ctxt->name##Nr <= 0) return(0); \
64: ctxt->name##Nr--; \
1.50 daniel 65: if (ctxt->name##Nr > 0) \
66: ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
67: else \
68: ctxt->name = NULL; \
1.69 daniel 69: ret = ctxt->name##Tab[ctxt->name##Nr]; \
70: ctxt->name##Tab[ctxt->name##Nr] = 0; \
71: return(ret); \
1.31 daniel 72: } \
73:
1.40 daniel 74: PUSH_AND_POP(xmlParserInputPtr, input)
1.41 daniel 75: PUSH_AND_POP(xmlNodePtr, node)
1.40 daniel 76:
1.55 daniel 77: /*
78: * Macros for accessing the content. Those should be used only by the parser,
79: * and not exported.
80: *
81: * Dirty macros, i.e. one need to make assumption on the context to use them
82: *
83: * CUR_PTR return the current pointer to the CHAR to be parsed.
84: * CUR returns the current CHAR value, i.e. a 8 bit value if compiled
85: * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
86: * in UNICODE mode. This should be used internally by the parser
87: * only to compare to ASCII values otherwise it would break when
88: * running with UTF-8 encoding.
89: * NXT(n) returns the n'th next CHAR. Same as CUR is should be used only
90: * to compare on ASCII based substring.
91: * SKIP(n) Skip n CHAR, and must also be used only to skip ASCII defined
92: * strings within the parser.
93: *
94: * Clean macros, not dependent of an ASCII context.
95: *
96: * CURRENT Returns the current char value, with the full decoding of
97: * UTF-8 if we are using this mode. It returns an int.
98: * NEXT Skip to the next character, this does the proper decoding
99: * in UTF-8 mode. It also pop-up unfinished entities on the fly.
100: * It returns the pointer to the current CHAR.
101: */
1.45 daniel 102:
103: #define CUR (*ctxt->input->cur)
1.55 daniel 104: #define SKIP(val) ctxt->input->cur += (val)
105: #define NXT(val) ctxt->input->cur[(val)]
106: #define CUR_PTR ctxt->input->cur
107:
108: #define SKIP_BLANKS \
109: while (IS_BLANK(*(ctxt->input->cur))) NEXT
110:
111: #ifndef USE_UTF_8
112: #define CURRENT (*ctxt->input->cur)
1.45 daniel 113: #define NEXT ((*ctxt->input->cur) ? \
114: (((*(ctxt->input->cur) == '\n') ? \
115: (ctxt->input->line++, ctxt->input->col = 1) : \
116: (ctxt->input->col++)), ctxt->input->cur++) : \
117: (xmlPopInput(ctxt), ctxt->input->cur))
1.55 daniel 118: #else
119: #endif
1.42 daniel 120:
1.40 daniel 121:
1.50 daniel 122: /**
123: * xmlPopInput:
124: * @ctxt: an XML parser context
125: *
1.40 daniel 126: * xmlPopInput: the current input pointed by ctxt->input came to an end
127: * pop it and return the next char.
1.45 daniel 128: *
129: * TODO A deallocation of the popped Input structure is needed
1.68 daniel 130: *
131: * Returns the current CHAR in the parser context
1.40 daniel 132: */
1.55 daniel 133: CHAR
134: xmlPopInput(xmlParserCtxtPtr ctxt) {
1.40 daniel 135: if (ctxt->inputNr == 1) return(0); /* End of main Input */
1.69 daniel 136: xmlFreeInputStream(inputPop(ctxt));
1.40 daniel 137: return(CUR);
138: }
139:
1.50 daniel 140: /**
141: * xmlPushInput:
142: * @ctxt: an XML parser context
143: * @input: an XML parser input fragment (entity, XML fragment ...).
144: *
1.40 daniel 145: * xmlPushInput: switch to a new input stream which is stacked on top
146: * of the previous one(s).
147: */
1.55 daniel 148: void
149: xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
1.40 daniel 150: if (input == NULL) return;
151: inputPush(ctxt, input);
152: }
153:
1.50 daniel 154: /**
1.69 daniel 155: * xmlFreeInputStream:
156: * @input: an xmlParserInputPtr
157: *
158: * Free up an input stream.
159: */
160: void
161: xmlFreeInputStream(xmlParserInputPtr input) {
162: if (input == NULL) return;
163:
164: if (input->filename != NULL) free((char *) input->filename);
165: if ((input->free != NULL) && (input->base != NULL))
166: input->free((char *) input->base);
167: memset(input, -1, sizeof(xmlParserInput));
168: free(input);
169: }
170:
171: /**
1.50 daniel 172: * xmlNewEntityInputStream:
173: * @ctxt: an XML parser context
174: * @entity: an Entity pointer
175: *
1.45 daniel 176: * Create a new input stream based on a memory buffer.
1.68 daniel 177: * Returns the new input stream
1.45 daniel 178: */
1.50 daniel 179: xmlParserInputPtr
180: xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
1.45 daniel 181: xmlParserInputPtr input;
182:
183: if (entity == NULL) {
1.55 daniel 184: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 185: ctxt->sax->error(ctxt->userData,
1.45 daniel 186: "internal: xmlNewEntityInputStream entity = NULL\n");
1.50 daniel 187: return(NULL);
1.45 daniel 188: }
189: if (entity->content == NULL) {
1.55 daniel 190: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 191: ctxt->sax->error(ctxt->userData,
1.45 daniel 192: "internal: xmlNewEntityInputStream entity->input = NULL\n");
1.50 daniel 193: return(NULL);
1.45 daniel 194: }
195: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
196: if (input == NULL) {
1.55 daniel 197: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 198: ctxt->sax->error(ctxt->userData, "malloc: couldn't allocate a new input stream\n");
1.50 daniel 199: return(NULL);
1.45 daniel 200: }
201: input->filename = entity->SystemID; /* TODO !!! char <- CHAR */
202: input->base = entity->content;
203: input->cur = entity->content;
204: input->line = 1;
205: input->col = 1;
1.69 daniel 206: input->free = NULL;
1.50 daniel 207: return(input);
1.45 daniel 208: }
209:
1.59 daniel 210: /**
211: * xmlNewStringInputStream:
212: * @ctxt: an XML parser context
213: * @entity: an Entity pointer
214: *
215: * Create a new input stream based on a memory buffer.
1.68 daniel 216: * Returns the new input stream
1.59 daniel 217: */
218: xmlParserInputPtr
219: xmlNewStringInputStream(xmlParserCtxtPtr ctxt, CHAR *string) {
220: xmlParserInputPtr input;
221:
222: if (string == NULL) {
223: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 224: ctxt->sax->error(ctxt->userData,
1.59 daniel 225: "internal: xmlNewStringInputStream string = NULL\n");
226: return(NULL);
227: }
228: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
229: if (input == NULL) {
230: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 231: ctxt->sax->error(ctxt->userData, "malloc: couldn't allocate a new input stream\n");
1.59 daniel 232: return(NULL);
233: }
234: input->filename = NULL;
235: input->base = string;
236: input->cur = string;
237: input->line = 1;
238: input->col = 1;
1.69 daniel 239: input->free = NULL;
1.59 daniel 240: return(input);
241: }
242:
1.76 ! daniel 243: /**
! 244: * xmlNewInputFromFile:
! 245: * @ctxt: an XML parser context
! 246: * @filename: the filename to use as entity
! 247: *
! 248: * Create a new input stream based on a file.
! 249: *
! 250: * Returns the new input stream or NULL in case of error
! 251: */
! 252: xmlParserInputPtr
! 253: xmlNewInputFromFile(xmlParserCtxtPtr ctxt, char *filename) {
! 254: #ifdef HAVE_ZLIB_H
! 255: gzFile input;
! 256: #else
! 257: int input;
! 258: #endif
! 259: int res;
! 260: int len;
! 261: struct stat buf;
! 262: char *buffer;
! 263: xmlParserInputPtr inputStream;
! 264: xmlCharEncoding enc;
! 265:
! 266: res = stat(filename, &buf);
! 267: if (res < 0) return(NULL);
! 268:
! 269: #ifdef HAVE_ZLIB_H
! 270: len = (buf.st_size * 8) + 1000;
! 271: retry_bigger:
! 272: buffer = malloc(len);
! 273: #else
! 274: len = buf.st_size + 100;
! 275: buffer = malloc(len);
! 276: #endif
! 277: if (buffer == NULL) {
! 278: perror("malloc");
! 279: return(NULL);
! 280: }
! 281:
! 282: memset(buffer, 0, len);
! 283: #ifdef HAVE_ZLIB_H
! 284: input = gzopen (filename, "r");
! 285: if (input == NULL) {
! 286: fprintf (stderr, "Cannot read file %s :\n", filename);
! 287: perror ("gzopen failed");
! 288: return(NULL);
! 289: }
! 290: #else
! 291: #ifdef WIN32
! 292: input = _open (filename, O_RDONLY | _O_BINARY);
! 293: #else
! 294: input = open (filename, O_RDONLY);
! 295: #endif
! 296: if (input < 0) {
! 297: fprintf (stderr, "Cannot read file %s :\n", filename);
! 298: perror ("open failed");
! 299: return(NULL);
! 300: }
! 301: #endif
! 302: #ifdef HAVE_ZLIB_H
! 303: res = gzread(input, buffer, len);
! 304: #else
! 305: res = read(input, buffer, buf.st_size);
! 306: #endif
! 307: if (res < 0) {
! 308: fprintf (stderr, "Cannot read file %s :\n", filename);
! 309: #ifdef HAVE_ZLIB_H
! 310: perror ("gzread failed");
! 311: #else
! 312: perror ("read failed");
! 313: #endif
! 314: return(NULL);
! 315: }
! 316: #ifdef HAVE_ZLIB_H
! 317: gzclose(input);
! 318: if (res >= len) {
! 319: free(buffer);
! 320: len *= 2;
! 321: goto retry_bigger;
! 322: }
! 323: buf.st_size = res;
! 324: #else
! 325: close(input);
! 326: #endif
! 327:
! 328: buffer[buf.st_size] = '\0';
! 329:
! 330: inputStream = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
! 331: if (inputStream == NULL) {
! 332: perror("malloc");
! 333: free(ctxt);
! 334: return(NULL);
! 335: }
! 336:
! 337: inputStream->filename = strdup(filename);
! 338: inputStream->line = 1;
! 339: inputStream->col = 1;
! 340:
! 341: /*
! 342: * plug some encoding conversion routines here. !!!
! 343: enc = xmlDetectCharEncoding(buffer);
! 344: xmlSwitchEncoding(ctxt, enc);
! 345: */
! 346:
! 347: inputStream->base = buffer;
! 348: inputStream->cur = buffer;
! 349: inputStream->free = (xmlParserInputDeallocate) free;
! 350:
! 351: return(inputStream);
! 352: }
! 353:
1.1 veillard 354:
1.28 daniel 355: /************************************************************************
356: * *
1.75 daniel 357: * Commodity functions to handle encodings *
358: * *
359: ************************************************************************/
360:
361: /**
362: * xmlSwitchEncoding:
363: * @ctxt: the parser context
364: * @len: the len of @cur
365: *
366: * change the input functions when discovering the character encoding
367: * of a given entity.
368: *
369: */
370: void
371: xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
372: {
373: switch (enc) {
374: case XML_CHAR_ENCODING_ERROR:
375: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
376: ctxt->sax->error(ctxt->userData, "encoding unknown\n");
377: ctxt->wellFormed = 0;
378: break;
379: case XML_CHAR_ENCODING_NONE:
380: /* let's assume it's UTF-8 without the XML decl */
381: return;
382: case XML_CHAR_ENCODING_UTF8:
383: /* default encoding, no conversion should be needed */
384: return;
385: case XML_CHAR_ENCODING_UTF16LE:
386: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
387: ctxt->sax->error(ctxt->userData,
388: "char encoding UTF16 little endian not supported\n");
389: break;
390: case XML_CHAR_ENCODING_UTF16BE:
391: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
392: ctxt->sax->error(ctxt->userData,
393: "char encoding UTF16 big endian not supported\n");
394: break;
395: case XML_CHAR_ENCODING_UCS4LE:
396: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
397: ctxt->sax->error(ctxt->userData,
398: "char encoding USC4 little endian not supported\n");
399: break;
400: case XML_CHAR_ENCODING_UCS4BE:
401: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
402: ctxt->sax->error(ctxt->userData,
403: "char encoding USC4 big endian not supported\n");
404: break;
405: case XML_CHAR_ENCODING_EBCDIC:
406: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
407: ctxt->sax->error(ctxt->userData,
408: "char encoding EBCDIC not supported\n");
409: break;
410: case XML_CHAR_ENCODING_UCS4_2143:
411: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
412: ctxt->sax->error(ctxt->userData,
413: "char encoding UCS4 2143 not supported\n");
414: break;
415: case XML_CHAR_ENCODING_UCS4_3412:
416: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
417: ctxt->sax->error(ctxt->userData,
418: "char encoding UCS4 3412 not supported\n");
419: break;
420: case XML_CHAR_ENCODING_UCS2:
421: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
422: ctxt->sax->error(ctxt->userData,
423: "char encoding UCS2 not supported\n");
424: break;
425: case XML_CHAR_ENCODING_8859_1:
426: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
427: ctxt->sax->error(ctxt->userData,
428: "char encoding ISO_8859_1 ISO Latin 1 not supported\n");
429: break;
430: case XML_CHAR_ENCODING_8859_2:
431: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
432: ctxt->sax->error(ctxt->userData,
433: "char encoding ISO_8859_2 ISO Latin 2 not supported\n");
434: break;
435: case XML_CHAR_ENCODING_8859_3:
436: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
437: ctxt->sax->error(ctxt->userData,
438: "char encoding ISO_8859_3 not supported\n");
439: break;
440: case XML_CHAR_ENCODING_8859_4:
441: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
442: ctxt->sax->error(ctxt->userData,
443: "char encoding ISO_8859_4 not supported\n");
444: break;
445: case XML_CHAR_ENCODING_8859_5:
446: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
447: ctxt->sax->error(ctxt->userData,
448: "char encoding ISO_8859_5 not supported\n");
449: break;
450: case XML_CHAR_ENCODING_8859_6:
451: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
452: ctxt->sax->error(ctxt->userData,
453: "char encoding ISO_8859_6 not supported\n");
454: break;
455: case XML_CHAR_ENCODING_8859_7:
456: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
457: ctxt->sax->error(ctxt->userData,
458: "char encoding ISO_8859_7 not supported\n");
459: break;
460: case XML_CHAR_ENCODING_8859_8:
461: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
462: ctxt->sax->error(ctxt->userData,
463: "char encoding ISO_8859_8 not supported\n");
464: break;
465: case XML_CHAR_ENCODING_8859_9:
466: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
467: ctxt->sax->error(ctxt->userData,
468: "char encoding ISO_8859_9 not supported\n");
469: break;
470: case XML_CHAR_ENCODING_2022_JP:
471: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
472: ctxt->sax->error(ctxt->userData,
473: "char encoding ISO-2022-JPnot supported\n");
474: break;
475: case XML_CHAR_ENCODING_SHIFT_JIS:
476: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
477: ctxt->sax->error(ctxt->userData,
478: "char encoding Shift_JISnot supported\n");
479: break;
480: case XML_CHAR_ENCODING_EUC_JP:
481: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
482: ctxt->sax->error(ctxt->userData,
483: "char encoding EUC-JPnot supported\n");
484: break;
485: }
486: }
487:
488: /************************************************************************
489: * *
1.28 daniel 490: * Commodity functions to handle CHARs *
491: * *
492: ************************************************************************/
493:
1.50 daniel 494: /**
495: * xmlStrndup:
496: * @cur: the input CHAR *
497: * @len: the len of @cur
498: *
499: * a strndup for array of CHAR's
1.68 daniel 500: *
501: * Returns a new CHAR * or NULL
1.1 veillard 502: */
1.55 daniel 503: CHAR *
504: xmlStrndup(const CHAR *cur, int len) {
1.1 veillard 505: CHAR *ret = malloc((len + 1) * sizeof(CHAR));
506:
507: if (ret == NULL) {
508: fprintf(stderr, "malloc of %d byte failed\n",
509: (len + 1) * sizeof(CHAR));
510: return(NULL);
511: }
512: memcpy(ret, cur, len * sizeof(CHAR));
513: ret[len] = 0;
514: return(ret);
515: }
516:
1.50 daniel 517: /**
518: * xmlStrdup:
519: * @cur: the input CHAR *
520: *
521: * a strdup for array of CHAR's
1.68 daniel 522: *
523: * Returns a new CHAR * or NULL
1.1 veillard 524: */
1.55 daniel 525: CHAR *
526: xmlStrdup(const CHAR *cur) {
1.6 httpng 527: const CHAR *p = cur;
1.1 veillard 528:
529: while (IS_CHAR(*p)) p++;
530: return(xmlStrndup(cur, p - cur));
531: }
532:
1.50 daniel 533: /**
534: * xmlCharStrndup:
535: * @cur: the input char *
536: * @len: the len of @cur
537: *
538: * a strndup for char's to CHAR's
1.68 daniel 539: *
540: * Returns a new CHAR * or NULL
1.45 daniel 541: */
542:
1.55 daniel 543: CHAR *
544: xmlCharStrndup(const char *cur, int len) {
1.45 daniel 545: int i;
546: CHAR *ret = malloc((len + 1) * sizeof(CHAR));
547:
548: if (ret == NULL) {
549: fprintf(stderr, "malloc of %d byte failed\n",
550: (len + 1) * sizeof(CHAR));
551: return(NULL);
552: }
553: for (i = 0;i < len;i++)
554: ret[i] = (CHAR) cur[i];
555: ret[len] = 0;
556: return(ret);
557: }
558:
1.50 daniel 559: /**
560: * xmlCharStrdup:
561: * @cur: the input char *
562: * @len: the len of @cur
563: *
564: * a strdup for char's to CHAR's
1.68 daniel 565: *
566: * Returns a new CHAR * or NULL
1.45 daniel 567: */
568:
1.55 daniel 569: CHAR *
570: xmlCharStrdup(const char *cur) {
1.45 daniel 571: const char *p = cur;
572:
573: while (*p != '\0') p++;
574: return(xmlCharStrndup(cur, p - cur));
575: }
576:
1.50 daniel 577: /**
578: * xmlStrcmp:
579: * @str1: the first CHAR *
580: * @str2: the second CHAR *
581: *
582: * a strcmp for CHAR's
1.68 daniel 583: *
584: * Returns the integer result of the comparison
1.14 veillard 585: */
586:
1.55 daniel 587: int
588: xmlStrcmp(const CHAR *str1, const CHAR *str2) {
1.14 veillard 589: register int tmp;
590:
591: do {
592: tmp = *str1++ - *str2++;
593: if (tmp != 0) return(tmp);
594: } while ((*str1 != 0) && (*str2 != 0));
595: return (*str1 - *str2);
596: }
597:
1.50 daniel 598: /**
599: * xmlStrncmp:
600: * @str1: the first CHAR *
601: * @str2: the second CHAR *
602: * @len: the max comparison length
603: *
604: * a strncmp for CHAR's
1.68 daniel 605: *
606: * Returns the integer result of the comparison
1.14 veillard 607: */
608:
1.55 daniel 609: int
610: xmlStrncmp(const CHAR *str1, const CHAR *str2, int len) {
1.14 veillard 611: register int tmp;
612:
613: if (len <= 0) return(0);
614: do {
615: tmp = *str1++ - *str2++;
616: if (tmp != 0) return(tmp);
617: len--;
618: if (len <= 0) return(0);
619: } while ((*str1 != 0) && (*str2 != 0));
620: return (*str1 - *str2);
621: }
622:
1.50 daniel 623: /**
624: * xmlStrchr:
625: * @str: the CHAR * array
626: * @val: the CHAR to search
627: *
628: * a strchr for CHAR's
1.68 daniel 629: *
630: * Returns the CHAR * for the first occurence or NULL.
1.14 veillard 631: */
632:
1.55 daniel 633: CHAR *
634: xmlStrchr(const CHAR *str, CHAR val) {
1.14 veillard 635: while (*str != 0) {
636: if (*str == val) return((CHAR *) str);
637: str++;
638: }
639: return(NULL);
640: }
1.28 daniel 641:
1.50 daniel 642: /**
643: * xmlStrlen:
644: * @str: the CHAR * array
645: *
646: * lenght of a CHAR's string
1.68 daniel 647: *
648: * Returns the number of CHAR contained in the ARRAY.
1.45 daniel 649: */
650:
1.55 daniel 651: int
652: xmlStrlen(const CHAR *str) {
1.45 daniel 653: int len = 0;
654:
655: if (str == NULL) return(0);
656: while (*str != 0) {
657: str++;
658: len++;
659: }
660: return(len);
661: }
662:
1.50 daniel 663: /**
664: * xmlStrncat:
1.68 daniel 665: * @cur: the original CHAR * array
1.50 daniel 666: * @add: the CHAR * array added
667: * @len: the length of @add
668: *
669: * a strncat for array of CHAR's
1.68 daniel 670: *
671: * Returns a new CHAR * containing the concatenated string.
1.45 daniel 672: */
673:
1.55 daniel 674: CHAR *
675: xmlStrncat(CHAR *cur, const CHAR *add, int len) {
1.45 daniel 676: int size;
677: CHAR *ret;
678:
679: if ((add == NULL) || (len == 0))
680: return(cur);
681: if (cur == NULL)
682: return(xmlStrndup(add, len));
683:
684: size = xmlStrlen(cur);
685: ret = realloc(cur, (size + len + 1) * sizeof(CHAR));
686: if (ret == NULL) {
687: fprintf(stderr, "xmlStrncat: realloc of %d byte failed\n",
688: (size + len + 1) * sizeof(CHAR));
689: return(cur);
690: }
691: memcpy(&ret[size], add, len * sizeof(CHAR));
692: ret[size + len] = 0;
693: return(ret);
694: }
695:
1.50 daniel 696: /**
697: * xmlStrcat:
1.68 daniel 698: * @cur: the original CHAR * array
1.50 daniel 699: * @add: the CHAR * array added
700: *
701: * a strcat for array of CHAR's
1.68 daniel 702: *
703: * Returns a new CHAR * containing the concatenated string.
1.45 daniel 704: */
1.55 daniel 705: CHAR *
706: xmlStrcat(CHAR *cur, const CHAR *add) {
1.45 daniel 707: const CHAR *p = add;
708:
709: if (add == NULL) return(cur);
710: if (cur == NULL)
711: return(xmlStrdup(add));
712:
713: while (IS_CHAR(*p)) p++;
714: return(xmlStrncat(cur, add, p - add));
715: }
716:
717: /************************************************************************
718: * *
719: * Commodity functions, cleanup needed ? *
720: * *
721: ************************************************************************/
722:
1.50 daniel 723: /**
724: * areBlanks:
725: * @ctxt: an XML parser context
726: * @str: a CHAR *
727: * @len: the size of @str
728: *
1.45 daniel 729: * Is this a sequence of blank chars that one can ignore ?
1.50 daniel 730: *
731: * TODO: to be corrected accodingly to DTD information if available
1.68 daniel 732: *
733: * Returns 1 if ignorable 0 otherwise.
1.45 daniel 734: */
735:
736: static int areBlanks(xmlParserCtxtPtr ctxt, const CHAR *str, int len) {
737: int i;
738: xmlNodePtr lastChild;
739:
740: for (i = 0;i < len;i++)
741: if (!(IS_BLANK(str[i]))) return(0);
742:
743: if (CUR != '<') return(0);
1.72 daniel 744: if (ctxt->node == NULL) return(0);
1.45 daniel 745: lastChild = xmlGetLastChild(ctxt->node);
746: if (lastChild == NULL) {
747: if (ctxt->node->content != NULL) return(0);
748: } else if (xmlNodeIsText(lastChild))
749: return(0);
750: return(1);
751: }
752:
1.50 daniel 753: /**
754: * xmlHandleEntity:
755: * @ctxt: an XML parser context
756: * @entity: an XML entity pointer.
757: *
758: * Default handling of defined entities, when should we define a new input
1.45 daniel 759: * stream ? When do we just handle that as a set of chars ?
1.50 daniel 760: * TODO: we should call the SAX handler here and have it resolve the issue
1.45 daniel 761: */
762:
1.55 daniel 763: void
764: xmlHandleEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
1.45 daniel 765: int len;
1.50 daniel 766: xmlParserInputPtr input;
1.45 daniel 767:
768: if (entity->content == NULL) {
1.55 daniel 769: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 770: ctxt->sax->error(ctxt->userData, "xmlHandleEntity %s: content == NULL\n",
1.45 daniel 771: entity->name);
1.59 daniel 772: ctxt->wellFormed = 0;
1.45 daniel 773: return;
774: }
775: len = xmlStrlen(entity->content);
776: if (len <= 2) goto handle_as_char;
777:
778: /*
779: * Redefine its content as an input stream.
780: */
1.50 daniel 781: input = xmlNewEntityInputStream(ctxt, entity);
782: xmlPushInput(ctxt, input);
1.45 daniel 783: return;
784:
785: handle_as_char:
786: /*
787: * Just handle the content as a set of chars.
788: */
1.72 daniel 789: if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
1.74 daniel 790: ctxt->sax->characters(ctxt->userData, entity->content, len);
1.45 daniel 791:
792: }
793:
794: /*
795: * Forward definition for recusive behaviour.
796: */
1.50 daniel 797: CHAR *xmlParsePEReference(xmlParserCtxtPtr ctxt);
798: CHAR *xmlParseReference(xmlParserCtxtPtr ctxt);
1.45 daniel 799:
1.28 daniel 800: /************************************************************************
801: * *
802: * Extra stuff for namespace support *
803: * Relates to http://www.w3.org/TR/WD-xml-names *
804: * *
805: ************************************************************************/
806:
1.50 daniel 807: /**
808: * xmlNamespaceParseNCName:
809: * @ctxt: an XML parser context
810: *
811: * parse an XML namespace name.
1.28 daniel 812: *
813: * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
814: *
815: * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
816: * CombiningChar | Extender
1.68 daniel 817: *
818: * Returns the namespace name or NULL
1.28 daniel 819: */
820:
1.55 daniel 821: CHAR *
822: xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt) {
1.28 daniel 823: const CHAR *q;
824: CHAR *ret = NULL;
825:
1.40 daniel 826: if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
827: q = NEXT;
1.28 daniel 828:
1.40 daniel 829: while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
830: (CUR == '.') || (CUR == '-') ||
831: (CUR == '_') ||
832: (IS_COMBINING(CUR)) ||
833: (IS_EXTENDER(CUR)))
834: NEXT;
1.28 daniel 835:
1.40 daniel 836: ret = xmlStrndup(q, CUR_PTR - q);
1.28 daniel 837:
838: return(ret);
839: }
840:
1.50 daniel 841: /**
842: * xmlNamespaceParseQName:
843: * @ctxt: an XML parser context
844: * @prefix: a CHAR **
845: *
846: * parse an XML qualified name
1.28 daniel 847: *
848: * [NS 5] QName ::= (Prefix ':')? LocalPart
849: *
850: * [NS 6] Prefix ::= NCName
851: *
852: * [NS 7] LocalPart ::= NCName
1.68 daniel 853: *
854: * Returns the function returns the local part, and prefix is updated
1.50 daniel 855: * to get the Prefix if any.
1.28 daniel 856: */
857:
1.55 daniel 858: CHAR *
859: xmlNamespaceParseQName(xmlParserCtxtPtr ctxt, CHAR **prefix) {
1.28 daniel 860: CHAR *ret = NULL;
861:
862: *prefix = NULL;
863: ret = xmlNamespaceParseNCName(ctxt);
1.40 daniel 864: if (CUR == ':') {
1.28 daniel 865: *prefix = ret;
1.40 daniel 866: NEXT;
1.28 daniel 867: ret = xmlNamespaceParseNCName(ctxt);
868: }
869:
870: return(ret);
871: }
872:
1.50 daniel 873: /**
1.72 daniel 874: * xmlSplitQName:
875: * @name: an XML parser context
876: * @prefix: a CHAR **
877: *
878: * parse an XML qualified name string
879: *
880: * [NS 5] QName ::= (Prefix ':')? LocalPart
881: *
882: * [NS 6] Prefix ::= NCName
883: *
884: * [NS 7] LocalPart ::= NCName
885: *
886: * Returns the function returns the local part, and prefix is updated
887: * to get the Prefix if any.
888: */
889:
890: CHAR *
891: xmlSplitQName(const CHAR *name, CHAR **prefix) {
892: CHAR *ret = NULL;
893: const CHAR *q;
894: const CHAR *cur = name;
895:
896: *prefix = NULL;
897: if (!IS_LETTER(*cur) && (*cur != '_')) return(NULL);
898: q = cur++;
899:
900: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
901: (*cur == '.') || (*cur == '-') ||
902: (*cur == '_') ||
903: (IS_COMBINING(*cur)) ||
904: (IS_EXTENDER(*cur)))
905: cur++;
906:
907: ret = xmlStrndup(q, cur - q);
908:
909: if (*cur == ':') {
910: cur++;
911: if (!IS_LETTER(*cur) && (*cur != '_')) return(ret);
912: *prefix = ret;
913:
914: q = cur++;
915:
916: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
917: (*cur == '.') || (*cur == '-') ||
918: (*cur == '_') ||
919: (IS_COMBINING(*cur)) ||
920: (IS_EXTENDER(*cur)))
921: cur++;
922:
923: ret = xmlStrndup(q, cur - q);
924: }
925:
926: return(ret);
927: }
928: /**
1.50 daniel 929: * xmlNamespaceParseNSDef:
930: * @ctxt: an XML parser context
931: *
932: * parse a namespace prefix declaration
1.28 daniel 933: *
934: * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral
935: *
936: * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)?
1.68 daniel 937: *
938: * Returns the namespace name
1.28 daniel 939: */
940:
1.55 daniel 941: CHAR *
942: xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt) {
1.28 daniel 943: CHAR *name = NULL;
944:
1.40 daniel 945: if ((CUR == 'x') && (NXT(1) == 'm') &&
946: (NXT(2) == 'l') && (NXT(3) == 'n') &&
947: (NXT(4) == 's')) {
948: SKIP(5);
949: if (CUR == ':') {
950: NEXT;
1.28 daniel 951: name = xmlNamespaceParseNCName(ctxt);
952: }
953: }
1.39 daniel 954: return(name);
1.28 daniel 955: }
956:
1.50 daniel 957: /**
958: * xmlParseQuotedString:
959: * @ctxt: an XML parser context
960: *
1.45 daniel 961: * [OLD] Parse and return a string between quotes or doublequotes
1.68 daniel 962: *
963: * Returns the string parser or NULL.
1.45 daniel 964: */
1.55 daniel 965: CHAR *
966: xmlParseQuotedString(xmlParserCtxtPtr ctxt) {
1.45 daniel 967: CHAR *ret = NULL;
968: const CHAR *q;
969:
970: if (CUR == '"') {
971: NEXT;
972: q = CUR_PTR;
973: while (IS_CHAR(CUR) && (CUR != '"')) NEXT;
1.55 daniel 974: if (CUR != '"') {
975: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 976: ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
1.59 daniel 977: ctxt->wellFormed = 0;
1.55 daniel 978: } else {
1.45 daniel 979: ret = xmlStrndup(q, CUR_PTR - q);
980: NEXT;
981: }
982: } else if (CUR == '\''){
983: NEXT;
984: q = CUR_PTR;
985: while (IS_CHAR(CUR) && (CUR != '\'')) NEXT;
1.55 daniel 986: if (CUR != '\'') {
987: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 988: ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
1.59 daniel 989: ctxt->wellFormed = 0;
1.55 daniel 990: } else {
1.45 daniel 991: ret = xmlStrndup(q, CUR_PTR - q);
992: NEXT;
993: }
994: }
995: return(ret);
996: }
997:
1.50 daniel 998: /**
999: * xmlParseNamespace:
1000: * @ctxt: an XML parser context
1001: *
1.45 daniel 1002: * [OLD] xmlParseNamespace: parse specific PI '<?namespace ...' constructs.
1003: *
1004: * This is what the older xml-name Working Draft specified, a bunch of
1005: * other stuff may still rely on it, so support is still here as
1006: * if ot was declared on the root of the Tree:-(
1007: */
1008:
1.55 daniel 1009: void
1010: xmlParseNamespace(xmlParserCtxtPtr ctxt) {
1.45 daniel 1011: CHAR *href = NULL;
1012: CHAR *prefix = NULL;
1013: int garbage = 0;
1014:
1015: /*
1016: * We just skipped "namespace" or "xml:namespace"
1017: */
1018: SKIP_BLANKS;
1019:
1020: while (IS_CHAR(CUR) && (CUR != '>')) {
1021: /*
1022: * We can have "ns" or "prefix" attributes
1023: * Old encoding as 'href' or 'AS' attributes is still supported
1024: */
1025: if ((CUR == 'n') && (NXT(1) == 's')) {
1026: garbage = 0;
1027: SKIP(2);
1028: SKIP_BLANKS;
1029:
1030: if (CUR != '=') continue;
1031: NEXT;
1032: SKIP_BLANKS;
1033:
1034: href = xmlParseQuotedString(ctxt);
1035: SKIP_BLANKS;
1036: } else if ((CUR == 'h') && (NXT(1) == 'r') &&
1037: (NXT(2) == 'e') && (NXT(3) == 'f')) {
1038: garbage = 0;
1039: SKIP(4);
1040: SKIP_BLANKS;
1041:
1042: if (CUR != '=') continue;
1043: NEXT;
1044: SKIP_BLANKS;
1045:
1046: href = xmlParseQuotedString(ctxt);
1047: SKIP_BLANKS;
1048: } else if ((CUR == 'p') && (NXT(1) == 'r') &&
1049: (NXT(2) == 'e') && (NXT(3) == 'f') &&
1050: (NXT(4) == 'i') && (NXT(5) == 'x')) {
1051: garbage = 0;
1052: SKIP(6);
1053: SKIP_BLANKS;
1054:
1055: if (CUR != '=') continue;
1056: NEXT;
1057: SKIP_BLANKS;
1058:
1059: prefix = xmlParseQuotedString(ctxt);
1060: SKIP_BLANKS;
1061: } else if ((CUR == 'A') && (NXT(1) == 'S')) {
1062: garbage = 0;
1063: SKIP(2);
1064: SKIP_BLANKS;
1065:
1066: if (CUR != '=') continue;
1067: NEXT;
1068: SKIP_BLANKS;
1069:
1070: prefix = xmlParseQuotedString(ctxt);
1071: SKIP_BLANKS;
1072: } else if ((CUR == '?') && (NXT(1) == '>')) {
1073: garbage = 0;
1074: CUR_PTR ++;
1075: } else {
1076: /*
1077: * Found garbage when parsing the namespace
1078: */
1079: if (!garbage)
1.55 daniel 1080: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1081: ctxt->sax->error(ctxt->userData, "xmlParseNamespace found garbage\n");
1.59 daniel 1082: ctxt->wellFormed = 0;
1.45 daniel 1083: NEXT;
1084: }
1085: }
1086:
1087: MOVETO_ENDTAG(CUR_PTR);
1088: NEXT;
1089:
1090: /*
1091: * Register the DTD.
1.72 daniel 1092: if (href != NULL)
1093: if ((ctxt->sax != NULL) && (ctxt->sax->globalNamespace != NULL))
1.74 daniel 1094: ctxt->sax->globalNamespace(ctxt->userData, href, prefix);
1.45 daniel 1095: */
1096:
1097: if (prefix != NULL) free(prefix);
1098: if (href != NULL) free(href);
1099: }
1100:
1.28 daniel 1101: /************************************************************************
1102: * *
1103: * The parser itself *
1104: * Relates to http://www.w3.org/TR/REC-xml *
1105: * *
1106: ************************************************************************/
1.14 veillard 1107:
1.50 daniel 1108: /**
1109: * xmlParseName:
1110: * @ctxt: an XML parser context
1111: *
1112: * parse an XML name.
1.22 daniel 1113: *
1114: * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
1115: * CombiningChar | Extender
1116: *
1117: * [5] Name ::= (Letter | '_' | ':') (NameChar)*
1118: *
1119: * [6] Names ::= Name (S Name)*
1.68 daniel 1120: *
1121: * Returns the Name parsed or NULL
1.1 veillard 1122: */
1123:
1.55 daniel 1124: CHAR *
1125: xmlParseName(xmlParserCtxtPtr ctxt) {
1.17 daniel 1126: const CHAR *q;
1127: CHAR *ret = NULL;
1.1 veillard 1128:
1.40 daniel 1129: if (!IS_LETTER(CUR) && (CUR != '_') &&
1130: (CUR != ':')) return(NULL);
1131: q = NEXT;
1132:
1133: while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1134: (CUR == '.') || (CUR == '-') ||
1135: (CUR == '_') || (CUR == ':') ||
1136: (IS_COMBINING(CUR)) ||
1137: (IS_EXTENDER(CUR)))
1138: NEXT;
1.22 daniel 1139:
1.40 daniel 1140: ret = xmlStrndup(q, CUR_PTR - q);
1.22 daniel 1141:
1142: return(ret);
1143: }
1144:
1.50 daniel 1145: /**
1146: * xmlParseNmtoken:
1147: * @ctxt: an XML parser context
1148: *
1149: * parse an XML Nmtoken.
1.22 daniel 1150: *
1151: * [7] Nmtoken ::= (NameChar)+
1152: *
1153: * [8] Nmtokens ::= Nmtoken (S Nmtoken)*
1.68 daniel 1154: *
1155: * Returns the Nmtoken parsed or NULL
1.22 daniel 1156: */
1157:
1.55 daniel 1158: CHAR *
1159: xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
1.22 daniel 1160: const CHAR *q;
1161: CHAR *ret = NULL;
1162:
1.40 daniel 1163: q = NEXT;
1.22 daniel 1164:
1.40 daniel 1165: while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1166: (CUR == '.') || (CUR == '-') ||
1167: (CUR == '_') || (CUR == ':') ||
1168: (IS_COMBINING(CUR)) ||
1169: (IS_EXTENDER(CUR)))
1170: NEXT;
1.3 veillard 1171:
1.40 daniel 1172: ret = xmlStrndup(q, CUR_PTR - q);
1.1 veillard 1173:
1.3 veillard 1174: return(ret);
1.1 veillard 1175: }
1176:
1.50 daniel 1177: /**
1178: * xmlParseEntityValue:
1179: * @ctxt: an XML parser context
1180: *
1181: * parse a value for ENTITY decl.
1.24 daniel 1182: *
1183: * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
1184: * "'" ([^%&'] | PEReference | Reference)* "'"
1.68 daniel 1185: *
1186: * Returns the EntityValue parsed or NULL
1.24 daniel 1187: */
1188:
1.55 daniel 1189: CHAR *
1190: xmlParseEntityValue(xmlParserCtxtPtr ctxt) {
1.46 daniel 1191: CHAR *ret = NULL, *cur;
1.24 daniel 1192: const CHAR *q;
1193:
1.40 daniel 1194: if (CUR == '"') {
1195: NEXT;
1.24 daniel 1196:
1.40 daniel 1197: q = CUR_PTR;
1198: while ((IS_CHAR(CUR)) && (CUR != '"')) {
1199: if (CUR == '%') {
1.46 daniel 1200: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50 daniel 1201: cur = xmlParsePEReference(ctxt);
1.46 daniel 1202: ret = xmlStrcat(ret, cur);
1203: q = CUR_PTR;
1.40 daniel 1204: } else if (CUR == '&') {
1.46 daniel 1205: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50 daniel 1206: cur = xmlParseReference(ctxt);
1207: if (cur != NULL) {
1208: CHAR buf[2];
1209: buf[0] = '&';
1210: buf[1] = 0;
1211: ret = xmlStrncat(ret, buf, 1);
1212: ret = xmlStrcat(ret, cur);
1213: buf[0] = ';';
1214: buf[1] = 0;
1215: ret = xmlStrncat(ret, buf, 1);
1216: }
1.46 daniel 1217: q = CUR_PTR;
1.24 daniel 1218: } else
1.40 daniel 1219: NEXT;
1.24 daniel 1220: }
1.40 daniel 1221: if (!IS_CHAR(CUR)) {
1.55 daniel 1222: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1223: ctxt->sax->error(ctxt->userData, "Unfinished EntityValue\n");
1.59 daniel 1224: ctxt->wellFormed = 0;
1.24 daniel 1225: } else {
1.46 daniel 1226: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.40 daniel 1227: NEXT;
1.24 daniel 1228: }
1.40 daniel 1229: } else if (CUR == '\'') {
1230: NEXT;
1231: q = CUR_PTR;
1232: while ((IS_CHAR(CUR)) && (CUR != '\'')) {
1233: if (CUR == '%') {
1.46 daniel 1234: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50 daniel 1235: cur = xmlParsePEReference(ctxt);
1.46 daniel 1236: ret = xmlStrcat(ret, cur);
1237: q = CUR_PTR;
1.40 daniel 1238: } else if (CUR == '&') {
1.46 daniel 1239: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50 daniel 1240: cur = xmlParseReference(ctxt);
1241: if (cur != NULL) {
1242: CHAR buf[2];
1243: buf[0] = '&';
1244: buf[1] = 0;
1245: ret = xmlStrncat(ret, buf, 1);
1246: ret = xmlStrcat(ret, cur);
1247: buf[0] = ';';
1248: buf[1] = 0;
1249: ret = xmlStrncat(ret, buf, 1);
1250: }
1.46 daniel 1251: q = CUR_PTR;
1.24 daniel 1252: } else
1.40 daniel 1253: NEXT;
1.24 daniel 1254: }
1.40 daniel 1255: if (!IS_CHAR(CUR)) {
1.55 daniel 1256: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1257: ctxt->sax->error(ctxt->userData, "Unfinished EntityValue\n");
1.59 daniel 1258: ctxt->wellFormed = 0;
1.24 daniel 1259: } else {
1.46 daniel 1260: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.40 daniel 1261: NEXT;
1.24 daniel 1262: }
1263: } else {
1.55 daniel 1264: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1265: ctxt->sax->error(ctxt->userData, "xmlParseEntityValue \" or ' expected\n");
1.59 daniel 1266: ctxt->wellFormed = 0;
1.24 daniel 1267: }
1268:
1269: return(ret);
1270: }
1271:
1.50 daniel 1272: /**
1273: * xmlParseAttValue:
1274: * @ctxt: an XML parser context
1275: *
1276: * parse a value for an attribute
1.29 daniel 1277: *
1278: * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
1279: * "'" ([^<&'] | Reference)* "'"
1.68 daniel 1280: *
1281: * Returns the AttValue parsed or NULL.
1.29 daniel 1282: */
1283:
1.55 daniel 1284: CHAR *
1285: xmlParseAttValue(xmlParserCtxtPtr ctxt) {
1.46 daniel 1286: CHAR *ret = NULL, *cur;
1.29 daniel 1287: const CHAR *q;
1288:
1.40 daniel 1289: if (CUR == '"') {
1290: NEXT;
1.29 daniel 1291:
1.40 daniel 1292: q = CUR_PTR;
1293: while ((IS_CHAR(CUR)) && (CUR != '"')) {
1.59 daniel 1294: if (CUR == '<') {
1295: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1296: ctxt->sax->error(ctxt->userData,
1.59 daniel 1297: "Unescaped '<' not allowed in attributes values\n");
1298: ctxt->wellFormed = 0;
1299: }
1.40 daniel 1300: if (CUR == '&') {
1.46 daniel 1301: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50 daniel 1302: cur = xmlParseReference(ctxt);
1303: if (cur != NULL) {
1304: /*
1305: * Special case for '&', we don't want to
1306: * resolve it here since it will break later
1307: * when searching entities in the string.
1308: */
1309: if ((cur[0] == '&') && (cur[1] == 0)) {
1310: CHAR buf[6] = { '&', 'a', 'm', 'p', ';', 0 };
1311: ret = xmlStrncat(ret, buf, 5);
1312: } else
1313: ret = xmlStrcat(ret, cur);
1314: free(cur);
1315: }
1.46 daniel 1316: q = CUR_PTR;
1.29 daniel 1317: } else
1.40 daniel 1318: NEXT;
1.50 daniel 1319: /*
1320: * Pop out finished entity references.
1321: */
1322: while ((CUR == 0) && (ctxt->inputNr > 1)) {
1323: if (CUR_PTR != q)
1324: ret = xmlStrncat(ret, q, CUR_PTR - q);
1325: xmlPopInput(ctxt);
1326: q = CUR_PTR;
1327: }
1.29 daniel 1328: }
1.40 daniel 1329: if (!IS_CHAR(CUR)) {
1.55 daniel 1330: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1331: ctxt->sax->error(ctxt->userData, "Unfinished AttValue\n");
1.59 daniel 1332: ctxt->wellFormed = 0;
1.29 daniel 1333: } else {
1.46 daniel 1334: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.40 daniel 1335: NEXT;
1.29 daniel 1336: }
1.40 daniel 1337: } else if (CUR == '\'') {
1338: NEXT;
1339: q = CUR_PTR;
1340: while ((IS_CHAR(CUR)) && (CUR != '\'')) {
1.59 daniel 1341: if (CUR == '<') {
1342: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1343: ctxt->sax->error(ctxt->userData,
1.59 daniel 1344: "Unescaped '<' not allowed in attributes values\n");
1345: ctxt->wellFormed = 0;
1346: }
1.40 daniel 1347: if (CUR == '&') {
1.46 daniel 1348: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50 daniel 1349: cur = xmlParseReference(ctxt);
1350: if (cur != NULL) {
1351: /*
1352: * Special case for '&', we don't want to
1353: * resolve it here since it will break later
1354: * when searching entities in the string.
1355: */
1356: if ((cur[0] == '&') && (cur[1] == 0)) {
1357: CHAR buf[6] = { '&', 'a', 'm', 'p', ';', 0 };
1358: ret = xmlStrncat(ret, buf, 5);
1359: } else
1360: ret = xmlStrcat(ret, cur);
1361: free(cur);
1362: }
1.46 daniel 1363: q = CUR_PTR;
1.29 daniel 1364: } else
1.40 daniel 1365: NEXT;
1.50 daniel 1366: /*
1367: * Pop out finished entity references.
1368: */
1369: while ((CUR == 0) && (ctxt->inputNr > 1)) {
1370: if (CUR_PTR != q)
1371: ret = xmlStrncat(ret, q, CUR_PTR - q);
1372: xmlPopInput(ctxt);
1373: q = CUR_PTR;
1374: }
1.29 daniel 1375: }
1.40 daniel 1376: if (!IS_CHAR(CUR)) {
1.55 daniel 1377: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1378: ctxt->sax->error(ctxt->userData, "Unfinished AttValue\n");
1.59 daniel 1379: ctxt->wellFormed = 0;
1.29 daniel 1380: } else {
1.46 daniel 1381: ret = xmlStrncat(ret, q, CUR_PTR - q);
1.40 daniel 1382: NEXT;
1.29 daniel 1383: }
1384: } else {
1.55 daniel 1385: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1386: ctxt->sax->error(ctxt->userData, "AttValue: \" or ' expected\n");
1.59 daniel 1387: ctxt->wellFormed = 0;
1.29 daniel 1388: }
1389:
1390: return(ret);
1391: }
1392:
1.50 daniel 1393: /**
1394: * xmlParseSystemLiteral:
1395: * @ctxt: an XML parser context
1396: *
1397: * parse an XML Literal
1.21 daniel 1398: *
1.22 daniel 1399: * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
1.68 daniel 1400: *
1401: * Returns the SystemLiteral parsed or NULL
1.21 daniel 1402: */
1403:
1.55 daniel 1404: CHAR *
1405: xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
1.21 daniel 1406: const CHAR *q;
1407: CHAR *ret = NULL;
1408:
1.40 daniel 1409: if (CUR == '"') {
1410: NEXT;
1411: q = CUR_PTR;
1412: while ((IS_CHAR(CUR)) && (CUR != '"'))
1413: NEXT;
1414: if (!IS_CHAR(CUR)) {
1.55 daniel 1415: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1416: ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
1.59 daniel 1417: ctxt->wellFormed = 0;
1.21 daniel 1418: } else {
1.40 daniel 1419: ret = xmlStrndup(q, CUR_PTR - q);
1420: NEXT;
1.21 daniel 1421: }
1.40 daniel 1422: } else if (CUR == '\'') {
1423: NEXT;
1424: q = CUR_PTR;
1425: while ((IS_CHAR(CUR)) && (CUR != '\''))
1426: NEXT;
1427: if (!IS_CHAR(CUR)) {
1.55 daniel 1428: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1429: ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
1.59 daniel 1430: ctxt->wellFormed = 0;
1.21 daniel 1431: } else {
1.40 daniel 1432: ret = xmlStrndup(q, CUR_PTR - q);
1433: NEXT;
1.21 daniel 1434: }
1435: } else {
1.55 daniel 1436: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1437: ctxt->sax->error(ctxt->userData, "SystemLiteral \" or ' expected\n");
1.59 daniel 1438: ctxt->wellFormed = 0;
1.21 daniel 1439: }
1440:
1441: return(ret);
1442: }
1443:
1.50 daniel 1444: /**
1445: * xmlParsePubidLiteral:
1446: * @ctxt: an XML parser context
1.21 daniel 1447: *
1.50 daniel 1448: * parse an XML public literal
1.68 daniel 1449: *
1450: * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1451: *
1452: * Returns the PubidLiteral parsed or NULL.
1.21 daniel 1453: */
1454:
1.55 daniel 1455: CHAR *
1456: xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
1.21 daniel 1457: const CHAR *q;
1458: CHAR *ret = NULL;
1459: /*
1460: * Name ::= (Letter | '_') (NameChar)*
1461: */
1.40 daniel 1462: if (CUR == '"') {
1463: NEXT;
1464: q = CUR_PTR;
1465: while (IS_PUBIDCHAR(CUR)) NEXT;
1466: if (CUR != '"') {
1.55 daniel 1467: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1468: ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
1.59 daniel 1469: ctxt->wellFormed = 0;
1.21 daniel 1470: } else {
1.40 daniel 1471: ret = xmlStrndup(q, CUR_PTR - q);
1472: NEXT;
1.21 daniel 1473: }
1.40 daniel 1474: } else if (CUR == '\'') {
1475: NEXT;
1476: q = CUR_PTR;
1477: while ((IS_LETTER(CUR)) && (CUR != '\''))
1478: NEXT;
1479: if (!IS_LETTER(CUR)) {
1.55 daniel 1480: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1481: ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
1.59 daniel 1482: ctxt->wellFormed = 0;
1.21 daniel 1483: } else {
1.40 daniel 1484: ret = xmlStrndup(q, CUR_PTR - q);
1485: NEXT;
1.21 daniel 1486: }
1487: } else {
1.55 daniel 1488: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1489: ctxt->sax->error(ctxt->userData, "SystemLiteral \" or ' expected\n");
1.59 daniel 1490: ctxt->wellFormed = 0;
1.21 daniel 1491: }
1492:
1493: return(ret);
1494: }
1495:
1.50 daniel 1496: /**
1497: * xmlParseCharData:
1498: * @ctxt: an XML parser context
1499: * @cdata: int indicating whether we are within a CDATA section
1500: *
1501: * parse a CharData section.
1502: * if we are within a CDATA section ']]>' marks an end of section.
1.27 daniel 1503: *
1504: * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
1505: */
1506:
1.55 daniel 1507: void
1508: xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) {
1.27 daniel 1509: const CHAR *q;
1510:
1.40 daniel 1511: q = CUR_PTR;
1512: while ((IS_CHAR(CUR)) && (CUR != '<') &&
1513: (CUR != '&')) {
1.59 daniel 1514: if ((CUR == ']') && (NXT(1) == ']') &&
1515: (NXT(2) == '>')) {
1516: if (cdata) break;
1517: else {
1518: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1519: ctxt->sax->error(ctxt->userData,
1.59 daniel 1520: "Sequence ']]>' not allowed in content\n");
1521: ctxt->wellFormed = 0;
1522: }
1523: }
1.40 daniel 1524: NEXT;
1.27 daniel 1525: }
1.45 daniel 1526: if (q == CUR_PTR) return;
1527:
1528: /*
1529: * Ok the segment [q CUR_PTR] is to be consumed as chars.
1530: */
1531: if (ctxt->sax != NULL) {
1.72 daniel 1532: if (areBlanks(ctxt, q, CUR_PTR - q)) {
1533: if (ctxt->sax->ignorableWhitespace != NULL)
1.74 daniel 1534: ctxt->sax->ignorableWhitespace(ctxt->userData, q, CUR_PTR - q);
1.72 daniel 1535: } else {
1536: if (ctxt->sax->characters != NULL)
1.74 daniel 1537: ctxt->sax->characters(ctxt->userData, q, CUR_PTR - q);
1.72 daniel 1538: }
1.45 daniel 1539: }
1.27 daniel 1540: }
1541:
1.50 daniel 1542: /**
1543: * xmlParseExternalID:
1544: * @ctxt: an XML parser context
1545: * @publicID: a CHAR** receiving PubidLiteral
1.67 daniel 1546: * @strict: indicate whether we should restrict parsing to only
1547: * production [75], see NOTE below
1.50 daniel 1548: *
1.67 daniel 1549: * Parse an External ID or a Public ID
1550: *
1551: * NOTE: Productions [75] and [83] interract badly since [75] can generate
1552: * 'PUBLIC' S PubidLiteral S SystemLiteral
1.22 daniel 1553: *
1554: * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
1555: * | 'PUBLIC' S PubidLiteral S SystemLiteral
1.67 daniel 1556: *
1557: * [83] PublicID ::= 'PUBLIC' S PubidLiteral
1558: *
1.68 daniel 1559: * Returns the function returns SystemLiteral and in the second
1.67 daniel 1560: * case publicID receives PubidLiteral, is strict is off
1561: * it is possible to return NULL and have publicID set.
1.22 daniel 1562: */
1563:
1.55 daniel 1564: CHAR *
1.67 daniel 1565: xmlParseExternalID(xmlParserCtxtPtr ctxt, CHAR **publicID, int strict) {
1.39 daniel 1566: CHAR *URI = NULL;
1.22 daniel 1567:
1.40 daniel 1568: if ((CUR == 'S') && (NXT(1) == 'Y') &&
1569: (NXT(2) == 'S') && (NXT(3) == 'T') &&
1570: (NXT(4) == 'E') && (NXT(5) == 'M')) {
1571: SKIP(6);
1.59 daniel 1572: if (!IS_BLANK(CUR)) {
1573: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1574: ctxt->sax->error(ctxt->userData,
1.59 daniel 1575: "Space required after 'SYSTEM'\n");
1576: ctxt->wellFormed = 0;
1577: }
1.42 daniel 1578: SKIP_BLANKS;
1.39 daniel 1579: URI = xmlParseSystemLiteral(ctxt);
1.59 daniel 1580: if (URI == NULL) {
1.55 daniel 1581: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1582: ctxt->sax->error(ctxt->userData,
1.39 daniel 1583: "xmlParseExternalID: SYSTEM, no URI\n");
1.59 daniel 1584: ctxt->wellFormed = 0;
1585: }
1.40 daniel 1586: } else if ((CUR == 'P') && (NXT(1) == 'U') &&
1587: (NXT(2) == 'B') && (NXT(3) == 'L') &&
1588: (NXT(4) == 'I') && (NXT(5) == 'C')) {
1589: SKIP(6);
1.59 daniel 1590: if (!IS_BLANK(CUR)) {
1591: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1592: ctxt->sax->error(ctxt->userData,
1.59 daniel 1593: "Space required after 'PUBLIC'\n");
1594: ctxt->wellFormed = 0;
1595: }
1.42 daniel 1596: SKIP_BLANKS;
1.39 daniel 1597: *publicID = xmlParsePubidLiteral(ctxt);
1.59 daniel 1598: if (*publicID == NULL) {
1.55 daniel 1599: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1600: ctxt->sax->error(ctxt->userData,
1.39 daniel 1601: "xmlParseExternalID: PUBLIC, no Public Identifier\n");
1.59 daniel 1602: ctxt->wellFormed = 0;
1603: }
1.67 daniel 1604: if (strict) {
1605: /*
1606: * We don't handle [83] so "S SystemLiteral" is required.
1607: */
1608: if (!IS_BLANK(CUR)) {
1609: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1610: ctxt->sax->error(ctxt->userData,
1.67 daniel 1611: "Space required after the Public Identifier\n");
1612: ctxt->wellFormed = 0;
1613: }
1614: } else {
1615: /*
1616: * We handle [83] so we return immediately, if
1617: * "S SystemLiteral" is not detected. From a purely parsing
1618: * point of view that's a nice mess.
1619: */
1620: const CHAR *ptr = CUR_PTR;
1621: if (!IS_BLANK(*ptr)) return(NULL);
1622:
1623: while (IS_BLANK(*ptr)) ptr++;
1624: if ((*ptr != '\'') || (*ptr != '"')) return(NULL);
1.59 daniel 1625: }
1.42 daniel 1626: SKIP_BLANKS;
1.39 daniel 1627: URI = xmlParseSystemLiteral(ctxt);
1.59 daniel 1628: if (URI == NULL) {
1.55 daniel 1629: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1630: ctxt->sax->error(ctxt->userData,
1.39 daniel 1631: "xmlParseExternalID: PUBLIC, no URI\n");
1.59 daniel 1632: ctxt->wellFormed = 0;
1633: }
1.22 daniel 1634: }
1.39 daniel 1635: return(URI);
1.22 daniel 1636: }
1637:
1.50 daniel 1638: /**
1639: * xmlParseComment:
1.69 daniel 1640: * @ctxt: an XML parser context
1641: * @create: should we create a node, or just skip the content
1.50 daniel 1642: *
1.3 veillard 1643: * Skip an XML (SGML) comment <!-- .... -->
1.31 daniel 1644: * This may or may not create a node (depending on the context)
1.38 daniel 1645: * The spec says that "For compatibility, the string "--" (double-hyphen)
1646: * must not occur within comments. "
1.22 daniel 1647: *
1648: * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
1.3 veillard 1649: */
1.72 daniel 1650: void
1.69 daniel 1651: xmlParseComment(xmlParserCtxtPtr ctxt, int create) {
1.17 daniel 1652: const CHAR *q, *start;
1653: const CHAR *r;
1.39 daniel 1654: CHAR *val;
1.3 veillard 1655:
1656: /*
1.22 daniel 1657: * Check that there is a comment right here.
1.3 veillard 1658: */
1.40 daniel 1659: if ((CUR != '<') || (NXT(1) != '!') ||
1.72 daniel 1660: (NXT(2) != '-') || (NXT(3) != '-')) return;
1.3 veillard 1661:
1.40 daniel 1662: SKIP(4);
1663: start = q = CUR_PTR;
1664: NEXT;
1665: r = CUR_PTR;
1666: NEXT;
1667: while (IS_CHAR(CUR) &&
1668: ((CUR == ':') || (CUR != '>') ||
1.16 daniel 1669: (*r != '-') || (*q != '-'))) {
1.59 daniel 1670: if ((*r == '-') && (*q == '-')) {
1.55 daniel 1671: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1672: ctxt->sax->error(ctxt->userData,
1.38 daniel 1673: "Comment must not contain '--' (double-hyphen)`\n");
1.59 daniel 1674: ctxt->wellFormed = 0;
1675: }
1.40 daniel 1676: NEXT;r++;q++;
1.3 veillard 1677: }
1.40 daniel 1678: if (!IS_CHAR(CUR)) {
1.55 daniel 1679: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1680: ctxt->sax->error(ctxt->userData, "Comment not terminated \n<!--%.50s\n", start);
1.59 daniel 1681: ctxt->wellFormed = 0;
1.3 veillard 1682: } else {
1.40 daniel 1683: NEXT;
1.31 daniel 1684: if (create) {
1.39 daniel 1685: val = xmlStrndup(start, q - start);
1.72 daniel 1686: if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL))
1.74 daniel 1687: ctxt->sax->comment(ctxt->userData, val);
1.39 daniel 1688: free(val);
1.31 daniel 1689: }
1.3 veillard 1690: }
1691: }
1692:
1.50 daniel 1693: /**
1694: * xmlParsePITarget:
1695: * @ctxt: an XML parser context
1696: *
1697: * parse the name of a PI
1.22 daniel 1698: *
1699: * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
1.68 daniel 1700: *
1701: * Returns the PITarget name or NULL
1.22 daniel 1702: */
1703:
1.55 daniel 1704: CHAR *
1705: xmlParsePITarget(xmlParserCtxtPtr ctxt) {
1.22 daniel 1706: CHAR *name;
1707:
1708: name = xmlParseName(ctxt);
1709: if ((name != NULL) && (name[3] == 0) &&
1710: ((name[0] == 'x') || (name[0] == 'X')) &&
1.31 daniel 1711: ((name[1] == 'm') || (name[1] == 'M')) &&
1712: ((name[2] == 'l') || (name[2] == 'L'))) {
1.55 daniel 1713: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1714: ctxt->sax->error(ctxt->userData, "xmlParsePItarget: invalid name prefix 'xml'\n");
1.22 daniel 1715: return(NULL);
1716: }
1717: return(name);
1718: }
1719:
1.50 daniel 1720: /**
1721: * xmlParsePI:
1722: * @ctxt: an XML parser context
1723: *
1724: * parse an XML Processing Instruction.
1.22 daniel 1725: *
1726: * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
1.68 daniel 1727: *
1.69 daniel 1728: * The processing is transfered to SAX once parsed.
1.3 veillard 1729: */
1730:
1.55 daniel 1731: void
1732: xmlParsePI(xmlParserCtxtPtr ctxt) {
1.22 daniel 1733: CHAR *target;
1734:
1.40 daniel 1735: if ((CUR == '<') && (NXT(1) == '?')) {
1.3 veillard 1736: /*
1737: * this is a Processing Instruction.
1738: */
1.40 daniel 1739: SKIP(2);
1.3 veillard 1740:
1741: /*
1.22 daniel 1742: * Parse the target name and check for special support like
1743: * namespace.
1744: *
1745: * TODO : PI handling should be dynamically redefinable using an
1746: * API. Only namespace should be in the code IMHO ...
1.3 veillard 1747: */
1.22 daniel 1748: target = xmlParsePITarget(ctxt);
1749: if (target != NULL) {
1.72 daniel 1750: const CHAR *q = CUR_PTR;
1751:
1752: while (IS_CHAR(CUR) &&
1753: ((CUR != '?') || (NXT(1) != '>')))
1754: NEXT;
1755: if (!IS_CHAR(CUR)) {
1756: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1757: ctxt->sax->error(ctxt->userData,
1.72 daniel 1758: "xmlParsePI: PI %s never end ...\n", target);
1759: ctxt->wellFormed = 0;
1.22 daniel 1760: } else {
1.72 daniel 1761: CHAR *data;
1.44 daniel 1762:
1.72 daniel 1763: data = xmlStrndup(q, CUR_PTR - q);
1764: SKIP(2);
1.44 daniel 1765:
1.72 daniel 1766: /*
1767: * SAX: PI detected.
1768: */
1769: if ((ctxt->sax) &&
1770: (ctxt->sax->processingInstruction != NULL))
1.74 daniel 1771: ctxt->sax->processingInstruction(ctxt->userData, target, data);
1.72 daniel 1772: free(data);
1.22 daniel 1773: }
1.39 daniel 1774: free(target);
1.3 veillard 1775: } else {
1.55 daniel 1776: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1777: ctxt->sax->error(ctxt->userData, "xmlParsePI : no target name\n");
1.59 daniel 1778: ctxt->wellFormed = 0;
1779:
1.22 daniel 1780: /********* Should we try to complete parsing the PI ???
1.40 daniel 1781: while (IS_CHAR(CUR) &&
1782: (CUR != '?') && (CUR != '>'))
1783: NEXT;
1784: if (!IS_CHAR(CUR)) {
1.22 daniel 1785: fprintf(stderr, "xmlParsePI: PI %s never end ...\n",
1786: target);
1787: }
1788: ********************************************************/
1789: }
1790: }
1791: }
1792:
1.50 daniel 1793: /**
1794: * xmlParseNotationDecl:
1795: * @ctxt: an XML parser context
1796: *
1797: * parse a notation declaration
1.22 daniel 1798: *
1799: * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
1800: *
1801: * Hence there is actually 3 choices:
1802: * 'PUBLIC' S PubidLiteral
1803: * 'PUBLIC' S PubidLiteral S SystemLiteral
1804: * and 'SYSTEM' S SystemLiteral
1.50 daniel 1805: *
1.67 daniel 1806: * See the NOTE on xmlParseExternalID().
1.22 daniel 1807: */
1808:
1.55 daniel 1809: void
1810: xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
1.22 daniel 1811: CHAR *name;
1.67 daniel 1812: CHAR *Pubid;
1813: CHAR *Systemid;
1.22 daniel 1814:
1.40 daniel 1815: if ((CUR == '<') && (NXT(1) == '!') &&
1816: (NXT(2) == 'N') && (NXT(3) == 'O') &&
1817: (NXT(4) == 'T') && (NXT(5) == 'A') &&
1818: (NXT(6) == 'T') && (NXT(7) == 'I') &&
1.67 daniel 1819: (NXT(8) == 'O') && (NXT(9) == 'N')) {
1.40 daniel 1820: SKIP(10);
1.67 daniel 1821: if (!IS_BLANK(CUR)) {
1822: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1823: ctxt->sax->error(ctxt->userData, "Space required after '<!NOTATION'\n");
1.67 daniel 1824: ctxt->wellFormed = 0;
1825: return;
1826: }
1827: SKIP_BLANKS;
1.22 daniel 1828:
1829: name = xmlParseName(ctxt);
1830: if (name == NULL) {
1.55 daniel 1831: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1832: ctxt->sax->error(ctxt->userData, "NOTATION: Name expected here\n");
1.67 daniel 1833: ctxt->wellFormed = 0;
1834: return;
1835: }
1836: if (!IS_BLANK(CUR)) {
1837: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1838: ctxt->sax->error(ctxt->userData,
1.67 daniel 1839: "Space required after the NOTATION name'\n");
1.59 daniel 1840: ctxt->wellFormed = 0;
1.22 daniel 1841: return;
1842: }
1.42 daniel 1843: SKIP_BLANKS;
1.67 daniel 1844:
1.22 daniel 1845: /*
1.67 daniel 1846: * Parse the IDs.
1.22 daniel 1847: */
1.67 daniel 1848: Systemid = xmlParseExternalID(ctxt, &Pubid, 1);
1849: SKIP_BLANKS;
1850:
1851: if (CUR == '>') {
1.40 daniel 1852: NEXT;
1.72 daniel 1853: if ((ctxt->sax != NULL) && (ctxt->sax->notationDecl != NULL))
1.74 daniel 1854: ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid);
1.67 daniel 1855: } else {
1856: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1857: ctxt->sax->error(ctxt->userData,
1.67 daniel 1858: "'>' required to close NOTATION declaration\n");
1859: ctxt->wellFormed = 0;
1860: }
1.22 daniel 1861: free(name);
1.67 daniel 1862: if (Systemid != NULL) free(Systemid);
1863: if (Pubid != NULL) free(Pubid);
1.22 daniel 1864: }
1865: }
1866:
1.50 daniel 1867: /**
1868: * xmlParseEntityDecl:
1869: * @ctxt: an XML parser context
1870: *
1871: * parse <!ENTITY declarations
1.22 daniel 1872: *
1873: * [70] EntityDecl ::= GEDecl | PEDecl
1874: *
1875: * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
1876: *
1877: * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
1878: *
1879: * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
1880: *
1881: * [74] PEDef ::= EntityValue | ExternalID
1.24 daniel 1882: *
1883: * [76] NDataDecl ::= S 'NDATA' S Name
1.22 daniel 1884: */
1885:
1.55 daniel 1886: void
1887: xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
1.39 daniel 1888: CHAR *name = NULL;
1.24 daniel 1889: CHAR *value = NULL;
1.39 daniel 1890: CHAR *URI = NULL, *literal = NULL;
1.24 daniel 1891: CHAR *ndata = NULL;
1.39 daniel 1892: int isParameter = 0;
1.22 daniel 1893:
1.40 daniel 1894: if ((CUR == '<') && (NXT(1) == '!') &&
1895: (NXT(2) == 'E') && (NXT(3) == 'N') &&
1896: (NXT(4) == 'T') && (NXT(5) == 'I') &&
1.59 daniel 1897: (NXT(6) == 'T') && (NXT(7) == 'Y')) {
1.40 daniel 1898: SKIP(8);
1.59 daniel 1899: if (!IS_BLANK(CUR)) {
1900: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1901: ctxt->sax->error(ctxt->userData, "Space required after '<!ENTITY'\n");
1.59 daniel 1902: ctxt->wellFormed = 0;
1903: }
1904: SKIP_BLANKS;
1.40 daniel 1905:
1906: if (CUR == '%') {
1907: NEXT;
1.59 daniel 1908: if (!IS_BLANK(CUR)) {
1909: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1910: ctxt->sax->error(ctxt->userData, "Space required after '%'\n");
1.59 daniel 1911: ctxt->wellFormed = 0;
1912: }
1.42 daniel 1913: SKIP_BLANKS;
1.39 daniel 1914: isParameter = 1;
1.22 daniel 1915: }
1916:
1917: name = xmlParseName(ctxt);
1.24 daniel 1918: if (name == NULL) {
1.55 daniel 1919: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1920: ctxt->sax->error(ctxt->userData, "xmlParseEntityDecl: no name\n");
1.59 daniel 1921: ctxt->wellFormed = 0;
1.24 daniel 1922: return;
1923: }
1.59 daniel 1924: if (!IS_BLANK(CUR)) {
1925: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1926: ctxt->sax->error(ctxt->userData,
1.59 daniel 1927: "Space required after the entity name\n");
1928: ctxt->wellFormed = 0;
1929: }
1.42 daniel 1930: SKIP_BLANKS;
1.24 daniel 1931:
1.22 daniel 1932: /*
1.68 daniel 1933: * handle the various case of definitions...
1.22 daniel 1934: */
1.39 daniel 1935: if (isParameter) {
1.40 daniel 1936: if ((CUR == '"') || (CUR == '\''))
1.24 daniel 1937: value = xmlParseEntityValue(ctxt);
1.39 daniel 1938: if (value) {
1.72 daniel 1939: if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74 daniel 1940: ctxt->sax->entityDecl(ctxt->userData, name,
1.39 daniel 1941: XML_INTERNAL_PARAMETER_ENTITY,
1942: NULL, NULL, value);
1943: }
1.24 daniel 1944: else {
1.67 daniel 1945: URI = xmlParseExternalID(ctxt, &literal, 1);
1.39 daniel 1946: if (URI) {
1.72 daniel 1947: if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74 daniel 1948: ctxt->sax->entityDecl(ctxt->userData, name,
1.39 daniel 1949: XML_EXTERNAL_PARAMETER_ENTITY,
1950: literal, URI, NULL);
1951: }
1.24 daniel 1952: }
1953: } else {
1.40 daniel 1954: if ((CUR == '"') || (CUR == '\'')) {
1.24 daniel 1955: value = xmlParseEntityValue(ctxt);
1.72 daniel 1956: if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74 daniel 1957: ctxt->sax->entityDecl(ctxt->userData, name,
1.39 daniel 1958: XML_INTERNAL_GENERAL_ENTITY,
1959: NULL, NULL, value);
1960: } else {
1.67 daniel 1961: URI = xmlParseExternalID(ctxt, &literal, 1);
1.59 daniel 1962: if ((CUR != '>') && (!IS_BLANK(CUR))) {
1963: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1964: ctxt->sax->error(ctxt->userData,
1.59 daniel 1965: "Space required before 'NDATA'\n");
1966: ctxt->wellFormed = 0;
1967: }
1.42 daniel 1968: SKIP_BLANKS;
1.40 daniel 1969: if ((CUR == 'N') && (NXT(1) == 'D') &&
1970: (NXT(2) == 'A') && (NXT(3) == 'T') &&
1971: (NXT(4) == 'A')) {
1972: SKIP(5);
1.59 daniel 1973: if (!IS_BLANK(CUR)) {
1974: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1975: ctxt->sax->error(ctxt->userData,
1.59 daniel 1976: "Space required after 'NDATA'\n");
1977: ctxt->wellFormed = 0;
1978: }
1.42 daniel 1979: SKIP_BLANKS;
1.24 daniel 1980: ndata = xmlParseName(ctxt);
1.72 daniel 1981: if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74 daniel 1982: ctxt->sax->entityDecl(ctxt->userData, name,
1.39 daniel 1983: XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
1984: literal, URI, ndata);
1985: } else {
1.72 daniel 1986: if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74 daniel 1987: ctxt->sax->entityDecl(ctxt->userData, name,
1.39 daniel 1988: XML_EXTERNAL_GENERAL_PARSED_ENTITY,
1989: literal, URI, NULL);
1.24 daniel 1990: }
1991: }
1992: }
1.42 daniel 1993: SKIP_BLANKS;
1.40 daniel 1994: if (CUR != '>') {
1.55 daniel 1995: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 1996: ctxt->sax->error(ctxt->userData,
1.31 daniel 1997: "xmlParseEntityDecl: entity %s not terminated\n", name);
1.59 daniel 1998: ctxt->wellFormed = 0;
1.24 daniel 1999: } else
1.40 daniel 2000: NEXT;
1.39 daniel 2001: if (name != NULL) free(name);
2002: if (value != NULL) free(value);
2003: if (URI != NULL) free(URI);
2004: if (literal != NULL) free(literal);
2005: if (ndata != NULL) free(ndata);
1.22 daniel 2006: }
2007: }
2008:
1.50 daniel 2009: /**
1.59 daniel 2010: * xmlParseDefaultDecl:
2011: * @ctxt: an XML parser context
2012: * @value: Receive a possible fixed default value for the attribute
2013: *
2014: * Parse an attribute default declaration
2015: *
2016: * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
2017: *
2018: * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
2019: * or XML_ATTRIBUTE_FIXED.
2020: */
2021:
2022: int
2023: xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, CHAR **value) {
2024: int val;
2025: CHAR *ret;
2026:
2027: *value = NULL;
2028: if ((CUR == '#') && (NXT(1) == 'R') &&
2029: (NXT(2) == 'E') && (NXT(3) == 'Q') &&
2030: (NXT(4) == 'U') && (NXT(5) == 'I') &&
2031: (NXT(6) == 'R') && (NXT(7) == 'E') &&
2032: (NXT(8) == 'D')) {
2033: SKIP(9);
2034: return(XML_ATTRIBUTE_REQUIRED);
2035: }
2036: if ((CUR == '#') && (NXT(1) == 'I') &&
2037: (NXT(2) == 'M') && (NXT(3) == 'P') &&
2038: (NXT(4) == 'L') && (NXT(5) == 'I') &&
2039: (NXT(6) == 'E') && (NXT(7) == 'D')) {
2040: SKIP(8);
2041: return(XML_ATTRIBUTE_IMPLIED);
2042: }
2043: val = XML_ATTRIBUTE_NONE;
2044: if ((CUR == '#') && (NXT(1) == 'F') &&
2045: (NXT(2) == 'I') && (NXT(3) == 'X') &&
2046: (NXT(4) == 'E') && (NXT(5) == 'D')) {
2047: SKIP(6);
2048: val = XML_ATTRIBUTE_FIXED;
2049: if (!IS_BLANK(CUR)) {
2050: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2051: ctxt->sax->error(ctxt->userData, "Space required after '#FIXED'\n");
1.59 daniel 2052: ctxt->wellFormed = 0;
2053: }
2054: SKIP_BLANKS;
2055: }
2056: ret = xmlParseAttValue(ctxt);
2057: if (ret == NULL) {
2058: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2059: ctxt->sax->error(ctxt->userData,
1.59 daniel 2060: "Attribute default value declaration error\n");
2061: ctxt->wellFormed = 0;
2062: } else
2063: *value = ret;
2064: return(val);
2065: }
2066:
2067: /**
1.66 daniel 2068: * xmlParseNotationType:
2069: * @ctxt: an XML parser context
2070: *
2071: * parse an Notation attribute type.
2072: *
2073: * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
2074: *
2075: * Note: the leading 'NOTATION' S part has already being parsed...
2076: *
2077: * Returns: the notation attribute tree built while parsing
2078: */
2079:
2080: xmlEnumerationPtr
2081: xmlParseNotationType(xmlParserCtxtPtr ctxt) {
2082: CHAR *name;
2083: xmlEnumerationPtr ret = NULL, last = NULL, cur;
2084:
2085: if (CUR != '(') {
2086: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2087: ctxt->sax->error(ctxt->userData, "'(' required to start 'NOTATION'\n");
1.66 daniel 2088: ctxt->wellFormed = 0;
2089: return(NULL);
2090: }
2091: do {
2092: NEXT;
2093: SKIP_BLANKS;
2094: name = xmlParseName(ctxt);
2095: if (name == NULL) {
2096: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2097: ctxt->sax->error(ctxt->userData,
1.66 daniel 2098: "Name expected in NOTATION declaration\n");
2099: ctxt->wellFormed = 0;
2100: return(ret);
2101: }
2102: cur = xmlCreateEnumeration(name);
1.67 daniel 2103: free(name);
1.66 daniel 2104: if (cur == NULL) return(ret);
2105: if (last == NULL) ret = last = cur;
2106: else {
2107: last->next = cur;
2108: last = cur;
2109: }
2110: SKIP_BLANKS;
2111: } while (CUR == '|');
2112: if (CUR != ')') {
2113: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2114: ctxt->sax->error(ctxt->userData,
1.66 daniel 2115: "')' required to finish NOTATION declaration\n");
2116: ctxt->wellFormed = 0;
2117: return(ret);
2118: }
2119: NEXT;
2120: return(ret);
2121: }
2122:
2123: /**
2124: * xmlParseEnumerationType:
2125: * @ctxt: an XML parser context
2126: *
2127: * parse an Enumeration attribute type.
2128: *
2129: * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
2130: *
2131: * Returns: the enumeration attribute tree built while parsing
2132: */
2133:
2134: xmlEnumerationPtr
2135: xmlParseEnumerationType(xmlParserCtxtPtr ctxt) {
2136: CHAR *name;
2137: xmlEnumerationPtr ret = NULL, last = NULL, cur;
2138:
2139: if (CUR != '(') {
2140: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2141: ctxt->sax->error(ctxt->userData,
1.66 daniel 2142: "'(' required to start ATTLIST enumeration\n");
2143: ctxt->wellFormed = 0;
2144: return(NULL);
2145: }
2146: do {
2147: NEXT;
2148: SKIP_BLANKS;
2149: name = xmlParseNmtoken(ctxt);
2150: if (name == NULL) {
2151: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2152: ctxt->sax->error(ctxt->userData,
1.66 daniel 2153: "NmToken expected in ATTLIST enumeration\n");
2154: ctxt->wellFormed = 0;
2155: return(ret);
2156: }
2157: cur = xmlCreateEnumeration(name);
1.67 daniel 2158: free(name);
1.66 daniel 2159: if (cur == NULL) return(ret);
2160: if (last == NULL) ret = last = cur;
2161: else {
2162: last->next = cur;
2163: last = cur;
2164: }
2165: SKIP_BLANKS;
2166: } while (CUR == '|');
2167: if (CUR != ')') {
2168: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2169: ctxt->sax->error(ctxt->userData,
1.66 daniel 2170: "')' required to finish ATTLIST enumeration\n");
2171: ctxt->wellFormed = 0;
2172: return(ret);
2173: }
2174: NEXT;
2175: return(ret);
2176: }
2177:
2178: /**
1.50 daniel 2179: * xmlParseEnumeratedType:
2180: * @ctxt: an XML parser context
1.66 daniel 2181: * @tree: the enumeration tree built while parsing
1.50 daniel 2182: *
1.66 daniel 2183: * parse an Enumerated attribute type.
1.22 daniel 2184: *
2185: * [57] EnumeratedType ::= NotationType | Enumeration
2186: *
2187: * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
2188: *
1.50 daniel 2189: *
1.66 daniel 2190: * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION
1.22 daniel 2191: */
2192:
1.66 daniel 2193: int
2194: xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
2195: if ((CUR == 'N') && (NXT(1) == 'O') &&
2196: (NXT(2) == 'T') && (NXT(3) == 'A') &&
2197: (NXT(4) == 'T') && (NXT(5) == 'I') &&
2198: (NXT(6) == 'O') && (NXT(7) == 'N')) {
2199: SKIP(8);
2200: if (!IS_BLANK(CUR)) {
2201: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2202: ctxt->sax->error(ctxt->userData, "Space required after 'NOTATION'\n");
1.66 daniel 2203: ctxt->wellFormed = 0;
2204: return(0);
2205: }
2206: SKIP_BLANKS;
2207: *tree = xmlParseNotationType(ctxt);
2208: if (*tree == NULL) return(0);
2209: return(XML_ATTRIBUTE_NOTATION);
2210: }
2211: *tree = xmlParseEnumerationType(ctxt);
2212: if (*tree == NULL) return(0);
2213: return(XML_ATTRIBUTE_ENUMERATION);
1.22 daniel 2214: }
2215:
1.50 daniel 2216: /**
2217: * xmlParseAttributeType:
2218: * @ctxt: an XML parser context
1.66 daniel 2219: * @tree: the enumeration tree built while parsing
1.50 daniel 2220: *
1.59 daniel 2221: * parse the Attribute list def for an element
1.22 daniel 2222: *
2223: * [54] AttType ::= StringType | TokenizedType | EnumeratedType
2224: *
2225: * [55] StringType ::= 'CDATA'
2226: *
2227: * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
2228: * 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
1.50 daniel 2229: *
1.69 daniel 2230: * Returns the attribute type
1.22 daniel 2231: */
1.59 daniel 2232: int
1.66 daniel 2233: xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
1.40 daniel 2234: if ((CUR == 'C') && (NXT(1) == 'D') &&
2235: (NXT(2) == 'A') && (NXT(3) == 'T') &&
2236: (NXT(4) == 'A')) {
2237: SKIP(5);
1.66 daniel 2238: return(XML_ATTRIBUTE_CDATA);
1.40 daniel 2239: } else if ((CUR == 'I') && (NXT(1) == 'D') &&
2240: (NXT(2) == 'R') && (NXT(3) == 'E') &&
2241: (NXT(4) == 'F')) {
2242: SKIP(5);
1.59 daniel 2243: return(XML_ATTRIBUTE_IDREF);
1.66 daniel 2244: } else if ((CUR == 'I') && (NXT(1) == 'D')) {
2245: SKIP(2);
2246: return(XML_ATTRIBUTE_ID);
1.40 daniel 2247: } else if ((CUR == 'I') && (NXT(1) == 'D') &&
2248: (NXT(2) == 'R') && (NXT(3) == 'E') &&
2249: (NXT(4) == 'F') && (NXT(5) == 'S')) {
2250: SKIP(6);
1.59 daniel 2251: return(XML_ATTRIBUTE_IDREFS);
1.40 daniel 2252: } else if ((CUR == 'E') && (NXT(1) == 'N') &&
2253: (NXT(2) == 'T') && (NXT(3) == 'I') &&
2254: (NXT(4) == 'T') && (NXT(5) == 'Y')) {
2255: SKIP(6);
1.59 daniel 2256: return(XML_ATTRIBUTE_ENTITY);
1.40 daniel 2257: } else if ((CUR == 'E') && (NXT(1) == 'N') &&
2258: (NXT(2) == 'T') && (NXT(3) == 'I') &&
2259: (NXT(4) == 'T') && (NXT(5) == 'I') &&
2260: (NXT(6) == 'E') && (NXT(7) == 'S')) {
2261: SKIP(8);
1.59 daniel 2262: return(XML_ATTRIBUTE_ENTITIES);
1.40 daniel 2263: } else if ((CUR == 'N') && (NXT(1) == 'M') &&
2264: (NXT(2) == 'T') && (NXT(3) == 'O') &&
2265: (NXT(4) == 'K') && (NXT(5) == 'E') &&
1.66 daniel 2266: (NXT(6) == 'N') && (NXT(7) == 'S')) {
2267: SKIP(8);
2268: return(XML_ATTRIBUTE_NMTOKENS);
2269: } else if ((CUR == 'N') && (NXT(1) == 'M') &&
2270: (NXT(2) == 'T') && (NXT(3) == 'O') &&
2271: (NXT(4) == 'K') && (NXT(5) == 'E') &&
1.40 daniel 2272: (NXT(6) == 'N')) {
2273: SKIP(7);
1.59 daniel 2274: return(XML_ATTRIBUTE_NMTOKEN);
1.22 daniel 2275: }
1.66 daniel 2276: return(xmlParseEnumeratedType(ctxt, tree));
1.22 daniel 2277: }
2278:
1.50 daniel 2279: /**
2280: * xmlParseAttributeListDecl:
2281: * @ctxt: an XML parser context
2282: *
2283: * : parse the Attribute list def for an element
1.22 daniel 2284: *
2285: * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
2286: *
2287: * [53] AttDef ::= S Name S AttType S DefaultDecl
1.50 daniel 2288: *
1.22 daniel 2289: */
1.55 daniel 2290: void
2291: xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
1.59 daniel 2292: CHAR *elemName;
2293: CHAR *attrName;
1.66 daniel 2294: xmlEnumerationPtr tree = NULL;
1.22 daniel 2295:
1.40 daniel 2296: if ((CUR == '<') && (NXT(1) == '!') &&
2297: (NXT(2) == 'A') && (NXT(3) == 'T') &&
2298: (NXT(4) == 'T') && (NXT(5) == 'L') &&
2299: (NXT(6) == 'I') && (NXT(7) == 'S') &&
1.59 daniel 2300: (NXT(8) == 'T')) {
1.40 daniel 2301: SKIP(9);
1.59 daniel 2302: if (!IS_BLANK(CUR)) {
2303: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2304: ctxt->sax->error(ctxt->userData, "Space required after '<!ATTLIST'\n");
1.59 daniel 2305: ctxt->wellFormed = 0;
2306: }
1.42 daniel 2307: SKIP_BLANKS;
1.59 daniel 2308: elemName = xmlParseName(ctxt);
2309: if (elemName == NULL) {
1.55 daniel 2310: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2311: ctxt->sax->error(ctxt->userData, "ATTLIST: no name for Element\n");
1.59 daniel 2312: ctxt->wellFormed = 0;
1.22 daniel 2313: return;
2314: }
1.42 daniel 2315: SKIP_BLANKS;
1.40 daniel 2316: while (CUR != '>') {
2317: const CHAR *check = CUR_PTR;
1.59 daniel 2318: int type;
2319: int def;
2320: CHAR *defaultValue = NULL;
2321:
2322: attrName = xmlParseName(ctxt);
2323: if (attrName == NULL) {
2324: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2325: ctxt->sax->error(ctxt->userData, "ATTLIST: no name for Attribute\n");
1.59 daniel 2326: ctxt->wellFormed = 0;
2327: break;
2328: }
2329: if (!IS_BLANK(CUR)) {
2330: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2331: ctxt->sax->error(ctxt->userData,
1.59 daniel 2332: "Space required after the attribute name\n");
2333: ctxt->wellFormed = 0;
2334: break;
2335: }
2336: SKIP_BLANKS;
2337:
1.66 daniel 2338: type = xmlParseAttributeType(ctxt, &tree);
1.59 daniel 2339: if (type <= 0) break;
1.22 daniel 2340:
1.59 daniel 2341: if (!IS_BLANK(CUR)) {
2342: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2343: ctxt->sax->error(ctxt->userData,
1.59 daniel 2344: "Space required after the attribute type\n");
2345: ctxt->wellFormed = 0;
2346: break;
2347: }
1.42 daniel 2348: SKIP_BLANKS;
1.59 daniel 2349:
2350: def = xmlParseDefaultDecl(ctxt, &defaultValue);
2351: if (def <= 0) break;
2352:
2353: if (CUR != '>') {
2354: if (!IS_BLANK(CUR)) {
2355: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2356: ctxt->sax->error(ctxt->userData,
1.59 daniel 2357: "Space required after the attribute default value\n");
2358: ctxt->wellFormed = 0;
2359: break;
2360: }
2361: SKIP_BLANKS;
2362: }
1.40 daniel 2363: if (check == CUR_PTR) {
1.55 daniel 2364: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2365: ctxt->sax->error(ctxt->userData,
1.59 daniel 2366: "xmlParseAttributeListDecl: detected internal error\n");
1.22 daniel 2367: break;
2368: }
1.72 daniel 2369: if ((ctxt->sax != NULL) && (ctxt->sax->attributeDecl != NULL))
1.74 daniel 2370: ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName,
1.66 daniel 2371: type, def, defaultValue, tree);
1.59 daniel 2372: if (attrName != NULL)
2373: free(attrName);
2374: if (defaultValue != NULL)
2375: free(defaultValue);
1.22 daniel 2376: }
1.40 daniel 2377: if (CUR == '>')
2378: NEXT;
1.22 daniel 2379:
1.59 daniel 2380: free(elemName);
1.22 daniel 2381: }
2382: }
2383:
1.50 daniel 2384: /**
1.61 daniel 2385: * xmlParseElementMixedContentDecl:
2386: * @ctxt: an XML parser context
2387: *
2388: * parse the declaration for a Mixed Element content
2389: * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
2390: *
2391: * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
2392: * '(' S? '#PCDATA' S? ')'
2393: *
2394: * returns: the list of the xmlElementContentPtr describing the element choices
2395: */
2396: xmlElementContentPtr
1.62 daniel 2397: xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
1.64 daniel 2398: xmlElementContentPtr ret = NULL, cur = NULL, n;
1.61 daniel 2399: CHAR *elem = NULL;
2400:
2401: if ((CUR == '#') && (NXT(1) == 'P') &&
2402: (NXT(2) == 'C') && (NXT(3) == 'D') &&
2403: (NXT(4) == 'A') && (NXT(5) == 'T') &&
2404: (NXT(6) == 'A')) {
2405: SKIP(7);
2406: SKIP_BLANKS;
1.63 daniel 2407: if (CUR == ')') {
2408: NEXT;
2409: ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
2410: return(ret);
2411: }
1.61 daniel 2412: if ((CUR == '(') || (CUR == '|')) {
2413: ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
2414: if (ret == NULL) return(NULL);
1.63 daniel 2415: } /********** else {
1.61 daniel 2416: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2417: ctxt->sax->error(ctxt->userData,
1.61 daniel 2418: "xmlParseElementMixedContentDecl : '|' or ')' expected\n");
2419: ctxt->wellFormed = 0;
2420: return(NULL);
1.63 daniel 2421: } **********/
1.61 daniel 2422: while (CUR == '|') {
1.64 daniel 2423: NEXT;
1.61 daniel 2424: if (elem == NULL) {
2425: ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2426: if (ret == NULL) return(NULL);
2427: ret->c1 = cur;
1.64 daniel 2428: cur = ret;
1.61 daniel 2429: } else {
1.64 daniel 2430: n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2431: if (n == NULL) return(NULL);
2432: n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
2433: cur->c2 = n;
2434: cur = n;
1.66 daniel 2435: free(elem);
1.61 daniel 2436: }
2437: SKIP_BLANKS;
2438: elem = xmlParseName(ctxt);
2439: if (elem == NULL) {
2440: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2441: ctxt->sax->error(ctxt->userData,
1.61 daniel 2442: "xmlParseElementMixedContentDecl : Name expected\n");
2443: ctxt->wellFormed = 0;
2444: xmlFreeElementContent(cur);
2445: return(NULL);
2446: }
2447: SKIP_BLANKS;
2448: }
1.63 daniel 2449: if ((CUR == ')') && (NXT(1) == '*')) {
1.66 daniel 2450: if (elem != NULL) {
1.61 daniel 2451: cur->c2 = xmlNewElementContent(elem,
2452: XML_ELEMENT_CONTENT_ELEMENT);
1.66 daniel 2453: free(elem);
2454: }
1.65 daniel 2455: ret->ocur = XML_ELEMENT_CONTENT_MULT;
1.64 daniel 2456: SKIP(2);
1.61 daniel 2457: } else {
1.66 daniel 2458: if (elem != NULL) free(elem);
1.61 daniel 2459: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2460: ctxt->sax->error(ctxt->userData,
1.63 daniel 2461: "xmlParseElementMixedContentDecl : '|' or ')*' expected\n");
1.61 daniel 2462: ctxt->wellFormed = 0;
2463: xmlFreeElementContent(ret);
2464: return(NULL);
2465: }
2466:
2467: } else {
2468: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2469: ctxt->sax->error(ctxt->userData,
1.61 daniel 2470: "xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
2471: ctxt->wellFormed = 0;
2472: }
2473: return(ret);
2474: }
2475:
2476: /**
2477: * xmlParseElementChildrenContentDecl:
1.50 daniel 2478: * @ctxt: an XML parser context
2479: *
1.61 daniel 2480: * parse the declaration for a Mixed Element content
2481: * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
1.22 daniel 2482: *
1.61 daniel 2483: *
1.22 daniel 2484: * [47] children ::= (choice | seq) ('?' | '*' | '+')?
2485: *
2486: * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
2487: *
2488: * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
2489: *
2490: * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
2491: *
1.62 daniel 2492: * returns: the tree of xmlElementContentPtr describing the element
1.61 daniel 2493: * hierarchy.
2494: */
2495: xmlElementContentPtr
1.62 daniel 2496: xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt) {
1.63 daniel 2497: xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
1.62 daniel 2498: CHAR *elem;
2499: CHAR type = 0;
2500:
2501: SKIP_BLANKS;
2502: if (CUR == '(') {
1.63 daniel 2503: /* Recurse on first child */
1.62 daniel 2504: NEXT;
2505: SKIP_BLANKS;
2506: cur = ret = xmlParseElementChildrenContentDecl(ctxt);
2507: SKIP_BLANKS;
2508: } else {
2509: elem = xmlParseName(ctxt);
2510: if (elem == NULL) {
2511: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2512: ctxt->sax->error(ctxt->userData,
1.62 daniel 2513: "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
2514: ctxt->wellFormed = 0;
2515: return(NULL);
2516: }
2517: cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
2518: if (CUR == '?') {
2519: ret->ocur = XML_ELEMENT_CONTENT_OPT;
2520: NEXT;
2521: } else if (CUR == '*') {
2522: ret->ocur = XML_ELEMENT_CONTENT_MULT;
2523: NEXT;
2524: } else if (CUR == '+') {
2525: ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2526: NEXT;
2527: } else {
2528: ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2529: }
1.66 daniel 2530: free(elem);
1.62 daniel 2531: }
2532: SKIP_BLANKS;
2533: while (CUR != ')') {
1.63 daniel 2534: /*
2535: * Each loop we parse one separator and one element.
2536: */
1.62 daniel 2537: if (CUR == ',') {
2538: if (type == 0) type = CUR;
2539:
2540: /*
2541: * Detect "Name | Name , Name" error
2542: */
2543: else if (type != CUR) {
2544: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2545: ctxt->sax->error(ctxt->userData,
1.62 daniel 2546: "xmlParseElementChildrenContentDecl : '%c' expected\n",
2547: type);
2548: ctxt->wellFormed = 0;
2549: xmlFreeElementContent(ret);
2550: return(NULL);
2551: }
1.64 daniel 2552: NEXT;
1.62 daniel 2553:
1.63 daniel 2554: op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
2555: if (op == NULL) {
2556: xmlFreeElementContent(ret);
2557: return(NULL);
2558: }
2559: if (last == NULL) {
2560: op->c1 = ret;
1.65 daniel 2561: ret = cur = op;
1.63 daniel 2562: } else {
2563: cur->c2 = op;
2564: op->c1 = last;
2565: cur =op;
1.65 daniel 2566: last = NULL;
1.63 daniel 2567: }
1.62 daniel 2568: } else if (CUR == '|') {
2569: if (type == 0) type = CUR;
2570:
2571: /*
1.63 daniel 2572: * Detect "Name , Name | Name" error
1.62 daniel 2573: */
2574: else if (type != CUR) {
2575: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2576: ctxt->sax->error(ctxt->userData,
1.62 daniel 2577: "xmlParseElementChildrenContentDecl : '%c' expected\n",
2578: type);
2579: ctxt->wellFormed = 0;
2580: xmlFreeElementContent(ret);
2581: return(NULL);
2582: }
1.64 daniel 2583: NEXT;
1.62 daniel 2584:
1.63 daniel 2585: op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2586: if (op == NULL) {
2587: xmlFreeElementContent(ret);
2588: return(NULL);
2589: }
2590: if (last == NULL) {
2591: op->c1 = ret;
1.65 daniel 2592: ret = cur = op;
1.63 daniel 2593: } else {
2594: cur->c2 = op;
2595: op->c1 = last;
2596: cur =op;
1.65 daniel 2597: last = NULL;
1.63 daniel 2598: }
1.62 daniel 2599: } else {
2600: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2601: ctxt->sax->error(ctxt->userData,
1.62 daniel 2602: "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
2603: ctxt->wellFormed = 0;
2604: xmlFreeElementContent(ret);
2605: return(NULL);
2606: }
2607: SKIP_BLANKS;
2608: if (CUR == '(') {
1.63 daniel 2609: /* Recurse on second child */
1.62 daniel 2610: NEXT;
2611: SKIP_BLANKS;
1.65 daniel 2612: last = xmlParseElementChildrenContentDecl(ctxt);
1.62 daniel 2613: SKIP_BLANKS;
2614: } else {
2615: elem = xmlParseName(ctxt);
2616: if (elem == NULL) {
2617: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2618: ctxt->sax->error(ctxt->userData,
1.62 daniel 2619: "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
2620: ctxt->wellFormed = 0;
2621: return(NULL);
2622: }
1.65 daniel 2623: last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
1.66 daniel 2624: free(elem);
1.62 daniel 2625: }
1.63 daniel 2626: if (CUR == '?') {
2627: ret->ocur = XML_ELEMENT_CONTENT_OPT;
2628: NEXT;
2629: } else if (CUR == '*') {
2630: ret->ocur = XML_ELEMENT_CONTENT_MULT;
2631: NEXT;
2632: } else if (CUR == '+') {
2633: ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2634: NEXT;
2635: } else {
2636: ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2637: }
2638: SKIP_BLANKS;
1.64 daniel 2639: }
1.65 daniel 2640: if ((cur != NULL) && (last != NULL)) {
2641: cur->c2 = last;
1.62 daniel 2642: }
2643: NEXT;
2644: if (CUR == '?') {
2645: ret->ocur = XML_ELEMENT_CONTENT_OPT;
2646: NEXT;
2647: } else if (CUR == '*') {
2648: ret->ocur = XML_ELEMENT_CONTENT_MULT;
2649: NEXT;
2650: } else if (CUR == '+') {
2651: ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2652: NEXT;
2653: } else {
2654: ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2655: }
2656: return(ret);
1.61 daniel 2657: }
2658:
2659: /**
2660: * xmlParseElementContentDecl:
2661: * @ctxt: an XML parser context
2662: * @name: the name of the element being defined.
2663: * @result: the Element Content pointer will be stored here if any
1.22 daniel 2664: *
1.61 daniel 2665: * parse the declaration for an Element content either Mixed or Children,
2666: * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
2667: *
2668: * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
1.50 daniel 2669: *
1.61 daniel 2670: * returns: the type of element content XML_ELEMENT_TYPE_xxx
1.22 daniel 2671: */
2672:
1.61 daniel 2673: int
2674: xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, CHAR *name,
2675: xmlElementContentPtr *result) {
2676:
2677: xmlElementContentPtr tree = NULL;
2678: int res;
2679:
2680: *result = NULL;
2681:
2682: if (CUR != '(') {
2683: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2684: ctxt->sax->error(ctxt->userData,
1.61 daniel 2685: "xmlParseElementContentDecl : '(' expected\n");
2686: ctxt->wellFormed = 0;
2687: return(-1);
2688: }
2689: NEXT;
2690: SKIP_BLANKS;
2691: if ((CUR == '#') && (NXT(1) == 'P') &&
2692: (NXT(2) == 'C') && (NXT(3) == 'D') &&
2693: (NXT(4) == 'A') && (NXT(5) == 'T') &&
2694: (NXT(6) == 'A')) {
1.62 daniel 2695: tree = xmlParseElementMixedContentDecl(ctxt);
1.61 daniel 2696: res = XML_ELEMENT_TYPE_MIXED;
2697: } else {
1.62 daniel 2698: tree = xmlParseElementChildrenContentDecl(ctxt);
1.61 daniel 2699: res = XML_ELEMENT_TYPE_ELEMENT;
2700: }
2701: SKIP_BLANKS;
1.63 daniel 2702: /****************************
1.61 daniel 2703: if (CUR != ')') {
2704: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2705: ctxt->sax->error(ctxt->userData,
1.61 daniel 2706: "xmlParseElementContentDecl : ')' expected\n");
2707: ctxt->wellFormed = 0;
2708: return(-1);
2709: }
1.63 daniel 2710: ****************************/
2711: *result = tree;
1.61 daniel 2712: return(res);
1.22 daniel 2713: }
2714:
1.50 daniel 2715: /**
2716: * xmlParseElementDecl:
2717: * @ctxt: an XML parser context
1.76 ! daniel 2718: * @external: boolean indicating whether this is part of the external subset
1.50 daniel 2719: *
2720: * parse an Element declaration.
1.22 daniel 2721: *
2722: * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
2723: *
2724: * TODO There is a check [ VC: Unique Element Type Declaration ]
1.69 daniel 2725: *
2726: * Returns the type of the element, or -1 in case of error
1.22 daniel 2727: */
1.59 daniel 2728: int
1.55 daniel 2729: xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
1.22 daniel 2730: CHAR *name;
1.59 daniel 2731: int ret = -1;
1.61 daniel 2732: xmlElementContentPtr content = NULL;
1.22 daniel 2733:
1.40 daniel 2734: if ((CUR == '<') && (NXT(1) == '!') &&
2735: (NXT(2) == 'E') && (NXT(3) == 'L') &&
2736: (NXT(4) == 'E') && (NXT(5) == 'M') &&
2737: (NXT(6) == 'E') && (NXT(7) == 'N') &&
1.59 daniel 2738: (NXT(8) == 'T')) {
1.40 daniel 2739: SKIP(9);
1.59 daniel 2740: if (!IS_BLANK(CUR)) {
2741: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2742: ctxt->sax->error(ctxt->userData,
1.59 daniel 2743: "Space required after 'ELEMENT'\n");
2744: ctxt->wellFormed = 0;
2745: }
1.42 daniel 2746: SKIP_BLANKS;
1.22 daniel 2747: name = xmlParseName(ctxt);
2748: if (name == NULL) {
1.55 daniel 2749: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2750: ctxt->sax->error(ctxt->userData,
1.59 daniel 2751: "xmlParseElementDecl: no name for Element\n");
2752: ctxt->wellFormed = 0;
2753: return(-1);
2754: }
2755: if (!IS_BLANK(CUR)) {
2756: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2757: ctxt->sax->error(ctxt->userData,
1.59 daniel 2758: "Space required after the element name\n");
2759: ctxt->wellFormed = 0;
1.22 daniel 2760: }
1.42 daniel 2761: SKIP_BLANKS;
1.40 daniel 2762: if ((CUR == 'E') && (NXT(1) == 'M') &&
2763: (NXT(2) == 'P') && (NXT(3) == 'T') &&
2764: (NXT(4) == 'Y')) {
2765: SKIP(5);
1.22 daniel 2766: /*
2767: * Element must always be empty.
2768: */
1.59 daniel 2769: ret = XML_ELEMENT_TYPE_EMPTY;
1.40 daniel 2770: } else if ((CUR == 'A') && (NXT(1) == 'N') &&
2771: (NXT(2) == 'Y')) {
2772: SKIP(3);
1.22 daniel 2773: /*
2774: * Element is a generic container.
2775: */
1.59 daniel 2776: ret = XML_ELEMENT_TYPE_ANY;
1.61 daniel 2777: } else if (CUR == '(') {
2778: ret = xmlParseElementContentDecl(ctxt, name, &content);
1.22 daniel 2779: } else {
1.61 daniel 2780: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2781: ctxt->sax->error(ctxt->userData,
1.61 daniel 2782: "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
2783: ctxt->wellFormed = 0;
2784: if (name != NULL) free(name);
2785: return(-1);
1.22 daniel 2786: }
1.42 daniel 2787: SKIP_BLANKS;
1.40 daniel 2788: if (CUR != '>') {
1.55 daniel 2789: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2790: ctxt->sax->error(ctxt->userData,
1.31 daniel 2791: "xmlParseElementDecl: expected '>' at the end\n");
1.59 daniel 2792: ctxt->wellFormed = 0;
1.61 daniel 2793: } else {
1.40 daniel 2794: NEXT;
1.72 daniel 2795: if ((ctxt->sax != NULL) && (ctxt->sax->elementDecl != NULL))
1.76 ! daniel 2796: ctxt->sax->elementDecl(ctxt->userData, name, ret,
! 2797: content);
1.61 daniel 2798: }
2799: if (name != NULL) {
2800: free(name);
2801: }
1.22 daniel 2802: }
1.59 daniel 2803: return(ret);
1.22 daniel 2804: }
2805:
1.50 daniel 2806: /**
2807: * xmlParseMarkupDecl:
2808: * @ctxt: an XML parser context
2809: *
2810: * parse Markup declarations
1.22 daniel 2811: *
2812: * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
2813: * NotationDecl | PI | Comment
2814: *
2815: * TODO There is a check [ VC: Proper Declaration/PE Nesting ]
2816: */
1.55 daniel 2817: void
2818: xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
1.22 daniel 2819: xmlParseElementDecl(ctxt);
2820: xmlParseAttributeListDecl(ctxt);
2821: xmlParseEntityDecl(ctxt);
2822: xmlParseNotationDecl(ctxt);
2823: xmlParsePI(ctxt);
1.31 daniel 2824: xmlParseComment(ctxt, 0);
1.22 daniel 2825: }
2826:
1.50 daniel 2827: /**
1.76 ! daniel 2828: * xmlParseTextDecl:
! 2829: * @ctxt: an XML parser context
! 2830: *
! 2831: * parse an XML declaration header for external entities
! 2832: *
! 2833: * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
! 2834: *
! 2835: * Returns the only valuable info for an external parsed entity, the encoding
! 2836: */
! 2837:
! 2838: CHAR *
! 2839: xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
! 2840: CHAR *version;
! 2841: CHAR *encoding = NULL;
! 2842:
! 2843: /*
! 2844: * We know that '<?xml' is here.
! 2845: */
! 2846: SKIP(5);
! 2847:
! 2848: if (!IS_BLANK(CUR)) {
! 2849: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
! 2850: ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
! 2851: ctxt->wellFormed = 0;
! 2852: }
! 2853: SKIP_BLANKS;
! 2854:
! 2855: /*
! 2856: * We may have the VersionInfo here.
! 2857: */
! 2858: version = xmlParseVersionInfo(ctxt);
! 2859: /* TODO: we should actually inherit from the referencing doc if absent
! 2860: if (version == NULL)
! 2861: version = xmlCharStrdup(XML_DEFAULT_VERSION);
! 2862: ctxt->version = xmlStrdup(version);
! 2863: */
! 2864: if (version != NULL)
! 2865: free(version);
! 2866:
! 2867: /*
! 2868: * We must have the encoding declaration
! 2869: */
! 2870: if (!IS_BLANK(CUR)) {
! 2871: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
! 2872: ctxt->sax->error(ctxt->userData, "Blank needed here\n");
! 2873: ctxt->wellFormed = 0;
! 2874: }
! 2875: encoding = xmlParseEncodingDecl(ctxt);
! 2876:
! 2877: SKIP_BLANKS;
! 2878: if ((CUR == '?') && (NXT(1) == '>')) {
! 2879: SKIP(2);
! 2880: } else if (CUR == '>') {
! 2881: /* Deprecated old WD ... */
! 2882: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
! 2883: ctxt->sax->error(ctxt->userData, "XML declaration must end-up with '?>'\n");
! 2884: ctxt->wellFormed = 0;
! 2885: NEXT;
! 2886: } else {
! 2887: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
! 2888: ctxt->sax->error(ctxt->userData, "parsing XML declaration: '?>' expected\n");
! 2889: ctxt->wellFormed = 0;
! 2890: MOVETO_ENDTAG(CUR_PTR);
! 2891: NEXT;
! 2892: }
! 2893: return(encoding);
! 2894: }
! 2895:
! 2896: /*
! 2897: * xmlParseConditionalSections
! 2898: * @ctxt: an XML parser context
! 2899: *
! 2900: * TODO : Conditionnal section are not yet supported !
! 2901: *
! 2902: * [61] conditionalSect ::= includeSect | ignoreSect
! 2903: * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
! 2904: * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
! 2905: * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
! 2906: * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
! 2907: */
! 2908:
! 2909: void
! 2910: xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
! 2911: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
! 2912: ctxt->sax->warning(ctxt->userData,
! 2913: "XML conditional section not supported\n");
! 2914: /*
! 2915: * Skip up to the end of the conditionnal section.
! 2916: */
! 2917: while ((CUR != 0) && ((CUR != ']') || (NXT(1) != ']') || (NXT(2) != '>')))
! 2918: NEXT;
! 2919: if (CUR == 0) {
! 2920: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
! 2921: ctxt->sax->error(ctxt->userData,
! 2922: "XML conditional section not closed\n");
! 2923: ctxt->wellFormed = 0;
! 2924: }
! 2925: }
! 2926:
! 2927: /**
! 2928: * xmlParseExternalSubset
! 2929: * @ctxt: an XML parser context
! 2930: *
! 2931: * parse Markup declarations from an external subset
! 2932: *
! 2933: * [30] extSubset ::= textDecl? extSubsetDecl
! 2934: *
! 2935: * [31] extSubsetDecl ::= (markupdecl | conditionalSect | PEReference | S) *
! 2936: *
! 2937: * TODO There is a check [ VC: Proper Declaration/PE Nesting ]
! 2938: */
! 2939: void
! 2940: xmlParseExternalSubset(xmlParserCtxtPtr ctxt) {
! 2941: if ((CUR == '<') && (NXT(1) == '?') &&
! 2942: (NXT(2) == 'x') && (NXT(3) == 'm') &&
! 2943: (NXT(4) == 'l')) {
! 2944: xmlParseTextDecl(ctxt);
! 2945: }
! 2946: while (((CUR == '<') && (NXT(1) == '?')) ||
! 2947: ((CUR == '<') && (NXT(1) == '!')) ||
! 2948: IS_BLANK(CUR)) {
! 2949: if ((CUR == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
! 2950: xmlParseConditionalSections(ctxt);
! 2951: } else if (IS_BLANK(CUR)) {
! 2952: NEXT;
! 2953: } else if (CUR == '%') {
! 2954: xmlParsePEReference(ctxt);
! 2955: } else
! 2956: xmlParseMarkupDecl(ctxt);
! 2957: }
! 2958:
! 2959: if (CUR != 0) {
! 2960: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
! 2961: ctxt->sax->error(ctxt->userData,
! 2962: "Extra content at the end of the document\n");
! 2963: ctxt->wellFormed = 0;
! 2964: }
! 2965:
! 2966: }
! 2967:
! 2968: /**
1.50 daniel 2969: * xmlParseCharRef:
2970: * @ctxt: an XML parser context
2971: *
2972: * parse Reference declarations
1.24 daniel 2973: *
2974: * [66] CharRef ::= '&#' [0-9]+ ';' |
2975: * '&#x' [0-9a-fA-F]+ ';'
1.68 daniel 2976: *
2977: * Returns the value parsed
1.24 daniel 2978: */
1.55 daniel 2979: CHAR *
2980: xmlParseCharRef(xmlParserCtxtPtr ctxt) {
1.29 daniel 2981: int val = 0;
1.44 daniel 2982: CHAR buf[2];
1.24 daniel 2983:
1.40 daniel 2984: if ((CUR == '&') && (NXT(1) == '#') &&
2985: (NXT(2) == 'x')) {
2986: SKIP(3);
2987: while (CUR != ';') {
2988: if ((CUR >= '0') && (CUR <= '9'))
2989: val = val * 16 + (CUR - '0');
2990: else if ((CUR >= 'a') && (CUR <= 'f'))
2991: val = val * 16 + (CUR - 'a') + 10;
2992: else if ((CUR >= 'A') && (CUR <= 'F'))
2993: val = val * 16 + (CUR - 'A') + 10;
1.24 daniel 2994: else {
1.55 daniel 2995: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 2996: ctxt->sax->error(ctxt->userData,
1.59 daniel 2997: "xmlParseCharRef: invalid hexadecimal value\n");
2998: ctxt->wellFormed = 0;
1.29 daniel 2999: val = 0;
1.24 daniel 3000: break;
3001: }
1.47 daniel 3002: NEXT;
1.24 daniel 3003: }
1.55 daniel 3004: if (CUR == ';')
1.40 daniel 3005: NEXT;
3006: } else if ((CUR == '&') && (NXT(1) == '#')) {
3007: SKIP(2);
3008: while (CUR != ';') {
3009: if ((CUR >= '0') && (CUR <= '9'))
1.55 daniel 3010: val = val * 10 + (CUR - '0');
1.24 daniel 3011: else {
1.55 daniel 3012: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3013: ctxt->sax->error(ctxt->userData,
1.58 daniel 3014: "xmlParseCharRef: invalid decimal value\n");
1.59 daniel 3015: ctxt->wellFormed = 0;
1.29 daniel 3016: val = 0;
1.24 daniel 3017: break;
3018: }
1.47 daniel 3019: NEXT;
1.24 daniel 3020: }
1.55 daniel 3021: if (CUR == ';')
1.40 daniel 3022: NEXT;
1.24 daniel 3023: } else {
1.55 daniel 3024: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3025: ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid value\n");
1.59 daniel 3026: ctxt->wellFormed = 0;
1.24 daniel 3027: }
1.29 daniel 3028: /*
3029: * Check the value IS_CHAR ...
3030: */
1.44 daniel 3031: if (IS_CHAR(val)) {
3032: buf[0] = (CHAR) val;
3033: buf[1] = 0;
1.50 daniel 3034: return(xmlStrndup(buf, 1));
1.44 daniel 3035: } else {
1.55 daniel 3036: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3037: ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid CHAR value %d\n",
1.58 daniel 3038: val);
1.59 daniel 3039: ctxt->wellFormed = 0;
1.29 daniel 3040: }
1.46 daniel 3041: return(NULL);
1.24 daniel 3042: }
3043:
1.50 daniel 3044: /**
3045: * xmlParseEntityRef:
3046: * @ctxt: an XML parser context
3047: *
3048: * parse ENTITY references declarations
1.24 daniel 3049: *
3050: * [68] EntityRef ::= '&' Name ';'
1.68 daniel 3051: *
3052: * Returns the entity ref string or NULL if directly as input stream.
1.24 daniel 3053: */
1.55 daniel 3054: CHAR *
3055: xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
1.46 daniel 3056: CHAR *ret = NULL;
1.50 daniel 3057: const CHAR *q;
1.24 daniel 3058: CHAR *name;
1.72 daniel 3059: xmlEntityPtr ent = NULL;
1.50 daniel 3060: xmlParserInputPtr input = NULL;
1.24 daniel 3061:
1.50 daniel 3062: q = CUR_PTR;
1.40 daniel 3063: if (CUR == '&') {
3064: NEXT;
1.24 daniel 3065: name = xmlParseName(ctxt);
3066: if (name == NULL) {
1.55 daniel 3067: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3068: ctxt->sax->error(ctxt->userData, "xmlParseEntityRef: no name\n");
1.59 daniel 3069: ctxt->wellFormed = 0;
1.24 daniel 3070: } else {
1.40 daniel 3071: if (CUR == ';') {
3072: NEXT;
1.24 daniel 3073: /*
1.59 daniel 3074: * Well Formedness Constraint if:
3075: * - standalone
3076: * or
3077: * - no external subset and no external parameter entities
3078: * referenced
3079: * then
3080: * the entity referenced must have been declared
3081: *
1.72 daniel 3082: * TODO: to be double checked !!! This is wrong !
1.59 daniel 3083: */
1.72 daniel 3084: if (ctxt->sax != NULL) {
3085: if (ctxt->sax->getEntity != NULL)
1.74 daniel 3086: ent = ctxt->sax->getEntity(ctxt->userData, name);
1.72 daniel 3087:
3088: if (((ctxt->sax->isStandalone != NULL) &&
1.74 daniel 3089: ctxt->sax->isStandalone(ctxt->userData) == 1) ||
1.72 daniel 3090: (((ctxt->sax->hasInternalSubset == NULL) ||
1.74 daniel 3091: ctxt->sax->hasInternalSubset(ctxt->userData) == 0) &&
1.72 daniel 3092: ((ctxt->sax->hasExternalSubset == NULL) ||
1.74 daniel 3093: ctxt->sax->hasExternalSubset(ctxt->userData) == 0))) {
1.72 daniel 3094: if (ent == NULL) {
3095: if ((ctxt->sax != NULL) &&
3096: (ctxt->sax->error != NULL))
1.74 daniel 3097: ctxt->sax->error(ctxt->userData,
1.72 daniel 3098: "Entity '%s' not defined\n", name);
3099: ctxt->wellFormed = 0;
3100: }
1.59 daniel 3101: }
1.72 daniel 3102: } else
3103: ctxt->wellFormed = 0;
1.59 daniel 3104:
3105: /*
3106: * Well Formedness Constraint :
3107: * The referenced entity must be a parsed entity.
3108: */
3109: if (ent != NULL) {
3110: switch (ent->type) {
3111: case XML_INTERNAL_PARAMETER_ENTITY:
3112: case XML_EXTERNAL_PARAMETER_ENTITY:
3113: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3114: ctxt->sax->error(ctxt->userData,
1.59 daniel 3115: "Attempt to reference the parameter entity '%s'\n", name);
3116: ctxt->wellFormed = 0;
3117: break;
3118:
3119: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3120: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3121: ctxt->sax->error(ctxt->userData,
1.59 daniel 3122: "Attempt to reference unparsed entity '%s'\n", name);
3123: ctxt->wellFormed = 0;
3124: break;
3125: }
3126: }
3127:
3128: /*
3129: * Well Formedness Constraint :
3130: * The referenced entity must not lead to recursion !
3131: */
3132:
3133: /*
1.52 daniel 3134: * We parsed the entity reference correctly, call SAX
3135: * interface for the proper behaviour:
3136: * - get a new input stream
3137: * - or keep the reference inline
1.24 daniel 3138: */
1.72 daniel 3139: if ((ctxt->sax) && (ctxt->sax->resolveEntity != NULL))
1.74 daniel 3140: input = ctxt->sax->resolveEntity(ctxt->userData, NULL, name);
1.52 daniel 3141: if (input != NULL)
3142: xmlPushInput(ctxt, input);
3143: else {
3144: ret = xmlStrndup(q, CUR_PTR - q);
3145: }
1.24 daniel 3146: } else {
1.46 daniel 3147: char cst[2] = { '&', 0 };
3148:
1.55 daniel 3149: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3150: ctxt->sax->error(ctxt->userData,
1.59 daniel 3151: "xmlParseEntityRef: expecting ';'\n");
3152: ctxt->wellFormed = 0;
1.46 daniel 3153: ret = xmlStrndup(cst, 1);
3154: ret = xmlStrcat(ret, name);
1.24 daniel 3155: }
1.45 daniel 3156: free(name);
1.24 daniel 3157: }
3158: }
1.46 daniel 3159: return(ret);
1.24 daniel 3160: }
3161:
1.50 daniel 3162: /**
3163: * xmlParseReference:
3164: * @ctxt: an XML parser context
3165: *
3166: * parse Reference declarations
1.24 daniel 3167: *
3168: * [67] Reference ::= EntityRef | CharRef
1.68 daniel 3169: *
3170: * Returns the entity string or NULL if handled directly by pushing
1.52 daniel 3171: * the entity value as the input.
1.24 daniel 3172: */
1.55 daniel 3173: CHAR *
3174: xmlParseReference(xmlParserCtxtPtr ctxt) {
1.44 daniel 3175: if ((CUR == '&') && (NXT(1) == '#')) {
1.59 daniel 3176: CHAR *val = xmlParseCharRef(ctxt);
3177: xmlParserInputPtr in;
3178:
3179: if (val != NULL) {
3180: in = xmlNewStringInputStream(ctxt, val);
3181: xmlPushInput(ctxt, in);
3182: }
3183: return(NULL);
1.44 daniel 3184: } else if (CUR == '&') {
1.50 daniel 3185: return(xmlParseEntityRef(ctxt));
1.24 daniel 3186: }
1.46 daniel 3187: return(NULL);
1.24 daniel 3188: }
3189:
1.50 daniel 3190: /**
3191: * xmlParsePEReference:
3192: * @ctxt: an XML parser context
3193: *
3194: * parse PEReference declarations
1.22 daniel 3195: *
3196: * [69] PEReference ::= '%' Name ';'
1.68 daniel 3197: *
3198: * Returns the entity content or NULL if handled directly.
1.22 daniel 3199: */
1.55 daniel 3200: CHAR *
3201: xmlParsePEReference(xmlParserCtxtPtr ctxt) {
1.46 daniel 3202: CHAR *ret = NULL;
1.22 daniel 3203: CHAR *name;
1.72 daniel 3204: xmlEntityPtr entity = NULL;
1.50 daniel 3205: xmlParserInputPtr input;
1.22 daniel 3206:
1.40 daniel 3207: if (CUR == '%') {
3208: NEXT;
1.22 daniel 3209: name = xmlParseName(ctxt);
3210: if (name == NULL) {
1.55 daniel 3211: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3212: ctxt->sax->error(ctxt->userData, "xmlParsePEReference: no name\n");
1.59 daniel 3213: ctxt->wellFormed = 0;
1.22 daniel 3214: } else {
1.40 daniel 3215: if (CUR == ';') {
3216: NEXT;
1.72 daniel 3217: if ((ctxt->sax != NULL) && (ctxt->sax->getEntity != NULL))
1.74 daniel 3218: entity = ctxt->sax->getEntity(ctxt->userData, name);
1.72 daniel 3219: /* TODO !!!! Must check that it's of the proper type !!! */
1.45 daniel 3220: if (entity == NULL) {
1.55 daniel 3221: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1.74 daniel 3222: ctxt->sax->warning(ctxt->userData,
1.59 daniel 3223: "xmlParsePEReference: %%%s; not found\n", name);
1.50 daniel 3224: } else {
3225: input = xmlNewEntityInputStream(ctxt, entity);
3226: xmlPushInput(ctxt, input);
1.45 daniel 3227: }
1.22 daniel 3228: } else {
1.50 daniel 3229: char cst[2] = { '%', 0 };
1.46 daniel 3230:
1.55 daniel 3231: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3232: ctxt->sax->error(ctxt->userData,
1.59 daniel 3233: "xmlParsePEReference: expecting ';'\n");
3234: ctxt->wellFormed = 0;
1.46 daniel 3235: ret = xmlStrndup(cst, 1);
3236: ret = xmlStrcat(ret, name);
1.22 daniel 3237: }
1.45 daniel 3238: free(name);
1.3 veillard 3239: }
3240: }
1.46 daniel 3241: return(ret);
1.3 veillard 3242: }
3243:
1.50 daniel 3244: /**
3245: * xmlParseDocTypeDecl :
3246: * @ctxt: an XML parser context
3247: *
3248: * parse a DOCTYPE declaration
1.21 daniel 3249: *
1.22 daniel 3250: * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
3251: * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
1.21 daniel 3252: */
3253:
1.55 daniel 3254: void
3255: xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
1.21 daniel 3256: CHAR *name;
3257: CHAR *ExternalID = NULL;
1.39 daniel 3258: CHAR *URI = NULL;
1.21 daniel 3259:
3260: /*
3261: * We know that '<!DOCTYPE' has been detected.
3262: */
1.40 daniel 3263: SKIP(9);
1.21 daniel 3264:
1.42 daniel 3265: SKIP_BLANKS;
1.21 daniel 3266:
3267: /*
3268: * Parse the DOCTYPE name.
3269: */
3270: name = xmlParseName(ctxt);
3271: if (name == NULL) {
1.55 daniel 3272: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3273: ctxt->sax->error(ctxt->userData, "xmlParseDocTypeDecl : no DOCTYPE name !\n");
1.59 daniel 3274: ctxt->wellFormed = 0;
1.21 daniel 3275: }
3276:
1.42 daniel 3277: SKIP_BLANKS;
1.21 daniel 3278:
3279: /*
1.22 daniel 3280: * Check for SystemID and ExternalID
3281: */
1.67 daniel 3282: URI = xmlParseExternalID(ctxt, &ExternalID, 1);
1.42 daniel 3283: SKIP_BLANKS;
1.36 daniel 3284:
1.76 ! daniel 3285: /*
! 3286: * NOTE: the SAX callback may try to fetch the external subset
! 3287: * entity and fill it up !
! 3288: */
1.72 daniel 3289: if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL))
1.74 daniel 3290: ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
1.22 daniel 3291:
3292: /*
3293: * Is there any DTD definition ?
3294: */
1.40 daniel 3295: if (CUR == '[') {
3296: NEXT;
1.22 daniel 3297: /*
3298: * Parse the succession of Markup declarations and
3299: * PEReferences.
3300: * Subsequence (markupdecl | PEReference | S)*
3301: */
1.40 daniel 3302: while (CUR != ']') {
3303: const CHAR *check = CUR_PTR;
1.22 daniel 3304:
1.42 daniel 3305: SKIP_BLANKS;
1.22 daniel 3306: xmlParseMarkupDecl(ctxt);
1.50 daniel 3307: xmlParsePEReference(ctxt);
1.22 daniel 3308:
1.40 daniel 3309: if (CUR_PTR == check) {
1.55 daniel 3310: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3311: ctxt->sax->error(ctxt->userData,
1.31 daniel 3312: "xmlParseDocTypeDecl: error detected in Markup declaration\n");
1.59 daniel 3313: ctxt->wellFormed = 0;
1.22 daniel 3314: break;
3315: }
3316: }
1.40 daniel 3317: if (CUR == ']') NEXT;
1.22 daniel 3318: }
3319:
3320: /*
3321: * We should be at the end of the DOCTYPE declaration.
1.21 daniel 3322: */
1.40 daniel 3323: if (CUR != '>') {
1.55 daniel 3324: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3325: ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
1.59 daniel 3326: ctxt->wellFormed = 0;
1.22 daniel 3327: /* We shouldn't try to resynchronize ... */
1.21 daniel 3328: }
1.40 daniel 3329: NEXT;
1.22 daniel 3330:
3331: /*
3332: * Cleanup, since we don't use all those identifiers
3333: * TODO : the DOCTYPE if available should be stored !
3334: */
1.39 daniel 3335: if (URI != NULL) free(URI);
1.22 daniel 3336: if (ExternalID != NULL) free(ExternalID);
3337: if (name != NULL) free(name);
1.21 daniel 3338: }
3339:
1.50 daniel 3340: /**
3341: * xmlParseAttribute:
3342: * @ctxt: an XML parser context
1.72 daniel 3343: * @value: a CHAR ** used to store the value of the attribute
1.50 daniel 3344: *
3345: * parse an attribute
1.3 veillard 3346: *
1.22 daniel 3347: * [41] Attribute ::= Name Eq AttValue
3348: *
3349: * [25] Eq ::= S? '=' S?
3350: *
1.29 daniel 3351: * With namespace:
3352: *
3353: * [NS 11] Attribute ::= QName Eq AttValue
1.43 daniel 3354: *
3355: * Also the case QName == xmlns:??? is handled independently as a namespace
3356: * definition.
1.69 daniel 3357: *
1.72 daniel 3358: * Returns the attribute name, and the value in *value.
1.3 veillard 3359: */
3360:
1.72 daniel 3361: CHAR *
3362: xmlParseAttribute(xmlParserCtxtPtr ctxt, CHAR **value) {
1.59 daniel 3363: CHAR *name, *val;
1.3 veillard 3364:
1.72 daniel 3365: *value = NULL;
3366: name = xmlParseName(ctxt);
1.22 daniel 3367: if (name == NULL) {
1.55 daniel 3368: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3369: ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
1.59 daniel 3370: ctxt->wellFormed = 0;
1.52 daniel 3371: return(NULL);
1.3 veillard 3372: }
3373:
3374: /*
1.29 daniel 3375: * read the value
1.3 veillard 3376: */
1.42 daniel 3377: SKIP_BLANKS;
1.40 daniel 3378: if (CUR == '=') {
3379: NEXT;
1.42 daniel 3380: SKIP_BLANKS;
1.72 daniel 3381: val = xmlParseAttValue(ctxt);
1.29 daniel 3382: } else {
1.55 daniel 3383: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3384: ctxt->sax->error(ctxt->userData,
1.59 daniel 3385: "Specification mandate value for attribute %s\n", name);
3386: ctxt->wellFormed = 0;
1.52 daniel 3387: return(NULL);
1.43 daniel 3388: }
3389:
1.72 daniel 3390: *value = val;
3391: return(name);
1.3 veillard 3392: }
3393:
1.50 daniel 3394: /**
3395: * xmlParseStartTag:
3396: * @ctxt: an XML parser context
3397: *
3398: * parse a start of tag either for rule element or
3399: * EmptyElement. In both case we don't parse the tag closing chars.
1.27 daniel 3400: *
3401: * [40] STag ::= '<' Name (S Attribute)* S? '>'
3402: *
1.29 daniel 3403: * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
3404: *
3405: * With namespace:
3406: *
3407: * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
3408: *
3409: * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
1.2 veillard 3410: */
3411:
1.72 daniel 3412: void
1.69 daniel 3413: xmlParseStartTag(xmlParserCtxtPtr ctxt) {
1.72 daniel 3414: CHAR *name;
3415: CHAR *attname;
3416: CHAR *attvalue;
3417: const CHAR **atts = NULL;
3418: int nbatts = 0;
3419: int maxatts = 0;
3420: int i;
1.2 veillard 3421:
1.72 daniel 3422: if (CUR != '<') return;
1.40 daniel 3423: NEXT;
1.3 veillard 3424:
1.72 daniel 3425: name = xmlParseName(ctxt);
1.59 daniel 3426: if (name == NULL) {
3427: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3428: ctxt->sax->error(ctxt->userData,
1.59 daniel 3429: "xmlParseStartTag: invalid element name\n");
3430: ctxt->wellFormed = 0;
1.72 daniel 3431: return;
1.50 daniel 3432: }
3433:
3434: /*
1.3 veillard 3435: * Now parse the attributes, it ends up with the ending
3436: *
3437: * (S Attribute)* S?
3438: */
1.42 daniel 3439: SKIP_BLANKS;
1.40 daniel 3440: while ((IS_CHAR(CUR)) &&
3441: (CUR != '>') &&
3442: ((CUR != '/') || (NXT(1) != '>'))) {
3443: const CHAR *q = CUR_PTR;
1.29 daniel 3444:
1.72 daniel 3445: attname = xmlParseAttribute(ctxt, &attvalue);
3446: if ((attname != NULL) && (attvalue != NULL)) {
3447: /*
3448: * Well formedness requires at most one declaration of an attribute
3449: */
3450: for (i = 0; i < nbatts;i += 2) {
3451: if (!xmlStrcmp(atts[i], attname)) {
3452: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3453: ctxt->sax->error(ctxt->userData, "Attribute %s redefined\n",
1.72 daniel 3454: name);
3455: ctxt->wellFormed = 0;
3456: free(attname);
3457: free(attvalue);
3458: break;
3459: }
3460: }
3461:
3462: /*
3463: * Add the pair to atts
3464: */
3465: if (atts == NULL) {
3466: maxatts = 10;
3467: atts = (const CHAR **) malloc(maxatts * sizeof(CHAR *));
3468: if (atts == NULL) {
3469: fprintf(stderr, "malloc of %d byte failed\n",
3470: maxatts * sizeof(CHAR *));
3471: return;
3472: }
3473: } else if (nbatts + 2 < maxatts) {
3474: maxatts *= 2;
3475: atts = (const CHAR **) realloc(atts, maxatts * sizeof(CHAR *));
3476: if (atts == NULL) {
3477: fprintf(stderr, "realloc of %d byte failed\n",
3478: maxatts * sizeof(CHAR *));
3479: return;
3480: }
3481: }
3482: atts[nbatts++] = attname;
3483: atts[nbatts++] = attvalue;
3484: atts[nbatts] = NULL;
3485: atts[nbatts + 1] = NULL;
3486: }
3487:
1.42 daniel 3488: SKIP_BLANKS;
1.40 daniel 3489: if (q == CUR_PTR) {
1.55 daniel 3490: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3491: ctxt->sax->error(ctxt->userData,
1.31 daniel 3492: "xmlParseStartTag: problem parsing attributes\n");
1.59 daniel 3493: ctxt->wellFormed = 0;
1.29 daniel 3494: break;
1.3 veillard 3495: }
3496: }
3497:
1.43 daniel 3498: /*
1.72 daniel 3499: * SAX: Start of Element !
1.43 daniel 3500: */
1.72 daniel 3501: if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
1.74 daniel 3502: ctxt->sax->startElement(ctxt->userData, name, atts);
1.43 daniel 3503:
1.52 daniel 3504: free(name);
1.72 daniel 3505: if (atts != NULL) {
3506: for (i = 0;i < nbatts;i++) free((CHAR *) atts[i]);
3507: free(atts);
3508: }
1.3 veillard 3509: }
3510:
1.50 daniel 3511: /**
3512: * xmlParseEndTag:
3513: * @ctxt: an XML parser context
3514: *
3515: * parse an end of tag
1.27 daniel 3516: *
3517: * [42] ETag ::= '</' Name S? '>'
1.29 daniel 3518: *
3519: * With namespace
3520: *
1.72 daniel 3521: * [NS 9] ETag ::= '</' QName S? '>'
1.7 veillard 3522: */
3523:
1.55 daniel 3524: void
1.72 daniel 3525: xmlParseEndTag(xmlParserCtxtPtr ctxt) {
3526: CHAR *name;
1.7 veillard 3527:
1.40 daniel 3528: if ((CUR != '<') || (NXT(1) != '/')) {
1.55 daniel 3529: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3530: ctxt->sax->error(ctxt->userData, "xmlParseEndTag: '</' not found\n");
1.59 daniel 3531: ctxt->wellFormed = 0;
1.27 daniel 3532: return;
3533: }
1.40 daniel 3534: SKIP(2);
1.7 veillard 3535:
1.72 daniel 3536: name = xmlParseName(ctxt);
1.7 veillard 3537:
3538: /*
3539: * We should definitely be at the ending "S? '>'" part
3540: */
1.42 daniel 3541: SKIP_BLANKS;
1.40 daniel 3542: if ((!IS_CHAR(CUR)) || (CUR != '>')) {
1.55 daniel 3543: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3544: ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
1.59 daniel 3545: ctxt->wellFormed = 0;
1.7 veillard 3546: } else
1.40 daniel 3547: NEXT;
1.7 veillard 3548:
1.72 daniel 3549: /*
3550: * SAX: End of Tag
3551: */
3552: if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
1.74 daniel 3553: ctxt->sax->endElement(ctxt->userData, name);
1.72 daniel 3554:
3555: if (name != NULL)
3556: free(name);
3557:
1.7 veillard 3558: return;
3559: }
3560:
1.50 daniel 3561: /**
3562: * xmlParseCDSect:
3563: * @ctxt: an XML parser context
3564: *
3565: * Parse escaped pure raw content.
1.29 daniel 3566: *
3567: * [18] CDSect ::= CDStart CData CDEnd
3568: *
3569: * [19] CDStart ::= '<![CDATA['
3570: *
3571: * [20] Data ::= (Char* - (Char* ']]>' Char*))
3572: *
3573: * [21] CDEnd ::= ']]>'
1.3 veillard 3574: */
1.55 daniel 3575: void
3576: xmlParseCDSect(xmlParserCtxtPtr ctxt) {
1.17 daniel 3577: const CHAR *r, *s, *base;
1.3 veillard 3578:
1.40 daniel 3579: if ((CUR == '<') && (NXT(1) == '!') &&
3580: (NXT(2) == '[') && (NXT(3) == 'C') &&
3581: (NXT(4) == 'D') && (NXT(5) == 'A') &&
3582: (NXT(6) == 'T') && (NXT(7) == 'A') &&
3583: (NXT(8) == '[')) {
3584: SKIP(9);
1.29 daniel 3585: } else
1.45 daniel 3586: return;
1.40 daniel 3587: base = CUR_PTR;
3588: if (!IS_CHAR(CUR)) {
1.55 daniel 3589: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3590: ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
1.59 daniel 3591: ctxt->wellFormed = 0;
1.45 daniel 3592: return;
1.3 veillard 3593: }
1.40 daniel 3594: r = NEXT;
3595: if (!IS_CHAR(CUR)) {
1.55 daniel 3596: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3597: ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
1.59 daniel 3598: ctxt->wellFormed = 0;
1.45 daniel 3599: return;
1.3 veillard 3600: }
1.40 daniel 3601: s = NEXT;
3602: while (IS_CHAR(CUR) &&
3603: ((*r != ']') || (*s != ']') || (CUR != '>'))) {
3604: r++;s++;NEXT;
1.3 veillard 3605: }
1.40 daniel 3606: if (!IS_CHAR(CUR)) {
1.55 daniel 3607: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3608: ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
1.59 daniel 3609: ctxt->wellFormed = 0;
1.45 daniel 3610: return;
1.3 veillard 3611: }
1.16 daniel 3612:
1.45 daniel 3613: /*
3614: * Ok the segment [base CUR_PTR] is to be consumed as chars.
3615: */
3616: if (ctxt->sax != NULL) {
1.72 daniel 3617: if (areBlanks(ctxt, base, CUR_PTR - base)) {
3618: if (ctxt->sax->ignorableWhitespace != NULL)
1.74 daniel 3619: ctxt->sax->ignorableWhitespace(ctxt->userData, base,
1.72 daniel 3620: (CUR_PTR - base) - 2);
3621: } else {
3622: if (ctxt->sax->characters != NULL)
1.74 daniel 3623: ctxt->sax->characters(ctxt->userData, base, (CUR_PTR - base) - 2);
1.72 daniel 3624: }
1.45 daniel 3625: }
1.2 veillard 3626: }
3627:
1.50 daniel 3628: /**
3629: * xmlParseContent:
3630: * @ctxt: an XML parser context
3631: *
3632: * Parse a content:
1.2 veillard 3633: *
1.27 daniel 3634: * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
1.2 veillard 3635: */
3636:
1.55 daniel 3637: void
3638: xmlParseContent(xmlParserCtxtPtr ctxt) {
1.40 daniel 3639: while ((CUR != '<') || (NXT(1) != '/')) {
3640: const CHAR *test = CUR_PTR;
1.27 daniel 3641:
3642: /*
3643: * First case : a Processing Instruction.
3644: */
1.40 daniel 3645: if ((CUR == '<') && (NXT(1) == '?')) {
1.27 daniel 3646: xmlParsePI(ctxt);
3647: }
1.72 daniel 3648:
1.27 daniel 3649: /*
3650: * Second case : a CDSection
3651: */
1.40 daniel 3652: else if ((CUR == '<') && (NXT(1) == '!') &&
3653: (NXT(2) == '[') && (NXT(3) == 'C') &&
3654: (NXT(4) == 'D') && (NXT(5) == 'A') &&
3655: (NXT(6) == 'T') && (NXT(7) == 'A') &&
3656: (NXT(8) == '[')) {
1.45 daniel 3657: xmlParseCDSect(ctxt);
1.27 daniel 3658: }
1.72 daniel 3659:
1.27 daniel 3660: /*
3661: * Third case : a comment
3662: */
1.40 daniel 3663: else if ((CUR == '<') && (NXT(1) == '!') &&
3664: (NXT(2) == '-') && (NXT(3) == '-')) {
1.72 daniel 3665: xmlParseComment(ctxt, 1);
1.27 daniel 3666: }
1.72 daniel 3667:
1.27 daniel 3668: /*
3669: * Fourth case : a sub-element.
3670: */
1.40 daniel 3671: else if (CUR == '<') {
1.72 daniel 3672: xmlParseElement(ctxt);
1.45 daniel 3673: }
1.72 daniel 3674:
1.45 daniel 3675: /*
1.50 daniel 3676: * Fifth case : a reference. If if has not been resolved,
3677: * parsing returns it's Name, create the node
1.45 daniel 3678: */
3679: else if (CUR == '&') {
1.50 daniel 3680: CHAR *val = xmlParseReference(ctxt);
3681: if (val != NULL) {
3682: if (val[0] != '&') {
3683: /*
3684: * inline predefined entity.
3685: */
1.72 daniel 3686: if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
1.74 daniel 3687: ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val));
1.50 daniel 3688: } else {
3689: /*
3690: * user defined entity, create a node.
3691: */
1.72 daniel 3692: if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL))
1.74 daniel 3693: ctxt->sax->reference(ctxt->userData, val);
1.50 daniel 3694: }
3695: free(val);
3696: }
1.27 daniel 3697: }
1.72 daniel 3698:
1.27 daniel 3699: /*
3700: * Last case, text. Note that References are handled directly.
3701: */
3702: else {
1.45 daniel 3703: xmlParseCharData(ctxt, 0);
1.3 veillard 3704: }
1.14 veillard 3705:
3706: /*
1.45 daniel 3707: * Pop-up of finished entities.
1.14 veillard 3708: */
1.69 daniel 3709: while ((CUR == 0) && (ctxt->inputNr > 1))
3710: xmlPopInput(ctxt);
1.45 daniel 3711:
1.40 daniel 3712: if (test == CUR_PTR) {
1.55 daniel 3713: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3714: ctxt->sax->error(ctxt->userData,
1.59 daniel 3715: "detected an error in element content\n");
3716: ctxt->wellFormed = 0;
1.29 daniel 3717: break;
3718: }
1.3 veillard 3719: }
1.2 veillard 3720: }
3721:
1.50 daniel 3722: /**
3723: * xmlParseElement:
3724: * @ctxt: an XML parser context
3725: *
3726: * parse an XML element, this is highly recursive
1.26 daniel 3727: *
3728: * [39] element ::= EmptyElemTag | STag content ETag
3729: *
3730: * [41] Attribute ::= Name Eq AttValue
1.2 veillard 3731: */
1.26 daniel 3732:
1.72 daniel 3733: void
1.69 daniel 3734: xmlParseElement(xmlParserCtxtPtr ctxt) {
1.40 daniel 3735: const CHAR *openTag = CUR_PTR;
1.32 daniel 3736: xmlParserNodeInfo node_info;
1.2 veillard 3737:
1.32 daniel 3738: /* Capture start position */
1.40 daniel 3739: node_info.begin_pos = CUR_PTR - ctxt->input->base;
3740: node_info.begin_line = ctxt->input->line;
1.32 daniel 3741:
1.72 daniel 3742: xmlParseStartTag(ctxt);
1.2 veillard 3743:
3744: /*
3745: * Check for an Empty Element.
3746: */
1.40 daniel 3747: if ((CUR == '/') && (NXT(1) == '>')) {
3748: SKIP(2);
1.72 daniel 3749: if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
1.74 daniel 3750: ctxt->sax->endElement(ctxt->userData, NULL);
1.72 daniel 3751: return;
1.2 veillard 3752: }
1.40 daniel 3753: if (CUR == '>') NEXT;
1.2 veillard 3754: else {
1.55 daniel 3755: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3756: ctxt->sax->error(ctxt->userData, "Couldn't find end of Start Tag\n%.30s\n",
1.57 daniel 3757: openTag);
1.59 daniel 3758: ctxt->wellFormed = 0;
1.45 daniel 3759:
3760: /*
3761: * end of parsing of this node.
1.72 daniel 3762: * TODO !!!!!!!! check the macro in case of non DOM parsing
1.45 daniel 3763: */
3764: nodePop(ctxt);
3765:
1.72 daniel 3766: return;
1.2 veillard 3767: }
3768:
3769: /*
3770: * Parse the content of the element:
3771: */
1.45 daniel 3772: xmlParseContent(ctxt);
1.40 daniel 3773: if (!IS_CHAR(CUR)) {
1.55 daniel 3774: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3775: ctxt->sax->error(ctxt->userData,
1.57 daniel 3776: "Premature end of data in tag %.30s\n", openTag);
1.59 daniel 3777: ctxt->wellFormed = 0;
1.45 daniel 3778:
3779: /*
3780: * end of parsing of this node.
1.72 daniel 3781: * TODO !!!!!!!! check the macro in case of non DOM parsing
1.45 daniel 3782: */
3783: nodePop(ctxt);
3784:
1.72 daniel 3785: return;
1.2 veillard 3786: }
3787:
3788: /*
1.27 daniel 3789: * parse the end of tag: '</' should be here.
1.2 veillard 3790: */
1.72 daniel 3791: xmlParseEndTag(ctxt);
1.2 veillard 3792: }
3793:
1.50 daniel 3794: /**
3795: * xmlParseVersionNum:
3796: * @ctxt: an XML parser context
3797: *
3798: * parse the XML version value.
1.29 daniel 3799: *
3800: * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
1.68 daniel 3801: *
3802: * Returns the string giving the XML version number, or NULL
1.29 daniel 3803: */
1.55 daniel 3804: CHAR *
3805: xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
1.40 daniel 3806: const CHAR *q = CUR_PTR;
1.29 daniel 3807: CHAR *ret;
3808:
1.40 daniel 3809: while (IS_CHAR(CUR) &&
3810: (((CUR >= 'a') && (CUR <= 'z')) ||
3811: ((CUR >= 'A') && (CUR <= 'Z')) ||
3812: ((CUR >= '0') && (CUR <= '9')) ||
3813: (CUR == '_') || (CUR == '.') ||
3814: (CUR == ':') || (CUR == '-'))) NEXT;
3815: ret = xmlStrndup(q, CUR_PTR - q);
1.29 daniel 3816: return(ret);
3817: }
3818:
1.50 daniel 3819: /**
3820: * xmlParseVersionInfo:
3821: * @ctxt: an XML parser context
3822: *
3823: * parse the XML version.
1.29 daniel 3824: *
3825: * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
3826: *
3827: * [25] Eq ::= S? '=' S?
1.50 daniel 3828: *
1.68 daniel 3829: * Returns the version string, e.g. "1.0"
1.29 daniel 3830: */
3831:
1.55 daniel 3832: CHAR *
3833: xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
1.29 daniel 3834: CHAR *version = NULL;
3835: const CHAR *q;
3836:
1.40 daniel 3837: if ((CUR == 'v') && (NXT(1) == 'e') &&
3838: (NXT(2) == 'r') && (NXT(3) == 's') &&
3839: (NXT(4) == 'i') && (NXT(5) == 'o') &&
3840: (NXT(6) == 'n')) {
3841: SKIP(7);
1.42 daniel 3842: SKIP_BLANKS;
1.40 daniel 3843: if (CUR != '=') {
1.55 daniel 3844: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3845: ctxt->sax->error(ctxt->userData, "xmlParseVersionInfo : expected '='\n");
1.59 daniel 3846: ctxt->wellFormed = 0;
1.31 daniel 3847: return(NULL);
3848: }
1.40 daniel 3849: NEXT;
1.42 daniel 3850: SKIP_BLANKS;
1.40 daniel 3851: if (CUR == '"') {
3852: NEXT;
3853: q = CUR_PTR;
1.29 daniel 3854: version = xmlParseVersionNum(ctxt);
1.55 daniel 3855: if (CUR != '"') {
3856: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3857: ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59 daniel 3858: ctxt->wellFormed = 0;
1.55 daniel 3859: } else
1.40 daniel 3860: NEXT;
3861: } else if (CUR == '\''){
3862: NEXT;
3863: q = CUR_PTR;
1.29 daniel 3864: version = xmlParseVersionNum(ctxt);
1.55 daniel 3865: if (CUR != '\'') {
3866: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3867: ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59 daniel 3868: ctxt->wellFormed = 0;
1.55 daniel 3869: } else
1.40 daniel 3870: NEXT;
1.31 daniel 3871: } else {
1.55 daniel 3872: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3873: ctxt->sax->error(ctxt->userData,
1.59 daniel 3874: "xmlParseVersionInfo : expected ' or \"\n");
3875: ctxt->wellFormed = 0;
1.29 daniel 3876: }
3877: }
3878: return(version);
3879: }
3880:
1.50 daniel 3881: /**
3882: * xmlParseEncName:
3883: * @ctxt: an XML parser context
3884: *
3885: * parse the XML encoding name
1.29 daniel 3886: *
3887: * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
1.50 daniel 3888: *
1.68 daniel 3889: * Returns the encoding name value or NULL
1.29 daniel 3890: */
1.55 daniel 3891: CHAR *
3892: xmlParseEncName(xmlParserCtxtPtr ctxt) {
1.40 daniel 3893: const CHAR *q = CUR_PTR;
1.29 daniel 3894: CHAR *ret = NULL;
3895:
1.40 daniel 3896: if (((CUR >= 'a') && (CUR <= 'z')) ||
3897: ((CUR >= 'A') && (CUR <= 'Z'))) {
3898: NEXT;
3899: while (IS_CHAR(CUR) &&
3900: (((CUR >= 'a') && (CUR <= 'z')) ||
3901: ((CUR >= 'A') && (CUR <= 'Z')) ||
3902: ((CUR >= '0') && (CUR <= '9')) ||
3903: (CUR == '-'))) NEXT;
3904: ret = xmlStrndup(q, CUR_PTR - q);
1.29 daniel 3905: } else {
1.55 daniel 3906: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3907: ctxt->sax->error(ctxt->userData, "Invalid XML encoding name\n");
1.59 daniel 3908: ctxt->wellFormed = 0;
1.29 daniel 3909: }
3910: return(ret);
3911: }
3912:
1.50 daniel 3913: /**
3914: * xmlParseEncodingDecl:
3915: * @ctxt: an XML parser context
3916: *
3917: * parse the XML encoding declaration
1.29 daniel 3918: *
3919: * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'")
1.50 daniel 3920: *
3921: * TODO: this should setup the conversion filters.
3922: *
1.68 daniel 3923: * Returns the encoding value or NULL
1.29 daniel 3924: */
3925:
1.55 daniel 3926: CHAR *
3927: xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
1.29 daniel 3928: CHAR *encoding = NULL;
3929: const CHAR *q;
3930:
1.42 daniel 3931: SKIP_BLANKS;
1.40 daniel 3932: if ((CUR == 'e') && (NXT(1) == 'n') &&
3933: (NXT(2) == 'c') && (NXT(3) == 'o') &&
3934: (NXT(4) == 'd') && (NXT(5) == 'i') &&
3935: (NXT(6) == 'n') && (NXT(7) == 'g')) {
3936: SKIP(8);
1.42 daniel 3937: SKIP_BLANKS;
1.40 daniel 3938: if (CUR != '=') {
1.55 daniel 3939: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3940: ctxt->sax->error(ctxt->userData, "xmlParseEncodingDecl : expected '='\n");
1.59 daniel 3941: ctxt->wellFormed = 0;
1.31 daniel 3942: return(NULL);
3943: }
1.40 daniel 3944: NEXT;
1.42 daniel 3945: SKIP_BLANKS;
1.40 daniel 3946: if (CUR == '"') {
3947: NEXT;
3948: q = CUR_PTR;
1.29 daniel 3949: encoding = xmlParseEncName(ctxt);
1.55 daniel 3950: if (CUR != '"') {
3951: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3952: ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59 daniel 3953: ctxt->wellFormed = 0;
1.55 daniel 3954: } else
1.40 daniel 3955: NEXT;
3956: } else if (CUR == '\''){
3957: NEXT;
3958: q = CUR_PTR;
1.29 daniel 3959: encoding = xmlParseEncName(ctxt);
1.55 daniel 3960: if (CUR != '\'') {
3961: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3962: ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59 daniel 3963: ctxt->wellFormed = 0;
1.55 daniel 3964: } else
1.40 daniel 3965: NEXT;
3966: } else if (CUR == '"'){
1.55 daniel 3967: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3968: ctxt->sax->error(ctxt->userData,
1.59 daniel 3969: "xmlParseEncodingDecl : expected ' or \"\n");
3970: ctxt->wellFormed = 0;
1.29 daniel 3971: }
3972: }
3973: return(encoding);
3974: }
3975:
1.50 daniel 3976: /**
3977: * xmlParseSDDecl:
3978: * @ctxt: an XML parser context
3979: *
3980: * parse the XML standalone declaration
1.29 daniel 3981: *
3982: * [32] SDDecl ::= S 'standalone' Eq
3983: * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"'))
1.68 daniel 3984: *
3985: * Returns 1 if standalone, 0 otherwise
1.29 daniel 3986: */
3987:
1.55 daniel 3988: int
3989: xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
1.29 daniel 3990: int standalone = -1;
3991:
1.42 daniel 3992: SKIP_BLANKS;
1.40 daniel 3993: if ((CUR == 's') && (NXT(1) == 't') &&
3994: (NXT(2) == 'a') && (NXT(3) == 'n') &&
3995: (NXT(4) == 'd') && (NXT(5) == 'a') &&
3996: (NXT(6) == 'l') && (NXT(7) == 'o') &&
3997: (NXT(8) == 'n') && (NXT(9) == 'e')) {
3998: SKIP(10);
3999: if (CUR != '=') {
1.55 daniel 4000: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4001: ctxt->sax->error(ctxt->userData,
1.59 daniel 4002: "XML standalone declaration : expected '='\n");
4003: ctxt->wellFormed = 0;
1.32 daniel 4004: return(standalone);
4005: }
1.40 daniel 4006: NEXT;
1.42 daniel 4007: SKIP_BLANKS;
1.40 daniel 4008: if (CUR == '\''){
4009: NEXT;
4010: if ((CUR == 'n') && (NXT(1) == 'o')) {
1.29 daniel 4011: standalone = 0;
1.40 daniel 4012: SKIP(2);
4013: } else if ((CUR == 'y') && (NXT(1) == 'e') &&
4014: (NXT(2) == 's')) {
1.29 daniel 4015: standalone = 1;
1.40 daniel 4016: SKIP(3);
1.29 daniel 4017: } else {
1.55 daniel 4018: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4019: ctxt->sax->error(ctxt->userData, "standalone accepts only 'yes' or 'no'\n");
1.59 daniel 4020: ctxt->wellFormed = 0;
1.29 daniel 4021: }
1.55 daniel 4022: if (CUR != '\'') {
4023: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4024: ctxt->sax->error(ctxt->userData, "String not closed\n");
1.59 daniel 4025: ctxt->wellFormed = 0;
1.55 daniel 4026: } else
1.40 daniel 4027: NEXT;
4028: } else if (CUR == '"'){
4029: NEXT;
4030: if ((CUR == 'n') && (NXT(1) == 'o')) {
1.29 daniel 4031: standalone = 0;
1.40 daniel 4032: SKIP(2);
4033: } else if ((CUR == 'y') && (NXT(1) == 'e') &&
4034: (NXT(2) == 's')) {
1.29 daniel 4035: standalone = 1;
1.40 daniel 4036: SKIP(3);
1.29 daniel 4037: } else {
1.55 daniel 4038: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4039: ctxt->sax->error(ctxt->userData,
1.59 daniel 4040: "standalone accepts only 'yes' or 'no'\n");
4041: ctxt->wellFormed = 0;
1.29 daniel 4042: }
1.55 daniel 4043: if (CUR != '"') {
4044: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4045: ctxt->sax->error(ctxt->userData, "String not closed\n");
1.59 daniel 4046: ctxt->wellFormed = 0;
1.55 daniel 4047: } else
1.40 daniel 4048: NEXT;
1.37 daniel 4049: } else {
1.55 daniel 4050: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4051: ctxt->sax->error(ctxt->userData, "Standalone value not found\n");
1.59 daniel 4052: ctxt->wellFormed = 0;
1.37 daniel 4053: }
1.29 daniel 4054: }
4055: return(standalone);
4056: }
4057:
1.50 daniel 4058: /**
4059: * xmlParseXMLDecl:
4060: * @ctxt: an XML parser context
4061: *
4062: * parse an XML declaration header
1.29 daniel 4063: *
4064: * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
1.1 veillard 4065: */
4066:
1.55 daniel 4067: void
4068: xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
1.1 veillard 4069: CHAR *version;
4070:
4071: /*
1.19 daniel 4072: * We know that '<?xml' is here.
1.1 veillard 4073: */
1.40 daniel 4074: SKIP(5);
1.1 veillard 4075:
1.59 daniel 4076: if (!IS_BLANK(CUR)) {
4077: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4078: ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
1.59 daniel 4079: ctxt->wellFormed = 0;
4080: }
1.42 daniel 4081: SKIP_BLANKS;
1.1 veillard 4082:
4083: /*
1.29 daniel 4084: * We should have the VersionInfo here.
1.1 veillard 4085: */
1.29 daniel 4086: version = xmlParseVersionInfo(ctxt);
4087: if (version == NULL)
1.45 daniel 4088: version = xmlCharStrdup(XML_DEFAULT_VERSION);
1.72 daniel 4089: ctxt->version = xmlStrdup(version);
1.45 daniel 4090: free(version);
1.29 daniel 4091:
4092: /*
4093: * We may have the encoding declaration
4094: */
1.59 daniel 4095: if (!IS_BLANK(CUR)) {
4096: if ((CUR == '?') && (NXT(1) == '>')) {
4097: SKIP(2);
4098: return;
4099: }
4100: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4101: ctxt->sax->error(ctxt->userData, "Blank needed here\n");
1.59 daniel 4102: ctxt->wellFormed = 0;
4103: }
1.72 daniel 4104: ctxt->encoding = xmlParseEncodingDecl(ctxt);
1.1 veillard 4105:
4106: /*
1.29 daniel 4107: * We may have the standalone status.
1.1 veillard 4108: */
1.72 daniel 4109: if ((ctxt->encoding != NULL) && (!IS_BLANK(CUR))) {
1.59 daniel 4110: if ((CUR == '?') && (NXT(1) == '>')) {
4111: SKIP(2);
4112: return;
4113: }
4114: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4115: ctxt->sax->error(ctxt->userData, "Blank needed here\n");
1.59 daniel 4116: ctxt->wellFormed = 0;
4117: }
4118: SKIP_BLANKS;
1.72 daniel 4119: ctxt->standalone = xmlParseSDDecl(ctxt);
1.1 veillard 4120:
1.42 daniel 4121: SKIP_BLANKS;
1.40 daniel 4122: if ((CUR == '?') && (NXT(1) == '>')) {
4123: SKIP(2);
4124: } else if (CUR == '>') {
1.31 daniel 4125: /* Deprecated old WD ... */
1.55 daniel 4126: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4127: ctxt->sax->error(ctxt->userData, "XML declaration must end-up with '?>'\n");
1.59 daniel 4128: ctxt->wellFormed = 0;
1.40 daniel 4129: NEXT;
1.29 daniel 4130: } else {
1.55 daniel 4131: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4132: ctxt->sax->error(ctxt->userData, "parsing XML declaration: '?>' expected\n");
1.59 daniel 4133: ctxt->wellFormed = 0;
1.40 daniel 4134: MOVETO_ENDTAG(CUR_PTR);
4135: NEXT;
1.29 daniel 4136: }
1.1 veillard 4137: }
4138:
1.50 daniel 4139: /**
4140: * xmlParseMisc:
4141: * @ctxt: an XML parser context
4142: *
4143: * parse an XML Misc* optionnal field.
1.21 daniel 4144: *
1.22 daniel 4145: * [27] Misc ::= Comment | PI | S
1.1 veillard 4146: */
4147:
1.55 daniel 4148: void
4149: xmlParseMisc(xmlParserCtxtPtr ctxt) {
1.40 daniel 4150: while (((CUR == '<') && (NXT(1) == '?')) ||
4151: ((CUR == '<') && (NXT(1) == '!') &&
4152: (NXT(2) == '-') && (NXT(3) == '-')) ||
4153: IS_BLANK(CUR)) {
4154: if ((CUR == '<') && (NXT(1) == '?')) {
1.16 daniel 4155: xmlParsePI(ctxt);
1.40 daniel 4156: } else if (IS_BLANK(CUR)) {
4157: NEXT;
1.1 veillard 4158: } else
1.31 daniel 4159: xmlParseComment(ctxt, 0);
1.1 veillard 4160: }
4161: }
4162:
1.50 daniel 4163: /**
4164: * xmlParseDocument :
4165: * @ctxt: an XML parser context
4166: *
4167: * parse an XML document (and build a tree if using the standard SAX
4168: * interface).
1.21 daniel 4169: *
1.22 daniel 4170: * [1] document ::= prolog element Misc*
1.29 daniel 4171: *
4172: * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
1.50 daniel 4173: *
1.68 daniel 4174: * Returns 0, -1 in case of error. the parser context is augmented
1.50 daniel 4175: * as a result of the parsing.
1.1 veillard 4176: */
4177:
1.55 daniel 4178: int
4179: xmlParseDocument(xmlParserCtxtPtr ctxt) {
1.45 daniel 4180: xmlDefaultSAXHandlerInit();
4181:
1.14 veillard 4182: /*
1.44 daniel 4183: * SAX: beginning of the document processing.
4184: */
1.72 daniel 4185: if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
1.74 daniel 4186: ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
1.44 daniel 4187:
4188: /*
1.14 veillard 4189: * We should check for encoding here and plug-in some
4190: * conversion code TODO !!!!
4191: */
1.1 veillard 4192:
4193: /*
4194: * Wipe out everything which is before the first '<'
4195: */
1.59 daniel 4196: if (IS_BLANK(CUR)) {
4197: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4198: ctxt->sax->error(ctxt->userData,
1.59 daniel 4199: "Extra spaces at the beginning of the document are not allowed\n");
4200: ctxt->wellFormed = 0;
4201: SKIP_BLANKS;
4202: }
4203:
4204: if (CUR == 0) {
4205: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4206: ctxt->sax->error(ctxt->userData, "Document is empty\n");
1.59 daniel 4207: ctxt->wellFormed = 0;
4208: }
1.1 veillard 4209:
4210: /*
4211: * Check for the XMLDecl in the Prolog.
4212: */
1.40 daniel 4213: if ((CUR == '<') && (NXT(1) == '?') &&
4214: (NXT(2) == 'x') && (NXT(3) == 'm') &&
4215: (NXT(4) == 'l')) {
1.19 daniel 4216: xmlParseXMLDecl(ctxt);
4217: /* SKIP_EOL(cur); */
1.42 daniel 4218: SKIP_BLANKS;
1.40 daniel 4219: } else if ((CUR == '<') && (NXT(1) == '?') &&
4220: (NXT(2) == 'X') && (NXT(3) == 'M') &&
4221: (NXT(4) == 'L')) {
1.19 daniel 4222: /*
4223: * The first drafts were using <?XML and the final W3C REC
4224: * now use <?xml ...
4225: */
1.16 daniel 4226: xmlParseXMLDecl(ctxt);
1.1 veillard 4227: /* SKIP_EOL(cur); */
1.42 daniel 4228: SKIP_BLANKS;
1.1 veillard 4229: } else {
1.72 daniel 4230: ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
1.1 veillard 4231: }
1.72 daniel 4232: if ((ctxt->sax) && (ctxt->sax->startDocument))
1.74 daniel 4233: ctxt->sax->startDocument(ctxt->userData);
1.1 veillard 4234:
4235: /*
4236: * The Misc part of the Prolog
4237: */
1.16 daniel 4238: xmlParseMisc(ctxt);
1.1 veillard 4239:
4240: /*
1.29 daniel 4241: * Then possibly doc type declaration(s) and more Misc
1.21 daniel 4242: * (doctypedecl Misc*)?
4243: */
1.40 daniel 4244: if ((CUR == '<') && (NXT(1) == '!') &&
4245: (NXT(2) == 'D') && (NXT(3) == 'O') &&
4246: (NXT(4) == 'C') && (NXT(5) == 'T') &&
4247: (NXT(6) == 'Y') && (NXT(7) == 'P') &&
4248: (NXT(8) == 'E')) {
1.22 daniel 4249: xmlParseDocTypeDecl(ctxt);
4250: xmlParseMisc(ctxt);
1.21 daniel 4251: }
4252:
4253: /*
4254: * Time to start parsing the tree itself
1.1 veillard 4255: */
1.72 daniel 4256: xmlParseElement(ctxt);
1.33 daniel 4257:
4258: /*
4259: * The Misc part at the end
4260: */
4261: xmlParseMisc(ctxt);
1.16 daniel 4262:
1.59 daniel 4263: if (CUR != 0) {
4264: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4265: ctxt->sax->error(ctxt->userData,
1.59 daniel 4266: "Extra content at the end of the document\n");
4267: ctxt->wellFormed = 0;
4268: }
4269:
1.44 daniel 4270: /*
4271: * SAX: end of the document processing.
4272: */
1.72 daniel 4273: if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
1.74 daniel 4274: ctxt->sax->endDocument(ctxt->userData);
1.59 daniel 4275: if (! ctxt->wellFormed) return(-1);
1.16 daniel 4276: return(0);
4277: }
4278:
1.50 daniel 4279: /**
1.69 daniel 4280: * xmlCreateFileParserCtxt :
1.50 daniel 4281: * @cur: a pointer to an array of CHAR
4282: *
1.69 daniel 4283: * Create a parser context for an XML in-memory document.
4284: *
4285: * Returns the new parser context or NULL
1.16 daniel 4286: */
1.69 daniel 4287: xmlParserCtxtPtr
4288: xmlCreateDocParserCtxt(CHAR *cur) {
1.16 daniel 4289: xmlParserCtxtPtr ctxt;
1.40 daniel 4290: xmlParserInputPtr input;
1.75 daniel 4291: xmlCharEncoding enc;
1.16 daniel 4292:
4293: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4294: if (ctxt == NULL) {
4295: perror("malloc");
4296: return(NULL);
4297: }
1.40 daniel 4298: xmlInitParserCtxt(ctxt);
4299: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4300: if (input == NULL) {
4301: perror("malloc");
4302: free(ctxt);
4303: return(NULL);
4304: }
4305:
1.75 daniel 4306: /*
4307: * plug some encoding conversion routines here. !!!
4308: */
4309: enc = xmlDetectCharEncoding(cur);
4310: xmlSwitchEncoding(ctxt, enc);
4311:
1.40 daniel 4312: input->filename = NULL;
4313: input->line = 1;
4314: input->col = 1;
4315: input->base = cur;
4316: input->cur = cur;
1.69 daniel 4317: input->free = NULL;
1.40 daniel 4318:
4319: inputPush(ctxt, input);
1.69 daniel 4320: return(ctxt);
4321: }
4322:
4323: /**
4324: * xmlSAXParseDoc :
4325: * @sax: the SAX handler block
4326: * @cur: a pointer to an array of CHAR
4327: * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4328: * documents
4329: *
4330: * parse an XML in-memory document and build a tree.
4331: * It use the given SAX function block to handle the parsing callback.
4332: * If sax is NULL, fallback to the default DOM tree building routines.
4333: *
4334: * Returns the resulting document tree
4335: */
4336:
4337: xmlDocPtr
4338: xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur, int recovery) {
4339: xmlDocPtr ret;
4340: xmlParserCtxtPtr ctxt;
4341:
4342: if (cur == NULL) return(NULL);
1.16 daniel 4343:
4344:
1.69 daniel 4345: ctxt = xmlCreateDocParserCtxt(cur);
4346: if (ctxt == NULL) return(NULL);
1.74 daniel 4347: if (sax != NULL) {
4348: ctxt->sax = sax;
4349: ctxt->userData = NULL;
4350: }
1.69 daniel 4351:
1.16 daniel 4352: xmlParseDocument(ctxt);
1.72 daniel 4353: if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59 daniel 4354: else {
4355: ret = NULL;
1.72 daniel 4356: xmlFreeDoc(ctxt->myDoc);
4357: ctxt->myDoc = NULL;
1.59 daniel 4358: }
1.69 daniel 4359: xmlFreeParserCtxt(ctxt);
1.16 daniel 4360:
1.1 veillard 4361: return(ret);
4362: }
4363:
1.50 daniel 4364: /**
1.55 daniel 4365: * xmlParseDoc :
4366: * @cur: a pointer to an array of CHAR
4367: *
4368: * parse an XML in-memory document and build a tree.
4369: *
1.68 daniel 4370: * Returns the resulting document tree
1.55 daniel 4371: */
4372:
1.69 daniel 4373: xmlDocPtr
4374: xmlParseDoc(CHAR *cur) {
1.59 daniel 4375: return(xmlSAXParseDoc(NULL, cur, 0));
1.76 ! daniel 4376: }
! 4377:
! 4378: /**
! 4379: * xmlSAXParseDTD :
! 4380: * @sax: the SAX handler block
! 4381: * @ExternalID: a NAME* containing the External ID of the DTD
! 4382: * @SystemID: a NAME* containing the URL to the DTD
! 4383: *
! 4384: * Load and parse an external subset.
! 4385: *
! 4386: * Returns the resulting xmlDtdPtr or NULL in case of error.
! 4387: */
! 4388:
! 4389: xmlDtdPtr
! 4390: xmlSAXParseDTD(xmlSAXHandlerPtr sax, const CHAR *ExternalID,
! 4391: const CHAR *SystemID) {
! 4392: xmlDtdPtr ret = NULL;
! 4393: xmlParserCtxtPtr ctxt;
! 4394: xmlParserInputPtr input;
! 4395: xmlCharEncoding enc;
! 4396:
! 4397: if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL);
! 4398:
! 4399: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
! 4400: if (ctxt == NULL) {
! 4401: perror("malloc");
! 4402: return(NULL);
! 4403: }
! 4404: xmlInitParserCtxt(ctxt);
! 4405: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
! 4406: if (input == NULL) {
! 4407: perror("malloc");
! 4408: free(ctxt);
! 4409: return(NULL);
! 4410: }
! 4411:
! 4412: /*
! 4413: * Set-up the SAX context
! 4414: */
! 4415: if (ctxt == NULL) return(NULL);
! 4416: if (sax != NULL) {
! 4417: ctxt->sax = sax;
! 4418: ctxt->userData = NULL;
! 4419: }
! 4420:
! 4421: /*
! 4422: * Ask the Entity resolver to load the damn thing
! 4423: */
! 4424:
! 4425: if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
! 4426: input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, SystemID);
! 4427: if (input == NULL) {
! 4428: xmlFreeParserCtxt(ctxt);
! 4429: return(NULL);
! 4430: }
! 4431:
! 4432: /*
! 4433: * plug some encoding conversion routines here. !!!
! 4434: */
! 4435: xmlPushInput(ctxt, input);
! 4436: enc = xmlDetectCharEncoding(ctxt->input->cur);
! 4437: xmlSwitchEncoding(ctxt, enc);
! 4438:
! 4439: input->filename = xmlStrdup(SystemID);
! 4440: input->line = 1;
! 4441: input->col = 1;
! 4442: input->base = ctxt->input->cur;
! 4443: input->cur = ctxt->input->cur;
! 4444: input->free = NULL;
! 4445:
! 4446: /*
! 4447: * let's parse that entity knowing it's an external subset.
! 4448: */
! 4449: xmlParseExternalSubset(ctxt);
! 4450:
! 4451: if (ctxt->myDoc != NULL) {
! 4452: if (ctxt->wellFormed) {
! 4453: ret = ctxt->myDoc->intSubset;
! 4454: ctxt->myDoc->intSubset = NULL;
! 4455: } else {
! 4456: ret = NULL;
! 4457: }
! 4458: xmlFreeDoc(ctxt->myDoc);
! 4459: ctxt->myDoc = NULL;
! 4460: }
! 4461: xmlFreeParserCtxt(ctxt);
! 4462:
! 4463: return(ret);
! 4464: }
! 4465:
! 4466: /**
! 4467: * xmlParseDTD :
! 4468: * @ExternalID: a NAME* containing the External ID of the DTD
! 4469: * @SystemID: a NAME* containing the URL to the DTD
! 4470: *
! 4471: * Load and parse an external subset.
! 4472: *
! 4473: * Returns the resulting xmlDtdPtr or NULL in case of error.
! 4474: */
! 4475:
! 4476: xmlDtdPtr
! 4477: xmlParseDTD(const CHAR *ExternalID, const CHAR *SystemID) {
! 4478: return(xmlSAXParseDTD(NULL, ExternalID, SystemID));
1.59 daniel 4479: }
4480:
4481: /**
4482: * xmlRecoverDoc :
4483: * @cur: a pointer to an array of CHAR
4484: *
4485: * parse an XML in-memory document and build a tree.
4486: * In the case the document is not Well Formed, a tree is built anyway
4487: *
1.68 daniel 4488: * Returns the resulting document tree
1.59 daniel 4489: */
4490:
1.69 daniel 4491: xmlDocPtr
4492: xmlRecoverDoc(CHAR *cur) {
1.59 daniel 4493: return(xmlSAXParseDoc(NULL, cur, 1));
1.55 daniel 4494: }
4495:
4496: /**
1.69 daniel 4497: * xmlCreateFileParserCtxt :
1.50 daniel 4498: * @filename: the filename
4499: *
1.69 daniel 4500: * Create a parser context for a file content.
4501: * Automatic support for ZLIB/Compress compressed document is provided
4502: * by default if found at compile-time.
1.50 daniel 4503: *
1.69 daniel 4504: * Returns the new parser context or NULL
1.9 httpng 4505: */
1.69 daniel 4506: xmlParserCtxtPtr
4507: xmlCreateFileParserCtxt(const char *filename)
4508: {
4509: xmlParserCtxtPtr ctxt;
1.20 daniel 4510: #ifdef HAVE_ZLIB_H
4511: gzFile input;
4512: #else
1.9 httpng 4513: int input;
1.20 daniel 4514: #endif
1.9 httpng 4515: int res;
1.55 daniel 4516: int len;
1.9 httpng 4517: struct stat buf;
4518: char *buffer;
1.40 daniel 4519: xmlParserInputPtr inputStream;
1.75 daniel 4520: xmlCharEncoding enc;
1.9 httpng 4521:
1.11 veillard 4522: res = stat(filename, &buf);
1.9 httpng 4523: if (res < 0) return(NULL);
4524:
1.20 daniel 4525: #ifdef HAVE_ZLIB_H
1.55 daniel 4526: len = (buf.st_size * 8) + 1000;
1.20 daniel 4527: retry_bigger:
1.55 daniel 4528: buffer = malloc(len);
1.20 daniel 4529: #else
1.55 daniel 4530: len = buf.st_size + 100;
4531: buffer = malloc(len);
1.20 daniel 4532: #endif
1.9 httpng 4533: if (buffer == NULL) {
4534: perror("malloc");
4535: return(NULL);
4536: }
4537:
1.55 daniel 4538: memset(buffer, 0, len);
1.20 daniel 4539: #ifdef HAVE_ZLIB_H
4540: input = gzopen (filename, "r");
4541: if (input == NULL) {
4542: fprintf (stderr, "Cannot read file %s :\n", filename);
4543: perror ("gzopen failed");
4544: return(NULL);
4545: }
4546: #else
1.72 daniel 4547: #ifdef WIN32
4548: input = _open (filename, O_RDONLY | _O_BINARY);
4549: #else
1.9 httpng 4550: input = open (filename, O_RDONLY);
1.72 daniel 4551: #endif
1.9 httpng 4552: if (input < 0) {
4553: fprintf (stderr, "Cannot read file %s :\n", filename);
4554: perror ("open failed");
4555: return(NULL);
4556: }
1.20 daniel 4557: #endif
4558: #ifdef HAVE_ZLIB_H
1.55 daniel 4559: res = gzread(input, buffer, len);
1.20 daniel 4560: #else
1.9 httpng 4561: res = read(input, buffer, buf.st_size);
1.20 daniel 4562: #endif
1.9 httpng 4563: if (res < 0) {
4564: fprintf (stderr, "Cannot read file %s :\n", filename);
1.20 daniel 4565: #ifdef HAVE_ZLIB_H
4566: perror ("gzread failed");
4567: #else
1.9 httpng 4568: perror ("read failed");
1.20 daniel 4569: #endif
1.9 httpng 4570: return(NULL);
4571: }
1.20 daniel 4572: #ifdef HAVE_ZLIB_H
4573: gzclose(input);
1.55 daniel 4574: if (res >= len) {
1.20 daniel 4575: free(buffer);
1.55 daniel 4576: len *= 2;
1.20 daniel 4577: goto retry_bigger;
4578: }
4579: buf.st_size = res;
4580: #else
1.9 httpng 4581: close(input);
1.20 daniel 4582: #endif
4583:
1.40 daniel 4584: buffer[buf.st_size] = '\0';
1.9 httpng 4585:
1.16 daniel 4586: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4587: if (ctxt == NULL) {
4588: perror("malloc");
4589: return(NULL);
4590: }
1.40 daniel 4591: xmlInitParserCtxt(ctxt);
4592: inputStream = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4593: if (inputStream == NULL) {
4594: perror("malloc");
4595: free(ctxt);
4596: return(NULL);
4597: }
4598:
4599: inputStream->filename = strdup(filename);
4600: inputStream->line = 1;
4601: inputStream->col = 1;
1.45 daniel 4602:
4603: /*
1.75 daniel 4604: * plug some encoding conversion routines here. !!!
1.45 daniel 4605: */
1.75 daniel 4606: enc = xmlDetectCharEncoding(buffer);
4607: xmlSwitchEncoding(ctxt, enc);
4608:
1.40 daniel 4609: inputStream->base = buffer;
4610: inputStream->cur = buffer;
1.69 daniel 4611: inputStream->free = (xmlParserInputDeallocate) free;
1.16 daniel 4612:
1.40 daniel 4613: inputPush(ctxt, inputStream);
1.69 daniel 4614: return(ctxt);
4615: }
4616:
4617: /**
4618: * xmlSAXParseFile :
4619: * @sax: the SAX handler block
4620: * @filename: the filename
4621: * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4622: * documents
4623: *
4624: * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4625: * compressed document is provided by default if found at compile-time.
4626: * It use the given SAX function block to handle the parsing callback.
4627: * If sax is NULL, fallback to the default DOM tree building routines.
4628: *
4629: * Returns the resulting document tree
4630: */
4631:
4632: xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
4633: int recovery) {
4634: xmlDocPtr ret;
4635: xmlParserCtxtPtr ctxt;
4636:
4637: ctxt = xmlCreateFileParserCtxt(filename);
4638: if (ctxt == NULL) return(NULL);
1.74 daniel 4639: if (sax != NULL) {
4640: ctxt->sax = sax;
4641: ctxt->userData = NULL;
4642: }
1.16 daniel 4643:
4644: xmlParseDocument(ctxt);
1.40 daniel 4645:
1.72 daniel 4646: if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59 daniel 4647: else {
4648: ret = NULL;
1.72 daniel 4649: xmlFreeDoc(ctxt->myDoc);
4650: ctxt->myDoc = NULL;
1.59 daniel 4651: }
1.69 daniel 4652: xmlFreeParserCtxt(ctxt);
1.20 daniel 4653:
4654: return(ret);
4655: }
4656:
1.55 daniel 4657: /**
4658: * xmlParseFile :
4659: * @filename: the filename
4660: *
4661: * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4662: * compressed document is provided by default if found at compile-time.
4663: *
1.68 daniel 4664: * Returns the resulting document tree
1.55 daniel 4665: */
4666:
4667: xmlDocPtr xmlParseFile(const char *filename) {
1.59 daniel 4668: return(xmlSAXParseFile(NULL, filename, 0));
4669: }
4670:
4671: /**
4672: * xmlRecoverFile :
4673: * @filename: the filename
4674: *
4675: * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4676: * compressed document is provided by default if found at compile-time.
4677: * In the case the document is not Well Formed, a tree is built anyway
4678: *
1.68 daniel 4679: * Returns the resulting document tree
1.59 daniel 4680: */
4681:
4682: xmlDocPtr xmlRecoverFile(const char *filename) {
4683: return(xmlSAXParseFile(NULL, filename, 1));
1.55 daniel 4684: }
1.32 daniel 4685:
1.50 daniel 4686: /**
1.69 daniel 4687: * xmlCreateMemoryParserCtxt :
1.68 daniel 4688: * @buffer: an pointer to a char array
1.50 daniel 4689: * @size: the siwe of the array
4690: *
1.69 daniel 4691: * Create a parser context for an XML in-memory document.
1.50 daniel 4692: *
1.69 daniel 4693: * Returns the new parser context or NULL
1.20 daniel 4694: */
1.69 daniel 4695: xmlParserCtxtPtr
4696: xmlCreateMemoryParserCtxt(char *buffer, int size) {
1.20 daniel 4697: xmlParserCtxtPtr ctxt;
1.40 daniel 4698: xmlParserInputPtr input;
1.75 daniel 4699: xmlCharEncoding enc;
1.40 daniel 4700:
4701: buffer[size - 1] = '\0';
4702:
1.20 daniel 4703: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4704: if (ctxt == NULL) {
4705: perror("malloc");
4706: return(NULL);
4707: }
1.40 daniel 4708: xmlInitParserCtxt(ctxt);
4709: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4710: if (input == NULL) {
4711: perror("malloc");
1.50 daniel 4712: free(ctxt->nodeTab);
4713: free(ctxt->inputTab);
1.40 daniel 4714: free(ctxt);
4715: return(NULL);
4716: }
1.20 daniel 4717:
1.40 daniel 4718: input->filename = NULL;
4719: input->line = 1;
4720: input->col = 1;
1.45 daniel 4721:
4722: /*
1.75 daniel 4723: * plug some encoding conversion routines here. !!!
1.45 daniel 4724: */
1.75 daniel 4725: enc = xmlDetectCharEncoding(buffer);
4726: xmlSwitchEncoding(ctxt, enc);
4727:
1.40 daniel 4728: input->base = buffer;
4729: input->cur = buffer;
1.69 daniel 4730: input->free = NULL;
1.20 daniel 4731:
1.40 daniel 4732: inputPush(ctxt, input);
1.69 daniel 4733: return(ctxt);
4734: }
4735:
4736: /**
4737: * xmlSAXParseMemory :
4738: * @sax: the SAX handler block
4739: * @buffer: an pointer to a char array
4740: * @size: the siwe of the array
4741: * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4742: * documents
4743: *
4744: * parse an XML in-memory block and use the given SAX function block
4745: * to handle the parsing callback. If sax is NULL, fallback to the default
4746: * DOM tree building routines.
4747: *
4748: * Returns the resulting document tree
4749: */
4750: xmlDocPtr
4751: xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
4752: xmlDocPtr ret;
4753: xmlParserCtxtPtr ctxt;
4754:
4755: ctxt = xmlCreateMemoryParserCtxt(buffer, size);
4756: if (ctxt == NULL) return(NULL);
1.74 daniel 4757: if (sax != NULL) {
4758: ctxt->sax = sax;
4759: ctxt->userData = NULL;
4760: }
1.20 daniel 4761:
4762: xmlParseDocument(ctxt);
1.40 daniel 4763:
1.72 daniel 4764: if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59 daniel 4765: else {
4766: ret = NULL;
1.72 daniel 4767: xmlFreeDoc(ctxt->myDoc);
4768: ctxt->myDoc = NULL;
1.59 daniel 4769: }
1.69 daniel 4770: xmlFreeParserCtxt(ctxt);
1.16 daniel 4771:
1.9 httpng 4772: return(ret);
1.17 daniel 4773: }
4774:
1.55 daniel 4775: /**
4776: * xmlParseMemory :
1.68 daniel 4777: * @buffer: an pointer to a char array
1.55 daniel 4778: * @size: the size of the array
4779: *
4780: * parse an XML in-memory block and build a tree.
4781: *
1.68 daniel 4782: * Returns the resulting document tree
1.55 daniel 4783: */
4784:
4785: xmlDocPtr xmlParseMemory(char *buffer, int size) {
1.59 daniel 4786: return(xmlSAXParseMemory(NULL, buffer, size, 0));
4787: }
4788:
4789: /**
4790: * xmlRecoverMemory :
1.68 daniel 4791: * @buffer: an pointer to a char array
1.59 daniel 4792: * @size: the size of the array
4793: *
4794: * parse an XML in-memory block and build a tree.
4795: * In the case the document is not Well Formed, a tree is built anyway
4796: *
1.68 daniel 4797: * Returns the resulting document tree
1.59 daniel 4798: */
4799:
4800: xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
4801: return(xmlSAXParseMemory(NULL, buffer, size, 1));
1.55 daniel 4802: }
1.17 daniel 4803:
1.50 daniel 4804: /**
4805: * xmlInitParserCtxt:
4806: * @ctxt: an XML parser context
4807: *
4808: * Initialize a parser context
4809: */
4810:
1.55 daniel 4811: void
4812: xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
1.17 daniel 4813: {
1.69 daniel 4814: /* Allocate the Input stack */
4815: ctxt->inputTab = (xmlParserInputPtr *) malloc(5 * sizeof(xmlParserInputPtr));
4816: ctxt->inputNr = 0;
4817: ctxt->inputMax = 5;
4818: ctxt->input = NULL;
1.72 daniel 4819: ctxt->version = NULL;
4820: ctxt->encoding = NULL;
4821: ctxt->standalone = -1;
1.69 daniel 4822:
4823: /* Allocate the Node stack */
4824: ctxt->nodeTab = (xmlNodePtr *) malloc(10 * sizeof(xmlNodePtr));
4825: ctxt->nodeNr = 0;
4826: ctxt->nodeMax = 10;
4827: ctxt->node = NULL;
4828:
4829: ctxt->sax = &xmlDefaultSAXHandler;
1.74 daniel 4830: ctxt->userData = ctxt;
1.72 daniel 4831: ctxt->myDoc = NULL;
1.69 daniel 4832: ctxt->wellFormed = 1;
4833: ctxt->record_info = 0;
4834: xmlInitNodeInfoSeq(&ctxt->node_seq);
4835: }
4836:
4837: /**
4838: * xmlFreeParserCtxt:
4839: * @ctxt: an XML parser context
4840: *
4841: * Free all the memory used by a parser context. However the parsed
1.72 daniel 4842: * document in ctxt->myDoc is not freed.
1.69 daniel 4843: */
4844:
4845: void
4846: xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
4847: {
4848: xmlParserInputPtr input;
4849:
4850: if (ctxt == NULL) return;
4851:
4852: while ((input = inputPop(ctxt)) != NULL) {
4853: xmlFreeInputStream(input);
4854: }
4855:
4856: if (ctxt->nodeTab != NULL) free(ctxt->nodeTab);
4857: if (ctxt->inputTab != NULL) free(ctxt->inputTab);
1.73 daniel 4858: if (ctxt->version != NULL) free((char *) ctxt->version);
1.69 daniel 4859: free(ctxt);
1.17 daniel 4860: }
4861:
1.50 daniel 4862: /**
4863: * xmlClearParserCtxt:
4864: * @ctxt: an XML parser context
4865: *
4866: * Clear (release owned resources) and reinitialize a parser context
4867: */
1.17 daniel 4868:
1.55 daniel 4869: void
4870: xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
1.17 daniel 4871: {
1.32 daniel 4872: xmlClearNodeInfoSeq(&ctxt->node_seq);
4873: xmlInitParserCtxt(ctxt);
1.17 daniel 4874: }
4875:
4876:
1.50 daniel 4877: /**
4878: * xmlSetupParserForBuffer:
4879: * @ctxt: an XML parser context
4880: * @buffer: a CHAR * buffer
4881: * @filename: a file name
4882: *
1.19 daniel 4883: * Setup the parser context to parse a new buffer; Clears any prior
4884: * contents from the parser context. The buffer parameter must not be
4885: * NULL, but the filename parameter can be
4886: */
1.55 daniel 4887: void
4888: xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const CHAR* buffer,
1.17 daniel 4889: const char* filename)
4890: {
1.40 daniel 4891: xmlParserInputPtr input;
4892:
4893: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4894: if (input == NULL) {
4895: perror("malloc");
4896: free(ctxt);
4897: exit(1);
4898: }
4899:
1.17 daniel 4900: xmlClearParserCtxt(ctxt);
1.40 daniel 4901: if (input->filename != NULL)
4902: input->filename = strdup(filename);
4903: else
4904: input->filename = NULL;
4905: input->line = 1;
4906: input->col = 1;
4907: input->base = buffer;
4908: input->cur = buffer;
4909:
4910: inputPush(ctxt, input);
1.17 daniel 4911: }
4912:
1.32 daniel 4913:
1.50 daniel 4914: /**
4915: * xmlParserFindNodeInfo:
4916: * @ctxt: an XML parser context
4917: * @node: an XML node within the tree
4918: *
4919: * Find the parser node info struct for a given node
4920: *
1.68 daniel 4921: * Returns an xmlParserNodeInfo block pointer or NULL
1.32 daniel 4922: */
4923: const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
4924: const xmlNode* node)
4925: {
4926: unsigned long pos;
4927:
4928: /* Find position where node should be at */
4929: pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
4930: if ( ctx->node_seq.buffer[pos].node == node )
4931: return &ctx->node_seq.buffer[pos];
4932: else
4933: return NULL;
4934: }
4935:
4936:
1.50 daniel 4937: /**
4938: * xmlInitNodeInfoSeq :
4939: * @seq: a node info sequence pointer
4940: *
4941: * -- Initialize (set to initial state) node info sequence
1.32 daniel 4942: */
1.55 daniel 4943: void
4944: xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
1.32 daniel 4945: {
4946: seq->length = 0;
4947: seq->maximum = 0;
4948: seq->buffer = NULL;
4949: }
4950:
1.50 daniel 4951: /**
4952: * xmlClearNodeInfoSeq :
4953: * @seq: a node info sequence pointer
4954: *
4955: * -- Clear (release memory and reinitialize) node
1.32 daniel 4956: * info sequence
4957: */
1.55 daniel 4958: void
4959: xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
1.32 daniel 4960: {
4961: if ( seq->buffer != NULL )
4962: free(seq->buffer);
4963: xmlInitNodeInfoSeq(seq);
4964: }
4965:
4966:
1.50 daniel 4967: /**
4968: * xmlParserFindNodeInfoIndex:
4969: * @seq: a node info sequence pointer
4970: * @node: an XML node pointer
4971: *
4972: *
1.32 daniel 4973: * xmlParserFindNodeInfoIndex : Find the index that the info record for
4974: * the given node is or should be at in a sorted sequence
1.68 daniel 4975: *
4976: * Returns a long indicating the position of the record
1.32 daniel 4977: */
4978: unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
4979: const xmlNode* node)
4980: {
4981: unsigned long upper, lower, middle;
4982: int found = 0;
4983:
4984: /* Do a binary search for the key */
4985: lower = 1;
4986: upper = seq->length;
4987: middle = 0;
4988: while ( lower <= upper && !found) {
4989: middle = lower + (upper - lower) / 2;
4990: if ( node == seq->buffer[middle - 1].node )
4991: found = 1;
4992: else if ( node < seq->buffer[middle - 1].node )
4993: upper = middle - 1;
4994: else
4995: lower = middle + 1;
4996: }
4997:
4998: /* Return position */
4999: if ( middle == 0 || seq->buffer[middle - 1].node < node )
5000: return middle;
5001: else
5002: return middle - 1;
5003: }
5004:
5005:
1.50 daniel 5006: /**
5007: * xmlParserAddNodeInfo:
5008: * @ctxt: an XML parser context
1.68 daniel 5009: * @info: a node info sequence pointer
1.50 daniel 5010: *
5011: * Insert node info record into the sorted sequence
1.32 daniel 5012: */
1.55 daniel 5013: void
5014: xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
1.68 daniel 5015: const xmlParserNodeInfo* info)
1.32 daniel 5016: {
5017: unsigned long pos;
5018: static unsigned int block_size = 5;
5019:
5020: /* Find pos and check to see if node is already in the sequence */
1.55 daniel 5021: pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
5022: if ( pos < ctxt->node_seq.length
5023: && ctxt->node_seq.buffer[pos].node == info->node ) {
5024: ctxt->node_seq.buffer[pos] = *info;
1.32 daniel 5025: }
5026:
5027: /* Otherwise, we need to add new node to buffer */
5028: else {
5029: /* Expand buffer by 5 if needed */
1.55 daniel 5030: if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
1.32 daniel 5031: xmlParserNodeInfo* tmp_buffer;
1.55 daniel 5032: unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
5033: *(ctxt->node_seq.maximum + block_size));
1.32 daniel 5034:
1.55 daniel 5035: if ( ctxt->node_seq.buffer == NULL )
1.32 daniel 5036: tmp_buffer = (xmlParserNodeInfo*)malloc(byte_size);
5037: else
1.55 daniel 5038: tmp_buffer = (xmlParserNodeInfo*)realloc(ctxt->node_seq.buffer, byte_size);
1.32 daniel 5039:
5040: if ( tmp_buffer == NULL ) {
1.55 daniel 5041: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 5042: ctxt->sax->error(ctxt->userData, "Out of memory\n");
1.32 daniel 5043: return;
5044: }
1.55 daniel 5045: ctxt->node_seq.buffer = tmp_buffer;
5046: ctxt->node_seq.maximum += block_size;
1.32 daniel 5047: }
5048:
5049: /* If position is not at end, move elements out of the way */
1.55 daniel 5050: if ( pos != ctxt->node_seq.length ) {
1.32 daniel 5051: unsigned long i;
5052:
1.55 daniel 5053: for ( i = ctxt->node_seq.length; i > pos; i-- )
5054: ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
1.32 daniel 5055: }
5056:
5057: /* Copy element and increase length */
1.55 daniel 5058: ctxt->node_seq.buffer[pos] = *info;
5059: ctxt->node_seq.length++;
1.32 daniel 5060: }
5061: }
Webmaster