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