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