Annotation of XML/parser.c, revision 1.84
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: }
1.84 ! daniel 2842: if (content != NULL) {
! 2843: xmlFreeElementContent(content);
! 2844: }
1.61 daniel 2845: if (name != NULL) {
2846: free(name);
2847: }
1.22 daniel 2848: }
1.59 daniel 2849: return(ret);
1.22 daniel 2850: }
2851:
1.50 daniel 2852: /**
2853: * xmlParseMarkupDecl:
2854: * @ctxt: an XML parser context
2855: *
2856: * parse Markup declarations
1.22 daniel 2857: *
2858: * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
2859: * NotationDecl | PI | Comment
2860: *
2861: * TODO There is a check [ VC: Proper Declaration/PE Nesting ]
2862: */
1.55 daniel 2863: void
2864: xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
1.22 daniel 2865: xmlParseElementDecl(ctxt);
2866: xmlParseAttributeListDecl(ctxt);
2867: xmlParseEntityDecl(ctxt);
2868: xmlParseNotationDecl(ctxt);
2869: xmlParsePI(ctxt);
1.31 daniel 2870: xmlParseComment(ctxt, 0);
1.22 daniel 2871: }
2872:
1.50 daniel 2873: /**
1.76 daniel 2874: * xmlParseTextDecl:
2875: * @ctxt: an XML parser context
2876: *
2877: * parse an XML declaration header for external entities
2878: *
2879: * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
2880: *
2881: * Returns the only valuable info for an external parsed entity, the encoding
2882: */
2883:
2884: CHAR *
2885: xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
2886: CHAR *version;
2887: CHAR *encoding = NULL;
2888:
2889: /*
2890: * We know that '<?xml' is here.
2891: */
2892: SKIP(5);
2893:
2894: if (!IS_BLANK(CUR)) {
2895: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2896: ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
2897: ctxt->wellFormed = 0;
2898: }
2899: SKIP_BLANKS;
2900:
2901: /*
2902: * We may have the VersionInfo here.
2903: */
2904: version = xmlParseVersionInfo(ctxt);
2905: /* TODO: we should actually inherit from the referencing doc if absent
2906: if (version == NULL)
2907: version = xmlCharStrdup(XML_DEFAULT_VERSION);
2908: ctxt->version = xmlStrdup(version);
2909: */
2910: if (version != NULL)
2911: free(version);
2912:
2913: /*
2914: * We must have the encoding declaration
2915: */
2916: if (!IS_BLANK(CUR)) {
2917: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2918: ctxt->sax->error(ctxt->userData, "Blank needed here\n");
2919: ctxt->wellFormed = 0;
2920: }
2921: encoding = xmlParseEncodingDecl(ctxt);
2922:
2923: SKIP_BLANKS;
2924: if ((CUR == '?') && (NXT(1) == '>')) {
2925: SKIP(2);
2926: } else if (CUR == '>') {
2927: /* Deprecated old WD ... */
2928: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2929: ctxt->sax->error(ctxt->userData, "XML declaration must end-up with '?>'\n");
2930: ctxt->wellFormed = 0;
2931: NEXT;
2932: } else {
2933: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2934: ctxt->sax->error(ctxt->userData, "parsing XML declaration: '?>' expected\n");
2935: ctxt->wellFormed = 0;
2936: MOVETO_ENDTAG(CUR_PTR);
2937: NEXT;
2938: }
2939: return(encoding);
2940: }
2941:
2942: /*
2943: * xmlParseConditionalSections
2944: * @ctxt: an XML parser context
2945: *
2946: * TODO : Conditionnal section are not yet supported !
2947: *
2948: * [61] conditionalSect ::= includeSect | ignoreSect
2949: * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
2950: * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
2951: * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
2952: * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
2953: */
2954:
2955: void
2956: xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
2957: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
2958: ctxt->sax->warning(ctxt->userData,
2959: "XML conditional section not supported\n");
2960: /*
2961: * Skip up to the end of the conditionnal section.
2962: */
2963: while ((CUR != 0) && ((CUR != ']') || (NXT(1) != ']') || (NXT(2) != '>')))
2964: NEXT;
2965: if (CUR == 0) {
2966: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2967: ctxt->sax->error(ctxt->userData,
2968: "XML conditional section not closed\n");
2969: ctxt->wellFormed = 0;
2970: }
2971: }
2972:
2973: /**
2974: * xmlParseExternalSubset
2975: * @ctxt: an XML parser context
2976: *
2977: * parse Markup declarations from an external subset
2978: *
2979: * [30] extSubset ::= textDecl? extSubsetDecl
2980: *
2981: * [31] extSubsetDecl ::= (markupdecl | conditionalSect | PEReference | S) *
2982: *
2983: * TODO There is a check [ VC: Proper Declaration/PE Nesting ]
2984: */
2985: void
1.79 daniel 2986: xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const CHAR *ExternalID,
2987: const CHAR *SystemID) {
1.76 daniel 2988: if ((CUR == '<') && (NXT(1) == '?') &&
2989: (NXT(2) == 'x') && (NXT(3) == 'm') &&
2990: (NXT(4) == 'l')) {
2991: xmlParseTextDecl(ctxt);
2992: }
1.79 daniel 2993: if (ctxt->myDoc == NULL) {
2994: ctxt->myDoc = xmlNewDoc("1.0");
2995: }
2996: if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL))
2997: xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID);
2998:
1.76 daniel 2999: while (((CUR == '<') && (NXT(1) == '?')) ||
3000: ((CUR == '<') && (NXT(1) == '!')) ||
3001: IS_BLANK(CUR)) {
3002: if ((CUR == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
3003: xmlParseConditionalSections(ctxt);
3004: } else if (IS_BLANK(CUR)) {
3005: NEXT;
3006: } else if (CUR == '%') {
3007: xmlParsePEReference(ctxt);
3008: } else
3009: xmlParseMarkupDecl(ctxt);
1.77 daniel 3010:
3011: /*
3012: * Pop-up of finished entities.
3013: */
3014: while ((CUR == 0) && (ctxt->inputNr > 1))
3015: xmlPopInput(ctxt);
3016:
1.76 daniel 3017: }
3018:
3019: if (CUR != 0) {
3020: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3021: ctxt->sax->error(ctxt->userData,
3022: "Extra content at the end of the document\n");
3023: ctxt->wellFormed = 0;
3024: }
3025:
3026: }
3027:
3028: /**
1.50 daniel 3029: * xmlParseCharRef:
3030: * @ctxt: an XML parser context
3031: *
3032: * parse Reference declarations
1.24 daniel 3033: *
3034: * [66] CharRef ::= '&#' [0-9]+ ';' |
3035: * '&#x' [0-9a-fA-F]+ ';'
1.68 daniel 3036: *
1.77 daniel 3037: * Returns the value parsed (as an int)
1.24 daniel 3038: */
1.77 daniel 3039: int
1.55 daniel 3040: xmlParseCharRef(xmlParserCtxtPtr ctxt) {
1.29 daniel 3041: int val = 0;
1.24 daniel 3042:
1.40 daniel 3043: if ((CUR == '&') && (NXT(1) == '#') &&
3044: (NXT(2) == 'x')) {
3045: SKIP(3);
3046: while (CUR != ';') {
3047: if ((CUR >= '0') && (CUR <= '9'))
3048: val = val * 16 + (CUR - '0');
3049: else if ((CUR >= 'a') && (CUR <= 'f'))
3050: val = val * 16 + (CUR - 'a') + 10;
3051: else if ((CUR >= 'A') && (CUR <= 'F'))
3052: val = val * 16 + (CUR - 'A') + 10;
1.24 daniel 3053: else {
1.55 daniel 3054: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3055: ctxt->sax->error(ctxt->userData,
1.59 daniel 3056: "xmlParseCharRef: invalid hexadecimal value\n");
3057: ctxt->wellFormed = 0;
1.29 daniel 3058: val = 0;
1.24 daniel 3059: break;
3060: }
1.47 daniel 3061: NEXT;
1.24 daniel 3062: }
1.55 daniel 3063: if (CUR == ';')
1.40 daniel 3064: NEXT;
3065: } else if ((CUR == '&') && (NXT(1) == '#')) {
3066: SKIP(2);
3067: while (CUR != ';') {
3068: if ((CUR >= '0') && (CUR <= '9'))
1.55 daniel 3069: val = val * 10 + (CUR - '0');
1.24 daniel 3070: else {
1.55 daniel 3071: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3072: ctxt->sax->error(ctxt->userData,
1.58 daniel 3073: "xmlParseCharRef: invalid decimal value\n");
1.59 daniel 3074: ctxt->wellFormed = 0;
1.29 daniel 3075: val = 0;
1.24 daniel 3076: break;
3077: }
1.47 daniel 3078: NEXT;
1.24 daniel 3079: }
1.55 daniel 3080: if (CUR == ';')
1.40 daniel 3081: NEXT;
1.24 daniel 3082: } else {
1.55 daniel 3083: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3084: ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid value\n");
1.59 daniel 3085: ctxt->wellFormed = 0;
1.24 daniel 3086: }
1.29 daniel 3087: /*
3088: * Check the value IS_CHAR ...
3089: */
1.44 daniel 3090: if (IS_CHAR(val)) {
1.77 daniel 3091: return(val);
1.44 daniel 3092: } else {
1.55 daniel 3093: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3094: ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid CHAR value %d\n",
1.58 daniel 3095: val);
1.59 daniel 3096: ctxt->wellFormed = 0;
1.29 daniel 3097: }
1.77 daniel 3098: return(0);
3099: }
3100:
3101: /**
3102: * xmlParseReference:
3103: * @ctxt: an XML parser context
3104: *
3105: * parse and handle entity references in content, depending on the SAX
3106: * interface, this may end-up in a call to character() if this is a
1.79 daniel 3107: * CharRef, a predefined entity, if there is no reference() callback.
3108: * or if the parser was asked to switch to that mode.
1.77 daniel 3109: *
3110: * [67] Reference ::= EntityRef | CharRef
3111: */
3112: void
3113: xmlParseReference(xmlParserCtxtPtr ctxt) {
3114: xmlEntityPtr ent;
3115: CHAR *val;
3116: if (CUR != '&') return;
3117:
3118: if (NXT(1) == '#') {
3119: CHAR out[2];
3120: int val = xmlParseCharRef(ctxt);
3121: /* TODO: invalid for UTF-8 variable encoding !!! */
3122: out[0] = val;
3123: out[1] = 0;
3124: if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
3125: ctxt->sax->characters(ctxt->userData, out, 1);
3126: } else {
3127: ent = xmlParseEntityRef(ctxt);
3128: if (ent == NULL) return;
3129: if ((ent->name != NULL) &&
3130: (ent->type != XML_INTERNAL_PREDEFINED_ENTITY) &&
1.79 daniel 3131: (ctxt->sax != NULL) && (ctxt->sax->reference != NULL) &&
3132: (ctxt->replaceEntities == 0)) {
3133:
1.77 daniel 3134: /*
3135: * Create a node.
3136: */
3137: ctxt->sax->reference(ctxt->userData, ent->name);
3138: return;
3139: }
3140: val = ent->content;
3141: if (val == NULL) return;
3142: /*
3143: * inline the entity.
3144: */
3145: if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
3146: ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val));
3147: }
1.24 daniel 3148: }
3149:
1.50 daniel 3150: /**
3151: * xmlParseEntityRef:
3152: * @ctxt: an XML parser context
3153: *
3154: * parse ENTITY references declarations
1.24 daniel 3155: *
3156: * [68] EntityRef ::= '&' Name ';'
1.68 daniel 3157: *
1.77 daniel 3158: * Returns the xmlEntityPtr if found, or NULL otherwise.
1.24 daniel 3159: */
1.77 daniel 3160: xmlEntityPtr
1.55 daniel 3161: xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
1.84 ! daniel 3162: const CHAR *q; /* !!!!!!!!!!! Unused !!!!!!!!!! */
1.24 daniel 3163: CHAR *name;
1.72 daniel 3164: xmlEntityPtr ent = NULL;
1.24 daniel 3165:
1.50 daniel 3166: q = CUR_PTR;
1.40 daniel 3167: if (CUR == '&') {
3168: NEXT;
1.24 daniel 3169: name = xmlParseName(ctxt);
3170: if (name == NULL) {
1.55 daniel 3171: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3172: ctxt->sax->error(ctxt->userData, "xmlParseEntityRef: no name\n");
1.59 daniel 3173: ctxt->wellFormed = 0;
1.24 daniel 3174: } else {
1.40 daniel 3175: if (CUR == ';') {
3176: NEXT;
1.24 daniel 3177: /*
1.77 daniel 3178: * Ask first SAX for entity resolution, otherwise try the
3179: * predefined set.
3180: */
3181: if (ctxt->sax != NULL) {
3182: if (ctxt->sax->getEntity != NULL)
3183: ent = ctxt->sax->getEntity(ctxt->userData, name);
3184: if (ent == NULL)
3185: ent = xmlGetPredefinedEntity(name);
3186: }
3187:
3188: /*
1.59 daniel 3189: * Well Formedness Constraint if:
3190: * - standalone
3191: * or
3192: * - no external subset and no external parameter entities
3193: * referenced
3194: * then
3195: * the entity referenced must have been declared
3196: *
1.72 daniel 3197: * TODO: to be double checked !!! This is wrong !
1.59 daniel 3198: */
1.77 daniel 3199: if (ent == NULL) {
3200: if (ctxt->sax != NULL) {
1.72 daniel 3201: if (((ctxt->sax->isStandalone != NULL) &&
1.77 daniel 3202: ctxt->sax->isStandalone(ctxt->userData) == 1) ||
1.72 daniel 3203: (((ctxt->sax->hasInternalSubset == NULL) ||
1.74 daniel 3204: ctxt->sax->hasInternalSubset(ctxt->userData) == 0) &&
1.72 daniel 3205: ((ctxt->sax->hasExternalSubset == NULL) ||
1.74 daniel 3206: ctxt->sax->hasExternalSubset(ctxt->userData) == 0))) {
1.77 daniel 3207: if (ctxt->sax->error != NULL)
3208: ctxt->sax->error(ctxt->userData,
3209: "Entity '%s' not defined\n", name);
3210: ctxt->wellFormed = 0;
3211: }
3212: } else {
3213: fprintf(stderr, "Entity '%s' not defined\n", name);
3214: ctxt->wellFormed = 0;
1.59 daniel 3215: }
1.77 daniel 3216: }
1.59 daniel 3217:
3218: /*
3219: * Well Formedness Constraint :
3220: * The referenced entity must be a parsed entity.
3221: */
3222: if (ent != NULL) {
3223: switch (ent->type) {
3224: case XML_INTERNAL_PARAMETER_ENTITY:
3225: case XML_EXTERNAL_PARAMETER_ENTITY:
3226: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3227: ctxt->sax->error(ctxt->userData,
1.59 daniel 3228: "Attempt to reference the parameter entity '%s'\n", name);
3229: ctxt->wellFormed = 0;
3230: break;
3231:
3232: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3233: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3234: ctxt->sax->error(ctxt->userData,
1.59 daniel 3235: "Attempt to reference unparsed entity '%s'\n", name);
3236: ctxt->wellFormed = 0;
3237: break;
3238: }
3239: }
3240:
3241: /*
1.77 daniel 3242: * TODO: !!!
1.59 daniel 3243: * Well Formedness Constraint :
3244: * The referenced entity must not lead to recursion !
3245: */
3246:
1.77 daniel 3247:
1.24 daniel 3248: } else {
1.55 daniel 3249: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3250: ctxt->sax->error(ctxt->userData,
1.59 daniel 3251: "xmlParseEntityRef: expecting ';'\n");
3252: ctxt->wellFormed = 0;
1.24 daniel 3253: }
1.45 daniel 3254: free(name);
1.24 daniel 3255: }
3256: }
1.77 daniel 3257: return(ent);
1.24 daniel 3258: }
3259:
1.50 daniel 3260: /**
3261: * xmlParsePEReference:
3262: * @ctxt: an XML parser context
3263: *
3264: * parse PEReference declarations
1.77 daniel 3265: * The entity content is handled directly by pushing it's content as
3266: * a new input stream.
1.22 daniel 3267: *
3268: * [69] PEReference ::= '%' Name ';'
1.68 daniel 3269: *
1.22 daniel 3270: */
1.77 daniel 3271: void
1.55 daniel 3272: xmlParsePEReference(xmlParserCtxtPtr ctxt) {
1.22 daniel 3273: CHAR *name;
1.72 daniel 3274: xmlEntityPtr entity = NULL;
1.50 daniel 3275: xmlParserInputPtr input;
1.22 daniel 3276:
1.40 daniel 3277: if (CUR == '%') {
3278: NEXT;
1.22 daniel 3279: name = xmlParseName(ctxt);
3280: if (name == NULL) {
1.55 daniel 3281: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3282: ctxt->sax->error(ctxt->userData, "xmlParsePEReference: no name\n");
1.59 daniel 3283: ctxt->wellFormed = 0;
1.22 daniel 3284: } else {
1.40 daniel 3285: if (CUR == ';') {
3286: NEXT;
1.72 daniel 3287: if ((ctxt->sax != NULL) && (ctxt->sax->getEntity != NULL))
1.79 daniel 3288: entity = ctxt->sax->getEntity(ctxt->userData, name);
1.72 daniel 3289: /* TODO !!!! Must check that it's of the proper type !!! */
1.45 daniel 3290: if (entity == NULL) {
1.55 daniel 3291: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1.74 daniel 3292: ctxt->sax->warning(ctxt->userData,
1.59 daniel 3293: "xmlParsePEReference: %%%s; not found\n", name);
1.50 daniel 3294: } else {
3295: input = xmlNewEntityInputStream(ctxt, entity);
3296: xmlPushInput(ctxt, input);
1.45 daniel 3297: }
1.22 daniel 3298: } else {
1.55 daniel 3299: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3300: ctxt->sax->error(ctxt->userData,
1.59 daniel 3301: "xmlParsePEReference: expecting ';'\n");
3302: ctxt->wellFormed = 0;
1.22 daniel 3303: }
1.45 daniel 3304: free(name);
1.3 veillard 3305: }
3306: }
3307: }
3308:
1.50 daniel 3309: /**
3310: * xmlParseDocTypeDecl :
3311: * @ctxt: an XML parser context
3312: *
3313: * parse a DOCTYPE declaration
1.21 daniel 3314: *
1.22 daniel 3315: * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
3316: * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
1.21 daniel 3317: */
3318:
1.55 daniel 3319: void
3320: xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
1.21 daniel 3321: CHAR *name;
3322: CHAR *ExternalID = NULL;
1.39 daniel 3323: CHAR *URI = NULL;
1.21 daniel 3324:
3325: /*
3326: * We know that '<!DOCTYPE' has been detected.
3327: */
1.40 daniel 3328: SKIP(9);
1.21 daniel 3329:
1.42 daniel 3330: SKIP_BLANKS;
1.21 daniel 3331:
3332: /*
3333: * Parse the DOCTYPE name.
3334: */
3335: name = xmlParseName(ctxt);
3336: if (name == NULL) {
1.55 daniel 3337: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3338: ctxt->sax->error(ctxt->userData, "xmlParseDocTypeDecl : no DOCTYPE name !\n");
1.59 daniel 3339: ctxt->wellFormed = 0;
1.21 daniel 3340: }
3341:
1.42 daniel 3342: SKIP_BLANKS;
1.21 daniel 3343:
3344: /*
1.22 daniel 3345: * Check for SystemID and ExternalID
3346: */
1.67 daniel 3347: URI = xmlParseExternalID(ctxt, &ExternalID, 1);
1.42 daniel 3348: SKIP_BLANKS;
1.36 daniel 3349:
1.76 daniel 3350: /*
3351: * NOTE: the SAX callback may try to fetch the external subset
3352: * entity and fill it up !
3353: */
1.72 daniel 3354: if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL))
1.74 daniel 3355: ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
1.22 daniel 3356:
3357: /*
3358: * Is there any DTD definition ?
3359: */
1.40 daniel 3360: if (CUR == '[') {
3361: NEXT;
1.22 daniel 3362: /*
3363: * Parse the succession of Markup declarations and
3364: * PEReferences.
3365: * Subsequence (markupdecl | PEReference | S)*
3366: */
1.40 daniel 3367: while (CUR != ']') {
3368: const CHAR *check = CUR_PTR;
1.22 daniel 3369:
1.42 daniel 3370: SKIP_BLANKS;
1.22 daniel 3371: xmlParseMarkupDecl(ctxt);
1.50 daniel 3372: xmlParsePEReference(ctxt);
1.22 daniel 3373:
1.40 daniel 3374: if (CUR_PTR == check) {
1.55 daniel 3375: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3376: ctxt->sax->error(ctxt->userData,
1.31 daniel 3377: "xmlParseDocTypeDecl: error detected in Markup declaration\n");
1.59 daniel 3378: ctxt->wellFormed = 0;
1.22 daniel 3379: break;
3380: }
1.77 daniel 3381:
3382: /*
3383: * Pop-up of finished entities.
3384: */
3385: while ((CUR == 0) && (ctxt->inputNr > 1))
3386: xmlPopInput(ctxt);
3387:
1.22 daniel 3388: }
1.40 daniel 3389: if (CUR == ']') NEXT;
1.22 daniel 3390: }
3391:
3392: /*
3393: * We should be at the end of the DOCTYPE declaration.
1.21 daniel 3394: */
1.40 daniel 3395: if (CUR != '>') {
1.55 daniel 3396: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3397: ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
1.59 daniel 3398: ctxt->wellFormed = 0;
1.22 daniel 3399: /* We shouldn't try to resynchronize ... */
1.21 daniel 3400: }
1.40 daniel 3401: NEXT;
1.22 daniel 3402:
3403: /*
3404: * Cleanup, since we don't use all those identifiers
3405: * TODO : the DOCTYPE if available should be stored !
3406: */
1.39 daniel 3407: if (URI != NULL) free(URI);
1.22 daniel 3408: if (ExternalID != NULL) free(ExternalID);
3409: if (name != NULL) free(name);
1.21 daniel 3410: }
3411:
1.50 daniel 3412: /**
3413: * xmlParseAttribute:
3414: * @ctxt: an XML parser context
1.72 daniel 3415: * @value: a CHAR ** used to store the value of the attribute
1.50 daniel 3416: *
3417: * parse an attribute
1.3 veillard 3418: *
1.22 daniel 3419: * [41] Attribute ::= Name Eq AttValue
3420: *
3421: * [25] Eq ::= S? '=' S?
3422: *
1.29 daniel 3423: * With namespace:
3424: *
3425: * [NS 11] Attribute ::= QName Eq AttValue
1.43 daniel 3426: *
3427: * Also the case QName == xmlns:??? is handled independently as a namespace
3428: * definition.
1.69 daniel 3429: *
1.72 daniel 3430: * Returns the attribute name, and the value in *value.
1.3 veillard 3431: */
3432:
1.72 daniel 3433: CHAR *
3434: xmlParseAttribute(xmlParserCtxtPtr ctxt, CHAR **value) {
1.59 daniel 3435: CHAR *name, *val;
1.3 veillard 3436:
1.72 daniel 3437: *value = NULL;
3438: name = xmlParseName(ctxt);
1.22 daniel 3439: if (name == NULL) {
1.55 daniel 3440: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3441: ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
1.59 daniel 3442: ctxt->wellFormed = 0;
1.52 daniel 3443: return(NULL);
1.3 veillard 3444: }
3445:
3446: /*
1.29 daniel 3447: * read the value
1.3 veillard 3448: */
1.42 daniel 3449: SKIP_BLANKS;
1.40 daniel 3450: if (CUR == '=') {
3451: NEXT;
1.42 daniel 3452: SKIP_BLANKS;
1.72 daniel 3453: val = xmlParseAttValue(ctxt);
1.29 daniel 3454: } else {
1.55 daniel 3455: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3456: ctxt->sax->error(ctxt->userData,
1.59 daniel 3457: "Specification mandate value for attribute %s\n", name);
3458: ctxt->wellFormed = 0;
1.52 daniel 3459: return(NULL);
1.43 daniel 3460: }
3461:
1.72 daniel 3462: *value = val;
3463: return(name);
1.3 veillard 3464: }
3465:
1.50 daniel 3466: /**
3467: * xmlParseStartTag:
3468: * @ctxt: an XML parser context
3469: *
3470: * parse a start of tag either for rule element or
3471: * EmptyElement. In both case we don't parse the tag closing chars.
1.27 daniel 3472: *
3473: * [40] STag ::= '<' Name (S Attribute)* S? '>'
3474: *
1.29 daniel 3475: * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
3476: *
3477: * With namespace:
3478: *
3479: * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
3480: *
3481: * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
1.83 daniel 3482: *
3483: * Returns the element name parsed
1.2 veillard 3484: */
3485:
1.83 daniel 3486: CHAR *
1.69 daniel 3487: xmlParseStartTag(xmlParserCtxtPtr ctxt) {
1.72 daniel 3488: CHAR *name;
3489: CHAR *attname;
3490: CHAR *attvalue;
3491: const CHAR **atts = NULL;
3492: int nbatts = 0;
3493: int maxatts = 0;
3494: int i;
1.2 veillard 3495:
1.83 daniel 3496: if (CUR != '<') return(NULL);
1.40 daniel 3497: NEXT;
1.3 veillard 3498:
1.72 daniel 3499: name = xmlParseName(ctxt);
1.59 daniel 3500: if (name == NULL) {
3501: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3502: ctxt->sax->error(ctxt->userData,
1.59 daniel 3503: "xmlParseStartTag: invalid element name\n");
3504: ctxt->wellFormed = 0;
1.83 daniel 3505: return(NULL);
1.50 daniel 3506: }
3507:
3508: /*
1.3 veillard 3509: * Now parse the attributes, it ends up with the ending
3510: *
3511: * (S Attribute)* S?
3512: */
1.42 daniel 3513: SKIP_BLANKS;
1.40 daniel 3514: while ((IS_CHAR(CUR)) &&
3515: (CUR != '>') &&
3516: ((CUR != '/') || (NXT(1) != '>'))) {
3517: const CHAR *q = CUR_PTR;
1.29 daniel 3518:
1.72 daniel 3519: attname = xmlParseAttribute(ctxt, &attvalue);
3520: if ((attname != NULL) && (attvalue != NULL)) {
3521: /*
3522: * Well formedness requires at most one declaration of an attribute
3523: */
3524: for (i = 0; i < nbatts;i += 2) {
3525: if (!xmlStrcmp(atts[i], attname)) {
3526: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3527: ctxt->sax->error(ctxt->userData, "Attribute %s redefined\n",
1.72 daniel 3528: name);
3529: ctxt->wellFormed = 0;
3530: free(attname);
3531: free(attvalue);
3532: break;
3533: }
3534: }
3535:
3536: /*
3537: * Add the pair to atts
3538: */
3539: if (atts == NULL) {
3540: maxatts = 10;
3541: atts = (const CHAR **) malloc(maxatts * sizeof(CHAR *));
3542: if (atts == NULL) {
3543: fprintf(stderr, "malloc of %d byte failed\n",
3544: maxatts * sizeof(CHAR *));
1.83 daniel 3545: return(NULL);
1.72 daniel 3546: }
3547: } else if (nbatts + 2 < maxatts) {
3548: maxatts *= 2;
3549: atts = (const CHAR **) realloc(atts, maxatts * sizeof(CHAR *));
3550: if (atts == NULL) {
3551: fprintf(stderr, "realloc of %d byte failed\n",
3552: maxatts * sizeof(CHAR *));
1.83 daniel 3553: return(NULL);
1.72 daniel 3554: }
3555: }
3556: atts[nbatts++] = attname;
3557: atts[nbatts++] = attvalue;
3558: atts[nbatts] = NULL;
3559: atts[nbatts + 1] = NULL;
3560: }
3561:
1.42 daniel 3562: SKIP_BLANKS;
1.40 daniel 3563: if (q == CUR_PTR) {
1.55 daniel 3564: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3565: ctxt->sax->error(ctxt->userData,
1.31 daniel 3566: "xmlParseStartTag: problem parsing attributes\n");
1.59 daniel 3567: ctxt->wellFormed = 0;
1.29 daniel 3568: break;
1.3 veillard 3569: }
3570: }
3571:
1.43 daniel 3572: /*
1.72 daniel 3573: * SAX: Start of Element !
1.43 daniel 3574: */
1.72 daniel 3575: if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
1.74 daniel 3576: ctxt->sax->startElement(ctxt->userData, name, atts);
1.43 daniel 3577:
1.72 daniel 3578: if (atts != NULL) {
3579: for (i = 0;i < nbatts;i++) free((CHAR *) atts[i]);
3580: free(atts);
3581: }
1.83 daniel 3582: return(name);
1.3 veillard 3583: }
3584:
1.50 daniel 3585: /**
3586: * xmlParseEndTag:
3587: * @ctxt: an XML parser context
1.83 daniel 3588: * @tagname: the tag name as parsed in the opening tag.
1.50 daniel 3589: *
3590: * parse an end of tag
1.27 daniel 3591: *
3592: * [42] ETag ::= '</' Name S? '>'
1.29 daniel 3593: *
3594: * With namespace
3595: *
1.72 daniel 3596: * [NS 9] ETag ::= '</' QName S? '>'
1.7 veillard 3597: */
3598:
1.55 daniel 3599: void
1.83 daniel 3600: xmlParseEndTag(xmlParserCtxtPtr ctxt, CHAR *tagname) {
1.72 daniel 3601: CHAR *name;
1.7 veillard 3602:
1.40 daniel 3603: if ((CUR != '<') || (NXT(1) != '/')) {
1.55 daniel 3604: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3605: ctxt->sax->error(ctxt->userData, "xmlParseEndTag: '</' not found\n");
1.59 daniel 3606: ctxt->wellFormed = 0;
1.27 daniel 3607: return;
3608: }
1.40 daniel 3609: SKIP(2);
1.7 veillard 3610:
1.72 daniel 3611: name = xmlParseName(ctxt);
1.7 veillard 3612:
3613: /*
3614: * We should definitely be at the ending "S? '>'" part
3615: */
1.42 daniel 3616: SKIP_BLANKS;
1.40 daniel 3617: if ((!IS_CHAR(CUR)) || (CUR != '>')) {
1.55 daniel 3618: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3619: ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
1.59 daniel 3620: ctxt->wellFormed = 0;
1.7 veillard 3621: } else
1.40 daniel 3622: NEXT;
1.7 veillard 3623:
1.72 daniel 3624: /*
1.83 daniel 3625: * Well formedness constraints, opening and closing must match.
3626: */
3627: if (xmlStrcmp(name, tagname)) {
3628: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3629: ctxt->sax->error(ctxt->userData,
3630: "Opening and ending tag mismatch: %s and %s\n", tagname, name);
3631: ctxt->wellFormed = 0;
3632: }
3633:
3634: /*
1.72 daniel 3635: * SAX: End of Tag
3636: */
3637: if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
1.74 daniel 3638: ctxt->sax->endElement(ctxt->userData, name);
1.72 daniel 3639:
3640: if (name != NULL)
3641: free(name);
3642:
1.7 veillard 3643: return;
3644: }
3645:
1.50 daniel 3646: /**
3647: * xmlParseCDSect:
3648: * @ctxt: an XML parser context
3649: *
3650: * Parse escaped pure raw content.
1.29 daniel 3651: *
3652: * [18] CDSect ::= CDStart CData CDEnd
3653: *
3654: * [19] CDStart ::= '<![CDATA['
3655: *
3656: * [20] Data ::= (Char* - (Char* ']]>' Char*))
3657: *
3658: * [21] CDEnd ::= ']]>'
1.3 veillard 3659: */
1.55 daniel 3660: void
3661: xmlParseCDSect(xmlParserCtxtPtr ctxt) {
1.17 daniel 3662: const CHAR *r, *s, *base;
1.3 veillard 3663:
1.40 daniel 3664: if ((CUR == '<') && (NXT(1) == '!') &&
3665: (NXT(2) == '[') && (NXT(3) == 'C') &&
3666: (NXT(4) == 'D') && (NXT(5) == 'A') &&
3667: (NXT(6) == 'T') && (NXT(7) == 'A') &&
3668: (NXT(8) == '[')) {
3669: SKIP(9);
1.29 daniel 3670: } else
1.45 daniel 3671: return;
1.40 daniel 3672: base = CUR_PTR;
3673: if (!IS_CHAR(CUR)) {
1.55 daniel 3674: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3675: ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
1.59 daniel 3676: ctxt->wellFormed = 0;
1.45 daniel 3677: return;
1.3 veillard 3678: }
1.40 daniel 3679: r = NEXT;
3680: if (!IS_CHAR(CUR)) {
1.55 daniel 3681: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3682: ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
1.59 daniel 3683: ctxt->wellFormed = 0;
1.45 daniel 3684: return;
1.3 veillard 3685: }
1.40 daniel 3686: s = NEXT;
3687: while (IS_CHAR(CUR) &&
3688: ((*r != ']') || (*s != ']') || (CUR != '>'))) {
3689: r++;s++;NEXT;
1.3 veillard 3690: }
1.40 daniel 3691: if (!IS_CHAR(CUR)) {
1.55 daniel 3692: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3693: ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
1.59 daniel 3694: ctxt->wellFormed = 0;
1.45 daniel 3695: return;
1.3 veillard 3696: }
1.16 daniel 3697:
1.45 daniel 3698: /*
3699: * Ok the segment [base CUR_PTR] is to be consumed as chars.
3700: */
3701: if (ctxt->sax != NULL) {
1.72 daniel 3702: if (areBlanks(ctxt, base, CUR_PTR - base)) {
3703: if (ctxt->sax->ignorableWhitespace != NULL)
1.74 daniel 3704: ctxt->sax->ignorableWhitespace(ctxt->userData, base,
1.72 daniel 3705: (CUR_PTR - base) - 2);
3706: } else {
3707: if (ctxt->sax->characters != NULL)
1.74 daniel 3708: ctxt->sax->characters(ctxt->userData, base, (CUR_PTR - base) - 2);
1.72 daniel 3709: }
1.45 daniel 3710: }
1.2 veillard 3711: }
3712:
1.50 daniel 3713: /**
3714: * xmlParseContent:
3715: * @ctxt: an XML parser context
3716: *
3717: * Parse a content:
1.2 veillard 3718: *
1.27 daniel 3719: * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
1.2 veillard 3720: */
3721:
1.55 daniel 3722: void
3723: xmlParseContent(xmlParserCtxtPtr ctxt) {
1.40 daniel 3724: while ((CUR != '<') || (NXT(1) != '/')) {
3725: const CHAR *test = CUR_PTR;
1.27 daniel 3726:
3727: /*
3728: * First case : a Processing Instruction.
3729: */
1.40 daniel 3730: if ((CUR == '<') && (NXT(1) == '?')) {
1.27 daniel 3731: xmlParsePI(ctxt);
3732: }
1.72 daniel 3733:
1.27 daniel 3734: /*
3735: * Second case : a CDSection
3736: */
1.40 daniel 3737: else if ((CUR == '<') && (NXT(1) == '!') &&
3738: (NXT(2) == '[') && (NXT(3) == 'C') &&
3739: (NXT(4) == 'D') && (NXT(5) == 'A') &&
3740: (NXT(6) == 'T') && (NXT(7) == 'A') &&
3741: (NXT(8) == '[')) {
1.45 daniel 3742: xmlParseCDSect(ctxt);
1.27 daniel 3743: }
1.72 daniel 3744:
1.27 daniel 3745: /*
3746: * Third case : a comment
3747: */
1.40 daniel 3748: else if ((CUR == '<') && (NXT(1) == '!') &&
3749: (NXT(2) == '-') && (NXT(3) == '-')) {
1.72 daniel 3750: xmlParseComment(ctxt, 1);
1.27 daniel 3751: }
1.72 daniel 3752:
1.27 daniel 3753: /*
3754: * Fourth case : a sub-element.
3755: */
1.40 daniel 3756: else if (CUR == '<') {
1.72 daniel 3757: xmlParseElement(ctxt);
1.45 daniel 3758: }
1.72 daniel 3759:
1.45 daniel 3760: /*
1.50 daniel 3761: * Fifth case : a reference. If if has not been resolved,
3762: * parsing returns it's Name, create the node
1.45 daniel 3763: */
3764: else if (CUR == '&') {
1.77 daniel 3765: xmlParseReference(ctxt);
1.27 daniel 3766: }
1.72 daniel 3767:
1.27 daniel 3768: /*
3769: * Last case, text. Note that References are handled directly.
3770: */
3771: else {
1.45 daniel 3772: xmlParseCharData(ctxt, 0);
1.3 veillard 3773: }
1.14 veillard 3774:
3775: /*
1.45 daniel 3776: * Pop-up of finished entities.
1.14 veillard 3777: */
1.69 daniel 3778: while ((CUR == 0) && (ctxt->inputNr > 1))
3779: xmlPopInput(ctxt);
1.45 daniel 3780:
1.40 daniel 3781: if (test == CUR_PTR) {
1.55 daniel 3782: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3783: ctxt->sax->error(ctxt->userData,
1.59 daniel 3784: "detected an error in element content\n");
3785: ctxt->wellFormed = 0;
1.29 daniel 3786: break;
3787: }
1.3 veillard 3788: }
1.2 veillard 3789: }
3790:
1.50 daniel 3791: /**
3792: * xmlParseElement:
3793: * @ctxt: an XML parser context
3794: *
3795: * parse an XML element, this is highly recursive
1.26 daniel 3796: *
3797: * [39] element ::= EmptyElemTag | STag content ETag
3798: *
3799: * [41] Attribute ::= Name Eq AttValue
1.2 veillard 3800: */
1.26 daniel 3801:
1.72 daniel 3802: void
1.69 daniel 3803: xmlParseElement(xmlParserCtxtPtr ctxt) {
1.40 daniel 3804: const CHAR *openTag = CUR_PTR;
1.83 daniel 3805: CHAR *name;
1.32 daniel 3806: xmlParserNodeInfo node_info;
1.2 veillard 3807:
1.32 daniel 3808: /* Capture start position */
1.40 daniel 3809: node_info.begin_pos = CUR_PTR - ctxt->input->base;
3810: node_info.begin_line = ctxt->input->line;
1.32 daniel 3811:
1.83 daniel 3812: name = xmlParseStartTag(ctxt);
3813: if (name == NULL) {
3814: return;
3815: }
1.2 veillard 3816:
3817: /*
3818: * Check for an Empty Element.
3819: */
1.40 daniel 3820: if ((CUR == '/') && (NXT(1) == '>')) {
3821: SKIP(2);
1.72 daniel 3822: if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
1.83 daniel 3823: ctxt->sax->endElement(ctxt->userData, name);
3824: free(name);
1.72 daniel 3825: return;
1.2 veillard 3826: }
1.40 daniel 3827: if (CUR == '>') NEXT;
1.2 veillard 3828: else {
1.55 daniel 3829: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3830: ctxt->sax->error(ctxt->userData, "Couldn't find end of Start Tag\n%.30s\n",
1.57 daniel 3831: openTag);
1.59 daniel 3832: ctxt->wellFormed = 0;
1.45 daniel 3833:
3834: /*
3835: * end of parsing of this node.
3836: */
3837: nodePop(ctxt);
1.83 daniel 3838: free(name);
1.72 daniel 3839: return;
1.2 veillard 3840: }
3841:
3842: /*
3843: * Parse the content of the element:
3844: */
1.45 daniel 3845: xmlParseContent(ctxt);
1.40 daniel 3846: if (!IS_CHAR(CUR)) {
1.55 daniel 3847: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3848: ctxt->sax->error(ctxt->userData,
1.57 daniel 3849: "Premature end of data in tag %.30s\n", openTag);
1.59 daniel 3850: ctxt->wellFormed = 0;
1.45 daniel 3851:
3852: /*
3853: * end of parsing of this node.
3854: */
3855: nodePop(ctxt);
1.83 daniel 3856: free(name);
1.72 daniel 3857: return;
1.2 veillard 3858: }
3859:
3860: /*
1.27 daniel 3861: * parse the end of tag: '</' should be here.
1.2 veillard 3862: */
1.83 daniel 3863: xmlParseEndTag(ctxt, name);
3864: free(name);
1.2 veillard 3865: }
3866:
1.50 daniel 3867: /**
3868: * xmlParseVersionNum:
3869: * @ctxt: an XML parser context
3870: *
3871: * parse the XML version value.
1.29 daniel 3872: *
3873: * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
1.68 daniel 3874: *
3875: * Returns the string giving the XML version number, or NULL
1.29 daniel 3876: */
1.55 daniel 3877: CHAR *
3878: xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
1.40 daniel 3879: const CHAR *q = CUR_PTR;
1.29 daniel 3880: CHAR *ret;
3881:
1.40 daniel 3882: while (IS_CHAR(CUR) &&
3883: (((CUR >= 'a') && (CUR <= 'z')) ||
3884: ((CUR >= 'A') && (CUR <= 'Z')) ||
3885: ((CUR >= '0') && (CUR <= '9')) ||
3886: (CUR == '_') || (CUR == '.') ||
3887: (CUR == ':') || (CUR == '-'))) NEXT;
3888: ret = xmlStrndup(q, CUR_PTR - q);
1.29 daniel 3889: return(ret);
3890: }
3891:
1.50 daniel 3892: /**
3893: * xmlParseVersionInfo:
3894: * @ctxt: an XML parser context
3895: *
3896: * parse the XML version.
1.29 daniel 3897: *
3898: * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
3899: *
3900: * [25] Eq ::= S? '=' S?
1.50 daniel 3901: *
1.68 daniel 3902: * Returns the version string, e.g. "1.0"
1.29 daniel 3903: */
3904:
1.55 daniel 3905: CHAR *
3906: xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
1.29 daniel 3907: CHAR *version = NULL;
3908: const CHAR *q;
3909:
1.40 daniel 3910: if ((CUR == 'v') && (NXT(1) == 'e') &&
3911: (NXT(2) == 'r') && (NXT(3) == 's') &&
3912: (NXT(4) == 'i') && (NXT(5) == 'o') &&
3913: (NXT(6) == 'n')) {
3914: SKIP(7);
1.42 daniel 3915: SKIP_BLANKS;
1.40 daniel 3916: if (CUR != '=') {
1.55 daniel 3917: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3918: ctxt->sax->error(ctxt->userData, "xmlParseVersionInfo : expected '='\n");
1.59 daniel 3919: ctxt->wellFormed = 0;
1.31 daniel 3920: return(NULL);
3921: }
1.40 daniel 3922: NEXT;
1.42 daniel 3923: SKIP_BLANKS;
1.40 daniel 3924: if (CUR == '"') {
3925: NEXT;
3926: q = CUR_PTR;
1.29 daniel 3927: version = xmlParseVersionNum(ctxt);
1.55 daniel 3928: if (CUR != '"') {
3929: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3930: ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59 daniel 3931: ctxt->wellFormed = 0;
1.55 daniel 3932: } else
1.40 daniel 3933: NEXT;
3934: } else if (CUR == '\''){
3935: NEXT;
3936: q = CUR_PTR;
1.29 daniel 3937: version = xmlParseVersionNum(ctxt);
1.55 daniel 3938: if (CUR != '\'') {
3939: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3940: ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59 daniel 3941: ctxt->wellFormed = 0;
1.55 daniel 3942: } else
1.40 daniel 3943: NEXT;
1.31 daniel 3944: } else {
1.55 daniel 3945: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3946: ctxt->sax->error(ctxt->userData,
1.59 daniel 3947: "xmlParseVersionInfo : expected ' or \"\n");
3948: ctxt->wellFormed = 0;
1.29 daniel 3949: }
3950: }
3951: return(version);
3952: }
3953:
1.50 daniel 3954: /**
3955: * xmlParseEncName:
3956: * @ctxt: an XML parser context
3957: *
3958: * parse the XML encoding name
1.29 daniel 3959: *
3960: * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
1.50 daniel 3961: *
1.68 daniel 3962: * Returns the encoding name value or NULL
1.29 daniel 3963: */
1.55 daniel 3964: CHAR *
3965: xmlParseEncName(xmlParserCtxtPtr ctxt) {
1.40 daniel 3966: const CHAR *q = CUR_PTR;
1.29 daniel 3967: CHAR *ret = NULL;
3968:
1.40 daniel 3969: if (((CUR >= 'a') && (CUR <= 'z')) ||
3970: ((CUR >= 'A') && (CUR <= 'Z'))) {
3971: NEXT;
3972: while (IS_CHAR(CUR) &&
3973: (((CUR >= 'a') && (CUR <= 'z')) ||
3974: ((CUR >= 'A') && (CUR <= 'Z')) ||
3975: ((CUR >= '0') && (CUR <= '9')) ||
3976: (CUR == '-'))) NEXT;
3977: ret = xmlStrndup(q, CUR_PTR - q);
1.29 daniel 3978: } else {
1.55 daniel 3979: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 3980: ctxt->sax->error(ctxt->userData, "Invalid XML encoding name\n");
1.59 daniel 3981: ctxt->wellFormed = 0;
1.29 daniel 3982: }
3983: return(ret);
3984: }
3985:
1.50 daniel 3986: /**
3987: * xmlParseEncodingDecl:
3988: * @ctxt: an XML parser context
3989: *
3990: * parse the XML encoding declaration
1.29 daniel 3991: *
3992: * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'")
1.50 daniel 3993: *
3994: * TODO: this should setup the conversion filters.
3995: *
1.68 daniel 3996: * Returns the encoding value or NULL
1.29 daniel 3997: */
3998:
1.55 daniel 3999: CHAR *
4000: xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
1.29 daniel 4001: CHAR *encoding = NULL;
4002: const CHAR *q;
4003:
1.42 daniel 4004: SKIP_BLANKS;
1.40 daniel 4005: if ((CUR == 'e') && (NXT(1) == 'n') &&
4006: (NXT(2) == 'c') && (NXT(3) == 'o') &&
4007: (NXT(4) == 'd') && (NXT(5) == 'i') &&
4008: (NXT(6) == 'n') && (NXT(7) == 'g')) {
4009: SKIP(8);
1.42 daniel 4010: SKIP_BLANKS;
1.40 daniel 4011: if (CUR != '=') {
1.55 daniel 4012: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4013: ctxt->sax->error(ctxt->userData, "xmlParseEncodingDecl : expected '='\n");
1.59 daniel 4014: ctxt->wellFormed = 0;
1.31 daniel 4015: return(NULL);
4016: }
1.40 daniel 4017: NEXT;
1.42 daniel 4018: SKIP_BLANKS;
1.40 daniel 4019: if (CUR == '"') {
4020: NEXT;
4021: q = CUR_PTR;
1.29 daniel 4022: encoding = xmlParseEncName(ctxt);
1.55 daniel 4023: if (CUR != '"') {
4024: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4025: ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59 daniel 4026: ctxt->wellFormed = 0;
1.55 daniel 4027: } else
1.40 daniel 4028: NEXT;
4029: } else if (CUR == '\''){
4030: NEXT;
4031: q = CUR_PTR;
1.29 daniel 4032: encoding = xmlParseEncName(ctxt);
1.55 daniel 4033: if (CUR != '\'') {
4034: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4035: ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59 daniel 4036: ctxt->wellFormed = 0;
1.55 daniel 4037: } else
1.40 daniel 4038: NEXT;
4039: } else if (CUR == '"'){
1.55 daniel 4040: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4041: ctxt->sax->error(ctxt->userData,
1.59 daniel 4042: "xmlParseEncodingDecl : expected ' or \"\n");
4043: ctxt->wellFormed = 0;
1.29 daniel 4044: }
4045: }
4046: return(encoding);
4047: }
4048:
1.50 daniel 4049: /**
4050: * xmlParseSDDecl:
4051: * @ctxt: an XML parser context
4052: *
4053: * parse the XML standalone declaration
1.29 daniel 4054: *
4055: * [32] SDDecl ::= S 'standalone' Eq
4056: * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"'))
1.68 daniel 4057: *
4058: * Returns 1 if standalone, 0 otherwise
1.29 daniel 4059: */
4060:
1.55 daniel 4061: int
4062: xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
1.29 daniel 4063: int standalone = -1;
4064:
1.42 daniel 4065: SKIP_BLANKS;
1.40 daniel 4066: if ((CUR == 's') && (NXT(1) == 't') &&
4067: (NXT(2) == 'a') && (NXT(3) == 'n') &&
4068: (NXT(4) == 'd') && (NXT(5) == 'a') &&
4069: (NXT(6) == 'l') && (NXT(7) == 'o') &&
4070: (NXT(8) == 'n') && (NXT(9) == 'e')) {
4071: SKIP(10);
1.81 daniel 4072: SKIP_BLANKS;
1.40 daniel 4073: if (CUR != '=') {
1.55 daniel 4074: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4075: ctxt->sax->error(ctxt->userData,
1.59 daniel 4076: "XML standalone declaration : expected '='\n");
4077: ctxt->wellFormed = 0;
1.32 daniel 4078: return(standalone);
4079: }
1.40 daniel 4080: NEXT;
1.42 daniel 4081: SKIP_BLANKS;
1.40 daniel 4082: if (CUR == '\''){
4083: NEXT;
4084: if ((CUR == 'n') && (NXT(1) == 'o')) {
1.29 daniel 4085: standalone = 0;
1.40 daniel 4086: SKIP(2);
4087: } else if ((CUR == 'y') && (NXT(1) == 'e') &&
4088: (NXT(2) == 's')) {
1.29 daniel 4089: standalone = 1;
1.40 daniel 4090: SKIP(3);
1.29 daniel 4091: } else {
1.55 daniel 4092: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4093: ctxt->sax->error(ctxt->userData, "standalone accepts only 'yes' or 'no'\n");
1.59 daniel 4094: ctxt->wellFormed = 0;
1.29 daniel 4095: }
1.55 daniel 4096: if (CUR != '\'') {
4097: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4098: ctxt->sax->error(ctxt->userData, "String not closed\n");
1.59 daniel 4099: ctxt->wellFormed = 0;
1.55 daniel 4100: } else
1.40 daniel 4101: NEXT;
4102: } else if (CUR == '"'){
4103: NEXT;
4104: if ((CUR == 'n') && (NXT(1) == 'o')) {
1.29 daniel 4105: standalone = 0;
1.40 daniel 4106: SKIP(2);
4107: } else if ((CUR == 'y') && (NXT(1) == 'e') &&
4108: (NXT(2) == 's')) {
1.29 daniel 4109: standalone = 1;
1.40 daniel 4110: SKIP(3);
1.29 daniel 4111: } else {
1.55 daniel 4112: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4113: ctxt->sax->error(ctxt->userData,
1.59 daniel 4114: "standalone accepts only 'yes' or 'no'\n");
4115: ctxt->wellFormed = 0;
1.29 daniel 4116: }
1.55 daniel 4117: if (CUR != '"') {
4118: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4119: ctxt->sax->error(ctxt->userData, "String not closed\n");
1.59 daniel 4120: ctxt->wellFormed = 0;
1.55 daniel 4121: } else
1.40 daniel 4122: NEXT;
1.37 daniel 4123: } else {
1.55 daniel 4124: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4125: ctxt->sax->error(ctxt->userData, "Standalone value not found\n");
1.59 daniel 4126: ctxt->wellFormed = 0;
1.37 daniel 4127: }
1.29 daniel 4128: }
4129: return(standalone);
4130: }
4131:
1.50 daniel 4132: /**
4133: * xmlParseXMLDecl:
4134: * @ctxt: an XML parser context
4135: *
4136: * parse an XML declaration header
1.29 daniel 4137: *
4138: * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
1.1 veillard 4139: */
4140:
1.55 daniel 4141: void
4142: xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
1.1 veillard 4143: CHAR *version;
4144:
4145: /*
1.19 daniel 4146: * We know that '<?xml' is here.
1.1 veillard 4147: */
1.40 daniel 4148: SKIP(5);
1.1 veillard 4149:
1.59 daniel 4150: if (!IS_BLANK(CUR)) {
4151: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4152: ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
1.59 daniel 4153: ctxt->wellFormed = 0;
4154: }
1.42 daniel 4155: SKIP_BLANKS;
1.1 veillard 4156:
4157: /*
1.29 daniel 4158: * We should have the VersionInfo here.
1.1 veillard 4159: */
1.29 daniel 4160: version = xmlParseVersionInfo(ctxt);
4161: if (version == NULL)
1.45 daniel 4162: version = xmlCharStrdup(XML_DEFAULT_VERSION);
1.72 daniel 4163: ctxt->version = xmlStrdup(version);
1.45 daniel 4164: free(version);
1.29 daniel 4165:
4166: /*
4167: * We may have the encoding declaration
4168: */
1.59 daniel 4169: if (!IS_BLANK(CUR)) {
4170: if ((CUR == '?') && (NXT(1) == '>')) {
4171: SKIP(2);
4172: return;
4173: }
4174: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4175: ctxt->sax->error(ctxt->userData, "Blank needed here\n");
1.59 daniel 4176: ctxt->wellFormed = 0;
4177: }
1.72 daniel 4178: ctxt->encoding = xmlParseEncodingDecl(ctxt);
1.1 veillard 4179:
4180: /*
1.29 daniel 4181: * We may have the standalone status.
1.1 veillard 4182: */
1.72 daniel 4183: if ((ctxt->encoding != NULL) && (!IS_BLANK(CUR))) {
1.59 daniel 4184: if ((CUR == '?') && (NXT(1) == '>')) {
4185: SKIP(2);
4186: return;
4187: }
4188: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4189: ctxt->sax->error(ctxt->userData, "Blank needed here\n");
1.59 daniel 4190: ctxt->wellFormed = 0;
4191: }
4192: SKIP_BLANKS;
1.72 daniel 4193: ctxt->standalone = xmlParseSDDecl(ctxt);
1.1 veillard 4194:
1.42 daniel 4195: SKIP_BLANKS;
1.40 daniel 4196: if ((CUR == '?') && (NXT(1) == '>')) {
4197: SKIP(2);
4198: } else if (CUR == '>') {
1.31 daniel 4199: /* Deprecated old WD ... */
1.55 daniel 4200: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4201: ctxt->sax->error(ctxt->userData, "XML declaration must end-up with '?>'\n");
1.59 daniel 4202: ctxt->wellFormed = 0;
1.40 daniel 4203: NEXT;
1.29 daniel 4204: } else {
1.55 daniel 4205: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4206: ctxt->sax->error(ctxt->userData, "parsing XML declaration: '?>' expected\n");
1.59 daniel 4207: ctxt->wellFormed = 0;
1.40 daniel 4208: MOVETO_ENDTAG(CUR_PTR);
4209: NEXT;
1.29 daniel 4210: }
1.1 veillard 4211: }
4212:
1.50 daniel 4213: /**
4214: * xmlParseMisc:
4215: * @ctxt: an XML parser context
4216: *
4217: * parse an XML Misc* optionnal field.
1.21 daniel 4218: *
1.22 daniel 4219: * [27] Misc ::= Comment | PI | S
1.1 veillard 4220: */
4221:
1.55 daniel 4222: void
4223: xmlParseMisc(xmlParserCtxtPtr ctxt) {
1.40 daniel 4224: while (((CUR == '<') && (NXT(1) == '?')) ||
4225: ((CUR == '<') && (NXT(1) == '!') &&
4226: (NXT(2) == '-') && (NXT(3) == '-')) ||
4227: IS_BLANK(CUR)) {
4228: if ((CUR == '<') && (NXT(1) == '?')) {
1.16 daniel 4229: xmlParsePI(ctxt);
1.40 daniel 4230: } else if (IS_BLANK(CUR)) {
4231: NEXT;
1.1 veillard 4232: } else
1.31 daniel 4233: xmlParseComment(ctxt, 0);
1.1 veillard 4234: }
4235: }
4236:
1.50 daniel 4237: /**
4238: * xmlParseDocument :
4239: * @ctxt: an XML parser context
4240: *
4241: * parse an XML document (and build a tree if using the standard SAX
4242: * interface).
1.21 daniel 4243: *
1.22 daniel 4244: * [1] document ::= prolog element Misc*
1.29 daniel 4245: *
4246: * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
1.50 daniel 4247: *
1.68 daniel 4248: * Returns 0, -1 in case of error. the parser context is augmented
1.50 daniel 4249: * as a result of the parsing.
1.1 veillard 4250: */
4251:
1.55 daniel 4252: int
4253: xmlParseDocument(xmlParserCtxtPtr ctxt) {
1.45 daniel 4254: xmlDefaultSAXHandlerInit();
4255:
1.14 veillard 4256: /*
1.44 daniel 4257: * SAX: beginning of the document processing.
4258: */
1.72 daniel 4259: if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
1.74 daniel 4260: ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
1.44 daniel 4261:
4262: /*
1.14 veillard 4263: * We should check for encoding here and plug-in some
4264: * conversion code TODO !!!!
4265: */
1.1 veillard 4266:
4267: /*
4268: * Wipe out everything which is before the first '<'
4269: */
1.59 daniel 4270: if (IS_BLANK(CUR)) {
4271: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4272: ctxt->sax->error(ctxt->userData,
1.59 daniel 4273: "Extra spaces at the beginning of the document are not allowed\n");
4274: ctxt->wellFormed = 0;
4275: SKIP_BLANKS;
4276: }
4277:
4278: if (CUR == 0) {
4279: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4280: ctxt->sax->error(ctxt->userData, "Document is empty\n");
1.59 daniel 4281: ctxt->wellFormed = 0;
4282: }
1.1 veillard 4283:
4284: /*
4285: * Check for the XMLDecl in the Prolog.
4286: */
1.40 daniel 4287: if ((CUR == '<') && (NXT(1) == '?') &&
4288: (NXT(2) == 'x') && (NXT(3) == 'm') &&
4289: (NXT(4) == 'l')) {
1.19 daniel 4290: xmlParseXMLDecl(ctxt);
4291: /* SKIP_EOL(cur); */
1.42 daniel 4292: SKIP_BLANKS;
1.40 daniel 4293: } else if ((CUR == '<') && (NXT(1) == '?') &&
4294: (NXT(2) == 'X') && (NXT(3) == 'M') &&
4295: (NXT(4) == 'L')) {
1.19 daniel 4296: /*
4297: * The first drafts were using <?XML and the final W3C REC
4298: * now use <?xml ...
4299: */
1.16 daniel 4300: xmlParseXMLDecl(ctxt);
1.1 veillard 4301: /* SKIP_EOL(cur); */
1.42 daniel 4302: SKIP_BLANKS;
1.1 veillard 4303: } else {
1.72 daniel 4304: ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
1.1 veillard 4305: }
1.72 daniel 4306: if ((ctxt->sax) && (ctxt->sax->startDocument))
1.74 daniel 4307: ctxt->sax->startDocument(ctxt->userData);
1.1 veillard 4308:
4309: /*
4310: * The Misc part of the Prolog
4311: */
1.16 daniel 4312: xmlParseMisc(ctxt);
1.1 veillard 4313:
4314: /*
1.29 daniel 4315: * Then possibly doc type declaration(s) and more Misc
1.21 daniel 4316: * (doctypedecl Misc*)?
4317: */
1.40 daniel 4318: if ((CUR == '<') && (NXT(1) == '!') &&
4319: (NXT(2) == 'D') && (NXT(3) == 'O') &&
4320: (NXT(4) == 'C') && (NXT(5) == 'T') &&
4321: (NXT(6) == 'Y') && (NXT(7) == 'P') &&
4322: (NXT(8) == 'E')) {
1.22 daniel 4323: xmlParseDocTypeDecl(ctxt);
4324: xmlParseMisc(ctxt);
1.21 daniel 4325: }
4326:
4327: /*
4328: * Time to start parsing the tree itself
1.1 veillard 4329: */
1.72 daniel 4330: xmlParseElement(ctxt);
1.33 daniel 4331:
4332: /*
4333: * The Misc part at the end
4334: */
4335: xmlParseMisc(ctxt);
1.16 daniel 4336:
1.59 daniel 4337: if (CUR != 0) {
4338: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 4339: ctxt->sax->error(ctxt->userData,
1.59 daniel 4340: "Extra content at the end of the document\n");
4341: ctxt->wellFormed = 0;
4342: }
4343:
1.44 daniel 4344: /*
4345: * SAX: end of the document processing.
4346: */
1.72 daniel 4347: if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
1.74 daniel 4348: ctxt->sax->endDocument(ctxt->userData);
1.59 daniel 4349: if (! ctxt->wellFormed) return(-1);
1.16 daniel 4350: return(0);
4351: }
4352:
1.50 daniel 4353: /**
1.69 daniel 4354: * xmlCreateFileParserCtxt :
1.50 daniel 4355: * @cur: a pointer to an array of CHAR
4356: *
1.69 daniel 4357: * Create a parser context for an XML in-memory document.
4358: *
4359: * Returns the new parser context or NULL
1.16 daniel 4360: */
1.69 daniel 4361: xmlParserCtxtPtr
4362: xmlCreateDocParserCtxt(CHAR *cur) {
1.16 daniel 4363: xmlParserCtxtPtr ctxt;
1.40 daniel 4364: xmlParserInputPtr input;
1.75 daniel 4365: xmlCharEncoding enc;
1.16 daniel 4366:
4367: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4368: if (ctxt == NULL) {
4369: perror("malloc");
4370: return(NULL);
4371: }
1.40 daniel 4372: xmlInitParserCtxt(ctxt);
4373: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4374: if (input == NULL) {
4375: perror("malloc");
4376: free(ctxt);
4377: return(NULL);
4378: }
4379:
1.75 daniel 4380: /*
4381: * plug some encoding conversion routines here. !!!
4382: */
4383: enc = xmlDetectCharEncoding(cur);
4384: xmlSwitchEncoding(ctxt, enc);
4385:
1.40 daniel 4386: input->filename = NULL;
4387: input->line = 1;
4388: input->col = 1;
4389: input->base = cur;
4390: input->cur = cur;
1.69 daniel 4391: input->free = NULL;
1.40 daniel 4392:
4393: inputPush(ctxt, input);
1.69 daniel 4394: return(ctxt);
4395: }
4396:
4397: /**
4398: * xmlSAXParseDoc :
4399: * @sax: the SAX handler block
4400: * @cur: a pointer to an array of CHAR
4401: * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4402: * documents
4403: *
4404: * parse an XML in-memory document and build a tree.
4405: * It use the given SAX function block to handle the parsing callback.
4406: * If sax is NULL, fallback to the default DOM tree building routines.
4407: *
4408: * Returns the resulting document tree
4409: */
4410:
4411: xmlDocPtr
4412: xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur, int recovery) {
4413: xmlDocPtr ret;
4414: xmlParserCtxtPtr ctxt;
4415:
4416: if (cur == NULL) return(NULL);
1.16 daniel 4417:
4418:
1.69 daniel 4419: ctxt = xmlCreateDocParserCtxt(cur);
4420: if (ctxt == NULL) return(NULL);
1.74 daniel 4421: if (sax != NULL) {
4422: ctxt->sax = sax;
4423: ctxt->userData = NULL;
4424: }
1.69 daniel 4425:
1.16 daniel 4426: xmlParseDocument(ctxt);
1.72 daniel 4427: if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59 daniel 4428: else {
4429: ret = NULL;
1.72 daniel 4430: xmlFreeDoc(ctxt->myDoc);
4431: ctxt->myDoc = NULL;
1.59 daniel 4432: }
1.69 daniel 4433: xmlFreeParserCtxt(ctxt);
1.16 daniel 4434:
1.1 veillard 4435: return(ret);
4436: }
4437:
1.50 daniel 4438: /**
1.55 daniel 4439: * xmlParseDoc :
4440: * @cur: a pointer to an array of CHAR
4441: *
4442: * parse an XML in-memory document and build a tree.
4443: *
1.68 daniel 4444: * Returns the resulting document tree
1.55 daniel 4445: */
4446:
1.69 daniel 4447: xmlDocPtr
4448: xmlParseDoc(CHAR *cur) {
1.59 daniel 4449: return(xmlSAXParseDoc(NULL, cur, 0));
1.76 daniel 4450: }
4451:
4452: /**
4453: * xmlSAXParseDTD :
4454: * @sax: the SAX handler block
4455: * @ExternalID: a NAME* containing the External ID of the DTD
4456: * @SystemID: a NAME* containing the URL to the DTD
4457: *
4458: * Load and parse an external subset.
4459: *
4460: * Returns the resulting xmlDtdPtr or NULL in case of error.
4461: */
4462:
4463: xmlDtdPtr
4464: xmlSAXParseDTD(xmlSAXHandlerPtr sax, const CHAR *ExternalID,
4465: const CHAR *SystemID) {
4466: xmlDtdPtr ret = NULL;
4467: xmlParserCtxtPtr ctxt;
1.83 daniel 4468: xmlParserInputPtr input = NULL;
1.76 daniel 4469: xmlCharEncoding enc;
4470:
4471: if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL);
4472:
4473: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4474: if (ctxt == NULL) {
4475: perror("malloc");
4476: return(NULL);
4477: }
4478: xmlInitParserCtxt(ctxt);
4479:
4480: /*
4481: * Set-up the SAX context
4482: */
4483: if (ctxt == NULL) return(NULL);
4484: if (sax != NULL) {
4485: ctxt->sax = sax;
4486: ctxt->userData = NULL;
4487: }
4488:
4489: /*
4490: * Ask the Entity resolver to load the damn thing
4491: */
4492:
4493: if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
4494: input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, SystemID);
4495: if (input == NULL) {
4496: xmlFreeParserCtxt(ctxt);
4497: return(NULL);
4498: }
4499:
4500: /*
4501: * plug some encoding conversion routines here. !!!
4502: */
4503: xmlPushInput(ctxt, input);
4504: enc = xmlDetectCharEncoding(ctxt->input->cur);
4505: xmlSwitchEncoding(ctxt, enc);
4506:
4507: input->filename = xmlStrdup(SystemID);
4508: input->line = 1;
4509: input->col = 1;
4510: input->base = ctxt->input->cur;
4511: input->cur = ctxt->input->cur;
4512: input->free = NULL;
4513:
4514: /*
4515: * let's parse that entity knowing it's an external subset.
4516: */
1.79 daniel 4517: xmlParseExternalSubset(ctxt, ExternalID, SystemID);
1.76 daniel 4518:
4519: if (ctxt->myDoc != NULL) {
4520: if (ctxt->wellFormed) {
4521: ret = ctxt->myDoc->intSubset;
4522: ctxt->myDoc->intSubset = NULL;
4523: } else {
4524: ret = NULL;
4525: }
4526: xmlFreeDoc(ctxt->myDoc);
4527: ctxt->myDoc = NULL;
4528: }
4529: xmlFreeParserCtxt(ctxt);
4530:
4531: return(ret);
4532: }
4533:
4534: /**
4535: * xmlParseDTD :
4536: * @ExternalID: a NAME* containing the External ID of the DTD
4537: * @SystemID: a NAME* containing the URL to the DTD
4538: *
4539: * Load and parse an external subset.
4540: *
4541: * Returns the resulting xmlDtdPtr or NULL in case of error.
4542: */
4543:
4544: xmlDtdPtr
4545: xmlParseDTD(const CHAR *ExternalID, const CHAR *SystemID) {
4546: return(xmlSAXParseDTD(NULL, ExternalID, SystemID));
1.59 daniel 4547: }
4548:
4549: /**
4550: * xmlRecoverDoc :
4551: * @cur: a pointer to an array of CHAR
4552: *
4553: * parse an XML in-memory document and build a tree.
4554: * In the case the document is not Well Formed, a tree is built anyway
4555: *
1.68 daniel 4556: * Returns the resulting document tree
1.59 daniel 4557: */
4558:
1.69 daniel 4559: xmlDocPtr
4560: xmlRecoverDoc(CHAR *cur) {
1.59 daniel 4561: return(xmlSAXParseDoc(NULL, cur, 1));
1.55 daniel 4562: }
4563:
4564: /**
1.69 daniel 4565: * xmlCreateFileParserCtxt :
1.50 daniel 4566: * @filename: the filename
4567: *
1.69 daniel 4568: * Create a parser context for a file content.
4569: * Automatic support for ZLIB/Compress compressed document is provided
4570: * by default if found at compile-time.
1.50 daniel 4571: *
1.69 daniel 4572: * Returns the new parser context or NULL
1.9 httpng 4573: */
1.69 daniel 4574: xmlParserCtxtPtr
4575: xmlCreateFileParserCtxt(const char *filename)
4576: {
4577: xmlParserCtxtPtr ctxt;
1.20 daniel 4578: #ifdef HAVE_ZLIB_H
4579: gzFile input;
4580: #else
1.9 httpng 4581: int input;
1.20 daniel 4582: #endif
1.9 httpng 4583: int res;
1.55 daniel 4584: int len;
1.9 httpng 4585: struct stat buf;
4586: char *buffer;
1.40 daniel 4587: xmlParserInputPtr inputStream;
1.75 daniel 4588: xmlCharEncoding enc;
1.9 httpng 4589:
1.11 veillard 4590: res = stat(filename, &buf);
1.9 httpng 4591: if (res < 0) return(NULL);
4592:
1.20 daniel 4593: #ifdef HAVE_ZLIB_H
1.55 daniel 4594: len = (buf.st_size * 8) + 1000;
1.20 daniel 4595: retry_bigger:
1.55 daniel 4596: buffer = malloc(len);
1.20 daniel 4597: #else
1.55 daniel 4598: len = buf.st_size + 100;
4599: buffer = malloc(len);
1.20 daniel 4600: #endif
1.9 httpng 4601: if (buffer == NULL) {
4602: perror("malloc");
4603: return(NULL);
4604: }
4605:
1.55 daniel 4606: memset(buffer, 0, len);
1.20 daniel 4607: #ifdef HAVE_ZLIB_H
4608: input = gzopen (filename, "r");
4609: if (input == NULL) {
4610: fprintf (stderr, "Cannot read file %s :\n", filename);
4611: perror ("gzopen failed");
4612: return(NULL);
4613: }
4614: #else
1.72 daniel 4615: #ifdef WIN32
4616: input = _open (filename, O_RDONLY | _O_BINARY);
4617: #else
1.9 httpng 4618: input = open (filename, O_RDONLY);
1.72 daniel 4619: #endif
1.9 httpng 4620: if (input < 0) {
4621: fprintf (stderr, "Cannot read file %s :\n", filename);
4622: perror ("open failed");
4623: return(NULL);
4624: }
1.20 daniel 4625: #endif
4626: #ifdef HAVE_ZLIB_H
1.55 daniel 4627: res = gzread(input, buffer, len);
1.20 daniel 4628: #else
1.9 httpng 4629: res = read(input, buffer, buf.st_size);
1.20 daniel 4630: #endif
1.9 httpng 4631: if (res < 0) {
4632: fprintf (stderr, "Cannot read file %s :\n", filename);
1.20 daniel 4633: #ifdef HAVE_ZLIB_H
4634: perror ("gzread failed");
4635: #else
1.9 httpng 4636: perror ("read failed");
1.20 daniel 4637: #endif
1.9 httpng 4638: return(NULL);
4639: }
1.20 daniel 4640: #ifdef HAVE_ZLIB_H
4641: gzclose(input);
1.55 daniel 4642: if (res >= len) {
1.20 daniel 4643: free(buffer);
1.55 daniel 4644: len *= 2;
1.20 daniel 4645: goto retry_bigger;
4646: }
4647: buf.st_size = res;
4648: #else
1.9 httpng 4649: close(input);
1.20 daniel 4650: #endif
4651:
1.40 daniel 4652: buffer[buf.st_size] = '\0';
1.9 httpng 4653:
1.16 daniel 4654: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4655: if (ctxt == NULL) {
4656: perror("malloc");
4657: return(NULL);
4658: }
1.40 daniel 4659: xmlInitParserCtxt(ctxt);
4660: inputStream = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4661: if (inputStream == NULL) {
4662: perror("malloc");
4663: free(ctxt);
4664: return(NULL);
4665: }
4666:
4667: inputStream->filename = strdup(filename);
4668: inputStream->line = 1;
4669: inputStream->col = 1;
1.45 daniel 4670:
4671: /*
1.75 daniel 4672: * plug some encoding conversion routines here. !!!
1.45 daniel 4673: */
1.75 daniel 4674: enc = xmlDetectCharEncoding(buffer);
4675: xmlSwitchEncoding(ctxt, enc);
4676:
1.40 daniel 4677: inputStream->base = buffer;
4678: inputStream->cur = buffer;
1.69 daniel 4679: inputStream->free = (xmlParserInputDeallocate) free;
1.16 daniel 4680:
1.40 daniel 4681: inputPush(ctxt, inputStream);
1.69 daniel 4682: return(ctxt);
4683: }
4684:
4685: /**
4686: * xmlSAXParseFile :
4687: * @sax: the SAX handler block
4688: * @filename: the filename
4689: * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4690: * documents
4691: *
4692: * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4693: * compressed document is provided by default if found at compile-time.
4694: * It use the given SAX function block to handle the parsing callback.
4695: * If sax is NULL, fallback to the default DOM tree building routines.
4696: *
4697: * Returns the resulting document tree
4698: */
4699:
1.79 daniel 4700: xmlDocPtr
4701: xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
1.69 daniel 4702: int recovery) {
4703: xmlDocPtr ret;
4704: xmlParserCtxtPtr ctxt;
4705:
4706: ctxt = xmlCreateFileParserCtxt(filename);
4707: if (ctxt == NULL) return(NULL);
1.74 daniel 4708: if (sax != NULL) {
4709: ctxt->sax = sax;
4710: ctxt->userData = NULL;
4711: }
1.16 daniel 4712:
4713: xmlParseDocument(ctxt);
1.40 daniel 4714:
1.72 daniel 4715: if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59 daniel 4716: else {
4717: ret = NULL;
1.72 daniel 4718: xmlFreeDoc(ctxt->myDoc);
4719: ctxt->myDoc = NULL;
1.59 daniel 4720: }
1.69 daniel 4721: xmlFreeParserCtxt(ctxt);
1.20 daniel 4722:
4723: return(ret);
4724: }
4725:
1.55 daniel 4726: /**
4727: * xmlParseFile :
4728: * @filename: the filename
4729: *
4730: * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4731: * compressed document is provided by default if found at compile-time.
4732: *
1.68 daniel 4733: * Returns the resulting document tree
1.55 daniel 4734: */
4735:
1.79 daniel 4736: xmlDocPtr
4737: xmlParseFile(const char *filename) {
1.59 daniel 4738: return(xmlSAXParseFile(NULL, filename, 0));
4739: }
4740:
4741: /**
4742: * xmlRecoverFile :
4743: * @filename: the filename
4744: *
4745: * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4746: * compressed document is provided by default if found at compile-time.
4747: * In the case the document is not Well Formed, a tree is built anyway
4748: *
1.68 daniel 4749: * Returns the resulting document tree
1.59 daniel 4750: */
4751:
1.79 daniel 4752: xmlDocPtr
4753: xmlRecoverFile(const char *filename) {
1.59 daniel 4754: return(xmlSAXParseFile(NULL, filename, 1));
1.55 daniel 4755: }
1.32 daniel 4756:
1.50 daniel 4757: /**
1.82 daniel 4758: * xmlSubstituteEntitiesDefault :
4759: * @val: int 0 or 1
1.79 daniel 4760: *
4761: * Set and return the previous value for default entity support.
4762: * Initially the parser always keep entity references instead of substituting
4763: * entity values in the output. This function has to be used to change the
4764: * default parser behaviour
4765: * SAX::subtituteEntities() has to be used for changing that on a file by
4766: * file basis.
4767: *
4768: * Returns the last value for 0 for no substitution, 1 for substitution.
4769: */
4770:
4771: int
4772: xmlSubstituteEntitiesDefault(int val) {
4773: int old = xmlSubstituteEntitiesDefaultValue;
4774:
4775: xmlSubstituteEntitiesDefaultValue = val;
4776: return(old);
4777: }
4778:
4779: /**
1.69 daniel 4780: * xmlCreateMemoryParserCtxt :
1.68 daniel 4781: * @buffer: an pointer to a char array
1.50 daniel 4782: * @size: the siwe of the array
4783: *
1.69 daniel 4784: * Create a parser context for an XML in-memory document.
1.50 daniel 4785: *
1.69 daniel 4786: * Returns the new parser context or NULL
1.20 daniel 4787: */
1.69 daniel 4788: xmlParserCtxtPtr
4789: xmlCreateMemoryParserCtxt(char *buffer, int size) {
1.20 daniel 4790: xmlParserCtxtPtr ctxt;
1.40 daniel 4791: xmlParserInputPtr input;
1.75 daniel 4792: xmlCharEncoding enc;
1.40 daniel 4793:
4794: buffer[size - 1] = '\0';
4795:
1.20 daniel 4796: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4797: if (ctxt == NULL) {
4798: perror("malloc");
4799: return(NULL);
4800: }
1.40 daniel 4801: xmlInitParserCtxt(ctxt);
4802: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4803: if (input == NULL) {
4804: perror("malloc");
1.50 daniel 4805: free(ctxt->nodeTab);
4806: free(ctxt->inputTab);
1.40 daniel 4807: free(ctxt);
4808: return(NULL);
4809: }
1.20 daniel 4810:
1.40 daniel 4811: input->filename = NULL;
4812: input->line = 1;
4813: input->col = 1;
1.45 daniel 4814:
4815: /*
1.75 daniel 4816: * plug some encoding conversion routines here. !!!
1.45 daniel 4817: */
1.75 daniel 4818: enc = xmlDetectCharEncoding(buffer);
4819: xmlSwitchEncoding(ctxt, enc);
4820:
1.40 daniel 4821: input->base = buffer;
4822: input->cur = buffer;
1.69 daniel 4823: input->free = NULL;
1.20 daniel 4824:
1.40 daniel 4825: inputPush(ctxt, input);
1.69 daniel 4826: return(ctxt);
4827: }
4828:
4829: /**
4830: * xmlSAXParseMemory :
4831: * @sax: the SAX handler block
4832: * @buffer: an pointer to a char array
4833: * @size: the siwe of the array
4834: * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4835: * documents
4836: *
4837: * parse an XML in-memory block and use the given SAX function block
4838: * to handle the parsing callback. If sax is NULL, fallback to the default
4839: * DOM tree building routines.
4840: *
4841: * Returns the resulting document tree
4842: */
4843: xmlDocPtr
4844: xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
4845: xmlDocPtr ret;
4846: xmlParserCtxtPtr ctxt;
4847:
4848: ctxt = xmlCreateMemoryParserCtxt(buffer, size);
4849: if (ctxt == NULL) return(NULL);
1.74 daniel 4850: if (sax != NULL) {
4851: ctxt->sax = sax;
4852: ctxt->userData = NULL;
4853: }
1.20 daniel 4854:
4855: xmlParseDocument(ctxt);
1.40 daniel 4856:
1.72 daniel 4857: if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59 daniel 4858: else {
4859: ret = NULL;
1.72 daniel 4860: xmlFreeDoc(ctxt->myDoc);
4861: ctxt->myDoc = NULL;
1.59 daniel 4862: }
1.69 daniel 4863: xmlFreeParserCtxt(ctxt);
1.16 daniel 4864:
1.9 httpng 4865: return(ret);
1.17 daniel 4866: }
4867:
1.55 daniel 4868: /**
4869: * xmlParseMemory :
1.68 daniel 4870: * @buffer: an pointer to a char array
1.55 daniel 4871: * @size: the size of the array
4872: *
4873: * parse an XML in-memory block and build a tree.
4874: *
1.68 daniel 4875: * Returns the resulting document tree
1.55 daniel 4876: */
4877:
4878: xmlDocPtr xmlParseMemory(char *buffer, int size) {
1.59 daniel 4879: return(xmlSAXParseMemory(NULL, buffer, size, 0));
4880: }
4881:
4882: /**
4883: * xmlRecoverMemory :
1.68 daniel 4884: * @buffer: an pointer to a char array
1.59 daniel 4885: * @size: the size of the array
4886: *
4887: * parse an XML in-memory block and build a tree.
4888: * In the case the document is not Well Formed, a tree is built anyway
4889: *
1.68 daniel 4890: * Returns the resulting document tree
1.59 daniel 4891: */
4892:
4893: xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
4894: return(xmlSAXParseMemory(NULL, buffer, size, 1));
1.55 daniel 4895: }
1.17 daniel 4896:
1.50 daniel 4897: /**
4898: * xmlInitParserCtxt:
4899: * @ctxt: an XML parser context
4900: *
4901: * Initialize a parser context
4902: */
4903:
1.55 daniel 4904: void
4905: xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
1.17 daniel 4906: {
1.69 daniel 4907: /* Allocate the Input stack */
4908: ctxt->inputTab = (xmlParserInputPtr *) malloc(5 * sizeof(xmlParserInputPtr));
4909: ctxt->inputNr = 0;
4910: ctxt->inputMax = 5;
4911: ctxt->input = NULL;
1.72 daniel 4912: ctxt->version = NULL;
4913: ctxt->encoding = NULL;
4914: ctxt->standalone = -1;
1.69 daniel 4915:
4916: /* Allocate the Node stack */
4917: ctxt->nodeTab = (xmlNodePtr *) malloc(10 * sizeof(xmlNodePtr));
4918: ctxt->nodeNr = 0;
4919: ctxt->nodeMax = 10;
4920: ctxt->node = NULL;
4921:
4922: ctxt->sax = &xmlDefaultSAXHandler;
1.74 daniel 4923: ctxt->userData = ctxt;
1.72 daniel 4924: ctxt->myDoc = NULL;
1.69 daniel 4925: ctxt->wellFormed = 1;
1.79 daniel 4926: ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue;
1.69 daniel 4927: ctxt->record_info = 0;
4928: xmlInitNodeInfoSeq(&ctxt->node_seq);
4929: }
4930:
4931: /**
4932: * xmlFreeParserCtxt:
4933: * @ctxt: an XML parser context
4934: *
4935: * Free all the memory used by a parser context. However the parsed
1.72 daniel 4936: * document in ctxt->myDoc is not freed.
1.69 daniel 4937: */
4938:
4939: void
4940: xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
4941: {
4942: xmlParserInputPtr input;
4943:
4944: if (ctxt == NULL) return;
4945:
4946: while ((input = inputPop(ctxt)) != NULL) {
4947: xmlFreeInputStream(input);
4948: }
4949:
4950: if (ctxt->nodeTab != NULL) free(ctxt->nodeTab);
4951: if (ctxt->inputTab != NULL) free(ctxt->inputTab);
1.73 daniel 4952: if (ctxt->version != NULL) free((char *) ctxt->version);
1.69 daniel 4953: free(ctxt);
1.17 daniel 4954: }
4955:
1.50 daniel 4956: /**
4957: * xmlClearParserCtxt:
4958: * @ctxt: an XML parser context
4959: *
4960: * Clear (release owned resources) and reinitialize a parser context
4961: */
1.17 daniel 4962:
1.55 daniel 4963: void
4964: xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
1.17 daniel 4965: {
1.32 daniel 4966: xmlClearNodeInfoSeq(&ctxt->node_seq);
4967: xmlInitParserCtxt(ctxt);
1.17 daniel 4968: }
4969:
4970:
1.50 daniel 4971: /**
4972: * xmlSetupParserForBuffer:
4973: * @ctxt: an XML parser context
4974: * @buffer: a CHAR * buffer
4975: * @filename: a file name
4976: *
1.19 daniel 4977: * Setup the parser context to parse a new buffer; Clears any prior
4978: * contents from the parser context. The buffer parameter must not be
4979: * NULL, but the filename parameter can be
4980: */
1.55 daniel 4981: void
4982: xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const CHAR* buffer,
1.17 daniel 4983: const char* filename)
4984: {
1.40 daniel 4985: xmlParserInputPtr input;
4986:
4987: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4988: if (input == NULL) {
4989: perror("malloc");
4990: free(ctxt);
4991: exit(1);
4992: }
4993:
1.17 daniel 4994: xmlClearParserCtxt(ctxt);
1.40 daniel 4995: if (input->filename != NULL)
4996: input->filename = strdup(filename);
4997: else
4998: input->filename = NULL;
4999: input->line = 1;
5000: input->col = 1;
5001: input->base = buffer;
5002: input->cur = buffer;
5003:
5004: inputPush(ctxt, input);
1.17 daniel 5005: }
5006:
1.32 daniel 5007:
1.50 daniel 5008: /**
5009: * xmlParserFindNodeInfo:
5010: * @ctxt: an XML parser context
5011: * @node: an XML node within the tree
5012: *
5013: * Find the parser node info struct for a given node
5014: *
1.68 daniel 5015: * Returns an xmlParserNodeInfo block pointer or NULL
1.32 daniel 5016: */
5017: const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
5018: const xmlNode* node)
5019: {
5020: unsigned long pos;
5021:
5022: /* Find position where node should be at */
5023: pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
5024: if ( ctx->node_seq.buffer[pos].node == node )
5025: return &ctx->node_seq.buffer[pos];
5026: else
5027: return NULL;
5028: }
5029:
5030:
1.50 daniel 5031: /**
5032: * xmlInitNodeInfoSeq :
5033: * @seq: a node info sequence pointer
5034: *
5035: * -- Initialize (set to initial state) node info sequence
1.32 daniel 5036: */
1.55 daniel 5037: void
5038: xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
1.32 daniel 5039: {
5040: seq->length = 0;
5041: seq->maximum = 0;
5042: seq->buffer = NULL;
5043: }
5044:
1.50 daniel 5045: /**
5046: * xmlClearNodeInfoSeq :
5047: * @seq: a node info sequence pointer
5048: *
5049: * -- Clear (release memory and reinitialize) node
1.32 daniel 5050: * info sequence
5051: */
1.55 daniel 5052: void
5053: xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
1.32 daniel 5054: {
5055: if ( seq->buffer != NULL )
5056: free(seq->buffer);
5057: xmlInitNodeInfoSeq(seq);
5058: }
5059:
5060:
1.50 daniel 5061: /**
5062: * xmlParserFindNodeInfoIndex:
5063: * @seq: a node info sequence pointer
5064: * @node: an XML node pointer
5065: *
5066: *
1.32 daniel 5067: * xmlParserFindNodeInfoIndex : Find the index that the info record for
5068: * the given node is or should be at in a sorted sequence
1.68 daniel 5069: *
5070: * Returns a long indicating the position of the record
1.32 daniel 5071: */
5072: unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
5073: const xmlNode* node)
5074: {
5075: unsigned long upper, lower, middle;
5076: int found = 0;
5077:
5078: /* Do a binary search for the key */
5079: lower = 1;
5080: upper = seq->length;
5081: middle = 0;
5082: while ( lower <= upper && !found) {
5083: middle = lower + (upper - lower) / 2;
5084: if ( node == seq->buffer[middle - 1].node )
5085: found = 1;
5086: else if ( node < seq->buffer[middle - 1].node )
5087: upper = middle - 1;
5088: else
5089: lower = middle + 1;
5090: }
5091:
5092: /* Return position */
5093: if ( middle == 0 || seq->buffer[middle - 1].node < node )
5094: return middle;
5095: else
5096: return middle - 1;
5097: }
5098:
5099:
1.50 daniel 5100: /**
5101: * xmlParserAddNodeInfo:
5102: * @ctxt: an XML parser context
1.68 daniel 5103: * @info: a node info sequence pointer
1.50 daniel 5104: *
5105: * Insert node info record into the sorted sequence
1.32 daniel 5106: */
1.55 daniel 5107: void
5108: xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
1.68 daniel 5109: const xmlParserNodeInfo* info)
1.32 daniel 5110: {
5111: unsigned long pos;
5112: static unsigned int block_size = 5;
5113:
5114: /* Find pos and check to see if node is already in the sequence */
1.55 daniel 5115: pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
5116: if ( pos < ctxt->node_seq.length
5117: && ctxt->node_seq.buffer[pos].node == info->node ) {
5118: ctxt->node_seq.buffer[pos] = *info;
1.32 daniel 5119: }
5120:
5121: /* Otherwise, we need to add new node to buffer */
5122: else {
5123: /* Expand buffer by 5 if needed */
1.55 daniel 5124: if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
1.32 daniel 5125: xmlParserNodeInfo* tmp_buffer;
1.55 daniel 5126: unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
5127: *(ctxt->node_seq.maximum + block_size));
1.32 daniel 5128:
1.55 daniel 5129: if ( ctxt->node_seq.buffer == NULL )
1.32 daniel 5130: tmp_buffer = (xmlParserNodeInfo*)malloc(byte_size);
5131: else
1.55 daniel 5132: tmp_buffer = (xmlParserNodeInfo*)realloc(ctxt->node_seq.buffer, byte_size);
1.32 daniel 5133:
5134: if ( tmp_buffer == NULL ) {
1.55 daniel 5135: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74 daniel 5136: ctxt->sax->error(ctxt->userData, "Out of memory\n");
1.32 daniel 5137: return;
5138: }
1.55 daniel 5139: ctxt->node_seq.buffer = tmp_buffer;
5140: ctxt->node_seq.maximum += block_size;
1.32 daniel 5141: }
5142:
5143: /* If position is not at end, move elements out of the way */
1.55 daniel 5144: if ( pos != ctxt->node_seq.length ) {
1.32 daniel 5145: unsigned long i;
5146:
1.55 daniel 5147: for ( i = ctxt->node_seq.length; i > pos; i-- )
5148: ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
1.32 daniel 5149: }
5150:
5151: /* Copy element and increase length */
1.55 daniel 5152: ctxt->node_seq.buffer[pos] = *info;
5153: ctxt->node_seq.length++;
1.32 daniel 5154: }
5155: }
1.77 daniel 5156:
5157:
Webmaster