blob: 2ce04c4bd401a31320fac5f75320bb497de1944c [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * parser.c : an XML 1.0 non-verifying parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006 * Daniel.Veillard@w3.org
Daniel Veillard260a68f1998-08-13 03:39:55 +00007 */
8
9#ifdef WIN32
10#define HAVE_FCNTL_H
11#include <io.h>
12#else
13#include <config.h>
14#endif
15#include <stdio.h>
16#include <ctype.h>
17#include <string.h> /* for memset() only */
Seth Alvese7f12e61998-10-01 20:51:15 +000018#include <stdlib.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000019#include <sys/stat.h>
20#ifdef HAVE_FCNTL_H
21#include <fcntl.h>
22#endif
23#ifdef HAVE_UNISTD_H
24#include <unistd.h>
25#endif
26#ifdef HAVE_ZLIB_H
27#include <zlib.h>
28#endif
29
30#include "tree.h"
31#include "parser.h"
32#include "entities.h"
Daniel Veillard27d88741999-05-29 11:51:49 +000033#include "encoding.h"
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000034#include "valid.h"
Daniel Veillard1e346af1999-02-22 10:33:01 +000035#include "parserInternals.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000036
Daniel Veillard14fff061999-06-22 21:49:07 +000037const char *xmlParserVersion = LIBXML_VERSION;
38
Daniel Veillard260a68f1998-08-13 03:39:55 +000039/************************************************************************
40 * *
41 * Parser stacks related functions and macros *
42 * *
43 ************************************************************************/
Daniel Veillard011b63c1999-06-02 17:44:04 +000044
45int xmlSubstituteEntitiesDefaultValue = 0;
46
Daniel Veillard260a68f1998-08-13 03:39:55 +000047/*
48 * Generic function for accessing stacks in the Parser Context
49 */
50
51#define PUSH_AND_POP(type, name) \
Daniel Veillard517752b1999-04-05 12:20:10 +000052extern int name##Push(xmlParserCtxtPtr ctxt, type value) { \
Daniel Veillard260a68f1998-08-13 03:39:55 +000053 if (ctxt->name##Nr >= ctxt->name##Max) { \
54 ctxt->name##Max *= 2; \
55 ctxt->name##Tab = (void *) realloc(ctxt->name##Tab, \
56 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
57 if (ctxt->name##Tab == NULL) { \
58 fprintf(stderr, "realloc failed !\n"); \
59 exit(1); \
60 } \
61 } \
62 ctxt->name##Tab[ctxt->name##Nr] = value; \
63 ctxt->name = value; \
64 return(ctxt->name##Nr++); \
65} \
Daniel Veillard517752b1999-04-05 12:20:10 +000066extern type name##Pop(xmlParserCtxtPtr ctxt) { \
Daniel Veillardd692aa41999-02-28 21:54:31 +000067 type ret; \
Daniel Veillard260a68f1998-08-13 03:39:55 +000068 if (ctxt->name##Nr <= 0) return(0); \
69 ctxt->name##Nr--; \
Daniel Veillardccb09631998-10-27 06:21:04 +000070 if (ctxt->name##Nr > 0) \
71 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
72 else \
73 ctxt->name = NULL; \
Daniel Veillardd692aa41999-02-28 21:54:31 +000074 ret = ctxt->name##Tab[ctxt->name##Nr]; \
75 ctxt->name##Tab[ctxt->name##Nr] = 0; \
76 return(ret); \
Daniel Veillard260a68f1998-08-13 03:39:55 +000077} \
78
79PUSH_AND_POP(xmlParserInputPtr, input)
80PUSH_AND_POP(xmlNodePtr, node)
81
Daniel Veillard0ba4d531998-11-01 19:34:31 +000082/*
83 * Macros for accessing the content. Those should be used only by the parser,
84 * and not exported.
85 *
86 * Dirty macros, i.e. one need to make assumption on the context to use them
87 *
88 * CUR_PTR return the current pointer to the CHAR to be parsed.
89 * CUR returns the current CHAR value, i.e. a 8 bit value if compiled
90 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
91 * in UNICODE mode. This should be used internally by the parser
92 * only to compare to ASCII values otherwise it would break when
93 * running with UTF-8 encoding.
94 * NXT(n) returns the n'th next CHAR. Same as CUR is should be used only
95 * to compare on ASCII based substring.
96 * SKIP(n) Skip n CHAR, and must also be used only to skip ASCII defined
97 * strings within the parser.
98 *
Daniel Veillard011b63c1999-06-02 17:44:04 +000099 * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000100 *
101 * CURRENT Returns the current char value, with the full decoding of
102 * UTF-8 if we are using this mode. It returns an int.
103 * NEXT Skip to the next character, this does the proper decoding
104 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
105 * It returns the pointer to the current CHAR.
Daniel Veillard011b63c1999-06-02 17:44:04 +0000106 * COPY(to) copy one char to *to, increment CUR_PTR and to accordingly
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000107 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000108
109#define CUR (*ctxt->input->cur)
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000110#define SKIP(val) ctxt->input->cur += (val)
111#define NXT(val) ctxt->input->cur[(val)]
112#define CUR_PTR ctxt->input->cur
113
114#define SKIP_BLANKS \
115 while (IS_BLANK(*(ctxt->input->cur))) NEXT
116
117#ifndef USE_UTF_8
118#define CURRENT (*ctxt->input->cur)
Daniel Veillard260a68f1998-08-13 03:39:55 +0000119#define NEXT ((*ctxt->input->cur) ? \
120 (((*(ctxt->input->cur) == '\n') ? \
121 (ctxt->input->line++, ctxt->input->col = 1) : \
122 (ctxt->input->col++)), ctxt->input->cur++) : \
123 (xmlPopInput(ctxt), ctxt->input->cur))
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000124#else
125#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000126
127
Daniel Veillard11e00581998-10-24 18:27:49 +0000128/**
129 * xmlPopInput:
130 * @ctxt: an XML parser context
131 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000132 * xmlPopInput: the current input pointed by ctxt->input came to an end
133 * pop it and return the next char.
134 *
135 * TODO A deallocation of the popped Input structure is needed
Daniel Veillard1e346af1999-02-22 10:33:01 +0000136 *
137 * Returns the current CHAR in the parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +0000138 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000139CHAR
140xmlPopInput(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000141 if (ctxt->inputNr == 1) return(0); /* End of main Input */
Daniel Veillardbc50b591999-03-01 12:28:53 +0000142 xmlFreeInputStream(inputPop(ctxt));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000143 return(CUR);
144}
145
Daniel Veillard11e00581998-10-24 18:27:49 +0000146/**
147 * xmlPushInput:
148 * @ctxt: an XML parser context
149 * @input: an XML parser input fragment (entity, XML fragment ...).
150 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000151 * xmlPushInput: switch to a new input stream which is stacked on top
152 * of the previous one(s).
153 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000154void
155xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000156 if (input == NULL) return;
157 inputPush(ctxt, input);
158}
159
Daniel Veillard11e00581998-10-24 18:27:49 +0000160/**
Daniel Veillardd692aa41999-02-28 21:54:31 +0000161 * xmlFreeInputStream:
162 * @input: an xmlParserInputPtr
163 *
164 * Free up an input stream.
165 */
166void
167xmlFreeInputStream(xmlParserInputPtr input) {
168 if (input == NULL) return;
169
Daniel Veillardbc50b591999-03-01 12:28:53 +0000170 if (input->filename != NULL) free((char *) input->filename);
Daniel Veillardd692aa41999-02-28 21:54:31 +0000171 if ((input->free != NULL) && (input->base != NULL))
172 input->free((char *) input->base);
173 memset(input, -1, sizeof(xmlParserInput));
174 free(input);
175}
176
177/**
Daniel Veillard11e00581998-10-24 18:27:49 +0000178 * xmlNewEntityInputStream:
179 * @ctxt: an XML parser context
180 * @entity: an Entity pointer
181 *
Daniel Veillard011b63c1999-06-02 17:44:04 +0000182 * Create a new input stream based on an xmlEntityPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +0000183 * Returns the new input stream
Daniel Veillard260a68f1998-08-13 03:39:55 +0000184 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000185xmlParserInputPtr
186xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000187 xmlParserInputPtr input;
188
189 if (entity == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000190 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000191 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000192 "internal: xmlNewEntityInputStream entity = NULL\n");
Daniel Veillardccb09631998-10-27 06:21:04 +0000193 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000194 }
195 if (entity->content == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000196 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000197 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000198 "internal: xmlNewEntityInputStream entity->input = NULL\n");
Daniel Veillardccb09631998-10-27 06:21:04 +0000199 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000200 }
201 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
202 if (input == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000203 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000204 ctxt->sax->error(ctxt->userData, "malloc: couldn't allocate a new input stream\n");
Daniel Veillardccb09631998-10-27 06:21:04 +0000205 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000206 }
207 input->filename = entity->SystemID; /* TODO !!! char <- CHAR */
208 input->base = entity->content;
209 input->cur = entity->content;
210 input->line = 1;
211 input->col = 1;
Daniel Veillardd692aa41999-02-28 21:54:31 +0000212 input->free = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000213 return(input);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000214}
215
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000216/**
217 * xmlNewStringInputStream:
218 * @ctxt: an XML parser context
Daniel Veillard011b63c1999-06-02 17:44:04 +0000219 * @entity: an Entity memory buffer
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000220 *
221 * Create a new input stream based on a memory buffer.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000222 * Returns the new input stream
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000223 */
224xmlParserInputPtr
Daniel Veillard011b63c1999-06-02 17:44:04 +0000225xmlNewStringInputStream(xmlParserCtxtPtr ctxt, CHAR *entity) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000226 xmlParserInputPtr input;
227
Daniel Veillard011b63c1999-06-02 17:44:04 +0000228 if (entity == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000229 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000230 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000231 "internal: xmlNewStringInputStream string = NULL\n");
232 return(NULL);
233 }
234 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
235 if (input == NULL) {
236 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000237 ctxt->sax->error(ctxt->userData, "malloc: couldn't allocate a new input stream\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000238 return(NULL);
239 }
240 input->filename = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000241 input->base = entity;
242 input->cur = entity;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000243 input->line = 1;
244 input->col = 1;
Daniel Veillardd692aa41999-02-28 21:54:31 +0000245 input->free = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000246 return(input);
247}
248
Daniel Veillard011b63c1999-06-02 17:44:04 +0000249/**
250 * xmlNewInputFromFile:
251 * @ctxt: an XML parser context
252 * @filename: the filename to use as entity
253 *
254 * Create a new input stream based on a file.
255 *
256 * Returns the new input stream or NULL in case of error
257 */
258xmlParserInputPtr
259xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) {
260#ifdef HAVE_ZLIB_H
261 gzFile input;
262#else
263 int input;
264#endif
265 int res;
266 int len;
267 struct stat buf;
268 char *buffer;
269 xmlParserInputPtr inputStream;
270 /* xmlCharEncoding enc; */
271
272 res = stat(filename, &buf);
273 if (res < 0) return(NULL);
274
275#ifdef HAVE_ZLIB_H
276 len = (buf.st_size * 8) + 1000;
277retry_bigger:
278 buffer = malloc(len);
279#else
280 len = buf.st_size + 100;
281 buffer = malloc(len);
282#endif
283 if (buffer == NULL) {
284 perror("malloc");
285 return(NULL);
286 }
287
288 memset(buffer, 0, len);
289#ifdef HAVE_ZLIB_H
290 input = gzopen (filename, "r");
291 if (input == NULL) {
292 fprintf (stderr, "Cannot read file %s :\n", filename);
293 perror ("gzopen failed");
294 return(NULL);
295 }
296#else
297#ifdef WIN32
298 input = _open (filename, O_RDONLY | _O_BINARY);
299#else
300 input = open (filename, O_RDONLY);
301#endif
302 if (input < 0) {
303 fprintf (stderr, "Cannot read file %s :\n", filename);
304 perror ("open failed");
305 return(NULL);
306 }
307#endif
308#ifdef HAVE_ZLIB_H
309 res = gzread(input, buffer, len);
310#else
311 res = read(input, buffer, buf.st_size);
312#endif
313 if (res < 0) {
314 fprintf (stderr, "Cannot read file %s :\n", filename);
315#ifdef HAVE_ZLIB_H
316 perror ("gzread failed");
317#else
318 perror ("read failed");
319#endif
320 return(NULL);
321 }
322#ifdef HAVE_ZLIB_H
323 gzclose(input);
324 if (res >= len) {
325 free(buffer);
326 len *= 2;
327 goto retry_bigger;
328 }
329 buf.st_size = res;
330#else
331 close(input);
332#endif
333
334 buffer[buf.st_size] = '\0';
335
336 inputStream = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
337 if (inputStream == NULL) {
338 perror("malloc");
339 free(ctxt);
340 return(NULL);
341 }
342
343 inputStream->filename = strdup(filename);
344 inputStream->line = 1;
345 inputStream->col = 1;
346
347 /*
348 * plug some encoding conversion routines here. !!!
349 enc = xmlDetectCharEncoding(buffer);
350 xmlSwitchEncoding(ctxt, enc);
351 */
352
353 inputStream->base = buffer;
354 inputStream->cur = buffer;
355 inputStream->free = (xmlParserInputDeallocate) free;
356
357 return(inputStream);
358}
359
360/************************************************************************
361 * *
362 * Commodity functions to handle entities *
363 * *
364 ************************************************************************/
365
366/*
367 * Macro used to grow the current buffer.
368 */
369#define growBuffer(buffer) { \
370 buffer##_size *= 2; \
371 buffer = (CHAR *) realloc(buffer, buffer##_size * sizeof(CHAR)); \
372 if (buffer == NULL) { \
373 perror("realloc failed"); \
374 exit(1); \
375 } \
376}
377
378
379/**
380 * xmlDecodeEntities:
381 * @ctxt: the parser context
382 * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF
383 * @len: the len to decode (in bytes !), -1 for no size limit
384 * @end: an end marker CHAR, 0 if none
385 * @end2: an end marker CHAR, 0 if none
386 * @end3: an end marker CHAR, 0 if none
387 *
388 * [67] Reference ::= EntityRef | CharRef
389 *
390 * [69] PEReference ::= '%' Name ';'
391 *
392 * Returns A newly allocated string with the substitution done. The caller
393 * must deallocate it !
394 */
395CHAR *
396xmlDecodeEntities(xmlParserCtxtPtr ctxt, int len, int what,
397 CHAR end, CHAR end2, CHAR end3) {
398 CHAR *buffer = NULL;
399 int buffer_size = 0;
400 CHAR *out = NULL;
401
402 CHAR *cur = NULL;
403 xmlEntityPtr ent;
404 const CHAR *start = CUR_PTR;
405 unsigned int max = (unsigned int) len;
406
407 /*
408 * allocate a translation buffer.
409 */
410 buffer_size = 1000;
411 buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
412 if (buffer == NULL) {
413 perror("xmlDecodeEntities: malloc failed");
414 return(NULL);
415 }
416 out = buffer;
417
418 /*
419 * Ok loop until we reach one of the ending char or a size limit.
420 */
421 while ((CUR_PTR - start < max) && (CUR != end) &&
422 (CUR != end2) && (CUR != end3)) {
423
424 if (CUR == '&' && (what & XML_SUBSTITUTE_REF)) {
425 if (NXT(1) == '#') {
426 int val = xmlParseCharRef(ctxt);
427 /* TODO: invalid for UTF-8 variable encoding !!! */
428 *out++ = val;
429 } else {
430 ent = xmlParseEntityRef(ctxt);
431 if (ent != NULL) {
432 cur = ent->content;
433 while (*cur != 0) {
434 *out++ = *cur++;
435 if (out - buffer > buffer_size - 100) {
436 int index = out - buffer;
437
438 growBuffer(buffer);
439 out = &buffer[index];
440 }
441 }
442 }
443 }
444 } else if (CUR == '%' && (what & XML_SUBSTITUTE_PEREF)) {
445 /*
446 * a PEReference induce to switch the entity flow,
447 * we break here to flush the current set of chars
448 * parsed if any. We will be called back later.
449 */
450 if (CUR_PTR != start) break;
451
452 xmlParsePEReference(ctxt);
453
454 /*
455 * Pop-up of finished entities.
456 */
457 while ((CUR == 0) && (ctxt->inputNr > 1))
458 xmlPopInput(ctxt);
459
460 break;
461 } else {
462 /* TODO: invalid for UTF-8 , use COPY(out); */
463 *out++ = CUR;
Raph Levien05240da1999-06-15 21:27:11 +0000464 if (out - buffer > buffer_size - 100) {
465 int index = out - buffer;
466
467 growBuffer(buffer);
468 out = &buffer[index];
469 }
Daniel Veillard011b63c1999-06-02 17:44:04 +0000470 NEXT;
471 }
472 }
473 *out++ = 0;
474 return(buffer);
475}
476
Daniel Veillard260a68f1998-08-13 03:39:55 +0000477
478/************************************************************************
479 * *
Daniel Veillard27d88741999-05-29 11:51:49 +0000480 * Commodity functions to handle encodings *
481 * *
482 ************************************************************************/
483
484/**
485 * xmlSwitchEncoding:
486 * @ctxt: the parser context
487 * @len: the len of @cur
488 *
489 * change the input functions when discovering the character encoding
490 * of a given entity.
491 *
492 */
493void
494xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
495{
496 switch (enc) {
497 case XML_CHAR_ENCODING_ERROR:
498 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
499 ctxt->sax->error(ctxt->userData, "encoding unknown\n");
500 ctxt->wellFormed = 0;
501 break;
502 case XML_CHAR_ENCODING_NONE:
503 /* let's assume it's UTF-8 without the XML decl */
504 return;
505 case XML_CHAR_ENCODING_UTF8:
506 /* default encoding, no conversion should be needed */
507 return;
508 case XML_CHAR_ENCODING_UTF16LE:
509 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
510 ctxt->sax->error(ctxt->userData,
511 "char encoding UTF16 little endian not supported\n");
512 break;
513 case XML_CHAR_ENCODING_UTF16BE:
514 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
515 ctxt->sax->error(ctxt->userData,
516 "char encoding UTF16 big endian not supported\n");
517 break;
518 case XML_CHAR_ENCODING_UCS4LE:
519 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
520 ctxt->sax->error(ctxt->userData,
521 "char encoding USC4 little endian not supported\n");
522 break;
523 case XML_CHAR_ENCODING_UCS4BE:
524 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
525 ctxt->sax->error(ctxt->userData,
526 "char encoding USC4 big endian not supported\n");
527 break;
528 case XML_CHAR_ENCODING_EBCDIC:
529 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
530 ctxt->sax->error(ctxt->userData,
531 "char encoding EBCDIC not supported\n");
532 break;
533 case XML_CHAR_ENCODING_UCS4_2143:
534 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
535 ctxt->sax->error(ctxt->userData,
536 "char encoding UCS4 2143 not supported\n");
537 break;
538 case XML_CHAR_ENCODING_UCS4_3412:
539 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
540 ctxt->sax->error(ctxt->userData,
541 "char encoding UCS4 3412 not supported\n");
542 break;
543 case XML_CHAR_ENCODING_UCS2:
544 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
545 ctxt->sax->error(ctxt->userData,
546 "char encoding UCS2 not supported\n");
547 break;
548 case XML_CHAR_ENCODING_8859_1:
549 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
550 ctxt->sax->error(ctxt->userData,
551 "char encoding ISO_8859_1 ISO Latin 1 not supported\n");
552 break;
553 case XML_CHAR_ENCODING_8859_2:
554 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
555 ctxt->sax->error(ctxt->userData,
556 "char encoding ISO_8859_2 ISO Latin 2 not supported\n");
557 break;
558 case XML_CHAR_ENCODING_8859_3:
559 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
560 ctxt->sax->error(ctxt->userData,
561 "char encoding ISO_8859_3 not supported\n");
562 break;
563 case XML_CHAR_ENCODING_8859_4:
564 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
565 ctxt->sax->error(ctxt->userData,
566 "char encoding ISO_8859_4 not supported\n");
567 break;
568 case XML_CHAR_ENCODING_8859_5:
569 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
570 ctxt->sax->error(ctxt->userData,
571 "char encoding ISO_8859_5 not supported\n");
572 break;
573 case XML_CHAR_ENCODING_8859_6:
574 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
575 ctxt->sax->error(ctxt->userData,
576 "char encoding ISO_8859_6 not supported\n");
577 break;
578 case XML_CHAR_ENCODING_8859_7:
579 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
580 ctxt->sax->error(ctxt->userData,
581 "char encoding ISO_8859_7 not supported\n");
582 break;
583 case XML_CHAR_ENCODING_8859_8:
584 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
585 ctxt->sax->error(ctxt->userData,
586 "char encoding ISO_8859_8 not supported\n");
587 break;
588 case XML_CHAR_ENCODING_8859_9:
589 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
590 ctxt->sax->error(ctxt->userData,
591 "char encoding ISO_8859_9 not supported\n");
592 break;
593 case XML_CHAR_ENCODING_2022_JP:
594 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
595 ctxt->sax->error(ctxt->userData,
596 "char encoding ISO-2022-JPnot supported\n");
597 break;
598 case XML_CHAR_ENCODING_SHIFT_JIS:
599 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
600 ctxt->sax->error(ctxt->userData,
601 "char encoding Shift_JISnot supported\n");
602 break;
603 case XML_CHAR_ENCODING_EUC_JP:
604 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
605 ctxt->sax->error(ctxt->userData,
606 "char encoding EUC-JPnot supported\n");
607 break;
608 }
609}
610
611/************************************************************************
612 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000613 * Commodity functions to handle CHARs *
614 * *
615 ************************************************************************/
616
Daniel Veillard11e00581998-10-24 18:27:49 +0000617/**
618 * xmlStrndup:
619 * @cur: the input CHAR *
620 * @len: the len of @cur
621 *
622 * a strndup for array of CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000623 *
624 * Returns a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000625 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000626CHAR *
627xmlStrndup(const CHAR *cur, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000628 CHAR *ret = malloc((len + 1) * sizeof(CHAR));
629
630 if (ret == NULL) {
631 fprintf(stderr, "malloc of %d byte failed\n",
632 (len + 1) * sizeof(CHAR));
633 return(NULL);
634 }
635 memcpy(ret, cur, len * sizeof(CHAR));
636 ret[len] = 0;
637 return(ret);
638}
639
Daniel Veillard11e00581998-10-24 18:27:49 +0000640/**
641 * xmlStrdup:
642 * @cur: the input CHAR *
643 *
644 * a strdup for array of CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000645 *
646 * Returns a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000647 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000648CHAR *
649xmlStrdup(const CHAR *cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000650 const CHAR *p = cur;
651
652 while (IS_CHAR(*p)) p++;
653 return(xmlStrndup(cur, p - cur));
654}
655
Daniel Veillard11e00581998-10-24 18:27:49 +0000656/**
657 * xmlCharStrndup:
658 * @cur: the input char *
659 * @len: the len of @cur
660 *
661 * a strndup for char's to CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000662 *
663 * Returns a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000664 */
665
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000666CHAR *
667xmlCharStrndup(const char *cur, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000668 int i;
669 CHAR *ret = malloc((len + 1) * sizeof(CHAR));
670
671 if (ret == NULL) {
672 fprintf(stderr, "malloc of %d byte failed\n",
673 (len + 1) * sizeof(CHAR));
674 return(NULL);
675 }
676 for (i = 0;i < len;i++)
677 ret[i] = (CHAR) cur[i];
678 ret[len] = 0;
679 return(ret);
680}
681
Daniel Veillard11e00581998-10-24 18:27:49 +0000682/**
683 * xmlCharStrdup:
684 * @cur: the input char *
685 * @len: the len of @cur
686 *
687 * a strdup for char's to CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000688 *
689 * Returns a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000690 */
691
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000692CHAR *
693xmlCharStrdup(const char *cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000694 const char *p = cur;
695
696 while (*p != '\0') p++;
697 return(xmlCharStrndup(cur, p - cur));
698}
699
Daniel Veillard11e00581998-10-24 18:27:49 +0000700/**
701 * xmlStrcmp:
702 * @str1: the first CHAR *
703 * @str2: the second CHAR *
704 *
705 * a strcmp for CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000706 *
707 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +0000708 */
709
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000710int
711xmlStrcmp(const CHAR *str1, const CHAR *str2) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000712 register int tmp;
713
714 do {
715 tmp = *str1++ - *str2++;
716 if (tmp != 0) return(tmp);
717 } while ((*str1 != 0) && (*str2 != 0));
718 return (*str1 - *str2);
719}
720
Daniel Veillard11e00581998-10-24 18:27:49 +0000721/**
722 * xmlStrncmp:
723 * @str1: the first CHAR *
724 * @str2: the second CHAR *
725 * @len: the max comparison length
726 *
727 * a strncmp for CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000728 *
729 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +0000730 */
731
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000732int
733xmlStrncmp(const CHAR *str1, const CHAR *str2, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000734 register int tmp;
735
736 if (len <= 0) return(0);
737 do {
738 tmp = *str1++ - *str2++;
739 if (tmp != 0) return(tmp);
740 len--;
741 if (len <= 0) return(0);
742 } while ((*str1 != 0) && (*str2 != 0));
743 return (*str1 - *str2);
744}
745
Daniel Veillard11e00581998-10-24 18:27:49 +0000746/**
747 * xmlStrchr:
748 * @str: the CHAR * array
749 * @val: the CHAR to search
750 *
751 * a strchr for CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000752 *
753 * Returns the CHAR * for the first occurence or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000754 */
755
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000756CHAR *
757xmlStrchr(const CHAR *str, CHAR val) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000758 while (*str != 0) {
759 if (*str == val) return((CHAR *) str);
760 str++;
761 }
762 return(NULL);
763}
764
Daniel Veillard11e00581998-10-24 18:27:49 +0000765/**
766 * xmlStrlen:
767 * @str: the CHAR * array
768 *
769 * lenght of a CHAR's string
Daniel Veillard1e346af1999-02-22 10:33:01 +0000770 *
771 * Returns the number of CHAR contained in the ARRAY.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000772 */
773
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000774int
775xmlStrlen(const CHAR *str) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000776 int len = 0;
777
778 if (str == NULL) return(0);
779 while (*str != 0) {
780 str++;
781 len++;
782 }
783 return(len);
784}
785
Daniel Veillard11e00581998-10-24 18:27:49 +0000786/**
787 * xmlStrncat:
Daniel Veillard1e346af1999-02-22 10:33:01 +0000788 * @cur: the original CHAR * array
Daniel Veillard11e00581998-10-24 18:27:49 +0000789 * @add: the CHAR * array added
790 * @len: the length of @add
791 *
792 * a strncat for array of CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000793 *
794 * Returns a new CHAR * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000795 */
796
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000797CHAR *
798xmlStrncat(CHAR *cur, const CHAR *add, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000799 int size;
800 CHAR *ret;
801
802 if ((add == NULL) || (len == 0))
803 return(cur);
804 if (cur == NULL)
805 return(xmlStrndup(add, len));
806
807 size = xmlStrlen(cur);
808 ret = realloc(cur, (size + len + 1) * sizeof(CHAR));
809 if (ret == NULL) {
810 fprintf(stderr, "xmlStrncat: realloc of %d byte failed\n",
811 (size + len + 1) * sizeof(CHAR));
812 return(cur);
813 }
814 memcpy(&ret[size], add, len * sizeof(CHAR));
815 ret[size + len] = 0;
816 return(ret);
817}
818
Daniel Veillard11e00581998-10-24 18:27:49 +0000819/**
820 * xmlStrcat:
Daniel Veillard1e346af1999-02-22 10:33:01 +0000821 * @cur: the original CHAR * array
Daniel Veillard11e00581998-10-24 18:27:49 +0000822 * @add: the CHAR * array added
823 *
824 * a strcat for array of CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000825 *
826 * Returns a new CHAR * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000827 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000828CHAR *
829xmlStrcat(CHAR *cur, const CHAR *add) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000830 const CHAR *p = add;
831
832 if (add == NULL) return(cur);
833 if (cur == NULL)
834 return(xmlStrdup(add));
835
836 while (IS_CHAR(*p)) p++;
837 return(xmlStrncat(cur, add, p - add));
838}
839
840/************************************************************************
841 * *
842 * Commodity functions, cleanup needed ? *
843 * *
844 ************************************************************************/
845
Daniel Veillard11e00581998-10-24 18:27:49 +0000846/**
847 * areBlanks:
848 * @ctxt: an XML parser context
849 * @str: a CHAR *
850 * @len: the size of @str
851 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000852 * Is this a sequence of blank chars that one can ignore ?
Daniel Veillard11e00581998-10-24 18:27:49 +0000853 *
854 * TODO: to be corrected accodingly to DTD information if available
Daniel Veillard1e346af1999-02-22 10:33:01 +0000855 *
856 * Returns 1 if ignorable 0 otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000857 */
858
859static int areBlanks(xmlParserCtxtPtr ctxt, const CHAR *str, int len) {
860 int i;
861 xmlNodePtr lastChild;
862
863 for (i = 0;i < len;i++)
864 if (!(IS_BLANK(str[i]))) return(0);
865
866 if (CUR != '<') return(0);
Daniel Veillard517752b1999-04-05 12:20:10 +0000867 if (ctxt->node == NULL) return(0);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000868 lastChild = xmlGetLastChild(ctxt->node);
869 if (lastChild == NULL) {
870 if (ctxt->node->content != NULL) return(0);
871 } else if (xmlNodeIsText(lastChild))
872 return(0);
873 return(1);
874}
875
Daniel Veillard11e00581998-10-24 18:27:49 +0000876/**
877 * xmlHandleEntity:
878 * @ctxt: an XML parser context
879 * @entity: an XML entity pointer.
880 *
881 * Default handling of defined entities, when should we define a new input
Daniel Veillard260a68f1998-08-13 03:39:55 +0000882 * stream ? When do we just handle that as a set of chars ?
Daniel Veillard11e00581998-10-24 18:27:49 +0000883 * TODO: we should call the SAX handler here and have it resolve the issue
Daniel Veillard260a68f1998-08-13 03:39:55 +0000884 */
885
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000886void
887xmlHandleEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000888 int len;
Daniel Veillardccb09631998-10-27 06:21:04 +0000889 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000890
891 if (entity->content == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000892 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000893 ctxt->sax->error(ctxt->userData, "xmlHandleEntity %s: content == NULL\n",
Daniel Veillard260a68f1998-08-13 03:39:55 +0000894 entity->name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000895 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000896 return;
897 }
898 len = xmlStrlen(entity->content);
899 if (len <= 2) goto handle_as_char;
900
901 /*
902 * Redefine its content as an input stream.
903 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000904 input = xmlNewEntityInputStream(ctxt, entity);
905 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000906 return;
907
908handle_as_char:
909 /*
910 * Just handle the content as a set of chars.
911 */
Daniel Veillard517752b1999-04-05 12:20:10 +0000912 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000913 ctxt->sax->characters(ctxt->userData, entity->content, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000914
915}
916
917/*
918 * Forward definition for recusive behaviour.
919 */
Daniel Veillard011b63c1999-06-02 17:44:04 +0000920void xmlParsePEReference(xmlParserCtxtPtr ctxt);
921void xmlParseReference(xmlParserCtxtPtr ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000922
923/************************************************************************
924 * *
925 * Extra stuff for namespace support *
926 * Relates to http://www.w3.org/TR/WD-xml-names *
927 * *
928 ************************************************************************/
929
Daniel Veillard11e00581998-10-24 18:27:49 +0000930/**
931 * xmlNamespaceParseNCName:
932 * @ctxt: an XML parser context
933 *
934 * parse an XML namespace name.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000935 *
936 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
937 *
938 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
939 * CombiningChar | Extender
Daniel Veillard1e346af1999-02-22 10:33:01 +0000940 *
941 * Returns the namespace name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000942 */
943
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000944CHAR *
945xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000946 const CHAR *q;
947 CHAR *ret = NULL;
948
949 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
950 q = NEXT;
951
952 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
953 (CUR == '.') || (CUR == '-') ||
954 (CUR == '_') ||
955 (IS_COMBINING(CUR)) ||
956 (IS_EXTENDER(CUR)))
957 NEXT;
958
959 ret = xmlStrndup(q, CUR_PTR - q);
960
961 return(ret);
962}
963
Daniel Veillard11e00581998-10-24 18:27:49 +0000964/**
965 * xmlNamespaceParseQName:
966 * @ctxt: an XML parser context
967 * @prefix: a CHAR **
968 *
969 * parse an XML qualified name
Daniel Veillard260a68f1998-08-13 03:39:55 +0000970 *
971 * [NS 5] QName ::= (Prefix ':')? LocalPart
972 *
973 * [NS 6] Prefix ::= NCName
974 *
975 * [NS 7] LocalPart ::= NCName
Daniel Veillard1e346af1999-02-22 10:33:01 +0000976 *
977 * Returns the function returns the local part, and prefix is updated
Daniel Veillard11e00581998-10-24 18:27:49 +0000978 * to get the Prefix if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000979 */
980
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000981CHAR *
982xmlNamespaceParseQName(xmlParserCtxtPtr ctxt, CHAR **prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000983 CHAR *ret = NULL;
984
985 *prefix = NULL;
986 ret = xmlNamespaceParseNCName(ctxt);
987 if (CUR == ':') {
988 *prefix = ret;
989 NEXT;
990 ret = xmlNamespaceParseNCName(ctxt);
991 }
992
993 return(ret);
994}
995
Daniel Veillard11e00581998-10-24 18:27:49 +0000996/**
Daniel Veillard517752b1999-04-05 12:20:10 +0000997 * xmlSplitQName:
998 * @name: an XML parser context
999 * @prefix: a CHAR **
1000 *
1001 * parse an XML qualified name string
1002 *
1003 * [NS 5] QName ::= (Prefix ':')? LocalPart
1004 *
1005 * [NS 6] Prefix ::= NCName
1006 *
1007 * [NS 7] LocalPart ::= NCName
1008 *
1009 * Returns the function returns the local part, and prefix is updated
1010 * to get the Prefix if any.
1011 */
1012
1013CHAR *
1014xmlSplitQName(const CHAR *name, CHAR **prefix) {
1015 CHAR *ret = NULL;
1016 const CHAR *q;
1017 const CHAR *cur = name;
1018
1019 *prefix = NULL;
1020 if (!IS_LETTER(*cur) && (*cur != '_')) return(NULL);
1021 q = cur++;
1022
1023 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1024 (*cur == '.') || (*cur == '-') ||
1025 (*cur == '_') ||
1026 (IS_COMBINING(*cur)) ||
1027 (IS_EXTENDER(*cur)))
1028 cur++;
1029
1030 ret = xmlStrndup(q, cur - q);
1031
1032 if (*cur == ':') {
1033 cur++;
1034 if (!IS_LETTER(*cur) && (*cur != '_')) return(ret);
1035 *prefix = ret;
1036
1037 q = cur++;
1038
1039 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1040 (*cur == '.') || (*cur == '-') ||
1041 (*cur == '_') ||
1042 (IS_COMBINING(*cur)) ||
1043 (IS_EXTENDER(*cur)))
1044 cur++;
1045
1046 ret = xmlStrndup(q, cur - q);
1047 }
1048
1049 return(ret);
1050}
1051/**
Daniel Veillard11e00581998-10-24 18:27:49 +00001052 * xmlNamespaceParseNSDef:
1053 * @ctxt: an XML parser context
1054 *
1055 * parse a namespace prefix declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00001056 *
1057 * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral
1058 *
1059 * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)?
Daniel Veillard1e346af1999-02-22 10:33:01 +00001060 *
1061 * Returns the namespace name
Daniel Veillard260a68f1998-08-13 03:39:55 +00001062 */
1063
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001064CHAR *
1065xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001066 CHAR *name = NULL;
1067
1068 if ((CUR == 'x') && (NXT(1) == 'm') &&
1069 (NXT(2) == 'l') && (NXT(3) == 'n') &&
1070 (NXT(4) == 's')) {
1071 SKIP(5);
1072 if (CUR == ':') {
1073 NEXT;
1074 name = xmlNamespaceParseNCName(ctxt);
1075 }
1076 }
1077 return(name);
1078}
1079
Daniel Veillard11e00581998-10-24 18:27:49 +00001080/**
1081 * xmlParseQuotedString:
1082 * @ctxt: an XML parser context
1083 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001084 * [OLD] Parse and return a string between quotes or doublequotes
Daniel Veillard1e346af1999-02-22 10:33:01 +00001085 *
1086 * Returns the string parser or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001087 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001088CHAR *
1089xmlParseQuotedString(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001090 CHAR *ret = NULL;
1091 const CHAR *q;
1092
1093 if (CUR == '"') {
1094 NEXT;
1095 q = CUR_PTR;
1096 while (IS_CHAR(CUR) && (CUR != '"')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001097 if (CUR != '"') {
1098 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001099 ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001100 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001101 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001102 ret = xmlStrndup(q, CUR_PTR - q);
1103 NEXT;
1104 }
1105 } else if (CUR == '\''){
1106 NEXT;
1107 q = CUR_PTR;
1108 while (IS_CHAR(CUR) && (CUR != '\'')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001109 if (CUR != '\'') {
1110 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001111 ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001112 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001113 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001114 ret = xmlStrndup(q, CUR_PTR - q);
1115 NEXT;
1116 }
1117 }
1118 return(ret);
1119}
1120
Daniel Veillard11e00581998-10-24 18:27:49 +00001121/**
1122 * xmlParseNamespace:
1123 * @ctxt: an XML parser context
1124 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001125 * [OLD] xmlParseNamespace: parse specific PI '<?namespace ...' constructs.
1126 *
1127 * This is what the older xml-name Working Draft specified, a bunch of
1128 * other stuff may still rely on it, so support is still here as
1129 * if ot was declared on the root of the Tree:-(
1130 */
1131
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001132void
1133xmlParseNamespace(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001134 CHAR *href = NULL;
1135 CHAR *prefix = NULL;
1136 int garbage = 0;
1137
1138 /*
1139 * We just skipped "namespace" or "xml:namespace"
1140 */
1141 SKIP_BLANKS;
1142
1143 while (IS_CHAR(CUR) && (CUR != '>')) {
1144 /*
1145 * We can have "ns" or "prefix" attributes
1146 * Old encoding as 'href' or 'AS' attributes is still supported
1147 */
1148 if ((CUR == 'n') && (NXT(1) == 's')) {
1149 garbage = 0;
1150 SKIP(2);
1151 SKIP_BLANKS;
1152
1153 if (CUR != '=') continue;
1154 NEXT;
1155 SKIP_BLANKS;
1156
1157 href = xmlParseQuotedString(ctxt);
1158 SKIP_BLANKS;
1159 } else if ((CUR == 'h') && (NXT(1) == 'r') &&
1160 (NXT(2) == 'e') && (NXT(3) == 'f')) {
1161 garbage = 0;
1162 SKIP(4);
1163 SKIP_BLANKS;
1164
1165 if (CUR != '=') continue;
1166 NEXT;
1167 SKIP_BLANKS;
1168
1169 href = xmlParseQuotedString(ctxt);
1170 SKIP_BLANKS;
1171 } else if ((CUR == 'p') && (NXT(1) == 'r') &&
1172 (NXT(2) == 'e') && (NXT(3) == 'f') &&
1173 (NXT(4) == 'i') && (NXT(5) == 'x')) {
1174 garbage = 0;
1175 SKIP(6);
1176 SKIP_BLANKS;
1177
1178 if (CUR != '=') continue;
1179 NEXT;
1180 SKIP_BLANKS;
1181
1182 prefix = xmlParseQuotedString(ctxt);
1183 SKIP_BLANKS;
1184 } else if ((CUR == 'A') && (NXT(1) == 'S')) {
1185 garbage = 0;
1186 SKIP(2);
1187 SKIP_BLANKS;
1188
1189 if (CUR != '=') continue;
1190 NEXT;
1191 SKIP_BLANKS;
1192
1193 prefix = xmlParseQuotedString(ctxt);
1194 SKIP_BLANKS;
1195 } else if ((CUR == '?') && (NXT(1) == '>')) {
1196 garbage = 0;
1197 CUR_PTR ++;
1198 } else {
1199 /*
1200 * Found garbage when parsing the namespace
1201 */
1202 if (!garbage)
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001203 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001204 ctxt->sax->error(ctxt->userData, "xmlParseNamespace found garbage\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001205 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001206 NEXT;
1207 }
1208 }
1209
1210 MOVETO_ENDTAG(CUR_PTR);
1211 NEXT;
1212
1213 /*
1214 * Register the DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001215 if (href != NULL)
Daniel Veillard517752b1999-04-05 12:20:10 +00001216 if ((ctxt->sax != NULL) && (ctxt->sax->globalNamespace != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001217 ctxt->sax->globalNamespace(ctxt->userData, href, prefix);
Daniel Veillard517752b1999-04-05 12:20:10 +00001218 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00001219
1220 if (prefix != NULL) free(prefix);
1221 if (href != NULL) free(href);
1222}
1223
1224/************************************************************************
1225 * *
1226 * The parser itself *
1227 * Relates to http://www.w3.org/TR/REC-xml *
1228 * *
1229 ************************************************************************/
1230
Daniel Veillard11e00581998-10-24 18:27:49 +00001231/**
1232 * xmlParseName:
1233 * @ctxt: an XML parser context
1234 *
1235 * parse an XML name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001236 *
1237 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
1238 * CombiningChar | Extender
1239 *
1240 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
1241 *
1242 * [6] Names ::= Name (S Name)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00001243 *
1244 * Returns the Name parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001245 */
1246
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001247CHAR *
1248xmlParseName(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001249 const CHAR *q;
1250 CHAR *ret = NULL;
1251
1252 if (!IS_LETTER(CUR) && (CUR != '_') &&
1253 (CUR != ':')) return(NULL);
1254 q = NEXT;
1255
1256 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1257 (CUR == '.') || (CUR == '-') ||
1258 (CUR == '_') || (CUR == ':') ||
1259 (IS_COMBINING(CUR)) ||
1260 (IS_EXTENDER(CUR)))
1261 NEXT;
1262
1263 ret = xmlStrndup(q, CUR_PTR - q);
1264
1265 return(ret);
1266}
1267
Daniel Veillard11e00581998-10-24 18:27:49 +00001268/**
1269 * xmlParseNmtoken:
1270 * @ctxt: an XML parser context
1271 *
1272 * parse an XML Nmtoken.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001273 *
1274 * [7] Nmtoken ::= (NameChar)+
1275 *
1276 * [8] Nmtokens ::= Nmtoken (S Nmtoken)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00001277 *
1278 * Returns the Nmtoken parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001279 */
1280
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001281CHAR *
1282xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001283 const CHAR *q;
1284 CHAR *ret = NULL;
1285
1286 q = NEXT;
1287
1288 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1289 (CUR == '.') || (CUR == '-') ||
1290 (CUR == '_') || (CUR == ':') ||
1291 (IS_COMBINING(CUR)) ||
1292 (IS_EXTENDER(CUR)))
1293 NEXT;
1294
1295 ret = xmlStrndup(q, CUR_PTR - q);
1296
1297 return(ret);
1298}
1299
Daniel Veillard11e00581998-10-24 18:27:49 +00001300/**
1301 * xmlParseEntityValue:
1302 * @ctxt: an XML parser context
Daniel Veillard011b63c1999-06-02 17:44:04 +00001303 * @orig: if non-NULL store a copy of the original entity value
Daniel Veillard11e00581998-10-24 18:27:49 +00001304 *
1305 * parse a value for ENTITY decl.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001306 *
1307 * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
1308 * "'" ([^%&'] | PEReference | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00001309 *
Daniel Veillard011b63c1999-06-02 17:44:04 +00001310 * Returns the EntityValue parsed with reference substitued or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001311 */
1312
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001313CHAR *
Daniel Veillard011b63c1999-06-02 17:44:04 +00001314xmlParseEntityValue(xmlParserCtxtPtr ctxt, CHAR **orig) {
1315 CHAR *ret = NULL;
1316 const CHAR *org = NULL;
1317 const CHAR *tst = NULL;
1318 const CHAR *temp = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001319
1320 if (CUR == '"') {
1321 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001322 org = CUR_PTR;
1323 while (CUR != '"') {
1324 tst = CUR_PTR;
1325 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_BOTH, '"', 0, 0);
1326 if ((temp == NULL) && (tst == CUR_PTR)) break;
1327 ret = xmlStrcat(ret, temp);
1328 if (temp != NULL) free((char *)temp);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001329 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00001330 if (CUR != '"') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001331 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00001332 ctxt->sax->error(ctxt->userData, "EntityValue: \" expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001333 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001334 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001335 if (orig != NULL)
1336 *orig = xmlStrndup(org, CUR_PTR - org);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001337 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001338 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001339 } else if (CUR == '\'') {
1340 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001341 org = CUR_PTR;
1342 while (CUR != '\'') {
1343 tst = CUR_PTR;
1344 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_BOTH, '\'', 0, 0);
1345 if ((temp == NULL) && (tst == CUR_PTR)) break;
1346 ret = xmlStrcat(ret, temp);
1347 if (temp != NULL) free((char *)temp);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001348 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00001349 if (CUR != '\'') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001350 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00001351 ctxt->sax->error(ctxt->userData, "EntityValue: ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001352 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001353 } else {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001354 if (orig != NULL)
1355 *orig = xmlStrndup(org, CUR_PTR - org);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001356 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001357 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001358 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001359 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00001360 ctxt->sax->error(ctxt->userData, "EntityValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001361 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001362 }
1363
1364 return(ret);
1365}
1366
Daniel Veillard11e00581998-10-24 18:27:49 +00001367/**
1368 * xmlParseAttValue:
1369 * @ctxt: an XML parser context
1370 *
1371 * parse a value for an attribute
Daniel Veillard011b63c1999-06-02 17:44:04 +00001372 * Note: the parser won't do substitution of entities here, this
1373 * will be handled later in xmlStringGetNodeList, unless it was
1374 * asked for ctxt->replaceEntities != 0
Daniel Veillard260a68f1998-08-13 03:39:55 +00001375 *
1376 * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
1377 * "'" ([^<&'] | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00001378 *
1379 * Returns the AttValue parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001380 */
1381
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001382CHAR *
1383xmlParseAttValue(xmlParserCtxtPtr ctxt) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001384 CHAR *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001385
1386 if (CUR == '"') {
1387 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001388 if (ctxt->replaceEntities != 0)
1389 ret = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_REF, '"', '<', 0);
1390 else
1391 ret = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_NONE, '"', '<', 0);
1392 if (CUR == '<') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001393 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00001394 ctxt->sax->error(ctxt->userData,
1395 "Unescaped '<' not allowed in attributes values\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001396 ctxt->wellFormed = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001397 }
1398 if (CUR != '"') {
1399 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1400 ctxt->sax->error(ctxt->userData, "AttValue: ' expected\n");
1401 ctxt->wellFormed = 0;
1402 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00001403 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001404 } else if (CUR == '\'') {
1405 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001406 if (ctxt->replaceEntities != 0)
1407 ret = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_REF, '\'', '<', 0);
1408 else
1409 ret = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_NONE, '\'', '<', 0);
1410 if (CUR == '<') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001411 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00001412 ctxt->sax->error(ctxt->userData,
1413 "Unescaped '<' not allowed in attributes values\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001414 ctxt->wellFormed = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001415 }
1416 if (CUR != '\'') {
1417 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1418 ctxt->sax->error(ctxt->userData, "AttValue: ' expected\n");
1419 ctxt->wellFormed = 0;
1420 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00001421 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001422 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001423 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001424 ctxt->sax->error(ctxt->userData, "AttValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001425 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001426 }
1427
1428 return(ret);
1429}
1430
Daniel Veillard11e00581998-10-24 18:27:49 +00001431/**
1432 * xmlParseSystemLiteral:
1433 * @ctxt: an XML parser context
1434 *
1435 * parse an XML Literal
Daniel Veillard260a68f1998-08-13 03:39:55 +00001436 *
1437 * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
Daniel Veillard1e346af1999-02-22 10:33:01 +00001438 *
1439 * Returns the SystemLiteral parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001440 */
1441
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001442CHAR *
1443xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001444 const CHAR *q;
1445 CHAR *ret = NULL;
1446
1447 if (CUR == '"') {
1448 NEXT;
1449 q = CUR_PTR;
1450 while ((IS_CHAR(CUR)) && (CUR != '"'))
1451 NEXT;
1452 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001453 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001454 ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001455 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001456 } else {
1457 ret = xmlStrndup(q, CUR_PTR - q);
1458 NEXT;
1459 }
1460 } else if (CUR == '\'') {
1461 NEXT;
1462 q = CUR_PTR;
1463 while ((IS_CHAR(CUR)) && (CUR != '\''))
1464 NEXT;
1465 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001466 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001467 ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001468 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001469 } else {
1470 ret = xmlStrndup(q, CUR_PTR - q);
1471 NEXT;
1472 }
1473 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001474 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001475 ctxt->sax->error(ctxt->userData, "SystemLiteral \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001476 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001477 }
1478
1479 return(ret);
1480}
1481
Daniel Veillard11e00581998-10-24 18:27:49 +00001482/**
1483 * xmlParsePubidLiteral:
1484 * @ctxt: an XML parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +00001485 *
Daniel Veillard11e00581998-10-24 18:27:49 +00001486 * parse an XML public literal
Daniel Veillard1e346af1999-02-22 10:33:01 +00001487 *
1488 * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1489 *
1490 * Returns the PubidLiteral parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001491 */
1492
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001493CHAR *
1494xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001495 const CHAR *q;
1496 CHAR *ret = NULL;
1497 /*
1498 * Name ::= (Letter | '_') (NameChar)*
1499 */
1500 if (CUR == '"') {
1501 NEXT;
1502 q = CUR_PTR;
1503 while (IS_PUBIDCHAR(CUR)) NEXT;
1504 if (CUR != '"') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001505 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001506 ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001507 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001508 } else {
1509 ret = xmlStrndup(q, CUR_PTR - q);
1510 NEXT;
1511 }
1512 } else if (CUR == '\'') {
1513 NEXT;
1514 q = CUR_PTR;
1515 while ((IS_LETTER(CUR)) && (CUR != '\''))
1516 NEXT;
1517 if (!IS_LETTER(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001518 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001519 ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001520 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001521 } else {
1522 ret = xmlStrndup(q, CUR_PTR - q);
1523 NEXT;
1524 }
1525 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001526 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001527 ctxt->sax->error(ctxt->userData, "SystemLiteral \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001528 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001529 }
1530
1531 return(ret);
1532}
1533
Daniel Veillard11e00581998-10-24 18:27:49 +00001534/**
1535 * xmlParseCharData:
1536 * @ctxt: an XML parser context
1537 * @cdata: int indicating whether we are within a CDATA section
1538 *
1539 * parse a CharData section.
1540 * if we are within a CDATA section ']]>' marks an end of section.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001541 *
1542 * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
1543 */
1544
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001545void
1546xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001547 const CHAR *q;
1548
1549 q = CUR_PTR;
1550 while ((IS_CHAR(CUR)) && (CUR != '<') &&
1551 (CUR != '&')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001552 if ((CUR == ']') && (NXT(1) == ']') &&
1553 (NXT(2) == '>')) {
1554 if (cdata) break;
1555 else {
1556 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001557 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001558 "Sequence ']]>' not allowed in content\n");
1559 ctxt->wellFormed = 0;
1560 }
1561 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001562 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001563 }
1564 if (q == CUR_PTR) return;
1565
1566 /*
1567 * Ok the segment [q CUR_PTR] is to be consumed as chars.
1568 */
1569 if (ctxt->sax != NULL) {
Daniel Veillard517752b1999-04-05 12:20:10 +00001570 if (areBlanks(ctxt, q, CUR_PTR - q)) {
1571 if (ctxt->sax->ignorableWhitespace != NULL)
Daniel Veillard27d88741999-05-29 11:51:49 +00001572 ctxt->sax->ignorableWhitespace(ctxt->userData, q, CUR_PTR - q);
Daniel Veillard517752b1999-04-05 12:20:10 +00001573 } else {
1574 if (ctxt->sax->characters != NULL)
Daniel Veillard27d88741999-05-29 11:51:49 +00001575 ctxt->sax->characters(ctxt->userData, q, CUR_PTR - q);
Daniel Veillard517752b1999-04-05 12:20:10 +00001576 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001577 }
1578}
1579
Daniel Veillard11e00581998-10-24 18:27:49 +00001580/**
1581 * xmlParseExternalID:
1582 * @ctxt: an XML parser context
1583 * @publicID: a CHAR** receiving PubidLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00001584 * @strict: indicate whether we should restrict parsing to only
1585 * production [75], see NOTE below
Daniel Veillard11e00581998-10-24 18:27:49 +00001586 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001587 * Parse an External ID or a Public ID
1588 *
1589 * NOTE: Productions [75] and [83] interract badly since [75] can generate
1590 * 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard260a68f1998-08-13 03:39:55 +00001591 *
1592 * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
1593 * | 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00001594 *
1595 * [83] PublicID ::= 'PUBLIC' S PubidLiteral
1596 *
1597 * Returns the function returns SystemLiteral and in the second
1598 * case publicID receives PubidLiteral, is strict is off
1599 * it is possible to return NULL and have publicID set.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001600 */
1601
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001602CHAR *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001603xmlParseExternalID(xmlParserCtxtPtr ctxt, CHAR **publicID, int strict) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001604 CHAR *URI = NULL;
1605
1606 if ((CUR == 'S') && (NXT(1) == 'Y') &&
1607 (NXT(2) == 'S') && (NXT(3) == 'T') &&
1608 (NXT(4) == 'E') && (NXT(5) == 'M')) {
1609 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001610 if (!IS_BLANK(CUR)) {
1611 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001612 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001613 "Space required after 'SYSTEM'\n");
1614 ctxt->wellFormed = 0;
1615 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001616 SKIP_BLANKS;
1617 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001618 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001619 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001620 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001621 "xmlParseExternalID: SYSTEM, no URI\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001622 ctxt->wellFormed = 0;
1623 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001624 } else if ((CUR == 'P') && (NXT(1) == 'U') &&
1625 (NXT(2) == 'B') && (NXT(3) == 'L') &&
1626 (NXT(4) == 'I') && (NXT(5) == 'C')) {
1627 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001628 if (!IS_BLANK(CUR)) {
1629 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001630 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001631 "Space required after 'PUBLIC'\n");
1632 ctxt->wellFormed = 0;
1633 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001634 SKIP_BLANKS;
1635 *publicID = xmlParsePubidLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001636 if (*publicID == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001637 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001638 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001639 "xmlParseExternalID: PUBLIC, no Public Identifier\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001640 ctxt->wellFormed = 0;
1641 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001642 if (strict) {
1643 /*
1644 * We don't handle [83] so "S SystemLiteral" is required.
1645 */
1646 if (!IS_BLANK(CUR)) {
1647 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001648 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00001649 "Space required after the Public Identifier\n");
1650 ctxt->wellFormed = 0;
1651 }
1652 } else {
1653 /*
1654 * We handle [83] so we return immediately, if
1655 * "S SystemLiteral" is not detected. From a purely parsing
1656 * point of view that's a nice mess.
1657 */
1658 const CHAR *ptr = CUR_PTR;
1659 if (!IS_BLANK(*ptr)) return(NULL);
1660
1661 while (IS_BLANK(*ptr)) ptr++;
1662 if ((*ptr != '\'') || (*ptr != '"')) return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001663 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001664 SKIP_BLANKS;
1665 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001666 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001667 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001668 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001669 "xmlParseExternalID: PUBLIC, no URI\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001670 ctxt->wellFormed = 0;
1671 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001672 }
1673 return(URI);
1674}
1675
Daniel Veillard11e00581998-10-24 18:27:49 +00001676/**
1677 * xmlParseComment:
Daniel Veillard1e346af1999-02-22 10:33:01 +00001678 * @ctxt: an XML parser context
1679 * @create: should we create a node, or just skip the content
Daniel Veillard11e00581998-10-24 18:27:49 +00001680 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001681 * Skip an XML (SGML) comment <!-- .... -->
1682 * This may or may not create a node (depending on the context)
1683 * The spec says that "For compatibility, the string "--" (double-hyphen)
1684 * must not occur within comments. "
1685 *
1686 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
1687 */
Daniel Veillard517752b1999-04-05 12:20:10 +00001688void
Daniel Veillard1e346af1999-02-22 10:33:01 +00001689xmlParseComment(xmlParserCtxtPtr ctxt, int create) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001690 const CHAR *q, *start;
1691 const CHAR *r;
1692 CHAR *val;
1693
1694 /*
1695 * Check that there is a comment right here.
1696 */
1697 if ((CUR != '<') || (NXT(1) != '!') ||
Daniel Veillard517752b1999-04-05 12:20:10 +00001698 (NXT(2) != '-') || (NXT(3) != '-')) return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001699
1700 SKIP(4);
1701 start = q = CUR_PTR;
1702 NEXT;
1703 r = CUR_PTR;
1704 NEXT;
1705 while (IS_CHAR(CUR) &&
1706 ((CUR == ':') || (CUR != '>') ||
1707 (*r != '-') || (*q != '-'))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001708 if ((*r == '-') && (*q == '-')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001709 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001710 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001711 "Comment must not contain '--' (double-hyphen)`\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001712 ctxt->wellFormed = 0;
1713 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001714 NEXT;r++;q++;
1715 }
1716 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001717 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001718 ctxt->sax->error(ctxt->userData, "Comment not terminated \n<!--%.50s\n", start);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001719 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001720 } else {
1721 NEXT;
1722 if (create) {
1723 val = xmlStrndup(start, q - start);
Daniel Veillard517752b1999-04-05 12:20:10 +00001724 if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001725 ctxt->sax->comment(ctxt->userData, val);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001726 free(val);
1727 }
1728 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001729}
1730
Daniel Veillard11e00581998-10-24 18:27:49 +00001731/**
1732 * xmlParsePITarget:
1733 * @ctxt: an XML parser context
1734 *
1735 * parse the name of a PI
Daniel Veillard260a68f1998-08-13 03:39:55 +00001736 *
1737 * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00001738 *
1739 * Returns the PITarget name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001740 */
1741
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001742CHAR *
1743xmlParsePITarget(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001744 CHAR *name;
1745
1746 name = xmlParseName(ctxt);
1747 if ((name != NULL) && (name[3] == 0) &&
1748 ((name[0] == 'x') || (name[0] == 'X')) &&
1749 ((name[1] == 'm') || (name[1] == 'M')) &&
1750 ((name[2] == 'l') || (name[2] == 'L'))) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001751 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001752 ctxt->sax->error(ctxt->userData, "xmlParsePItarget: invalid name prefix 'xml'\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001753 return(NULL);
1754 }
1755 return(name);
1756}
1757
Daniel Veillard11e00581998-10-24 18:27:49 +00001758/**
1759 * xmlParsePI:
1760 * @ctxt: an XML parser context
1761 *
1762 * parse an XML Processing Instruction.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001763 *
1764 * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
Daniel Veillard1e346af1999-02-22 10:33:01 +00001765 *
1766 * The processing is transfered to SAX once parsed.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001767 */
1768
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001769void
1770xmlParsePI(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001771 CHAR *target;
1772
1773 if ((CUR == '<') && (NXT(1) == '?')) {
1774 /*
1775 * this is a Processing Instruction.
1776 */
1777 SKIP(2);
1778
1779 /*
1780 * Parse the target name and check for special support like
1781 * namespace.
1782 *
1783 * TODO : PI handling should be dynamically redefinable using an
1784 * API. Only namespace should be in the code IMHO ...
1785 */
1786 target = xmlParsePITarget(ctxt);
1787 if (target != NULL) {
Daniel Veillard517752b1999-04-05 12:20:10 +00001788 const CHAR *q = CUR_PTR;
1789
1790 while (IS_CHAR(CUR) &&
1791 ((CUR != '?') || (NXT(1) != '>')))
1792 NEXT;
1793 if (!IS_CHAR(CUR)) {
1794 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001795 ctxt->sax->error(ctxt->userData,
Daniel Veillard517752b1999-04-05 12:20:10 +00001796 "xmlParsePI: PI %s never end ...\n", target);
1797 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001798 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00001799 CHAR *data;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001800
Daniel Veillard517752b1999-04-05 12:20:10 +00001801 data = xmlStrndup(q, CUR_PTR - q);
1802 SKIP(2);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001803
Daniel Veillard517752b1999-04-05 12:20:10 +00001804 /*
1805 * SAX: PI detected.
1806 */
1807 if ((ctxt->sax) &&
1808 (ctxt->sax->processingInstruction != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001809 ctxt->sax->processingInstruction(ctxt->userData, target, data);
Daniel Veillard517752b1999-04-05 12:20:10 +00001810 free(data);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001811 }
1812 free(target);
1813 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001814 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001815 ctxt->sax->error(ctxt->userData, "xmlParsePI : no target name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001816 ctxt->wellFormed = 0;
1817
Daniel Veillard260a68f1998-08-13 03:39:55 +00001818 /********* Should we try to complete parsing the PI ???
1819 while (IS_CHAR(CUR) &&
1820 (CUR != '?') && (CUR != '>'))
1821 NEXT;
1822 if (!IS_CHAR(CUR)) {
1823 fprintf(stderr, "xmlParsePI: PI %s never end ...\n",
1824 target);
1825 }
1826 ********************************************************/
1827 }
1828 }
1829}
1830
Daniel Veillard11e00581998-10-24 18:27:49 +00001831/**
1832 * xmlParseNotationDecl:
1833 * @ctxt: an XML parser context
1834 *
1835 * parse a notation declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00001836 *
1837 * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
1838 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001839 * Hence there is actually 3 choices:
1840 * 'PUBLIC' S PubidLiteral
1841 * 'PUBLIC' S PubidLiteral S SystemLiteral
1842 * and 'SYSTEM' S SystemLiteral
Daniel Veillard11e00581998-10-24 18:27:49 +00001843 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001844 * See the NOTE on xmlParseExternalID().
Daniel Veillard260a68f1998-08-13 03:39:55 +00001845 */
1846
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001847void
1848xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001849 CHAR *name;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001850 CHAR *Pubid;
1851 CHAR *Systemid;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001852
1853 if ((CUR == '<') && (NXT(1) == '!') &&
1854 (NXT(2) == 'N') && (NXT(3) == 'O') &&
1855 (NXT(4) == 'T') && (NXT(5) == 'A') &&
1856 (NXT(6) == 'T') && (NXT(7) == 'I') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00001857 (NXT(8) == 'O') && (NXT(9) == 'N')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001858 SKIP(10);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001859 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001860 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001861 ctxt->sax->error(ctxt->userData, "Space required after '<!NOTATION'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001862 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001863 return;
1864 }
1865 SKIP_BLANKS;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001866
1867 name = xmlParseName(ctxt);
1868 if (name == NULL) {
1869 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001870 ctxt->sax->error(ctxt->userData, "NOTATION: Name expected here\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001871 ctxt->wellFormed = 0;
1872 return;
1873 }
1874 if (!IS_BLANK(CUR)) {
1875 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001876 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00001877 "Space required after the NOTATION name'\n");
1878 ctxt->wellFormed = 0;
1879 return;
1880 }
1881 SKIP_BLANKS;
1882
Daniel Veillard260a68f1998-08-13 03:39:55 +00001883 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00001884 * Parse the IDs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001885 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001886 Systemid = xmlParseExternalID(ctxt, &Pubid, 1);
1887 SKIP_BLANKS;
1888
1889 if (CUR == '>') {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001890 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00001891 if ((ctxt->sax != NULL) && (ctxt->sax->notationDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001892 ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001893 } else {
1894 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001895 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00001896 "'>' required to close NOTATION declaration\n");
1897 ctxt->wellFormed = 0;
1898 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001899 free(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001900 if (Systemid != NULL) free(Systemid);
1901 if (Pubid != NULL) free(Pubid);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001902 }
1903}
1904
Daniel Veillard11e00581998-10-24 18:27:49 +00001905/**
1906 * xmlParseEntityDecl:
1907 * @ctxt: an XML parser context
1908 *
1909 * parse <!ENTITY declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00001910 *
1911 * [70] EntityDecl ::= GEDecl | PEDecl
1912 *
1913 * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
1914 *
1915 * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
1916 *
1917 * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
1918 *
1919 * [74] PEDef ::= EntityValue | ExternalID
1920 *
1921 * [76] NDataDecl ::= S 'NDATA' S Name
1922 */
1923
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001924void
1925xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001926 CHAR *name = NULL;
1927 CHAR *value = NULL;
1928 CHAR *URI = NULL, *literal = NULL;
1929 CHAR *ndata = NULL;
1930 int isParameter = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001931 CHAR *orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001932
1933 if ((CUR == '<') && (NXT(1) == '!') &&
1934 (NXT(2) == 'E') && (NXT(3) == 'N') &&
1935 (NXT(4) == 'T') && (NXT(5) == 'I') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001936 (NXT(6) == 'T') && (NXT(7) == 'Y')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001937 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001938 if (!IS_BLANK(CUR)) {
1939 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001940 ctxt->sax->error(ctxt->userData, "Space required after '<!ENTITY'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001941 ctxt->wellFormed = 0;
1942 }
1943 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001944
1945 if (CUR == '%') {
1946 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001947 if (!IS_BLANK(CUR)) {
1948 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001949 ctxt->sax->error(ctxt->userData, "Space required after '%'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001950 ctxt->wellFormed = 0;
1951 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001952 SKIP_BLANKS;
1953 isParameter = 1;
1954 }
1955
1956 name = xmlParseName(ctxt);
1957 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001958 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001959 ctxt->sax->error(ctxt->userData, "xmlParseEntityDecl: no name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001960 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001961 return;
1962 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001963 if (!IS_BLANK(CUR)) {
1964 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001965 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001966 "Space required after the entity name\n");
1967 ctxt->wellFormed = 0;
1968 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001969 SKIP_BLANKS;
1970
1971 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00001972 * handle the various case of definitions...
Daniel Veillard260a68f1998-08-13 03:39:55 +00001973 */
1974 if (isParameter) {
1975 if ((CUR == '"') || (CUR == '\''))
Daniel Veillard011b63c1999-06-02 17:44:04 +00001976 value = xmlParseEntityValue(ctxt, &orig);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001977 if (value) {
Daniel Veillard517752b1999-04-05 12:20:10 +00001978 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001979 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001980 XML_INTERNAL_PARAMETER_ENTITY,
1981 NULL, NULL, value);
1982 }
1983 else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001984 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001985 if (URI) {
Daniel Veillard517752b1999-04-05 12:20:10 +00001986 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001987 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001988 XML_EXTERNAL_PARAMETER_ENTITY,
1989 literal, URI, NULL);
1990 }
1991 }
1992 } else {
1993 if ((CUR == '"') || (CUR == '\'')) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001994 value = xmlParseEntityValue(ctxt, &orig);
Daniel Veillard517752b1999-04-05 12:20:10 +00001995 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001996 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001997 XML_INTERNAL_GENERAL_ENTITY,
1998 NULL, NULL, value);
1999 } else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00002000 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002001 if ((CUR != '>') && (!IS_BLANK(CUR))) {
2002 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002003 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002004 "Space required before 'NDATA'\n");
2005 ctxt->wellFormed = 0;
2006 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002007 SKIP_BLANKS;
2008 if ((CUR == 'N') && (NXT(1) == 'D') &&
2009 (NXT(2) == 'A') && (NXT(3) == 'T') &&
2010 (NXT(4) == 'A')) {
2011 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002012 if (!IS_BLANK(CUR)) {
2013 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002014 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002015 "Space required after 'NDATA'\n");
2016 ctxt->wellFormed = 0;
2017 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002018 SKIP_BLANKS;
2019 ndata = xmlParseName(ctxt);
Daniel Veillard517752b1999-04-05 12:20:10 +00002020 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002021 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002022 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
2023 literal, URI, ndata);
2024 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00002025 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002026 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002027 XML_EXTERNAL_GENERAL_PARSED_ENTITY,
2028 literal, URI, NULL);
2029 }
2030 }
2031 }
2032 SKIP_BLANKS;
2033 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002034 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002035 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002036 "xmlParseEntityDecl: entity %s not terminated\n", name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002037 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002038 } else
2039 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002040 if (orig != NULL) {
2041 /*
2042 * TODO: somwhat unclean, extending the SAx API would be better !
2043 */
2044 xmlEntityPtr cur = NULL;
2045
2046 if ((ctxt->sax != NULL) && (ctxt->sax->getEntity != NULL))
2047 cur = ctxt->sax->getEntity(ctxt, name);
2048 if (cur != NULL)
2049 cur->orig = orig;
2050 else
2051 free(orig);
2052 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002053 if (name != NULL) free(name);
2054 if (value != NULL) free(value);
2055 if (URI != NULL) free(URI);
2056 if (literal != NULL) free(literal);
2057 if (ndata != NULL) free(ndata);
2058 }
2059}
2060
Daniel Veillard11e00581998-10-24 18:27:49 +00002061/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002062 * xmlParseDefaultDecl:
2063 * @ctxt: an XML parser context
2064 * @value: Receive a possible fixed default value for the attribute
2065 *
2066 * Parse an attribute default declaration
2067 *
2068 * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
2069 *
2070 * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
2071 * or XML_ATTRIBUTE_FIXED.
2072 */
2073
2074int
2075xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, CHAR **value) {
2076 int val;
2077 CHAR *ret;
2078
2079 *value = NULL;
2080 if ((CUR == '#') && (NXT(1) == 'R') &&
2081 (NXT(2) == 'E') && (NXT(3) == 'Q') &&
2082 (NXT(4) == 'U') && (NXT(5) == 'I') &&
2083 (NXT(6) == 'R') && (NXT(7) == 'E') &&
2084 (NXT(8) == 'D')) {
2085 SKIP(9);
2086 return(XML_ATTRIBUTE_REQUIRED);
2087 }
2088 if ((CUR == '#') && (NXT(1) == 'I') &&
2089 (NXT(2) == 'M') && (NXT(3) == 'P') &&
2090 (NXT(4) == 'L') && (NXT(5) == 'I') &&
2091 (NXT(6) == 'E') && (NXT(7) == 'D')) {
2092 SKIP(8);
2093 return(XML_ATTRIBUTE_IMPLIED);
2094 }
2095 val = XML_ATTRIBUTE_NONE;
2096 if ((CUR == '#') && (NXT(1) == 'F') &&
2097 (NXT(2) == 'I') && (NXT(3) == 'X') &&
2098 (NXT(4) == 'E') && (NXT(5) == 'D')) {
2099 SKIP(6);
2100 val = XML_ATTRIBUTE_FIXED;
2101 if (!IS_BLANK(CUR)) {
2102 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002103 ctxt->sax->error(ctxt->userData, "Space required after '#FIXED'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002104 ctxt->wellFormed = 0;
2105 }
2106 SKIP_BLANKS;
2107 }
2108 ret = xmlParseAttValue(ctxt);
2109 if (ret == NULL) {
2110 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002111 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002112 "Attribute default value declaration error\n");
2113 ctxt->wellFormed = 0;
2114 } else
2115 *value = ret;
2116 return(val);
2117}
2118
2119/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00002120 * xmlParseNotationType:
2121 * @ctxt: an XML parser context
2122 *
2123 * parse an Notation attribute type.
2124 *
2125 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
2126 *
2127 * Note: the leading 'NOTATION' S part has already being parsed...
2128 *
2129 * Returns: the notation attribute tree built while parsing
2130 */
2131
2132xmlEnumerationPtr
2133xmlParseNotationType(xmlParserCtxtPtr ctxt) {
2134 CHAR *name;
2135 xmlEnumerationPtr ret = NULL, last = NULL, cur;
2136
2137 if (CUR != '(') {
2138 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002139 ctxt->sax->error(ctxt->userData, "'(' required to start 'NOTATION'\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00002140 ctxt->wellFormed = 0;
2141 return(NULL);
2142 }
2143 do {
2144 NEXT;
2145 SKIP_BLANKS;
2146 name = xmlParseName(ctxt);
2147 if (name == NULL) {
2148 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002149 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002150 "Name expected in NOTATION declaration\n");
2151 ctxt->wellFormed = 0;
2152 return(ret);
2153 }
2154 cur = xmlCreateEnumeration(name);
2155 free(name);
2156 if (cur == NULL) return(ret);
2157 if (last == NULL) ret = last = cur;
2158 else {
2159 last->next = cur;
2160 last = cur;
2161 }
2162 SKIP_BLANKS;
2163 } while (CUR == '|');
2164 if (CUR != ')') {
2165 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002166 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002167 "')' required to finish NOTATION declaration\n");
2168 ctxt->wellFormed = 0;
2169 return(ret);
2170 }
2171 NEXT;
2172 return(ret);
2173}
2174
2175/**
2176 * xmlParseEnumerationType:
2177 * @ctxt: an XML parser context
2178 *
2179 * parse an Enumeration attribute type.
2180 *
2181 * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
2182 *
2183 * Returns: the enumeration attribute tree built while parsing
2184 */
2185
2186xmlEnumerationPtr
2187xmlParseEnumerationType(xmlParserCtxtPtr ctxt) {
2188 CHAR *name;
2189 xmlEnumerationPtr ret = NULL, last = NULL, cur;
2190
2191 if (CUR != '(') {
2192 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002193 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002194 "'(' required to start ATTLIST enumeration\n");
2195 ctxt->wellFormed = 0;
2196 return(NULL);
2197 }
2198 do {
2199 NEXT;
2200 SKIP_BLANKS;
2201 name = xmlParseNmtoken(ctxt);
2202 if (name == NULL) {
2203 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002204 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002205 "NmToken expected in ATTLIST enumeration\n");
2206 ctxt->wellFormed = 0;
2207 return(ret);
2208 }
2209 cur = xmlCreateEnumeration(name);
2210 free(name);
2211 if (cur == NULL) return(ret);
2212 if (last == NULL) ret = last = cur;
2213 else {
2214 last->next = cur;
2215 last = cur;
2216 }
2217 SKIP_BLANKS;
2218 } while (CUR == '|');
2219 if (CUR != ')') {
2220 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002221 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002222 "')' required to finish ATTLIST enumeration\n");
2223 ctxt->wellFormed = 0;
2224 return(ret);
2225 }
2226 NEXT;
2227 return(ret);
2228}
2229
2230/**
Daniel Veillard11e00581998-10-24 18:27:49 +00002231 * xmlParseEnumeratedType:
2232 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00002233 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00002234 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00002235 * parse an Enumerated attribute type.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002236 *
2237 * [57] EnumeratedType ::= NotationType | Enumeration
2238 *
2239 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
2240 *
Daniel Veillard11e00581998-10-24 18:27:49 +00002241 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00002242 * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION
Daniel Veillard260a68f1998-08-13 03:39:55 +00002243 */
2244
Daniel Veillard1e346af1999-02-22 10:33:01 +00002245int
2246xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
2247 if ((CUR == 'N') && (NXT(1) == 'O') &&
2248 (NXT(2) == 'T') && (NXT(3) == 'A') &&
2249 (NXT(4) == 'T') && (NXT(5) == 'I') &&
2250 (NXT(6) == 'O') && (NXT(7) == 'N')) {
2251 SKIP(8);
2252 if (!IS_BLANK(CUR)) {
2253 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002254 ctxt->sax->error(ctxt->userData, "Space required after 'NOTATION'\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00002255 ctxt->wellFormed = 0;
2256 return(0);
2257 }
2258 SKIP_BLANKS;
2259 *tree = xmlParseNotationType(ctxt);
2260 if (*tree == NULL) return(0);
2261 return(XML_ATTRIBUTE_NOTATION);
2262 }
2263 *tree = xmlParseEnumerationType(ctxt);
2264 if (*tree == NULL) return(0);
2265 return(XML_ATTRIBUTE_ENUMERATION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002266}
2267
Daniel Veillard11e00581998-10-24 18:27:49 +00002268/**
2269 * xmlParseAttributeType:
2270 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00002271 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00002272 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002273 * parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00002274 *
2275 * [54] AttType ::= StringType | TokenizedType | EnumeratedType
2276 *
2277 * [55] StringType ::= 'CDATA'
2278 *
2279 * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
2280 * 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
Daniel Veillard11e00581998-10-24 18:27:49 +00002281 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00002282 * Returns the attribute type
Daniel Veillard260a68f1998-08-13 03:39:55 +00002283 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002284int
Daniel Veillard1e346af1999-02-22 10:33:01 +00002285xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002286 if ((CUR == 'C') && (NXT(1) == 'D') &&
2287 (NXT(2) == 'A') && (NXT(3) == 'T') &&
2288 (NXT(4) == 'A')) {
2289 SKIP(5);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002290 return(XML_ATTRIBUTE_CDATA);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002291 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
2292 (NXT(2) == 'R') && (NXT(3) == 'E') &&
2293 (NXT(4) == 'F')) {
2294 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002295 return(XML_ATTRIBUTE_IDREF);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002296 } else if ((CUR == 'I') && (NXT(1) == 'D')) {
2297 SKIP(2);
2298 return(XML_ATTRIBUTE_ID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002299 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
2300 (NXT(2) == 'R') && (NXT(3) == 'E') &&
2301 (NXT(4) == 'F') && (NXT(5) == 'S')) {
2302 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002303 return(XML_ATTRIBUTE_IDREFS);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002304 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
2305 (NXT(2) == 'T') && (NXT(3) == 'I') &&
2306 (NXT(4) == 'T') && (NXT(5) == 'Y')) {
2307 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002308 return(XML_ATTRIBUTE_ENTITY);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002309 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
2310 (NXT(2) == 'T') && (NXT(3) == 'I') &&
2311 (NXT(4) == 'T') && (NXT(5) == 'I') &&
2312 (NXT(6) == 'E') && (NXT(7) == 'S')) {
2313 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002314 return(XML_ATTRIBUTE_ENTITIES);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002315 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
2316 (NXT(2) == 'T') && (NXT(3) == 'O') &&
2317 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00002318 (NXT(6) == 'N') && (NXT(7) == 'S')) {
2319 SKIP(8);
2320 return(XML_ATTRIBUTE_NMTOKENS);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002321 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
2322 (NXT(2) == 'T') && (NXT(3) == 'O') &&
2323 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00002324 (NXT(6) == 'N')) {
2325 SKIP(7);
2326 return(XML_ATTRIBUTE_NMTOKEN);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002327 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002328 return(xmlParseEnumeratedType(ctxt, tree));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002329}
2330
Daniel Veillard11e00581998-10-24 18:27:49 +00002331/**
2332 * xmlParseAttributeListDecl:
2333 * @ctxt: an XML parser context
2334 *
2335 * : parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00002336 *
2337 * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
2338 *
2339 * [53] AttDef ::= S Name S AttType S DefaultDecl
Daniel Veillard11e00581998-10-24 18:27:49 +00002340 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002341 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002342void
2343xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002344 CHAR *elemName;
2345 CHAR *attrName;
Daniel Veillard1e346af1999-02-22 10:33:01 +00002346 xmlEnumerationPtr tree = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002347
Daniel Veillard260a68f1998-08-13 03:39:55 +00002348 if ((CUR == '<') && (NXT(1) == '!') &&
2349 (NXT(2) == 'A') && (NXT(3) == 'T') &&
2350 (NXT(4) == 'T') && (NXT(5) == 'L') &&
2351 (NXT(6) == 'I') && (NXT(7) == 'S') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002352 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002353 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002354 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002355 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002356 ctxt->sax->error(ctxt->userData, "Space required after '<!ATTLIST'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002357 ctxt->wellFormed = 0;
2358 }
2359 SKIP_BLANKS;
2360 elemName = xmlParseName(ctxt);
2361 if (elemName == NULL) {
2362 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002363 ctxt->sax->error(ctxt->userData, "ATTLIST: no name for Element\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002364 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002365 return;
2366 }
2367 SKIP_BLANKS;
2368 while (CUR != '>') {
2369 const CHAR *check = CUR_PTR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002370 int type;
2371 int def;
2372 CHAR *defaultValue = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002373
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002374 attrName = xmlParseName(ctxt);
2375 if (attrName == NULL) {
2376 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002377 ctxt->sax->error(ctxt->userData, "ATTLIST: no name for Attribute\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002378 ctxt->wellFormed = 0;
2379 break;
2380 }
2381 if (!IS_BLANK(CUR)) {
2382 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002383 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002384 "Space required after the attribute name\n");
2385 ctxt->wellFormed = 0;
2386 break;
2387 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002388 SKIP_BLANKS;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002389
Daniel Veillard1e346af1999-02-22 10:33:01 +00002390 type = xmlParseAttributeType(ctxt, &tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002391 if (type <= 0) break;
2392
2393 if (!IS_BLANK(CUR)) {
2394 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002395 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002396 "Space required after the attribute type\n");
2397 ctxt->wellFormed = 0;
2398 break;
2399 }
2400 SKIP_BLANKS;
2401
2402 def = xmlParseDefaultDecl(ctxt, &defaultValue);
2403 if (def <= 0) break;
2404
2405 if (CUR != '>') {
2406 if (!IS_BLANK(CUR)) {
2407 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002408 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002409 "Space required after the attribute default value\n");
2410 ctxt->wellFormed = 0;
2411 break;
2412 }
2413 SKIP_BLANKS;
2414 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002415 if (check == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002416 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002417 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002418 "xmlParseAttributeListDecl: detected internal error\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002419 break;
2420 }
Daniel Veillard517752b1999-04-05 12:20:10 +00002421 if ((ctxt->sax != NULL) && (ctxt->sax->attributeDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002422 ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002423 type, def, defaultValue, tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002424 if (attrName != NULL)
2425 free(attrName);
2426 if (defaultValue != NULL)
2427 free(defaultValue);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002428 }
2429 if (CUR == '>')
2430 NEXT;
2431
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002432 free(elemName);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002433 }
2434}
2435
Daniel Veillard11e00581998-10-24 18:27:49 +00002436/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002437 * xmlParseElementMixedContentDecl:
Daniel Veillard11e00581998-10-24 18:27:49 +00002438 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002439 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002440 * parse the declaration for a Mixed Element content
2441 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
Daniel Veillard260a68f1998-08-13 03:39:55 +00002442 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002443 * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
2444 * '(' S? '#PCDATA' S? ')'
2445 *
2446 * returns: the list of the xmlElementContentPtr describing the element choices
2447 */
2448xmlElementContentPtr
2449xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard1899e851999-02-01 12:18:54 +00002450 xmlElementContentPtr ret = NULL, cur = NULL, n;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002451 CHAR *elem = NULL;
2452
2453 if ((CUR == '#') && (NXT(1) == 'P') &&
2454 (NXT(2) == 'C') && (NXT(3) == 'D') &&
2455 (NXT(4) == 'A') && (NXT(5) == 'T') &&
2456 (NXT(6) == 'A')) {
2457 SKIP(7);
2458 SKIP_BLANKS;
Daniel Veillard3b9def11999-01-31 22:15:06 +00002459 if (CUR == ')') {
2460 NEXT;
2461 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
2462 return(ret);
2463 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002464 if ((CUR == '(') || (CUR == '|')) {
2465 ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
2466 if (ret == NULL) return(NULL);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002467 } /********** else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002468 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002469 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002470 "xmlParseElementMixedContentDecl : '|' or ')' expected\n");
2471 ctxt->wellFormed = 0;
2472 return(NULL);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002473 } **********/
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002474 while (CUR == '|') {
Daniel Veillard1899e851999-02-01 12:18:54 +00002475 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002476 if (elem == NULL) {
2477 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2478 if (ret == NULL) return(NULL);
2479 ret->c1 = cur;
Daniel Veillard1899e851999-02-01 12:18:54 +00002480 cur = ret;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002481 } else {
Daniel Veillard1899e851999-02-01 12:18:54 +00002482 n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2483 if (n == NULL) return(NULL);
2484 n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
2485 cur->c2 = n;
2486 cur = n;
Daniel Veillard1e346af1999-02-22 10:33:01 +00002487 free(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002488 }
2489 SKIP_BLANKS;
2490 elem = xmlParseName(ctxt);
2491 if (elem == NULL) {
2492 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002493 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002494 "xmlParseElementMixedContentDecl : Name expected\n");
2495 ctxt->wellFormed = 0;
2496 xmlFreeElementContent(cur);
2497 return(NULL);
2498 }
2499 SKIP_BLANKS;
2500 }
Daniel Veillard3b9def11999-01-31 22:15:06 +00002501 if ((CUR == ')') && (NXT(1) == '*')) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00002502 if (elem != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002503 cur->c2 = xmlNewElementContent(elem,
2504 XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002505 free(elem);
2506 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002507 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2508 SKIP(2);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002509 } else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00002510 if (elem != NULL) free(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002511 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002512 ctxt->sax->error(ctxt->userData,
Daniel Veillard3b9def11999-01-31 22:15:06 +00002513 "xmlParseElementMixedContentDecl : '|' or ')*' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002514 ctxt->wellFormed = 0;
2515 xmlFreeElementContent(ret);
2516 return(NULL);
2517 }
2518
2519 } else {
2520 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002521 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002522 "xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
2523 ctxt->wellFormed = 0;
2524 }
2525 return(ret);
2526}
2527
2528/**
2529 * xmlParseElementChildrenContentDecl:
2530 * @ctxt: an XML parser context
2531 *
2532 * parse the declaration for a Mixed Element content
2533 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
2534 *
2535 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002536 * [47] children ::= (choice | seq) ('?' | '*' | '+')?
2537 *
2538 * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
2539 *
2540 * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
2541 *
2542 * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
2543 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002544 * returns: the tree of xmlElementContentPtr describing the element
2545 * hierarchy.
2546 */
2547xmlElementContentPtr
2548xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt) {
2549 xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
2550 CHAR *elem;
2551 CHAR type = 0;
2552
2553 SKIP_BLANKS;
2554 if (CUR == '(') {
2555 /* Recurse on first child */
2556 NEXT;
2557 SKIP_BLANKS;
2558 cur = ret = xmlParseElementChildrenContentDecl(ctxt);
2559 SKIP_BLANKS;
2560 } else {
2561 elem = xmlParseName(ctxt);
2562 if (elem == NULL) {
2563 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002564 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002565 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
2566 ctxt->wellFormed = 0;
2567 return(NULL);
2568 }
2569 cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
2570 if (CUR == '?') {
2571 ret->ocur = XML_ELEMENT_CONTENT_OPT;
2572 NEXT;
2573 } else if (CUR == '*') {
2574 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2575 NEXT;
2576 } else if (CUR == '+') {
2577 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2578 NEXT;
2579 } else {
2580 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2581 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002582 free(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002583 }
2584 SKIP_BLANKS;
2585 while (CUR != ')') {
2586 /*
2587 * Each loop we parse one separator and one element.
2588 */
2589 if (CUR == ',') {
2590 if (type == 0) type = CUR;
2591
2592 /*
2593 * Detect "Name | Name , Name" error
2594 */
2595 else if (type != CUR) {
2596 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002597 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002598 "xmlParseElementChildrenContentDecl : '%c' expected\n",
2599 type);
2600 ctxt->wellFormed = 0;
2601 xmlFreeElementContent(ret);
2602 return(NULL);
2603 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002604 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002605
2606 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
2607 if (op == NULL) {
2608 xmlFreeElementContent(ret);
2609 return(NULL);
2610 }
2611 if (last == NULL) {
2612 op->c1 = ret;
2613 ret = cur = op;
2614 } else {
2615 cur->c2 = op;
2616 op->c1 = last;
2617 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00002618 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002619 }
2620 } else if (CUR == '|') {
2621 if (type == 0) type = CUR;
2622
2623 /*
2624 * Detect "Name , Name | Name" error
2625 */
2626 else if (type != CUR) {
2627 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002628 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002629 "xmlParseElementChildrenContentDecl : '%c' expected\n",
2630 type);
2631 ctxt->wellFormed = 0;
2632 xmlFreeElementContent(ret);
2633 return(NULL);
2634 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002635 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002636
2637 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2638 if (op == NULL) {
2639 xmlFreeElementContent(ret);
2640 return(NULL);
2641 }
2642 if (last == NULL) {
2643 op->c1 = ret;
2644 ret = cur = op;
2645 } else {
2646 cur->c2 = op;
2647 op->c1 = last;
2648 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00002649 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002650 }
2651 } else {
2652 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002653 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002654 "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
2655 ctxt->wellFormed = 0;
2656 xmlFreeElementContent(ret);
2657 return(NULL);
2658 }
2659 SKIP_BLANKS;
2660 if (CUR == '(') {
2661 /* Recurse on second child */
2662 NEXT;
2663 SKIP_BLANKS;
Daniel Veillard1899e851999-02-01 12:18:54 +00002664 last = xmlParseElementChildrenContentDecl(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002665 SKIP_BLANKS;
2666 } else {
2667 elem = xmlParseName(ctxt);
2668 if (elem == NULL) {
2669 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002670 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002671 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
2672 ctxt->wellFormed = 0;
2673 return(NULL);
2674 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002675 last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002676 free(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002677 }
2678 if (CUR == '?') {
2679 ret->ocur = XML_ELEMENT_CONTENT_OPT;
2680 NEXT;
2681 } else if (CUR == '*') {
2682 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2683 NEXT;
2684 } else if (CUR == '+') {
2685 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2686 NEXT;
2687 } else {
2688 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2689 }
2690 SKIP_BLANKS;
2691 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002692 if ((cur != NULL) && (last != NULL)) {
2693 cur->c2 = last;
2694 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002695 NEXT;
2696 if (CUR == '?') {
2697 ret->ocur = XML_ELEMENT_CONTENT_OPT;
2698 NEXT;
2699 } else if (CUR == '*') {
2700 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2701 NEXT;
2702 } else if (CUR == '+') {
2703 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2704 NEXT;
2705 } else {
2706 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2707 }
2708 return(ret);
2709}
2710
2711/**
2712 * xmlParseElementContentDecl:
2713 * @ctxt: an XML parser context
2714 * @name: the name of the element being defined.
2715 * @result: the Element Content pointer will be stored here if any
Daniel Veillard260a68f1998-08-13 03:39:55 +00002716 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002717 * parse the declaration for an Element content either Mixed or Children,
2718 * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
2719 *
2720 * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
Daniel Veillard11e00581998-10-24 18:27:49 +00002721 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002722 * returns: the type of element content XML_ELEMENT_TYPE_xxx
Daniel Veillard260a68f1998-08-13 03:39:55 +00002723 */
2724
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002725int
2726xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, CHAR *name,
2727 xmlElementContentPtr *result) {
2728
2729 xmlElementContentPtr tree = NULL;
2730 int res;
2731
2732 *result = NULL;
2733
2734 if (CUR != '(') {
2735 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002736 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002737 "xmlParseElementContentDecl : '(' expected\n");
2738 ctxt->wellFormed = 0;
2739 return(-1);
2740 }
2741 NEXT;
2742 SKIP_BLANKS;
2743 if ((CUR == '#') && (NXT(1) == 'P') &&
2744 (NXT(2) == 'C') && (NXT(3) == 'D') &&
2745 (NXT(4) == 'A') && (NXT(5) == 'T') &&
2746 (NXT(6) == 'A')) {
2747 tree = xmlParseElementMixedContentDecl(ctxt);
2748 res = XML_ELEMENT_TYPE_MIXED;
2749 } else {
2750 tree = xmlParseElementChildrenContentDecl(ctxt);
2751 res = XML_ELEMENT_TYPE_ELEMENT;
2752 }
2753 SKIP_BLANKS;
2754 /****************************
2755 if (CUR != ')') {
2756 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002757 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002758 "xmlParseElementContentDecl : ')' expected\n");
2759 ctxt->wellFormed = 0;
2760 return(-1);
2761 }
2762 ****************************/
Daniel Veillard3b9def11999-01-31 22:15:06 +00002763 *result = tree;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002764 return(res);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002765}
2766
Daniel Veillard11e00581998-10-24 18:27:49 +00002767/**
2768 * xmlParseElementDecl:
2769 * @ctxt: an XML parser context
2770 *
2771 * parse an Element declaration.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002772 *
2773 * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
2774 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002775 * TODO There is a check [ VC: Unique Element Type Declaration ]
Daniel Veillard1e346af1999-02-22 10:33:01 +00002776 *
2777 * Returns the type of the element, or -1 in case of error
Daniel Veillard260a68f1998-08-13 03:39:55 +00002778 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002779int
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002780xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002781 CHAR *name;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002782 int ret = -1;
2783 xmlElementContentPtr content = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002784
2785 if ((CUR == '<') && (NXT(1) == '!') &&
2786 (NXT(2) == 'E') && (NXT(3) == 'L') &&
2787 (NXT(4) == 'E') && (NXT(5) == 'M') &&
2788 (NXT(6) == 'E') && (NXT(7) == 'N') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002789 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002790 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002791 if (!IS_BLANK(CUR)) {
2792 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002793 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002794 "Space required after 'ELEMENT'\n");
2795 ctxt->wellFormed = 0;
2796 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002797 SKIP_BLANKS;
2798 name = xmlParseName(ctxt);
2799 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002800 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002801 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002802 "xmlParseElementDecl: no name for Element\n");
2803 ctxt->wellFormed = 0;
2804 return(-1);
2805 }
2806 if (!IS_BLANK(CUR)) {
2807 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002808 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002809 "Space required after the element name\n");
2810 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002811 }
2812 SKIP_BLANKS;
2813 if ((CUR == 'E') && (NXT(1) == 'M') &&
2814 (NXT(2) == 'P') && (NXT(3) == 'T') &&
2815 (NXT(4) == 'Y')) {
2816 SKIP(5);
2817 /*
2818 * Element must always be empty.
2819 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002820 ret = XML_ELEMENT_TYPE_EMPTY;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002821 } else if ((CUR == 'A') && (NXT(1) == 'N') &&
2822 (NXT(2) == 'Y')) {
2823 SKIP(3);
2824 /*
2825 * Element is a generic container.
2826 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002827 ret = XML_ELEMENT_TYPE_ANY;
2828 } else if (CUR == '(') {
2829 ret = xmlParseElementContentDecl(ctxt, name, &content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002830 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002831 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002832 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002833 "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
2834 ctxt->wellFormed = 0;
2835 if (name != NULL) free(name);
2836 return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002837 }
2838 SKIP_BLANKS;
2839 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002840 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002841 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002842 "xmlParseElementDecl: expected '>' at the end\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002843 ctxt->wellFormed = 0;
2844 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002845 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00002846 if ((ctxt->sax != NULL) && (ctxt->sax->elementDecl != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002847 ctxt->sax->elementDecl(ctxt->userData, name, ret,
2848 content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002849 }
Daniel Veillard14fff061999-06-22 21:49:07 +00002850 if (content != NULL) {
2851 xmlFreeElementContent(content);
2852 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002853 if (name != NULL) {
2854 free(name);
2855 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002856 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002857 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002858}
2859
Daniel Veillard11e00581998-10-24 18:27:49 +00002860/**
2861 * xmlParseMarkupDecl:
2862 * @ctxt: an XML parser context
2863 *
2864 * parse Markup declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002865 *
2866 * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
2867 * NotationDecl | PI | Comment
2868 *
2869 * TODO There is a check [ VC: Proper Declaration/PE Nesting ]
2870 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002871void
2872xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002873 xmlParseElementDecl(ctxt);
2874 xmlParseAttributeListDecl(ctxt);
2875 xmlParseEntityDecl(ctxt);
2876 xmlParseNotationDecl(ctxt);
2877 xmlParsePI(ctxt);
2878 xmlParseComment(ctxt, 0);
2879}
2880
Daniel Veillard11e00581998-10-24 18:27:49 +00002881/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00002882 * xmlParseTextDecl:
2883 * @ctxt: an XML parser context
2884 *
2885 * parse an XML declaration header for external entities
2886 *
2887 * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
2888 *
2889 * Returns the only valuable info for an external parsed entity, the encoding
2890 */
2891
2892CHAR *
2893xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
2894 CHAR *version;
2895 CHAR *encoding = NULL;
2896
2897 /*
2898 * We know that '<?xml' is here.
2899 */
2900 SKIP(5);
2901
2902 if (!IS_BLANK(CUR)) {
2903 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2904 ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
2905 ctxt->wellFormed = 0;
2906 }
2907 SKIP_BLANKS;
2908
2909 /*
2910 * We may have the VersionInfo here.
2911 */
2912 version = xmlParseVersionInfo(ctxt);
2913 /* TODO: we should actually inherit from the referencing doc if absent
2914 if (version == NULL)
2915 version = xmlCharStrdup(XML_DEFAULT_VERSION);
2916 ctxt->version = xmlStrdup(version);
2917 */
2918 if (version != NULL)
2919 free(version);
2920
2921 /*
2922 * We must have the encoding declaration
2923 */
2924 if (!IS_BLANK(CUR)) {
2925 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2926 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
2927 ctxt->wellFormed = 0;
2928 }
2929 encoding = xmlParseEncodingDecl(ctxt);
2930
2931 SKIP_BLANKS;
2932 if ((CUR == '?') && (NXT(1) == '>')) {
2933 SKIP(2);
2934 } else if (CUR == '>') {
2935 /* Deprecated old WD ... */
2936 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2937 ctxt->sax->error(ctxt->userData, "XML declaration must end-up with '?>'\n");
2938 ctxt->wellFormed = 0;
2939 NEXT;
2940 } else {
2941 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2942 ctxt->sax->error(ctxt->userData, "parsing XML declaration: '?>' expected\n");
2943 ctxt->wellFormed = 0;
2944 MOVETO_ENDTAG(CUR_PTR);
2945 NEXT;
2946 }
2947 return(encoding);
2948}
2949
2950/*
2951 * xmlParseConditionalSections
2952 * @ctxt: an XML parser context
2953 *
2954 * TODO : Conditionnal section are not yet supported !
2955 *
2956 * [61] conditionalSect ::= includeSect | ignoreSect
2957 * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
2958 * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
2959 * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
2960 * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
2961 */
2962
2963void
2964xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
2965 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
2966 ctxt->sax->warning(ctxt->userData,
2967 "XML conditional section not supported\n");
2968 /*
2969 * Skip up to the end of the conditionnal section.
2970 */
2971 while ((CUR != 0) && ((CUR != ']') || (NXT(1) != ']') || (NXT(2) != '>')))
2972 NEXT;
2973 if (CUR == 0) {
2974 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2975 ctxt->sax->error(ctxt->userData,
2976 "XML conditional section not closed\n");
2977 ctxt->wellFormed = 0;
2978 }
2979}
2980
2981/**
2982 * xmlParseExternalSubset
2983 * @ctxt: an XML parser context
2984 *
2985 * parse Markup declarations from an external subset
2986 *
2987 * [30] extSubset ::= textDecl? extSubsetDecl
2988 *
2989 * [31] extSubsetDecl ::= (markupdecl | conditionalSect | PEReference | S) *
2990 *
2991 * TODO There is a check [ VC: Proper Declaration/PE Nesting ]
2992 */
2993void
2994xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const CHAR *ExternalID,
2995 const CHAR *SystemID) {
2996 if ((CUR == '<') && (NXT(1) == '?') &&
2997 (NXT(2) == 'x') && (NXT(3) == 'm') &&
2998 (NXT(4) == 'l')) {
2999 xmlParseTextDecl(ctxt);
3000 }
3001 if (ctxt->myDoc == NULL) {
3002 ctxt->myDoc = xmlNewDoc("1.0");
3003 }
3004 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL))
3005 xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID);
3006
3007 while (((CUR == '<') && (NXT(1) == '?')) ||
3008 ((CUR == '<') && (NXT(1) == '!')) ||
3009 IS_BLANK(CUR)) {
3010 if ((CUR == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
3011 xmlParseConditionalSections(ctxt);
3012 } else if (IS_BLANK(CUR)) {
3013 NEXT;
3014 } else if (CUR == '%') {
3015 xmlParsePEReference(ctxt);
3016 } else
3017 xmlParseMarkupDecl(ctxt);
3018
3019 /*
3020 * Pop-up of finished entities.
3021 */
3022 while ((CUR == 0) && (ctxt->inputNr > 1))
3023 xmlPopInput(ctxt);
3024
3025 }
3026
3027 if (CUR != 0) {
3028 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3029 ctxt->sax->error(ctxt->userData,
3030 "Extra content at the end of the document\n");
3031 ctxt->wellFormed = 0;
3032 }
3033
3034}
3035
3036/**
Daniel Veillard11e00581998-10-24 18:27:49 +00003037 * xmlParseCharRef:
3038 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00003039 *
3040 * parse Reference declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00003041 *
3042 * [66] CharRef ::= '&#' [0-9]+ ';' |
3043 * '&#x' [0-9a-fA-F]+ ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00003044 *
Daniel Veillard011b63c1999-06-02 17:44:04 +00003045 * Returns the value parsed (as an int)
Daniel Veillard260a68f1998-08-13 03:39:55 +00003046 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00003047int
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003048xmlParseCharRef(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003049 int val = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003050
3051 if ((CUR == '&') && (NXT(1) == '#') &&
3052 (NXT(2) == 'x')) {
3053 SKIP(3);
3054 while (CUR != ';') {
3055 if ((CUR >= '0') && (CUR <= '9'))
3056 val = val * 16 + (CUR - '0');
3057 else if ((CUR >= 'a') && (CUR <= 'f'))
3058 val = val * 16 + (CUR - 'a') + 10;
3059 else if ((CUR >= 'A') && (CUR <= 'F'))
3060 val = val * 16 + (CUR - 'A') + 10;
3061 else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003062 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003063 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003064 "xmlParseCharRef: invalid hexadecimal value\n");
3065 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003066 val = 0;
3067 break;
3068 }
Daniel Veillard845664d1998-08-13 04:43:19 +00003069 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003070 }
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003071 if (CUR == ';')
Daniel Veillard260a68f1998-08-13 03:39:55 +00003072 NEXT;
3073 } else if ((CUR == '&') && (NXT(1) == '#')) {
3074 SKIP(2);
3075 while (CUR != ';') {
3076 if ((CUR >= '0') && (CUR <= '9'))
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003077 val = val * 10 + (CUR - '0');
Daniel Veillard260a68f1998-08-13 03:39:55 +00003078 else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003079 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003080 ctxt->sax->error(ctxt->userData,
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00003081 "xmlParseCharRef: invalid decimal value\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003082 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003083 val = 0;
3084 break;
3085 }
Daniel Veillard845664d1998-08-13 04:43:19 +00003086 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003087 }
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003088 if (CUR == ';')
Daniel Veillard260a68f1998-08-13 03:39:55 +00003089 NEXT;
3090 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003091 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003092 ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid value\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003093 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003094 }
3095 /*
3096 * Check the value IS_CHAR ...
3097 */
3098 if (IS_CHAR(val)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00003099 return(val);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003100 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003101 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003102 ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid CHAR value %d\n",
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00003103 val);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003104 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003105 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00003106 return(0);
3107}
3108
3109/**
3110 * xmlParseReference:
3111 * @ctxt: an XML parser context
3112 *
3113 * parse and handle entity references in content, depending on the SAX
3114 * interface, this may end-up in a call to character() if this is a
3115 * CharRef, a predefined entity, if there is no reference() callback.
3116 * or if the parser was asked to switch to that mode.
3117 *
3118 * [67] Reference ::= EntityRef | CharRef
3119 */
3120void
3121xmlParseReference(xmlParserCtxtPtr ctxt) {
3122 xmlEntityPtr ent;
3123 CHAR *val;
3124 if (CUR != '&') return;
3125
3126 if (NXT(1) == '#') {
3127 CHAR out[2];
3128 int val = xmlParseCharRef(ctxt);
3129 /* TODO: invalid for UTF-8 variable encoding !!! */
3130 out[0] = val;
3131 out[1] = 0;
3132 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
3133 ctxt->sax->characters(ctxt->userData, out, 1);
3134 } else {
3135 ent = xmlParseEntityRef(ctxt);
3136 if (ent == NULL) return;
3137 if ((ent->name != NULL) &&
3138 (ent->type != XML_INTERNAL_PREDEFINED_ENTITY) &&
3139 (ctxt->sax != NULL) && (ctxt->sax->reference != NULL) &&
3140 (ctxt->replaceEntities == 0)) {
3141
3142 /*
3143 * Create a node.
3144 */
3145 ctxt->sax->reference(ctxt->userData, ent->name);
3146 return;
3147 }
3148 val = ent->content;
3149 if (val == NULL) return;
3150 /*
3151 * inline the entity.
3152 */
3153 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
3154 ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val));
3155 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003156}
3157
Daniel Veillard11e00581998-10-24 18:27:49 +00003158/**
3159 * xmlParseEntityRef:
3160 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00003161 *
3162 * parse ENTITY references declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00003163 *
3164 * [68] EntityRef ::= '&' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00003165 *
Daniel Veillard011b63c1999-06-02 17:44:04 +00003166 * Returns the xmlEntityPtr if found, or NULL otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003167 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00003168xmlEntityPtr
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003169xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
Daniel Veillard14fff061999-06-22 21:49:07 +00003170 const CHAR *q; /* !!!!!!!!!!! Unused !!!!!!!!!! */
Daniel Veillard260a68f1998-08-13 03:39:55 +00003171 CHAR *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00003172 xmlEntityPtr ent = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003173
Daniel Veillardccb09631998-10-27 06:21:04 +00003174 q = CUR_PTR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003175 if (CUR == '&') {
3176 NEXT;
3177 name = xmlParseName(ctxt);
3178 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003179 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003180 ctxt->sax->error(ctxt->userData, "xmlParseEntityRef: no name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003181 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003182 } else {
3183 if (CUR == ';') {
3184 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003185 /*
Daniel Veillard011b63c1999-06-02 17:44:04 +00003186 * Ask first SAX for entity resolution, otherwise try the
3187 * predefined set.
3188 */
3189 if (ctxt->sax != NULL) {
3190 if (ctxt->sax->getEntity != NULL)
3191 ent = ctxt->sax->getEntity(ctxt->userData, name);
3192 if (ent == NULL)
3193 ent = xmlGetPredefinedEntity(name);
3194 }
3195
3196 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003197 * Well Formedness Constraint if:
3198 * - standalone
3199 * or
3200 * - no external subset and no external parameter entities
3201 * referenced
3202 * then
3203 * the entity referenced must have been declared
3204 *
Daniel Veillard517752b1999-04-05 12:20:10 +00003205 * TODO: to be double checked !!! This is wrong !
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003206 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00003207 if (ent == NULL) {
3208 if (ctxt->sax != NULL) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003209 if (((ctxt->sax->isStandalone != NULL) &&
Daniel Veillard011b63c1999-06-02 17:44:04 +00003210 ctxt->sax->isStandalone(ctxt->userData) == 1) ||
Daniel Veillard517752b1999-04-05 12:20:10 +00003211 (((ctxt->sax->hasInternalSubset == NULL) ||
Daniel Veillard27d88741999-05-29 11:51:49 +00003212 ctxt->sax->hasInternalSubset(ctxt->userData) == 0) &&
Daniel Veillard517752b1999-04-05 12:20:10 +00003213 ((ctxt->sax->hasExternalSubset == NULL) ||
Daniel Veillard27d88741999-05-29 11:51:49 +00003214 ctxt->sax->hasExternalSubset(ctxt->userData) == 0))) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00003215 if (ctxt->sax->error != NULL)
3216 ctxt->sax->error(ctxt->userData,
3217 "Entity '%s' not defined\n", name);
3218 ctxt->wellFormed = 0;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003219 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00003220 } else {
3221 fprintf(stderr, "Entity '%s' not defined\n", name);
3222 ctxt->wellFormed = 0;
3223 }
3224 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003225
3226 /*
3227 * Well Formedness Constraint :
3228 * The referenced entity must be a parsed entity.
3229 */
3230 if (ent != NULL) {
3231 switch (ent->type) {
3232 case XML_INTERNAL_PARAMETER_ENTITY:
3233 case XML_EXTERNAL_PARAMETER_ENTITY:
3234 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003235 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003236 "Attempt to reference the parameter entity '%s'\n", name);
3237 ctxt->wellFormed = 0;
3238 break;
3239
3240 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
3241 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003242 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003243 "Attempt to reference unparsed entity '%s'\n", name);
3244 ctxt->wellFormed = 0;
3245 break;
3246 }
3247 }
3248
3249 /*
Daniel Veillard011b63c1999-06-02 17:44:04 +00003250 * TODO: !!!
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003251 * Well Formedness Constraint :
3252 * The referenced entity must not lead to recursion !
3253 */
3254
Daniel Veillard260a68f1998-08-13 03:39:55 +00003255
Daniel Veillard011b63c1999-06-02 17:44:04 +00003256 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003257 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003258 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003259 "xmlParseEntityRef: expecting ';'\n");
3260 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003261 }
3262 free(name);
3263 }
3264 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00003265 return(ent);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003266}
3267
Daniel Veillard11e00581998-10-24 18:27:49 +00003268/**
3269 * xmlParsePEReference:
3270 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00003271 *
3272 * parse PEReference declarations
Daniel Veillard011b63c1999-06-02 17:44:04 +00003273 * The entity content is handled directly by pushing it's content as
3274 * a new input stream.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003275 *
3276 * [69] PEReference ::= '%' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00003277 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00003278 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00003279void
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003280xmlParsePEReference(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003281 CHAR *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00003282 xmlEntityPtr entity = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +00003283 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003284
3285 if (CUR == '%') {
3286 NEXT;
3287 name = xmlParseName(ctxt);
3288 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003289 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003290 ctxt->sax->error(ctxt->userData, "xmlParsePEReference: no name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003291 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003292 } else {
3293 if (CUR == ';') {
3294 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00003295 if ((ctxt->sax != NULL) && (ctxt->sax->getEntity != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00003296 entity = ctxt->sax->getEntity(ctxt->userData, name);
Daniel Veillard517752b1999-04-05 12:20:10 +00003297 /* TODO !!!! Must check that it's of the proper type !!! */
Daniel Veillard260a68f1998-08-13 03:39:55 +00003298 if (entity == NULL) {
Daniel Veillard42dc9b31998-11-09 01:17:21 +00003299 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003300 ctxt->sax->warning(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003301 "xmlParsePEReference: %%%s; not found\n", name);
Daniel Veillardccb09631998-10-27 06:21:04 +00003302 } else {
3303 input = xmlNewEntityInputStream(ctxt, entity);
3304 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003305 }
3306 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003307 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003308 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003309 "xmlParsePEReference: expecting ';'\n");
3310 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003311 }
3312 free(name);
3313 }
3314 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003315}
3316
Daniel Veillard11e00581998-10-24 18:27:49 +00003317/**
3318 * xmlParseDocTypeDecl :
3319 * @ctxt: an XML parser context
3320 *
3321 * parse a DOCTYPE declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003322 *
3323 * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
3324 * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
3325 */
3326
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003327void
3328xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003329 CHAR *name;
3330 CHAR *ExternalID = NULL;
3331 CHAR *URI = NULL;
3332
3333 /*
3334 * We know that '<!DOCTYPE' has been detected.
3335 */
3336 SKIP(9);
3337
3338 SKIP_BLANKS;
3339
3340 /*
3341 * Parse the DOCTYPE name.
3342 */
3343 name = xmlParseName(ctxt);
3344 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003345 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003346 ctxt->sax->error(ctxt->userData, "xmlParseDocTypeDecl : no DOCTYPE name !\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003347 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003348 }
3349
3350 SKIP_BLANKS;
3351
3352 /*
3353 * Check for SystemID and ExternalID
3354 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00003355 URI = xmlParseExternalID(ctxt, &ExternalID, 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003356 SKIP_BLANKS;
3357
Daniel Veillard011b63c1999-06-02 17:44:04 +00003358 /*
3359 * NOTE: the SAX callback may try to fetch the external subset
3360 * entity and fill it up !
3361 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003362 if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003363 ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003364
3365 /*
3366 * Is there any DTD definition ?
3367 */
3368 if (CUR == '[') {
3369 NEXT;
3370 /*
3371 * Parse the succession of Markup declarations and
3372 * PEReferences.
3373 * Subsequence (markupdecl | PEReference | S)*
3374 */
3375 while (CUR != ']') {
3376 const CHAR *check = CUR_PTR;
3377
3378 SKIP_BLANKS;
3379 xmlParseMarkupDecl(ctxt);
Daniel Veillardccb09631998-10-27 06:21:04 +00003380 xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003381
3382 if (CUR_PTR == check) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003383 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003384 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003385 "xmlParseDocTypeDecl: error detected in Markup declaration\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003386 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003387 break;
3388 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00003389
3390 /*
3391 * Pop-up of finished entities.
3392 */
3393 while ((CUR == 0) && (ctxt->inputNr > 1))
3394 xmlPopInput(ctxt);
3395
Daniel Veillard260a68f1998-08-13 03:39:55 +00003396 }
3397 if (CUR == ']') NEXT;
3398 }
3399
3400 /*
3401 * We should be at the end of the DOCTYPE declaration.
3402 */
3403 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003404 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003405 ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003406 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003407 /* We shouldn't try to resynchronize ... */
3408 }
3409 NEXT;
3410
3411 /*
3412 * Cleanup, since we don't use all those identifiers
3413 * TODO : the DOCTYPE if available should be stored !
3414 */
3415 if (URI != NULL) free(URI);
3416 if (ExternalID != NULL) free(ExternalID);
3417 if (name != NULL) free(name);
3418}
3419
Daniel Veillard11e00581998-10-24 18:27:49 +00003420/**
3421 * xmlParseAttribute:
3422 * @ctxt: an XML parser context
Daniel Veillard517752b1999-04-05 12:20:10 +00003423 * @value: a CHAR ** used to store the value of the attribute
Daniel Veillard11e00581998-10-24 18:27:49 +00003424 *
3425 * parse an attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00003426 *
3427 * [41] Attribute ::= Name Eq AttValue
3428 *
3429 * [25] Eq ::= S? '=' S?
3430 *
3431 * With namespace:
3432 *
3433 * [NS 11] Attribute ::= QName Eq AttValue
3434 *
3435 * Also the case QName == xmlns:??? is handled independently as a namespace
3436 * definition.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003437 *
Daniel Veillard517752b1999-04-05 12:20:10 +00003438 * Returns the attribute name, and the value in *value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003439 */
3440
Daniel Veillard517752b1999-04-05 12:20:10 +00003441CHAR *
3442xmlParseAttribute(xmlParserCtxtPtr ctxt, CHAR **value) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003443 CHAR *name, *val;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003444
Daniel Veillard517752b1999-04-05 12:20:10 +00003445 *value = NULL;
3446 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003447 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003448 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003449 ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003450 ctxt->wellFormed = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00003451 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003452 }
3453
3454 /*
3455 * read the value
3456 */
3457 SKIP_BLANKS;
3458 if (CUR == '=') {
3459 NEXT;
3460 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00003461 val = xmlParseAttValue(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003462 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003463 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003464 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003465 "Specification mandate value for attribute %s\n", name);
3466 ctxt->wellFormed = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00003467 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003468 }
3469
Daniel Veillard517752b1999-04-05 12:20:10 +00003470 *value = val;
3471 return(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003472}
3473
Daniel Veillard11e00581998-10-24 18:27:49 +00003474/**
3475 * xmlParseStartTag:
3476 * @ctxt: an XML parser context
3477 *
3478 * parse a start of tag either for rule element or
3479 * EmptyElement. In both case we don't parse the tag closing chars.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003480 *
3481 * [40] STag ::= '<' Name (S Attribute)* S? '>'
3482 *
3483 * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
3484 *
3485 * With namespace:
3486 *
3487 * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
3488 *
3489 * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
Daniel Veillard14fff061999-06-22 21:49:07 +00003490 *
3491 * Returns the element name parsed
Daniel Veillard260a68f1998-08-13 03:39:55 +00003492 */
3493
Daniel Veillard14fff061999-06-22 21:49:07 +00003494CHAR *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003495xmlParseStartTag(xmlParserCtxtPtr ctxt) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003496 CHAR *name;
3497 CHAR *attname;
3498 CHAR *attvalue;
3499 const CHAR **atts = NULL;
3500 int nbatts = 0;
3501 int maxatts = 0;
3502 int i;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003503
Daniel Veillard14fff061999-06-22 21:49:07 +00003504 if (CUR != '<') return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003505 NEXT;
3506
Daniel Veillard517752b1999-04-05 12:20:10 +00003507 name = xmlParseName(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003508 if (name == NULL) {
3509 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003510 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003511 "xmlParseStartTag: invalid element name\n");
3512 ctxt->wellFormed = 0;
Daniel Veillard14fff061999-06-22 21:49:07 +00003513 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003514 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003515
3516 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00003517 * Now parse the attributes, it ends up with the ending
3518 *
3519 * (S Attribute)* S?
3520 */
3521 SKIP_BLANKS;
3522 while ((IS_CHAR(CUR)) &&
3523 (CUR != '>') &&
3524 ((CUR != '/') || (NXT(1) != '>'))) {
3525 const CHAR *q = CUR_PTR;
3526
Daniel Veillard517752b1999-04-05 12:20:10 +00003527 attname = xmlParseAttribute(ctxt, &attvalue);
3528 if ((attname != NULL) && (attvalue != NULL)) {
3529 /*
3530 * Well formedness requires at most one declaration of an attribute
3531 */
3532 for (i = 0; i < nbatts;i += 2) {
3533 if (!xmlStrcmp(atts[i], attname)) {
3534 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003535 ctxt->sax->error(ctxt->userData, "Attribute %s redefined\n",
Daniel Veillard517752b1999-04-05 12:20:10 +00003536 name);
3537 ctxt->wellFormed = 0;
3538 free(attname);
3539 free(attvalue);
3540 break;
3541 }
3542 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003543
Daniel Veillard517752b1999-04-05 12:20:10 +00003544 /*
3545 * Add the pair to atts
3546 */
3547 if (atts == NULL) {
3548 maxatts = 10;
3549 atts = (const CHAR **) malloc(maxatts * sizeof(CHAR *));
3550 if (atts == NULL) {
3551 fprintf(stderr, "malloc of %d byte failed\n",
3552 maxatts * sizeof(CHAR *));
Daniel Veillard14fff061999-06-22 21:49:07 +00003553 return(NULL);
Daniel Veillard517752b1999-04-05 12:20:10 +00003554 }
3555 } else if (nbatts + 2 < maxatts) {
3556 maxatts *= 2;
3557 atts = (const CHAR **) realloc(atts, maxatts * sizeof(CHAR *));
3558 if (atts == NULL) {
3559 fprintf(stderr, "realloc of %d byte failed\n",
3560 maxatts * sizeof(CHAR *));
Daniel Veillard14fff061999-06-22 21:49:07 +00003561 return(NULL);
Daniel Veillard517752b1999-04-05 12:20:10 +00003562 }
3563 }
3564 atts[nbatts++] = attname;
3565 atts[nbatts++] = attvalue;
3566 atts[nbatts] = NULL;
3567 atts[nbatts + 1] = NULL;
3568 }
3569
3570 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003571 if (q == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003572 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003573 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003574 "xmlParseStartTag: problem parsing attributes\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003575 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003576 break;
3577 }
3578 }
3579
3580 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00003581 * SAX: Start of Element !
3582 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003583 if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003584 ctxt->sax->startElement(ctxt->userData, name, atts);
Daniel Veillard517752b1999-04-05 12:20:10 +00003585
Daniel Veillard517752b1999-04-05 12:20:10 +00003586 if (atts != NULL) {
3587 for (i = 0;i < nbatts;i++) free((CHAR *) atts[i]);
3588 free(atts);
3589 }
Daniel Veillard14fff061999-06-22 21:49:07 +00003590 return(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003591}
3592
Daniel Veillard11e00581998-10-24 18:27:49 +00003593/**
3594 * xmlParseEndTag:
3595 * @ctxt: an XML parser context
Daniel Veillard14fff061999-06-22 21:49:07 +00003596 * @tagname: the tag name as parsed in the opening tag.
Daniel Veillard11e00581998-10-24 18:27:49 +00003597 *
3598 * parse an end of tag
Daniel Veillard260a68f1998-08-13 03:39:55 +00003599 *
3600 * [42] ETag ::= '</' Name S? '>'
3601 *
3602 * With namespace
3603 *
Daniel Veillard517752b1999-04-05 12:20:10 +00003604 * [NS 9] ETag ::= '</' QName S? '>'
Daniel Veillard260a68f1998-08-13 03:39:55 +00003605 */
3606
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003607void
Daniel Veillard14fff061999-06-22 21:49:07 +00003608xmlParseEndTag(xmlParserCtxtPtr ctxt, CHAR *tagname) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003609 CHAR *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003610
3611 if ((CUR != '<') || (NXT(1) != '/')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003612 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003613 ctxt->sax->error(ctxt->userData, "xmlParseEndTag: '</' not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003614 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003615 return;
3616 }
3617 SKIP(2);
3618
Daniel Veillard517752b1999-04-05 12:20:10 +00003619 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003620
3621 /*
3622 * We should definitely be at the ending "S? '>'" part
3623 */
3624 SKIP_BLANKS;
3625 if ((!IS_CHAR(CUR)) || (CUR != '>')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003626 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003627 ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003628 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003629 } else
3630 NEXT;
3631
Daniel Veillard517752b1999-04-05 12:20:10 +00003632 /*
Daniel Veillard14fff061999-06-22 21:49:07 +00003633 * Well formedness constraints, opening and closing must match.
3634 */
3635 if (xmlStrcmp(name, tagname)) {
3636 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3637 ctxt->sax->error(ctxt->userData,
3638 "Opening and ending tag mismatch: %s and %s\n", tagname, name);
3639 ctxt->wellFormed = 0;
3640 }
3641
3642 /*
Daniel Veillard517752b1999-04-05 12:20:10 +00003643 * SAX: End of Tag
3644 */
3645 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003646 ctxt->sax->endElement(ctxt->userData, name);
Daniel Veillard517752b1999-04-05 12:20:10 +00003647
3648 if (name != NULL)
3649 free(name);
3650
Daniel Veillard260a68f1998-08-13 03:39:55 +00003651 return;
3652}
3653
Daniel Veillard11e00581998-10-24 18:27:49 +00003654/**
3655 * xmlParseCDSect:
3656 * @ctxt: an XML parser context
3657 *
3658 * Parse escaped pure raw content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003659 *
3660 * [18] CDSect ::= CDStart CData CDEnd
3661 *
3662 * [19] CDStart ::= '<![CDATA['
3663 *
3664 * [20] Data ::= (Char* - (Char* ']]>' Char*))
3665 *
3666 * [21] CDEnd ::= ']]>'
3667 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003668void
3669xmlParseCDSect(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003670 const CHAR *r, *s, *base;
3671
3672 if ((CUR == '<') && (NXT(1) == '!') &&
3673 (NXT(2) == '[') && (NXT(3) == 'C') &&
3674 (NXT(4) == 'D') && (NXT(5) == 'A') &&
3675 (NXT(6) == 'T') && (NXT(7) == 'A') &&
3676 (NXT(8) == '[')) {
3677 SKIP(9);
3678 } else
3679 return;
3680 base = CUR_PTR;
3681 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003682 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003683 ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003684 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003685 return;
3686 }
3687 r = NEXT;
3688 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003689 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003690 ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003691 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003692 return;
3693 }
3694 s = NEXT;
3695 while (IS_CHAR(CUR) &&
3696 ((*r != ']') || (*s != ']') || (CUR != '>'))) {
3697 r++;s++;NEXT;
3698 }
3699 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003700 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003701 ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003702 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003703 return;
3704 }
3705
3706 /*
3707 * Ok the segment [base CUR_PTR] is to be consumed as chars.
3708 */
3709 if (ctxt->sax != NULL) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003710 if (areBlanks(ctxt, base, CUR_PTR - base)) {
3711 if (ctxt->sax->ignorableWhitespace != NULL)
Daniel Veillard27d88741999-05-29 11:51:49 +00003712 ctxt->sax->ignorableWhitespace(ctxt->userData, base,
Daniel Veillard517752b1999-04-05 12:20:10 +00003713 (CUR_PTR - base) - 2);
3714 } else {
3715 if (ctxt->sax->characters != NULL)
Daniel Veillard27d88741999-05-29 11:51:49 +00003716 ctxt->sax->characters(ctxt->userData, base, (CUR_PTR - base) - 2);
Daniel Veillard517752b1999-04-05 12:20:10 +00003717 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003718 }
3719}
3720
Daniel Veillard11e00581998-10-24 18:27:49 +00003721/**
3722 * xmlParseContent:
3723 * @ctxt: an XML parser context
3724 *
3725 * Parse a content:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003726 *
3727 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
3728 */
3729
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003730void
3731xmlParseContent(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003732 while ((CUR != '<') || (NXT(1) != '/')) {
3733 const CHAR *test = CUR_PTR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003734
3735 /*
3736 * First case : a Processing Instruction.
3737 */
3738 if ((CUR == '<') && (NXT(1) == '?')) {
3739 xmlParsePI(ctxt);
3740 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003741
Daniel Veillard260a68f1998-08-13 03:39:55 +00003742 /*
3743 * Second case : a CDSection
3744 */
3745 else if ((CUR == '<') && (NXT(1) == '!') &&
3746 (NXT(2) == '[') && (NXT(3) == 'C') &&
3747 (NXT(4) == 'D') && (NXT(5) == 'A') &&
3748 (NXT(6) == 'T') && (NXT(7) == 'A') &&
3749 (NXT(8) == '[')) {
3750 xmlParseCDSect(ctxt);
3751 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003752
Daniel Veillard260a68f1998-08-13 03:39:55 +00003753 /*
3754 * Third case : a comment
3755 */
3756 else if ((CUR == '<') && (NXT(1) == '!') &&
3757 (NXT(2) == '-') && (NXT(3) == '-')) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003758 xmlParseComment(ctxt, 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003759 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003760
Daniel Veillard260a68f1998-08-13 03:39:55 +00003761 /*
3762 * Fourth case : a sub-element.
3763 */
3764 else if (CUR == '<') {
Daniel Veillard517752b1999-04-05 12:20:10 +00003765 xmlParseElement(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003766 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003767
Daniel Veillard260a68f1998-08-13 03:39:55 +00003768 /*
Daniel Veillardccb09631998-10-27 06:21:04 +00003769 * Fifth case : a reference. If if has not been resolved,
3770 * parsing returns it's Name, create the node
Daniel Veillard260a68f1998-08-13 03:39:55 +00003771 */
3772 else if (CUR == '&') {
Daniel Veillard011b63c1999-06-02 17:44:04 +00003773 xmlParseReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003774 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003775
Daniel Veillard260a68f1998-08-13 03:39:55 +00003776 /*
3777 * Last case, text. Note that References are handled directly.
3778 */
3779 else {
3780 xmlParseCharData(ctxt, 0);
3781 }
3782
3783 /*
3784 * Pop-up of finished entities.
3785 */
Daniel Veillardbc50b591999-03-01 12:28:53 +00003786 while ((CUR == 0) && (ctxt->inputNr > 1))
3787 xmlPopInput(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003788
3789 if (test == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003790 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003791 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003792 "detected an error in element content\n");
3793 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003794 break;
3795 }
3796 }
3797}
3798
Daniel Veillard11e00581998-10-24 18:27:49 +00003799/**
3800 * xmlParseElement:
3801 * @ctxt: an XML parser context
3802 *
3803 * parse an XML element, this is highly recursive
Daniel Veillard260a68f1998-08-13 03:39:55 +00003804 *
3805 * [39] element ::= EmptyElemTag | STag content ETag
3806 *
3807 * [41] Attribute ::= Name Eq AttValue
3808 */
3809
Daniel Veillard517752b1999-04-05 12:20:10 +00003810void
Daniel Veillard1e346af1999-02-22 10:33:01 +00003811xmlParseElement(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003812 const CHAR *openTag = CUR_PTR;
Daniel Veillard14fff061999-06-22 21:49:07 +00003813 CHAR *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003814 xmlParserNodeInfo node_info;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003815
3816 /* Capture start position */
3817 node_info.begin_pos = CUR_PTR - ctxt->input->base;
3818 node_info.begin_line = ctxt->input->line;
3819
Daniel Veillard14fff061999-06-22 21:49:07 +00003820 name = xmlParseStartTag(ctxt);
3821 if (name == NULL) {
3822 return;
3823 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003824
3825 /*
3826 * Check for an Empty Element.
3827 */
3828 if ((CUR == '/') && (NXT(1) == '>')) {
3829 SKIP(2);
Daniel Veillard517752b1999-04-05 12:20:10 +00003830 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard14fff061999-06-22 21:49:07 +00003831 ctxt->sax->endElement(ctxt->userData, name);
3832 free(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00003833 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003834 }
3835 if (CUR == '>') NEXT;
3836 else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003837 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003838 ctxt->sax->error(ctxt->userData, "Couldn't find end of Start Tag\n%.30s\n",
Daniel Veillard242590e1998-11-13 18:04:35 +00003839 openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003840 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003841
3842 /*
3843 * end of parsing of this node.
3844 */
3845 nodePop(ctxt);
Daniel Veillard14fff061999-06-22 21:49:07 +00003846 free(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00003847 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003848 }
3849
3850 /*
3851 * Parse the content of the element:
3852 */
3853 xmlParseContent(ctxt);
3854 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003855 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003856 ctxt->sax->error(ctxt->userData,
Daniel Veillard242590e1998-11-13 18:04:35 +00003857 "Premature end of data in tag %.30s\n", openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003858 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003859
3860 /*
3861 * end of parsing of this node.
3862 */
3863 nodePop(ctxt);
Daniel Veillard14fff061999-06-22 21:49:07 +00003864 free(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00003865 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003866 }
3867
3868 /*
3869 * parse the end of tag: '</' should be here.
3870 */
Daniel Veillard14fff061999-06-22 21:49:07 +00003871 xmlParseEndTag(ctxt, name);
3872 free(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003873}
3874
Daniel Veillard11e00581998-10-24 18:27:49 +00003875/**
3876 * xmlParseVersionNum:
3877 * @ctxt: an XML parser context
3878 *
3879 * parse the XML version value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003880 *
3881 * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
Daniel Veillard1e346af1999-02-22 10:33:01 +00003882 *
3883 * Returns the string giving the XML version number, or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003884 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003885CHAR *
3886xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003887 const CHAR *q = CUR_PTR;
3888 CHAR *ret;
3889
3890 while (IS_CHAR(CUR) &&
3891 (((CUR >= 'a') && (CUR <= 'z')) ||
3892 ((CUR >= 'A') && (CUR <= 'Z')) ||
3893 ((CUR >= '0') && (CUR <= '9')) ||
3894 (CUR == '_') || (CUR == '.') ||
3895 (CUR == ':') || (CUR == '-'))) NEXT;
3896 ret = xmlStrndup(q, CUR_PTR - q);
3897 return(ret);
3898}
3899
Daniel Veillard11e00581998-10-24 18:27:49 +00003900/**
3901 * xmlParseVersionInfo:
3902 * @ctxt: an XML parser context
3903 *
3904 * parse the XML version.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003905 *
3906 * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
3907 *
3908 * [25] Eq ::= S? '=' S?
Daniel Veillard11e00581998-10-24 18:27:49 +00003909 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003910 * Returns the version string, e.g. "1.0"
Daniel Veillard260a68f1998-08-13 03:39:55 +00003911 */
3912
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003913CHAR *
3914xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003915 CHAR *version = NULL;
3916 const CHAR *q;
3917
3918 if ((CUR == 'v') && (NXT(1) == 'e') &&
3919 (NXT(2) == 'r') && (NXT(3) == 's') &&
3920 (NXT(4) == 'i') && (NXT(5) == 'o') &&
3921 (NXT(6) == 'n')) {
3922 SKIP(7);
3923 SKIP_BLANKS;
3924 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003925 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003926 ctxt->sax->error(ctxt->userData, "xmlParseVersionInfo : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003927 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003928 return(NULL);
3929 }
3930 NEXT;
3931 SKIP_BLANKS;
3932 if (CUR == '"') {
3933 NEXT;
3934 q = CUR_PTR;
3935 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003936 if (CUR != '"') {
3937 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003938 ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003939 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003940 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003941 NEXT;
3942 } else if (CUR == '\''){
3943 NEXT;
3944 q = CUR_PTR;
3945 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003946 if (CUR != '\'') {
3947 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003948 ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003949 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003950 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003951 NEXT;
3952 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003953 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003954 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003955 "xmlParseVersionInfo : expected ' or \"\n");
3956 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003957 }
3958 }
3959 return(version);
3960}
3961
Daniel Veillard11e00581998-10-24 18:27:49 +00003962/**
3963 * xmlParseEncName:
3964 * @ctxt: an XML parser context
3965 *
3966 * parse the XML encoding name
Daniel Veillard260a68f1998-08-13 03:39:55 +00003967 *
3968 * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
Daniel Veillard11e00581998-10-24 18:27:49 +00003969 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003970 * Returns the encoding name value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003971 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003972CHAR *
3973xmlParseEncName(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003974 const CHAR *q = CUR_PTR;
3975 CHAR *ret = NULL;
3976
3977 if (((CUR >= 'a') && (CUR <= 'z')) ||
3978 ((CUR >= 'A') && (CUR <= 'Z'))) {
3979 NEXT;
3980 while (IS_CHAR(CUR) &&
3981 (((CUR >= 'a') && (CUR <= 'z')) ||
3982 ((CUR >= 'A') && (CUR <= 'Z')) ||
3983 ((CUR >= '0') && (CUR <= '9')) ||
3984 (CUR == '-'))) NEXT;
3985 ret = xmlStrndup(q, CUR_PTR - q);
3986 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003987 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003988 ctxt->sax->error(ctxt->userData, "Invalid XML encoding name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003989 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003990 }
3991 return(ret);
3992}
3993
Daniel Veillard11e00581998-10-24 18:27:49 +00003994/**
3995 * xmlParseEncodingDecl:
3996 * @ctxt: an XML parser context
3997 *
3998 * parse the XML encoding declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003999 *
4000 * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'")
Daniel Veillard11e00581998-10-24 18:27:49 +00004001 *
4002 * TODO: this should setup the conversion filters.
4003 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004004 * Returns the encoding value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00004005 */
4006
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004007CHAR *
4008xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004009 CHAR *encoding = NULL;
4010 const CHAR *q;
4011
4012 SKIP_BLANKS;
4013 if ((CUR == 'e') && (NXT(1) == 'n') &&
4014 (NXT(2) == 'c') && (NXT(3) == 'o') &&
4015 (NXT(4) == 'd') && (NXT(5) == 'i') &&
4016 (NXT(6) == 'n') && (NXT(7) == 'g')) {
4017 SKIP(8);
4018 SKIP_BLANKS;
4019 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004020 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004021 ctxt->sax->error(ctxt->userData, "xmlParseEncodingDecl : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004022 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004023 return(NULL);
4024 }
4025 NEXT;
4026 SKIP_BLANKS;
4027 if (CUR == '"') {
4028 NEXT;
4029 q = CUR_PTR;
4030 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004031 if (CUR != '"') {
4032 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004033 ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004034 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004035 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00004036 NEXT;
4037 } else if (CUR == '\''){
4038 NEXT;
4039 q = CUR_PTR;
4040 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004041 if (CUR != '\'') {
4042 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004043 ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004044 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004045 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00004046 NEXT;
4047 } else if (CUR == '"'){
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004048 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004049 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004050 "xmlParseEncodingDecl : expected ' or \"\n");
4051 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004052 }
4053 }
4054 return(encoding);
4055}
4056
Daniel Veillard11e00581998-10-24 18:27:49 +00004057/**
4058 * xmlParseSDDecl:
4059 * @ctxt: an XML parser context
4060 *
4061 * parse the XML standalone declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00004062 *
4063 * [32] SDDecl ::= S 'standalone' Eq
4064 * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00004065 *
4066 * Returns 1 if standalone, 0 otherwise
Daniel Veillard260a68f1998-08-13 03:39:55 +00004067 */
4068
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004069int
4070xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004071 int standalone = -1;
4072
4073 SKIP_BLANKS;
4074 if ((CUR == 's') && (NXT(1) == 't') &&
4075 (NXT(2) == 'a') && (NXT(3) == 'n') &&
4076 (NXT(4) == 'd') && (NXT(5) == 'a') &&
4077 (NXT(6) == 'l') && (NXT(7) == 'o') &&
4078 (NXT(8) == 'n') && (NXT(9) == 'e')) {
4079 SKIP(10);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004080 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004081 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004082 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004083 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004084 "XML standalone declaration : expected '='\n");
4085 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004086 return(standalone);
4087 }
4088 NEXT;
4089 SKIP_BLANKS;
4090 if (CUR == '\''){
4091 NEXT;
4092 if ((CUR == 'n') && (NXT(1) == 'o')) {
4093 standalone = 0;
4094 SKIP(2);
4095 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
4096 (NXT(2) == 's')) {
4097 standalone = 1;
4098 SKIP(3);
4099 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004100 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004101 ctxt->sax->error(ctxt->userData, "standalone accepts only 'yes' or 'no'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004102 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004103 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004104 if (CUR != '\'') {
4105 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004106 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004107 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004108 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00004109 NEXT;
4110 } else if (CUR == '"'){
4111 NEXT;
4112 if ((CUR == 'n') && (NXT(1) == 'o')) {
4113 standalone = 0;
4114 SKIP(2);
4115 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
4116 (NXT(2) == 's')) {
4117 standalone = 1;
4118 SKIP(3);
4119 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004120 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004121 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004122 "standalone accepts only 'yes' or 'no'\n");
4123 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004124 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004125 if (CUR != '"') {
4126 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004127 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004128 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004129 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00004130 NEXT;
4131 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004132 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004133 ctxt->sax->error(ctxt->userData, "Standalone value not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004134 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004135 }
4136 }
4137 return(standalone);
4138}
4139
Daniel Veillard11e00581998-10-24 18:27:49 +00004140/**
4141 * xmlParseXMLDecl:
4142 * @ctxt: an XML parser context
4143 *
4144 * parse an XML declaration header
Daniel Veillard260a68f1998-08-13 03:39:55 +00004145 *
4146 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
4147 */
4148
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004149void
4150xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004151 CHAR *version;
4152
4153 /*
4154 * We know that '<?xml' is here.
4155 */
4156 SKIP(5);
4157
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004158 if (!IS_BLANK(CUR)) {
4159 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004160 ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004161 ctxt->wellFormed = 0;
4162 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004163 SKIP_BLANKS;
4164
4165 /*
4166 * We should have the VersionInfo here.
4167 */
4168 version = xmlParseVersionInfo(ctxt);
4169 if (version == NULL)
4170 version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard517752b1999-04-05 12:20:10 +00004171 ctxt->version = xmlStrdup(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004172 free(version);
4173
4174 /*
4175 * We may have the encoding declaration
4176 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004177 if (!IS_BLANK(CUR)) {
4178 if ((CUR == '?') && (NXT(1) == '>')) {
4179 SKIP(2);
4180 return;
4181 }
4182 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004183 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004184 ctxt->wellFormed = 0;
4185 }
Daniel Veillard517752b1999-04-05 12:20:10 +00004186 ctxt->encoding = xmlParseEncodingDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004187
4188 /*
4189 * We may have the standalone status.
4190 */
Daniel Veillard517752b1999-04-05 12:20:10 +00004191 if ((ctxt->encoding != NULL) && (!IS_BLANK(CUR))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004192 if ((CUR == '?') && (NXT(1) == '>')) {
4193 SKIP(2);
4194 return;
4195 }
4196 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004197 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004198 ctxt->wellFormed = 0;
4199 }
4200 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00004201 ctxt->standalone = xmlParseSDDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004202
4203 SKIP_BLANKS;
4204 if ((CUR == '?') && (NXT(1) == '>')) {
4205 SKIP(2);
4206 } else if (CUR == '>') {
4207 /* Deprecated old WD ... */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004208 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004209 ctxt->sax->error(ctxt->userData, "XML declaration must end-up with '?>'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004210 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004211 NEXT;
4212 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004213 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004214 ctxt->sax->error(ctxt->userData, "parsing XML declaration: '?>' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004215 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004216 MOVETO_ENDTAG(CUR_PTR);
4217 NEXT;
4218 }
4219}
4220
Daniel Veillard11e00581998-10-24 18:27:49 +00004221/**
4222 * xmlParseMisc:
4223 * @ctxt: an XML parser context
4224 *
4225 * parse an XML Misc* optionnal field.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004226 *
4227 * [27] Misc ::= Comment | PI | S
4228 */
4229
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004230void
4231xmlParseMisc(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004232 while (((CUR == '<') && (NXT(1) == '?')) ||
4233 ((CUR == '<') && (NXT(1) == '!') &&
4234 (NXT(2) == '-') && (NXT(3) == '-')) ||
4235 IS_BLANK(CUR)) {
4236 if ((CUR == '<') && (NXT(1) == '?')) {
4237 xmlParsePI(ctxt);
4238 } else if (IS_BLANK(CUR)) {
4239 NEXT;
4240 } else
4241 xmlParseComment(ctxt, 0);
4242 }
4243}
4244
Daniel Veillard11e00581998-10-24 18:27:49 +00004245/**
4246 * xmlParseDocument :
4247 * @ctxt: an XML parser context
4248 *
4249 * parse an XML document (and build a tree if using the standard SAX
4250 * interface).
Daniel Veillard260a68f1998-08-13 03:39:55 +00004251 *
4252 * [1] document ::= prolog element Misc*
4253 *
4254 * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
Daniel Veillard11e00581998-10-24 18:27:49 +00004255 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004256 * Returns 0, -1 in case of error. the parser context is augmented
Daniel Veillard11e00581998-10-24 18:27:49 +00004257 * as a result of the parsing.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004258 */
4259
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004260int
4261xmlParseDocument(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004262 xmlDefaultSAXHandlerInit();
4263
4264 /*
4265 * SAX: beginning of the document processing.
4266 */
Daniel Veillard517752b1999-04-05 12:20:10 +00004267 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
Daniel Veillard27d88741999-05-29 11:51:49 +00004268 ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004269
4270 /*
4271 * We should check for encoding here and plug-in some
4272 * conversion code TODO !!!!
4273 */
4274
4275 /*
4276 * Wipe out everything which is before the first '<'
4277 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004278 if (IS_BLANK(CUR)) {
4279 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004280 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004281 "Extra spaces at the beginning of the document are not allowed\n");
4282 ctxt->wellFormed = 0;
4283 SKIP_BLANKS;
4284 }
4285
4286 if (CUR == 0) {
4287 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004288 ctxt->sax->error(ctxt->userData, "Document is empty\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004289 ctxt->wellFormed = 0;
4290 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004291
4292 /*
4293 * Check for the XMLDecl in the Prolog.
4294 */
4295 if ((CUR == '<') && (NXT(1) == '?') &&
4296 (NXT(2) == 'x') && (NXT(3) == 'm') &&
4297 (NXT(4) == 'l')) {
4298 xmlParseXMLDecl(ctxt);
4299 /* SKIP_EOL(cur); */
4300 SKIP_BLANKS;
4301 } else if ((CUR == '<') && (NXT(1) == '?') &&
4302 (NXT(2) == 'X') && (NXT(3) == 'M') &&
4303 (NXT(4) == 'L')) {
4304 /*
4305 * The first drafts were using <?XML and the final W3C REC
4306 * now use <?xml ...
4307 */
4308 xmlParseXMLDecl(ctxt);
4309 /* SKIP_EOL(cur); */
4310 SKIP_BLANKS;
4311 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00004312 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004313 }
Daniel Veillard517752b1999-04-05 12:20:10 +00004314 if ((ctxt->sax) && (ctxt->sax->startDocument))
Daniel Veillard27d88741999-05-29 11:51:49 +00004315 ctxt->sax->startDocument(ctxt->userData);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004316
4317 /*
4318 * The Misc part of the Prolog
4319 */
4320 xmlParseMisc(ctxt);
4321
4322 /*
4323 * Then possibly doc type declaration(s) and more Misc
4324 * (doctypedecl Misc*)?
4325 */
4326 if ((CUR == '<') && (NXT(1) == '!') &&
4327 (NXT(2) == 'D') && (NXT(3) == 'O') &&
4328 (NXT(4) == 'C') && (NXT(5) == 'T') &&
4329 (NXT(6) == 'Y') && (NXT(7) == 'P') &&
4330 (NXT(8) == 'E')) {
4331 xmlParseDocTypeDecl(ctxt);
4332 xmlParseMisc(ctxt);
4333 }
4334
4335 /*
4336 * Time to start parsing the tree itself
4337 */
Daniel Veillard517752b1999-04-05 12:20:10 +00004338 xmlParseElement(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004339
4340 /*
4341 * The Misc part at the end
4342 */
4343 xmlParseMisc(ctxt);
4344
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004345 if (CUR != 0) {
4346 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004347 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004348 "Extra content at the end of the document\n");
4349 ctxt->wellFormed = 0;
4350 }
4351
Daniel Veillard260a68f1998-08-13 03:39:55 +00004352 /*
4353 * SAX: end of the document processing.
4354 */
Daniel Veillard517752b1999-04-05 12:20:10 +00004355 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004356 ctxt->sax->endDocument(ctxt->userData);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004357 if (! ctxt->wellFormed) return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004358 return(0);
4359}
4360
Daniel Veillard11e00581998-10-24 18:27:49 +00004361/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00004362 * xmlCreateFileParserCtxt :
4363 * @cur: a pointer to an array of CHAR
4364 *
4365 * Create a parser context for an XML in-memory document.
4366 *
4367 * Returns the new parser context or NULL
4368 */
4369xmlParserCtxtPtr
4370xmlCreateDocParserCtxt(CHAR *cur) {
4371 xmlParserCtxtPtr ctxt;
4372 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00004373 xmlCharEncoding enc;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004374
4375 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4376 if (ctxt == NULL) {
4377 perror("malloc");
4378 return(NULL);
4379 }
4380 xmlInitParserCtxt(ctxt);
4381 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4382 if (input == NULL) {
4383 perror("malloc");
4384 free(ctxt);
4385 return(NULL);
4386 }
4387
Daniel Veillard27d88741999-05-29 11:51:49 +00004388 /*
4389 * plug some encoding conversion routines here. !!!
4390 */
4391 enc = xmlDetectCharEncoding(cur);
4392 xmlSwitchEncoding(ctxt, enc);
4393
Daniel Veillardd692aa41999-02-28 21:54:31 +00004394 input->filename = NULL;
4395 input->line = 1;
4396 input->col = 1;
4397 input->base = cur;
4398 input->cur = cur;
4399 input->free = NULL;
4400
4401 inputPush(ctxt, input);
4402 return(ctxt);
4403}
4404
4405/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004406 * xmlSAXParseDoc :
4407 * @sax: the SAX handler block
Daniel Veillard11e00581998-10-24 18:27:49 +00004408 * @cur: a pointer to an array of CHAR
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004409 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4410 * documents
Daniel Veillard11e00581998-10-24 18:27:49 +00004411 *
4412 * parse an XML in-memory document and build a tree.
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004413 * It use the given SAX function block to handle the parsing callback.
4414 * If sax is NULL, fallback to the default DOM tree building routines.
Daniel Veillard11e00581998-10-24 18:27:49 +00004415 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004416 * Returns the resulting document tree
Daniel Veillard260a68f1998-08-13 03:39:55 +00004417 */
4418
Daniel Veillard1e346af1999-02-22 10:33:01 +00004419xmlDocPtr
4420xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur, int recovery) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004421 xmlDocPtr ret;
4422 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004423
4424 if (cur == NULL) return(NULL);
4425
Daniel Veillardd692aa41999-02-28 21:54:31 +00004426
4427 ctxt = xmlCreateDocParserCtxt(cur);
4428 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00004429 if (sax != NULL) {
4430 ctxt->sax = sax;
4431 ctxt->userData = NULL;
4432 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004433
4434 xmlParseDocument(ctxt);
Daniel Veillard517752b1999-04-05 12:20:10 +00004435 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004436 else {
4437 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00004438 xmlFreeDoc(ctxt->myDoc);
4439 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004440 }
Daniel Veillard97fea181999-06-26 23:07:37 +00004441 if (sax != NULL)
4442 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004443 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004444
4445 return(ret);
4446}
4447
Daniel Veillard11e00581998-10-24 18:27:49 +00004448/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004449 * xmlParseDoc :
4450 * @cur: a pointer to an array of CHAR
4451 *
4452 * parse an XML in-memory document and build a tree.
4453 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004454 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004455 */
4456
Daniel Veillard1e346af1999-02-22 10:33:01 +00004457xmlDocPtr
4458xmlParseDoc(CHAR *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004459 return(xmlSAXParseDoc(NULL, cur, 0));
4460}
4461
4462/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004463 * xmlSAXParseDTD :
4464 * @sax: the SAX handler block
4465 * @ExternalID: a NAME* containing the External ID of the DTD
4466 * @SystemID: a NAME* containing the URL to the DTD
4467 *
4468 * Load and parse an external subset.
4469 *
4470 * Returns the resulting xmlDtdPtr or NULL in case of error.
4471 */
4472
4473xmlDtdPtr
4474xmlSAXParseDTD(xmlSAXHandlerPtr sax, const CHAR *ExternalID,
4475 const CHAR *SystemID) {
4476 xmlDtdPtr ret = NULL;
4477 xmlParserCtxtPtr ctxt;
Daniel Veillard14fff061999-06-22 21:49:07 +00004478 xmlParserInputPtr input = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004479 xmlCharEncoding enc;
4480
4481 if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL);
4482
4483 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4484 if (ctxt == NULL) {
4485 perror("malloc");
4486 return(NULL);
4487 }
4488 xmlInitParserCtxt(ctxt);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004489
4490 /*
4491 * Set-up the SAX context
4492 */
4493 if (ctxt == NULL) return(NULL);
4494 if (sax != NULL) {
4495 ctxt->sax = sax;
4496 ctxt->userData = NULL;
4497 }
4498
4499 /*
4500 * Ask the Entity resolver to load the damn thing
4501 */
4502
4503 if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
4504 input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, SystemID);
4505 if (input == NULL) {
Daniel Veillard97fea181999-06-26 23:07:37 +00004506 if (sax != NULL) ctxt->sax = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004507 xmlFreeParserCtxt(ctxt);
4508 return(NULL);
4509 }
4510
4511 /*
4512 * plug some encoding conversion routines here. !!!
4513 */
4514 xmlPushInput(ctxt, input);
4515 enc = xmlDetectCharEncoding(ctxt->input->cur);
4516 xmlSwitchEncoding(ctxt, enc);
4517
4518 input->filename = xmlStrdup(SystemID);
4519 input->line = 1;
4520 input->col = 1;
4521 input->base = ctxt->input->cur;
4522 input->cur = ctxt->input->cur;
4523 input->free = NULL;
4524
4525 /*
4526 * let's parse that entity knowing it's an external subset.
4527 */
4528 xmlParseExternalSubset(ctxt, ExternalID, SystemID);
4529
4530 if (ctxt->myDoc != NULL) {
4531 if (ctxt->wellFormed) {
4532 ret = ctxt->myDoc->intSubset;
4533 ctxt->myDoc->intSubset = NULL;
4534 } else {
4535 ret = NULL;
4536 }
4537 xmlFreeDoc(ctxt->myDoc);
4538 ctxt->myDoc = NULL;
4539 }
Daniel Veillard97fea181999-06-26 23:07:37 +00004540 if (sax != NULL) ctxt->sax = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004541 xmlFreeParserCtxt(ctxt);
4542
4543 return(ret);
4544}
4545
4546/**
4547 * xmlParseDTD :
4548 * @ExternalID: a NAME* containing the External ID of the DTD
4549 * @SystemID: a NAME* containing the URL to the DTD
4550 *
4551 * Load and parse an external subset.
4552 *
4553 * Returns the resulting xmlDtdPtr or NULL in case of error.
4554 */
4555
4556xmlDtdPtr
4557xmlParseDTD(const CHAR *ExternalID, const CHAR *SystemID) {
4558 return(xmlSAXParseDTD(NULL, ExternalID, SystemID));
4559}
4560
4561/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004562 * xmlRecoverDoc :
4563 * @cur: a pointer to an array of CHAR
4564 *
4565 * parse an XML in-memory document and build a tree.
4566 * In the case the document is not Well Formed, a tree is built anyway
4567 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004568 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004569 */
4570
Daniel Veillard1e346af1999-02-22 10:33:01 +00004571xmlDocPtr
4572xmlRecoverDoc(CHAR *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004573 return(xmlSAXParseDoc(NULL, cur, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004574}
4575
4576/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00004577 * xmlCreateFileParserCtxt :
Daniel Veillard11e00581998-10-24 18:27:49 +00004578 * @filename: the filename
4579 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004580 * Create a parser context for a file content.
4581 * Automatic support for ZLIB/Compress compressed document is provided
4582 * by default if found at compile-time.
Daniel Veillard11e00581998-10-24 18:27:49 +00004583 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004584 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00004585 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00004586xmlParserCtxtPtr
4587xmlCreateFileParserCtxt(const char *filename)
4588{
4589 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004590#ifdef HAVE_ZLIB_H
4591 gzFile input;
4592#else
4593 int input;
4594#endif
4595 int res;
Daniel Veillard27271681998-10-30 06:39:40 +00004596 int len;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004597 struct stat buf;
4598 char *buffer;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004599 xmlParserInputPtr inputStream;
Daniel Veillard27d88741999-05-29 11:51:49 +00004600 xmlCharEncoding enc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004601
4602 res = stat(filename, &buf);
4603 if (res < 0) return(NULL);
4604
4605#ifdef HAVE_ZLIB_H
Daniel Veillard27271681998-10-30 06:39:40 +00004606 len = (buf.st_size * 8) + 1000;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004607retry_bigger:
Daniel Veillard27271681998-10-30 06:39:40 +00004608 buffer = malloc(len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004609#else
Daniel Veillard27271681998-10-30 06:39:40 +00004610 len = buf.st_size + 100;
4611 buffer = malloc(len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004612#endif
4613 if (buffer == NULL) {
4614 perror("malloc");
4615 return(NULL);
4616 }
4617
Daniel Veillard27271681998-10-30 06:39:40 +00004618 memset(buffer, 0, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004619#ifdef HAVE_ZLIB_H
4620 input = gzopen (filename, "r");
4621 if (input == NULL) {
4622 fprintf (stderr, "Cannot read file %s :\n", filename);
4623 perror ("gzopen failed");
4624 return(NULL);
4625 }
4626#else
Daniel Veillard64068b31999-03-24 20:42:16 +00004627#ifdef WIN32
4628 input = _open (filename, O_RDONLY | _O_BINARY);
4629#else
Daniel Veillard260a68f1998-08-13 03:39:55 +00004630 input = open (filename, O_RDONLY);
Daniel Veillard64068b31999-03-24 20:42:16 +00004631#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004632 if (input < 0) {
4633 fprintf (stderr, "Cannot read file %s :\n", filename);
4634 perror ("open failed");
4635 return(NULL);
4636 }
4637#endif
4638#ifdef HAVE_ZLIB_H
Daniel Veillard27271681998-10-30 06:39:40 +00004639 res = gzread(input, buffer, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004640#else
4641 res = read(input, buffer, buf.st_size);
4642#endif
4643 if (res < 0) {
4644 fprintf (stderr, "Cannot read file %s :\n", filename);
4645#ifdef HAVE_ZLIB_H
4646 perror ("gzread failed");
4647#else
4648 perror ("read failed");
4649#endif
4650 return(NULL);
4651 }
4652#ifdef HAVE_ZLIB_H
4653 gzclose(input);
Daniel Veillard27271681998-10-30 06:39:40 +00004654 if (res >= len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004655 free(buffer);
Daniel Veillard27271681998-10-30 06:39:40 +00004656 len *= 2;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004657 goto retry_bigger;
4658 }
4659 buf.st_size = res;
4660#else
4661 close(input);
4662#endif
4663
Daniel Veillard14fff061999-06-22 21:49:07 +00004664 buffer[res] = '\0';
Daniel Veillard260a68f1998-08-13 03:39:55 +00004665
4666 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4667 if (ctxt == NULL) {
4668 perror("malloc");
4669 return(NULL);
4670 }
4671 xmlInitParserCtxt(ctxt);
4672 inputStream = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4673 if (inputStream == NULL) {
4674 perror("malloc");
4675 free(ctxt);
4676 return(NULL);
4677 }
4678
4679 inputStream->filename = strdup(filename);
4680 inputStream->line = 1;
4681 inputStream->col = 1;
4682
4683 /*
Daniel Veillard27d88741999-05-29 11:51:49 +00004684 * plug some encoding conversion routines here. !!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00004685 */
Daniel Veillard27d88741999-05-29 11:51:49 +00004686 enc = xmlDetectCharEncoding(buffer);
4687 xmlSwitchEncoding(ctxt, enc);
4688
Daniel Veillard260a68f1998-08-13 03:39:55 +00004689 inputStream->base = buffer;
4690 inputStream->cur = buffer;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004691 inputStream->free = (xmlParserInputDeallocate) free;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004692
4693 inputPush(ctxt, inputStream);
Daniel Veillardd692aa41999-02-28 21:54:31 +00004694 return(ctxt);
4695}
4696
4697/**
4698 * xmlSAXParseFile :
4699 * @sax: the SAX handler block
4700 * @filename: the filename
4701 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4702 * documents
4703 *
4704 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4705 * compressed document is provided by default if found at compile-time.
4706 * It use the given SAX function block to handle the parsing callback.
4707 * If sax is NULL, fallback to the default DOM tree building routines.
4708 *
4709 * Returns the resulting document tree
4710 */
4711
Daniel Veillard011b63c1999-06-02 17:44:04 +00004712xmlDocPtr
4713xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
Daniel Veillardd692aa41999-02-28 21:54:31 +00004714 int recovery) {
4715 xmlDocPtr ret;
4716 xmlParserCtxtPtr ctxt;
4717
4718 ctxt = xmlCreateFileParserCtxt(filename);
4719 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00004720 if (sax != NULL) {
4721 ctxt->sax = sax;
4722 ctxt->userData = NULL;
4723 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004724
4725 xmlParseDocument(ctxt);
4726
Daniel Veillard517752b1999-04-05 12:20:10 +00004727 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004728 else {
4729 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00004730 xmlFreeDoc(ctxt->myDoc);
4731 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004732 }
Daniel Veillard97fea181999-06-26 23:07:37 +00004733 if (sax != NULL)
4734 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004735 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004736
4737 return(ret);
4738}
4739
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004740/**
4741 * xmlParseFile :
4742 * @filename: the filename
4743 *
4744 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4745 * compressed document is provided by default if found at compile-time.
4746 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004747 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004748 */
4749
Daniel Veillard011b63c1999-06-02 17:44:04 +00004750xmlDocPtr
4751xmlParseFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004752 return(xmlSAXParseFile(NULL, filename, 0));
4753}
4754
4755/**
4756 * xmlRecoverFile :
4757 * @filename: the filename
4758 *
4759 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4760 * compressed document is provided by default if found at compile-time.
4761 * In the case the document is not Well Formed, a tree is built anyway
4762 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004763 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004764 */
4765
Daniel Veillard011b63c1999-06-02 17:44:04 +00004766xmlDocPtr
4767xmlRecoverFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004768 return(xmlSAXParseFile(NULL, filename, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004769}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004770
Daniel Veillard11e00581998-10-24 18:27:49 +00004771/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004772 * xmlSubstituteEntitiesDefault :
4773 * @val: int 0 or 1
4774 *
4775 * Set and return the previous value for default entity support.
4776 * Initially the parser always keep entity references instead of substituting
4777 * entity values in the output. This function has to be used to change the
4778 * default parser behaviour
4779 * SAX::subtituteEntities() has to be used for changing that on a file by
4780 * file basis.
4781 *
4782 * Returns the last value for 0 for no substitution, 1 for substitution.
4783 */
4784
4785int
4786xmlSubstituteEntitiesDefault(int val) {
4787 int old = xmlSubstituteEntitiesDefaultValue;
4788
4789 xmlSubstituteEntitiesDefaultValue = val;
4790 return(old);
4791}
4792
4793/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00004794 * xmlCreateMemoryParserCtxt :
Daniel Veillard1e346af1999-02-22 10:33:01 +00004795 * @buffer: an pointer to a char array
Daniel Veillard11e00581998-10-24 18:27:49 +00004796 * @size: the siwe of the array
4797 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004798 * Create a parser context for an XML in-memory document.
Daniel Veillard11e00581998-10-24 18:27:49 +00004799 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004800 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00004801 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00004802xmlParserCtxtPtr
4803xmlCreateMemoryParserCtxt(char *buffer, int size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004804 xmlParserCtxtPtr ctxt;
4805 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00004806 xmlCharEncoding enc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004807
4808 buffer[size - 1] = '\0';
4809
4810 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4811 if (ctxt == NULL) {
4812 perror("malloc");
4813 return(NULL);
4814 }
4815 xmlInitParserCtxt(ctxt);
4816 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4817 if (input == NULL) {
4818 perror("malloc");
Daniel Veillardccb09631998-10-27 06:21:04 +00004819 free(ctxt->nodeTab);
4820 free(ctxt->inputTab);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004821 free(ctxt);
4822 return(NULL);
4823 }
4824
4825 input->filename = NULL;
4826 input->line = 1;
4827 input->col = 1;
4828
4829 /*
Daniel Veillard27d88741999-05-29 11:51:49 +00004830 * plug some encoding conversion routines here. !!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00004831 */
Daniel Veillard27d88741999-05-29 11:51:49 +00004832 enc = xmlDetectCharEncoding(buffer);
4833 xmlSwitchEncoding(ctxt, enc);
4834
Daniel Veillard260a68f1998-08-13 03:39:55 +00004835 input->base = buffer;
4836 input->cur = buffer;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004837 input->free = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004838
4839 inputPush(ctxt, input);
Daniel Veillardd692aa41999-02-28 21:54:31 +00004840 return(ctxt);
4841}
4842
4843/**
4844 * xmlSAXParseMemory :
4845 * @sax: the SAX handler block
4846 * @buffer: an pointer to a char array
4847 * @size: the siwe of the array
4848 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4849 * documents
4850 *
4851 * parse an XML in-memory block and use the given SAX function block
4852 * to handle the parsing callback. If sax is NULL, fallback to the default
4853 * DOM tree building routines.
4854 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004855 * Returns the resulting document tree
4856 */
4857xmlDocPtr
4858xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
4859 xmlDocPtr ret;
4860 xmlParserCtxtPtr ctxt;
4861
4862 ctxt = xmlCreateMemoryParserCtxt(buffer, size);
4863 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00004864 if (sax != NULL) {
4865 ctxt->sax = sax;
4866 ctxt->userData = NULL;
4867 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004868
4869 xmlParseDocument(ctxt);
4870
Daniel Veillard517752b1999-04-05 12:20:10 +00004871 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004872 else {
4873 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00004874 xmlFreeDoc(ctxt->myDoc);
4875 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004876 }
Daniel Veillard97fea181999-06-26 23:07:37 +00004877 if (sax != NULL)
4878 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004879 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004880
4881 return(ret);
4882}
4883
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004884/**
4885 * xmlParseMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00004886 * @buffer: an pointer to a char array
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004887 * @size: the size of the array
4888 *
4889 * parse an XML in-memory block and build a tree.
4890 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004891 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004892 */
4893
4894xmlDocPtr xmlParseMemory(char *buffer, int size) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004895 return(xmlSAXParseMemory(NULL, buffer, size, 0));
4896}
4897
4898/**
4899 * xmlRecoverMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00004900 * @buffer: an pointer to a char array
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004901 * @size: the size of the array
4902 *
4903 * parse an XML in-memory block and build a tree.
4904 * In the case the document is not Well Formed, a tree is built anyway
4905 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004906 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004907 */
4908
4909xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
4910 return(xmlSAXParseMemory(NULL, buffer, size, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004911}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004912
Daniel Veillard11e00581998-10-24 18:27:49 +00004913/**
4914 * xmlInitParserCtxt:
4915 * @ctxt: an XML parser context
4916 *
4917 * Initialize a parser context
4918 */
4919
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004920void
4921xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004922{
Daniel Veillard97fea181999-06-26 23:07:37 +00004923 xmlSAXHandler *sax;
4924
4925 sax = (xmlSAXHandler *) malloc(sizeof(xmlSAXHandler));
4926 if (sax == NULL) {
4927 fprintf(stderr, "xmlInitParserCtxt: out of memory\n");
4928 }
4929
Daniel Veillardd692aa41999-02-28 21:54:31 +00004930 /* Allocate the Input stack */
4931 ctxt->inputTab = (xmlParserInputPtr *) malloc(5 * sizeof(xmlParserInputPtr));
4932 ctxt->inputNr = 0;
4933 ctxt->inputMax = 5;
4934 ctxt->input = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00004935 ctxt->version = NULL;
4936 ctxt->encoding = NULL;
4937 ctxt->standalone = -1;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004938
Daniel Veillardd692aa41999-02-28 21:54:31 +00004939 /* Allocate the Node stack */
4940 ctxt->nodeTab = (xmlNodePtr *) malloc(10 * sizeof(xmlNodePtr));
4941 ctxt->nodeNr = 0;
4942 ctxt->nodeMax = 10;
4943 ctxt->node = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004944
Daniel Veillard97fea181999-06-26 23:07:37 +00004945 if (sax == NULL) ctxt->sax = &xmlDefaultSAXHandler;
4946 else {
4947 ctxt->sax = sax;
4948 memcpy(sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
4949 }
Daniel Veillard27d88741999-05-29 11:51:49 +00004950 ctxt->userData = ctxt;
Daniel Veillard517752b1999-04-05 12:20:10 +00004951 ctxt->myDoc = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004952 ctxt->wellFormed = 1;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004953 ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004954 ctxt->record_info = 0;
4955 xmlInitNodeInfoSeq(&ctxt->node_seq);
4956}
4957
4958/**
4959 * xmlFreeParserCtxt:
4960 * @ctxt: an XML parser context
4961 *
4962 * Free all the memory used by a parser context. However the parsed
Daniel Veillard517752b1999-04-05 12:20:10 +00004963 * document in ctxt->myDoc is not freed.
Daniel Veillardd692aa41999-02-28 21:54:31 +00004964 */
4965
4966void
4967xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
4968{
4969 xmlParserInputPtr input;
4970
4971 if (ctxt == NULL) return;
4972
4973 while ((input = inputPop(ctxt)) != NULL) {
4974 xmlFreeInputStream(input);
4975 }
4976
4977 if (ctxt->nodeTab != NULL) free(ctxt->nodeTab);
4978 if (ctxt->inputTab != NULL) free(ctxt->inputTab);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004979 if (ctxt->version != NULL) free((char *) ctxt->version);
Daniel Veillard97fea181999-06-26 23:07:37 +00004980 if ((ctxt->sax != NULL) && (ctxt->sax != &xmlDefaultSAXHandler))
4981 free(ctxt->sax);
Daniel Veillardd692aa41999-02-28 21:54:31 +00004982 free(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004983}
4984
Daniel Veillard11e00581998-10-24 18:27:49 +00004985/**
4986 * xmlClearParserCtxt:
4987 * @ctxt: an XML parser context
4988 *
4989 * Clear (release owned resources) and reinitialize a parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +00004990 */
Daniel Veillard11e00581998-10-24 18:27:49 +00004991
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004992void
4993xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004994{
4995 xmlClearNodeInfoSeq(&ctxt->node_seq);
4996 xmlInitParserCtxt(ctxt);
4997}
4998
4999
Daniel Veillard11e00581998-10-24 18:27:49 +00005000/**
5001 * xmlSetupParserForBuffer:
5002 * @ctxt: an XML parser context
5003 * @buffer: a CHAR * buffer
5004 * @filename: a file name
5005 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00005006 * Setup the parser context to parse a new buffer; Clears any prior
5007 * contents from the parser context. The buffer parameter must not be
5008 * NULL, but the filename parameter can be
5009 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005010void
5011xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const CHAR* buffer,
Daniel Veillard260a68f1998-08-13 03:39:55 +00005012 const char* filename)
5013{
5014 xmlParserInputPtr input;
5015
5016 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
5017 if (input == NULL) {
5018 perror("malloc");
5019 free(ctxt);
5020 exit(1);
5021 }
5022
5023 xmlClearParserCtxt(ctxt);
5024 if (input->filename != NULL)
5025 input->filename = strdup(filename);
5026 else
5027 input->filename = NULL;
5028 input->line = 1;
5029 input->col = 1;
5030 input->base = buffer;
5031 input->cur = buffer;
5032
5033 inputPush(ctxt, input);
5034}
5035
5036
Daniel Veillard11e00581998-10-24 18:27:49 +00005037/**
5038 * xmlParserFindNodeInfo:
5039 * @ctxt: an XML parser context
5040 * @node: an XML node within the tree
5041 *
5042 * Find the parser node info struct for a given node
5043 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005044 * Returns an xmlParserNodeInfo block pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00005045 */
5046const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
5047 const xmlNode* node)
5048{
5049 unsigned long pos;
5050
5051 /* Find position where node should be at */
5052 pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
5053 if ( ctx->node_seq.buffer[pos].node == node )
5054 return &ctx->node_seq.buffer[pos];
5055 else
5056 return NULL;
5057}
5058
5059
Daniel Veillard11e00581998-10-24 18:27:49 +00005060/**
5061 * xmlInitNodeInfoSeq :
5062 * @seq: a node info sequence pointer
5063 *
5064 * -- Initialize (set to initial state) node info sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00005065 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005066void
5067xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00005068{
5069 seq->length = 0;
5070 seq->maximum = 0;
5071 seq->buffer = NULL;
5072}
5073
Daniel Veillard11e00581998-10-24 18:27:49 +00005074/**
5075 * xmlClearNodeInfoSeq :
5076 * @seq: a node info sequence pointer
5077 *
5078 * -- Clear (release memory and reinitialize) node
Daniel Veillard260a68f1998-08-13 03:39:55 +00005079 * info sequence
5080 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005081void
5082xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00005083{
5084 if ( seq->buffer != NULL )
5085 free(seq->buffer);
5086 xmlInitNodeInfoSeq(seq);
5087}
5088
5089
Daniel Veillard11e00581998-10-24 18:27:49 +00005090/**
5091 * xmlParserFindNodeInfoIndex:
5092 * @seq: a node info sequence pointer
5093 * @node: an XML node pointer
5094 *
5095 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00005096 * xmlParserFindNodeInfoIndex : Find the index that the info record for
5097 * the given node is or should be at in a sorted sequence
Daniel Veillard1164e751999-02-16 16:29:17 +00005098 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005099 * Returns a long indicating the position of the record
Daniel Veillard260a68f1998-08-13 03:39:55 +00005100 */
5101unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
5102 const xmlNode* node)
5103{
5104 unsigned long upper, lower, middle;
5105 int found = 0;
5106
5107 /* Do a binary search for the key */
5108 lower = 1;
5109 upper = seq->length;
5110 middle = 0;
5111 while ( lower <= upper && !found) {
5112 middle = lower + (upper - lower) / 2;
5113 if ( node == seq->buffer[middle - 1].node )
5114 found = 1;
5115 else if ( node < seq->buffer[middle - 1].node )
5116 upper = middle - 1;
5117 else
5118 lower = middle + 1;
5119 }
5120
5121 /* Return position */
5122 if ( middle == 0 || seq->buffer[middle - 1].node < node )
5123 return middle;
5124 else
5125 return middle - 1;
5126}
5127
5128
Daniel Veillard11e00581998-10-24 18:27:49 +00005129/**
5130 * xmlParserAddNodeInfo:
5131 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00005132 * @info: a node info sequence pointer
Daniel Veillard11e00581998-10-24 18:27:49 +00005133 *
5134 * Insert node info record into the sorted sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00005135 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005136void
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005137xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
Daniel Veillard1e346af1999-02-22 10:33:01 +00005138 const xmlParserNodeInfo* info)
Daniel Veillard260a68f1998-08-13 03:39:55 +00005139{
5140 unsigned long pos;
5141 static unsigned int block_size = 5;
5142
5143 /* Find pos and check to see if node is already in the sequence */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005144 pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
5145 if ( pos < ctxt->node_seq.length
5146 && ctxt->node_seq.buffer[pos].node == info->node ) {
5147 ctxt->node_seq.buffer[pos] = *info;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005148 }
5149
5150 /* Otherwise, we need to add new node to buffer */
5151 else {
5152 /* Expand buffer by 5 if needed */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005153 if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005154 xmlParserNodeInfo* tmp_buffer;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005155 unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
5156 *(ctxt->node_seq.maximum + block_size));
Daniel Veillard260a68f1998-08-13 03:39:55 +00005157
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005158 if ( ctxt->node_seq.buffer == NULL )
Daniel Veillard260a68f1998-08-13 03:39:55 +00005159 tmp_buffer = (xmlParserNodeInfo*)malloc(byte_size);
5160 else
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005161 tmp_buffer = (xmlParserNodeInfo*)realloc(ctxt->node_seq.buffer, byte_size);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005162
5163 if ( tmp_buffer == NULL ) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005164 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005165 ctxt->sax->error(ctxt->userData, "Out of memory\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00005166 return;
5167 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005168 ctxt->node_seq.buffer = tmp_buffer;
5169 ctxt->node_seq.maximum += block_size;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005170 }
5171
5172 /* If position is not at end, move elements out of the way */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005173 if ( pos != ctxt->node_seq.length ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005174 unsigned long i;
5175
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005176 for ( i = ctxt->node_seq.length; i > pos; i-- )
5177 ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
Daniel Veillard260a68f1998-08-13 03:39:55 +00005178 }
5179
5180 /* Copy element and increase length */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005181 ctxt->node_seq.buffer[pos] = *info;
5182 ctxt->node_seq.length++;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005183 }
5184}
Daniel Veillard011b63c1999-06-02 17:44:04 +00005185
5186