Annotation of XML/parser.c, revision 1.73
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))
184: ctxt->sax->error(ctxt,
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))
190: ctxt->sax->error(ctxt,
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))
197: ctxt->sax->error(ctxt, "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))
223: ctxt->sax->error(ctxt,
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))
230: ctxt->sax->error(ctxt, "malloc: couldn't allocate a new input stream\n");
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))
525: ctxt->sax->error(ctxt, "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))
545: ctxt->sax->characters(ctxt, 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.58 daniel 731: ctxt->sax->error(ctxt, "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.58 daniel 743: ctxt->sax->error(ctxt, "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))
836: ctxt->sax->error(ctxt, "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))
849: ctxt->sax->globalNamespace(ctxt, 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))
978: ctxt->sax->error(ctxt, "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))
1012: ctxt->sax->error(ctxt, "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))
1020: ctxt->sax->error(ctxt, "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))
1051: ctxt->sax->error(ctxt,
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))
1086: ctxt->sax->error(ctxt, "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))
1098: ctxt->sax->error(ctxt,
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))
1133: ctxt->sax->error(ctxt, "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))
1141: ctxt->sax->error(ctxt, "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))
1171: ctxt->sax->error(ctxt, "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))
1184: ctxt->sax->error(ctxt, "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))
1192: ctxt->sax->error(ctxt, "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))
1223: ctxt->sax->error(ctxt, "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))
1236: ctxt->sax->error(ctxt, "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))
1244: ctxt->sax->error(ctxt, "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))
1274: ctxt->sax->error(ctxt,
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)
1289: ctxt->sax->ignorableWhitespace(ctxt, q, CUR_PTR - q);
1290: } else {
1291: if (ctxt->sax->characters != NULL)
1292: ctxt->sax->characters(ctxt, q, CUR_PTR - q);
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))
1329: ctxt->sax->error(ctxt,
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))
1337: ctxt->sax->error(ctxt,
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))
1347: ctxt->sax->error(ctxt,
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))
1355: ctxt->sax->error(ctxt,
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))
1365: ctxt->sax->error(ctxt,
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))
1385: ctxt->sax->error(ctxt,
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))
1427: ctxt->sax->error(ctxt,
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))
1435: ctxt->sax->error(ctxt, "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))
1442: ctxt->sax->comment(ctxt, 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))
1469: ctxt->sax->error(ctxt, "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))
1512: ctxt->sax->error(ctxt,
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))
1526: ctxt->sax->processingInstruction(ctxt, target, data);
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))
1532: ctxt->sax->error(ctxt, "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))
1578: ctxt->sax->error(ctxt, "Space required after '<!NOTATION'\n");
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.67 daniel 1587: ctxt->sax->error(ctxt, "NOTATION: Name expected here\n");
1588: ctxt->wellFormed = 0;
1589: return;
1590: }
1591: if (!IS_BLANK(CUR)) {
1592: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1593: ctxt->sax->error(ctxt,
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))
1609: ctxt->sax->notationDecl(ctxt, name, Pubid, Systemid);
1.67 daniel 1610: } else {
1611: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1612: ctxt->sax->error(ctxt,
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))
1656: ctxt->sax->error(ctxt, "Space required after '<!ENTITY'\n");
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))
1665: ctxt->sax->error(ctxt, "Space required after '%'\n");
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))
1675: ctxt->sax->error(ctxt, "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))
1681: ctxt->sax->error(ctxt,
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))
1695: ctxt->sax->entityDecl(ctxt, 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))
1703: ctxt->sax->entityDecl(ctxt, 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))
1712: ctxt->sax->entityDecl(ctxt, 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))
1719: ctxt->sax->error(ctxt,
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))
1730: ctxt->sax->error(ctxt,
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))
1737: ctxt->sax->entityDecl(ctxt, 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))
1742: ctxt->sax->entityDecl(ctxt, 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))
1751: ctxt->sax->error(ctxt,
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))
1806: ctxt->sax->error(ctxt, "Space required after '#FIXED'\n");
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))
1814: ctxt->sax->error(ctxt,
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))
1842: ctxt->sax->error(ctxt, "'(' required to start 'NOTATION'\n");
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))
1852: ctxt->sax->error(ctxt,
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))
1869: ctxt->sax->error(ctxt,
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))
1896: ctxt->sax->error(ctxt,
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))
1907: ctxt->sax->error(ctxt,
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))
1924: ctxt->sax->error(ctxt,
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))
1957: ctxt->sax->error(ctxt, "Space required after 'NOTATION'\n");
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))
2059: ctxt->sax->error(ctxt, "Space required after '<!ATTLIST'\n");
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.59 daniel 2066: ctxt->sax->error(ctxt, "ATTLIST: no name for Element\n");
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))
2080: ctxt->sax->error(ctxt, "ATTLIST: no name for Attribute\n");
2081: ctxt->wellFormed = 0;
2082: break;
2083: }
2084: if (!IS_BLANK(CUR)) {
2085: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2086: ctxt->sax->error(ctxt,
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))
2098: ctxt->sax->error(ctxt,
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))
2111: ctxt->sax->error(ctxt,
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))
2120: ctxt->sax->error(ctxt,
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))
2125: ctxt->sax->attributeDecl(ctxt, 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))
2172: ctxt->sax->error(ctxt,
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))
2196: ctxt->sax->error(ctxt,
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))
2215: ctxt->sax->error(ctxt,
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))
2224: ctxt->sax->error(ctxt,
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))
2267: ctxt->sax->error(ctxt,
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))
2300: ctxt->sax->error(ctxt,
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))
2331: ctxt->sax->error(ctxt,
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))
2356: ctxt->sax->error(ctxt,
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))
2373: ctxt->sax->error(ctxt,
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))
2439: ctxt->sax->error(ctxt,
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))
2460: ctxt->sax->error(ctxt,
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))
2496: ctxt->sax->error(ctxt,
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.59 daniel 2504: ctxt->sax->error(ctxt,
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))
2511: ctxt->sax->error(ctxt,
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))
2535: ctxt->sax->error(ctxt,
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))
2544: ctxt->sax->error(ctxt,
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))
2550: ctxt->sax->elementDecl(ctxt, 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.58 daniel 2608: ctxt->sax->error(ctxt,
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.58 daniel 2625: ctxt->sax->error(ctxt,
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))
2637: ctxt->sax->error(ctxt, "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.58 daniel 2649: ctxt->sax->error(ctxt, "xmlParseCharRef: invalid CHAR value %d\n",
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))
2680: ctxt->sax->error(ctxt, "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)
2698: ent = ctxt->sax->getEntity(ctxt, name);
2699:
2700: if (((ctxt->sax->isStandalone != NULL) &&
2701: ctxt->sax->isStandalone(ctxt) == 1) ||
2702: (((ctxt->sax->hasInternalSubset == NULL) ||
2703: ctxt->sax->hasInternalSubset(ctxt) == 0) &&
2704: ((ctxt->sax->hasExternalSubset == NULL) ||
2705: ctxt->sax->hasExternalSubset(ctxt) == 0))) {
2706: if (ent == NULL) {
2707: if ((ctxt->sax != NULL) &&
2708: (ctxt->sax->error != NULL))
2709: ctxt->sax->error(ctxt,
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))
2726: ctxt->sax->error(ctxt,
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))
2733: ctxt->sax->error(ctxt,
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.52 daniel 2752: input = ctxt->sax->resolveEntity(ctxt, NULL, name);
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.59 daniel 2762: ctxt->sax->error(ctxt,
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))
2824: ctxt->sax->error(ctxt, "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))
2830: entity = ctxt->sax->getEntity(ctxt, name);
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))
2834: ctxt->sax->warning(ctxt,
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.59 daniel 2844: ctxt->sax->error(ctxt,
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))
2885: ctxt->sax->error(ctxt, "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))
2898: ctxt->sax->internalSubset(ctxt, 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))
2919: ctxt->sax->error(ctxt,
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))
2933: ctxt->sax->error(ctxt, "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))
2977: ctxt->sax->error(ctxt, "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.59 daniel 2992: ctxt->sax->error(ctxt,
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))
3036: ctxt->sax->error(ctxt,
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))
3061: ctxt->sax->error(ctxt, "Attribute %s redefined\n",
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))
3099: ctxt->sax->error(ctxt,
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))
3110: ctxt->sax->startElement(ctxt, 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))
3138: ctxt->sax->error(ctxt, "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))
3152: ctxt->sax->error(ctxt, "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))
3161: ctxt->sax->endElement(ctxt, name);
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))
3198: ctxt->sax->error(ctxt, "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))
3205: ctxt->sax->error(ctxt, "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))
3216: ctxt->sax->error(ctxt, "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)
3227: ctxt->sax->ignorableWhitespace(ctxt, base,
3228: (CUR_PTR - base) - 2);
3229: } else {
3230: if (ctxt->sax->characters != NULL)
3231: ctxt->sax->characters(ctxt, base, (CUR_PTR - base) - 2);
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))
3295: ctxt->sax->characters(ctxt, 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))
3301: ctxt->sax->reference(ctxt, 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.59 daniel 3322: ctxt->sax->error(ctxt,
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))
3358: ctxt->sax->endElement(ctxt, NULL);
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.57 daniel 3364: ctxt->sax->error(ctxt, "Couldn't find end of Start Tag\n%.30s\n",
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.57 daniel 3383: ctxt->sax->error(ctxt,
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))
3453: ctxt->sax->error(ctxt, "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))
3465: ctxt->sax->error(ctxt, "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))
3475: ctxt->sax->error(ctxt, "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.59 daniel 3481: ctxt->sax->error(ctxt,
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))
3515: ctxt->sax->error(ctxt, "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))
3548: ctxt->sax->error(ctxt, "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))
3560: ctxt->sax->error(ctxt, "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))
3570: ctxt->sax->error(ctxt, "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.59 daniel 3576: ctxt->sax->error(ctxt,
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.59 daniel 3609: ctxt->sax->error(ctxt,
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))
3627: ctxt->sax->error(ctxt, "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))
3632: ctxt->sax->error(ctxt, "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.59 daniel 3647: ctxt->sax->error(ctxt,
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))
3653: ctxt->sax->error(ctxt, "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))
3659: ctxt->sax->error(ctxt, "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))
3686: ctxt->sax->error(ctxt, "Blank needed after '<?xml'\n");
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))
3709: ctxt->sax->error(ctxt, "Blank needed here\n");
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))
3723: ctxt->sax->error(ctxt, "Blank needed here\n");
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))
3735: ctxt->sax->error(ctxt, "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))
3740: ctxt->sax->error(ctxt, "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.44 daniel 3794: ctxt->sax->setDocumentLocator(ctxt, &xmlDefaultSAXLocator);
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))
3806: ctxt->sax->error(ctxt,
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))
3814: ctxt->sax->error(ctxt, "Document is empty\n");
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))
3841: ctxt->sax->startDocument(ctxt);
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))
3873: ctxt->sax->error(ctxt,
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.44 daniel 3882: ctxt->sax->endDocument(ctxt);
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);
3948: if (sax != NULL) ctxt->sax = sax;
3949:
1.16 daniel 3950: xmlParseDocument(ctxt);
1.72 daniel 3951: if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59 daniel 3952: else {
3953: ret = NULL;
1.72 daniel 3954: xmlFreeDoc(ctxt->myDoc);
3955: ctxt->myDoc = NULL;
1.59 daniel 3956: }
1.69 daniel 3957: xmlFreeParserCtxt(ctxt);
1.16 daniel 3958:
1.1 veillard 3959: return(ret);
3960: }
3961:
1.50 daniel 3962: /**
1.55 daniel 3963: * xmlParseDoc :
3964: * @cur: a pointer to an array of CHAR
3965: *
3966: * parse an XML in-memory document and build a tree.
3967: *
1.68 daniel 3968: * Returns the resulting document tree
1.55 daniel 3969: */
3970:
1.69 daniel 3971: xmlDocPtr
3972: xmlParseDoc(CHAR *cur) {
1.59 daniel 3973: return(xmlSAXParseDoc(NULL, cur, 0));
3974: }
3975:
3976: /**
3977: * xmlRecoverDoc :
3978: * @cur: a pointer to an array of CHAR
3979: *
3980: * parse an XML in-memory document and build a tree.
3981: * In the case the document is not Well Formed, a tree is built anyway
3982: *
1.68 daniel 3983: * Returns the resulting document tree
1.59 daniel 3984: */
3985:
1.69 daniel 3986: xmlDocPtr
3987: xmlRecoverDoc(CHAR *cur) {
1.59 daniel 3988: return(xmlSAXParseDoc(NULL, cur, 1));
1.55 daniel 3989: }
3990:
3991: /**
1.69 daniel 3992: * xmlCreateFileParserCtxt :
1.50 daniel 3993: * @filename: the filename
3994: *
1.69 daniel 3995: * Create a parser context for a file content.
3996: * Automatic support for ZLIB/Compress compressed document is provided
3997: * by default if found at compile-time.
1.50 daniel 3998: *
1.69 daniel 3999: * Returns the new parser context or NULL
1.9 httpng 4000: */
1.69 daniel 4001: xmlParserCtxtPtr
4002: xmlCreateFileParserCtxt(const char *filename)
4003: {
4004: xmlParserCtxtPtr ctxt;
1.20 daniel 4005: #ifdef HAVE_ZLIB_H
4006: gzFile input;
4007: #else
1.9 httpng 4008: int input;
1.20 daniel 4009: #endif
1.9 httpng 4010: int res;
1.55 daniel 4011: int len;
1.9 httpng 4012: struct stat buf;
4013: char *buffer;
1.40 daniel 4014: xmlParserInputPtr inputStream;
1.9 httpng 4015:
1.11 veillard 4016: res = stat(filename, &buf);
1.9 httpng 4017: if (res < 0) return(NULL);
4018:
1.20 daniel 4019: #ifdef HAVE_ZLIB_H
1.55 daniel 4020: len = (buf.st_size * 8) + 1000;
1.20 daniel 4021: retry_bigger:
1.55 daniel 4022: buffer = malloc(len);
1.20 daniel 4023: #else
1.55 daniel 4024: len = buf.st_size + 100;
4025: buffer = malloc(len);
1.20 daniel 4026: #endif
1.9 httpng 4027: if (buffer == NULL) {
4028: perror("malloc");
4029: return(NULL);
4030: }
4031:
1.55 daniel 4032: memset(buffer, 0, len);
1.20 daniel 4033: #ifdef HAVE_ZLIB_H
4034: input = gzopen (filename, "r");
4035: if (input == NULL) {
4036: fprintf (stderr, "Cannot read file %s :\n", filename);
4037: perror ("gzopen failed");
4038: return(NULL);
4039: }
4040: #else
1.72 daniel 4041: #ifdef WIN32
4042: input = _open (filename, O_RDONLY | _O_BINARY);
4043: #else
1.9 httpng 4044: input = open (filename, O_RDONLY);
1.72 daniel 4045: #endif
1.9 httpng 4046: if (input < 0) {
4047: fprintf (stderr, "Cannot read file %s :\n", filename);
4048: perror ("open failed");
4049: return(NULL);
4050: }
1.20 daniel 4051: #endif
4052: #ifdef HAVE_ZLIB_H
1.55 daniel 4053: res = gzread(input, buffer, len);
1.20 daniel 4054: #else
1.9 httpng 4055: res = read(input, buffer, buf.st_size);
1.20 daniel 4056: #endif
1.9 httpng 4057: if (res < 0) {
4058: fprintf (stderr, "Cannot read file %s :\n", filename);
1.20 daniel 4059: #ifdef HAVE_ZLIB_H
4060: perror ("gzread failed");
4061: #else
1.9 httpng 4062: perror ("read failed");
1.20 daniel 4063: #endif
1.9 httpng 4064: return(NULL);
4065: }
1.20 daniel 4066: #ifdef HAVE_ZLIB_H
4067: gzclose(input);
1.55 daniel 4068: if (res >= len) {
1.20 daniel 4069: free(buffer);
1.55 daniel 4070: len *= 2;
1.20 daniel 4071: goto retry_bigger;
4072: }
4073: buf.st_size = res;
4074: #else
1.9 httpng 4075: close(input);
1.20 daniel 4076: #endif
4077:
1.40 daniel 4078: buffer[buf.st_size] = '\0';
1.9 httpng 4079:
1.16 daniel 4080: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4081: if (ctxt == NULL) {
4082: perror("malloc");
4083: return(NULL);
4084: }
1.40 daniel 4085: xmlInitParserCtxt(ctxt);
4086: inputStream = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4087: if (inputStream == NULL) {
4088: perror("malloc");
4089: free(ctxt);
4090: return(NULL);
4091: }
4092:
4093: inputStream->filename = strdup(filename);
4094: inputStream->line = 1;
4095: inputStream->col = 1;
1.45 daniel 4096:
4097: /*
4098: * TODO : plug some encoding conversion routines here. !!!
4099: */
1.40 daniel 4100: inputStream->base = buffer;
4101: inputStream->cur = buffer;
1.69 daniel 4102: inputStream->free = (xmlParserInputDeallocate) free;
1.16 daniel 4103:
1.40 daniel 4104: inputPush(ctxt, inputStream);
1.69 daniel 4105: return(ctxt);
4106: }
4107:
4108: /**
4109: * xmlSAXParseFile :
4110: * @sax: the SAX handler block
4111: * @filename: the filename
4112: * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4113: * documents
4114: *
4115: * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4116: * compressed document is provided by default if found at compile-time.
4117: * It use the given SAX function block to handle the parsing callback.
4118: * If sax is NULL, fallback to the default DOM tree building routines.
4119: *
4120: * Returns the resulting document tree
4121: */
4122:
4123: xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
4124: int recovery) {
4125: xmlDocPtr ret;
4126: xmlParserCtxtPtr ctxt;
4127:
4128: ctxt = xmlCreateFileParserCtxt(filename);
4129: if (ctxt == NULL) return(NULL);
4130: if (sax != NULL) ctxt->sax = sax;
1.16 daniel 4131:
4132: xmlParseDocument(ctxt);
1.40 daniel 4133:
1.72 daniel 4134: if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59 daniel 4135: else {
4136: ret = NULL;
1.72 daniel 4137: xmlFreeDoc(ctxt->myDoc);
4138: ctxt->myDoc = NULL;
1.59 daniel 4139: }
1.69 daniel 4140: xmlFreeParserCtxt(ctxt);
1.20 daniel 4141:
4142: return(ret);
4143: }
4144:
1.55 daniel 4145: /**
4146: * xmlParseFile :
4147: * @filename: the filename
4148: *
4149: * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4150: * compressed document is provided by default if found at compile-time.
4151: *
1.68 daniel 4152: * Returns the resulting document tree
1.55 daniel 4153: */
4154:
4155: xmlDocPtr xmlParseFile(const char *filename) {
1.59 daniel 4156: return(xmlSAXParseFile(NULL, filename, 0));
4157: }
4158:
4159: /**
4160: * xmlRecoverFile :
4161: * @filename: the filename
4162: *
4163: * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4164: * compressed document is provided by default if found at compile-time.
4165: * In the case the document is not Well Formed, a tree is built anyway
4166: *
1.68 daniel 4167: * Returns the resulting document tree
1.59 daniel 4168: */
4169:
4170: xmlDocPtr xmlRecoverFile(const char *filename) {
4171: return(xmlSAXParseFile(NULL, filename, 1));
1.55 daniel 4172: }
1.32 daniel 4173:
1.50 daniel 4174: /**
1.69 daniel 4175: * xmlCreateMemoryParserCtxt :
1.68 daniel 4176: * @buffer: an pointer to a char array
1.50 daniel 4177: * @size: the siwe of the array
4178: *
1.69 daniel 4179: * Create a parser context for an XML in-memory document.
1.50 daniel 4180: *
1.69 daniel 4181: * Returns the new parser context or NULL
1.20 daniel 4182: */
1.69 daniel 4183: xmlParserCtxtPtr
4184: xmlCreateMemoryParserCtxt(char *buffer, int size) {
1.20 daniel 4185: xmlParserCtxtPtr ctxt;
1.40 daniel 4186: xmlParserInputPtr input;
4187:
4188: buffer[size - 1] = '\0';
4189:
1.20 daniel 4190: ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4191: if (ctxt == NULL) {
4192: perror("malloc");
4193: return(NULL);
4194: }
1.40 daniel 4195: xmlInitParserCtxt(ctxt);
4196: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4197: if (input == NULL) {
4198: perror("malloc");
1.50 daniel 4199: free(ctxt->nodeTab);
4200: free(ctxt->inputTab);
1.40 daniel 4201: free(ctxt);
4202: return(NULL);
4203: }
1.20 daniel 4204:
1.40 daniel 4205: input->filename = NULL;
4206: input->line = 1;
4207: input->col = 1;
1.45 daniel 4208:
4209: /*
4210: * TODO : plug some encoding conversion routines here. !!!
4211: */
1.40 daniel 4212: input->base = buffer;
4213: input->cur = buffer;
1.69 daniel 4214: input->free = NULL;
1.20 daniel 4215:
1.40 daniel 4216: inputPush(ctxt, input);
1.69 daniel 4217: return(ctxt);
4218: }
4219:
4220: /**
4221: * xmlSAXParseMemory :
4222: * @sax: the SAX handler block
4223: * @buffer: an pointer to a char array
4224: * @size: the siwe of the array
4225: * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4226: * documents
4227: *
4228: * parse an XML in-memory block and use the given SAX function block
4229: * to handle the parsing callback. If sax is NULL, fallback to the default
4230: * DOM tree building routines.
4231: *
4232: * TODO : plug some encoding conversion routines here. !!!
4233: *
4234: * Returns the resulting document tree
4235: */
4236: xmlDocPtr
4237: xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
4238: xmlDocPtr ret;
4239: xmlParserCtxtPtr ctxt;
4240:
4241: ctxt = xmlCreateMemoryParserCtxt(buffer, size);
4242: if (ctxt == NULL) return(NULL);
4243: if (sax != NULL) ctxt->sax = sax;
1.20 daniel 4244:
4245: xmlParseDocument(ctxt);
1.40 daniel 4246:
1.72 daniel 4247: if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59 daniel 4248: else {
4249: ret = NULL;
1.72 daniel 4250: xmlFreeDoc(ctxt->myDoc);
4251: ctxt->myDoc = NULL;
1.59 daniel 4252: }
1.69 daniel 4253: xmlFreeParserCtxt(ctxt);
1.16 daniel 4254:
1.9 httpng 4255: return(ret);
1.17 daniel 4256: }
4257:
1.55 daniel 4258: /**
4259: * xmlParseMemory :
1.68 daniel 4260: * @buffer: an pointer to a char array
1.55 daniel 4261: * @size: the size of the array
4262: *
4263: * parse an XML in-memory block and build a tree.
4264: *
1.68 daniel 4265: * Returns the resulting document tree
1.55 daniel 4266: */
4267:
4268: xmlDocPtr xmlParseMemory(char *buffer, int size) {
1.59 daniel 4269: return(xmlSAXParseMemory(NULL, buffer, size, 0));
4270: }
4271:
4272: /**
4273: * xmlRecoverMemory :
1.68 daniel 4274: * @buffer: an pointer to a char array
1.59 daniel 4275: * @size: the size of the array
4276: *
4277: * parse an XML in-memory block and build a tree.
4278: * In the case the document is not Well Formed, a tree is built anyway
4279: *
1.68 daniel 4280: * Returns the resulting document tree
1.59 daniel 4281: */
4282:
4283: xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
4284: return(xmlSAXParseMemory(NULL, buffer, size, 1));
1.55 daniel 4285: }
1.17 daniel 4286:
1.50 daniel 4287: /**
4288: * xmlInitParserCtxt:
4289: * @ctxt: an XML parser context
4290: *
4291: * Initialize a parser context
4292: */
4293:
1.55 daniel 4294: void
4295: xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
1.17 daniel 4296: {
1.69 daniel 4297: /* Allocate the Input stack */
4298: ctxt->inputTab = (xmlParserInputPtr *) malloc(5 * sizeof(xmlParserInputPtr));
4299: ctxt->inputNr = 0;
4300: ctxt->inputMax = 5;
4301: ctxt->input = NULL;
1.72 daniel 4302: ctxt->version = NULL;
4303: ctxt->encoding = NULL;
4304: ctxt->standalone = -1;
1.69 daniel 4305:
4306: /* Allocate the Node stack */
4307: ctxt->nodeTab = (xmlNodePtr *) malloc(10 * sizeof(xmlNodePtr));
4308: ctxt->nodeNr = 0;
4309: ctxt->nodeMax = 10;
4310: ctxt->node = NULL;
4311:
4312: ctxt->sax = &xmlDefaultSAXHandler;
1.72 daniel 4313: ctxt->myDoc = NULL;
1.69 daniel 4314: ctxt->wellFormed = 1;
4315: ctxt->record_info = 0;
4316: xmlInitNodeInfoSeq(&ctxt->node_seq);
4317: }
4318:
4319: /**
4320: * xmlFreeParserCtxt:
4321: * @ctxt: an XML parser context
4322: *
4323: * Free all the memory used by a parser context. However the parsed
1.72 daniel 4324: * document in ctxt->myDoc is not freed.
1.69 daniel 4325: */
4326:
4327: void
4328: xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
4329: {
4330: xmlParserInputPtr input;
4331:
4332: if (ctxt == NULL) return;
4333:
4334: while ((input = inputPop(ctxt)) != NULL) {
4335: xmlFreeInputStream(input);
4336: }
4337:
4338: if (ctxt->nodeTab != NULL) free(ctxt->nodeTab);
4339: if (ctxt->inputTab != NULL) free(ctxt->inputTab);
1.73 ! daniel 4340: if (ctxt->version != NULL) free((char *) ctxt->version);
1.69 daniel 4341: free(ctxt);
1.17 daniel 4342: }
4343:
1.50 daniel 4344: /**
4345: * xmlClearParserCtxt:
4346: * @ctxt: an XML parser context
4347: *
4348: * Clear (release owned resources) and reinitialize a parser context
4349: */
1.17 daniel 4350:
1.55 daniel 4351: void
4352: xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
1.17 daniel 4353: {
1.32 daniel 4354: xmlClearNodeInfoSeq(&ctxt->node_seq);
4355: xmlInitParserCtxt(ctxt);
1.17 daniel 4356: }
4357:
4358:
1.50 daniel 4359: /**
4360: * xmlSetupParserForBuffer:
4361: * @ctxt: an XML parser context
4362: * @buffer: a CHAR * buffer
4363: * @filename: a file name
4364: *
1.19 daniel 4365: * Setup the parser context to parse a new buffer; Clears any prior
4366: * contents from the parser context. The buffer parameter must not be
4367: * NULL, but the filename parameter can be
4368: */
1.55 daniel 4369: void
4370: xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const CHAR* buffer,
1.17 daniel 4371: const char* filename)
4372: {
1.40 daniel 4373: xmlParserInputPtr input;
4374:
4375: input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4376: if (input == NULL) {
4377: perror("malloc");
4378: free(ctxt);
4379: exit(1);
4380: }
4381:
1.17 daniel 4382: xmlClearParserCtxt(ctxt);
1.40 daniel 4383: if (input->filename != NULL)
4384: input->filename = strdup(filename);
4385: else
4386: input->filename = NULL;
4387: input->line = 1;
4388: input->col = 1;
4389: input->base = buffer;
4390: input->cur = buffer;
4391:
4392: inputPush(ctxt, input);
1.17 daniel 4393: }
4394:
1.32 daniel 4395:
1.50 daniel 4396: /**
4397: * xmlParserFindNodeInfo:
4398: * @ctxt: an XML parser context
4399: * @node: an XML node within the tree
4400: *
4401: * Find the parser node info struct for a given node
4402: *
1.68 daniel 4403: * Returns an xmlParserNodeInfo block pointer or NULL
1.32 daniel 4404: */
4405: const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
4406: const xmlNode* node)
4407: {
4408: unsigned long pos;
4409:
4410: /* Find position where node should be at */
4411: pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
4412: if ( ctx->node_seq.buffer[pos].node == node )
4413: return &ctx->node_seq.buffer[pos];
4414: else
4415: return NULL;
4416: }
4417:
4418:
1.50 daniel 4419: /**
4420: * xmlInitNodeInfoSeq :
4421: * @seq: a node info sequence pointer
4422: *
4423: * -- Initialize (set to initial state) node info sequence
1.32 daniel 4424: */
1.55 daniel 4425: void
4426: xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
1.32 daniel 4427: {
4428: seq->length = 0;
4429: seq->maximum = 0;
4430: seq->buffer = NULL;
4431: }
4432:
1.50 daniel 4433: /**
4434: * xmlClearNodeInfoSeq :
4435: * @seq: a node info sequence pointer
4436: *
4437: * -- Clear (release memory and reinitialize) node
1.32 daniel 4438: * info sequence
4439: */
1.55 daniel 4440: void
4441: xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
1.32 daniel 4442: {
4443: if ( seq->buffer != NULL )
4444: free(seq->buffer);
4445: xmlInitNodeInfoSeq(seq);
4446: }
4447:
4448:
1.50 daniel 4449: /**
4450: * xmlParserFindNodeInfoIndex:
4451: * @seq: a node info sequence pointer
4452: * @node: an XML node pointer
4453: *
4454: *
1.32 daniel 4455: * xmlParserFindNodeInfoIndex : Find the index that the info record for
4456: * the given node is or should be at in a sorted sequence
1.68 daniel 4457: *
4458: * Returns a long indicating the position of the record
1.32 daniel 4459: */
4460: unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
4461: const xmlNode* node)
4462: {
4463: unsigned long upper, lower, middle;
4464: int found = 0;
4465:
4466: /* Do a binary search for the key */
4467: lower = 1;
4468: upper = seq->length;
4469: middle = 0;
4470: while ( lower <= upper && !found) {
4471: middle = lower + (upper - lower) / 2;
4472: if ( node == seq->buffer[middle - 1].node )
4473: found = 1;
4474: else if ( node < seq->buffer[middle - 1].node )
4475: upper = middle - 1;
4476: else
4477: lower = middle + 1;
4478: }
4479:
4480: /* Return position */
4481: if ( middle == 0 || seq->buffer[middle - 1].node < node )
4482: return middle;
4483: else
4484: return middle - 1;
4485: }
4486:
4487:
1.50 daniel 4488: /**
4489: * xmlParserAddNodeInfo:
4490: * @ctxt: an XML parser context
1.68 daniel 4491: * @info: a node info sequence pointer
1.50 daniel 4492: *
4493: * Insert node info record into the sorted sequence
1.32 daniel 4494: */
1.55 daniel 4495: void
4496: xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
1.68 daniel 4497: const xmlParserNodeInfo* info)
1.32 daniel 4498: {
4499: unsigned long pos;
4500: static unsigned int block_size = 5;
4501:
4502: /* Find pos and check to see if node is already in the sequence */
1.55 daniel 4503: pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
4504: if ( pos < ctxt->node_seq.length
4505: && ctxt->node_seq.buffer[pos].node == info->node ) {
4506: ctxt->node_seq.buffer[pos] = *info;
1.32 daniel 4507: }
4508:
4509: /* Otherwise, we need to add new node to buffer */
4510: else {
4511: /* Expand buffer by 5 if needed */
1.55 daniel 4512: if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
1.32 daniel 4513: xmlParserNodeInfo* tmp_buffer;
1.55 daniel 4514: unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
4515: *(ctxt->node_seq.maximum + block_size));
1.32 daniel 4516:
1.55 daniel 4517: if ( ctxt->node_seq.buffer == NULL )
1.32 daniel 4518: tmp_buffer = (xmlParserNodeInfo*)malloc(byte_size);
4519: else
1.55 daniel 4520: tmp_buffer = (xmlParserNodeInfo*)realloc(ctxt->node_seq.buffer, byte_size);
1.32 daniel 4521:
4522: if ( tmp_buffer == NULL ) {
1.55 daniel 4523: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.58 daniel 4524: ctxt->sax->error(ctxt, "Out of memory\n");
1.32 daniel 4525: return;
4526: }
1.55 daniel 4527: ctxt->node_seq.buffer = tmp_buffer;
4528: ctxt->node_seq.maximum += block_size;
1.32 daniel 4529: }
4530:
4531: /* If position is not at end, move elements out of the way */
1.55 daniel 4532: if ( pos != ctxt->node_seq.length ) {
1.32 daniel 4533: unsigned long i;
4534:
1.55 daniel 4535: for ( i = ctxt->node_seq.length; i > pos; i-- )
4536: ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
1.32 daniel 4537: }
4538:
4539: /* Copy element and increase length */
1.55 daniel 4540: ctxt->node_seq.buffer[pos] = *info;
4541: ctxt->node_seq.length++;
1.32 daniel 4542: }
4543: }
Webmaster