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