blob: 659af3fcd785b1c1f466c7bca3bda56556133a4a [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
Daniel Veillard7f7d1111999-09-22 09:46:25 +000013#include "config.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000014#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000015
Daniel Veillard260a68f1998-08-13 03:39:55 +000016#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000017#include <string.h> /* for memset() only */
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
Seth Alvese7f12e61998-10-01 20:51:15 +000022#include <stdlib.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000023#endif
24#ifdef HAVE_SYS_STAT_H
Daniel Veillard260a68f1998-08-13 03:39:55 +000025#include <sys/stat.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000026#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +000027#ifdef HAVE_FCNTL_H
28#include <fcntl.h>
29#endif
30#ifdef HAVE_UNISTD_H
31#include <unistd.h>
32#endif
33#ifdef HAVE_ZLIB_H
34#include <zlib.h>
35#endif
36
Daniel Veillard6454aec1999-09-02 22:04:43 +000037#include "xmlmemory.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000038#include "tree.h"
39#include "parser.h"
40#include "entities.h"
Daniel Veillard27d88741999-05-29 11:51:49 +000041#include "encoding.h"
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000042#include "valid.h"
Daniel Veillard1e346af1999-02-22 10:33:01 +000043#include "parserInternals.h"
Daniel Veillarde2d034d1999-07-27 19:52:06 +000044#include "xmlIO.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000045#include "xml-error.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000046
Daniel Veillard14fff061999-06-22 21:49:07 +000047const char *xmlParserVersion = LIBXML_VERSION;
48
Daniel Veillarde2d034d1999-07-27 19:52:06 +000049
50/************************************************************************
51 * *
52 * Input handling functions for progressive parsing *
53 * *
54 ************************************************************************/
55
56/* #define DEBUG_INPUT */
57
Daniel Veillardb05deb71999-08-10 19:04:08 +000058#define INPUT_CHUNK 250
59/* we need to keep enough input to show errors in context */
60#define LINE_LEN 80
Daniel Veillarde2d034d1999-07-27 19:52:06 +000061
62#ifdef DEBUG_INPUT
63#define CHECK_BUFFER(in) check_buffer(in)
Daniel Veillarde2d034d1999-07-27 19:52:06 +000064
65void check_buffer(xmlParserInputPtr in) {
66 if (in->base != in->buf->buffer->content) {
67 fprintf(stderr, "xmlParserInput: base mismatch problem\n");
68 }
69 if (in->cur < in->base) {
70 fprintf(stderr, "xmlParserInput: cur < base problem\n");
71 }
72 if (in->cur > in->base + in->buf->buffer->use) {
73 fprintf(stderr, "xmlParserInput: cur > base + use problem\n");
74 }
75 fprintf(stderr,"buffer %x : content %x, cur %d, use %d, size %d\n",
76 (int) in, (int) in->buf->buffer->content, in->cur - in->base,
77 in->buf->buffer->use, in->buf->buffer->size);
78}
79
Daniel Veillardb05deb71999-08-10 19:04:08 +000080#else
81#define CHECK_BUFFER(in)
82#endif
83
Daniel Veillarde2d034d1999-07-27 19:52:06 +000084
85/**
86 * xmlParserInputRead:
87 * @in: an XML parser input
88 * @len: an indicative size for the lookahead
89 *
90 * This function refresh the input for the parser. It doesn't try to
91 * preserve pointers to the input buffer, and discard already read data
92 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +000093 * Returns the number of xmlChars read, or -1 in case of error, 0 indicate the
Daniel Veillarde2d034d1999-07-27 19:52:06 +000094 * end of this entity
95 */
96int
97xmlParserInputRead(xmlParserInputPtr in, int len) {
98 int ret;
99 int used;
100 int index;
101
102#ifdef DEBUG_INPUT
103 fprintf(stderr, "Read\n");
104#endif
105 if (in->buf == NULL) return(-1);
106 if (in->base == NULL) return(-1);
107 if (in->cur == NULL) return(-1);
108 if (in->buf->buffer == NULL) return(-1);
109
110 CHECK_BUFFER(in);
111
112 used = in->cur - in->buf->buffer->content;
113 ret = xmlBufferShrink(in->buf->buffer, used);
114 if (ret > 0) {
115 in->cur -= ret;
116 in->consumed += ret;
117 }
118 ret = xmlParserInputBufferRead(in->buf, len);
119 if (in->base != in->buf->buffer->content) {
120 /*
121 * the buffer has been realloced
122 */
123 index = in->cur - in->base;
124 in->base = in->buf->buffer->content;
125 in->cur = &in->buf->buffer->content[index];
126 }
127
128 CHECK_BUFFER(in);
129
130 return(ret);
131}
132
133/**
134 * xmlParserInputGrow:
135 * @in: an XML parser input
136 * @len: an indicative size for the lookahead
137 *
138 * This function increase the input for the parser. It tries to
139 * preserve pointers to the input buffer, and keep already read data
140 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000141 * Returns the number of xmlChars read, or -1 in case of error, 0 indicate the
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000142 * end of this entity
143 */
144int
145xmlParserInputGrow(xmlParserInputPtr in, int len) {
146 int ret;
147 int index;
148
149#ifdef DEBUG_INPUT
150 fprintf(stderr, "Grow\n");
151#endif
152 if (in->buf == NULL) return(-1);
153 if (in->base == NULL) return(-1);
154 if (in->cur == NULL) return(-1);
155 if (in->buf->buffer == NULL) return(-1);
156
157 CHECK_BUFFER(in);
158
159 index = in->cur - in->base;
160 if (in->buf->buffer->use > index + INPUT_CHUNK) {
161
162 CHECK_BUFFER(in);
163
164 return(0);
165 }
166 ret = xmlParserInputBufferGrow(in->buf, len);
167 if (in->base != in->buf->buffer->content) {
168 /*
169 * the buffer has been realloced
170 */
171 index = in->cur - in->base;
172 in->base = in->buf->buffer->content;
173 in->cur = &in->buf->buffer->content[index];
174 }
175
176 CHECK_BUFFER(in);
177
178 return(ret);
179}
180
181/**
182 * xmlParserInputShrink:
183 * @in: an XML parser input
184 *
185 * This function removes used input for the parser.
186 */
187void
188xmlParserInputShrink(xmlParserInputPtr in) {
189 int used;
190 int ret;
191 int index;
192
193#ifdef DEBUG_INPUT
194 fprintf(stderr, "Shrink\n");
195#endif
196 if (in->buf == NULL) return;
197 if (in->base == NULL) return;
198 if (in->cur == NULL) return;
199 if (in->buf->buffer == NULL) return;
200
201 CHECK_BUFFER(in);
202
203 used = in->cur - in->buf->buffer->content;
204 if (used > INPUT_CHUNK) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000205 ret = xmlBufferShrink(in->buf->buffer, used - LINE_LEN);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000206 if (ret > 0) {
207 in->cur -= ret;
208 in->consumed += ret;
209 }
210 }
211
212 CHECK_BUFFER(in);
213
214 if (in->buf->buffer->use > INPUT_CHUNK) {
215 return;
216 }
217 xmlParserInputBufferRead(in->buf, 2 * INPUT_CHUNK);
218 if (in->base != in->buf->buffer->content) {
219 /*
220 * the buffer has been realloced
221 */
222 index = in->cur - in->base;
223 in->base = in->buf->buffer->content;
224 in->cur = &in->buf->buffer->content[index];
225 }
226
227 CHECK_BUFFER(in);
228}
229
Daniel Veillard260a68f1998-08-13 03:39:55 +0000230/************************************************************************
231 * *
232 * Parser stacks related functions and macros *
233 * *
234 ************************************************************************/
Daniel Veillard011b63c1999-06-02 17:44:04 +0000235
236int xmlSubstituteEntitiesDefaultValue = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000237int xmlDoValidityCheckingDefaultValue = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000238
Daniel Veillard260a68f1998-08-13 03:39:55 +0000239/*
240 * Generic function for accessing stacks in the Parser Context
241 */
242
243#define PUSH_AND_POP(type, name) \
Daniel Veillard517752b1999-04-05 12:20:10 +0000244extern int name##Push(xmlParserCtxtPtr ctxt, type value) { \
Daniel Veillard260a68f1998-08-13 03:39:55 +0000245 if (ctxt->name##Nr >= ctxt->name##Max) { \
246 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000247 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard260a68f1998-08-13 03:39:55 +0000248 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
249 if (ctxt->name##Tab == NULL) { \
250 fprintf(stderr, "realloc failed !\n"); \
251 exit(1); \
252 } \
253 } \
254 ctxt->name##Tab[ctxt->name##Nr] = value; \
255 ctxt->name = value; \
256 return(ctxt->name##Nr++); \
257} \
Daniel Veillard517752b1999-04-05 12:20:10 +0000258extern type name##Pop(xmlParserCtxtPtr ctxt) { \
Daniel Veillardd692aa41999-02-28 21:54:31 +0000259 type ret; \
Daniel Veillard260a68f1998-08-13 03:39:55 +0000260 if (ctxt->name##Nr <= 0) return(0); \
261 ctxt->name##Nr--; \
Daniel Veillardccb09631998-10-27 06:21:04 +0000262 if (ctxt->name##Nr > 0) \
263 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
264 else \
265 ctxt->name = NULL; \
Daniel Veillardd692aa41999-02-28 21:54:31 +0000266 ret = ctxt->name##Tab[ctxt->name##Nr]; \
267 ctxt->name##Tab[ctxt->name##Nr] = 0; \
268 return(ret); \
Daniel Veillard260a68f1998-08-13 03:39:55 +0000269} \
270
271PUSH_AND_POP(xmlParserInputPtr, input)
272PUSH_AND_POP(xmlNodePtr, node)
273
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000274/*
275 * Macros for accessing the content. Those should be used only by the parser,
276 * and not exported.
277 *
278 * Dirty macros, i.e. one need to make assumption on the context to use them
279 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000280 * CUR_PTR return the current pointer to the xmlChar to be parsed.
281 * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000282 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
283 * in UNICODE mode. This should be used internally by the parser
284 * only to compare to ASCII values otherwise it would break when
285 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000286 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000287 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000288 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000289 * strings within the parser.
290 *
Daniel Veillard011b63c1999-06-02 17:44:04 +0000291 * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000292 *
293 * CURRENT Returns the current char value, with the full decoding of
294 * UTF-8 if we are using this mode. It returns an int.
295 * NEXT Skip to the next character, this does the proper decoding
296 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillard011b63c1999-06-02 17:44:04 +0000297 * COPY(to) copy one char to *to, increment CUR_PTR and to accordingly
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000298 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000299
Daniel Veillardb05deb71999-08-10 19:04:08 +0000300#define CUR (ctxt->token ? ctxt->token : (*ctxt->input->cur))
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000301#define SKIP(val) ctxt->input->cur += (val)
302#define NXT(val) ctxt->input->cur[(val)]
303#define CUR_PTR ctxt->input->cur
Daniel Veillardb05deb71999-08-10 19:04:08 +0000304#define SHRINK xmlParserInputShrink(ctxt->input); \
305 if ((*ctxt->input->cur == 0) && \
306 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \
307 xmlPopInput(ctxt)
308
309#define GROW xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \
310 if ((*ctxt->input->cur == 0) && \
311 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \
312 xmlPopInput(ctxt)
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000313
314#define SKIP_BLANKS \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000315 do { \
316 while (IS_BLANK(CUR)) NEXT; \
317 if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \
318 if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt); \
319 } while (IS_BLANK(CUR));
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000320
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000321#define CURRENT (*ctxt->input->cur)
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000322#define NEXT { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000323 if (ctxt->token != 0) ctxt->token = 0; \
324 else { \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000325 if ((*ctxt->input->cur == 0) && \
326 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) { \
327 xmlPopInput(ctxt); \
328 } else { \
329 if (*(ctxt->input->cur) == '\n') { \
330 ctxt->input->line++; ctxt->input->col = 1; \
331 } else ctxt->input->col++; \
332 ctxt->input->cur++; \
333 if (*ctxt->input->cur == 0) \
334 xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000335 } \
336 if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \
337 if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt); \
338}}
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000339
Daniel Veillard260a68f1998-08-13 03:39:55 +0000340
Daniel Veillardb05deb71999-08-10 19:04:08 +0000341/************************************************************************
342 * *
343 * Commodity functions to handle entities processing *
344 * *
345 ************************************************************************/
Daniel Veillard260a68f1998-08-13 03:39:55 +0000346
Daniel Veillard11e00581998-10-24 18:27:49 +0000347/**
348 * xmlPopInput:
349 * @ctxt: an XML parser context
350 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000351 * xmlPopInput: the current input pointed by ctxt->input came to an end
352 * pop it and return the next char.
353 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000354 * Returns the current xmlChar in the parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +0000355 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000356xmlChar
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000357xmlPopInput(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000358 if (ctxt->inputNr == 1) return(0); /* End of main Input */
Daniel Veillardbc50b591999-03-01 12:28:53 +0000359 xmlFreeInputStream(inputPop(ctxt));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000360 if ((*ctxt->input->cur == 0) &&
361 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))
362 return(xmlPopInput(ctxt));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000363 return(CUR);
364}
365
Daniel Veillard11e00581998-10-24 18:27:49 +0000366/**
367 * xmlPushInput:
368 * @ctxt: an XML parser context
369 * @input: an XML parser input fragment (entity, XML fragment ...).
370 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000371 * xmlPushInput: switch to a new input stream which is stacked on top
372 * of the previous one(s).
373 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000374void
375xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000376 if (input == NULL) return;
377 inputPush(ctxt, input);
378}
379
Daniel Veillard11e00581998-10-24 18:27:49 +0000380/**
Daniel Veillardd692aa41999-02-28 21:54:31 +0000381 * xmlFreeInputStream:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000382 * @input: an xmlP arserInputPtr
Daniel Veillardd692aa41999-02-28 21:54:31 +0000383 *
384 * Free up an input stream.
385 */
386void
387xmlFreeInputStream(xmlParserInputPtr input) {
388 if (input == NULL) return;
389
Daniel Veillard6454aec1999-09-02 22:04:43 +0000390 if (input->filename != NULL) xmlFree((char *) input->filename);
391 if (input->directory != NULL) xmlFree((char *) input->directory);
Daniel Veillardd692aa41999-02-28 21:54:31 +0000392 if ((input->free != NULL) && (input->base != NULL))
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000393 input->free((xmlChar *) input->base);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000394 if (input->buf != NULL)
395 xmlFreeParserInputBuffer(input->buf);
Daniel Veillardd692aa41999-02-28 21:54:31 +0000396 memset(input, -1, sizeof(xmlParserInput));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000397 xmlFree(input);
Daniel Veillardd692aa41999-02-28 21:54:31 +0000398}
399
400/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000401 * xmlNewInputStream:
402 * @ctxt: an XML parser context
403 *
404 * Create a new input stream structure
405 * Returns the new input stream or NULL
406 */
407xmlParserInputPtr
408xmlNewInputStream(xmlParserCtxtPtr ctxt) {
409 xmlParserInputPtr input;
410
Daniel Veillard6454aec1999-09-02 22:04:43 +0000411 input = (xmlParserInputPtr) xmlMalloc(sizeof(xmlParserInput));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000412 if (input == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000413 ctxt->errNo = XML_ERR_NO_MEMORY;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000414 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000415 ctxt->sax->error(ctxt->userData,
416 "malloc: couldn't allocate a new input stream\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000417 ctxt->errNo = XML_ERR_NO_MEMORY;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000418 return(NULL);
419 }
420 input->filename = NULL;
421 input->directory = NULL;
422 input->base = NULL;
423 input->cur = NULL;
424 input->buf = NULL;
425 input->line = 1;
426 input->col = 1;
427 input->buf = NULL;
428 input->free = NULL;
429 input->consumed = 0;
430 return(input);
431}
432
433/**
Daniel Veillard11e00581998-10-24 18:27:49 +0000434 * xmlNewEntityInputStream:
435 * @ctxt: an XML parser context
436 * @entity: an Entity pointer
437 *
Daniel Veillard011b63c1999-06-02 17:44:04 +0000438 * Create a new input stream based on an xmlEntityPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +0000439 *
440 * Returns the new input stream or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000441 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000442xmlParserInputPtr
443xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000444 xmlParserInputPtr input;
445
446 if (entity == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000447 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000448 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000449 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000450 "internal: xmlNewEntityInputStream entity = NULL\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000451 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillardccb09631998-10-27 06:21:04 +0000452 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000453 }
454 if (entity->content == NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000455 switch (entity->type) {
456 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000457 ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000458 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
459 ctxt->sax->error(ctxt->userData,
460 "xmlNewEntityInputStream unparsed entity !\n");
461 break;
462 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
463 case XML_EXTERNAL_PARAMETER_ENTITY:
464 return(xmlLoadExternalEntity((char *) entity->SystemID,
465 (char *) entity->ExternalID, ctxt->input));
466 case XML_INTERNAL_GENERAL_ENTITY:
467 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
468 ctxt->sax->error(ctxt->userData,
469 "Internal entity %s without content !\n", entity->name);
470 break;
471 case XML_INTERNAL_PARAMETER_ENTITY:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000472 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000473 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
474 ctxt->sax->error(ctxt->userData,
475 "Internal parameter entity %s without content !\n", entity->name);
476 break;
477 case XML_INTERNAL_PREDEFINED_ENTITY:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000478 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000479 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
480 ctxt->sax->error(ctxt->userData,
481 "Predefined entity %s without content !\n", entity->name);
482 break;
483 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000484 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000485 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000486 input = xmlNewInputStream(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000487 if (input == NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000488 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000489 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000490 input->filename = (char *) entity->SystemID; /* TODO !!! char <- xmlChar */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000491 input->base = entity->content;
492 input->cur = entity->content;
Daniel Veillardccb09631998-10-27 06:21:04 +0000493 return(input);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000494}
495
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000496/**
497 * xmlNewStringInputStream:
498 * @ctxt: an XML parser context
Daniel Veillardb05deb71999-08-10 19:04:08 +0000499 * @buffer: an memory buffer
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000500 *
501 * Create a new input stream based on a memory buffer.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000502 * Returns the new input stream
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000503 */
504xmlParserInputPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000505xmlNewStringInputStream(xmlParserCtxtPtr ctxt, const xmlChar *buffer) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000506 xmlParserInputPtr input;
507
Daniel Veillardb05deb71999-08-10 19:04:08 +0000508 if (buffer == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000509 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000510 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000511 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000512 "internal: xmlNewStringInputStream string = NULL\n");
513 return(NULL);
514 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000515 input = xmlNewInputStream(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000516 if (input == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000517 return(NULL);
518 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000519 input->base = buffer;
520 input->cur = buffer;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000521 return(input);
522}
523
Daniel Veillard011b63c1999-06-02 17:44:04 +0000524/**
525 * xmlNewInputFromFile:
526 * @ctxt: an XML parser context
527 * @filename: the filename to use as entity
528 *
529 * Create a new input stream based on a file.
530 *
531 * Returns the new input stream or NULL in case of error
532 */
533xmlParserInputPtr
534xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000535 xmlParserInputBufferPtr buf;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000536 xmlParserInputPtr inputStream;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000537 char *directory = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000538
Daniel Veillardb05deb71999-08-10 19:04:08 +0000539 if (ctxt == NULL) return(NULL);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000540 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000541 if (buf == NULL) {
542 char name[1024];
Daniel Veillard011b63c1999-06-02 17:44:04 +0000543
Daniel Veillardb05deb71999-08-10 19:04:08 +0000544 if ((ctxt->input != NULL) && (ctxt->input->directory != NULL)) {
545#ifdef WIN32
546 sprintf(name, "%s\\%s", ctxt->input->directory, filename);
547#else
548 sprintf(name, "%s/%s", ctxt->input->directory, filename);
549#endif
550 buf = xmlParserInputBufferCreateFilename(name,
551 XML_CHAR_ENCODING_NONE);
552 if (buf != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000553 directory = xmlMemStrdup(ctxt->input->directory);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000554 }
555 if ((buf == NULL) && (ctxt->directory != NULL)) {
556#ifdef WIN32
557 sprintf(name, "%s\\%s", ctxt->directory, filename);
558#else
559 sprintf(name, "%s/%s", ctxt->directory, filename);
560#endif
561 buf = xmlParserInputBufferCreateFilename(name,
562 XML_CHAR_ENCODING_NONE);
563 if (buf != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000564 directory = xmlMemStrdup(ctxt->directory);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000565 }
566 if (buf == NULL)
567 return(NULL);
568 }
569 if (directory == NULL)
570 directory = xmlParserGetDirectory(filename);
571
572 inputStream = xmlNewInputStream(ctxt);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000573 if (inputStream == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000574 if (directory != NULL) xmlFree((char *) directory);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000575 return(NULL);
576 }
577
Daniel Veillard6454aec1999-09-02 22:04:43 +0000578 inputStream->filename = xmlMemStrdup(filename);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000579 inputStream->directory = directory;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000580 inputStream->buf = buf;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000581
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000582 inputStream->base = inputStream->buf->buffer->content;
583 inputStream->cur = inputStream->buf->buffer->content;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000584 if ((ctxt->directory == NULL) && (directory != NULL))
585 ctxt->directory = directory;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000586 return(inputStream);
587}
588
589/************************************************************************
590 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000591 * Commodity functions to handle parser contexts *
592 * *
593 ************************************************************************/
594
595/**
596 * xmlInitParserCtxt:
597 * @ctxt: an XML parser context
598 *
599 * Initialize a parser context
600 */
601
602void
603xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
604{
605 xmlSAXHandler *sax;
606
Daniel Veillard6454aec1999-09-02 22:04:43 +0000607 sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000608 if (sax == NULL) {
609 fprintf(stderr, "xmlInitParserCtxt: out of memory\n");
610 }
611
612 /* Allocate the Input stack */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000613 ctxt->inputTab = (xmlParserInputPtr *) xmlMalloc(5 * sizeof(xmlParserInputPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000614 ctxt->inputNr = 0;
615 ctxt->inputMax = 5;
616 ctxt->input = NULL;
617 ctxt->version = NULL;
618 ctxt->encoding = NULL;
619 ctxt->standalone = -1;
620 ctxt->hasExternalSubset = 0;
621 ctxt->hasPErefs = 0;
622 ctxt->html = 0;
623 ctxt->external = 0;
624 ctxt->instate = XML_PARSER_PROLOG;
625 ctxt->token = 0;
626 ctxt->directory = NULL;
627
628 /* Allocate the Node stack */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000629 ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(10 * sizeof(xmlNodePtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000630 ctxt->nodeNr = 0;
631 ctxt->nodeMax = 10;
632 ctxt->node = NULL;
633
634 if (sax == NULL) ctxt->sax = &xmlDefaultSAXHandler;
635 else {
636 ctxt->sax = sax;
637 memcpy(sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
638 }
639 ctxt->userData = ctxt;
640 ctxt->myDoc = NULL;
641 ctxt->wellFormed = 1;
642 ctxt->valid = 1;
643 ctxt->validate = xmlDoValidityCheckingDefaultValue;
644 ctxt->vctxt.userData = ctxt;
645 ctxt->vctxt.error = xmlParserValidityError;
646 ctxt->vctxt.warning = xmlParserValidityWarning;
647 ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue;
648 ctxt->record_info = 0;
649 xmlInitNodeInfoSeq(&ctxt->node_seq);
650}
651
652/**
653 * xmlFreeParserCtxt:
654 * @ctxt: an XML parser context
655 *
656 * Free all the memory used by a parser context. However the parsed
657 * document in ctxt->myDoc is not freed.
658 */
659
660void
661xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
662{
663 xmlParserInputPtr input;
664
665 if (ctxt == NULL) return;
666
667 while ((input = inputPop(ctxt)) != NULL) {
668 xmlFreeInputStream(input);
669 }
670
Daniel Veillard6454aec1999-09-02 22:04:43 +0000671 if (ctxt->nodeTab != NULL) xmlFree(ctxt->nodeTab);
672 if (ctxt->inputTab != NULL) xmlFree(ctxt->inputTab);
673 if (ctxt->version != NULL) xmlFree((char *) ctxt->version);
674 if (ctxt->encoding != NULL) xmlFree((char *) ctxt->encoding);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000675 if ((ctxt->sax != NULL) && (ctxt->sax != &xmlDefaultSAXHandler))
Daniel Veillard6454aec1999-09-02 22:04:43 +0000676 xmlFree(ctxt->sax);
677 if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory);
678 xmlFree(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000679}
680
681/**
682 * xmlNewParserCtxt:
683 *
684 * Allocate and initialize a new parser context.
685 *
686 * Returns the xmlParserCtxtPtr or NULL
687 */
688
689xmlParserCtxtPtr
690xmlNewParserCtxt()
691{
692 xmlParserCtxtPtr ctxt;
693
Daniel Veillard6454aec1999-09-02 22:04:43 +0000694 ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000695 if (ctxt == NULL) {
696 fprintf(stderr, "xmlNewParserCtxt : cannot allocate context\n");
697 perror("malloc");
698 return(NULL);
699 }
700 xmlInitParserCtxt(ctxt);
701 return(ctxt);
702}
703
704/**
705 * xmlClearParserCtxt:
706 * @ctxt: an XML parser context
707 *
708 * Clear (release owned resources) and reinitialize a parser context
709 */
710
711void
712xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
713{
714 xmlClearNodeInfoSeq(&ctxt->node_seq);
715 xmlInitParserCtxt(ctxt);
716}
717
718/************************************************************************
719 * *
Daniel Veillard011b63c1999-06-02 17:44:04 +0000720 * Commodity functions to handle entities *
721 * *
722 ************************************************************************/
723
Daniel Veillardb05deb71999-08-10 19:04:08 +0000724void xmlParserHandleReference(xmlParserCtxtPtr ctxt);
725void xmlParserHandlePEReference(xmlParserCtxtPtr ctxt);
726
727/**
728 * xmlParseCharRef:
729 * @ctxt: an XML parser context
730 *
731 * parse Reference declarations
732 *
733 * [66] CharRef ::= '&#' [0-9]+ ';' |
734 * '&#x' [0-9a-fA-F]+ ';'
735 *
736 * [ WFC: Legal Character ]
737 * Characters referred to using character references must match the
738 * production for Char.
739 *
740 * Returns the value parsed (as an int)
741 */
742int
743xmlParseCharRef(xmlParserCtxtPtr ctxt) {
744 int val = 0;
745
746 if (ctxt->token != 0) {
747 val = ctxt->token;
748 ctxt->token = 0;
749 return(val);
750 }
751 if ((CUR == '&') && (NXT(1) == '#') &&
752 (NXT(2) == 'x')) {
753 SKIP(3);
754 while (CUR != ';') {
755 if ((CUR >= '0') && (CUR <= '9'))
756 val = val * 16 + (CUR - '0');
757 else if ((CUR >= 'a') && (CUR <= 'f'))
758 val = val * 16 + (CUR - 'a') + 10;
759 else if ((CUR >= 'A') && (CUR <= 'F'))
760 val = val * 16 + (CUR - 'A') + 10;
761 else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000762 ctxt->errNo = XML_ERR_INVALID_HEX_CHARREF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000763 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
764 ctxt->sax->error(ctxt->userData,
765 "xmlParseCharRef: invalid hexadecimal value\n");
766 ctxt->wellFormed = 0;
767 val = 0;
768 break;
769 }
770 NEXT;
771 }
772 if (CUR == ';')
773 NEXT;
774 } else if ((CUR == '&') && (NXT(1) == '#')) {
775 SKIP(2);
776 while (CUR != ';') {
777 if ((CUR >= '0') && (CUR <= '9'))
778 val = val * 10 + (CUR - '0');
779 else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000780 ctxt->errNo = XML_ERR_INVALID_DEC_CHARREF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000781 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
782 ctxt->sax->error(ctxt->userData,
783 "xmlParseCharRef: invalid decimal value\n");
784 ctxt->wellFormed = 0;
785 val = 0;
786 break;
787 }
788 NEXT;
789 }
790 if (CUR == ';')
791 NEXT;
792 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000793 ctxt->errNo = XML_ERR_INVALID_CHARREF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000794 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
795 ctxt->sax->error(ctxt->userData,
796 "xmlParseCharRef: invalid value\n");
797 ctxt->wellFormed = 0;
798 }
799
800 /*
801 * [ WFC: Legal Character ]
802 * Characters referred to using character references must match the
803 * production for Char.
804 */
805 if (IS_CHAR(val)) {
806 return(val);
807 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000808 ctxt->errNo = XML_ERR_INVALID_CHAR;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000809 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000810 ctxt->sax->error(ctxt->userData, "CharRef: invalid xmlChar value %d\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000811 val);
812 ctxt->wellFormed = 0;
813 }
814 return(0);
815}
816
817/**
818 * xmlParserHandleReference:
819 * @ctxt: the parser context
820 *
821 * [67] Reference ::= EntityRef | CharRef
822 *
823 * [68] EntityRef ::= '&' Name ';'
824 *
825 * [ WFC: Entity Declared ]
826 * the Name given in the entity reference must match that in an entity
827 * declaration, except that well-formed documents need not declare any
828 * of the following entities: amp, lt, gt, apos, quot.
829 *
830 * [ WFC: Parsed Entity ]
831 * An entity reference must not contain the name of an unparsed entity
832 *
833 * [66] CharRef ::= '&#' [0-9]+ ';' |
834 * '&#x' [0-9a-fA-F]+ ';'
835 *
836 * A PEReference may have been detectect in the current input stream
837 * the handling is done accordingly to
838 * http://www.w3.org/TR/REC-xml#entproc
839 */
840void
841xmlParserHandleReference(xmlParserCtxtPtr ctxt) {
842 xmlParserInputPtr input;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000843 xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000844 xmlEntityPtr ent = NULL;
845
846 if (ctxt->token != 0) return;
847 if (CUR != '&') return;
848 GROW;
849 if ((CUR == '&') && (NXT(1) == '#')) {
850 switch(ctxt->instate) {
851 case XML_PARSER_CDATA_SECTION:
852 return;
853 case XML_PARSER_COMMENT:
854 return;
855 case XML_PARSER_EOF:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000856 ctxt->errNo = XML_ERR_CHARREF_AT_EOF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000857 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
858 ctxt->sax->error(ctxt->userData, "CharRef at EOF\n");
859 ctxt->wellFormed = 0;
860 return;
861 case XML_PARSER_PROLOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000862 ctxt->errNo = XML_ERR_CHARREF_IN_PROLOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000863 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
864 ctxt->sax->error(ctxt->userData, "CharRef in prolog!\n");
865 ctxt->wellFormed = 0;
866 return;
867 case XML_PARSER_EPILOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000868 ctxt->errNo = XML_ERR_CHARREF_IN_EPILOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000869 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
870 ctxt->sax->error(ctxt->userData, "CharRef in epilog!\n");
871 ctxt->wellFormed = 0;
872 return;
873 case XML_PARSER_DTD:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000874 ctxt->errNo = XML_ERR_CHARREF_IN_DTD;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000875 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
876 ctxt->sax->error(ctxt->userData,
877 "CharRef are forbiden in DTDs!\n");
878 ctxt->wellFormed = 0;
879 return;
880 case XML_PARSER_ENTITY_DECL:
881 /* we just ignore it there */
882 return;
883 case XML_PARSER_ENTITY_VALUE:
884 /*
885 * NOTE: in the case of entity values, we don't do the
886 * substitution here since we need the litteral
887 * entity value to be able to save the internal
888 * subset of the document.
889 * This will be handled by xmlDecodeEntities
890 */
891 return;
892 case XML_PARSER_CONTENT:
893 case XML_PARSER_ATTRIBUTE_VALUE:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000894 /* !!! this may not be Ok for UTF-8, multibyte sequence */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000895 ctxt->token = xmlParseCharRef(ctxt);
896 return;
897 }
898 return;
899 }
900
901 switch(ctxt->instate) {
902 case XML_PARSER_CDATA_SECTION:
903 return;
904 case XML_PARSER_COMMENT:
905 return;
906 case XML_PARSER_EOF:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000907 ctxt->errNo = XML_ERR_ENTITYREF_AT_EOF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000908 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
909 ctxt->sax->error(ctxt->userData, "Reference at EOF\n");
910 ctxt->wellFormed = 0;
911 return;
912 case XML_PARSER_PROLOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000913 ctxt->errNo = XML_ERR_ENTITYREF_IN_PROLOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000914 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
915 ctxt->sax->error(ctxt->userData, "Reference in prolog!\n");
916 ctxt->wellFormed = 0;
917 return;
918 case XML_PARSER_EPILOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000919 ctxt->errNo = XML_ERR_ENTITYREF_IN_EPILOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000920 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
921 ctxt->sax->error(ctxt->userData, "Reference in epilog!\n");
922 ctxt->wellFormed = 0;
923 return;
924 case XML_PARSER_ENTITY_VALUE:
925 /*
926 * NOTE: in the case of entity values, we don't do the
927 * substitution here since we need the litteral
928 * entity value to be able to save the internal
929 * subset of the document.
930 * This will be handled by xmlDecodeEntities
931 */
932 return;
933 case XML_PARSER_ATTRIBUTE_VALUE:
934 /*
935 * NOTE: in the case of attributes values, we don't do the
936 * substitution here unless we are in a mode where
937 * the parser is explicitely asked to substitute
938 * entities. The SAX callback is called with values
939 * without entity substitution.
940 * This will then be handled by xmlDecodeEntities
941 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000942 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000943 case XML_PARSER_ENTITY_DECL:
944 /*
945 * we just ignore it there
946 * the substitution will be done once the entity is referenced
947 */
948 return;
949 case XML_PARSER_DTD:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000950 ctxt->errNo = XML_ERR_ENTITYREF_IN_DTD;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000951 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
952 ctxt->sax->error(ctxt->userData,
953 "Entity references are forbiden in DTDs!\n");
954 ctxt->wellFormed = 0;
955 return;
956 case XML_PARSER_CONTENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000957 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000958 }
959
960 NEXT;
961 name = xmlScanName(ctxt);
962 if (name == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000963 ctxt->errNo = XML_ERR_ENTITYREF_NO_NAME;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000964 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
965 ctxt->sax->error(ctxt->userData, "Entity reference: no name\n");
966 ctxt->wellFormed = 0;
967 ctxt->token = '&';
968 return;
969 }
970 if (NXT(xmlStrlen(name)) != ';') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000971 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000972 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
973 ctxt->sax->error(ctxt->userData,
974 "Entity reference: ';' expected\n");
975 ctxt->wellFormed = 0;
976 ctxt->token = '&';
Daniel Veillard6454aec1999-09-02 22:04:43 +0000977 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000978 return;
979 }
980 SKIP(xmlStrlen(name) + 1);
981 if (ctxt->sax != NULL) {
982 if (ctxt->sax->getEntity != NULL)
983 ent = ctxt->sax->getEntity(ctxt->userData, name);
984 }
985
986 /*
987 * [ WFC: Entity Declared ]
988 * the Name given in the entity reference must match that in an entity
989 * declaration, except that well-formed documents need not declare any
990 * of the following entities: amp, lt, gt, apos, quot.
991 */
992 if (ent == NULL)
993 ent = xmlGetPredefinedEntity(name);
994 if (ent == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000995 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000996 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
997 ctxt->sax->error(ctxt->userData,
998 "Entity reference: entity %s not declared\n",
999 name);
1000 ctxt->wellFormed = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001001 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001002 return;
1003 }
1004
1005 /*
1006 * [ WFC: Parsed Entity ]
1007 * An entity reference must not contain the name of an unparsed entity
1008 */
1009 if (ent->type == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001010 ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001011 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1012 ctxt->sax->error(ctxt->userData,
1013 "Entity reference to unparsed entity %s\n", name);
1014 ctxt->wellFormed = 0;
1015 }
1016
1017 if (ent->type == XML_INTERNAL_PREDEFINED_ENTITY) {
1018 ctxt->token = ent->content[0];
Daniel Veillard6454aec1999-09-02 22:04:43 +00001019 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001020 return;
1021 }
1022 input = xmlNewEntityInputStream(ctxt, ent);
1023 xmlPushInput(ctxt, input);
Daniel Veillard6454aec1999-09-02 22:04:43 +00001024 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001025 return;
1026}
1027
1028/**
1029 * xmlParserHandlePEReference:
1030 * @ctxt: the parser context
1031 *
1032 * [69] PEReference ::= '%' Name ';'
1033 *
1034 * [ WFC: No Recursion ]
1035 * TODO A parsed entity must not contain a recursive
1036 * reference to itself, either directly or indirectly.
1037 *
1038 * [ WFC: Entity Declared ]
1039 * In a document without any DTD, a document with only an internal DTD
1040 * subset which contains no parameter entity references, or a document
1041 * with "standalone='yes'", ... ... The declaration of a parameter
1042 * entity must precede any reference to it...
1043 *
1044 * [ VC: Entity Declared ]
1045 * In a document with an external subset or external parameter entities
1046 * with "standalone='no'", ... ... The declaration of a parameter entity
1047 * must precede any reference to it...
1048 *
1049 * [ WFC: In DTD ]
1050 * Parameter-entity references may only appear in the DTD.
1051 * NOTE: misleading but this is handled.
1052 *
1053 * A PEReference may have been detected in the current input stream
1054 * the handling is done accordingly to
1055 * http://www.w3.org/TR/REC-xml#entproc
1056 * i.e.
1057 * - Included in literal in entity values
1058 * - Included as Paraemeter Entity reference within DTDs
1059 */
1060void
1061xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001062 xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001063 xmlEntityPtr entity = NULL;
1064 xmlParserInputPtr input;
1065
1066 if (ctxt->token != 0) return;
1067 if (CUR != '%') return;
1068 switch(ctxt->instate) {
1069 case XML_PARSER_CDATA_SECTION:
1070 return;
1071 case XML_PARSER_COMMENT:
1072 return;
1073 case XML_PARSER_EOF:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001074 ctxt->errNo = XML_ERR_PEREF_AT_EOF;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001075 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1076 ctxt->sax->error(ctxt->userData, "PEReference at EOF\n");
1077 ctxt->wellFormed = 0;
1078 return;
1079 case XML_PARSER_PROLOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001080 ctxt->errNo = XML_ERR_PEREF_IN_PROLOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001081 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1082 ctxt->sax->error(ctxt->userData, "PEReference in prolog!\n");
1083 ctxt->wellFormed = 0;
1084 return;
1085 case XML_PARSER_ENTITY_DECL:
1086 case XML_PARSER_CONTENT:
1087 case XML_PARSER_ATTRIBUTE_VALUE:
1088 /* we just ignore it there */
1089 return;
1090 case XML_PARSER_EPILOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001091 ctxt->errNo = XML_ERR_PEREF_IN_EPILOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001092 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1093 ctxt->sax->error(ctxt->userData, "PEReference in epilog!\n");
1094 ctxt->wellFormed = 0;
1095 return;
1096 case XML_PARSER_ENTITY_VALUE:
1097 /*
1098 * NOTE: in the case of entity values, we don't do the
1099 * substitution here since we need the litteral
1100 * entity value to be able to save the internal
1101 * subset of the document.
1102 * This will be handled by xmlDecodeEntities
1103 */
1104 return;
1105 case XML_PARSER_DTD:
1106 /*
1107 * [WFC: Well-Formedness Constraint: PEs in Internal Subset]
1108 * In the internal DTD subset, parameter-entity references
1109 * can occur only where markup declarations can occur, not
1110 * within markup declarations.
1111 * In that case this is handled in xmlParseMarkupDecl
1112 */
1113 if ((ctxt->external == 0) && (ctxt->inputNr == 1))
1114 return;
1115 }
1116
1117 NEXT;
1118 name = xmlParseName(ctxt);
1119 if (name == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001120 ctxt->errNo = XML_ERR_PEREF_NO_NAME;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001121 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1122 ctxt->sax->error(ctxt->userData, "xmlHandlePEReference: no name\n");
1123 ctxt->wellFormed = 0;
1124 } else {
1125 if (CUR == ';') {
1126 NEXT;
1127 if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL))
1128 entity = ctxt->sax->getParameterEntity(ctxt->userData, name);
1129 if (entity == NULL) {
1130
1131 /*
1132 * [ WFC: Entity Declared ]
1133 * In a document without any DTD, a document with only an
1134 * internal DTD subset which contains no parameter entity
1135 * references, or a document with "standalone='yes'", ...
1136 * ... The declaration of a parameter entity must precede
1137 * any reference to it...
1138 */
1139 if ((ctxt->standalone == 1) ||
1140 ((ctxt->hasExternalSubset == 0) &&
1141 (ctxt->hasPErefs == 0))) {
1142 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1143 ctxt->sax->error(ctxt->userData,
1144 "PEReference: %%%s; not found\n", name);
1145 ctxt->wellFormed = 0;
1146 } else {
1147 /*
1148 * [ VC: Entity Declared ]
1149 * In a document with an external subset or external
1150 * parameter entities with "standalone='no'", ...
1151 * ... The declaration of a parameter entity must precede
1152 * any reference to it...
1153 */
1154 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1155 ctxt->sax->warning(ctxt->userData,
1156 "PEReference: %%%s; not found\n", name);
1157 ctxt->valid = 0;
1158 }
1159 } else {
1160 if ((entity->type == XML_INTERNAL_PARAMETER_ENTITY) ||
1161 (entity->type == XML_EXTERNAL_PARAMETER_ENTITY)) {
1162 /*
1163 * TODO !!!! handle the extra spaces added before and after
1164 * c.f. http://www.w3.org/TR/REC-xml#as-PE
1165 * TODO !!!! Avoid quote processing in parameters value
1166 * c.f. http://www.w3.org/TR/REC-xml#inliteral
1167 */
1168 input = xmlNewEntityInputStream(ctxt, entity);
1169 xmlPushInput(ctxt, input);
1170 } else {
1171 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1172 ctxt->sax->error(ctxt->userData,
1173 "xmlHandlePEReference: %s is not a parameter entity\n",
1174 name);
1175 ctxt->wellFormed = 0;
1176 }
1177 }
1178 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001179 ctxt->errNo = XML_ERR_PEREF_SEMICOL_MISSING;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001180 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1181 ctxt->sax->error(ctxt->userData,
1182 "xmlHandlePEReference: expecting ';'\n");
1183 ctxt->wellFormed = 0;
1184 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001185 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001186 }
1187}
1188
Daniel Veillard011b63c1999-06-02 17:44:04 +00001189/*
1190 * Macro used to grow the current buffer.
1191 */
1192#define growBuffer(buffer) { \
1193 buffer##_size *= 2; \
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001194 buffer = (xmlChar *) xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \
Daniel Veillard011b63c1999-06-02 17:44:04 +00001195 if (buffer == NULL) { \
1196 perror("realloc failed"); \
1197 exit(1); \
1198 } \
1199}
1200
Daniel Veillard011b63c1999-06-02 17:44:04 +00001201/**
1202 * xmlDecodeEntities:
1203 * @ctxt: the parser context
1204 * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF
1205 * @len: the len to decode (in bytes !), -1 for no size limit
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001206 * @end: an end marker xmlChar, 0 if none
1207 * @end2: an end marker xmlChar, 0 if none
1208 * @end3: an end marker xmlChar, 0 if none
Daniel Veillard011b63c1999-06-02 17:44:04 +00001209 *
1210 * [67] Reference ::= EntityRef | CharRef
1211 *
1212 * [69] PEReference ::= '%' Name ';'
1213 *
1214 * Returns A newly allocated string with the substitution done. The caller
1215 * must deallocate it !
1216 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001217xmlChar *
Daniel Veillard011b63c1999-06-02 17:44:04 +00001218xmlDecodeEntities(xmlParserCtxtPtr ctxt, int len, int what,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001219 xmlChar end, xmlChar end2, xmlChar end3) {
1220 xmlChar *buffer = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001221 int buffer_size = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001222 xmlChar *out = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001223
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001224 xmlChar *current = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001225 xmlEntityPtr ent;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001226 int nbchars = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001227 unsigned int max = (unsigned int) len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001228 xmlChar cur;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001229
1230 /*
1231 * allocate a translation buffer.
1232 */
1233 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001234 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard011b63c1999-06-02 17:44:04 +00001235 if (buffer == NULL) {
1236 perror("xmlDecodeEntities: malloc failed");
1237 return(NULL);
1238 }
1239 out = buffer;
1240
1241 /*
1242 * Ok loop until we reach one of the ending char or a size limit.
1243 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001244 cur = CUR;
1245 while ((nbchars < max) && (cur != end) &&
1246 (cur != end2) && (cur != end3)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001247
Daniel Veillardb05deb71999-08-10 19:04:08 +00001248 if (cur == 0) break;
1249 if ((cur == '&') && (NXT(1) == '#')) {
1250 int val = xmlParseCharRef(ctxt);
1251 *out++ = val;
1252 nbchars += 3;
1253 } else if ((cur == '&') && (what & XML_SUBSTITUTE_REF)) {
1254 ent = xmlParseEntityRef(ctxt);
1255 if ((ent != NULL) &&
1256 (ctxt->replaceEntities != 0)) {
1257 current = ent->content;
1258 while (*current != 0) {
1259 *out++ = *current++;
1260 if (out - buffer > buffer_size - 100) {
1261 int index = out - buffer;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001262
Daniel Veillardb05deb71999-08-10 19:04:08 +00001263 growBuffer(buffer);
1264 out = &buffer[index];
Daniel Veillard011b63c1999-06-02 17:44:04 +00001265 }
1266 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001267 nbchars += 3 + xmlStrlen(ent->name);
1268 } else if (ent != NULL) {
1269 int i = xmlStrlen(ent->name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001270 const xmlChar *cur = ent->name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001271
1272 nbchars += i + 2;
1273 *out++ = '&';
1274 if (out - buffer > buffer_size - i - 100) {
1275 int index = out - buffer;
1276
1277 growBuffer(buffer);
1278 out = &buffer[index];
1279 }
1280 for (;i > 0;i--)
1281 *out++ = *cur++;
1282 *out++ = ';';
Daniel Veillard011b63c1999-06-02 17:44:04 +00001283 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001284 } else if (cur == '%' && (what & XML_SUBSTITUTE_PEREF)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001285 /*
1286 * a PEReference induce to switch the entity flow,
1287 * we break here to flush the current set of chars
1288 * parsed if any. We will be called back later.
1289 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001290 if (nbchars != 0) break;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001291
1292 xmlParsePEReference(ctxt);
1293
1294 /*
1295 * Pop-up of finished entities.
1296 */
1297 while ((CUR == 0) && (ctxt->inputNr > 1))
1298 xmlPopInput(ctxt);
1299
Daniel Veillardb05deb71999-08-10 19:04:08 +00001300 break;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001301 } else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001302 /* invalid for UTF-8 , use COPY(out); !!!!!! */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001303 *out++ = cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001304 nbchars++;
Raph Levien05240da1999-06-15 21:27:11 +00001305 if (out - buffer > buffer_size - 100) {
1306 int index = out - buffer;
1307
1308 growBuffer(buffer);
1309 out = &buffer[index];
1310 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00001311 NEXT;
1312 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001313 cur = CUR;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001314 }
1315 *out++ = 0;
1316 return(buffer);
1317}
1318
Daniel Veillard260a68f1998-08-13 03:39:55 +00001319
1320/************************************************************************
1321 * *
Daniel Veillard27d88741999-05-29 11:51:49 +00001322 * Commodity functions to handle encodings *
1323 * *
1324 ************************************************************************/
1325
1326/**
1327 * xmlSwitchEncoding:
1328 * @ctxt: the parser context
1329 * @len: the len of @cur
1330 *
1331 * change the input functions when discovering the character encoding
1332 * of a given entity.
1333 *
1334 */
1335void
1336xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
1337{
1338 switch (enc) {
1339 case XML_CHAR_ENCODING_ERROR:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001340 ctxt->errNo = XML_ERR_UNKNOWN_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001341 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1342 ctxt->sax->error(ctxt->userData, "encoding unknown\n");
1343 ctxt->wellFormed = 0;
1344 break;
1345 case XML_CHAR_ENCODING_NONE:
1346 /* let's assume it's UTF-8 without the XML decl */
1347 return;
1348 case XML_CHAR_ENCODING_UTF8:
1349 /* default encoding, no conversion should be needed */
1350 return;
1351 case XML_CHAR_ENCODING_UTF16LE:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001352 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001353 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1354 ctxt->sax->error(ctxt->userData,
1355 "char encoding UTF16 little endian not supported\n");
1356 break;
1357 case XML_CHAR_ENCODING_UTF16BE:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001358 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001359 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1360 ctxt->sax->error(ctxt->userData,
1361 "char encoding UTF16 big endian not supported\n");
1362 break;
1363 case XML_CHAR_ENCODING_UCS4LE:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001364 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001365 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1366 ctxt->sax->error(ctxt->userData,
1367 "char encoding USC4 little endian not supported\n");
1368 break;
1369 case XML_CHAR_ENCODING_UCS4BE:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001370 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001371 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1372 ctxt->sax->error(ctxt->userData,
1373 "char encoding USC4 big endian not supported\n");
1374 break;
1375 case XML_CHAR_ENCODING_EBCDIC:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001376 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001377 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1378 ctxt->sax->error(ctxt->userData,
1379 "char encoding EBCDIC not supported\n");
1380 break;
1381 case XML_CHAR_ENCODING_UCS4_2143:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001382 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001383 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1384 ctxt->sax->error(ctxt->userData,
1385 "char encoding UCS4 2143 not supported\n");
1386 break;
1387 case XML_CHAR_ENCODING_UCS4_3412:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001388 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001389 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1390 ctxt->sax->error(ctxt->userData,
1391 "char encoding UCS4 3412 not supported\n");
1392 break;
1393 case XML_CHAR_ENCODING_UCS2:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001394 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001395 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1396 ctxt->sax->error(ctxt->userData,
1397 "char encoding UCS2 not supported\n");
1398 break;
1399 case XML_CHAR_ENCODING_8859_1:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001400 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001401 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1402 ctxt->sax->error(ctxt->userData,
1403 "char encoding ISO_8859_1 ISO Latin 1 not supported\n");
1404 break;
1405 case XML_CHAR_ENCODING_8859_2:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001406 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001407 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1408 ctxt->sax->error(ctxt->userData,
1409 "char encoding ISO_8859_2 ISO Latin 2 not supported\n");
1410 break;
1411 case XML_CHAR_ENCODING_8859_3:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001412 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001413 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1414 ctxt->sax->error(ctxt->userData,
1415 "char encoding ISO_8859_3 not supported\n");
1416 break;
1417 case XML_CHAR_ENCODING_8859_4:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001418 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001419 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1420 ctxt->sax->error(ctxt->userData,
1421 "char encoding ISO_8859_4 not supported\n");
1422 break;
1423 case XML_CHAR_ENCODING_8859_5:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001424 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001425 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1426 ctxt->sax->error(ctxt->userData,
1427 "char encoding ISO_8859_5 not supported\n");
1428 break;
1429 case XML_CHAR_ENCODING_8859_6:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001430 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001431 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1432 ctxt->sax->error(ctxt->userData,
1433 "char encoding ISO_8859_6 not supported\n");
1434 break;
1435 case XML_CHAR_ENCODING_8859_7:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001436 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001437 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1438 ctxt->sax->error(ctxt->userData,
1439 "char encoding ISO_8859_7 not supported\n");
1440 break;
1441 case XML_CHAR_ENCODING_8859_8:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001442 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001443 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1444 ctxt->sax->error(ctxt->userData,
1445 "char encoding ISO_8859_8 not supported\n");
1446 break;
1447 case XML_CHAR_ENCODING_8859_9:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001448 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001449 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1450 ctxt->sax->error(ctxt->userData,
1451 "char encoding ISO_8859_9 not supported\n");
1452 break;
1453 case XML_CHAR_ENCODING_2022_JP:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001454 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001455 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1456 ctxt->sax->error(ctxt->userData,
1457 "char encoding ISO-2022-JPnot supported\n");
1458 break;
1459 case XML_CHAR_ENCODING_SHIFT_JIS:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001460 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001461 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1462 ctxt->sax->error(ctxt->userData,
1463 "char encoding Shift_JISnot supported\n");
1464 break;
1465 case XML_CHAR_ENCODING_EUC_JP:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001466 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001467 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1468 ctxt->sax->error(ctxt->userData,
1469 "char encoding EUC-JPnot supported\n");
1470 break;
1471 }
1472}
1473
1474/************************************************************************
1475 * *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001476 * Commodity functions to handle xmlChars *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001477 * *
1478 ************************************************************************/
1479
Daniel Veillard11e00581998-10-24 18:27:49 +00001480/**
1481 * xmlStrndup:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001482 * @cur: the input xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001483 * @len: the len of @cur
1484 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001485 * a strndup for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001486 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001487 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001488 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001489xmlChar *
1490xmlStrndup(const xmlChar *cur, int len) {
1491 xmlChar *ret = xmlMalloc((len + 1) * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001492
1493 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001494 fprintf(stderr, "malloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001495 (len + 1) * (long)sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001496 return(NULL);
1497 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001498 memcpy(ret, cur, len * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001499 ret[len] = 0;
1500 return(ret);
1501}
1502
Daniel Veillard11e00581998-10-24 18:27:49 +00001503/**
1504 * xmlStrdup:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001505 * @cur: the input xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001506 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001507 * a strdup for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001508 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001509 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001510 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001511xmlChar *
1512xmlStrdup(const xmlChar *cur) {
1513 const xmlChar *p = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001514
1515 while (IS_CHAR(*p)) p++;
1516 return(xmlStrndup(cur, p - cur));
1517}
1518
Daniel Veillard11e00581998-10-24 18:27:49 +00001519/**
1520 * xmlCharStrndup:
1521 * @cur: the input char *
1522 * @len: the len of @cur
1523 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001524 * a strndup for char's to xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001525 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001526 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001527 */
1528
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001529xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001530xmlCharStrndup(const char *cur, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001531 int i;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001532 xmlChar *ret = xmlMalloc((len + 1) * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001533
1534 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001535 fprintf(stderr, "malloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001536 (len + 1) * (long)sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001537 return(NULL);
1538 }
1539 for (i = 0;i < len;i++)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001540 ret[i] = (xmlChar) cur[i];
Daniel Veillard260a68f1998-08-13 03:39:55 +00001541 ret[len] = 0;
1542 return(ret);
1543}
1544
Daniel Veillard11e00581998-10-24 18:27:49 +00001545/**
1546 * xmlCharStrdup:
1547 * @cur: the input char *
1548 * @len: the len of @cur
1549 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001550 * a strdup for char's to xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001551 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001552 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001553 */
1554
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001555xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001556xmlCharStrdup(const char *cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001557 const char *p = cur;
1558
1559 while (*p != '\0') p++;
1560 return(xmlCharStrndup(cur, p - cur));
1561}
1562
Daniel Veillard11e00581998-10-24 18:27:49 +00001563/**
1564 * xmlStrcmp:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001565 * @str1: the first xmlChar *
1566 * @str2: the second xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001567 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001568 * a strcmp for xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001569 *
1570 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +00001571 */
1572
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001573int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001574xmlStrcmp(const xmlChar *str1, const xmlChar *str2) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001575 register int tmp;
1576
1577 do {
1578 tmp = *str1++ - *str2++;
1579 if (tmp != 0) return(tmp);
1580 } while ((*str1 != 0) && (*str2 != 0));
1581 return (*str1 - *str2);
1582}
1583
Daniel Veillard11e00581998-10-24 18:27:49 +00001584/**
1585 * xmlStrncmp:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001586 * @str1: the first xmlChar *
1587 * @str2: the second xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001588 * @len: the max comparison length
1589 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001590 * a strncmp for xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001591 *
1592 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +00001593 */
1594
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001595int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001596xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001597 register int tmp;
1598
1599 if (len <= 0) return(0);
1600 do {
1601 tmp = *str1++ - *str2++;
1602 if (tmp != 0) return(tmp);
1603 len--;
1604 if (len <= 0) return(0);
1605 } while ((*str1 != 0) && (*str2 != 0));
1606 return (*str1 - *str2);
1607}
1608
Daniel Veillard11e00581998-10-24 18:27:49 +00001609/**
1610 * xmlStrchr:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001611 * @str: the xmlChar * array
1612 * @val: the xmlChar to search
Daniel Veillard11e00581998-10-24 18:27:49 +00001613 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001614 * a strchr for xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001615 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001616 * Returns the xmlChar * for the first occurence or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001617 */
1618
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001619const xmlChar *
1620xmlStrchr(const xmlChar *str, xmlChar val) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001621 while (*str != 0) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001622 if (*str == val) return((xmlChar *) str);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001623 str++;
1624 }
1625 return(NULL);
1626}
1627
Daniel Veillard11e00581998-10-24 18:27:49 +00001628/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001629 * xmlStrstr:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001630 * @str: the xmlChar * array (haystack)
1631 * @val: the xmlChar to search (needle)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001632 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001633 * a strstr for xmlChar's
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001634 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001635 * Returns the xmlChar * for the first occurence or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001636 */
1637
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001638const xmlChar *
1639xmlStrstr(const xmlChar *str, xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001640 int n;
1641
1642 if (str == NULL) return(NULL);
1643 if (val == NULL) return(NULL);
1644 n = xmlStrlen(val);
1645
1646 if (n == 0) return(str);
1647 while (*str != 0) {
1648 if (*str == *val) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001649 if (!xmlStrncmp(str, val, n)) return((const xmlChar *) str);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001650 }
1651 str++;
1652 }
1653 return(NULL);
1654}
1655
1656/**
1657 * xmlStrsub:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001658 * @str: the xmlChar * array (haystack)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001659 * @start: the index of the first char (zero based)
1660 * @len: the length of the substring
1661 *
1662 * Extract a substring of a given string
1663 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001664 * Returns the xmlChar * for the first occurence or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001665 */
1666
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001667xmlChar *
1668xmlStrsub(const xmlChar *str, int start, int len) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001669 int i;
1670
1671 if (str == NULL) return(NULL);
1672 if (start < 0) return(NULL);
1673 if (len < 0) return(NULL);
1674
1675 for (i = 0;i < start;i++) {
1676 if (*str == 0) return(NULL);
1677 str++;
1678 }
1679 if (*str == 0) return(NULL);
1680 return(xmlStrndup(str, len));
1681}
1682
1683/**
Daniel Veillard11e00581998-10-24 18:27:49 +00001684 * xmlStrlen:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001685 * @str: the xmlChar * array
Daniel Veillard11e00581998-10-24 18:27:49 +00001686 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001687 * lenght of a xmlChar's string
Daniel Veillard1e346af1999-02-22 10:33:01 +00001688 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001689 * Returns the number of xmlChar contained in the ARRAY.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001690 */
1691
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001692int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001693xmlStrlen(const xmlChar *str) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001694 int len = 0;
1695
1696 if (str == NULL) return(0);
1697 while (*str != 0) {
1698 str++;
1699 len++;
1700 }
1701 return(len);
1702}
1703
Daniel Veillard11e00581998-10-24 18:27:49 +00001704/**
1705 * xmlStrncat:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001706 * @cur: the original xmlChar * array
1707 * @add: the xmlChar * array added
Daniel Veillard11e00581998-10-24 18:27:49 +00001708 * @len: the length of @add
1709 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001710 * a strncat for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001711 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001712 * Returns a new xmlChar * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001713 */
1714
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001715xmlChar *
1716xmlStrncat(xmlChar *cur, const xmlChar *add, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001717 int size;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001718 xmlChar *ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001719
1720 if ((add == NULL) || (len == 0))
1721 return(cur);
1722 if (cur == NULL)
1723 return(xmlStrndup(add, len));
1724
1725 size = xmlStrlen(cur);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001726 ret = xmlRealloc(cur, (size + len + 1) * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001727 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001728 fprintf(stderr, "xmlStrncat: realloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001729 (size + len + 1) * (long)sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001730 return(cur);
1731 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001732 memcpy(&ret[size], add, len * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001733 ret[size + len] = 0;
1734 return(ret);
1735}
1736
Daniel Veillard11e00581998-10-24 18:27:49 +00001737/**
1738 * xmlStrcat:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001739 * @cur: the original xmlChar * array
1740 * @add: the xmlChar * array added
Daniel Veillard11e00581998-10-24 18:27:49 +00001741 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001742 * a strcat for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001743 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001744 * Returns a new xmlChar * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001745 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001746xmlChar *
1747xmlStrcat(xmlChar *cur, const xmlChar *add) {
1748 const xmlChar *p = add;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001749
1750 if (add == NULL) return(cur);
1751 if (cur == NULL)
1752 return(xmlStrdup(add));
1753
1754 while (IS_CHAR(*p)) p++;
1755 return(xmlStrncat(cur, add, p - add));
1756}
1757
1758/************************************************************************
1759 * *
1760 * Commodity functions, cleanup needed ? *
1761 * *
1762 ************************************************************************/
1763
Daniel Veillard11e00581998-10-24 18:27:49 +00001764/**
1765 * areBlanks:
1766 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001767 * @str: a xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001768 * @len: the size of @str
1769 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001770 * Is this a sequence of blank chars that one can ignore ?
Daniel Veillard11e00581998-10-24 18:27:49 +00001771 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001772 * TODO: Whether white space are significant has to be checked accordingly
1773 * to DTD informations if available
Daniel Veillard1e346af1999-02-22 10:33:01 +00001774 *
1775 * Returns 1 if ignorable 0 otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001776 */
1777
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001778static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001779 int i, ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001780 xmlNodePtr lastChild;
1781
1782 for (i = 0;i < len;i++)
1783 if (!(IS_BLANK(str[i]))) return(0);
1784
1785 if (CUR != '<') return(0);
Daniel Veillard517752b1999-04-05 12:20:10 +00001786 if (ctxt->node == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001787 if (ctxt->myDoc != NULL) {
1788 ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name);
1789 if (ret == 0) return(1);
1790 if (ret == 1) return(0);
1791 }
1792 /*
1793 * heuristic
1794 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00001795 lastChild = xmlGetLastChild(ctxt->node);
1796 if (lastChild == NULL) {
1797 if (ctxt->node->content != NULL) return(0);
1798 } else if (xmlNodeIsText(lastChild))
1799 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001800 else if ((ctxt->node->childs != NULL) &&
1801 (xmlNodeIsText(ctxt->node->childs)))
1802 return(0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001803 return(1);
1804}
1805
Daniel Veillard11e00581998-10-24 18:27:49 +00001806/**
1807 * xmlHandleEntity:
1808 * @ctxt: an XML parser context
1809 * @entity: an XML entity pointer.
1810 *
1811 * Default handling of defined entities, when should we define a new input
Daniel Veillard260a68f1998-08-13 03:39:55 +00001812 * stream ? When do we just handle that as a set of chars ?
Daniel Veillardb05deb71999-08-10 19:04:08 +00001813 *
1814 * OBSOLETE: to be removed at some point.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001815 */
1816
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001817void
1818xmlHandleEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001819 int len;
Daniel Veillardccb09631998-10-27 06:21:04 +00001820 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001821
1822 if (entity->content == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001823 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001824 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001825 ctxt->sax->error(ctxt->userData, "xmlHandleEntity %s: content == NULL\n",
Daniel Veillard260a68f1998-08-13 03:39:55 +00001826 entity->name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001827 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001828 return;
1829 }
1830 len = xmlStrlen(entity->content);
1831 if (len <= 2) goto handle_as_char;
1832
1833 /*
1834 * Redefine its content as an input stream.
1835 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001836 input = xmlNewEntityInputStream(ctxt, entity);
1837 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001838 return;
1839
1840handle_as_char:
1841 /*
1842 * Just handle the content as a set of chars.
1843 */
Daniel Veillard517752b1999-04-05 12:20:10 +00001844 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001845 ctxt->sax->characters(ctxt->userData, entity->content, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001846
1847}
1848
1849/*
1850 * Forward definition for recusive behaviour.
1851 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00001852void xmlParsePEReference(xmlParserCtxtPtr ctxt);
1853void xmlParseReference(xmlParserCtxtPtr ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001854
1855/************************************************************************
1856 * *
1857 * Extra stuff for namespace support *
1858 * Relates to http://www.w3.org/TR/WD-xml-names *
1859 * *
1860 ************************************************************************/
1861
Daniel Veillard11e00581998-10-24 18:27:49 +00001862/**
1863 * xmlNamespaceParseNCName:
1864 * @ctxt: an XML parser context
1865 *
1866 * parse an XML namespace name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001867 *
1868 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
1869 *
1870 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
1871 * CombiningChar | Extender
Daniel Veillard1e346af1999-02-22 10:33:01 +00001872 *
1873 * Returns the namespace name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001874 */
1875
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001876xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001877xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001878 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001879 int len = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001880
1881 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001882
1883 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1884 (CUR == '.') || (CUR == '-') ||
1885 (CUR == '_') ||
1886 (IS_COMBINING(CUR)) ||
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001887 (IS_EXTENDER(CUR))) {
1888 buf[len++] = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001889 NEXT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001890 if (len >= XML_MAX_NAMELEN) {
1891 fprintf(stderr,
1892 "xmlNamespaceParseNCName: reached XML_MAX_NAMELEN limit\n");
1893 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1894 (CUR == '.') || (CUR == '-') ||
1895 (CUR == '_') ||
1896 (IS_COMBINING(CUR)) ||
1897 (IS_EXTENDER(CUR)))
1898 NEXT;
1899 break;
1900 }
1901 }
1902 return(xmlStrndup(buf, len));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001903}
1904
Daniel Veillard11e00581998-10-24 18:27:49 +00001905/**
1906 * xmlNamespaceParseQName:
1907 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001908 * @prefix: a xmlChar **
Daniel Veillard11e00581998-10-24 18:27:49 +00001909 *
1910 * parse an XML qualified name
Daniel Veillard260a68f1998-08-13 03:39:55 +00001911 *
1912 * [NS 5] QName ::= (Prefix ':')? LocalPart
1913 *
1914 * [NS 6] Prefix ::= NCName
1915 *
1916 * [NS 7] LocalPart ::= NCName
Daniel Veillard1e346af1999-02-22 10:33:01 +00001917 *
1918 * Returns the function returns the local part, and prefix is updated
Daniel Veillard11e00581998-10-24 18:27:49 +00001919 * to get the Prefix if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001920 */
1921
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001922xmlChar *
1923xmlNamespaceParseQName(xmlParserCtxtPtr ctxt, xmlChar **prefix) {
1924 xmlChar *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001925
1926 *prefix = NULL;
1927 ret = xmlNamespaceParseNCName(ctxt);
1928 if (CUR == ':') {
1929 *prefix = ret;
1930 NEXT;
1931 ret = xmlNamespaceParseNCName(ctxt);
1932 }
1933
1934 return(ret);
1935}
1936
Daniel Veillard11e00581998-10-24 18:27:49 +00001937/**
Daniel Veillard517752b1999-04-05 12:20:10 +00001938 * xmlSplitQName:
1939 * @name: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001940 * @prefix: a xmlChar **
Daniel Veillard517752b1999-04-05 12:20:10 +00001941 *
1942 * parse an XML qualified name string
1943 *
1944 * [NS 5] QName ::= (Prefix ':')? LocalPart
1945 *
1946 * [NS 6] Prefix ::= NCName
1947 *
1948 * [NS 7] LocalPart ::= NCName
1949 *
1950 * Returns the function returns the local part, and prefix is updated
1951 * to get the Prefix if any.
1952 */
1953
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001954xmlChar *
1955xmlSplitQName(const xmlChar *name, xmlChar **prefix) {
1956 xmlChar *ret = NULL;
1957 const xmlChar *q;
1958 const xmlChar *cur = name;
Daniel Veillard517752b1999-04-05 12:20:10 +00001959
1960 *prefix = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001961
1962 /* xml: prefix is not really a namespace */
1963 if ((cur[0] == 'x') && (cur[1] == 'm') &&
1964 (cur[2] == 'l') && (cur[3] == ':'))
1965 return(xmlStrdup(name));
1966
Daniel Veillard517752b1999-04-05 12:20:10 +00001967 if (!IS_LETTER(*cur) && (*cur != '_')) return(NULL);
1968 q = cur++;
1969
1970 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1971 (*cur == '.') || (*cur == '-') ||
1972 (*cur == '_') ||
1973 (IS_COMBINING(*cur)) ||
1974 (IS_EXTENDER(*cur)))
1975 cur++;
1976
1977 ret = xmlStrndup(q, cur - q);
1978
1979 if (*cur == ':') {
1980 cur++;
1981 if (!IS_LETTER(*cur) && (*cur != '_')) return(ret);
1982 *prefix = ret;
1983
1984 q = cur++;
1985
1986 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1987 (*cur == '.') || (*cur == '-') ||
1988 (*cur == '_') ||
1989 (IS_COMBINING(*cur)) ||
1990 (IS_EXTENDER(*cur)))
1991 cur++;
1992
1993 ret = xmlStrndup(q, cur - q);
1994 }
1995
1996 return(ret);
1997}
1998/**
Daniel Veillard11e00581998-10-24 18:27:49 +00001999 * xmlNamespaceParseNSDef:
2000 * @ctxt: an XML parser context
2001 *
2002 * parse a namespace prefix declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00002003 *
2004 * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral
2005 *
2006 * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)?
Daniel Veillard1e346af1999-02-22 10:33:01 +00002007 *
2008 * Returns the namespace name
Daniel Veillard260a68f1998-08-13 03:39:55 +00002009 */
2010
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002011xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002012xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002013 xmlChar *name = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002014
2015 if ((CUR == 'x') && (NXT(1) == 'm') &&
2016 (NXT(2) == 'l') && (NXT(3) == 'n') &&
2017 (NXT(4) == 's')) {
2018 SKIP(5);
2019 if (CUR == ':') {
2020 NEXT;
2021 name = xmlNamespaceParseNCName(ctxt);
2022 }
2023 }
2024 return(name);
2025}
2026
Daniel Veillard11e00581998-10-24 18:27:49 +00002027/**
2028 * xmlParseQuotedString:
2029 * @ctxt: an XML parser context
2030 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002031 * [OLD] Parse and return a string between quotes or doublequotes
Daniel Veillardb05deb71999-08-10 19:04:08 +00002032 * To be removed at next drop of binary compatibility
Daniel Veillard1e346af1999-02-22 10:33:01 +00002033 *
2034 * Returns the string parser or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002035 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002036xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002037xmlParseQuotedString(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002038 xmlChar *ret = NULL;
2039 const xmlChar *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002040
2041 if (CUR == '"') {
2042 NEXT;
2043 q = CUR_PTR;
2044 while (IS_CHAR(CUR) && (CUR != '"')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002045 if (CUR != '"') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002046 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002047 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002048 ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002049 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002050 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002051 ret = xmlStrndup(q, CUR_PTR - q);
2052 NEXT;
2053 }
2054 } else if (CUR == '\''){
2055 NEXT;
2056 q = CUR_PTR;
2057 while (IS_CHAR(CUR) && (CUR != '\'')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002058 if (CUR != '\'') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002059 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002060 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002061 ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002062 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002063 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002064 ret = xmlStrndup(q, CUR_PTR - q);
2065 NEXT;
2066 }
2067 }
2068 return(ret);
2069}
2070
Daniel Veillard11e00581998-10-24 18:27:49 +00002071/**
2072 * xmlParseNamespace:
2073 * @ctxt: an XML parser context
2074 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002075 * [OLD] xmlParseNamespace: parse specific PI '<?namespace ...' constructs.
2076 *
2077 * This is what the older xml-name Working Draft specified, a bunch of
2078 * other stuff may still rely on it, so support is still here as
2079 * if ot was declared on the root of the Tree:-(
Daniel Veillardb05deb71999-08-10 19:04:08 +00002080 *
2081 * To be removed at next drop of binary compatibility
Daniel Veillard260a68f1998-08-13 03:39:55 +00002082 */
2083
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002084void
2085xmlParseNamespace(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002086 xmlChar *href = NULL;
2087 xmlChar *prefix = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002088 int garbage = 0;
2089
2090 /*
2091 * We just skipped "namespace" or "xml:namespace"
2092 */
2093 SKIP_BLANKS;
2094
2095 while (IS_CHAR(CUR) && (CUR != '>')) {
2096 /*
2097 * We can have "ns" or "prefix" attributes
2098 * Old encoding as 'href' or 'AS' attributes is still supported
2099 */
2100 if ((CUR == 'n') && (NXT(1) == 's')) {
2101 garbage = 0;
2102 SKIP(2);
2103 SKIP_BLANKS;
2104
2105 if (CUR != '=') continue;
2106 NEXT;
2107 SKIP_BLANKS;
2108
2109 href = xmlParseQuotedString(ctxt);
2110 SKIP_BLANKS;
2111 } else if ((CUR == 'h') && (NXT(1) == 'r') &&
2112 (NXT(2) == 'e') && (NXT(3) == 'f')) {
2113 garbage = 0;
2114 SKIP(4);
2115 SKIP_BLANKS;
2116
2117 if (CUR != '=') continue;
2118 NEXT;
2119 SKIP_BLANKS;
2120
2121 href = xmlParseQuotedString(ctxt);
2122 SKIP_BLANKS;
2123 } else if ((CUR == 'p') && (NXT(1) == 'r') &&
2124 (NXT(2) == 'e') && (NXT(3) == 'f') &&
2125 (NXT(4) == 'i') && (NXT(5) == 'x')) {
2126 garbage = 0;
2127 SKIP(6);
2128 SKIP_BLANKS;
2129
2130 if (CUR != '=') continue;
2131 NEXT;
2132 SKIP_BLANKS;
2133
2134 prefix = xmlParseQuotedString(ctxt);
2135 SKIP_BLANKS;
2136 } else if ((CUR == 'A') && (NXT(1) == 'S')) {
2137 garbage = 0;
2138 SKIP(2);
2139 SKIP_BLANKS;
2140
2141 if (CUR != '=') continue;
2142 NEXT;
2143 SKIP_BLANKS;
2144
2145 prefix = xmlParseQuotedString(ctxt);
2146 SKIP_BLANKS;
2147 } else if ((CUR == '?') && (NXT(1) == '>')) {
2148 garbage = 0;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002149 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002150 } else {
2151 /*
2152 * Found garbage when parsing the namespace
2153 */
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002154 if (!garbage) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002155 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002156 ctxt->sax->error(ctxt->userData,
2157 "xmlParseNamespace found garbage\n");
2158 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002159 ctxt->errNo = XML_ERR_NS_DECL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002160 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002161 NEXT;
2162 }
2163 }
2164
2165 MOVETO_ENDTAG(CUR_PTR);
2166 NEXT;
2167
2168 /*
2169 * Register the DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002170 if (href != NULL)
Daniel Veillard517752b1999-04-05 12:20:10 +00002171 if ((ctxt->sax != NULL) && (ctxt->sax->globalNamespace != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002172 ctxt->sax->globalNamespace(ctxt->userData, href, prefix);
Daniel Veillard517752b1999-04-05 12:20:10 +00002173 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00002174
Daniel Veillard6454aec1999-09-02 22:04:43 +00002175 if (prefix != NULL) xmlFree(prefix);
2176 if (href != NULL) xmlFree(href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002177}
2178
2179/************************************************************************
2180 * *
2181 * The parser itself *
2182 * Relates to http://www.w3.org/TR/REC-xml *
2183 * *
2184 ************************************************************************/
2185
Daniel Veillard11e00581998-10-24 18:27:49 +00002186/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002187 * xmlScanName:
2188 * @ctxt: an XML parser context
2189 *
2190 * Trickery: parse an XML name but without consuming the input flow
2191 * Needed for rollback cases.
2192 *
2193 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
2194 * CombiningChar | Extender
2195 *
2196 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
2197 *
2198 * [6] Names ::= Name (S Name)*
2199 *
2200 * Returns the Name parsed or NULL
2201 */
2202
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002203xmlChar *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002204xmlScanName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002205 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb05deb71999-08-10 19:04:08 +00002206 int len = 0;
2207
2208 GROW;
2209 if (!IS_LETTER(CUR) && (CUR != '_') &&
2210 (CUR != ':')) {
2211 return(NULL);
2212 }
2213
2214 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
2215 (NXT(len) == '.') || (NXT(len) == '-') ||
2216 (NXT(len) == '_') || (NXT(len) == ':') ||
2217 (IS_COMBINING(NXT(len))) ||
2218 (IS_EXTENDER(NXT(len)))) {
2219 buf[len] = NXT(len);
2220 len++;
2221 if (len >= XML_MAX_NAMELEN) {
2222 fprintf(stderr,
2223 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
2224 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
2225 (NXT(len) == '.') || (NXT(len) == '-') ||
2226 (NXT(len) == '_') || (NXT(len) == ':') ||
2227 (IS_COMBINING(NXT(len))) ||
2228 (IS_EXTENDER(NXT(len))))
2229 len++;
2230 break;
2231 }
2232 }
2233 return(xmlStrndup(buf, len));
2234}
2235
2236/**
Daniel Veillard11e00581998-10-24 18:27:49 +00002237 * xmlParseName:
2238 * @ctxt: an XML parser context
2239 *
2240 * parse an XML name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002241 *
2242 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
2243 * CombiningChar | Extender
2244 *
2245 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
2246 *
2247 * [6] Names ::= Name (S Name)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00002248 *
2249 * Returns the Name parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002250 */
2251
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002252xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002253xmlParseName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002254 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002255 int len = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002256 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002257
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002258 GROW;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002259 cur = CUR;
2260 if (!IS_LETTER(cur) && (cur != '_') &&
2261 (cur != ':')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002262 return(NULL);
2263 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002264
Daniel Veillardb05deb71999-08-10 19:04:08 +00002265 while ((IS_LETTER(cur)) || (IS_DIGIT(cur)) ||
2266 (cur == '.') || (cur == '-') ||
2267 (cur == '_') || (cur == ':') ||
2268 (IS_COMBINING(cur)) ||
2269 (IS_EXTENDER(cur))) {
2270 buf[len++] = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002271 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002272 cur = CUR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002273 if (len >= XML_MAX_NAMELEN) {
2274 fprintf(stderr,
2275 "xmlParseName: reached XML_MAX_NAMELEN limit\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00002276 while ((IS_LETTER(cur)) || (IS_DIGIT(cur)) ||
2277 (cur == '.') || (cur == '-') ||
2278 (cur == '_') || (cur == ':') ||
2279 (IS_COMBINING(cur)) ||
2280 (IS_EXTENDER(cur))) {
2281 NEXT;
2282 cur = CUR;
2283 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002284 break;
2285 }
2286 }
2287 return(xmlStrndup(buf, len));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002288}
2289
Daniel Veillard11e00581998-10-24 18:27:49 +00002290/**
2291 * xmlParseNmtoken:
2292 * @ctxt: an XML parser context
2293 *
2294 * parse an XML Nmtoken.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002295 *
2296 * [7] Nmtoken ::= (NameChar)+
2297 *
2298 * [8] Nmtokens ::= Nmtoken (S Nmtoken)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00002299 *
2300 * Returns the Nmtoken parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002301 */
2302
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002303xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002304xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002305 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002306 int len = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002307
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002308 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002309 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2310 (CUR == '.') || (CUR == '-') ||
2311 (CUR == '_') || (CUR == ':') ||
2312 (IS_COMBINING(CUR)) ||
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002313 (IS_EXTENDER(CUR))) {
2314 buf[len++] = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002315 NEXT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002316 if (len >= XML_MAX_NAMELEN) {
2317 fprintf(stderr,
2318 "xmlParseNmtoken: reached XML_MAX_NAMELEN limit\n");
2319 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2320 (CUR == '.') || (CUR == '-') ||
2321 (CUR == '_') || (CUR == ':') ||
2322 (IS_COMBINING(CUR)) ||
2323 (IS_EXTENDER(CUR)))
2324 NEXT;
2325 break;
2326 }
2327 }
2328 return(xmlStrndup(buf, len));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002329}
2330
Daniel Veillard11e00581998-10-24 18:27:49 +00002331/**
2332 * xmlParseEntityValue:
2333 * @ctxt: an XML parser context
Daniel Veillard011b63c1999-06-02 17:44:04 +00002334 * @orig: if non-NULL store a copy of the original entity value
Daniel Veillard11e00581998-10-24 18:27:49 +00002335 *
2336 * parse a value for ENTITY decl.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002337 *
2338 * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
2339 * "'" ([^%&'] | PEReference | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00002340 *
Daniel Veillard011b63c1999-06-02 17:44:04 +00002341 * Returns the EntityValue parsed with reference substitued or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002342 */
2343
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002344xmlChar *
2345xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) {
2346 xmlChar *ret = NULL;
2347 const xmlChar *org = NULL;
2348 const xmlChar *tst = NULL;
2349 const xmlChar *temp = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002350 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002351
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002352 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002353 if (CUR == '"') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002354 ctxt->instate = XML_PARSER_ENTITY_VALUE;
2355 input = ctxt->input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002356 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002357 org = CUR_PTR;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002358 /*
2359 * NOTE: 4.4.5 Included in Literal
2360 * When a parameter entity reference appears in a literal entity
2361 * value, ... a single or double quote character in the replacement
2362 * text is always treated as a normal data character and will not
2363 * terminate the literal.
2364 * In practice it means we stop the loop only when back at parsing
2365 * the initial entity and the quote is found
2366 */
2367 while ((CUR != '"') || (ctxt->input != input)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002368 tst = CUR_PTR;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002369 /*
2370 * NOTE: 4.4.7 Bypassed
2371 * When a general entity reference appears in the EntityValue in
2372 * an entity declaration, it is bypassed and left as is.
2373 * so XML_SUBSTITUTE_REF is not set.
2374 */
2375 if (ctxt->input != input)
2376 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_PEREF,
2377 0, 0, 0);
2378 else
2379 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_PEREF,
2380 '"', 0, 0);
2381
2382 /*
2383 * Pop-up of finished entities.
2384 */
2385 while ((CUR == 0) && (ctxt->inputNr > 1))
2386 xmlPopInput(ctxt);
2387
2388 if ((temp == NULL) && (tst == CUR_PTR)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002389 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002390 break;
2391 }
2392 if ((temp[0] == 0) && (tst == CUR_PTR)) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00002393 xmlFree((char *)temp);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002394 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002395 break;
2396 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00002397 ret = xmlStrcat(ret, temp);
Daniel Veillard6454aec1999-09-02 22:04:43 +00002398 if (temp != NULL) xmlFree((char *)temp);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002399 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002400 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00002401 if (CUR != '"') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002402 ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002403 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002404 ctxt->sax->error(ctxt->userData, "EntityValue: \" expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002405 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002406 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002407 if (orig != NULL) /* !!!!!!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00002408 *orig = xmlStrndup(org, CUR_PTR - org);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002409 if (ret == NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002410 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002411 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002412 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002413 } else if (CUR == '\'') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002414 ctxt->instate = XML_PARSER_ENTITY_VALUE;
2415 input = ctxt->input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002416 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002417 org = CUR_PTR;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002418 /*
2419 * NOTE: 4.4.5 Included in Literal
2420 * When a parameter entity reference appears in a literal entity
2421 * value, ... a single or double quote character in the replacement
2422 * text is always treated as a normal data character and will not
2423 * terminate the literal.
2424 * In practice it means we stop the loop only when back at parsing
2425 * the initial entity and the quote is found
2426 */
2427 while ((CUR != '\'') || (ctxt->input != input)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002428 tst = CUR_PTR;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002429 /*
2430 * NOTE: 4.4.7 Bypassed
2431 * When a general entity reference appears in the EntityValue in
2432 * an entity declaration, it is bypassed and left as is.
2433 * so XML_SUBSTITUTE_REF is not set.
2434 */
2435 if (ctxt->input != input)
2436 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_PEREF,
2437 0, 0, 0);
2438 else
2439 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_PEREF,
2440 '\'', 0, 0);
2441
2442 /*
2443 * Pop-up of finished entities.
2444 */
2445 while ((CUR == 0) && (ctxt->inputNr > 1))
2446 xmlPopInput(ctxt);
2447
2448 if ((temp == NULL) && (tst == CUR_PTR)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002449 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002450 break;
2451 }
2452 if ((temp[0] == 0) && (tst == CUR_PTR)) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00002453 xmlFree((char *)temp);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002454 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002455 break;
2456 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00002457 ret = xmlStrcat(ret, temp);
Daniel Veillard6454aec1999-09-02 22:04:43 +00002458 if (temp != NULL) xmlFree((char *)temp);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002459 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002460 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00002461 if (CUR != '\'') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002462 ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002463 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002464 ctxt->sax->error(ctxt->userData, "EntityValue: ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002465 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002466 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002467 if (orig != NULL) /* !!!!!!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00002468 *orig = xmlStrndup(org, CUR_PTR - org);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002469 if (ret == NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002470 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002471 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002472 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002473 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002474 ctxt->errNo = XML_ERR_ENTITY_NOT_STARTED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002475 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002476 ctxt->sax->error(ctxt->userData, "EntityValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002477 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002478 }
2479
2480 return(ret);
2481}
2482
Daniel Veillard11e00581998-10-24 18:27:49 +00002483/**
2484 * xmlParseAttValue:
2485 * @ctxt: an XML parser context
2486 *
2487 * parse a value for an attribute
Daniel Veillard011b63c1999-06-02 17:44:04 +00002488 * Note: the parser won't do substitution of entities here, this
Daniel Veillardb96e6431999-08-29 21:02:19 +00002489 * will be handled later in xmlStringGetNodeList
Daniel Veillard260a68f1998-08-13 03:39:55 +00002490 *
2491 * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
2492 * "'" ([^<&'] | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00002493 *
2494 * Returns the AttValue parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002495 */
2496
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002497xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002498xmlParseAttValue(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002499 xmlChar *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002500
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002501 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002502 if (CUR == '"') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002503 ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002504 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002505 ret = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_REF, '"', '<', 0);
Daniel Veillard011b63c1999-06-02 17:44:04 +00002506 if (CUR == '<') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002507 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002508 ctxt->sax->error(ctxt->userData,
2509 "Unescaped '<' not allowed in attributes values\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002510 ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002511 ctxt->wellFormed = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002512 }
2513 if (CUR != '"') {
2514 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2515 ctxt->sax->error(ctxt->userData, "AttValue: ' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002516 ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002517 ctxt->wellFormed = 0;
2518 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00002519 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002520 } else if (CUR == '\'') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002521 ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002522 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002523 ret = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_REF, '\'', '<', 0);
Daniel Veillard011b63c1999-06-02 17:44:04 +00002524 if (CUR == '<') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002525 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002526 ctxt->sax->error(ctxt->userData,
2527 "Unescaped '<' not allowed in attributes values\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002528 ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002529 ctxt->wellFormed = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002530 }
2531 if (CUR != '\'') {
2532 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2533 ctxt->sax->error(ctxt->userData, "AttValue: ' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002534 ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002535 ctxt->wellFormed = 0;
2536 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00002537 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002538 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002539 ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_STARTED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002540 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002541 ctxt->sax->error(ctxt->userData, "AttValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002542 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002543 }
2544
2545 return(ret);
2546}
2547
Daniel Veillard11e00581998-10-24 18:27:49 +00002548/**
2549 * xmlParseSystemLiteral:
2550 * @ctxt: an XML parser context
2551 *
2552 * parse an XML Literal
Daniel Veillard260a68f1998-08-13 03:39:55 +00002553 *
2554 * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
Daniel Veillard1e346af1999-02-22 10:33:01 +00002555 *
2556 * Returns the SystemLiteral parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002557 */
2558
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002559xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002560xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002561 const xmlChar *q;
2562 xmlChar *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002563
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002564 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002565 if (CUR == '"') {
2566 NEXT;
2567 q = CUR_PTR;
2568 while ((IS_CHAR(CUR)) && (CUR != '"'))
2569 NEXT;
2570 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002571 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002572 ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002573 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002574 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002575 } else {
2576 ret = xmlStrndup(q, CUR_PTR - q);
2577 NEXT;
2578 }
2579 } else if (CUR == '\'') {
2580 NEXT;
2581 q = CUR_PTR;
2582 while ((IS_CHAR(CUR)) && (CUR != '\''))
2583 NEXT;
2584 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002585 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002586 ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002587 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002588 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002589 } else {
2590 ret = xmlStrndup(q, CUR_PTR - q);
2591 NEXT;
2592 }
2593 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002594 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002595 ctxt->sax->error(ctxt->userData,
2596 "SystemLiteral \" or ' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002597 ctxt->errNo = XML_ERR_LITERAL_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002598 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002599 }
2600
2601 return(ret);
2602}
2603
Daniel Veillard11e00581998-10-24 18:27:49 +00002604/**
2605 * xmlParsePubidLiteral:
2606 * @ctxt: an XML parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +00002607 *
Daniel Veillard11e00581998-10-24 18:27:49 +00002608 * parse an XML public literal
Daniel Veillard1e346af1999-02-22 10:33:01 +00002609 *
2610 * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
2611 *
2612 * Returns the PubidLiteral parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002613 */
2614
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002615xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002616xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002617 const xmlChar *q;
2618 xmlChar *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002619 /*
2620 * Name ::= (Letter | '_') (NameChar)*
2621 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002622 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002623 if (CUR == '"') {
2624 NEXT;
2625 q = CUR_PTR;
2626 while (IS_PUBIDCHAR(CUR)) NEXT;
2627 if (CUR != '"') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002628 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002629 ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002630 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002631 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002632 } else {
2633 ret = xmlStrndup(q, CUR_PTR - q);
2634 NEXT;
2635 }
2636 } else if (CUR == '\'') {
2637 NEXT;
2638 q = CUR_PTR;
2639 while ((IS_LETTER(CUR)) && (CUR != '\''))
2640 NEXT;
2641 if (!IS_LETTER(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002642 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002643 ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002644 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002645 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002646 } else {
2647 ret = xmlStrndup(q, CUR_PTR - q);
2648 NEXT;
2649 }
2650 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002651 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002652 ctxt->sax->error(ctxt->userData,
2653 "SystemLiteral \" or ' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002654 ctxt->errNo = XML_ERR_LITERAL_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002655 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002656 }
2657
2658 return(ret);
2659}
2660
Daniel Veillard11e00581998-10-24 18:27:49 +00002661/**
2662 * xmlParseCharData:
2663 * @ctxt: an XML parser context
2664 * @cdata: int indicating whether we are within a CDATA section
2665 *
2666 * parse a CharData section.
2667 * if we are within a CDATA section ']]>' marks an end of section.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002668 *
2669 * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
2670 */
2671
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002672void
2673xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002674 xmlChar buf[1000];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002675 int nbchar = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002676 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002677
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002678 SHRINK;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002679 /*
2680 * !!!!!!!!!!!!
2681 * NOTE: NXT(0) is used here to avoid breaking on &lt; or &amp;
2682 * entities substitutions.
2683 */
2684 cur = CUR;
2685 while ((IS_CHAR(cur)) && (cur != '<') &&
2686 (cur != '&')) {
2687 if ((cur == ']') && (NXT(1) == ']') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002688 (NXT(2) == '>')) {
2689 if (cdata) break;
2690 else {
2691 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002692 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002693 "Sequence ']]>' not allowed in content\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002694 ctxt->errNo = XML_ERR_MISPLACED_CDATA_END;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002695 ctxt->wellFormed = 0;
2696 }
2697 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002698 buf[nbchar++] = CUR;
2699 if (nbchar == 1000) {
2700 /*
2701 * Ok the segment is to be consumed as chars.
2702 */
2703 if (ctxt->sax != NULL) {
2704 if (areBlanks(ctxt, buf, nbchar)) {
2705 if (ctxt->sax->ignorableWhitespace != NULL)
2706 ctxt->sax->ignorableWhitespace(ctxt->userData,
2707 buf, nbchar);
2708 } else {
2709 if (ctxt->sax->characters != NULL)
2710 ctxt->sax->characters(ctxt->userData, buf, nbchar);
2711 }
2712 }
2713 nbchar = 0;
2714 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002715 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002716 cur = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002717 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002718 if (nbchar != 0) {
2719 /*
2720 * Ok the segment is to be consumed as chars.
2721 */
2722 if (ctxt->sax != NULL) {
2723 if (areBlanks(ctxt, buf, nbchar)) {
2724 if (ctxt->sax->ignorableWhitespace != NULL)
2725 ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar);
2726 } else {
2727 if (ctxt->sax->characters != NULL)
2728 ctxt->sax->characters(ctxt->userData, buf, nbchar);
2729 }
2730 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002731 }
2732}
2733
Daniel Veillard11e00581998-10-24 18:27:49 +00002734/**
2735 * xmlParseExternalID:
2736 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002737 * @publicID: a xmlChar** receiving PubidLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00002738 * @strict: indicate whether we should restrict parsing to only
2739 * production [75], see NOTE below
Daniel Veillard11e00581998-10-24 18:27:49 +00002740 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00002741 * Parse an External ID or a Public ID
2742 *
2743 * NOTE: Productions [75] and [83] interract badly since [75] can generate
2744 * 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard260a68f1998-08-13 03:39:55 +00002745 *
2746 * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
2747 * | 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00002748 *
2749 * [83] PublicID ::= 'PUBLIC' S PubidLiteral
2750 *
2751 * Returns the function returns SystemLiteral and in the second
2752 * case publicID receives PubidLiteral, is strict is off
2753 * it is possible to return NULL and have publicID set.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002754 */
2755
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002756xmlChar *
2757xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) {
2758 xmlChar *URI = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002759
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002760 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002761 if ((CUR == 'S') && (NXT(1) == 'Y') &&
2762 (NXT(2) == 'S') && (NXT(3) == 'T') &&
2763 (NXT(4) == 'E') && (NXT(5) == 'M')) {
2764 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002765 if (!IS_BLANK(CUR)) {
2766 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002767 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002768 "Space required after 'SYSTEM'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002769 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002770 ctxt->wellFormed = 0;
2771 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002772 SKIP_BLANKS;
2773 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002774 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002775 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002776 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002777 "xmlParseExternalID: SYSTEM, no URI\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002778 ctxt->errNo = XML_ERR_URI_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002779 ctxt->wellFormed = 0;
2780 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002781 } else if ((CUR == 'P') && (NXT(1) == 'U') &&
2782 (NXT(2) == 'B') && (NXT(3) == 'L') &&
2783 (NXT(4) == 'I') && (NXT(5) == 'C')) {
2784 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002785 if (!IS_BLANK(CUR)) {
2786 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002787 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002788 "Space required after 'PUBLIC'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002789 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002790 ctxt->wellFormed = 0;
2791 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002792 SKIP_BLANKS;
2793 *publicID = xmlParsePubidLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002794 if (*publicID == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002795 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002796 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002797 "xmlParseExternalID: PUBLIC, no Public Identifier\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002798 ctxt->errNo = XML_ERR_PUBID_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002799 ctxt->wellFormed = 0;
2800 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002801 if (strict) {
2802 /*
2803 * We don't handle [83] so "S SystemLiteral" is required.
2804 */
2805 if (!IS_BLANK(CUR)) {
2806 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002807 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002808 "Space required after the Public Identifier\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002809 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00002810 ctxt->wellFormed = 0;
2811 }
2812 } else {
2813 /*
2814 * We handle [83] so we return immediately, if
2815 * "S SystemLiteral" is not detected. From a purely parsing
2816 * point of view that's a nice mess.
2817 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002818 const xmlChar *ptr = CUR_PTR;
Daniel Veillard1e346af1999-02-22 10:33:01 +00002819 if (!IS_BLANK(*ptr)) return(NULL);
2820
2821 while (IS_BLANK(*ptr)) ptr++;
2822 if ((*ptr != '\'') || (*ptr != '"')) return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002823 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002824 SKIP_BLANKS;
2825 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002826 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002827 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002828 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002829 "xmlParseExternalID: PUBLIC, no URI\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002830 ctxt->errNo = XML_ERR_URI_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002831 ctxt->wellFormed = 0;
2832 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002833 }
2834 return(URI);
2835}
2836
Daniel Veillard11e00581998-10-24 18:27:49 +00002837/**
2838 * xmlParseComment:
Daniel Veillard1e346af1999-02-22 10:33:01 +00002839 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002840 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002841 * Skip an XML (SGML) comment <!-- .... -->
Daniel Veillard260a68f1998-08-13 03:39:55 +00002842 * The spec says that "For compatibility, the string "--" (double-hyphen)
2843 * must not occur within comments. "
2844 *
2845 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
2846 */
Daniel Veillard517752b1999-04-05 12:20:10 +00002847void
Daniel Veillardb96e6431999-08-29 21:02:19 +00002848xmlParseComment(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002849 const xmlChar *q, *start;
2850 const xmlChar *r;
2851 xmlChar *val;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002852
2853 /*
2854 * Check that there is a comment right here.
2855 */
2856 if ((CUR != '<') || (NXT(1) != '!') ||
Daniel Veillard517752b1999-04-05 12:20:10 +00002857 (NXT(2) != '-') || (NXT(3) != '-')) return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002858
Daniel Veillardb05deb71999-08-10 19:04:08 +00002859 ctxt->instate = XML_PARSER_COMMENT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002860 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002861 SKIP(4);
2862 start = q = CUR_PTR;
2863 NEXT;
2864 r = CUR_PTR;
2865 NEXT;
2866 while (IS_CHAR(CUR) &&
2867 ((CUR == ':') || (CUR != '>') ||
2868 (*r != '-') || (*q != '-'))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002869 if ((*r == '-') && (*q == '-')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002870 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002871 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002872 "Comment must not contain '--' (double-hyphen)`\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002873 ctxt->errNo = XML_ERR_HYPHEN_IN_COMMENT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002874 ctxt->wellFormed = 0;
2875 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002876 NEXT;r++;q++;
2877 }
2878 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002879 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002880 ctxt->sax->error(ctxt->userData,
2881 "Comment not terminated \n<!--%.50s\n", start);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002882 ctxt->errNo = XML_ERR_COMMENT_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002883 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002884 } else {
2885 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002886 val = xmlStrndup(start, q - start);
2887 if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL))
2888 ctxt->sax->comment(ctxt->userData, val);
Daniel Veillard6454aec1999-09-02 22:04:43 +00002889 xmlFree(val);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002890 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002891}
2892
Daniel Veillard11e00581998-10-24 18:27:49 +00002893/**
2894 * xmlParsePITarget:
2895 * @ctxt: an XML parser context
2896 *
2897 * parse the name of a PI
Daniel Veillard260a68f1998-08-13 03:39:55 +00002898 *
2899 * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00002900 *
2901 * Returns the PITarget name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002902 */
2903
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002904xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002905xmlParsePITarget(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002906 xmlChar *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002907
2908 name = xmlParseName(ctxt);
2909 if ((name != NULL) && (name[3] == 0) &&
2910 ((name[0] == 'x') || (name[0] == 'X')) &&
2911 ((name[1] == 'm') || (name[1] == 'M')) &&
2912 ((name[2] == 'l') || (name[2] == 'L'))) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002913 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
2914 ctxt->sax->error(ctxt->userData,
2915 "xmlParsePItarget: invalid name prefix 'xml'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002916 ctxt->errNo = XML_ERR_RESERVED_XML_NAME;
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002917 /* ctxt->wellFormed = 0; !!! ? */
2918 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002919 return(NULL);
2920 }
2921 return(name);
2922}
2923
Daniel Veillard11e00581998-10-24 18:27:49 +00002924/**
2925 * xmlParsePI:
2926 * @ctxt: an XML parser context
2927 *
2928 * parse an XML Processing Instruction.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002929 *
2930 * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
Daniel Veillard1e346af1999-02-22 10:33:01 +00002931 *
2932 * The processing is transfered to SAX once parsed.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002933 */
2934
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002935void
2936xmlParsePI(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002937 xmlChar *target;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002938
2939 if ((CUR == '<') && (NXT(1) == '?')) {
2940 /*
2941 * this is a Processing Instruction.
2942 */
2943 SKIP(2);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002944 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002945
2946 /*
2947 * Parse the target name and check for special support like
2948 * namespace.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002949 */
2950 target = xmlParsePITarget(ctxt);
2951 if (target != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002952 const xmlChar *q;
Daniel Veillard517752b1999-04-05 12:20:10 +00002953
Daniel Veillardb96e6431999-08-29 21:02:19 +00002954 if (!IS_BLANK(CUR)) {
2955 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2956 ctxt->sax->error(ctxt->userData,
2957 "xmlParsePI: PI %s space expected\n", target);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002958 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002959 ctxt->wellFormed = 0;
2960 }
2961 SKIP_BLANKS;
2962 q = CUR_PTR;
Daniel Veillard517752b1999-04-05 12:20:10 +00002963 while (IS_CHAR(CUR) &&
2964 ((CUR != '?') || (NXT(1) != '>')))
2965 NEXT;
2966 if (!IS_CHAR(CUR)) {
2967 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002968 ctxt->sax->error(ctxt->userData,
Daniel Veillard517752b1999-04-05 12:20:10 +00002969 "xmlParsePI: PI %s never end ...\n", target);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002970 ctxt->errNo = XML_ERR_PI_NOT_FINISHED;
Daniel Veillard517752b1999-04-05 12:20:10 +00002971 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002972 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002973 xmlChar *data;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002974
Daniel Veillard517752b1999-04-05 12:20:10 +00002975 data = xmlStrndup(q, CUR_PTR - q);
2976 SKIP(2);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002977
Daniel Veillard517752b1999-04-05 12:20:10 +00002978 /*
2979 * SAX: PI detected.
2980 */
2981 if ((ctxt->sax) &&
2982 (ctxt->sax->processingInstruction != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002983 ctxt->sax->processingInstruction(ctxt->userData,
2984 target, data);
Daniel Veillard6454aec1999-09-02 22:04:43 +00002985 xmlFree(data);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002986 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00002987 xmlFree(target);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002988 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002989 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002990 ctxt->sax->error(ctxt->userData,
2991 "xmlParsePI : no target name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002992 ctxt->errNo = XML_ERR_PI_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002993 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002994 }
2995 }
2996}
2997
Daniel Veillard11e00581998-10-24 18:27:49 +00002998/**
2999 * xmlParseNotationDecl:
3000 * @ctxt: an XML parser context
3001 *
3002 * parse a notation declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003003 *
3004 * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
3005 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00003006 * Hence there is actually 3 choices:
3007 * 'PUBLIC' S PubidLiteral
3008 * 'PUBLIC' S PubidLiteral S SystemLiteral
3009 * and 'SYSTEM' S SystemLiteral
Daniel Veillard11e00581998-10-24 18:27:49 +00003010 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003011 * See the NOTE on xmlParseExternalID().
Daniel Veillard260a68f1998-08-13 03:39:55 +00003012 */
3013
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003014void
3015xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003016 xmlChar *name;
3017 xmlChar *Pubid;
3018 xmlChar *Systemid;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003019
3020 if ((CUR == '<') && (NXT(1) == '!') &&
3021 (NXT(2) == 'N') && (NXT(3) == 'O') &&
3022 (NXT(4) == 'T') && (NXT(5) == 'A') &&
3023 (NXT(6) == 'T') && (NXT(7) == 'I') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00003024 (NXT(8) == 'O') && (NXT(9) == 'N')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003025 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003026 SKIP(10);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003027 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003028 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003029 ctxt->sax->error(ctxt->userData,
3030 "Space required after '<!NOTATION'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003031 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003032 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003033 return;
3034 }
3035 SKIP_BLANKS;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003036
3037 name = xmlParseName(ctxt);
3038 if (name == NULL) {
3039 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003040 ctxt->sax->error(ctxt->userData,
3041 "NOTATION: Name expected here\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003042 ctxt->errNo = XML_ERR_NOTATION_NOT_STARTED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003043 ctxt->wellFormed = 0;
3044 return;
3045 }
3046 if (!IS_BLANK(CUR)) {
3047 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003048 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003049 "Space required after the NOTATION name'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003050 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003051 ctxt->wellFormed = 0;
3052 return;
3053 }
3054 SKIP_BLANKS;
3055
Daniel Veillard260a68f1998-08-13 03:39:55 +00003056 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00003057 * Parse the IDs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003058 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00003059 Systemid = xmlParseExternalID(ctxt, &Pubid, 1);
3060 SKIP_BLANKS;
3061
3062 if (CUR == '>') {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003063 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00003064 if ((ctxt->sax != NULL) && (ctxt->sax->notationDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003065 ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003066 } else {
3067 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003068 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003069 "'>' required to close NOTATION declaration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003070 ctxt->errNo = XML_ERR_NOTATION_NOT_FINISHED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003071 ctxt->wellFormed = 0;
3072 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00003073 xmlFree(name);
3074 if (Systemid != NULL) xmlFree(Systemid);
3075 if (Pubid != NULL) xmlFree(Pubid);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003076 }
3077}
3078
Daniel Veillard11e00581998-10-24 18:27:49 +00003079/**
3080 * xmlParseEntityDecl:
3081 * @ctxt: an XML parser context
3082 *
3083 * parse <!ENTITY declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00003084 *
3085 * [70] EntityDecl ::= GEDecl | PEDecl
3086 *
3087 * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
3088 *
3089 * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
3090 *
3091 * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
3092 *
3093 * [74] PEDef ::= EntityValue | ExternalID
3094 *
3095 * [76] NDataDecl ::= S 'NDATA' S Name
Daniel Veillardb05deb71999-08-10 19:04:08 +00003096 *
3097 * [ VC: Notation Declared ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003098 * The Name must match the declared name of a notation.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003099 */
3100
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003101void
3102xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003103 xmlChar *name = NULL;
3104 xmlChar *value = NULL;
3105 xmlChar *URI = NULL, *literal = NULL;
3106 xmlChar *ndata = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003107 int isParameter = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003108 xmlChar *orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003109
Daniel Veillardb05deb71999-08-10 19:04:08 +00003110 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003111 if ((CUR == '<') && (NXT(1) == '!') &&
3112 (NXT(2) == 'E') && (NXT(3) == 'N') &&
3113 (NXT(4) == 'T') && (NXT(5) == 'I') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003114 (NXT(6) == 'T') && (NXT(7) == 'Y')) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003115 ctxt->instate = XML_PARSER_ENTITY_DECL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003116 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003117 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003118 if (!IS_BLANK(CUR)) {
3119 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003120 ctxt->sax->error(ctxt->userData,
3121 "Space required after '<!ENTITY'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003122 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003123 ctxt->wellFormed = 0;
3124 }
3125 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003126
3127 if (CUR == '%') {
3128 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003129 if (!IS_BLANK(CUR)) {
3130 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003131 ctxt->sax->error(ctxt->userData,
3132 "Space required after '%'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003133 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003134 ctxt->wellFormed = 0;
3135 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003136 SKIP_BLANKS;
3137 isParameter = 1;
3138 }
3139
3140 name = xmlParseName(ctxt);
3141 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003142 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003143 ctxt->sax->error(ctxt->userData, "xmlParseEntityDecl: no name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003144 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003145 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003146 return;
3147 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003148 if (!IS_BLANK(CUR)) {
3149 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003150 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003151 "Space required after the entity name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003152 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003153 ctxt->wellFormed = 0;
3154 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003155 SKIP_BLANKS;
3156
3157 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00003158 * handle the various case of definitions...
Daniel Veillard260a68f1998-08-13 03:39:55 +00003159 */
3160 if (isParameter) {
3161 if ((CUR == '"') || (CUR == '\''))
Daniel Veillard011b63c1999-06-02 17:44:04 +00003162 value = xmlParseEntityValue(ctxt, &orig);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003163 if (value) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003164 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003165 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003166 XML_INTERNAL_PARAMETER_ENTITY,
3167 NULL, NULL, value);
3168 }
3169 else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00003170 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003171 if (URI) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003172 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003173 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003174 XML_EXTERNAL_PARAMETER_ENTITY,
3175 literal, URI, NULL);
3176 }
3177 }
3178 } else {
3179 if ((CUR == '"') || (CUR == '\'')) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00003180 value = xmlParseEntityValue(ctxt, &orig);
Daniel Veillard517752b1999-04-05 12:20:10 +00003181 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003182 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003183 XML_INTERNAL_GENERAL_ENTITY,
3184 NULL, NULL, value);
3185 } else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00003186 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003187 if ((CUR != '>') && (!IS_BLANK(CUR))) {
3188 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003189 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003190 "Space required before 'NDATA'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003191 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003192 ctxt->wellFormed = 0;
3193 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003194 SKIP_BLANKS;
3195 if ((CUR == 'N') && (NXT(1) == 'D') &&
3196 (NXT(2) == 'A') && (NXT(3) == 'T') &&
3197 (NXT(4) == 'A')) {
3198 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003199 if (!IS_BLANK(CUR)) {
3200 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003201 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003202 "Space required after 'NDATA'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003203 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003204 ctxt->wellFormed = 0;
3205 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003206 SKIP_BLANKS;
3207 ndata = xmlParseName(ctxt);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003208 if ((ctxt->sax != NULL) &&
3209 (ctxt->sax->unparsedEntityDecl != NULL))
3210 ctxt->sax->unparsedEntityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003211 literal, URI, ndata);
3212 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00003213 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003214 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003215 XML_EXTERNAL_GENERAL_PARSED_ENTITY,
3216 literal, URI, NULL);
3217 }
3218 }
3219 }
3220 SKIP_BLANKS;
3221 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003222 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003223 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003224 "xmlParseEntityDecl: entity %s not terminated\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003225 ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003226 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003227 } else
3228 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00003229 if (orig != NULL) {
3230 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00003231 * Ugly mechanism to save the raw entity value.
Daniel Veillard011b63c1999-06-02 17:44:04 +00003232 */
3233 xmlEntityPtr cur = NULL;
3234
Daniel Veillardb05deb71999-08-10 19:04:08 +00003235 if (isParameter) {
3236 if ((ctxt->sax != NULL) &&
3237 (ctxt->sax->getParameterEntity != NULL))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003238 cur = ctxt->sax->getParameterEntity(ctxt->userData, name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003239 } else {
3240 if ((ctxt->sax != NULL) &&
3241 (ctxt->sax->getEntity != NULL))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003242 cur = ctxt->sax->getEntity(ctxt->userData, name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003243 }
3244 if (cur != NULL) {
3245 if (cur->orig != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003246 xmlFree(orig);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003247 else
3248 cur->orig = orig;
3249 } else
Daniel Veillard6454aec1999-09-02 22:04:43 +00003250 xmlFree(orig);
Daniel Veillard011b63c1999-06-02 17:44:04 +00003251 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00003252 if (name != NULL) xmlFree(name);
3253 if (value != NULL) xmlFree(value);
3254 if (URI != NULL) xmlFree(URI);
3255 if (literal != NULL) xmlFree(literal);
3256 if (ndata != NULL) xmlFree(ndata);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003257 }
3258}
3259
Daniel Veillard11e00581998-10-24 18:27:49 +00003260/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003261 * xmlParseDefaultDecl:
3262 * @ctxt: an XML parser context
3263 * @value: Receive a possible fixed default value for the attribute
3264 *
3265 * Parse an attribute default declaration
3266 *
3267 * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
3268 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003269 * [ VC: Required Attribute ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003270 * if the default declaration is the keyword #REQUIRED, then the
3271 * attribute must be specified for all elements of the type in the
3272 * attribute-list declaration.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003273 *
3274 * [ VC: Attribute Default Legal ]
3275 * The declared default value must meet the lexical constraints of
3276 * the declared attribute type c.f. xmlValidateAttributeDecl()
3277 *
3278 * [ VC: Fixed Attribute Default ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003279 * if an attribute has a default value declared with the #FIXED
3280 * keyword, instances of that attribute must match the default value.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003281 *
3282 * [ WFC: No < in Attribute Values ]
3283 * handled in xmlParseAttValue()
3284 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003285 * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
3286 * or XML_ATTRIBUTE_FIXED.
3287 */
3288
3289int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003290xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003291 int val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003292 xmlChar *ret;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003293
3294 *value = NULL;
3295 if ((CUR == '#') && (NXT(1) == 'R') &&
3296 (NXT(2) == 'E') && (NXT(3) == 'Q') &&
3297 (NXT(4) == 'U') && (NXT(5) == 'I') &&
3298 (NXT(6) == 'R') && (NXT(7) == 'E') &&
3299 (NXT(8) == 'D')) {
3300 SKIP(9);
3301 return(XML_ATTRIBUTE_REQUIRED);
3302 }
3303 if ((CUR == '#') && (NXT(1) == 'I') &&
3304 (NXT(2) == 'M') && (NXT(3) == 'P') &&
3305 (NXT(4) == 'L') && (NXT(5) == 'I') &&
3306 (NXT(6) == 'E') && (NXT(7) == 'D')) {
3307 SKIP(8);
3308 return(XML_ATTRIBUTE_IMPLIED);
3309 }
3310 val = XML_ATTRIBUTE_NONE;
3311 if ((CUR == '#') && (NXT(1) == 'F') &&
3312 (NXT(2) == 'I') && (NXT(3) == 'X') &&
3313 (NXT(4) == 'E') && (NXT(5) == 'D')) {
3314 SKIP(6);
3315 val = XML_ATTRIBUTE_FIXED;
3316 if (!IS_BLANK(CUR)) {
3317 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003318 ctxt->sax->error(ctxt->userData,
3319 "Space required after '#FIXED'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003320 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003321 ctxt->wellFormed = 0;
3322 }
3323 SKIP_BLANKS;
3324 }
3325 ret = xmlParseAttValue(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003326 ctxt->instate = XML_PARSER_DTD;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003327 if (ret == NULL) {
3328 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003329 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003330 "Attribute default value declaration error\n");
3331 ctxt->wellFormed = 0;
3332 } else
3333 *value = ret;
3334 return(val);
3335}
3336
3337/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00003338 * xmlParseNotationType:
3339 * @ctxt: an XML parser context
3340 *
3341 * parse an Notation attribute type.
3342 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003343 * Note: the leading 'NOTATION' S part has already being parsed...
3344 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003345 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
3346 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003347 * [ VC: Notation Attributes ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003348 * Values of this type must match one of the notation names included
Daniel Veillardb05deb71999-08-10 19:04:08 +00003349 * in the declaration; all notation names in the declaration must be declared.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003350 *
3351 * Returns: the notation attribute tree built while parsing
3352 */
3353
3354xmlEnumerationPtr
3355xmlParseNotationType(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003356 xmlChar *name;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003357 xmlEnumerationPtr ret = NULL, last = NULL, cur;
3358
3359 if (CUR != '(') {
3360 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003361 ctxt->sax->error(ctxt->userData,
3362 "'(' required to start 'NOTATION'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003363 ctxt->errNo = XML_ERR_NOTATION_NOT_STARTED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003364 ctxt->wellFormed = 0;
3365 return(NULL);
3366 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003367 SHRINK;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003368 do {
3369 NEXT;
3370 SKIP_BLANKS;
3371 name = xmlParseName(ctxt);
3372 if (name == NULL) {
3373 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003374 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003375 "Name expected in NOTATION declaration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003376 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003377 ctxt->wellFormed = 0;
3378 return(ret);
3379 }
3380 cur = xmlCreateEnumeration(name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003381 xmlFree(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003382 if (cur == NULL) return(ret);
3383 if (last == NULL) ret = last = cur;
3384 else {
3385 last->next = cur;
3386 last = cur;
3387 }
3388 SKIP_BLANKS;
3389 } while (CUR == '|');
3390 if (CUR != ')') {
3391 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003392 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003393 "')' required to finish NOTATION declaration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003394 ctxt->errNo = XML_ERR_NOTATION_NOT_FINISHED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003395 ctxt->wellFormed = 0;
3396 return(ret);
3397 }
3398 NEXT;
3399 return(ret);
3400}
3401
3402/**
3403 * xmlParseEnumerationType:
3404 * @ctxt: an XML parser context
3405 *
3406 * parse an Enumeration attribute type.
3407 *
3408 * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
3409 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003410 * [ VC: Enumeration ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003411 * Values of this type must match one of the Nmtoken tokens in
Daniel Veillardb05deb71999-08-10 19:04:08 +00003412 * the declaration
3413 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003414 * Returns: the enumeration attribute tree built while parsing
3415 */
3416
3417xmlEnumerationPtr
3418xmlParseEnumerationType(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003419 xmlChar *name;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003420 xmlEnumerationPtr ret = NULL, last = NULL, cur;
3421
3422 if (CUR != '(') {
3423 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003424 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003425 "'(' required to start ATTLIST enumeration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003426 ctxt->errNo = XML_ERR_ATTLIST_NOT_STARTED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003427 ctxt->wellFormed = 0;
3428 return(NULL);
3429 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003430 SHRINK;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003431 do {
3432 NEXT;
3433 SKIP_BLANKS;
3434 name = xmlParseNmtoken(ctxt);
3435 if (name == NULL) {
3436 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003437 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003438 "NmToken expected in ATTLIST enumeration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003439 ctxt->errNo = XML_ERR_NMTOKEN_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003440 ctxt->wellFormed = 0;
3441 return(ret);
3442 }
3443 cur = xmlCreateEnumeration(name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003444 xmlFree(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003445 if (cur == NULL) return(ret);
3446 if (last == NULL) ret = last = cur;
3447 else {
3448 last->next = cur;
3449 last = cur;
3450 }
3451 SKIP_BLANKS;
3452 } while (CUR == '|');
3453 if (CUR != ')') {
3454 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003455 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003456 "')' required to finish ATTLIST enumeration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003457 ctxt->errNo = XML_ERR_ATTLIST_NOT_FINISHED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003458 ctxt->wellFormed = 0;
3459 return(ret);
3460 }
3461 NEXT;
3462 return(ret);
3463}
3464
3465/**
Daniel Veillard11e00581998-10-24 18:27:49 +00003466 * xmlParseEnumeratedType:
3467 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00003468 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00003469 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003470 * parse an Enumerated attribute type.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003471 *
3472 * [57] EnumeratedType ::= NotationType | Enumeration
3473 *
3474 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
3475 *
Daniel Veillard11e00581998-10-24 18:27:49 +00003476 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003477 * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION
Daniel Veillard260a68f1998-08-13 03:39:55 +00003478 */
3479
Daniel Veillard1e346af1999-02-22 10:33:01 +00003480int
3481xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
3482 if ((CUR == 'N') && (NXT(1) == 'O') &&
3483 (NXT(2) == 'T') && (NXT(3) == 'A') &&
3484 (NXT(4) == 'T') && (NXT(5) == 'I') &&
3485 (NXT(6) == 'O') && (NXT(7) == 'N')) {
3486 SKIP(8);
3487 if (!IS_BLANK(CUR)) {
3488 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003489 ctxt->sax->error(ctxt->userData,
3490 "Space required after 'NOTATION'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003491 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003492 ctxt->wellFormed = 0;
3493 return(0);
3494 }
3495 SKIP_BLANKS;
3496 *tree = xmlParseNotationType(ctxt);
3497 if (*tree == NULL) return(0);
3498 return(XML_ATTRIBUTE_NOTATION);
3499 }
3500 *tree = xmlParseEnumerationType(ctxt);
3501 if (*tree == NULL) return(0);
3502 return(XML_ATTRIBUTE_ENUMERATION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003503}
3504
Daniel Veillard11e00581998-10-24 18:27:49 +00003505/**
3506 * xmlParseAttributeType:
3507 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00003508 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00003509 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003510 * parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00003511 *
3512 * [54] AttType ::= StringType | TokenizedType | EnumeratedType
3513 *
3514 * [55] StringType ::= 'CDATA'
3515 *
3516 * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
3517 * 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
Daniel Veillard11e00581998-10-24 18:27:49 +00003518 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003519 * Validity constraints for attribute values syntax are checked in
3520 * xmlValidateAttributeValue()
3521 *
3522 * [ VC: ID ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003523 * Values of type ID must match the Name production. A name must not
Daniel Veillardb05deb71999-08-10 19:04:08 +00003524 * appear more than once in an XML document as a value of this type;
3525 * i.e., ID values must uniquely identify the elements which bear them.
3526 *
3527 * [ VC: One ID per Element Type ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003528 * No element type may have more than one ID attribute specified.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003529 *
3530 * [ VC: ID Attribute Default ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003531 * An ID attribute must have a declared default of #IMPLIED or #REQUIRED.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003532 *
3533 * [ VC: IDREF ]
3534 * Values of type IDREF must match the Name production, and values
Daniel Veillardb96e6431999-08-29 21:02:19 +00003535 * of type IDREFS must match Names; TODO each IDREF Name must match the value
3536 * of an ID attribute on some element in the XML document; i.e. IDREF
Daniel Veillardb05deb71999-08-10 19:04:08 +00003537 * values must match the value of some ID attribute.
3538 *
3539 * [ VC: Entity Name ]
3540 * Values of type ENTITY must match the Name production, values
Daniel Veillardb96e6431999-08-29 21:02:19 +00003541 * of type ENTITIES must match Names; TODO each Entity Name must match the
3542 * name of an unparsed entity declared in the DTD.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003543 *
3544 * [ VC: Name Token ]
3545 * Values of type NMTOKEN must match the Nmtoken production; values
3546 * of type NMTOKENS must match Nmtokens.
3547 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003548 * Returns the attribute type
Daniel Veillard260a68f1998-08-13 03:39:55 +00003549 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003550int
Daniel Veillard1e346af1999-02-22 10:33:01 +00003551xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003552 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003553 if ((CUR == 'C') && (NXT(1) == 'D') &&
3554 (NXT(2) == 'A') && (NXT(3) == 'T') &&
3555 (NXT(4) == 'A')) {
3556 SKIP(5);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003557 return(XML_ATTRIBUTE_CDATA);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003558 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
3559 (NXT(2) == 'R') && (NXT(3) == 'E') &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00003560 (NXT(4) == 'F') && (NXT(5) == 'S')) {
3561 SKIP(6);
3562 return(XML_ATTRIBUTE_IDREFS);
3563 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
3564 (NXT(2) == 'R') && (NXT(3) == 'E') &&
Daniel Veillard260a68f1998-08-13 03:39:55 +00003565 (NXT(4) == 'F')) {
3566 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003567 return(XML_ATTRIBUTE_IDREF);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003568 } else if ((CUR == 'I') && (NXT(1) == 'D')) {
3569 SKIP(2);
3570 return(XML_ATTRIBUTE_ID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003571 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
3572 (NXT(2) == 'T') && (NXT(3) == 'I') &&
3573 (NXT(4) == 'T') && (NXT(5) == 'Y')) {
3574 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003575 return(XML_ATTRIBUTE_ENTITY);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003576 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
3577 (NXT(2) == 'T') && (NXT(3) == 'I') &&
3578 (NXT(4) == 'T') && (NXT(5) == 'I') &&
3579 (NXT(6) == 'E') && (NXT(7) == 'S')) {
3580 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003581 return(XML_ATTRIBUTE_ENTITIES);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003582 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
3583 (NXT(2) == 'T') && (NXT(3) == 'O') &&
3584 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00003585 (NXT(6) == 'N') && (NXT(7) == 'S')) {
3586 SKIP(8);
3587 return(XML_ATTRIBUTE_NMTOKENS);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003588 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
3589 (NXT(2) == 'T') && (NXT(3) == 'O') &&
3590 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00003591 (NXT(6) == 'N')) {
3592 SKIP(7);
3593 return(XML_ATTRIBUTE_NMTOKEN);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003594 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00003595 return(xmlParseEnumeratedType(ctxt, tree));
Daniel Veillard260a68f1998-08-13 03:39:55 +00003596}
3597
Daniel Veillard11e00581998-10-24 18:27:49 +00003598/**
3599 * xmlParseAttributeListDecl:
3600 * @ctxt: an XML parser context
3601 *
3602 * : parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00003603 *
3604 * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
3605 *
3606 * [53] AttDef ::= S Name S AttType S DefaultDecl
Daniel Veillard11e00581998-10-24 18:27:49 +00003607 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00003608 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003609void
3610xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003611 xmlChar *elemName;
3612 xmlChar *attrName;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003613 xmlEnumerationPtr tree;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003614
Daniel Veillard260a68f1998-08-13 03:39:55 +00003615 if ((CUR == '<') && (NXT(1) == '!') &&
3616 (NXT(2) == 'A') && (NXT(3) == 'T') &&
3617 (NXT(4) == 'T') && (NXT(5) == 'L') &&
3618 (NXT(6) == 'I') && (NXT(7) == 'S') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003619 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003620 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003621 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003622 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003623 ctxt->sax->error(ctxt->userData,
3624 "Space required after '<!ATTLIST'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003625 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003626 ctxt->wellFormed = 0;
3627 }
3628 SKIP_BLANKS;
3629 elemName = xmlParseName(ctxt);
3630 if (elemName == NULL) {
3631 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003632 ctxt->sax->error(ctxt->userData,
3633 "ATTLIST: no name for Element\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003634 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003635 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003636 return;
3637 }
3638 SKIP_BLANKS;
3639 while (CUR != '>') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003640 const xmlChar *check = CUR_PTR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003641 int type;
3642 int def;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003643 xmlChar *defaultValue = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003644
Daniel Veillardb05deb71999-08-10 19:04:08 +00003645 tree = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003646 attrName = xmlParseName(ctxt);
3647 if (attrName == NULL) {
3648 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003649 ctxt->sax->error(ctxt->userData,
3650 "ATTLIST: no name for Attribute\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003651 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003652 ctxt->wellFormed = 0;
3653 break;
3654 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003655 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003656 if (!IS_BLANK(CUR)) {
3657 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003658 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003659 "Space required after the attribute name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003660 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003661 ctxt->wellFormed = 0;
3662 break;
3663 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003664 SKIP_BLANKS;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003665
Daniel Veillard1e346af1999-02-22 10:33:01 +00003666 type = xmlParseAttributeType(ctxt, &tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003667 if (type <= 0) break;
3668
Daniel Veillardb05deb71999-08-10 19:04:08 +00003669 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003670 if (!IS_BLANK(CUR)) {
3671 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003672 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003673 "Space required after the attribute type\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003674 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003675 ctxt->wellFormed = 0;
3676 break;
3677 }
3678 SKIP_BLANKS;
3679
3680 def = xmlParseDefaultDecl(ctxt, &defaultValue);
3681 if (def <= 0) break;
3682
Daniel Veillardb05deb71999-08-10 19:04:08 +00003683 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003684 if (CUR != '>') {
3685 if (!IS_BLANK(CUR)) {
3686 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003687 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003688 "Space required after the attribute default value\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003689 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003690 ctxt->wellFormed = 0;
3691 break;
3692 }
3693 SKIP_BLANKS;
3694 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003695 if (check == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003696 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003697 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003698 "xmlParseAttributeListDecl: detected internal error\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003699 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003700 break;
3701 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003702 if ((ctxt->sax != NULL) && (ctxt->sax->attributeDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003703 ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003704 type, def, defaultValue, tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003705 if (attrName != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003706 xmlFree(attrName);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003707 if (defaultValue != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003708 xmlFree(defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003709 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003710 }
3711 if (CUR == '>')
3712 NEXT;
3713
Daniel Veillard6454aec1999-09-02 22:04:43 +00003714 xmlFree(elemName);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003715 }
3716}
3717
Daniel Veillard11e00581998-10-24 18:27:49 +00003718/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003719 * xmlParseElementMixedContentDecl:
Daniel Veillard11e00581998-10-24 18:27:49 +00003720 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00003721 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003722 * parse the declaration for a Mixed Element content
3723 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
Daniel Veillard260a68f1998-08-13 03:39:55 +00003724 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003725 * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
3726 * '(' S? '#PCDATA' S? ')'
3727 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003728 * [ VC: Proper Group/PE Nesting ] applies to [51] too (see [49])
3729 *
3730 * [ VC: No Duplicate Types ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003731 * The same name must not appear more than once in a single
3732 * mixed-content declaration.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003733 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003734 * returns: the list of the xmlElementContentPtr describing the element choices
3735 */
3736xmlElementContentPtr
3737xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard1899e851999-02-01 12:18:54 +00003738 xmlElementContentPtr ret = NULL, cur = NULL, n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003739 xmlChar *elem = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003740
Daniel Veillardb05deb71999-08-10 19:04:08 +00003741 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003742 if ((CUR == '#') && (NXT(1) == 'P') &&
3743 (NXT(2) == 'C') && (NXT(3) == 'D') &&
3744 (NXT(4) == 'A') && (NXT(5) == 'T') &&
3745 (NXT(6) == 'A')) {
3746 SKIP(7);
3747 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003748 SHRINK;
Daniel Veillard3b9def11999-01-31 22:15:06 +00003749 if (CUR == ')') {
3750 NEXT;
3751 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
3752 return(ret);
3753 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003754 if ((CUR == '(') || (CUR == '|')) {
3755 ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
3756 if (ret == NULL) return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003757 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003758 while (CUR == '|') {
Daniel Veillard1899e851999-02-01 12:18:54 +00003759 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003760 if (elem == NULL) {
3761 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
3762 if (ret == NULL) return(NULL);
3763 ret->c1 = cur;
Daniel Veillard1899e851999-02-01 12:18:54 +00003764 cur = ret;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003765 } else {
Daniel Veillard1899e851999-02-01 12:18:54 +00003766 n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
3767 if (n == NULL) return(NULL);
3768 n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
3769 cur->c2 = n;
3770 cur = n;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003771 xmlFree(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003772 }
3773 SKIP_BLANKS;
3774 elem = xmlParseName(ctxt);
3775 if (elem == NULL) {
3776 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003777 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003778 "xmlParseElementMixedContentDecl : Name expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003779 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003780 ctxt->wellFormed = 0;
3781 xmlFreeElementContent(cur);
3782 return(NULL);
3783 }
3784 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003785 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003786 }
Daniel Veillard3b9def11999-01-31 22:15:06 +00003787 if ((CUR == ')') && (NXT(1) == '*')) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00003788 if (elem != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003789 cur->c2 = xmlNewElementContent(elem,
3790 XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003791 xmlFree(elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003792 }
Daniel Veillard1899e851999-02-01 12:18:54 +00003793 ret->ocur = XML_ELEMENT_CONTENT_MULT;
3794 SKIP(2);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003795 } else {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003796 if (elem != NULL) xmlFree(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003797 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003798 ctxt->sax->error(ctxt->userData,
Daniel Veillard3b9def11999-01-31 22:15:06 +00003799 "xmlParseElementMixedContentDecl : '|' or ')*' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003800 ctxt->errNo = XML_ERR_MIXED_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003801 ctxt->wellFormed = 0;
3802 xmlFreeElementContent(ret);
3803 return(NULL);
3804 }
3805
3806 } else {
3807 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003808 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003809 "xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003810 ctxt->errNo = XML_ERR_PCDATA_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003811 ctxt->wellFormed = 0;
3812 }
3813 return(ret);
3814}
3815
3816/**
3817 * xmlParseElementChildrenContentDecl:
3818 * @ctxt: an XML parser context
3819 *
3820 * parse the declaration for a Mixed Element content
3821 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
3822 *
3823 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00003824 * [47] children ::= (choice | seq) ('?' | '*' | '+')?
3825 *
3826 * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
3827 *
3828 * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
3829 *
3830 * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
3831 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003832 * [ VC: Proper Group/PE Nesting ] applies to [49] and [50]
3833 * TODO Parameter-entity replacement text must be properly nested
3834 * with parenthetized groups. That is to say, if either of the
3835 * opening or closing parentheses in a choice, seq, or Mixed
3836 * construct is contained in the replacement text for a parameter
3837 * entity, both must be contained in the same replacement text. For
3838 * interoperability, if a parameter-entity reference appears in a
3839 * choice, seq, or Mixed construct, its replacement text should not
3840 * be empty, and neither the first nor last non-blank character of
3841 * the replacement text should be a connector (| or ,).
3842 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003843 * returns: the tree of xmlElementContentPtr describing the element
3844 * hierarchy.
3845 */
3846xmlElementContentPtr
3847xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt) {
3848 xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003849 xmlChar *elem;
3850 xmlChar type = 0;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003851
3852 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003853 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003854 if (CUR == '(') {
3855 /* Recurse on first child */
3856 NEXT;
3857 SKIP_BLANKS;
3858 cur = ret = xmlParseElementChildrenContentDecl(ctxt);
3859 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003860 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003861 } else {
3862 elem = xmlParseName(ctxt);
3863 if (elem == NULL) {
3864 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003865 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003866 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003867 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003868 ctxt->wellFormed = 0;
3869 return(NULL);
3870 }
3871 cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003872 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003873 if (CUR == '?') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003874 cur->ocur = XML_ELEMENT_CONTENT_OPT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003875 NEXT;
3876 } else if (CUR == '*') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003877 cur->ocur = XML_ELEMENT_CONTENT_MULT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003878 NEXT;
3879 } else if (CUR == '+') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003880 cur->ocur = XML_ELEMENT_CONTENT_PLUS;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003881 NEXT;
3882 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003883 cur->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003884 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00003885 xmlFree(elem);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003886 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003887 }
3888 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003889 SHRINK;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003890 while (CUR != ')') {
3891 /*
3892 * Each loop we parse one separator and one element.
3893 */
3894 if (CUR == ',') {
3895 if (type == 0) type = CUR;
3896
3897 /*
3898 * Detect "Name | Name , Name" error
3899 */
3900 else if (type != CUR) {
3901 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003902 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003903 "xmlParseElementChildrenContentDecl : '%c' expected\n",
3904 type);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003905 ctxt->errNo = XML_ERR_SEPARATOR_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003906 ctxt->wellFormed = 0;
3907 xmlFreeElementContent(ret);
3908 return(NULL);
3909 }
Daniel Veillard1899e851999-02-01 12:18:54 +00003910 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003911
3912 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
3913 if (op == NULL) {
3914 xmlFreeElementContent(ret);
3915 return(NULL);
3916 }
3917 if (last == NULL) {
3918 op->c1 = ret;
3919 ret = cur = op;
3920 } else {
3921 cur->c2 = op;
3922 op->c1 = last;
3923 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00003924 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003925 }
3926 } else if (CUR == '|') {
3927 if (type == 0) type = CUR;
3928
3929 /*
3930 * Detect "Name , Name | Name" error
3931 */
3932 else if (type != CUR) {
3933 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003934 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003935 "xmlParseElementChildrenContentDecl : '%c' expected\n",
3936 type);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003937 ctxt->errNo = XML_ERR_SEPARATOR_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003938 ctxt->wellFormed = 0;
3939 xmlFreeElementContent(ret);
3940 return(NULL);
3941 }
Daniel Veillard1899e851999-02-01 12:18:54 +00003942 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003943
3944 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
3945 if (op == NULL) {
3946 xmlFreeElementContent(ret);
3947 return(NULL);
3948 }
3949 if (last == NULL) {
3950 op->c1 = ret;
3951 ret = cur = op;
3952 } else {
3953 cur->c2 = op;
3954 op->c1 = last;
3955 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00003956 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003957 }
3958 } else {
3959 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003960 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003961 "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
3962 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003963 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003964 xmlFreeElementContent(ret);
3965 return(NULL);
3966 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003967 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003968 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003969 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003970 if (CUR == '(') {
3971 /* Recurse on second child */
3972 NEXT;
3973 SKIP_BLANKS;
Daniel Veillard1899e851999-02-01 12:18:54 +00003974 last = xmlParseElementChildrenContentDecl(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003975 SKIP_BLANKS;
3976 } else {
3977 elem = xmlParseName(ctxt);
3978 if (elem == NULL) {
3979 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003980 ctxt->sax->error(ctxt->userData,
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003981 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003982 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003983 ctxt->wellFormed = 0;
3984 return(NULL);
3985 }
Daniel Veillard1899e851999-02-01 12:18:54 +00003986 last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003987 xmlFree(elem);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003988 if (CUR == '?') {
3989 last->ocur = XML_ELEMENT_CONTENT_OPT;
3990 NEXT;
3991 } else if (CUR == '*') {
3992 last->ocur = XML_ELEMENT_CONTENT_MULT;
3993 NEXT;
3994 } else if (CUR == '+') {
3995 last->ocur = XML_ELEMENT_CONTENT_PLUS;
3996 NEXT;
3997 } else {
3998 last->ocur = XML_ELEMENT_CONTENT_ONCE;
3999 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004000 }
4001 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004002 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004003 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004004 if ((cur != NULL) && (last != NULL)) {
4005 cur->c2 = last;
4006 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004007 NEXT;
4008 if (CUR == '?') {
4009 ret->ocur = XML_ELEMENT_CONTENT_OPT;
4010 NEXT;
4011 } else if (CUR == '*') {
4012 ret->ocur = XML_ELEMENT_CONTENT_MULT;
4013 NEXT;
4014 } else if (CUR == '+') {
4015 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
4016 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004017 }
4018 return(ret);
4019}
4020
4021/**
4022 * xmlParseElementContentDecl:
4023 * @ctxt: an XML parser context
4024 * @name: the name of the element being defined.
4025 * @result: the Element Content pointer will be stored here if any
Daniel Veillard260a68f1998-08-13 03:39:55 +00004026 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004027 * parse the declaration for an Element content either Mixed or Children,
4028 * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
4029 *
4030 * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
Daniel Veillard11e00581998-10-24 18:27:49 +00004031 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004032 * returns: the type of element content XML_ELEMENT_TYPE_xxx
Daniel Veillard260a68f1998-08-13 03:39:55 +00004033 */
4034
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004035int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004036xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, xmlChar *name,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004037 xmlElementContentPtr *result) {
4038
4039 xmlElementContentPtr tree = NULL;
4040 int res;
4041
4042 *result = NULL;
4043
4044 if (CUR != '(') {
4045 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004046 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004047 "xmlParseElementContentDecl : '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004048 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004049 ctxt->wellFormed = 0;
4050 return(-1);
4051 }
4052 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004053 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004054 SKIP_BLANKS;
4055 if ((CUR == '#') && (NXT(1) == 'P') &&
4056 (NXT(2) == 'C') && (NXT(3) == 'D') &&
4057 (NXT(4) == 'A') && (NXT(5) == 'T') &&
4058 (NXT(6) == 'A')) {
4059 tree = xmlParseElementMixedContentDecl(ctxt);
4060 res = XML_ELEMENT_TYPE_MIXED;
4061 } else {
4062 tree = xmlParseElementChildrenContentDecl(ctxt);
4063 res = XML_ELEMENT_TYPE_ELEMENT;
4064 }
4065 SKIP_BLANKS;
4066 /****************************
4067 if (CUR != ')') {
4068 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004069 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004070 "xmlParseElementContentDecl : ')' expected\n");
4071 ctxt->wellFormed = 0;
4072 return(-1);
4073 }
4074 ****************************/
Daniel Veillard3b9def11999-01-31 22:15:06 +00004075 *result = tree;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004076 return(res);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004077}
4078
Daniel Veillard11e00581998-10-24 18:27:49 +00004079/**
4080 * xmlParseElementDecl:
4081 * @ctxt: an XML parser context
4082 *
4083 * parse an Element declaration.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004084 *
4085 * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
4086 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004087 * [ VC: Unique Element Type Declaration ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004088 * No element type may be declared more than once
Daniel Veillard1e346af1999-02-22 10:33:01 +00004089 *
4090 * Returns the type of the element, or -1 in case of error
Daniel Veillard260a68f1998-08-13 03:39:55 +00004091 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004092int
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004093xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004094 xmlChar *name;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004095 int ret = -1;
4096 xmlElementContentPtr content = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004097
Daniel Veillardb05deb71999-08-10 19:04:08 +00004098 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004099 if ((CUR == '<') && (NXT(1) == '!') &&
4100 (NXT(2) == 'E') && (NXT(3) == 'L') &&
4101 (NXT(4) == 'E') && (NXT(5) == 'M') &&
4102 (NXT(6) == 'E') && (NXT(7) == 'N') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004103 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004104 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004105 if (!IS_BLANK(CUR)) {
4106 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004107 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004108 "Space required after 'ELEMENT'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004109 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004110 ctxt->wellFormed = 0;
4111 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004112 SKIP_BLANKS;
4113 name = xmlParseName(ctxt);
4114 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004115 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004116 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004117 "xmlParseElementDecl: no name for Element\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004118 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004119 ctxt->wellFormed = 0;
4120 return(-1);
4121 }
4122 if (!IS_BLANK(CUR)) {
4123 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004124 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004125 "Space required after the element name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004126 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004127 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004128 }
4129 SKIP_BLANKS;
4130 if ((CUR == 'E') && (NXT(1) == 'M') &&
4131 (NXT(2) == 'P') && (NXT(3) == 'T') &&
4132 (NXT(4) == 'Y')) {
4133 SKIP(5);
4134 /*
4135 * Element must always be empty.
4136 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004137 ret = XML_ELEMENT_TYPE_EMPTY;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004138 } else if ((CUR == 'A') && (NXT(1) == 'N') &&
4139 (NXT(2) == 'Y')) {
4140 SKIP(3);
4141 /*
4142 * Element is a generic container.
4143 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004144 ret = XML_ELEMENT_TYPE_ANY;
4145 } else if (CUR == '(') {
4146 ret = xmlParseElementContentDecl(ctxt, name, &content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004147 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004148 /*
4149 * [ WFC: PEs in Internal Subset ] error handling.
4150 */
4151 if ((CUR == '%') && (ctxt->external == 0) &&
4152 (ctxt->inputNr == 1)) {
4153 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4154 ctxt->sax->error(ctxt->userData,
4155 "PEReference: forbidden within markup decl in internal subset\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004156 ctxt->errNo = XML_ERR_PEREF_IN_INT_SUBSET;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004157 } else {
4158 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4159 ctxt->sax->error(ctxt->userData,
4160 "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004161 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004162 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004163 ctxt->wellFormed = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004164 if (name != NULL) xmlFree(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004165 return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004166 }
4167 SKIP_BLANKS;
4168 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004169 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004170 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00004171 "xmlParseElementDecl: expected '>' at the end\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004172 ctxt->errNo = XML_ERR_GT_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004173 ctxt->wellFormed = 0;
4174 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004175 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00004176 if ((ctxt->sax != NULL) && (ctxt->sax->elementDecl != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00004177 ctxt->sax->elementDecl(ctxt->userData, name, ret,
4178 content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004179 }
Daniel Veillard14fff061999-06-22 21:49:07 +00004180 if (content != NULL) {
4181 xmlFreeElementContent(content);
4182 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004183 if (name != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004184 xmlFree(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004185 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004186 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004187 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004188}
4189
Daniel Veillard11e00581998-10-24 18:27:49 +00004190/**
4191 * xmlParseMarkupDecl:
4192 * @ctxt: an XML parser context
4193 *
4194 * parse Markup declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00004195 *
4196 * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
4197 * NotationDecl | PI | Comment
4198 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004199 * [ VC: Proper Declaration/PE Nesting ]
4200 * TODO Parameter-entity replacement text must be properly nested with
4201 * markup declarations. That is to say, if either the first character
4202 * or the last character of a markup declaration (markupdecl above) is
4203 * contained in the replacement text for a parameter-entity reference,
4204 * both must be contained in the same replacement text.
4205 *
4206 * [ WFC: PEs in Internal Subset ]
4207 * In the internal DTD subset, parameter-entity references can occur
4208 * only where markup declarations can occur, not within markup declarations.
4209 * (This does not apply to references that occur in external parameter
4210 * entities or to the external subset.)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004211 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004212void
4213xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004214 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004215 xmlParseElementDecl(ctxt);
4216 xmlParseAttributeListDecl(ctxt);
4217 xmlParseEntityDecl(ctxt);
4218 xmlParseNotationDecl(ctxt);
4219 xmlParsePI(ctxt);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004220 xmlParseComment(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004221 /*
4222 * This is only for internal subset. On external entities,
4223 * the replacement is done before parsing stage
4224 */
4225 if ((ctxt->external == 0) && (ctxt->inputNr == 1))
4226 xmlParsePEReference(ctxt);
4227 ctxt->instate = XML_PARSER_DTD;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004228}
4229
Daniel Veillard11e00581998-10-24 18:27:49 +00004230/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004231 * xmlParseTextDecl:
4232 * @ctxt: an XML parser context
4233 *
4234 * parse an XML declaration header for external entities
4235 *
4236 * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
4237 *
4238 * Returns the only valuable info for an external parsed entity, the encoding
4239 */
4240
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004241xmlChar *
Daniel Veillard011b63c1999-06-02 17:44:04 +00004242xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004243 xmlChar *version;
4244 xmlChar *encoding = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004245
4246 /*
4247 * We know that '<?xml' is here.
4248 */
4249 SKIP(5);
4250
4251 if (!IS_BLANK(CUR)) {
4252 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004253 ctxt->sax->error(ctxt->userData,
4254 "Space needed after '<?xml'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004255 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004256 ctxt->wellFormed = 0;
4257 }
4258 SKIP_BLANKS;
4259
4260 /*
4261 * We may have the VersionInfo here.
4262 */
4263 version = xmlParseVersionInfo(ctxt);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004264 if (version == NULL)
4265 version = xmlCharStrdup(XML_DEFAULT_VERSION);
4266 ctxt->version = xmlStrdup(version);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004267 xmlFree(version);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004268
4269 /*
4270 * We must have the encoding declaration
4271 */
4272 if (!IS_BLANK(CUR)) {
4273 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004274 ctxt->sax->error(ctxt->userData, "Space needed here\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004275 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004276 ctxt->wellFormed = 0;
4277 }
4278 encoding = xmlParseEncodingDecl(ctxt);
4279
4280 SKIP_BLANKS;
4281 if ((CUR == '?') && (NXT(1) == '>')) {
4282 SKIP(2);
4283 } else if (CUR == '>') {
4284 /* Deprecated old WD ... */
4285 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004286 ctxt->sax->error(ctxt->userData,
4287 "XML declaration must end-up with '?>'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004288 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004289 ctxt->wellFormed = 0;
4290 NEXT;
4291 } else {
4292 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004293 ctxt->sax->error(ctxt->userData,
4294 "parsing XML declaration: '?>' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004295 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004296 ctxt->wellFormed = 0;
4297 MOVETO_ENDTAG(CUR_PTR);
4298 NEXT;
4299 }
4300 return(encoding);
4301}
4302
4303/*
4304 * xmlParseConditionalSections
4305 * @ctxt: an XML parser context
4306 *
4307 * TODO : Conditionnal section are not yet supported !
4308 *
4309 * [61] conditionalSect ::= includeSect | ignoreSect
4310 * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
4311 * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
4312 * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
4313 * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
4314 */
4315
4316void
4317xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
4318 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
4319 ctxt->sax->warning(ctxt->userData,
4320 "XML conditional section not supported\n");
4321 /*
4322 * Skip up to the end of the conditionnal section.
4323 */
4324 while ((CUR != 0) && ((CUR != ']') || (NXT(1) != ']') || (NXT(2) != '>')))
4325 NEXT;
4326 if (CUR == 0) {
4327 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4328 ctxt->sax->error(ctxt->userData,
4329 "XML conditional section not closed\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004330 ctxt->errNo = XML_ERR_CONDSEC_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004331 ctxt->wellFormed = 0;
4332 }
4333}
4334
4335/**
4336 * xmlParseExternalSubset
4337 * @ctxt: an XML parser context
4338 *
4339 * parse Markup declarations from an external subset
4340 *
4341 * [30] extSubset ::= textDecl? extSubsetDecl
4342 *
4343 * [31] extSubsetDecl ::= (markupdecl | conditionalSect | PEReference | S) *
Daniel Veillard011b63c1999-06-02 17:44:04 +00004344 */
4345void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004346xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID,
4347 const xmlChar *SystemID) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004348 if ((CUR == '<') && (NXT(1) == '?') &&
4349 (NXT(2) == 'x') && (NXT(3) == 'm') &&
4350 (NXT(4) == 'l')) {
4351 xmlParseTextDecl(ctxt);
4352 }
4353 if (ctxt->myDoc == NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004354 ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004355 }
4356 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL))
4357 xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID);
4358
Daniel Veillardb05deb71999-08-10 19:04:08 +00004359 ctxt->instate = XML_PARSER_DTD;
4360 ctxt->external = 1;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004361 while (((CUR == '<') && (NXT(1) == '?')) ||
4362 ((CUR == '<') && (NXT(1) == '!')) ||
4363 IS_BLANK(CUR)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004364 const xmlChar *check = CUR_PTR;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004365 int cons = ctxt->input->consumed;
4366
Daniel Veillard011b63c1999-06-02 17:44:04 +00004367 if ((CUR == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
4368 xmlParseConditionalSections(ctxt);
4369 } else if (IS_BLANK(CUR)) {
4370 NEXT;
4371 } else if (CUR == '%') {
4372 xmlParsePEReference(ctxt);
4373 } else
4374 xmlParseMarkupDecl(ctxt);
4375
4376 /*
4377 * Pop-up of finished entities.
4378 */
4379 while ((CUR == 0) && (ctxt->inputNr > 1))
4380 xmlPopInput(ctxt);
4381
Daniel Veillardb96e6431999-08-29 21:02:19 +00004382 if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
4383 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4384 ctxt->sax->error(ctxt->userData,
4385 "Content error in the external subset\n");
4386 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004387 ctxt->errNo = XML_ERR_EXT_SUBSET_NOT_FINISHED;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004388 break;
4389 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004390 }
4391
4392 if (CUR != 0) {
4393 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4394 ctxt->sax->error(ctxt->userData,
4395 "Extra content at the end of the document\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004396 ctxt->errNo = XML_ERR_EXT_SUBSET_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004397 ctxt->wellFormed = 0;
4398 }
4399
4400}
4401
4402/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004403 * xmlParseReference:
4404 * @ctxt: an XML parser context
4405 *
4406 * parse and handle entity references in content, depending on the SAX
4407 * interface, this may end-up in a call to character() if this is a
4408 * CharRef, a predefined entity, if there is no reference() callback.
4409 * or if the parser was asked to switch to that mode.
4410 *
4411 * [67] Reference ::= EntityRef | CharRef
4412 */
4413void
4414xmlParseReference(xmlParserCtxtPtr ctxt) {
4415 xmlEntityPtr ent;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004416 xmlChar *val;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004417 if (CUR != '&') return;
4418
Daniel Veillardb96e6431999-08-29 21:02:19 +00004419 if (ctxt->inputNr > 1) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004420 xmlChar cur[2] = { '&' , 0 } ;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004421
4422 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
4423 ctxt->sax->characters(ctxt->userData, cur, 1);
4424 if (ctxt->token == '&')
4425 ctxt->token = 0;
4426 else {
4427 SKIP(1);
4428 }
4429 return;
4430 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004431 if (NXT(1) == '#') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004432 xmlChar out[2];
Daniel Veillard011b63c1999-06-02 17:44:04 +00004433 int val = xmlParseCharRef(ctxt);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004434 /* invalid for UTF-8 variable encoding !!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00004435 out[0] = val;
4436 out[1] = 0;
4437 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
4438 ctxt->sax->characters(ctxt->userData, out, 1);
4439 } else {
4440 ent = xmlParseEntityRef(ctxt);
4441 if (ent == NULL) return;
4442 if ((ent->name != NULL) &&
Daniel Veillardb96e6431999-08-29 21:02:19 +00004443 (ent->type != XML_INTERNAL_PREDEFINED_ENTITY)) {
4444 if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) &&
4445 (ctxt->replaceEntities == 0)) {
4446 /*
4447 * Create a node.
4448 */
4449 ctxt->sax->reference(ctxt->userData, ent->name);
4450 return;
4451 } else if (ctxt->replaceEntities) {
4452 xmlParserInputPtr input;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004453
Daniel Veillardb96e6431999-08-29 21:02:19 +00004454 input = xmlNewEntityInputStream(ctxt, ent);
4455 xmlPushInput(ctxt, input);
4456 return;
4457 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004458 }
4459 val = ent->content;
4460 if (val == NULL) return;
4461 /*
4462 * inline the entity.
4463 */
4464 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
4465 ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val));
4466 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004467}
4468
Daniel Veillard11e00581998-10-24 18:27:49 +00004469/**
4470 * xmlParseEntityRef:
4471 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00004472 *
4473 * parse ENTITY references declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00004474 *
4475 * [68] EntityRef ::= '&' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00004476 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004477 * [ WFC: Entity Declared ]
4478 * In a document without any DTD, a document with only an internal DTD
4479 * subset which contains no parameter entity references, or a document
4480 * with "standalone='yes'", the Name given in the entity reference
4481 * must match that in an entity declaration, except that well-formed
4482 * documents need not declare any of the following entities: amp, lt,
4483 * gt, apos, quot. The declaration of a parameter entity must precede
4484 * any reference to it. Similarly, the declaration of a general entity
4485 * must precede any reference to it which appears in a default value in an
4486 * attribute-list declaration. Note that if entities are declared in the
4487 * external subset or in external parameter entities, a non-validating
4488 * processor is not obligated to read and process their declarations;
4489 * for such documents, the rule that an entity must be declared is a
4490 * well-formedness constraint only if standalone='yes'.
4491 *
4492 * [ WFC: Parsed Entity ]
4493 * An entity reference must not contain the name of an unparsed entity
4494 *
Daniel Veillard011b63c1999-06-02 17:44:04 +00004495 * Returns the xmlEntityPtr if found, or NULL otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004496 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00004497xmlEntityPtr
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004498xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004499 xmlChar *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00004500 xmlEntityPtr ent = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004501
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004502 GROW;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004503
Daniel Veillard260a68f1998-08-13 03:39:55 +00004504 if (CUR == '&') {
4505 NEXT;
4506 name = xmlParseName(ctxt);
4507 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004508 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00004509 ctxt->sax->error(ctxt->userData,
4510 "xmlParseEntityRef: no name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004511 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004512 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004513 } else {
4514 if (CUR == ';') {
4515 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004516 /*
Daniel Veillard011b63c1999-06-02 17:44:04 +00004517 * Ask first SAX for entity resolution, otherwise try the
4518 * predefined set.
4519 */
4520 if (ctxt->sax != NULL) {
4521 if (ctxt->sax->getEntity != NULL)
4522 ent = ctxt->sax->getEntity(ctxt->userData, name);
4523 if (ent == NULL)
4524 ent = xmlGetPredefinedEntity(name);
4525 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004526 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00004527 * [ WFC: Entity Declared ]
4528 * In a document without any DTD, a document with only an
4529 * internal DTD subset which contains no parameter entity
4530 * references, or a document with "standalone='yes'", the
4531 * Name given in the entity reference must match that in an
4532 * entity declaration, except that well-formed documents
4533 * need not declare any of the following entities: amp, lt,
4534 * gt, apos, quot.
4535 * The declaration of a parameter entity must precede any
4536 * reference to it.
4537 * Similarly, the declaration of a general entity must
4538 * precede any reference to it which appears in a default
4539 * value in an attribute-list declaration. Note that if
4540 * entities are declared in the external subset or in
4541 * external parameter entities, a non-validating processor
4542 * is not obligated to read and process their declarations;
4543 * for such documents, the rule that an entity must be
4544 * declared is a well-formedness constraint only if
4545 * standalone='yes'.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004546 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00004547 if (ent == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004548 if ((ctxt->standalone == 1) ||
4549 ((ctxt->hasExternalSubset == 0) &&
4550 (ctxt->hasPErefs == 0))) {
4551 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00004552 ctxt->sax->error(ctxt->userData,
4553 "Entity '%s' not defined\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004554 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004555 ctxt->wellFormed = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004556 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004557 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
4558 ctxt->sax->warning(ctxt->userData,
4559 "Entity '%s' not defined\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004560 ctxt->errNo = XML_WAR_UNDECLARED_ENTITY;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004561 }
4562 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004563
4564 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00004565 * [ WFC: Parsed Entity ]
4566 * An entity reference must not contain the name of an
4567 * unparsed entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004568 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00004569 else if (ent->type == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
4570 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4571 ctxt->sax->error(ctxt->userData,
4572 "Entity reference to unparsed entity %s\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004573 ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004574 ctxt->wellFormed = 0;
4575 }
4576
4577 /*
4578 * [ WFC: No External Entity References ]
4579 * Attribute values cannot contain direct or indirect
4580 * entity references to external entities.
4581 */
4582 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
4583 (ent->type == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
4584 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4585 ctxt->sax->error(ctxt->userData,
4586 "Attribute references external entity '%s'\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004587 ctxt->errNo = XML_ERR_ENTITY_IS_EXTERNAL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004588 ctxt->wellFormed = 0;
4589 }
4590 /*
4591 * [ WFC: No < in Attribute Values ]
4592 * The replacement text of any entity referred to directly or
4593 * indirectly in an attribute value (other than "&lt;") must
4594 * not contain a <.
4595 */
4596 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
Daniel Veillardb96e6431999-08-29 21:02:19 +00004597 (ent != NULL) &&
4598 (xmlStrcmp(ent->name, BAD_CAST "lt")) &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00004599 (ent->content != NULL) &&
4600 (xmlStrchr(ent->content, '<'))) {
4601 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4602 ctxt->sax->error(ctxt->userData,
4603 "'<' in entity '%s' is not allowed in attributes values\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004604 ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004605 ctxt->wellFormed = 0;
4606 }
4607
4608 /*
4609 * Internal check, no parameter entities here ...
4610 */
4611 else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004612 switch (ent->type) {
4613 case XML_INTERNAL_PARAMETER_ENTITY:
4614 case XML_EXTERNAL_PARAMETER_ENTITY:
4615 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004616 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004617 "Attempt to reference the parameter entity '%s'\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004618 ctxt->errNo = XML_ERR_ENTITY_IS_PARAMETER;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004619 ctxt->wellFormed = 0;
4620 break;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004621 }
4622 }
4623
4624 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00004625 * [ WFC: No Recursion ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004626 * TODO A parsed entity must not contain a recursive reference
4627 * to itself, either directly or indirectly.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004628 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00004629
Daniel Veillard011b63c1999-06-02 17:44:04 +00004630 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004631 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004632 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004633 "xmlParseEntityRef: expecting ';'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004634 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004635 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004636 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00004637 xmlFree(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004638 }
4639 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004640 return(ent);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004641}
4642
Daniel Veillard11e00581998-10-24 18:27:49 +00004643/**
4644 * xmlParsePEReference:
4645 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00004646 *
4647 * parse PEReference declarations
Daniel Veillard011b63c1999-06-02 17:44:04 +00004648 * The entity content is handled directly by pushing it's content as
4649 * a new input stream.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004650 *
4651 * [69] PEReference ::= '%' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00004652 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004653 * [ WFC: No Recursion ]
4654 * TODO A parsed entity must not contain a recursive
4655 * reference to itself, either directly or indirectly.
4656 *
4657 * [ WFC: Entity Declared ]
4658 * In a document without any DTD, a document with only an internal DTD
4659 * subset which contains no parameter entity references, or a document
4660 * with "standalone='yes'", ... ... The declaration of a parameter
4661 * entity must precede any reference to it...
4662 *
4663 * [ VC: Entity Declared ]
4664 * In a document with an external subset or external parameter entities
4665 * with "standalone='no'", ... ... The declaration of a parameter entity
4666 * must precede any reference to it...
4667 *
4668 * [ WFC: In DTD ]
4669 * Parameter-entity references may only appear in the DTD.
4670 * NOTE: misleading but this is handled.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004671 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00004672void
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004673xmlParsePEReference(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004674 xmlChar *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00004675 xmlEntityPtr entity = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +00004676 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004677
4678 if (CUR == '%') {
4679 NEXT;
4680 name = xmlParseName(ctxt);
4681 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004682 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004683 ctxt->sax->error(ctxt->userData,
4684 "xmlParsePEReference: no name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004685 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004686 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004687 } else {
4688 if (CUR == ';') {
4689 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004690 if ((ctxt->sax != NULL) &&
4691 (ctxt->sax->getParameterEntity != NULL))
4692 entity = ctxt->sax->getParameterEntity(ctxt->userData,
4693 name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004694 if (entity == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004695 /*
4696 * [ WFC: Entity Declared ]
4697 * In a document without any DTD, a document with only an
4698 * internal DTD subset which contains no parameter entity
4699 * references, or a document with "standalone='yes'", ...
4700 * ... The declaration of a parameter entity must precede
4701 * any reference to it...
4702 */
4703 if ((ctxt->standalone == 1) ||
4704 ((ctxt->hasExternalSubset == 0) &&
4705 (ctxt->hasPErefs == 0))) {
4706 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4707 ctxt->sax->error(ctxt->userData,
4708 "PEReference: %%%s; not found\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004709 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004710 ctxt->wellFormed = 0;
4711 } else {
4712 /*
4713 * [ VC: Entity Declared ]
4714 * In a document with an external subset or external
4715 * parameter entities with "standalone='no'", ...
4716 * ... The declaration of a parameter entity must precede
4717 * any reference to it...
4718 */
4719 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
4720 ctxt->sax->warning(ctxt->userData,
4721 "PEReference: %%%s; not found\n", name);
4722 ctxt->valid = 0;
4723 }
Daniel Veillardccb09631998-10-27 06:21:04 +00004724 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004725 /*
4726 * Internal checking in case the entity quest barfed
4727 */
4728 if ((entity->type != XML_INTERNAL_PARAMETER_ENTITY) &&
4729 (entity->type != XML_EXTERNAL_PARAMETER_ENTITY)) {
4730 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
4731 ctxt->sax->warning(ctxt->userData,
4732 "Internal: %%%s; is not a parameter entity\n", name);
4733 } else {
4734 input = xmlNewEntityInputStream(ctxt, entity);
4735 xmlPushInput(ctxt, input);
4736 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004737 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00004738 ctxt->hasPErefs = 1;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004739 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004740 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004741 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004742 "xmlParsePEReference: expecting ';'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004743 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004744 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004745 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00004746 xmlFree(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004747 }
4748 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004749}
4750
Daniel Veillard11e00581998-10-24 18:27:49 +00004751/**
4752 * xmlParseDocTypeDecl :
4753 * @ctxt: an XML parser context
4754 *
4755 * parse a DOCTYPE declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00004756 *
4757 * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
4758 * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
Daniel Veillardb05deb71999-08-10 19:04:08 +00004759 *
4760 * [ VC: Root Element Type ]
4761 * The Name in the document type declaration must match the element
4762 * type of the root element.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004763 */
4764
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004765void
4766xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004767 xmlChar *name;
4768 xmlChar *ExternalID = NULL;
4769 xmlChar *URI = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004770
4771 /*
4772 * We know that '<!DOCTYPE' has been detected.
4773 */
4774 SKIP(9);
4775
4776 SKIP_BLANKS;
4777
4778 /*
4779 * Parse the DOCTYPE name.
4780 */
4781 name = xmlParseName(ctxt);
4782 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004783 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004784 ctxt->sax->error(ctxt->userData,
4785 "xmlParseDocTypeDecl : no DOCTYPE name !\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004786 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004787 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004788 }
4789
4790 SKIP_BLANKS;
4791
4792 /*
4793 * Check for SystemID and ExternalID
4794 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00004795 URI = xmlParseExternalID(ctxt, &ExternalID, 1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004796
4797 if ((URI != NULL) || (ExternalID != NULL)) {
4798 ctxt->hasExternalSubset = 1;
4799 }
4800
Daniel Veillard260a68f1998-08-13 03:39:55 +00004801 SKIP_BLANKS;
4802
Daniel Veillard011b63c1999-06-02 17:44:04 +00004803 /*
4804 * NOTE: the SAX callback may try to fetch the external subset
4805 * entity and fill it up !
4806 */
Daniel Veillard517752b1999-04-05 12:20:10 +00004807 if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004808 ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004809
4810 /*
4811 * Is there any DTD definition ?
4812 */
4813 if (CUR == '[') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004814 ctxt->instate = XML_PARSER_DTD;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004815 NEXT;
4816 /*
4817 * Parse the succession of Markup declarations and
4818 * PEReferences.
4819 * Subsequence (markupdecl | PEReference | S)*
4820 */
4821 while (CUR != ']') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004822 const xmlChar *check = CUR_PTR;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004823 int cons = ctxt->input->consumed;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004824
4825 SKIP_BLANKS;
4826 xmlParseMarkupDecl(ctxt);
Daniel Veillardccb09631998-10-27 06:21:04 +00004827 xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004828
Daniel Veillard011b63c1999-06-02 17:44:04 +00004829 /*
4830 * Pop-up of finished entities.
4831 */
4832 while ((CUR == 0) && (ctxt->inputNr > 1))
4833 xmlPopInput(ctxt);
4834
Daniel Veillardc26087b1999-08-30 11:23:51 +00004835 if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004836 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4837 ctxt->sax->error(ctxt->userData,
4838 "xmlParseDocTypeDecl: error detected in Markup declaration\n");
4839 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004840 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004841 break;
4842 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004843 }
4844 if (CUR == ']') NEXT;
4845 }
4846
4847 /*
4848 * We should be at the end of the DOCTYPE declaration.
4849 */
4850 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004851 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004852 ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004853 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004854 ctxt->errNo = XML_ERR_DOCTYPE_NOT_FINISHED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004855 }
4856 NEXT;
4857
4858 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00004859 * Cleanup
Daniel Veillard260a68f1998-08-13 03:39:55 +00004860 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00004861 if (URI != NULL) xmlFree(URI);
4862 if (ExternalID != NULL) xmlFree(ExternalID);
4863 if (name != NULL) xmlFree(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004864}
4865
Daniel Veillard11e00581998-10-24 18:27:49 +00004866/**
4867 * xmlParseAttribute:
4868 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004869 * @value: a xmlChar ** used to store the value of the attribute
Daniel Veillard11e00581998-10-24 18:27:49 +00004870 *
4871 * parse an attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00004872 *
4873 * [41] Attribute ::= Name Eq AttValue
4874 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004875 * [ WFC: No External Entity References ]
4876 * Attribute values cannot contain direct or indirect entity references
4877 * to external entities.
4878 *
4879 * [ WFC: No < in Attribute Values ]
4880 * The replacement text of any entity referred to directly or indirectly in
4881 * an attribute value (other than "&lt;") must not contain a <.
4882 *
4883 * [ VC: Attribute Value Type ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004884 * The attribute must have been declared; the value must be of the type
Daniel Veillardb05deb71999-08-10 19:04:08 +00004885 * declared for it.
4886 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004887 * [25] Eq ::= S? '=' S?
4888 *
4889 * With namespace:
4890 *
4891 * [NS 11] Attribute ::= QName Eq AttValue
4892 *
4893 * Also the case QName == xmlns:??? is handled independently as a namespace
4894 * definition.
Daniel Veillard1e346af1999-02-22 10:33:01 +00004895 *
Daniel Veillard517752b1999-04-05 12:20:10 +00004896 * Returns the attribute name, and the value in *value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004897 */
4898
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004899xmlChar *
4900xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) {
4901 xmlChar *name, *val;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004902
Daniel Veillard517752b1999-04-05 12:20:10 +00004903 *value = NULL;
4904 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004905 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004906 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004907 ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004908 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004909 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillardccb09631998-10-27 06:21:04 +00004910 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004911 }
4912
4913 /*
4914 * read the value
4915 */
4916 SKIP_BLANKS;
4917 if (CUR == '=') {
4918 NEXT;
4919 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00004920 val = xmlParseAttValue(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004921 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004922 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004923 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004924 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004925 "Specification mandate value for attribute %s\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004926 ctxt->errNo = XML_ERR_ATTRIBUTE_WITHOUT_VALUE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004927 ctxt->wellFormed = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00004928 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004929 }
4930
Daniel Veillard517752b1999-04-05 12:20:10 +00004931 *value = val;
4932 return(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004933}
4934
Daniel Veillard11e00581998-10-24 18:27:49 +00004935/**
4936 * xmlParseStartTag:
4937 * @ctxt: an XML parser context
4938 *
4939 * parse a start of tag either for rule element or
4940 * EmptyElement. In both case we don't parse the tag closing chars.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004941 *
4942 * [40] STag ::= '<' Name (S Attribute)* S? '>'
4943 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004944 * [ WFC: Unique Att Spec ]
4945 * No attribute name may appear more than once in the same start-tag or
4946 * empty-element tag.
4947 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004948 * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
4949 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004950 * [ WFC: Unique Att Spec ]
4951 * No attribute name may appear more than once in the same start-tag or
4952 * empty-element tag.
4953 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004954 * With namespace:
4955 *
4956 * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
4957 *
4958 * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
Daniel Veillard14fff061999-06-22 21:49:07 +00004959 *
4960 * Returns the element name parsed
Daniel Veillard260a68f1998-08-13 03:39:55 +00004961 */
4962
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004963xmlChar *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004964xmlParseStartTag(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004965 xmlChar *name;
4966 xmlChar *attname;
4967 xmlChar *attvalue;
4968 const xmlChar **atts = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00004969 int nbatts = 0;
4970 int maxatts = 0;
4971 int i;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004972
Daniel Veillard14fff061999-06-22 21:49:07 +00004973 if (CUR != '<') return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004974 NEXT;
4975
Daniel Veillard517752b1999-04-05 12:20:10 +00004976 name = xmlParseName(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004977 if (name == NULL) {
4978 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004979 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004980 "xmlParseStartTag: invalid element name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004981 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004982 ctxt->wellFormed = 0;
Daniel Veillard14fff061999-06-22 21:49:07 +00004983 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004984 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004985
4986 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00004987 * Now parse the attributes, it ends up with the ending
4988 *
4989 * (S Attribute)* S?
4990 */
4991 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004992 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004993 while ((IS_CHAR(CUR)) &&
4994 (CUR != '>') &&
4995 ((CUR != '/') || (NXT(1) != '>'))) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004996 const xmlChar *q = CUR_PTR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004997 int cons = ctxt->input->consumed;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004998
Daniel Veillard517752b1999-04-05 12:20:10 +00004999 attname = xmlParseAttribute(ctxt, &attvalue);
5000 if ((attname != NULL) && (attvalue != NULL)) {
5001 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005002 * [ WFC: Unique Att Spec ]
5003 * No attribute name may appear more than once in the same
5004 * start-tag or empty-element tag.
Daniel Veillard517752b1999-04-05 12:20:10 +00005005 */
5006 for (i = 0; i < nbatts;i += 2) {
5007 if (!xmlStrcmp(atts[i], attname)) {
5008 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00005009 ctxt->sax->error(ctxt->userData,
5010 "Attribute %s redefined\n",
5011 attname);
Daniel Veillard517752b1999-04-05 12:20:10 +00005012 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005013 ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED;
Daniel Veillard6454aec1999-09-02 22:04:43 +00005014 xmlFree(attname);
5015 xmlFree(attvalue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005016 goto failed;
Daniel Veillard517752b1999-04-05 12:20:10 +00005017 }
5018 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005019
Daniel Veillard517752b1999-04-05 12:20:10 +00005020 /*
5021 * Add the pair to atts
5022 */
5023 if (atts == NULL) {
5024 maxatts = 10;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005025 atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *));
Daniel Veillard517752b1999-04-05 12:20:10 +00005026 if (atts == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00005027 fprintf(stderr, "malloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005028 maxatts * (long)sizeof(xmlChar *));
Daniel Veillard14fff061999-06-22 21:49:07 +00005029 return(NULL);
Daniel Veillard517752b1999-04-05 12:20:10 +00005030 }
5031 } else if (nbatts + 2 < maxatts) {
5032 maxatts *= 2;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005033 atts = (const xmlChar **) xmlRealloc(atts,
5034 maxatts * sizeof(xmlChar *));
Daniel Veillard517752b1999-04-05 12:20:10 +00005035 if (atts == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00005036 fprintf(stderr, "realloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005037 maxatts * (long)sizeof(xmlChar *));
Daniel Veillard14fff061999-06-22 21:49:07 +00005038 return(NULL);
Daniel Veillard517752b1999-04-05 12:20:10 +00005039 }
5040 }
5041 atts[nbatts++] = attname;
5042 atts[nbatts++] = attvalue;
5043 atts[nbatts] = NULL;
5044 atts[nbatts + 1] = NULL;
5045 }
5046
Daniel Veillardb96e6431999-08-29 21:02:19 +00005047failed:
Daniel Veillard517752b1999-04-05 12:20:10 +00005048 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005049 if ((cons == ctxt->input->consumed) && (q == CUR_PTR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005050 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005051 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00005052 "xmlParseStartTag: problem parsing attributes\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005053 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005054 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005055 break;
5056 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005057 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005058 }
5059
5060 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00005061 * SAX: Start of Element !
5062 */
Daniel Veillard517752b1999-04-05 12:20:10 +00005063 if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005064 ctxt->sax->startElement(ctxt->userData, name, atts);
Daniel Veillard517752b1999-04-05 12:20:10 +00005065
Daniel Veillard517752b1999-04-05 12:20:10 +00005066 if (atts != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005067 for (i = 0;i < nbatts;i++) xmlFree((xmlChar *) atts[i]);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005068 xmlFree(atts);
Daniel Veillard517752b1999-04-05 12:20:10 +00005069 }
Daniel Veillard14fff061999-06-22 21:49:07 +00005070 return(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005071}
5072
Daniel Veillard11e00581998-10-24 18:27:49 +00005073/**
5074 * xmlParseEndTag:
5075 * @ctxt: an XML parser context
Daniel Veillard14fff061999-06-22 21:49:07 +00005076 * @tagname: the tag name as parsed in the opening tag.
Daniel Veillard11e00581998-10-24 18:27:49 +00005077 *
5078 * parse an end of tag
Daniel Veillard260a68f1998-08-13 03:39:55 +00005079 *
5080 * [42] ETag ::= '</' Name S? '>'
5081 *
5082 * With namespace
5083 *
Daniel Veillard517752b1999-04-05 12:20:10 +00005084 * [NS 9] ETag ::= '</' QName S? '>'
Daniel Veillard260a68f1998-08-13 03:39:55 +00005085 */
5086
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005087void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005088xmlParseEndTag(xmlParserCtxtPtr ctxt, xmlChar *tagname) {
5089 xmlChar *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005090
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005091 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005092 if ((CUR != '<') || (NXT(1) != '/')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005093 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005094 ctxt->sax->error(ctxt->userData, "xmlParseEndTag: '</' not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005095 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005096 ctxt->errNo = XML_ERR_LTSLASH_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005097 return;
5098 }
5099 SKIP(2);
5100
Daniel Veillard517752b1999-04-05 12:20:10 +00005101 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005102
5103 /*
5104 * We should definitely be at the ending "S? '>'" part
5105 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005106 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005107 SKIP_BLANKS;
5108 if ((!IS_CHAR(CUR)) || (CUR != '>')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005109 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005110 ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005111 ctxt->errNo = XML_ERR_GT_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005112 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005113 } else
5114 NEXT;
5115
Daniel Veillard517752b1999-04-05 12:20:10 +00005116 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005117 * [ WFC: Element Type Match ]
5118 * The Name in an element's end-tag must match the element type in the
5119 * start-tag.
5120 *
Daniel Veillard14fff061999-06-22 21:49:07 +00005121 */
5122 if (xmlStrcmp(name, tagname)) {
5123 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5124 ctxt->sax->error(ctxt->userData,
5125 "Opening and ending tag mismatch: %s and %s\n", tagname, name);
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005126
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005127 ctxt->errNo = XML_ERR_TAG_NAME_MISMATCH;
Daniel Veillard14fff061999-06-22 21:49:07 +00005128 ctxt->wellFormed = 0;
5129 }
5130
5131 /*
Daniel Veillard517752b1999-04-05 12:20:10 +00005132 * SAX: End of Tag
5133 */
5134 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005135 ctxt->sax->endElement(ctxt->userData, name);
Daniel Veillard517752b1999-04-05 12:20:10 +00005136
5137 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00005138 xmlFree(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00005139
Daniel Veillard260a68f1998-08-13 03:39:55 +00005140 return;
5141}
5142
Daniel Veillard11e00581998-10-24 18:27:49 +00005143/**
5144 * xmlParseCDSect:
5145 * @ctxt: an XML parser context
5146 *
5147 * Parse escaped pure raw content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005148 *
5149 * [18] CDSect ::= CDStart CData CDEnd
5150 *
5151 * [19] CDStart ::= '<![CDATA['
5152 *
5153 * [20] Data ::= (Char* - (Char* ']]>' Char*))
5154 *
5155 * [21] CDEnd ::= ']]>'
5156 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005157void
5158xmlParseCDSect(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005159 const xmlChar *base;
5160 xmlChar r, s;
5161 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005162
Daniel Veillardb05deb71999-08-10 19:04:08 +00005163 if ((NXT(0) == '<') && (NXT(1) == '!') &&
Daniel Veillard260a68f1998-08-13 03:39:55 +00005164 (NXT(2) == '[') && (NXT(3) == 'C') &&
5165 (NXT(4) == 'D') && (NXT(5) == 'A') &&
5166 (NXT(6) == 'T') && (NXT(7) == 'A') &&
5167 (NXT(8) == '[')) {
5168 SKIP(9);
5169 } else
5170 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005171
5172 ctxt->instate = XML_PARSER_CDATA_SECTION;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005173 base = CUR_PTR;
5174 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005175 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005176 ctxt->sax->error(ctxt->userData,
5177 "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005178 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005179 ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005180 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005181 return;
5182 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00005183 r = CUR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005184 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005185 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005186 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005187 ctxt->sax->error(ctxt->userData,
5188 "CData section not finished\n%.50s\n", base);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005189 ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005190 ctxt->wellFormed = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005191 ctxt->instate = XML_PARSER_CONTENT;
5192 return;
5193 }
5194 s = CUR;
5195 NEXT;
5196 cur = CUR;
5197 while (IS_CHAR(cur) &&
5198 ((r != ']') || (s != ']') || (cur != '>'))) {
5199 r = s;
5200 s = cur;
5201 NEXT;
5202 cur = CUR;
5203 }
5204 ctxt->instate = XML_PARSER_CONTENT;
5205 if (!IS_CHAR(CUR)) {
5206 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005207 ctxt->sax->error(ctxt->userData,
5208 "CData section not finished\n%.50s\n", base);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005209 ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005210 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005211 return;
5212 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005213 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005214
5215 /*
5216 * Ok the segment [base CUR_PTR] is to be consumed as chars.
5217 */
5218 if (ctxt->sax != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00005219 if (ctxt->sax->cdataBlock != NULL)
5220 ctxt->sax->cdataBlock(ctxt->userData, base, (CUR_PTR - base) - 3);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005221 }
5222}
5223
Daniel Veillard11e00581998-10-24 18:27:49 +00005224/**
5225 * xmlParseContent:
5226 * @ctxt: an XML parser context
5227 *
5228 * Parse a content:
Daniel Veillard260a68f1998-08-13 03:39:55 +00005229 *
5230 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
5231 */
5232
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005233void
5234xmlParseContent(xmlParserCtxtPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00005235 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005236 while ((CUR != '<') || (NXT(1) != '/')) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005237 const xmlChar *test = CUR_PTR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005238 int cons = ctxt->input->consumed;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005239 xmlChar tok = ctxt->token;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005240
5241 /*
5242 * First case : a Processing Instruction.
5243 */
5244 if ((CUR == '<') && (NXT(1) == '?')) {
5245 xmlParsePI(ctxt);
5246 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005247
Daniel Veillard260a68f1998-08-13 03:39:55 +00005248 /*
5249 * Second case : a CDSection
5250 */
5251 else if ((CUR == '<') && (NXT(1) == '!') &&
5252 (NXT(2) == '[') && (NXT(3) == 'C') &&
5253 (NXT(4) == 'D') && (NXT(5) == 'A') &&
5254 (NXT(6) == 'T') && (NXT(7) == 'A') &&
5255 (NXT(8) == '[')) {
5256 xmlParseCDSect(ctxt);
5257 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005258
Daniel Veillard260a68f1998-08-13 03:39:55 +00005259 /*
5260 * Third case : a comment
5261 */
5262 else if ((CUR == '<') && (NXT(1) == '!') &&
5263 (NXT(2) == '-') && (NXT(3) == '-')) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00005264 xmlParseComment(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005265 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005266 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005267
Daniel Veillard260a68f1998-08-13 03:39:55 +00005268 /*
5269 * Fourth case : a sub-element.
5270 */
5271 else if (CUR == '<') {
Daniel Veillard517752b1999-04-05 12:20:10 +00005272 xmlParseElement(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005273 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005274
Daniel Veillard260a68f1998-08-13 03:39:55 +00005275 /*
Daniel Veillardccb09631998-10-27 06:21:04 +00005276 * Fifth case : a reference. If if has not been resolved,
5277 * parsing returns it's Name, create the node
Daniel Veillard260a68f1998-08-13 03:39:55 +00005278 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00005279
Daniel Veillard260a68f1998-08-13 03:39:55 +00005280 else if (CUR == '&') {
Daniel Veillard011b63c1999-06-02 17:44:04 +00005281 xmlParseReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005282 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005283
Daniel Veillard260a68f1998-08-13 03:39:55 +00005284 /*
5285 * Last case, text. Note that References are handled directly.
5286 */
5287 else {
5288 xmlParseCharData(ctxt, 0);
5289 }
5290
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005291 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005292 /*
5293 * Pop-up of finished entities.
5294 */
Daniel Veillardbc50b591999-03-01 12:28:53 +00005295 while ((CUR == 0) && (ctxt->inputNr > 1))
5296 xmlPopInput(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005297
Daniel Veillardb96e6431999-08-29 21:02:19 +00005298 if ((cons == ctxt->input->consumed) && (test == CUR_PTR) &&
5299 (tok == ctxt->token)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005300 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005301 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005302 "detected an error in element content\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005303 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005304 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005305 break;
5306 }
5307 }
5308}
5309
Daniel Veillard11e00581998-10-24 18:27:49 +00005310/**
5311 * xmlParseElement:
5312 * @ctxt: an XML parser context
5313 *
5314 * parse an XML element, this is highly recursive
Daniel Veillard260a68f1998-08-13 03:39:55 +00005315 *
5316 * [39] element ::= EmptyElemTag | STag content ETag
5317 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005318 * [ WFC: Element Type Match ]
5319 * The Name in an element's end-tag must match the element type in the
5320 * start-tag.
5321 *
5322 * [ VC: Element Valid ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00005323 * An element is valid if there is a declaration matching elementdecl
Daniel Veillardb05deb71999-08-10 19:04:08 +00005324 * where the Name matches the element type and one of the following holds:
5325 * - The declaration matches EMPTY and the element has no content.
5326 * - The declaration matches children and the sequence of child elements
5327 * belongs to the language generated by the regular expression in the
5328 * content model, with optional white space (characters matching the
5329 * nonterminal S) between each pair of child elements.
5330 * - The declaration matches Mixed and the content consists of character
5331 * data and child elements whose types match names in the content model.
5332 * - The declaration matches ANY, and the types of any child elements have
5333 * been declared.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005334 */
5335
Daniel Veillard517752b1999-04-05 12:20:10 +00005336void
Daniel Veillard1e346af1999-02-22 10:33:01 +00005337xmlParseElement(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005338 const xmlChar *openTag = CUR_PTR;
5339 xmlChar *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005340 xmlParserNodeInfo node_info;
Daniel Veillardc26087b1999-08-30 11:23:51 +00005341 xmlNodePtr ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005342
5343 /* Capture start position */
Daniel Veillardc26087b1999-08-30 11:23:51 +00005344 if (ctxt->record_info) {
5345 node_info.begin_pos = ctxt->input->consumed +
5346 (CUR_PTR - ctxt->input->base);
5347 node_info.begin_line = ctxt->input->line;
5348 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005349
Daniel Veillard14fff061999-06-22 21:49:07 +00005350 name = xmlParseStartTag(ctxt);
5351 if (name == NULL) {
5352 return;
5353 }
Daniel Veillardc26087b1999-08-30 11:23:51 +00005354 ret = ctxt->node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005355
5356 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005357 * [ VC: Root Element Type ]
5358 * The Name in the document type declaration must match the element
5359 * type of the root element.
5360 */
5361 if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc &&
5362 ctxt->node && (ctxt->node == ctxt->myDoc->root))
5363 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
5364
5365 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00005366 * Check for an Empty Element.
5367 */
5368 if ((CUR == '/') && (NXT(1) == '>')) {
5369 SKIP(2);
Daniel Veillard517752b1999-04-05 12:20:10 +00005370 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard14fff061999-06-22 21:49:07 +00005371 ctxt->sax->endElement(ctxt->userData, name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005372 xmlFree(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00005373 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005374 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005375 if (CUR == '>') {
5376 NEXT;
5377 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005378 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005379 ctxt->sax->error(ctxt->userData,
5380 "Couldn't find end of Start Tag\n%.30s\n",
Daniel Veillard242590e1998-11-13 18:04:35 +00005381 openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005382 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005383 ctxt->errNo = XML_ERR_GT_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005384
5385 /*
5386 * end of parsing of this node.
5387 */
5388 nodePop(ctxt);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005389 xmlFree(name);
Daniel Veillardc26087b1999-08-30 11:23:51 +00005390
5391 /*
5392 * Capture end position and add node
5393 */
5394 if ( ret != NULL && ctxt->record_info ) {
5395 node_info.end_pos = ctxt->input->consumed +
5396 (CUR_PTR - ctxt->input->base);
5397 node_info.end_line = ctxt->input->line;
5398 node_info.node = ret;
5399 xmlParserAddNodeInfo(ctxt, &node_info);
5400 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005401 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005402 }
5403
5404 /*
5405 * Parse the content of the element:
5406 */
5407 xmlParseContent(ctxt);
5408 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005409 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005410 ctxt->sax->error(ctxt->userData,
Daniel Veillard242590e1998-11-13 18:04:35 +00005411 "Premature end of data in tag %.30s\n", openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005412 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005413 ctxt->errNo = XML_ERR_TAG_NOT_FINISED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005414
5415 /*
5416 * end of parsing of this node.
5417 */
5418 nodePop(ctxt);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005419 xmlFree(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00005420 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005421 }
5422
5423 /*
5424 * parse the end of tag: '</' should be here.
5425 */
Daniel Veillard14fff061999-06-22 21:49:07 +00005426 xmlParseEndTag(ctxt, name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005427 xmlFree(name);
Daniel Veillardc26087b1999-08-30 11:23:51 +00005428
5429 /*
5430 * Capture end position and add node
5431 */
5432 if ( ret != NULL && ctxt->record_info ) {
5433 node_info.end_pos = ctxt->input->consumed +
5434 (CUR_PTR - ctxt->input->base);
5435 node_info.end_line = ctxt->input->line;
5436 node_info.node = ret;
5437 xmlParserAddNodeInfo(ctxt, &node_info);
5438 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005439}
5440
Daniel Veillard11e00581998-10-24 18:27:49 +00005441/**
5442 * xmlParseVersionNum:
5443 * @ctxt: an XML parser context
5444 *
5445 * parse the XML version value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005446 *
5447 * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
Daniel Veillard1e346af1999-02-22 10:33:01 +00005448 *
5449 * Returns the string giving the XML version number, or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00005450 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005451xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005452xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005453 const xmlChar *q = CUR_PTR;
5454 xmlChar *ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005455
5456 while (IS_CHAR(CUR) &&
5457 (((CUR >= 'a') && (CUR <= 'z')) ||
5458 ((CUR >= 'A') && (CUR <= 'Z')) ||
5459 ((CUR >= '0') && (CUR <= '9')) ||
5460 (CUR == '_') || (CUR == '.') ||
5461 (CUR == ':') || (CUR == '-'))) NEXT;
5462 ret = xmlStrndup(q, CUR_PTR - q);
5463 return(ret);
5464}
5465
Daniel Veillard11e00581998-10-24 18:27:49 +00005466/**
5467 * xmlParseVersionInfo:
5468 * @ctxt: an XML parser context
5469 *
5470 * parse the XML version.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005471 *
5472 * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
5473 *
5474 * [25] Eq ::= S? '=' S?
Daniel Veillard11e00581998-10-24 18:27:49 +00005475 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005476 * Returns the version string, e.g. "1.0"
Daniel Veillard260a68f1998-08-13 03:39:55 +00005477 */
5478
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005479xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005480xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005481 xmlChar *version = NULL;
5482 const xmlChar *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005483
5484 if ((CUR == 'v') && (NXT(1) == 'e') &&
5485 (NXT(2) == 'r') && (NXT(3) == 's') &&
5486 (NXT(4) == 'i') && (NXT(5) == 'o') &&
5487 (NXT(6) == 'n')) {
5488 SKIP(7);
5489 SKIP_BLANKS;
5490 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005491 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005492 ctxt->sax->error(ctxt->userData,
5493 "xmlParseVersionInfo : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005494 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005495 ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005496 return(NULL);
5497 }
5498 NEXT;
5499 SKIP_BLANKS;
5500 if (CUR == '"') {
5501 NEXT;
5502 q = CUR_PTR;
5503 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005504 if (CUR != '"') {
5505 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005506 ctxt->sax->error(ctxt->userData,
5507 "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005508 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005509 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005510 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005511 NEXT;
5512 } else if (CUR == '\''){
5513 NEXT;
5514 q = CUR_PTR;
5515 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005516 if (CUR != '\'') {
5517 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005518 ctxt->sax->error(ctxt->userData,
5519 "String not closed\n%.50s\n", q);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005520 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005521 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005522 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005523 NEXT;
5524 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005525 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005526 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005527 "xmlParseVersionInfo : expected ' or \"\n");
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005528 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005529 ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005530 }
5531 }
5532 return(version);
5533}
5534
Daniel Veillard11e00581998-10-24 18:27:49 +00005535/**
5536 * xmlParseEncName:
5537 * @ctxt: an XML parser context
5538 *
5539 * parse the XML encoding name
Daniel Veillard260a68f1998-08-13 03:39:55 +00005540 *
5541 * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
Daniel Veillard11e00581998-10-24 18:27:49 +00005542 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005543 * Returns the encoding name value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00005544 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005545xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005546xmlParseEncName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005547 const xmlChar *q = CUR_PTR;
5548 xmlChar *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005549
5550 if (((CUR >= 'a') && (CUR <= 'z')) ||
5551 ((CUR >= 'A') && (CUR <= 'Z'))) {
5552 NEXT;
5553 while (IS_CHAR(CUR) &&
5554 (((CUR >= 'a') && (CUR <= 'z')) ||
5555 ((CUR >= 'A') && (CUR <= 'Z')) ||
5556 ((CUR >= '0') && (CUR <= '9')) ||
5557 (CUR == '-'))) NEXT;
5558 ret = xmlStrndup(q, CUR_PTR - q);
5559 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005560 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005561 ctxt->sax->error(ctxt->userData, "Invalid XML encoding name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005562 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005563 ctxt->errNo = XML_ERR_ENCODING_NAME;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005564 }
5565 return(ret);
5566}
5567
Daniel Veillard11e00581998-10-24 18:27:49 +00005568/**
5569 * xmlParseEncodingDecl:
5570 * @ctxt: an XML parser context
5571 *
5572 * parse the XML encoding declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00005573 *
5574 * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'")
Daniel Veillard11e00581998-10-24 18:27:49 +00005575 *
5576 * TODO: this should setup the conversion filters.
5577 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005578 * Returns the encoding value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00005579 */
5580
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005581xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005582xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005583 xmlChar *encoding = NULL;
5584 const xmlChar *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005585
5586 SKIP_BLANKS;
5587 if ((CUR == 'e') && (NXT(1) == 'n') &&
5588 (NXT(2) == 'c') && (NXT(3) == 'o') &&
5589 (NXT(4) == 'd') && (NXT(5) == 'i') &&
5590 (NXT(6) == 'n') && (NXT(7) == 'g')) {
5591 SKIP(8);
5592 SKIP_BLANKS;
5593 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005594 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005595 ctxt->sax->error(ctxt->userData,
5596 "xmlParseEncodingDecl : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005597 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005598 ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005599 return(NULL);
5600 }
5601 NEXT;
5602 SKIP_BLANKS;
5603 if (CUR == '"') {
5604 NEXT;
5605 q = CUR_PTR;
5606 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005607 if (CUR != '"') {
5608 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005609 ctxt->sax->error(ctxt->userData,
5610 "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005611 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005612 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005613 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005614 NEXT;
5615 } else if (CUR == '\''){
5616 NEXT;
5617 q = CUR_PTR;
5618 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005619 if (CUR != '\'') {
5620 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005621 ctxt->sax->error(ctxt->userData,
5622 "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005623 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005624 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005625 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005626 NEXT;
5627 } else if (CUR == '"'){
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005628 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005629 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005630 "xmlParseEncodingDecl : expected ' or \"\n");
5631 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005632 ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005633 }
5634 }
5635 return(encoding);
5636}
5637
Daniel Veillard11e00581998-10-24 18:27:49 +00005638/**
5639 * xmlParseSDDecl:
5640 * @ctxt: an XML parser context
5641 *
5642 * parse the XML standalone declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00005643 *
5644 * [32] SDDecl ::= S 'standalone' Eq
5645 * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00005646 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005647 * [ VC: Standalone Document Declaration ]
5648 * TODO The standalone document declaration must have the value "no"
5649 * if any external markup declarations contain declarations of:
5650 * - attributes with default values, if elements to which these
5651 * attributes apply appear in the document without specifications
5652 * of values for these attributes, or
5653 * - entities (other than amp, lt, gt, apos, quot), if references
5654 * to those entities appear in the document, or
5655 * - attributes with values subject to normalization, where the
5656 * attribute appears in the document with a value which will change
5657 * as a result of normalization, or
5658 * - element types with element content, if white space occurs directly
5659 * within any instance of those types.
5660 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005661 * Returns 1 if standalone, 0 otherwise
Daniel Veillard260a68f1998-08-13 03:39:55 +00005662 */
5663
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005664int
5665xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005666 int standalone = -1;
5667
5668 SKIP_BLANKS;
5669 if ((CUR == 's') && (NXT(1) == 't') &&
5670 (NXT(2) == 'a') && (NXT(3) == 'n') &&
5671 (NXT(4) == 'd') && (NXT(5) == 'a') &&
5672 (NXT(6) == 'l') && (NXT(7) == 'o') &&
5673 (NXT(8) == 'n') && (NXT(9) == 'e')) {
5674 SKIP(10);
Daniel Veillard011b63c1999-06-02 17:44:04 +00005675 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005676 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005677 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005678 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005679 "XML standalone declaration : expected '='\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005680 ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005681 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005682 return(standalone);
5683 }
5684 NEXT;
5685 SKIP_BLANKS;
5686 if (CUR == '\''){
5687 NEXT;
5688 if ((CUR == 'n') && (NXT(1) == 'o')) {
5689 standalone = 0;
5690 SKIP(2);
5691 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
5692 (NXT(2) == 's')) {
5693 standalone = 1;
5694 SKIP(3);
5695 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005696 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005697 ctxt->sax->error(ctxt->userData,
5698 "standalone accepts only 'yes' or 'no'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005699 ctxt->errNo = XML_ERR_STANDALONE_VALUE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005700 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005701 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005702 if (CUR != '\'') {
5703 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005704 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005705 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005706 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005707 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005708 NEXT;
5709 } else if (CUR == '"'){
5710 NEXT;
5711 if ((CUR == 'n') && (NXT(1) == 'o')) {
5712 standalone = 0;
5713 SKIP(2);
5714 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
5715 (NXT(2) == 's')) {
5716 standalone = 1;
5717 SKIP(3);
5718 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005719 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005720 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005721 "standalone accepts only 'yes' or 'no'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005722 ctxt->errNo = XML_ERR_STANDALONE_VALUE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005723 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005724 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005725 if (CUR != '"') {
5726 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005727 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005728 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005729 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005730 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005731 NEXT;
5732 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005733 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005734 ctxt->sax->error(ctxt->userData,
5735 "Standalone value not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005736 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005737 ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005738 }
5739 }
5740 return(standalone);
5741}
5742
Daniel Veillard11e00581998-10-24 18:27:49 +00005743/**
5744 * xmlParseXMLDecl:
5745 * @ctxt: an XML parser context
5746 *
5747 * parse an XML declaration header
Daniel Veillard260a68f1998-08-13 03:39:55 +00005748 *
5749 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
5750 */
5751
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005752void
5753xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005754 xmlChar *version;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005755
5756 /*
5757 * We know that '<?xml' is here.
5758 */
5759 SKIP(5);
5760
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005761 if (!IS_BLANK(CUR)) {
5762 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005763 ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005764 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005765 ctxt->wellFormed = 0;
5766 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005767 SKIP_BLANKS;
5768
5769 /*
5770 * We should have the VersionInfo here.
5771 */
5772 version = xmlParseVersionInfo(ctxt);
5773 if (version == NULL)
5774 version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard517752b1999-04-05 12:20:10 +00005775 ctxt->version = xmlStrdup(version);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005776 xmlFree(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005777
5778 /*
5779 * We may have the encoding declaration
5780 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005781 if (!IS_BLANK(CUR)) {
5782 if ((CUR == '?') && (NXT(1) == '>')) {
5783 SKIP(2);
5784 return;
5785 }
5786 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005787 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005788 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005789 ctxt->wellFormed = 0;
5790 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005791 ctxt->encoding = xmlParseEncodingDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005792
5793 /*
5794 * We may have the standalone status.
5795 */
Daniel Veillard517752b1999-04-05 12:20:10 +00005796 if ((ctxt->encoding != NULL) && (!IS_BLANK(CUR))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005797 if ((CUR == '?') && (NXT(1) == '>')) {
5798 SKIP(2);
5799 return;
5800 }
5801 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005802 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005803 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005804 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005805 }
5806 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00005807 ctxt->standalone = xmlParseSDDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005808
5809 SKIP_BLANKS;
5810 if ((CUR == '?') && (NXT(1) == '>')) {
5811 SKIP(2);
5812 } else if (CUR == '>') {
5813 /* Deprecated old WD ... */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005814 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005815 ctxt->sax->error(ctxt->userData,
5816 "XML declaration must end-up with '?>'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005817 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005818 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005819 NEXT;
5820 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005821 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005822 ctxt->sax->error(ctxt->userData,
5823 "parsing XML declaration: '?>' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005824 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005825 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005826 MOVETO_ENDTAG(CUR_PTR);
5827 NEXT;
5828 }
5829}
5830
Daniel Veillard11e00581998-10-24 18:27:49 +00005831/**
5832 * xmlParseMisc:
5833 * @ctxt: an XML parser context
5834 *
5835 * parse an XML Misc* optionnal field.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005836 *
5837 * [27] Misc ::= Comment | PI | S
5838 */
5839
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005840void
5841xmlParseMisc(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005842 while (((CUR == '<') && (NXT(1) == '?')) ||
5843 ((CUR == '<') && (NXT(1) == '!') &&
5844 (NXT(2) == '-') && (NXT(3) == '-')) ||
5845 IS_BLANK(CUR)) {
5846 if ((CUR == '<') && (NXT(1) == '?')) {
5847 xmlParsePI(ctxt);
5848 } else if (IS_BLANK(CUR)) {
5849 NEXT;
5850 } else
Daniel Veillardb96e6431999-08-29 21:02:19 +00005851 xmlParseComment(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005852 }
5853}
5854
Daniel Veillard11e00581998-10-24 18:27:49 +00005855/**
5856 * xmlParseDocument :
5857 * @ctxt: an XML parser context
5858 *
5859 * parse an XML document (and build a tree if using the standard SAX
5860 * interface).
Daniel Veillard260a68f1998-08-13 03:39:55 +00005861 *
5862 * [1] document ::= prolog element Misc*
5863 *
5864 * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
Daniel Veillard11e00581998-10-24 18:27:49 +00005865 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005866 * Returns 0, -1 in case of error. the parser context is augmented
Daniel Veillard11e00581998-10-24 18:27:49 +00005867 * as a result of the parsing.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005868 */
5869
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005870int
5871xmlParseDocument(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005872 xmlDefaultSAXHandlerInit();
5873
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005874 GROW;
5875
Daniel Veillard260a68f1998-08-13 03:39:55 +00005876 /*
5877 * SAX: beginning of the document processing.
5878 */
Daniel Veillard517752b1999-04-05 12:20:10 +00005879 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
Daniel Veillard27d88741999-05-29 11:51:49 +00005880 ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005881
5882 /*
Daniel Veillardb96e6431999-08-29 21:02:19 +00005883 * TODO We should check for encoding here and plug-in some
5884 * conversion code !!!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00005885 */
5886
5887 /*
5888 * Wipe out everything which is before the first '<'
5889 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005890 if (IS_BLANK(CUR)) {
5891 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005892 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005893 "Extra spaces at the beginning of the document are not allowed\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005894 ctxt->errNo = XML_ERR_DOCUMENT_START;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005895 ctxt->wellFormed = 0;
5896 SKIP_BLANKS;
5897 }
5898
5899 if (CUR == 0) {
5900 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005901 ctxt->sax->error(ctxt->userData, "Document is empty\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005902 ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005903 ctxt->wellFormed = 0;
5904 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005905
5906 /*
5907 * Check for the XMLDecl in the Prolog.
5908 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005909 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005910 if ((CUR == '<') && (NXT(1) == '?') &&
5911 (NXT(2) == 'x') && (NXT(3) == 'm') &&
5912 (NXT(4) == 'l')) {
5913 xmlParseXMLDecl(ctxt);
5914 /* SKIP_EOL(cur); */
5915 SKIP_BLANKS;
5916 } else if ((CUR == '<') && (NXT(1) == '?') &&
5917 (NXT(2) == 'X') && (NXT(3) == 'M') &&
5918 (NXT(4) == 'L')) {
5919 /*
5920 * The first drafts were using <?XML and the final W3C REC
5921 * now use <?xml ...
5922 */
5923 xmlParseXMLDecl(ctxt);
5924 /* SKIP_EOL(cur); */
5925 SKIP_BLANKS;
5926 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00005927 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005928 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005929 if ((ctxt->sax) && (ctxt->sax->startDocument))
Daniel Veillard27d88741999-05-29 11:51:49 +00005930 ctxt->sax->startDocument(ctxt->userData);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005931
5932 /*
5933 * The Misc part of the Prolog
5934 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005935 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005936 xmlParseMisc(ctxt);
5937
5938 /*
5939 * Then possibly doc type declaration(s) and more Misc
5940 * (doctypedecl Misc*)?
5941 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005942 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005943 if ((CUR == '<') && (NXT(1) == '!') &&
5944 (NXT(2) == 'D') && (NXT(3) == 'O') &&
5945 (NXT(4) == 'C') && (NXT(5) == 'T') &&
5946 (NXT(6) == 'Y') && (NXT(7) == 'P') &&
5947 (NXT(8) == 'E')) {
5948 xmlParseDocTypeDecl(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005949 ctxt->instate = XML_PARSER_PROLOG;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005950 xmlParseMisc(ctxt);
5951 }
5952
5953 /*
5954 * Time to start parsing the tree itself
5955 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005956 GROW;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005957 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard517752b1999-04-05 12:20:10 +00005958 xmlParseElement(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005959 ctxt->instate = XML_PARSER_EPILOG;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005960
5961 /*
5962 * The Misc part at the end
5963 */
5964 xmlParseMisc(ctxt);
5965
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005966 if (CUR != 0) {
5967 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005968 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005969 "Extra content at the end of the document\n");
5970 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005971 ctxt->errNo = XML_ERR_DOCUMENT_END;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005972 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00005973 ctxt->instate = XML_PARSER_EOF;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005974
Daniel Veillard260a68f1998-08-13 03:39:55 +00005975 /*
5976 * SAX: end of the document processing.
5977 */
Daniel Veillard517752b1999-04-05 12:20:10 +00005978 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005979 ctxt->sax->endDocument(ctxt->userData);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005980 if (! ctxt->wellFormed) return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005981 return(0);
5982}
5983
Daniel Veillardb05deb71999-08-10 19:04:08 +00005984/************************************************************************
5985 * *
5986 * I/O front end functions to the parser *
5987 * *
5988 ************************************************************************/
5989
Daniel Veillard11e00581998-10-24 18:27:49 +00005990/**
Daniel Veillardbe70ff71999-07-05 16:50:46 +00005991 * xmlCreateDocParserCtxt :
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005992 * @cur: a pointer to an array of xmlChar
Daniel Veillardd692aa41999-02-28 21:54:31 +00005993 *
5994 * Create a parser context for an XML in-memory document.
5995 *
5996 * Returns the new parser context or NULL
5997 */
5998xmlParserCtxtPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005999xmlCreateDocParserCtxt(xmlChar *cur) {
Daniel Veillardd692aa41999-02-28 21:54:31 +00006000 xmlParserCtxtPtr ctxt;
6001 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00006002 xmlCharEncoding enc;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006003
Daniel Veillardb05deb71999-08-10 19:04:08 +00006004 ctxt = xmlNewParserCtxt();
Daniel Veillardd692aa41999-02-28 21:54:31 +00006005 if (ctxt == NULL) {
Daniel Veillardd692aa41999-02-28 21:54:31 +00006006 return(NULL);
6007 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006008 input = xmlNewInputStream(ctxt);
Daniel Veillardd692aa41999-02-28 21:54:31 +00006009 if (input == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00006010 xmlFreeParserCtxt(ctxt);
Daniel Veillardd692aa41999-02-28 21:54:31 +00006011 return(NULL);
6012 }
6013
Daniel Veillard27d88741999-05-29 11:51:49 +00006014 /*
6015 * plug some encoding conversion routines here. !!!
6016 */
6017 enc = xmlDetectCharEncoding(cur);
6018 xmlSwitchEncoding(ctxt, enc);
6019
Daniel Veillardd692aa41999-02-28 21:54:31 +00006020 input->base = cur;
6021 input->cur = cur;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006022
6023 inputPush(ctxt, input);
6024 return(ctxt);
6025}
6026
6027/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006028 * xmlSAXParseDoc :
6029 * @sax: the SAX handler block
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006030 * @cur: a pointer to an array of xmlChar
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006031 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
6032 * documents
Daniel Veillard11e00581998-10-24 18:27:49 +00006033 *
6034 * parse an XML in-memory document and build a tree.
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006035 * It use the given SAX function block to handle the parsing callback.
6036 * If sax is NULL, fallback to the default DOM tree building routines.
Daniel Veillard11e00581998-10-24 18:27:49 +00006037 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006038 * Returns the resulting document tree
Daniel Veillard260a68f1998-08-13 03:39:55 +00006039 */
6040
Daniel Veillard1e346af1999-02-22 10:33:01 +00006041xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006042xmlSAXParseDoc(xmlSAXHandlerPtr sax, xmlChar *cur, int recovery) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006043 xmlDocPtr ret;
6044 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006045
6046 if (cur == NULL) return(NULL);
6047
Daniel Veillardd692aa41999-02-28 21:54:31 +00006048
6049 ctxt = xmlCreateDocParserCtxt(cur);
6050 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00006051 if (sax != NULL) {
6052 ctxt->sax = sax;
6053 ctxt->userData = NULL;
6054 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006055
6056 xmlParseDocument(ctxt);
Daniel Veillard517752b1999-04-05 12:20:10 +00006057 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006058 else {
6059 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00006060 xmlFreeDoc(ctxt->myDoc);
6061 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006062 }
Daniel Veillard97fea181999-06-26 23:07:37 +00006063 if (sax != NULL)
6064 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006065 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006066
6067 return(ret);
6068}
6069
Daniel Veillard11e00581998-10-24 18:27:49 +00006070/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006071 * xmlParseDoc :
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006072 * @cur: a pointer to an array of xmlChar
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006073 *
6074 * parse an XML in-memory document and build a tree.
6075 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006076 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006077 */
6078
Daniel Veillard1e346af1999-02-22 10:33:01 +00006079xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006080xmlParseDoc(xmlChar *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006081 return(xmlSAXParseDoc(NULL, cur, 0));
6082}
6083
6084/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00006085 * xmlSAXParseDTD :
6086 * @sax: the SAX handler block
6087 * @ExternalID: a NAME* containing the External ID of the DTD
6088 * @SystemID: a NAME* containing the URL to the DTD
6089 *
6090 * Load and parse an external subset.
6091 *
6092 * Returns the resulting xmlDtdPtr or NULL in case of error.
6093 */
6094
6095xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006096xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID,
6097 const xmlChar *SystemID) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00006098 xmlDtdPtr ret = NULL;
6099 xmlParserCtxtPtr ctxt;
Daniel Veillard14fff061999-06-22 21:49:07 +00006100 xmlParserInputPtr input = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00006101 xmlCharEncoding enc;
6102
6103 if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL);
6104
Daniel Veillardb05deb71999-08-10 19:04:08 +00006105 ctxt = xmlNewParserCtxt();
Daniel Veillard011b63c1999-06-02 17:44:04 +00006106 if (ctxt == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00006107 return(NULL);
6108 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00006109
6110 /*
6111 * Set-up the SAX context
6112 */
6113 if (ctxt == NULL) return(NULL);
6114 if (sax != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006115 if (ctxt->sax != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00006116 xmlFree(ctxt->sax);
Daniel Veillard011b63c1999-06-02 17:44:04 +00006117 ctxt->sax = sax;
6118 ctxt->userData = NULL;
6119 }
6120
6121 /*
6122 * Ask the Entity resolver to load the damn thing
6123 */
6124
6125 if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
6126 input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, SystemID);
6127 if (input == NULL) {
Daniel Veillard97fea181999-06-26 23:07:37 +00006128 if (sax != NULL) ctxt->sax = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00006129 xmlFreeParserCtxt(ctxt);
6130 return(NULL);
6131 }
6132
6133 /*
6134 * plug some encoding conversion routines here. !!!
6135 */
6136 xmlPushInput(ctxt, input);
6137 enc = xmlDetectCharEncoding(ctxt->input->cur);
6138 xmlSwitchEncoding(ctxt, enc);
6139
Daniel Veillardb05deb71999-08-10 19:04:08 +00006140 if (input->filename == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00006141 input->filename = (char *) xmlStrdup(SystemID); /* !!!!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00006142 input->line = 1;
6143 input->col = 1;
6144 input->base = ctxt->input->cur;
6145 input->cur = ctxt->input->cur;
6146 input->free = NULL;
6147
6148 /*
6149 * let's parse that entity knowing it's an external subset.
6150 */
6151 xmlParseExternalSubset(ctxt, ExternalID, SystemID);
6152
6153 if (ctxt->myDoc != NULL) {
6154 if (ctxt->wellFormed) {
6155 ret = ctxt->myDoc->intSubset;
6156 ctxt->myDoc->intSubset = NULL;
6157 } else {
6158 ret = NULL;
6159 }
6160 xmlFreeDoc(ctxt->myDoc);
6161 ctxt->myDoc = NULL;
6162 }
Daniel Veillard97fea181999-06-26 23:07:37 +00006163 if (sax != NULL) ctxt->sax = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00006164 xmlFreeParserCtxt(ctxt);
6165
6166 return(ret);
6167}
6168
6169/**
6170 * xmlParseDTD :
6171 * @ExternalID: a NAME* containing the External ID of the DTD
6172 * @SystemID: a NAME* containing the URL to the DTD
6173 *
6174 * Load and parse an external subset.
6175 *
6176 * Returns the resulting xmlDtdPtr or NULL in case of error.
6177 */
6178
6179xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006180xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00006181 return(xmlSAXParseDTD(NULL, ExternalID, SystemID));
6182}
6183
6184/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006185 * xmlRecoverDoc :
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006186 * @cur: a pointer to an array of xmlChar
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006187 *
6188 * parse an XML in-memory document and build a tree.
6189 * In the case the document is not Well Formed, a tree is built anyway
6190 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006191 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006192 */
6193
Daniel Veillard1e346af1999-02-22 10:33:01 +00006194xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006195xmlRecoverDoc(xmlChar *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006196 return(xmlSAXParseDoc(NULL, cur, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006197}
6198
6199/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00006200 * xmlCreateFileParserCtxt :
Daniel Veillard11e00581998-10-24 18:27:49 +00006201 * @filename: the filename
6202 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006203 * Create a parser context for a file content.
6204 * Automatic support for ZLIB/Compress compressed document is provided
6205 * by default if found at compile-time.
Daniel Veillard11e00581998-10-24 18:27:49 +00006206 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006207 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00006208 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00006209xmlParserCtxtPtr
6210xmlCreateFileParserCtxt(const char *filename)
6211{
6212 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006213 xmlParserInputPtr inputStream;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006214 xmlParserInputBufferPtr buf;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006215 char *directory = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006216
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006217 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
6218 if (buf == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006219
Daniel Veillardb05deb71999-08-10 19:04:08 +00006220 ctxt = xmlNewParserCtxt();
Daniel Veillard260a68f1998-08-13 03:39:55 +00006221 if (ctxt == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006222 return(NULL);
6223 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006224
6225 inputStream = xmlNewInputStream(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006226 if (inputStream == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00006227 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006228 return(NULL);
6229 }
6230
Daniel Veillard6454aec1999-09-02 22:04:43 +00006231 inputStream->filename = xmlMemStrdup(filename);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006232 inputStream->buf = buf;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006233 inputStream->base = inputStream->buf->buffer->content;
6234 inputStream->cur = inputStream->buf->buffer->content;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006235
6236 inputPush(ctxt, inputStream);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006237 if ((ctxt->directory == NULL) && (directory == NULL))
6238 directory = xmlParserGetDirectory(filename);
6239 if ((ctxt->directory == NULL) && (directory != NULL))
6240 ctxt->directory = directory;
6241
Daniel Veillardd692aa41999-02-28 21:54:31 +00006242 return(ctxt);
6243}
6244
6245/**
6246 * xmlSAXParseFile :
6247 * @sax: the SAX handler block
6248 * @filename: the filename
6249 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
6250 * documents
6251 *
6252 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
6253 * compressed document is provided by default if found at compile-time.
6254 * It use the given SAX function block to handle the parsing callback.
6255 * If sax is NULL, fallback to the default DOM tree building routines.
6256 *
6257 * Returns the resulting document tree
6258 */
6259
Daniel Veillard011b63c1999-06-02 17:44:04 +00006260xmlDocPtr
6261xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
Daniel Veillardd692aa41999-02-28 21:54:31 +00006262 int recovery) {
6263 xmlDocPtr ret;
6264 xmlParserCtxtPtr ctxt;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006265 char *directory = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006266
6267 ctxt = xmlCreateFileParserCtxt(filename);
6268 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00006269 if (sax != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006270 if (ctxt->sax != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00006271 xmlFree(ctxt->sax);
Daniel Veillard27d88741999-05-29 11:51:49 +00006272 ctxt->sax = sax;
6273 ctxt->userData = NULL;
6274 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006275
Daniel Veillardb05deb71999-08-10 19:04:08 +00006276 if ((ctxt->directory == NULL) && (directory == NULL))
6277 directory = xmlParserGetDirectory(filename);
6278 if ((ctxt->directory == NULL) && (directory != NULL))
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006279 ctxt->directory = (char *) xmlStrdup((xmlChar *) directory); /* !!!!!!! */
Daniel Veillardb05deb71999-08-10 19:04:08 +00006280
Daniel Veillard260a68f1998-08-13 03:39:55 +00006281 xmlParseDocument(ctxt);
6282
Daniel Veillard517752b1999-04-05 12:20:10 +00006283 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006284 else {
6285 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00006286 xmlFreeDoc(ctxt->myDoc);
6287 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006288 }
Daniel Veillard97fea181999-06-26 23:07:37 +00006289 if (sax != NULL)
6290 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006291 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006292
6293 return(ret);
6294}
6295
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006296/**
6297 * xmlParseFile :
6298 * @filename: the filename
6299 *
6300 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
6301 * compressed document is provided by default if found at compile-time.
6302 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006303 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006304 */
6305
Daniel Veillard011b63c1999-06-02 17:44:04 +00006306xmlDocPtr
6307xmlParseFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006308 return(xmlSAXParseFile(NULL, filename, 0));
6309}
6310
6311/**
6312 * xmlRecoverFile :
6313 * @filename: the filename
6314 *
6315 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
6316 * compressed document is provided by default if found at compile-time.
6317 * In the case the document is not Well Formed, a tree is built anyway
6318 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006319 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006320 */
6321
Daniel Veillard011b63c1999-06-02 17:44:04 +00006322xmlDocPtr
6323xmlRecoverFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006324 return(xmlSAXParseFile(NULL, filename, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006325}
Daniel Veillard260a68f1998-08-13 03:39:55 +00006326
Daniel Veillard11e00581998-10-24 18:27:49 +00006327/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00006328 * xmlCreateMemoryParserCtxt :
Daniel Veillard1e346af1999-02-22 10:33:01 +00006329 * @buffer: an pointer to a char array
Daniel Veillard11e00581998-10-24 18:27:49 +00006330 * @size: the siwe of the array
6331 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006332 * Create a parser context for an XML in-memory document.
Daniel Veillard11e00581998-10-24 18:27:49 +00006333 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006334 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00006335 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00006336xmlParserCtxtPtr
6337xmlCreateMemoryParserCtxt(char *buffer, int size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006338 xmlParserCtxtPtr ctxt;
6339 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00006340 xmlCharEncoding enc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006341
6342 buffer[size - 1] = '\0';
6343
Daniel Veillardb05deb71999-08-10 19:04:08 +00006344 ctxt = xmlNewParserCtxt();
Daniel Veillard260a68f1998-08-13 03:39:55 +00006345 if (ctxt == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006346 return(NULL);
6347 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006348
6349 input = xmlNewInputStream(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006350 if (input == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00006351 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006352 return(NULL);
6353 }
6354
6355 input->filename = NULL;
6356 input->line = 1;
6357 input->col = 1;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006358 input->buf = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006359 input->consumed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006360
6361 /*
Daniel Veillard27d88741999-05-29 11:51:49 +00006362 * plug some encoding conversion routines here. !!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00006363 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00006364 enc = xmlDetectCharEncoding(BAD_CAST buffer);
Daniel Veillard27d88741999-05-29 11:51:49 +00006365 xmlSwitchEncoding(ctxt, enc);
6366
Daniel Veillardb96e6431999-08-29 21:02:19 +00006367 input->base = BAD_CAST buffer;
6368 input->cur = BAD_CAST buffer;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006369 input->free = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006370
6371 inputPush(ctxt, input);
Daniel Veillardd692aa41999-02-28 21:54:31 +00006372 return(ctxt);
6373}
6374
6375/**
6376 * xmlSAXParseMemory :
6377 * @sax: the SAX handler block
6378 * @buffer: an pointer to a char array
6379 * @size: the siwe of the array
6380 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
6381 * documents
6382 *
6383 * parse an XML in-memory block and use the given SAX function block
6384 * to handle the parsing callback. If sax is NULL, fallback to the default
6385 * DOM tree building routines.
6386 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006387 * Returns the resulting document tree
6388 */
6389xmlDocPtr
6390xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
6391 xmlDocPtr ret;
6392 xmlParserCtxtPtr ctxt;
6393
6394 ctxt = xmlCreateMemoryParserCtxt(buffer, size);
6395 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00006396 if (sax != NULL) {
6397 ctxt->sax = sax;
6398 ctxt->userData = NULL;
6399 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006400
6401 xmlParseDocument(ctxt);
6402
Daniel Veillard517752b1999-04-05 12:20:10 +00006403 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006404 else {
6405 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00006406 xmlFreeDoc(ctxt->myDoc);
6407 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006408 }
Daniel Veillard97fea181999-06-26 23:07:37 +00006409 if (sax != NULL)
6410 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006411 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006412
6413 return(ret);
6414}
6415
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006416/**
6417 * xmlParseMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00006418 * @buffer: an pointer to a char array
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006419 * @size: the size of the array
6420 *
6421 * parse an XML in-memory block and build a tree.
6422 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006423 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006424 */
6425
6426xmlDocPtr xmlParseMemory(char *buffer, int size) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006427 return(xmlSAXParseMemory(NULL, buffer, size, 0));
6428}
6429
6430/**
6431 * xmlRecoverMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00006432 * @buffer: an pointer to a char array
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006433 * @size: the size of the array
6434 *
6435 * parse an XML in-memory block and build a tree.
6436 * In the case the document is not Well Formed, a tree is built anyway
6437 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006438 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006439 */
6440
6441xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
6442 return(xmlSAXParseMemory(NULL, buffer, size, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006443}
Daniel Veillard260a68f1998-08-13 03:39:55 +00006444
Daniel Veillard260a68f1998-08-13 03:39:55 +00006445
Daniel Veillard11e00581998-10-24 18:27:49 +00006446/**
6447 * xmlSetupParserForBuffer:
6448 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006449 * @buffer: a xmlChar * buffer
Daniel Veillard11e00581998-10-24 18:27:49 +00006450 * @filename: a file name
6451 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00006452 * Setup the parser context to parse a new buffer; Clears any prior
6453 * contents from the parser context. The buffer parameter must not be
6454 * NULL, but the filename parameter can be
6455 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006456void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006457xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer,
Daniel Veillard260a68f1998-08-13 03:39:55 +00006458 const char* filename)
6459{
Daniel Veillardb05deb71999-08-10 19:04:08 +00006460 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006461
Daniel Veillardb05deb71999-08-10 19:04:08 +00006462 input = xmlNewInputStream(ctxt);
6463 if (input == NULL) {
6464 perror("malloc");
Daniel Veillard6454aec1999-09-02 22:04:43 +00006465 xmlFree(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006466 exit(1);
6467 }
6468
6469 xmlClearParserCtxt(ctxt);
6470 if (filename != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00006471 input->filename = xmlMemStrdup(filename);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006472 input->base = buffer;
6473 input->cur = buffer;
6474 inputPush(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006475}
6476
6477
Daniel Veillardb05deb71999-08-10 19:04:08 +00006478/************************************************************************
6479 * *
6480 * Miscelaneous *
6481 * *
6482 ************************************************************************/
6483
6484
Daniel Veillard11e00581998-10-24 18:27:49 +00006485/**
6486 * xmlParserFindNodeInfo:
6487 * @ctxt: an XML parser context
6488 * @node: an XML node within the tree
6489 *
6490 * Find the parser node info struct for a given node
6491 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006492 * Returns an xmlParserNodeInfo block pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00006493 */
6494const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
6495 const xmlNode* node)
6496{
6497 unsigned long pos;
6498
6499 /* Find position where node should be at */
6500 pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
6501 if ( ctx->node_seq.buffer[pos].node == node )
6502 return &ctx->node_seq.buffer[pos];
6503 else
6504 return NULL;
6505}
6506
6507
Daniel Veillard11e00581998-10-24 18:27:49 +00006508/**
6509 * xmlInitNodeInfoSeq :
6510 * @seq: a node info sequence pointer
6511 *
6512 * -- Initialize (set to initial state) node info sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00006513 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006514void
6515xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00006516{
6517 seq->length = 0;
6518 seq->maximum = 0;
6519 seq->buffer = NULL;
6520}
6521
Daniel Veillard11e00581998-10-24 18:27:49 +00006522/**
6523 * xmlClearNodeInfoSeq :
6524 * @seq: a node info sequence pointer
6525 *
6526 * -- Clear (release memory and reinitialize) node
Daniel Veillard260a68f1998-08-13 03:39:55 +00006527 * info sequence
6528 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006529void
6530xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00006531{
6532 if ( seq->buffer != NULL )
Daniel Veillard6454aec1999-09-02 22:04:43 +00006533 xmlFree(seq->buffer);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006534 xmlInitNodeInfoSeq(seq);
6535}
6536
6537
Daniel Veillard11e00581998-10-24 18:27:49 +00006538/**
6539 * xmlParserFindNodeInfoIndex:
6540 * @seq: a node info sequence pointer
6541 * @node: an XML node pointer
6542 *
6543 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00006544 * xmlParserFindNodeInfoIndex : Find the index that the info record for
6545 * the given node is or should be at in a sorted sequence
Daniel Veillard1164e751999-02-16 16:29:17 +00006546 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006547 * Returns a long indicating the position of the record
Daniel Veillard260a68f1998-08-13 03:39:55 +00006548 */
6549unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
6550 const xmlNode* node)
6551{
6552 unsigned long upper, lower, middle;
6553 int found = 0;
6554
6555 /* Do a binary search for the key */
6556 lower = 1;
6557 upper = seq->length;
6558 middle = 0;
6559 while ( lower <= upper && !found) {
6560 middle = lower + (upper - lower) / 2;
6561 if ( node == seq->buffer[middle - 1].node )
6562 found = 1;
6563 else if ( node < seq->buffer[middle - 1].node )
6564 upper = middle - 1;
6565 else
6566 lower = middle + 1;
6567 }
6568
6569 /* Return position */
6570 if ( middle == 0 || seq->buffer[middle - 1].node < node )
6571 return middle;
6572 else
6573 return middle - 1;
6574}
6575
6576
Daniel Veillard11e00581998-10-24 18:27:49 +00006577/**
6578 * xmlParserAddNodeInfo:
6579 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00006580 * @info: a node info sequence pointer
Daniel Veillard11e00581998-10-24 18:27:49 +00006581 *
6582 * Insert node info record into the sorted sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00006583 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006584void
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006585xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
Daniel Veillard1e346af1999-02-22 10:33:01 +00006586 const xmlParserNodeInfo* info)
Daniel Veillard260a68f1998-08-13 03:39:55 +00006587{
6588 unsigned long pos;
6589 static unsigned int block_size = 5;
6590
6591 /* Find pos and check to see if node is already in the sequence */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006592 pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
6593 if ( pos < ctxt->node_seq.length
6594 && ctxt->node_seq.buffer[pos].node == info->node ) {
6595 ctxt->node_seq.buffer[pos] = *info;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006596 }
6597
6598 /* Otherwise, we need to add new node to buffer */
6599 else {
6600 /* Expand buffer by 5 if needed */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006601 if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006602 xmlParserNodeInfo* tmp_buffer;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006603 unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
6604 *(ctxt->node_seq.maximum + block_size));
Daniel Veillard260a68f1998-08-13 03:39:55 +00006605
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006606 if ( ctxt->node_seq.buffer == NULL )
Daniel Veillard6454aec1999-09-02 22:04:43 +00006607 tmp_buffer = (xmlParserNodeInfo*) xmlMalloc(byte_size);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006608 else
Daniel Veillard6454aec1999-09-02 22:04:43 +00006609 tmp_buffer = (xmlParserNodeInfo*) xmlRealloc(ctxt->node_seq.buffer, byte_size);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006610
6611 if ( tmp_buffer == NULL ) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006612 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006613 ctxt->sax->error(ctxt->userData, "Out of memory\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006614 ctxt->errNo = XML_ERR_NO_MEMORY;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006615 return;
6616 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006617 ctxt->node_seq.buffer = tmp_buffer;
6618 ctxt->node_seq.maximum += block_size;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006619 }
6620
6621 /* If position is not at end, move elements out of the way */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006622 if ( pos != ctxt->node_seq.length ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006623 unsigned long i;
6624
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006625 for ( i = ctxt->node_seq.length; i > pos; i-- )
6626 ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
Daniel Veillard260a68f1998-08-13 03:39:55 +00006627 }
6628
6629 /* Copy element and increase length */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006630 ctxt->node_seq.buffer[pos] = *info;
6631 ctxt->node_seq.length++;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006632 }
6633}
Daniel Veillard011b63c1999-06-02 17:44:04 +00006634
6635
Daniel Veillardb05deb71999-08-10 19:04:08 +00006636/**
6637 * xmlSubstituteEntitiesDefault :
6638 * @val: int 0 or 1
6639 *
6640 * Set and return the previous value for default entity support.
6641 * Initially the parser always keep entity references instead of substituting
6642 * entity values in the output. This function has to be used to change the
6643 * default parser behaviour
6644 * SAX::subtituteEntities() has to be used for changing that on a file by
6645 * file basis.
6646 *
6647 * Returns the last value for 0 for no substitution, 1 for substitution.
6648 */
6649
6650int
6651xmlSubstituteEntitiesDefault(int val) {
6652 int old = xmlSubstituteEntitiesDefaultValue;
6653
6654 xmlSubstituteEntitiesDefaultValue = val;
6655 return(old);
6656}
6657