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