blob: 7bbe088a10fe967c7df180039e10f5b432f92819 [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 Veillard51e3b151999-11-12 17:02:31 +0000382 * @input: an xmlParserInputPtr
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) {
Daniel Veillard35008381999-10-25 13:15:52 +0000747fprintf(stderr, "xmlParseCharRef : ctxt->token != 0\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +0000748 val = ctxt->token;
749 ctxt->token = 0;
750 return(val);
751 }
752 if ((CUR == '&') && (NXT(1) == '#') &&
753 (NXT(2) == 'x')) {
754 SKIP(3);
755 while (CUR != ';') {
756 if ((CUR >= '0') && (CUR <= '9'))
757 val = val * 16 + (CUR - '0');
758 else if ((CUR >= 'a') && (CUR <= 'f'))
759 val = val * 16 + (CUR - 'a') + 10;
760 else if ((CUR >= 'A') && (CUR <= 'F'))
761 val = val * 16 + (CUR - 'A') + 10;
762 else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000763 ctxt->errNo = XML_ERR_INVALID_HEX_CHARREF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000764 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
765 ctxt->sax->error(ctxt->userData,
766 "xmlParseCharRef: invalid hexadecimal value\n");
767 ctxt->wellFormed = 0;
768 val = 0;
769 break;
770 }
771 NEXT;
772 }
773 if (CUR == ';')
Daniel Veillard35008381999-10-25 13:15:52 +0000774 SKIP(1); /* on purpose to avoid reentrancy problems with NEXT */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000775 } else if ((CUR == '&') && (NXT(1) == '#')) {
776 SKIP(2);
777 while (CUR != ';') {
778 if ((CUR >= '0') && (CUR <= '9'))
779 val = val * 10 + (CUR - '0');
780 else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000781 ctxt->errNo = XML_ERR_INVALID_DEC_CHARREF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000782 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
783 ctxt->sax->error(ctxt->userData,
784 "xmlParseCharRef: invalid decimal value\n");
785 ctxt->wellFormed = 0;
786 val = 0;
787 break;
788 }
789 NEXT;
790 }
791 if (CUR == ';')
Daniel Veillard35008381999-10-25 13:15:52 +0000792 SKIP(1); /* on purpose to avoid reentrancy problems with NEXT */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000793 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000794 ctxt->errNo = XML_ERR_INVALID_CHARREF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000795 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
796 ctxt->sax->error(ctxt->userData,
797 "xmlParseCharRef: invalid value\n");
798 ctxt->wellFormed = 0;
799 }
800
801 /*
802 * [ WFC: Legal Character ]
803 * Characters referred to using character references must match the
804 * production for Char.
805 */
806 if (IS_CHAR(val)) {
807 return(val);
808 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000809 ctxt->errNo = XML_ERR_INVALID_CHAR;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000810 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000811 ctxt->sax->error(ctxt->userData, "CharRef: invalid xmlChar value %d\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000812 val);
813 ctxt->wellFormed = 0;
814 }
815 return(0);
816}
817
818/**
819 * xmlParserHandleReference:
820 * @ctxt: the parser context
821 *
822 * [67] Reference ::= EntityRef | CharRef
823 *
824 * [68] EntityRef ::= '&' Name ';'
825 *
826 * [ WFC: Entity Declared ]
827 * the Name given in the entity reference must match that in an entity
828 * declaration, except that well-formed documents need not declare any
829 * of the following entities: amp, lt, gt, apos, quot.
830 *
831 * [ WFC: Parsed Entity ]
832 * An entity reference must not contain the name of an unparsed entity
833 *
834 * [66] CharRef ::= '&#' [0-9]+ ';' |
835 * '&#x' [0-9a-fA-F]+ ';'
836 *
837 * A PEReference may have been detectect in the current input stream
838 * the handling is done accordingly to
839 * http://www.w3.org/TR/REC-xml#entproc
840 */
841void
842xmlParserHandleReference(xmlParserCtxtPtr ctxt) {
843 xmlParserInputPtr input;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000844 xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000845 xmlEntityPtr ent = NULL;
846
Daniel Veillard35008381999-10-25 13:15:52 +0000847 if (ctxt->token != 0) {
848fprintf(stderr, "xmlParserHandleReference : ctxt->token != 0\n");
849 return;
850 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000851 if (CUR != '&') return;
852 GROW;
853 if ((CUR == '&') && (NXT(1) == '#')) {
854 switch(ctxt->instate) {
855 case XML_PARSER_CDATA_SECTION:
856 return;
857 case XML_PARSER_COMMENT:
858 return;
859 case XML_PARSER_EOF:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000860 ctxt->errNo = XML_ERR_CHARREF_AT_EOF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000861 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
862 ctxt->sax->error(ctxt->userData, "CharRef at EOF\n");
863 ctxt->wellFormed = 0;
864 return;
865 case XML_PARSER_PROLOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000866 ctxt->errNo = XML_ERR_CHARREF_IN_PROLOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000867 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
868 ctxt->sax->error(ctxt->userData, "CharRef in prolog!\n");
869 ctxt->wellFormed = 0;
870 return;
871 case XML_PARSER_EPILOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000872 ctxt->errNo = XML_ERR_CHARREF_IN_EPILOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000873 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
874 ctxt->sax->error(ctxt->userData, "CharRef in epilog!\n");
875 ctxt->wellFormed = 0;
876 return;
877 case XML_PARSER_DTD:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000878 ctxt->errNo = XML_ERR_CHARREF_IN_DTD;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000879 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
880 ctxt->sax->error(ctxt->userData,
881 "CharRef are forbiden in DTDs!\n");
882 ctxt->wellFormed = 0;
883 return;
884 case XML_PARSER_ENTITY_DECL:
885 /* we just ignore it there */
886 return;
887 case XML_PARSER_ENTITY_VALUE:
888 /*
889 * NOTE: in the case of entity values, we don't do the
Daniel Veillard51e3b151999-11-12 17:02:31 +0000890 * substitution here since we need the literal
Daniel Veillardb05deb71999-08-10 19:04:08 +0000891 * entity value to be able to save the internal
892 * subset of the document.
893 * This will be handled by xmlDecodeEntities
894 */
895 return;
896 case XML_PARSER_CONTENT:
897 case XML_PARSER_ATTRIBUTE_VALUE:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000898 /* !!! this may not be Ok for UTF-8, multibyte sequence */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000899 ctxt->token = xmlParseCharRef(ctxt);
900 return;
901 }
902 return;
903 }
904
905 switch(ctxt->instate) {
906 case XML_PARSER_CDATA_SECTION:
907 return;
908 case XML_PARSER_COMMENT:
909 return;
910 case XML_PARSER_EOF:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000911 ctxt->errNo = XML_ERR_ENTITYREF_AT_EOF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000912 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
913 ctxt->sax->error(ctxt->userData, "Reference at EOF\n");
914 ctxt->wellFormed = 0;
915 return;
916 case XML_PARSER_PROLOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000917 ctxt->errNo = XML_ERR_ENTITYREF_IN_PROLOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000918 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
919 ctxt->sax->error(ctxt->userData, "Reference in prolog!\n");
920 ctxt->wellFormed = 0;
921 return;
922 case XML_PARSER_EPILOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000923 ctxt->errNo = XML_ERR_ENTITYREF_IN_EPILOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000924 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
925 ctxt->sax->error(ctxt->userData, "Reference in epilog!\n");
926 ctxt->wellFormed = 0;
927 return;
928 case XML_PARSER_ENTITY_VALUE:
929 /*
930 * NOTE: in the case of entity values, we don't do the
Daniel Veillard51e3b151999-11-12 17:02:31 +0000931 * substitution here since we need the literal
Daniel Veillardb05deb71999-08-10 19:04:08 +0000932 * entity value to be able to save the internal
933 * subset of the document.
934 * This will be handled by xmlDecodeEntities
935 */
936 return;
937 case XML_PARSER_ATTRIBUTE_VALUE:
938 /*
939 * NOTE: in the case of attributes values, we don't do the
940 * substitution here unless we are in a mode where
941 * the parser is explicitely asked to substitute
942 * entities. The SAX callback is called with values
943 * without entity substitution.
944 * This will then be handled by xmlDecodeEntities
945 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000946 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000947 case XML_PARSER_ENTITY_DECL:
948 /*
949 * we just ignore it there
950 * the substitution will be done once the entity is referenced
951 */
952 return;
953 case XML_PARSER_DTD:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000954 ctxt->errNo = XML_ERR_ENTITYREF_IN_DTD;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000955 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
956 ctxt->sax->error(ctxt->userData,
957 "Entity references are forbiden in DTDs!\n");
958 ctxt->wellFormed = 0;
959 return;
960 case XML_PARSER_CONTENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000961 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000962 }
963
964 NEXT;
965 name = xmlScanName(ctxt);
966 if (name == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000967 ctxt->errNo = XML_ERR_ENTITYREF_NO_NAME;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000968 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
969 ctxt->sax->error(ctxt->userData, "Entity reference: no name\n");
970 ctxt->wellFormed = 0;
971 ctxt->token = '&';
972 return;
973 }
974 if (NXT(xmlStrlen(name)) != ';') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000975 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000976 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
977 ctxt->sax->error(ctxt->userData,
978 "Entity reference: ';' expected\n");
979 ctxt->wellFormed = 0;
980 ctxt->token = '&';
Daniel Veillard6454aec1999-09-02 22:04:43 +0000981 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000982 return;
983 }
984 SKIP(xmlStrlen(name) + 1);
985 if (ctxt->sax != NULL) {
986 if (ctxt->sax->getEntity != NULL)
987 ent = ctxt->sax->getEntity(ctxt->userData, name);
988 }
989
990 /*
991 * [ WFC: Entity Declared ]
992 * the Name given in the entity reference must match that in an entity
993 * declaration, except that well-formed documents need not declare any
994 * of the following entities: amp, lt, gt, apos, quot.
995 */
996 if (ent == NULL)
997 ent = xmlGetPredefinedEntity(name);
998 if (ent == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000999 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001000 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1001 ctxt->sax->error(ctxt->userData,
1002 "Entity reference: entity %s not declared\n",
1003 name);
1004 ctxt->wellFormed = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001005 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001006 return;
1007 }
1008
1009 /*
1010 * [ WFC: Parsed Entity ]
1011 * An entity reference must not contain the name of an unparsed entity
1012 */
1013 if (ent->type == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001014 ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001015 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1016 ctxt->sax->error(ctxt->userData,
1017 "Entity reference to unparsed entity %s\n", name);
1018 ctxt->wellFormed = 0;
1019 }
1020
1021 if (ent->type == XML_INTERNAL_PREDEFINED_ENTITY) {
1022 ctxt->token = ent->content[0];
Daniel Veillard6454aec1999-09-02 22:04:43 +00001023 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001024 return;
1025 }
1026 input = xmlNewEntityInputStream(ctxt, ent);
1027 xmlPushInput(ctxt, input);
Daniel Veillard6454aec1999-09-02 22:04:43 +00001028 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001029 return;
1030}
1031
1032/**
1033 * xmlParserHandlePEReference:
1034 * @ctxt: the parser context
1035 *
1036 * [69] PEReference ::= '%' Name ';'
1037 *
1038 * [ WFC: No Recursion ]
1039 * TODO A parsed entity must not contain a recursive
1040 * reference to itself, either directly or indirectly.
1041 *
1042 * [ WFC: Entity Declared ]
1043 * In a document without any DTD, a document with only an internal DTD
1044 * subset which contains no parameter entity references, or a document
1045 * with "standalone='yes'", ... ... The declaration of a parameter
1046 * entity must precede any reference to it...
1047 *
1048 * [ VC: Entity Declared ]
1049 * In a document with an external subset or external parameter entities
1050 * with "standalone='no'", ... ... The declaration of a parameter entity
1051 * must precede any reference to it...
1052 *
1053 * [ WFC: In DTD ]
1054 * Parameter-entity references may only appear in the DTD.
1055 * NOTE: misleading but this is handled.
1056 *
1057 * A PEReference may have been detected in the current input stream
1058 * the handling is done accordingly to
1059 * http://www.w3.org/TR/REC-xml#entproc
1060 * i.e.
1061 * - Included in literal in entity values
1062 * - Included as Paraemeter Entity reference within DTDs
1063 */
1064void
1065xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001066 xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001067 xmlEntityPtr entity = NULL;
1068 xmlParserInputPtr input;
1069
Daniel Veillard35008381999-10-25 13:15:52 +00001070 if (ctxt->token != 0) {
1071fprintf(stderr, "xmlParserHandlePEReference : ctxt->token != 0\n");
1072 return;
1073 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001074 if (CUR != '%') return;
1075 switch(ctxt->instate) {
1076 case XML_PARSER_CDATA_SECTION:
1077 return;
1078 case XML_PARSER_COMMENT:
1079 return;
1080 case XML_PARSER_EOF:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001081 ctxt->errNo = XML_ERR_PEREF_AT_EOF;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001082 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1083 ctxt->sax->error(ctxt->userData, "PEReference at EOF\n");
1084 ctxt->wellFormed = 0;
1085 return;
1086 case XML_PARSER_PROLOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001087 ctxt->errNo = XML_ERR_PEREF_IN_PROLOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001088 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1089 ctxt->sax->error(ctxt->userData, "PEReference in prolog!\n");
1090 ctxt->wellFormed = 0;
1091 return;
1092 case XML_PARSER_ENTITY_DECL:
1093 case XML_PARSER_CONTENT:
1094 case XML_PARSER_ATTRIBUTE_VALUE:
1095 /* we just ignore it there */
1096 return;
1097 case XML_PARSER_EPILOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001098 ctxt->errNo = XML_ERR_PEREF_IN_EPILOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001099 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1100 ctxt->sax->error(ctxt->userData, "PEReference in epilog!\n");
1101 ctxt->wellFormed = 0;
1102 return;
1103 case XML_PARSER_ENTITY_VALUE:
1104 /*
1105 * NOTE: in the case of entity values, we don't do the
Daniel Veillard51e3b151999-11-12 17:02:31 +00001106 * substitution here since we need the literal
Daniel Veillardb05deb71999-08-10 19:04:08 +00001107 * entity value to be able to save the internal
1108 * subset of the document.
1109 * This will be handled by xmlDecodeEntities
1110 */
1111 return;
1112 case XML_PARSER_DTD:
1113 /*
1114 * [WFC: Well-Formedness Constraint: PEs in Internal Subset]
1115 * In the internal DTD subset, parameter-entity references
1116 * can occur only where markup declarations can occur, not
1117 * within markup declarations.
1118 * In that case this is handled in xmlParseMarkupDecl
1119 */
1120 if ((ctxt->external == 0) && (ctxt->inputNr == 1))
1121 return;
1122 }
1123
1124 NEXT;
1125 name = xmlParseName(ctxt);
1126 if (name == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001127 ctxt->errNo = XML_ERR_PEREF_NO_NAME;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001128 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1129 ctxt->sax->error(ctxt->userData, "xmlHandlePEReference: no name\n");
1130 ctxt->wellFormed = 0;
1131 } else {
1132 if (CUR == ';') {
1133 NEXT;
1134 if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL))
1135 entity = ctxt->sax->getParameterEntity(ctxt->userData, name);
1136 if (entity == NULL) {
1137
1138 /*
1139 * [ WFC: Entity Declared ]
1140 * In a document without any DTD, a document with only an
1141 * internal DTD subset which contains no parameter entity
1142 * references, or a document with "standalone='yes'", ...
1143 * ... The declaration of a parameter entity must precede
1144 * any reference to it...
1145 */
1146 if ((ctxt->standalone == 1) ||
1147 ((ctxt->hasExternalSubset == 0) &&
1148 (ctxt->hasPErefs == 0))) {
1149 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1150 ctxt->sax->error(ctxt->userData,
1151 "PEReference: %%%s; not found\n", name);
1152 ctxt->wellFormed = 0;
1153 } else {
1154 /*
1155 * [ VC: Entity Declared ]
1156 * In a document with an external subset or external
1157 * parameter entities with "standalone='no'", ...
1158 * ... The declaration of a parameter entity must precede
1159 * any reference to it...
1160 */
1161 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1162 ctxt->sax->warning(ctxt->userData,
1163 "PEReference: %%%s; not found\n", name);
1164 ctxt->valid = 0;
1165 }
1166 } else {
1167 if ((entity->type == XML_INTERNAL_PARAMETER_ENTITY) ||
1168 (entity->type == XML_EXTERNAL_PARAMETER_ENTITY)) {
1169 /*
1170 * TODO !!!! handle the extra spaces added before and after
1171 * c.f. http://www.w3.org/TR/REC-xml#as-PE
1172 * TODO !!!! Avoid quote processing in parameters value
1173 * c.f. http://www.w3.org/TR/REC-xml#inliteral
1174 */
1175 input = xmlNewEntityInputStream(ctxt, entity);
1176 xmlPushInput(ctxt, input);
1177 } else {
1178 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1179 ctxt->sax->error(ctxt->userData,
1180 "xmlHandlePEReference: %s is not a parameter entity\n",
1181 name);
1182 ctxt->wellFormed = 0;
1183 }
1184 }
1185 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001186 ctxt->errNo = XML_ERR_PEREF_SEMICOL_MISSING;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001187 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1188 ctxt->sax->error(ctxt->userData,
1189 "xmlHandlePEReference: expecting ';'\n");
1190 ctxt->wellFormed = 0;
1191 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001192 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001193 }
1194}
1195
Daniel Veillard011b63c1999-06-02 17:44:04 +00001196/*
1197 * Macro used to grow the current buffer.
1198 */
1199#define growBuffer(buffer) { \
1200 buffer##_size *= 2; \
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001201 buffer = (xmlChar *) xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \
Daniel Veillard011b63c1999-06-02 17:44:04 +00001202 if (buffer == NULL) { \
1203 perror("realloc failed"); \
1204 exit(1); \
1205 } \
1206}
1207
Daniel Veillard011b63c1999-06-02 17:44:04 +00001208/**
1209 * xmlDecodeEntities:
1210 * @ctxt: the parser context
1211 * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF
1212 * @len: the len to decode (in bytes !), -1 for no size limit
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001213 * @end: an end marker xmlChar, 0 if none
1214 * @end2: an end marker xmlChar, 0 if none
1215 * @end3: an end marker xmlChar, 0 if none
Daniel Veillard011b63c1999-06-02 17:44:04 +00001216 *
1217 * [67] Reference ::= EntityRef | CharRef
1218 *
1219 * [69] PEReference ::= '%' Name ';'
1220 *
1221 * Returns A newly allocated string with the substitution done. The caller
1222 * must deallocate it !
1223 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001224xmlChar *
Daniel Veillard011b63c1999-06-02 17:44:04 +00001225xmlDecodeEntities(xmlParserCtxtPtr ctxt, int len, int what,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001226 xmlChar end, xmlChar end2, xmlChar end3) {
1227 xmlChar *buffer = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001228 int buffer_size = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001229 xmlChar *out = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001230
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001231 xmlChar *current = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001232 xmlEntityPtr ent;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001233 int nbchars = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001234 unsigned int max = (unsigned int) len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001235 xmlChar cur;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001236
1237 /*
1238 * allocate a translation buffer.
1239 */
1240 buffer_size = 1000;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001241 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard011b63c1999-06-02 17:44:04 +00001242 if (buffer == NULL) {
1243 perror("xmlDecodeEntities: malloc failed");
1244 return(NULL);
1245 }
1246 out = buffer;
1247
1248 /*
1249 * Ok loop until we reach one of the ending char or a size limit.
1250 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001251 cur = CUR;
1252 while ((nbchars < max) && (cur != end) &&
1253 (cur != end2) && (cur != end3)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001254
Daniel Veillardb05deb71999-08-10 19:04:08 +00001255 if (cur == 0) break;
1256 if ((cur == '&') && (NXT(1) == '#')) {
1257 int val = xmlParseCharRef(ctxt);
1258 *out++ = val;
1259 nbchars += 3;
1260 } else if ((cur == '&') && (what & XML_SUBSTITUTE_REF)) {
1261 ent = xmlParseEntityRef(ctxt);
1262 if ((ent != NULL) &&
1263 (ctxt->replaceEntities != 0)) {
1264 current = ent->content;
1265 while (*current != 0) {
1266 *out++ = *current++;
1267 if (out - buffer > buffer_size - 100) {
1268 int index = out - buffer;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001269
Daniel Veillardb05deb71999-08-10 19:04:08 +00001270 growBuffer(buffer);
1271 out = &buffer[index];
Daniel Veillard011b63c1999-06-02 17:44:04 +00001272 }
1273 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001274 nbchars += 3 + xmlStrlen(ent->name);
1275 } else if (ent != NULL) {
1276 int i = xmlStrlen(ent->name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001277 const xmlChar *cur = ent->name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001278
1279 nbchars += i + 2;
1280 *out++ = '&';
1281 if (out - buffer > buffer_size - i - 100) {
1282 int index = out - buffer;
1283
1284 growBuffer(buffer);
1285 out = &buffer[index];
1286 }
1287 for (;i > 0;i--)
1288 *out++ = *cur++;
1289 *out++ = ';';
Daniel Veillard011b63c1999-06-02 17:44:04 +00001290 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001291 } else if (cur == '%' && (what & XML_SUBSTITUTE_PEREF)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001292 /*
1293 * a PEReference induce to switch the entity flow,
1294 * we break here to flush the current set of chars
1295 * parsed if any. We will be called back later.
1296 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001297 if (nbchars != 0) break;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001298
1299 xmlParsePEReference(ctxt);
1300
1301 /*
1302 * Pop-up of finished entities.
1303 */
1304 while ((CUR == 0) && (ctxt->inputNr > 1))
1305 xmlPopInput(ctxt);
1306
Daniel Veillardb05deb71999-08-10 19:04:08 +00001307 break;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001308 } else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001309 /* invalid for UTF-8 , use COPY(out); !!!!!! */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001310 *out++ = cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001311 nbchars++;
Raph Levien05240da1999-06-15 21:27:11 +00001312 if (out - buffer > buffer_size - 100) {
1313 int index = out - buffer;
1314
1315 growBuffer(buffer);
1316 out = &buffer[index];
1317 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00001318 NEXT;
1319 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001320 cur = CUR;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001321 }
1322 *out++ = 0;
1323 return(buffer);
1324}
1325
Daniel Veillard260a68f1998-08-13 03:39:55 +00001326
1327/************************************************************************
1328 * *
Daniel Veillard27d88741999-05-29 11:51:49 +00001329 * Commodity functions to handle encodings *
1330 * *
1331 ************************************************************************/
1332
1333/**
1334 * xmlSwitchEncoding:
1335 * @ctxt: the parser context
Daniel Veillard00fdf371999-10-08 09:40:39 +00001336 * @enc: the encoding value (number)
Daniel Veillard27d88741999-05-29 11:51:49 +00001337 *
1338 * change the input functions when discovering the character encoding
1339 * of a given entity.
Daniel Veillard27d88741999-05-29 11:51:49 +00001340 */
1341void
1342xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
1343{
1344 switch (enc) {
1345 case XML_CHAR_ENCODING_ERROR:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001346 ctxt->errNo = XML_ERR_UNKNOWN_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001347 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1348 ctxt->sax->error(ctxt->userData, "encoding unknown\n");
1349 ctxt->wellFormed = 0;
1350 break;
1351 case XML_CHAR_ENCODING_NONE:
1352 /* let's assume it's UTF-8 without the XML decl */
1353 return;
1354 case XML_CHAR_ENCODING_UTF8:
1355 /* default encoding, no conversion should be needed */
1356 return;
1357 case XML_CHAR_ENCODING_UTF16LE:
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 little endian not supported\n");
1362 break;
1363 case XML_CHAR_ENCODING_UTF16BE:
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 UTF16 big endian not supported\n");
1368 break;
1369 case XML_CHAR_ENCODING_UCS4LE:
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 little endian not supported\n");
1374 break;
1375 case XML_CHAR_ENCODING_UCS4BE:
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 USC4 big endian not supported\n");
1380 break;
1381 case XML_CHAR_ENCODING_EBCDIC:
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 EBCDIC not supported\n");
1386 break;
1387 case XML_CHAR_ENCODING_UCS4_2143:
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 2143 not supported\n");
1392 break;
1393 case XML_CHAR_ENCODING_UCS4_3412:
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 UCS4 3412 not supported\n");
1398 break;
1399 case XML_CHAR_ENCODING_UCS2:
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 UCS2 not supported\n");
1404 break;
1405 case XML_CHAR_ENCODING_8859_1:
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_1 ISO Latin 1 not supported\n");
1410 break;
1411 case XML_CHAR_ENCODING_8859_2:
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_2 ISO Latin 2 not supported\n");
1416 break;
1417 case XML_CHAR_ENCODING_8859_3:
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_3 not supported\n");
1422 break;
1423 case XML_CHAR_ENCODING_8859_4:
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_4 not supported\n");
1428 break;
1429 case XML_CHAR_ENCODING_8859_5:
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_5 not supported\n");
1434 break;
1435 case XML_CHAR_ENCODING_8859_6:
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_6 not supported\n");
1440 break;
1441 case XML_CHAR_ENCODING_8859_7:
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_7 not supported\n");
1446 break;
1447 case XML_CHAR_ENCODING_8859_8:
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_8 not supported\n");
1452 break;
1453 case XML_CHAR_ENCODING_8859_9:
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_8859_9 not supported\n");
1458 break;
1459 case XML_CHAR_ENCODING_2022_JP:
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 ISO-2022-JPnot supported\n");
1464 break;
1465 case XML_CHAR_ENCODING_SHIFT_JIS:
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 Shift_JISnot supported\n");
1470 break;
1471 case XML_CHAR_ENCODING_EUC_JP:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001472 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001473 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1474 ctxt->sax->error(ctxt->userData,
1475 "char encoding EUC-JPnot supported\n");
1476 break;
1477 }
1478}
1479
1480/************************************************************************
1481 * *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001482 * Commodity functions to handle xmlChars *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001483 * *
1484 ************************************************************************/
1485
Daniel Veillard11e00581998-10-24 18:27:49 +00001486/**
1487 * xmlStrndup:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001488 * @cur: the input xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001489 * @len: the len of @cur
1490 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001491 * a strndup for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001492 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001493 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001494 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001495xmlChar *
1496xmlStrndup(const xmlChar *cur, int len) {
1497 xmlChar *ret = xmlMalloc((len + 1) * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001498
1499 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001500 fprintf(stderr, "malloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001501 (len + 1) * (long)sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001502 return(NULL);
1503 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001504 memcpy(ret, cur, len * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001505 ret[len] = 0;
1506 return(ret);
1507}
1508
Daniel Veillard11e00581998-10-24 18:27:49 +00001509/**
1510 * xmlStrdup:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001511 * @cur: the input xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001512 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001513 * a strdup for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001514 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001515 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001516 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001517xmlChar *
1518xmlStrdup(const xmlChar *cur) {
1519 const xmlChar *p = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001520
1521 while (IS_CHAR(*p)) p++;
1522 return(xmlStrndup(cur, p - cur));
1523}
1524
Daniel Veillard11e00581998-10-24 18:27:49 +00001525/**
1526 * xmlCharStrndup:
1527 * @cur: the input char *
1528 * @len: the len of @cur
1529 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001530 * a strndup for char's to xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001531 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001532 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001533 */
1534
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001535xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001536xmlCharStrndup(const char *cur, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001537 int i;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001538 xmlChar *ret = xmlMalloc((len + 1) * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001539
1540 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001541 fprintf(stderr, "malloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001542 (len + 1) * (long)sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001543 return(NULL);
1544 }
1545 for (i = 0;i < len;i++)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001546 ret[i] = (xmlChar) cur[i];
Daniel Veillard260a68f1998-08-13 03:39:55 +00001547 ret[len] = 0;
1548 return(ret);
1549}
1550
Daniel Veillard11e00581998-10-24 18:27:49 +00001551/**
1552 * xmlCharStrdup:
1553 * @cur: the input char *
1554 * @len: the len of @cur
1555 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001556 * a strdup for char's to xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001557 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001558 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001559 */
1560
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001561xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001562xmlCharStrdup(const char *cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001563 const char *p = cur;
1564
1565 while (*p != '\0') p++;
1566 return(xmlCharStrndup(cur, p - cur));
1567}
1568
Daniel Veillard11e00581998-10-24 18:27:49 +00001569/**
1570 * xmlStrcmp:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001571 * @str1: the first xmlChar *
1572 * @str2: the second xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001573 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001574 * a strcmp for xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001575 *
1576 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +00001577 */
1578
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001579int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001580xmlStrcmp(const xmlChar *str1, const xmlChar *str2) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001581 register int tmp;
1582
1583 do {
1584 tmp = *str1++ - *str2++;
1585 if (tmp != 0) return(tmp);
1586 } while ((*str1 != 0) && (*str2 != 0));
1587 return (*str1 - *str2);
1588}
1589
Daniel Veillard11e00581998-10-24 18:27:49 +00001590/**
1591 * xmlStrncmp:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001592 * @str1: the first xmlChar *
1593 * @str2: the second xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001594 * @len: the max comparison length
1595 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001596 * a strncmp for xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001597 *
1598 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +00001599 */
1600
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001601int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001602xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001603 register int tmp;
1604
1605 if (len <= 0) return(0);
1606 do {
1607 tmp = *str1++ - *str2++;
1608 if (tmp != 0) return(tmp);
1609 len--;
1610 if (len <= 0) return(0);
1611 } while ((*str1 != 0) && (*str2 != 0));
1612 return (*str1 - *str2);
1613}
1614
Daniel Veillard11e00581998-10-24 18:27:49 +00001615/**
1616 * xmlStrchr:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001617 * @str: the xmlChar * array
1618 * @val: the xmlChar to search
Daniel Veillard11e00581998-10-24 18:27:49 +00001619 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001620 * a strchr for xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001621 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001622 * Returns the xmlChar * for the first occurence or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001623 */
1624
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001625const xmlChar *
1626xmlStrchr(const xmlChar *str, xmlChar val) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001627 while (*str != 0) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001628 if (*str == val) return((xmlChar *) str);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001629 str++;
1630 }
1631 return(NULL);
1632}
1633
Daniel Veillard11e00581998-10-24 18:27:49 +00001634/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001635 * xmlStrstr:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001636 * @str: the xmlChar * array (haystack)
1637 * @val: the xmlChar to search (needle)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001638 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001639 * a strstr for xmlChar's
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001640 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001641 * Returns the xmlChar * for the first occurence or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001642 */
1643
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001644const xmlChar *
1645xmlStrstr(const xmlChar *str, xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001646 int n;
1647
1648 if (str == NULL) return(NULL);
1649 if (val == NULL) return(NULL);
1650 n = xmlStrlen(val);
1651
1652 if (n == 0) return(str);
1653 while (*str != 0) {
1654 if (*str == *val) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001655 if (!xmlStrncmp(str, val, n)) return((const xmlChar *) str);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001656 }
1657 str++;
1658 }
1659 return(NULL);
1660}
1661
1662/**
1663 * xmlStrsub:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001664 * @str: the xmlChar * array (haystack)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001665 * @start: the index of the first char (zero based)
1666 * @len: the length of the substring
1667 *
1668 * Extract a substring of a given string
1669 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001670 * Returns the xmlChar * for the first occurence or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001671 */
1672
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001673xmlChar *
1674xmlStrsub(const xmlChar *str, int start, int len) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001675 int i;
1676
1677 if (str == NULL) return(NULL);
1678 if (start < 0) return(NULL);
1679 if (len < 0) return(NULL);
1680
1681 for (i = 0;i < start;i++) {
1682 if (*str == 0) return(NULL);
1683 str++;
1684 }
1685 if (*str == 0) return(NULL);
1686 return(xmlStrndup(str, len));
1687}
1688
1689/**
Daniel Veillard11e00581998-10-24 18:27:49 +00001690 * xmlStrlen:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001691 * @str: the xmlChar * array
Daniel Veillard11e00581998-10-24 18:27:49 +00001692 *
Daniel Veillard51e3b151999-11-12 17:02:31 +00001693 * length of a xmlChar's string
Daniel Veillard1e346af1999-02-22 10:33:01 +00001694 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001695 * Returns the number of xmlChar contained in the ARRAY.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001696 */
1697
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001698int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001699xmlStrlen(const xmlChar *str) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001700 int len = 0;
1701
1702 if (str == NULL) return(0);
1703 while (*str != 0) {
1704 str++;
1705 len++;
1706 }
1707 return(len);
1708}
1709
Daniel Veillard11e00581998-10-24 18:27:49 +00001710/**
1711 * xmlStrncat:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001712 * @cur: the original xmlChar * array
1713 * @add: the xmlChar * array added
Daniel Veillard11e00581998-10-24 18:27:49 +00001714 * @len: the length of @add
1715 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001716 * a strncat for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001717 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001718 * Returns a new xmlChar * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001719 */
1720
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001721xmlChar *
1722xmlStrncat(xmlChar *cur, const xmlChar *add, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001723 int size;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001724 xmlChar *ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001725
1726 if ((add == NULL) || (len == 0))
1727 return(cur);
1728 if (cur == NULL)
1729 return(xmlStrndup(add, len));
1730
1731 size = xmlStrlen(cur);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001732 ret = xmlRealloc(cur, (size + len + 1) * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001733 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001734 fprintf(stderr, "xmlStrncat: realloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001735 (size + len + 1) * (long)sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001736 return(cur);
1737 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001738 memcpy(&ret[size], add, len * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001739 ret[size + len] = 0;
1740 return(ret);
1741}
1742
Daniel Veillard11e00581998-10-24 18:27:49 +00001743/**
1744 * xmlStrcat:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001745 * @cur: the original xmlChar * array
1746 * @add: the xmlChar * array added
Daniel Veillard11e00581998-10-24 18:27:49 +00001747 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001748 * a strcat for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001749 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001750 * Returns a new xmlChar * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001751 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001752xmlChar *
1753xmlStrcat(xmlChar *cur, const xmlChar *add) {
1754 const xmlChar *p = add;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001755
1756 if (add == NULL) return(cur);
1757 if (cur == NULL)
1758 return(xmlStrdup(add));
1759
1760 while (IS_CHAR(*p)) p++;
1761 return(xmlStrncat(cur, add, p - add));
1762}
1763
1764/************************************************************************
1765 * *
1766 * Commodity functions, cleanup needed ? *
1767 * *
1768 ************************************************************************/
1769
Daniel Veillard11e00581998-10-24 18:27:49 +00001770/**
1771 * areBlanks:
1772 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001773 * @str: a xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001774 * @len: the size of @str
1775 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001776 * Is this a sequence of blank chars that one can ignore ?
Daniel Veillard11e00581998-10-24 18:27:49 +00001777 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001778 * TODO: Whether white space are significant has to be checked accordingly
1779 * to DTD informations if available
Daniel Veillard1e346af1999-02-22 10:33:01 +00001780 *
1781 * Returns 1 if ignorable 0 otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001782 */
1783
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001784static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001785 int i, ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001786 xmlNodePtr lastChild;
1787
1788 for (i = 0;i < len;i++)
1789 if (!(IS_BLANK(str[i]))) return(0);
1790
1791 if (CUR != '<') return(0);
Daniel Veillard517752b1999-04-05 12:20:10 +00001792 if (ctxt->node == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001793 if (ctxt->myDoc != NULL) {
1794 ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name);
1795 if (ret == 0) return(1);
1796 if (ret == 1) return(0);
1797 }
1798 /*
1799 * heuristic
1800 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00001801 lastChild = xmlGetLastChild(ctxt->node);
1802 if (lastChild == NULL) {
1803 if (ctxt->node->content != NULL) return(0);
1804 } else if (xmlNodeIsText(lastChild))
1805 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001806 else if ((ctxt->node->childs != NULL) &&
1807 (xmlNodeIsText(ctxt->node->childs)))
1808 return(0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001809 return(1);
1810}
1811
Daniel Veillard11e00581998-10-24 18:27:49 +00001812/**
1813 * xmlHandleEntity:
1814 * @ctxt: an XML parser context
1815 * @entity: an XML entity pointer.
1816 *
1817 * Default handling of defined entities, when should we define a new input
Daniel Veillard260a68f1998-08-13 03:39:55 +00001818 * stream ? When do we just handle that as a set of chars ?
Daniel Veillardb05deb71999-08-10 19:04:08 +00001819 *
1820 * OBSOLETE: to be removed at some point.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001821 */
1822
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001823void
1824xmlHandleEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001825 int len;
Daniel Veillardccb09631998-10-27 06:21:04 +00001826 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001827
1828 if (entity->content == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001829 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001830 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001831 ctxt->sax->error(ctxt->userData, "xmlHandleEntity %s: content == NULL\n",
Daniel Veillard260a68f1998-08-13 03:39:55 +00001832 entity->name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001833 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001834 return;
1835 }
1836 len = xmlStrlen(entity->content);
1837 if (len <= 2) goto handle_as_char;
1838
1839 /*
1840 * Redefine its content as an input stream.
1841 */
Daniel Veillardccb09631998-10-27 06:21:04 +00001842 input = xmlNewEntityInputStream(ctxt, entity);
1843 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001844 return;
1845
1846handle_as_char:
1847 /*
1848 * Just handle the content as a set of chars.
1849 */
Daniel Veillard517752b1999-04-05 12:20:10 +00001850 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001851 ctxt->sax->characters(ctxt->userData, entity->content, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001852
1853}
1854
1855/*
1856 * Forward definition for recusive behaviour.
1857 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00001858void xmlParsePEReference(xmlParserCtxtPtr ctxt);
1859void xmlParseReference(xmlParserCtxtPtr ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001860
1861/************************************************************************
1862 * *
1863 * Extra stuff for namespace support *
1864 * Relates to http://www.w3.org/TR/WD-xml-names *
1865 * *
1866 ************************************************************************/
1867
Daniel Veillard11e00581998-10-24 18:27:49 +00001868/**
1869 * xmlNamespaceParseNCName:
1870 * @ctxt: an XML parser context
1871 *
1872 * parse an XML namespace name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001873 *
1874 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
1875 *
1876 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
1877 * CombiningChar | Extender
Daniel Veillard1e346af1999-02-22 10:33:01 +00001878 *
1879 * Returns the namespace name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001880 */
1881
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001882xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001883xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001884 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001885 int len = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001886
1887 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001888
1889 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1890 (CUR == '.') || (CUR == '-') ||
1891 (CUR == '_') ||
1892 (IS_COMBINING(CUR)) ||
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001893 (IS_EXTENDER(CUR))) {
1894 buf[len++] = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001895 NEXT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001896 if (len >= XML_MAX_NAMELEN) {
1897 fprintf(stderr,
1898 "xmlNamespaceParseNCName: reached XML_MAX_NAMELEN limit\n");
1899 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1900 (CUR == '.') || (CUR == '-') ||
1901 (CUR == '_') ||
1902 (IS_COMBINING(CUR)) ||
1903 (IS_EXTENDER(CUR)))
1904 NEXT;
1905 break;
1906 }
1907 }
1908 return(xmlStrndup(buf, len));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001909}
1910
Daniel Veillard11e00581998-10-24 18:27:49 +00001911/**
1912 * xmlNamespaceParseQName:
1913 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001914 * @prefix: a xmlChar **
Daniel Veillard11e00581998-10-24 18:27:49 +00001915 *
1916 * parse an XML qualified name
Daniel Veillard260a68f1998-08-13 03:39:55 +00001917 *
1918 * [NS 5] QName ::= (Prefix ':')? LocalPart
1919 *
1920 * [NS 6] Prefix ::= NCName
1921 *
1922 * [NS 7] LocalPart ::= NCName
Daniel Veillard1e346af1999-02-22 10:33:01 +00001923 *
Daniel Veillard51e3b151999-11-12 17:02:31 +00001924 * Returns the local part, and prefix is updated
Daniel Veillard11e00581998-10-24 18:27:49 +00001925 * to get the Prefix if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001926 */
1927
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001928xmlChar *
1929xmlNamespaceParseQName(xmlParserCtxtPtr ctxt, xmlChar **prefix) {
1930 xmlChar *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001931
1932 *prefix = NULL;
1933 ret = xmlNamespaceParseNCName(ctxt);
1934 if (CUR == ':') {
1935 *prefix = ret;
1936 NEXT;
1937 ret = xmlNamespaceParseNCName(ctxt);
1938 }
1939
1940 return(ret);
1941}
1942
Daniel Veillard11e00581998-10-24 18:27:49 +00001943/**
Daniel Veillard517752b1999-04-05 12:20:10 +00001944 * xmlSplitQName:
1945 * @name: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001946 * @prefix: a xmlChar **
Daniel Veillard517752b1999-04-05 12:20:10 +00001947 *
1948 * parse an XML qualified name string
1949 *
1950 * [NS 5] QName ::= (Prefix ':')? LocalPart
1951 *
1952 * [NS 6] Prefix ::= NCName
1953 *
1954 * [NS 7] LocalPart ::= NCName
1955 *
Daniel Veillard51e3b151999-11-12 17:02:31 +00001956 * Returns the local part, and prefix is updated
Daniel Veillard517752b1999-04-05 12:20:10 +00001957 * to get the Prefix if any.
1958 */
1959
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001960xmlChar *
1961xmlSplitQName(const xmlChar *name, xmlChar **prefix) {
1962 xmlChar *ret = NULL;
1963 const xmlChar *q;
1964 const xmlChar *cur = name;
Daniel Veillard517752b1999-04-05 12:20:10 +00001965
1966 *prefix = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001967
1968 /* xml: prefix is not really a namespace */
1969 if ((cur[0] == 'x') && (cur[1] == 'm') &&
1970 (cur[2] == 'l') && (cur[3] == ':'))
1971 return(xmlStrdup(name));
1972
Daniel Veillard517752b1999-04-05 12:20:10 +00001973 if (!IS_LETTER(*cur) && (*cur != '_')) return(NULL);
1974 q = cur++;
1975
1976 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1977 (*cur == '.') || (*cur == '-') ||
1978 (*cur == '_') ||
1979 (IS_COMBINING(*cur)) ||
1980 (IS_EXTENDER(*cur)))
1981 cur++;
1982
1983 ret = xmlStrndup(q, cur - q);
1984
1985 if (*cur == ':') {
1986 cur++;
1987 if (!IS_LETTER(*cur) && (*cur != '_')) return(ret);
1988 *prefix = ret;
1989
1990 q = cur++;
1991
1992 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1993 (*cur == '.') || (*cur == '-') ||
1994 (*cur == '_') ||
1995 (IS_COMBINING(*cur)) ||
1996 (IS_EXTENDER(*cur)))
1997 cur++;
1998
1999 ret = xmlStrndup(q, cur - q);
2000 }
2001
2002 return(ret);
2003}
2004/**
Daniel Veillard11e00581998-10-24 18:27:49 +00002005 * xmlNamespaceParseNSDef:
2006 * @ctxt: an XML parser context
2007 *
2008 * parse a namespace prefix declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00002009 *
2010 * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral
2011 *
2012 * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)?
Daniel Veillard1e346af1999-02-22 10:33:01 +00002013 *
2014 * Returns the namespace name
Daniel Veillard260a68f1998-08-13 03:39:55 +00002015 */
2016
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002017xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002018xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002019 xmlChar *name = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002020
2021 if ((CUR == 'x') && (NXT(1) == 'm') &&
2022 (NXT(2) == 'l') && (NXT(3) == 'n') &&
2023 (NXT(4) == 's')) {
2024 SKIP(5);
2025 if (CUR == ':') {
2026 NEXT;
2027 name = xmlNamespaceParseNCName(ctxt);
2028 }
2029 }
2030 return(name);
2031}
2032
Daniel Veillard11e00581998-10-24 18:27:49 +00002033/**
2034 * xmlParseQuotedString:
2035 * @ctxt: an XML parser context
2036 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002037 * [OLD] Parse and return a string between quotes or doublequotes
Daniel Veillardb05deb71999-08-10 19:04:08 +00002038 * To be removed at next drop of binary compatibility
Daniel Veillard1e346af1999-02-22 10:33:01 +00002039 *
2040 * Returns the string parser or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002041 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002042xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002043xmlParseQuotedString(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002044 xmlChar *ret = NULL;
2045 const xmlChar *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002046
2047 if (CUR == '"') {
2048 NEXT;
2049 q = CUR_PTR;
2050 while (IS_CHAR(CUR) && (CUR != '"')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002051 if (CUR != '"') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002052 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002053 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002054 ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002055 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002056 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002057 ret = xmlStrndup(q, CUR_PTR - q);
2058 NEXT;
2059 }
2060 } else if (CUR == '\''){
2061 NEXT;
2062 q = CUR_PTR;
2063 while (IS_CHAR(CUR) && (CUR != '\'')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002064 if (CUR != '\'') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002065 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002066 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002067 ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002068 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002069 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002070 ret = xmlStrndup(q, CUR_PTR - q);
2071 NEXT;
2072 }
2073 }
2074 return(ret);
2075}
2076
Daniel Veillard11e00581998-10-24 18:27:49 +00002077/**
2078 * xmlParseNamespace:
2079 * @ctxt: an XML parser context
2080 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002081 * [OLD] xmlParseNamespace: parse specific PI '<?namespace ...' constructs.
2082 *
2083 * This is what the older xml-name Working Draft specified, a bunch of
2084 * other stuff may still rely on it, so support is still here as
Daniel Veillard51e3b151999-11-12 17:02:31 +00002085 * if it was declared on the root of the Tree:-(
Daniel Veillardb05deb71999-08-10 19:04:08 +00002086 *
2087 * To be removed at next drop of binary compatibility
Daniel Veillard260a68f1998-08-13 03:39:55 +00002088 */
2089
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002090void
2091xmlParseNamespace(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002092 xmlChar *href = NULL;
2093 xmlChar *prefix = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002094 int garbage = 0;
2095
2096 /*
2097 * We just skipped "namespace" or "xml:namespace"
2098 */
2099 SKIP_BLANKS;
2100
2101 while (IS_CHAR(CUR) && (CUR != '>')) {
2102 /*
2103 * We can have "ns" or "prefix" attributes
2104 * Old encoding as 'href' or 'AS' attributes is still supported
2105 */
2106 if ((CUR == 'n') && (NXT(1) == 's')) {
2107 garbage = 0;
2108 SKIP(2);
2109 SKIP_BLANKS;
2110
2111 if (CUR != '=') continue;
2112 NEXT;
2113 SKIP_BLANKS;
2114
2115 href = xmlParseQuotedString(ctxt);
2116 SKIP_BLANKS;
2117 } else if ((CUR == 'h') && (NXT(1) == 'r') &&
2118 (NXT(2) == 'e') && (NXT(3) == 'f')) {
2119 garbage = 0;
2120 SKIP(4);
2121 SKIP_BLANKS;
2122
2123 if (CUR != '=') continue;
2124 NEXT;
2125 SKIP_BLANKS;
2126
2127 href = xmlParseQuotedString(ctxt);
2128 SKIP_BLANKS;
2129 } else if ((CUR == 'p') && (NXT(1) == 'r') &&
2130 (NXT(2) == 'e') && (NXT(3) == 'f') &&
2131 (NXT(4) == 'i') && (NXT(5) == 'x')) {
2132 garbage = 0;
2133 SKIP(6);
2134 SKIP_BLANKS;
2135
2136 if (CUR != '=') continue;
2137 NEXT;
2138 SKIP_BLANKS;
2139
2140 prefix = xmlParseQuotedString(ctxt);
2141 SKIP_BLANKS;
2142 } else if ((CUR == 'A') && (NXT(1) == 'S')) {
2143 garbage = 0;
2144 SKIP(2);
2145 SKIP_BLANKS;
2146
2147 if (CUR != '=') continue;
2148 NEXT;
2149 SKIP_BLANKS;
2150
2151 prefix = xmlParseQuotedString(ctxt);
2152 SKIP_BLANKS;
2153 } else if ((CUR == '?') && (NXT(1) == '>')) {
2154 garbage = 0;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002155 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002156 } else {
2157 /*
2158 * Found garbage when parsing the namespace
2159 */
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002160 if (!garbage) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002161 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002162 ctxt->sax->error(ctxt->userData,
2163 "xmlParseNamespace found garbage\n");
2164 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002165 ctxt->errNo = XML_ERR_NS_DECL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002166 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002167 NEXT;
2168 }
2169 }
2170
2171 MOVETO_ENDTAG(CUR_PTR);
2172 NEXT;
2173
2174 /*
2175 * Register the DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002176 if (href != NULL)
Daniel Veillard517752b1999-04-05 12:20:10 +00002177 if ((ctxt->sax != NULL) && (ctxt->sax->globalNamespace != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002178 ctxt->sax->globalNamespace(ctxt->userData, href, prefix);
Daniel Veillard517752b1999-04-05 12:20:10 +00002179 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00002180
Daniel Veillard6454aec1999-09-02 22:04:43 +00002181 if (prefix != NULL) xmlFree(prefix);
2182 if (href != NULL) xmlFree(href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002183}
2184
2185/************************************************************************
2186 * *
2187 * The parser itself *
2188 * Relates to http://www.w3.org/TR/REC-xml *
2189 * *
2190 ************************************************************************/
2191
Daniel Veillard11e00581998-10-24 18:27:49 +00002192/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002193 * xmlScanName:
2194 * @ctxt: an XML parser context
2195 *
2196 * Trickery: parse an XML name but without consuming the input flow
2197 * Needed for rollback cases.
2198 *
2199 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
2200 * CombiningChar | Extender
2201 *
2202 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
2203 *
2204 * [6] Names ::= Name (S Name)*
2205 *
2206 * Returns the Name parsed or NULL
2207 */
2208
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002209xmlChar *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002210xmlScanName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002211 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb05deb71999-08-10 19:04:08 +00002212 int len = 0;
2213
2214 GROW;
2215 if (!IS_LETTER(CUR) && (CUR != '_') &&
2216 (CUR != ':')) {
2217 return(NULL);
2218 }
2219
2220 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
2221 (NXT(len) == '.') || (NXT(len) == '-') ||
2222 (NXT(len) == '_') || (NXT(len) == ':') ||
2223 (IS_COMBINING(NXT(len))) ||
2224 (IS_EXTENDER(NXT(len)))) {
2225 buf[len] = NXT(len);
2226 len++;
2227 if (len >= XML_MAX_NAMELEN) {
2228 fprintf(stderr,
2229 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
2230 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
2231 (NXT(len) == '.') || (NXT(len) == '-') ||
2232 (NXT(len) == '_') || (NXT(len) == ':') ||
2233 (IS_COMBINING(NXT(len))) ||
2234 (IS_EXTENDER(NXT(len))))
2235 len++;
2236 break;
2237 }
2238 }
2239 return(xmlStrndup(buf, len));
2240}
2241
2242/**
Daniel Veillard11e00581998-10-24 18:27:49 +00002243 * xmlParseName:
2244 * @ctxt: an XML parser context
2245 *
2246 * parse an XML name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002247 *
2248 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
2249 * CombiningChar | Extender
2250 *
2251 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
2252 *
2253 * [6] Names ::= Name (S Name)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00002254 *
2255 * Returns the Name parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002256 */
2257
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002258xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002259xmlParseName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002260 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002261 int len = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002262 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002263
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002264 GROW;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002265 cur = CUR;
2266 if (!IS_LETTER(cur) && (cur != '_') &&
2267 (cur != ':')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002268 return(NULL);
2269 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002270
Daniel Veillardb05deb71999-08-10 19:04:08 +00002271 while ((IS_LETTER(cur)) || (IS_DIGIT(cur)) ||
2272 (cur == '.') || (cur == '-') ||
2273 (cur == '_') || (cur == ':') ||
2274 (IS_COMBINING(cur)) ||
2275 (IS_EXTENDER(cur))) {
2276 buf[len++] = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002277 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002278 cur = CUR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002279 if (len >= XML_MAX_NAMELEN) {
2280 fprintf(stderr,
2281 "xmlParseName: reached XML_MAX_NAMELEN limit\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00002282 while ((IS_LETTER(cur)) || (IS_DIGIT(cur)) ||
2283 (cur == '.') || (cur == '-') ||
2284 (cur == '_') || (cur == ':') ||
2285 (IS_COMBINING(cur)) ||
2286 (IS_EXTENDER(cur))) {
2287 NEXT;
2288 cur = CUR;
2289 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002290 break;
2291 }
2292 }
2293 return(xmlStrndup(buf, len));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002294}
2295
Daniel Veillard11e00581998-10-24 18:27:49 +00002296/**
2297 * xmlParseNmtoken:
2298 * @ctxt: an XML parser context
2299 *
2300 * parse an XML Nmtoken.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002301 *
2302 * [7] Nmtoken ::= (NameChar)+
2303 *
2304 * [8] Nmtokens ::= Nmtoken (S Nmtoken)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00002305 *
2306 * Returns the Nmtoken parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002307 */
2308
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002309xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002310xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002311 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002312 int len = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002313
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002314 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002315 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2316 (CUR == '.') || (CUR == '-') ||
2317 (CUR == '_') || (CUR == ':') ||
2318 (IS_COMBINING(CUR)) ||
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002319 (IS_EXTENDER(CUR))) {
2320 buf[len++] = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002321 NEXT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002322 if (len >= XML_MAX_NAMELEN) {
2323 fprintf(stderr,
2324 "xmlParseNmtoken: reached XML_MAX_NAMELEN limit\n");
2325 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2326 (CUR == '.') || (CUR == '-') ||
2327 (CUR == '_') || (CUR == ':') ||
2328 (IS_COMBINING(CUR)) ||
2329 (IS_EXTENDER(CUR)))
2330 NEXT;
2331 break;
2332 }
2333 }
2334 return(xmlStrndup(buf, len));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002335}
2336
Daniel Veillard11e00581998-10-24 18:27:49 +00002337/**
2338 * xmlParseEntityValue:
2339 * @ctxt: an XML parser context
Daniel Veillard011b63c1999-06-02 17:44:04 +00002340 * @orig: if non-NULL store a copy of the original entity value
Daniel Veillard11e00581998-10-24 18:27:49 +00002341 *
2342 * parse a value for ENTITY decl.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002343 *
2344 * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
2345 * "'" ([^%&'] | PEReference | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00002346 *
Daniel Veillard011b63c1999-06-02 17:44:04 +00002347 * Returns the EntityValue parsed with reference substitued or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002348 */
2349
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002350xmlChar *
2351xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) {
2352 xmlChar *ret = NULL;
2353 const xmlChar *org = NULL;
2354 const xmlChar *tst = NULL;
2355 const xmlChar *temp = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002356 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002357
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002358 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002359 if (CUR == '"') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002360 ctxt->instate = XML_PARSER_ENTITY_VALUE;
2361 input = ctxt->input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002362 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002363 org = CUR_PTR;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002364 /*
2365 * NOTE: 4.4.5 Included in Literal
2366 * When a parameter entity reference appears in a literal entity
2367 * value, ... a single or double quote character in the replacement
2368 * text is always treated as a normal data character and will not
2369 * terminate the literal.
2370 * In practice it means we stop the loop only when back at parsing
2371 * the initial entity and the quote is found
2372 */
2373 while ((CUR != '"') || (ctxt->input != input)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002374 tst = CUR_PTR;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002375 /*
2376 * NOTE: 4.4.7 Bypassed
2377 * When a general entity reference appears in the EntityValue in
2378 * an entity declaration, it is bypassed and left as is.
2379 * so XML_SUBSTITUTE_REF is not set.
2380 */
2381 if (ctxt->input != input)
2382 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_PEREF,
2383 0, 0, 0);
2384 else
2385 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_PEREF,
2386 '"', 0, 0);
2387
2388 /*
2389 * Pop-up of finished entities.
2390 */
2391 while ((CUR == 0) && (ctxt->inputNr > 1))
2392 xmlPopInput(ctxt);
2393
2394 if ((temp == NULL) && (tst == CUR_PTR)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002395 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002396 break;
2397 }
2398 if ((temp[0] == 0) && (tst == CUR_PTR)) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00002399 xmlFree((char *)temp);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002400 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002401 break;
2402 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00002403 ret = xmlStrcat(ret, temp);
Daniel Veillard6454aec1999-09-02 22:04:43 +00002404 if (temp != NULL) xmlFree((char *)temp);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002405 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002406 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00002407 if (CUR != '"') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002408 ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002409 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002410 ctxt->sax->error(ctxt->userData, "EntityValue: \" expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002411 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002412 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002413 if (orig != NULL) /* !!!!!!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00002414 *orig = xmlStrndup(org, CUR_PTR - org);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002415 if (ret == NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002416 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002417 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002418 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002419 } else if (CUR == '\'') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002420 ctxt->instate = XML_PARSER_ENTITY_VALUE;
2421 input = ctxt->input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002422 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002423 org = CUR_PTR;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002424 /*
2425 * NOTE: 4.4.5 Included in Literal
2426 * When a parameter entity reference appears in a literal entity
2427 * value, ... a single or double quote character in the replacement
2428 * text is always treated as a normal data character and will not
2429 * terminate the literal.
2430 * In practice it means we stop the loop only when back at parsing
2431 * the initial entity and the quote is found
2432 */
2433 while ((CUR != '\'') || (ctxt->input != input)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00002434 tst = CUR_PTR;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002435 /*
2436 * NOTE: 4.4.7 Bypassed
2437 * When a general entity reference appears in the EntityValue in
2438 * an entity declaration, it is bypassed and left as is.
2439 * so XML_SUBSTITUTE_REF is not set.
2440 */
2441 if (ctxt->input != input)
2442 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_PEREF,
2443 0, 0, 0);
2444 else
2445 temp = xmlDecodeEntities(ctxt, -1, XML_SUBSTITUTE_PEREF,
2446 '\'', 0, 0);
2447
2448 /*
2449 * Pop-up of finished entities.
2450 */
2451 while ((CUR == 0) && (ctxt->inputNr > 1))
2452 xmlPopInput(ctxt);
2453
2454 if ((temp == NULL) && (tst == CUR_PTR)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002455 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002456 break;
2457 }
2458 if ((temp[0] == 0) && (tst == CUR_PTR)) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00002459 xmlFree((char *)temp);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002460 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002461 break;
2462 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00002463 ret = xmlStrcat(ret, temp);
Daniel Veillard6454aec1999-09-02 22:04:43 +00002464 if (temp != NULL) xmlFree((char *)temp);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002465 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002466 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00002467 if (CUR != '\'') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002468 ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002469 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002470 ctxt->sax->error(ctxt->userData, "EntityValue: ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002471 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002472 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002473 if (orig != NULL) /* !!!!!!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00002474 *orig = xmlStrndup(org, CUR_PTR - org);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002475 if (ret == NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002476 ret = xmlStrndup((xmlChar *) "", 0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002477 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00002478 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002479 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002480 ctxt->errNo = XML_ERR_ENTITY_NOT_STARTED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002481 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002482 ctxt->sax->error(ctxt->userData, "EntityValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002483 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002484 }
2485
2486 return(ret);
2487}
2488
Daniel Veillard11e00581998-10-24 18:27:49 +00002489/**
2490 * xmlParseAttValue:
2491 * @ctxt: an XML parser context
2492 *
2493 * parse a value for an attribute
Daniel Veillard011b63c1999-06-02 17:44:04 +00002494 * Note: the parser won't do substitution of entities here, this
Daniel Veillardb96e6431999-08-29 21:02:19 +00002495 * will be handled later in xmlStringGetNodeList
Daniel Veillard260a68f1998-08-13 03:39:55 +00002496 *
2497 * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
2498 * "'" ([^<&'] | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00002499 *
Daniel Veillard7f858501999-11-17 17:32:38 +00002500 * 3.3.3 Attribute-Value Normalization:
2501 * Before the value of an attribute is passed to the application or
2502 * checked for validity, the XML processor must normalize it as follows:
2503 * - a character reference is processed by appending the referenced
2504 * character to the attribute value
2505 * - an entity reference is processed by recursively processing the
2506 * replacement text of the entity
2507 * - a whitespace character (#x20, #xD, #xA, #x9) is processed by
2508 * appending #x20 to the normalized value, except that only a single
2509 * #x20 is appended for a "#xD#xA" sequence that is part of an external
2510 * parsed entity or the literal entity value of an internal parsed entity
2511 * - other characters are processed by appending them to the normalized value
Daniel Veillard07136651999-11-18 14:02:05 +00002512 * If the declared value is not CDATA, then the XML processor must further
2513 * process the normalized attribute value by discarding any leading and
2514 * trailing space (#x20) characters, and by replacing sequences of space
2515 * (#x20) characters by a single space (#x20) character.
2516 * All attributes for which no declaration has been read should be treated
2517 * by a non-validating parser as if declared CDATA.
Daniel Veillard7f858501999-11-17 17:32:38 +00002518 *
2519 * Returns the AttValue parsed or NULL. The value has to be freed by the caller.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002520 */
2521
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002522xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002523xmlParseAttValue(xmlParserCtxtPtr ctxt) {
Daniel Veillard7f858501999-11-17 17:32:38 +00002524 xmlChar limit = 0;
2525 xmlChar *buffer = NULL;
2526 int buffer_size = 0;
2527 xmlChar *out = NULL;
2528
2529 xmlChar *current = NULL;
2530 xmlEntityPtr ent;
2531 xmlChar cur;
Daniel Veillard7f858501999-11-17 17:32:38 +00002532
Daniel Veillard260a68f1998-08-13 03:39:55 +00002533
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002534 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002535 if (CUR == '"') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002536 ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
Daniel Veillard7f858501999-11-17 17:32:38 +00002537 limit = '"';
Daniel Veillard260a68f1998-08-13 03:39:55 +00002538 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002539 } else if (CUR == '\'') {
Daniel Veillard7f858501999-11-17 17:32:38 +00002540 limit = '\'';
Daniel Veillardb05deb71999-08-10 19:04:08 +00002541 ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002542 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002543 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002544 ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_STARTED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002545 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002546 ctxt->sax->error(ctxt->userData, "AttValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002547 ctxt->wellFormed = 0;
Daniel Veillard7f858501999-11-17 17:32:38 +00002548 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002549 }
2550
Daniel Veillard7f858501999-11-17 17:32:38 +00002551 /*
2552 * allocate a translation buffer.
2553 */
2554 buffer_size = 100;
2555 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
2556 if (buffer == NULL) {
2557 perror("xmlParseAttValue: malloc failed");
2558 return(NULL);
2559 }
2560 out = buffer;
2561
2562 /*
2563 * Ok loop until we reach one of the ending char or a size limit.
2564 */
2565 cur = CUR;
2566 while ((cur != limit) && (cur != '<')) {
2567
2568 if (cur == 0) break;
2569 if ((cur == '&') && (NXT(1) == '#')) {
2570 int val = xmlParseCharRef(ctxt);
2571 *out++ = val;
Daniel Veillard7f858501999-11-17 17:32:38 +00002572 } else if (cur == '&') {
2573 ent = xmlParseEntityRef(ctxt);
2574 if ((ent != NULL) &&
2575 (ctxt->replaceEntities != 0)) {
2576 current = ent->content;
2577 while (*current != 0) {
2578 *out++ = *current++;
2579 if (out - buffer > buffer_size - 10) {
2580 int index = out - buffer;
2581
2582 growBuffer(buffer);
2583 out = &buffer[index];
2584 }
2585 }
2586 } else if (ent != NULL) {
2587 int i = xmlStrlen(ent->name);
2588 const xmlChar *cur = ent->name;
2589
2590 *out++ = '&';
2591 if (out - buffer > buffer_size - i - 10) {
2592 int index = out - buffer;
2593
2594 growBuffer(buffer);
2595 out = &buffer[index];
2596 }
2597 for (;i > 0;i--)
2598 *out++ = *cur++;
2599 *out++ = ';';
2600 }
Daniel Veillard7f858501999-11-17 17:32:38 +00002601 } else {
2602 /* invalid for UTF-8 , use COPY(out); !!!!!! */
2603 if ((cur == 0x20) || (cur == 0xD) || (cur == 0xA) || (cur == 0x9)) {
Daniel Veillard07136651999-11-18 14:02:05 +00002604 *out++ = 0x20;
2605 if (out - buffer > buffer_size - 10) {
2606 int index = out - buffer;
2607
2608 growBuffer(buffer);
2609 out = &buffer[index];
Daniel Veillard7f858501999-11-17 17:32:38 +00002610 }
Daniel Veillard7f858501999-11-17 17:32:38 +00002611 } else {
2612 *out++ = cur;
2613 if (out - buffer > buffer_size - 10) {
2614 int index = out - buffer;
2615
2616 growBuffer(buffer);
2617 out = &buffer[index];
2618 }
Daniel Veillard7f858501999-11-17 17:32:38 +00002619 }
2620 NEXT;
2621 }
2622 cur = CUR;
2623 }
2624 *out++ = 0;
2625 if (CUR == '<') {
2626 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2627 ctxt->sax->error(ctxt->userData,
2628 "Unescaped '<' not allowed in attributes values\n");
2629 ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
2630 ctxt->wellFormed = 0;
2631 } else if (CUR != limit) {
2632 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2633 ctxt->sax->error(ctxt->userData, "AttValue: ' expected\n");
2634 ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_FINISHED;
2635 ctxt->wellFormed = 0;
2636 } else
2637 NEXT;
2638 return(buffer);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002639}
2640
Daniel Veillard11e00581998-10-24 18:27:49 +00002641/**
2642 * xmlParseSystemLiteral:
2643 * @ctxt: an XML parser context
2644 *
2645 * parse an XML Literal
Daniel Veillard260a68f1998-08-13 03:39:55 +00002646 *
2647 * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
Daniel Veillard1e346af1999-02-22 10:33:01 +00002648 *
2649 * Returns the SystemLiteral parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002650 */
2651
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002652xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002653xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002654 const xmlChar *q;
2655 xmlChar *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002656
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002657 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002658 if (CUR == '"') {
2659 NEXT;
2660 q = CUR_PTR;
2661 while ((IS_CHAR(CUR)) && (CUR != '"'))
2662 NEXT;
2663 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002664 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002665 ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002666 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002667 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002668 } else {
2669 ret = xmlStrndup(q, CUR_PTR - q);
2670 NEXT;
2671 }
2672 } else if (CUR == '\'') {
2673 NEXT;
2674 q = CUR_PTR;
2675 while ((IS_CHAR(CUR)) && (CUR != '\''))
2676 NEXT;
2677 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002678 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002679 ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002680 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002681 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002682 } else {
2683 ret = xmlStrndup(q, CUR_PTR - q);
2684 NEXT;
2685 }
2686 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002687 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002688 ctxt->sax->error(ctxt->userData,
2689 "SystemLiteral \" or ' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002690 ctxt->errNo = XML_ERR_LITERAL_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002691 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002692 }
2693
2694 return(ret);
2695}
2696
Daniel Veillard11e00581998-10-24 18:27:49 +00002697/**
2698 * xmlParsePubidLiteral:
2699 * @ctxt: an XML parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +00002700 *
Daniel Veillard11e00581998-10-24 18:27:49 +00002701 * parse an XML public literal
Daniel Veillard1e346af1999-02-22 10:33:01 +00002702 *
2703 * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
2704 *
2705 * Returns the PubidLiteral parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002706 */
2707
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002708xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002709xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002710 const xmlChar *q;
2711 xmlChar *ret = NULL;
Daniel Veillard6077d031999-10-09 09:11:45 +00002712
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002713 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002714 if (CUR == '"') {
2715 NEXT;
2716 q = CUR_PTR;
2717 while (IS_PUBIDCHAR(CUR)) NEXT;
2718 if (CUR != '"') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002719 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002720 ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002721 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002722 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002723 } else {
2724 ret = xmlStrndup(q, CUR_PTR - q);
2725 NEXT;
2726 }
2727 } else if (CUR == '\'') {
2728 NEXT;
2729 q = CUR_PTR;
Daniel Veillard6077d031999-10-09 09:11:45 +00002730 while (IS_PUBIDCHAR(CUR)) NEXT;
2731 if (CUR != '\'') {
2732 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002733 ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002734 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002735 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002736 } else {
2737 ret = xmlStrndup(q, CUR_PTR - q);
2738 NEXT;
2739 }
2740 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002741 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002742 ctxt->sax->error(ctxt->userData,
2743 "SystemLiteral \" or ' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002744 ctxt->errNo = XML_ERR_LITERAL_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002745 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002746 }
2747
2748 return(ret);
2749}
2750
Daniel Veillard11e00581998-10-24 18:27:49 +00002751/**
2752 * xmlParseCharData:
2753 * @ctxt: an XML parser context
2754 * @cdata: int indicating whether we are within a CDATA section
2755 *
2756 * parse a CharData section.
2757 * if we are within a CDATA section ']]>' marks an end of section.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002758 *
2759 * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
2760 */
2761
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002762void
2763xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002764 xmlChar buf[1000];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002765 int nbchar = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002766 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002767
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002768 SHRINK;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002769 /*
2770 * !!!!!!!!!!!!
2771 * NOTE: NXT(0) is used here to avoid breaking on &lt; or &amp;
2772 * entities substitutions.
2773 */
2774 cur = CUR;
2775 while ((IS_CHAR(cur)) && (cur != '<') &&
2776 (cur != '&')) {
2777 if ((cur == ']') && (NXT(1) == ']') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002778 (NXT(2) == '>')) {
2779 if (cdata) break;
2780 else {
2781 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002782 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002783 "Sequence ']]>' not allowed in content\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002784 ctxt->errNo = XML_ERR_MISPLACED_CDATA_END;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002785 ctxt->wellFormed = 0;
2786 }
2787 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002788 buf[nbchar++] = CUR;
2789 if (nbchar == 1000) {
2790 /*
2791 * Ok the segment is to be consumed as chars.
2792 */
2793 if (ctxt->sax != NULL) {
2794 if (areBlanks(ctxt, buf, nbchar)) {
2795 if (ctxt->sax->ignorableWhitespace != NULL)
2796 ctxt->sax->ignorableWhitespace(ctxt->userData,
2797 buf, nbchar);
2798 } else {
2799 if (ctxt->sax->characters != NULL)
2800 ctxt->sax->characters(ctxt->userData, buf, nbchar);
2801 }
2802 }
2803 nbchar = 0;
2804 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002805 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002806 cur = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002807 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002808 if (nbchar != 0) {
2809 /*
2810 * Ok the segment is to be consumed as chars.
2811 */
2812 if (ctxt->sax != NULL) {
2813 if (areBlanks(ctxt, buf, nbchar)) {
2814 if (ctxt->sax->ignorableWhitespace != NULL)
2815 ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar);
2816 } else {
2817 if (ctxt->sax->characters != NULL)
2818 ctxt->sax->characters(ctxt->userData, buf, nbchar);
2819 }
2820 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002821 }
2822}
2823
Daniel Veillard11e00581998-10-24 18:27:49 +00002824/**
2825 * xmlParseExternalID:
2826 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002827 * @publicID: a xmlChar** receiving PubidLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00002828 * @strict: indicate whether we should restrict parsing to only
2829 * production [75], see NOTE below
Daniel Veillard11e00581998-10-24 18:27:49 +00002830 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00002831 * Parse an External ID or a Public ID
2832 *
2833 * NOTE: Productions [75] and [83] interract badly since [75] can generate
2834 * 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard260a68f1998-08-13 03:39:55 +00002835 *
2836 * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
2837 * | 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00002838 *
2839 * [83] PublicID ::= 'PUBLIC' S PubidLiteral
2840 *
2841 * Returns the function returns SystemLiteral and in the second
2842 * case publicID receives PubidLiteral, is strict is off
2843 * it is possible to return NULL and have publicID set.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002844 */
2845
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002846xmlChar *
2847xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) {
2848 xmlChar *URI = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002849
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002850 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002851 if ((CUR == 'S') && (NXT(1) == 'Y') &&
2852 (NXT(2) == 'S') && (NXT(3) == 'T') &&
2853 (NXT(4) == 'E') && (NXT(5) == 'M')) {
2854 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002855 if (!IS_BLANK(CUR)) {
2856 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002857 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002858 "Space required after 'SYSTEM'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002859 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002860 ctxt->wellFormed = 0;
2861 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002862 SKIP_BLANKS;
2863 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002864 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002865 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002866 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002867 "xmlParseExternalID: SYSTEM, no URI\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002868 ctxt->errNo = XML_ERR_URI_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002869 ctxt->wellFormed = 0;
2870 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002871 } else if ((CUR == 'P') && (NXT(1) == 'U') &&
2872 (NXT(2) == 'B') && (NXT(3) == 'L') &&
2873 (NXT(4) == 'I') && (NXT(5) == 'C')) {
2874 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002875 if (!IS_BLANK(CUR)) {
2876 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002877 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002878 "Space required after 'PUBLIC'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002879 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002880 ctxt->wellFormed = 0;
2881 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002882 SKIP_BLANKS;
2883 *publicID = xmlParsePubidLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002884 if (*publicID == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002885 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002886 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002887 "xmlParseExternalID: PUBLIC, no Public Identifier\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002888 ctxt->errNo = XML_ERR_PUBID_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002889 ctxt->wellFormed = 0;
2890 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002891 if (strict) {
2892 /*
2893 * We don't handle [83] so "S SystemLiteral" is required.
2894 */
2895 if (!IS_BLANK(CUR)) {
2896 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002897 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002898 "Space required after the Public Identifier\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002899 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00002900 ctxt->wellFormed = 0;
2901 }
2902 } else {
2903 /*
2904 * We handle [83] so we return immediately, if
2905 * "S SystemLiteral" is not detected. From a purely parsing
2906 * point of view that's a nice mess.
2907 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002908 const xmlChar *ptr = CUR_PTR;
Daniel Veillard1e346af1999-02-22 10:33:01 +00002909 if (!IS_BLANK(*ptr)) return(NULL);
2910
2911 while (IS_BLANK(*ptr)) ptr++;
2912 if ((*ptr != '\'') || (*ptr != '"')) return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002913 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002914 SKIP_BLANKS;
2915 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002916 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002917 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002918 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002919 "xmlParseExternalID: PUBLIC, no URI\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002920 ctxt->errNo = XML_ERR_URI_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002921 ctxt->wellFormed = 0;
2922 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002923 }
2924 return(URI);
2925}
2926
Daniel Veillard11e00581998-10-24 18:27:49 +00002927/**
2928 * xmlParseComment:
Daniel Veillard1e346af1999-02-22 10:33:01 +00002929 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002930 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002931 * Skip an XML (SGML) comment <!-- .... -->
Daniel Veillard260a68f1998-08-13 03:39:55 +00002932 * The spec says that "For compatibility, the string "--" (double-hyphen)
2933 * must not occur within comments. "
2934 *
2935 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
2936 */
Daniel Veillard517752b1999-04-05 12:20:10 +00002937void
Daniel Veillardb96e6431999-08-29 21:02:19 +00002938xmlParseComment(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002939 const xmlChar *q, *start;
2940 const xmlChar *r;
2941 xmlChar *val;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002942
2943 /*
2944 * Check that there is a comment right here.
2945 */
2946 if ((CUR != '<') || (NXT(1) != '!') ||
Daniel Veillard517752b1999-04-05 12:20:10 +00002947 (NXT(2) != '-') || (NXT(3) != '-')) return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002948
Daniel Veillardb05deb71999-08-10 19:04:08 +00002949 ctxt->instate = XML_PARSER_COMMENT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002950 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002951 SKIP(4);
2952 start = q = CUR_PTR;
2953 NEXT;
2954 r = CUR_PTR;
2955 NEXT;
2956 while (IS_CHAR(CUR) &&
2957 ((CUR == ':') || (CUR != '>') ||
2958 (*r != '-') || (*q != '-'))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002959 if ((*r == '-') && (*q == '-')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002960 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002961 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002962 "Comment must not contain '--' (double-hyphen)`\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002963 ctxt->errNo = XML_ERR_HYPHEN_IN_COMMENT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002964 ctxt->wellFormed = 0;
2965 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002966 NEXT;r++;q++;
2967 }
2968 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002969 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002970 ctxt->sax->error(ctxt->userData,
2971 "Comment not terminated \n<!--%.50s\n", start);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002972 ctxt->errNo = XML_ERR_COMMENT_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002973 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002974 } else {
2975 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002976 val = xmlStrndup(start, q - start);
2977 if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL))
2978 ctxt->sax->comment(ctxt->userData, val);
Daniel Veillard6454aec1999-09-02 22:04:43 +00002979 xmlFree(val);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002980 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002981}
2982
Daniel Veillard11e00581998-10-24 18:27:49 +00002983/**
2984 * xmlParsePITarget:
2985 * @ctxt: an XML parser context
2986 *
2987 * parse the name of a PI
Daniel Veillard260a68f1998-08-13 03:39:55 +00002988 *
2989 * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00002990 *
2991 * Returns the PITarget name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002992 */
2993
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002994xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002995xmlParsePITarget(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002996 xmlChar *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002997
2998 name = xmlParseName(ctxt);
2999 if ((name != NULL) && (name[3] == 0) &&
3000 ((name[0] == 'x') || (name[0] == 'X')) &&
3001 ((name[1] == 'm') || (name[1] == 'M')) &&
3002 ((name[2] == 'l') || (name[2] == 'L'))) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003003 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
3004 ctxt->sax->error(ctxt->userData,
3005 "xmlParsePItarget: invalid name prefix 'xml'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003006 ctxt->errNo = XML_ERR_RESERVED_XML_NAME;
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003007 /* ctxt->wellFormed = 0; !!! ? */
3008 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003009 return(NULL);
3010 }
3011 return(name);
3012}
3013
Daniel Veillard11e00581998-10-24 18:27:49 +00003014/**
3015 * xmlParsePI:
3016 * @ctxt: an XML parser context
3017 *
3018 * parse an XML Processing Instruction.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003019 *
3020 * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
Daniel Veillard1e346af1999-02-22 10:33:01 +00003021 *
3022 * The processing is transfered to SAX once parsed.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003023 */
3024
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003025void
3026xmlParsePI(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003027 xmlChar *target;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003028
3029 if ((CUR == '<') && (NXT(1) == '?')) {
3030 /*
3031 * this is a Processing Instruction.
3032 */
3033 SKIP(2);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003034 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003035
3036 /*
3037 * Parse the target name and check for special support like
3038 * namespace.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003039 */
3040 target = xmlParsePITarget(ctxt);
3041 if (target != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003042 const xmlChar *q;
Daniel Veillard517752b1999-04-05 12:20:10 +00003043
Daniel Veillardb96e6431999-08-29 21:02:19 +00003044 if (!IS_BLANK(CUR)) {
3045 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3046 ctxt->sax->error(ctxt->userData,
3047 "xmlParsePI: PI %s space expected\n", target);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003048 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003049 ctxt->wellFormed = 0;
3050 }
3051 SKIP_BLANKS;
3052 q = CUR_PTR;
Daniel Veillard517752b1999-04-05 12:20:10 +00003053 while (IS_CHAR(CUR) &&
3054 ((CUR != '?') || (NXT(1) != '>')))
3055 NEXT;
3056 if (!IS_CHAR(CUR)) {
3057 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003058 ctxt->sax->error(ctxt->userData,
Daniel Veillard517752b1999-04-05 12:20:10 +00003059 "xmlParsePI: PI %s never end ...\n", target);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003060 ctxt->errNo = XML_ERR_PI_NOT_FINISHED;
Daniel Veillard517752b1999-04-05 12:20:10 +00003061 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003062 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003063 xmlChar *data;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003064
Daniel Veillard517752b1999-04-05 12:20:10 +00003065 data = xmlStrndup(q, CUR_PTR - q);
3066 SKIP(2);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003067
Daniel Veillard517752b1999-04-05 12:20:10 +00003068 /*
3069 * SAX: PI detected.
3070 */
3071 if ((ctxt->sax) &&
3072 (ctxt->sax->processingInstruction != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00003073 ctxt->sax->processingInstruction(ctxt->userData,
3074 target, data);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003075 xmlFree(data);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003076 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00003077 xmlFree(target);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003078 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003079 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00003080 ctxt->sax->error(ctxt->userData,
3081 "xmlParsePI : no target name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003082 ctxt->errNo = XML_ERR_PI_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003083 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003084 }
3085 }
3086}
3087
Daniel Veillard11e00581998-10-24 18:27:49 +00003088/**
3089 * xmlParseNotationDecl:
3090 * @ctxt: an XML parser context
3091 *
3092 * parse a notation declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003093 *
3094 * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
3095 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00003096 * Hence there is actually 3 choices:
3097 * 'PUBLIC' S PubidLiteral
3098 * 'PUBLIC' S PubidLiteral S SystemLiteral
3099 * and 'SYSTEM' S SystemLiteral
Daniel Veillard11e00581998-10-24 18:27:49 +00003100 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003101 * See the NOTE on xmlParseExternalID().
Daniel Veillard260a68f1998-08-13 03:39:55 +00003102 */
3103
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003104void
3105xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003106 xmlChar *name;
3107 xmlChar *Pubid;
3108 xmlChar *Systemid;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003109
3110 if ((CUR == '<') && (NXT(1) == '!') &&
3111 (NXT(2) == 'N') && (NXT(3) == 'O') &&
3112 (NXT(4) == 'T') && (NXT(5) == 'A') &&
3113 (NXT(6) == 'T') && (NXT(7) == 'I') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00003114 (NXT(8) == 'O') && (NXT(9) == 'N')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003115 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003116 SKIP(10);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003117 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003118 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003119 ctxt->sax->error(ctxt->userData,
3120 "Space required after '<!NOTATION'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003121 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003122 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003123 return;
3124 }
3125 SKIP_BLANKS;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003126
3127 name = xmlParseName(ctxt);
3128 if (name == NULL) {
3129 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003130 ctxt->sax->error(ctxt->userData,
3131 "NOTATION: Name expected here\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003132 ctxt->errNo = XML_ERR_NOTATION_NOT_STARTED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003133 ctxt->wellFormed = 0;
3134 return;
3135 }
3136 if (!IS_BLANK(CUR)) {
3137 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003138 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003139 "Space required after the NOTATION name'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003140 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003141 ctxt->wellFormed = 0;
3142 return;
3143 }
3144 SKIP_BLANKS;
3145
Daniel Veillard260a68f1998-08-13 03:39:55 +00003146 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00003147 * Parse the IDs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003148 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00003149 Systemid = xmlParseExternalID(ctxt, &Pubid, 1);
3150 SKIP_BLANKS;
3151
3152 if (CUR == '>') {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003153 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00003154 if ((ctxt->sax != NULL) && (ctxt->sax->notationDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003155 ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003156 } else {
3157 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003158 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003159 "'>' required to close NOTATION declaration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003160 ctxt->errNo = XML_ERR_NOTATION_NOT_FINISHED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003161 ctxt->wellFormed = 0;
3162 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00003163 xmlFree(name);
3164 if (Systemid != NULL) xmlFree(Systemid);
3165 if (Pubid != NULL) xmlFree(Pubid);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003166 }
3167}
3168
Daniel Veillard11e00581998-10-24 18:27:49 +00003169/**
3170 * xmlParseEntityDecl:
3171 * @ctxt: an XML parser context
3172 *
3173 * parse <!ENTITY declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00003174 *
3175 * [70] EntityDecl ::= GEDecl | PEDecl
3176 *
3177 * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
3178 *
3179 * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
3180 *
3181 * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
3182 *
3183 * [74] PEDef ::= EntityValue | ExternalID
3184 *
3185 * [76] NDataDecl ::= S 'NDATA' S Name
Daniel Veillardb05deb71999-08-10 19:04:08 +00003186 *
3187 * [ VC: Notation Declared ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003188 * The Name must match the declared name of a notation.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003189 */
3190
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003191void
3192xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003193 xmlChar *name = NULL;
3194 xmlChar *value = NULL;
3195 xmlChar *URI = NULL, *literal = NULL;
3196 xmlChar *ndata = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003197 int isParameter = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003198 xmlChar *orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003199
Daniel Veillardb05deb71999-08-10 19:04:08 +00003200 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003201 if ((CUR == '<') && (NXT(1) == '!') &&
3202 (NXT(2) == 'E') && (NXT(3) == 'N') &&
3203 (NXT(4) == 'T') && (NXT(5) == 'I') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003204 (NXT(6) == 'T') && (NXT(7) == 'Y')) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003205 ctxt->instate = XML_PARSER_ENTITY_DECL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003206 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003207 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003208 if (!IS_BLANK(CUR)) {
3209 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003210 ctxt->sax->error(ctxt->userData,
3211 "Space required after '<!ENTITY'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003212 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003213 ctxt->wellFormed = 0;
3214 }
3215 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003216
3217 if (CUR == '%') {
3218 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003219 if (!IS_BLANK(CUR)) {
3220 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003221 ctxt->sax->error(ctxt->userData,
3222 "Space required after '%'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003223 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003224 ctxt->wellFormed = 0;
3225 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003226 SKIP_BLANKS;
3227 isParameter = 1;
3228 }
3229
3230 name = xmlParseName(ctxt);
3231 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003232 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003233 ctxt->sax->error(ctxt->userData, "xmlParseEntityDecl: no name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003234 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003235 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003236 return;
3237 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003238 if (!IS_BLANK(CUR)) {
3239 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003240 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003241 "Space required after the entity name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003242 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003243 ctxt->wellFormed = 0;
3244 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003245 SKIP_BLANKS;
3246
3247 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00003248 * handle the various case of definitions...
Daniel Veillard260a68f1998-08-13 03:39:55 +00003249 */
3250 if (isParameter) {
3251 if ((CUR == '"') || (CUR == '\''))
Daniel Veillard011b63c1999-06-02 17:44:04 +00003252 value = xmlParseEntityValue(ctxt, &orig);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003253 if (value) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003254 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003255 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003256 XML_INTERNAL_PARAMETER_ENTITY,
3257 NULL, NULL, value);
3258 }
3259 else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00003260 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003261 if (URI) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003262 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003263 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003264 XML_EXTERNAL_PARAMETER_ENTITY,
3265 literal, URI, NULL);
3266 }
3267 }
3268 } else {
3269 if ((CUR == '"') || (CUR == '\'')) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00003270 value = xmlParseEntityValue(ctxt, &orig);
Daniel Veillard517752b1999-04-05 12:20:10 +00003271 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003272 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003273 XML_INTERNAL_GENERAL_ENTITY,
3274 NULL, NULL, value);
3275 } else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00003276 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003277 if ((CUR != '>') && (!IS_BLANK(CUR))) {
3278 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003279 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003280 "Space required before 'NDATA'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003281 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003282 ctxt->wellFormed = 0;
3283 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003284 SKIP_BLANKS;
3285 if ((CUR == 'N') && (NXT(1) == 'D') &&
3286 (NXT(2) == 'A') && (NXT(3) == 'T') &&
3287 (NXT(4) == 'A')) {
3288 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003289 if (!IS_BLANK(CUR)) {
3290 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003291 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003292 "Space required after 'NDATA'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003293 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003294 ctxt->wellFormed = 0;
3295 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003296 SKIP_BLANKS;
3297 ndata = xmlParseName(ctxt);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003298 if ((ctxt->sax != NULL) &&
3299 (ctxt->sax->unparsedEntityDecl != NULL))
3300 ctxt->sax->unparsedEntityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003301 literal, URI, ndata);
3302 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00003303 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003304 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003305 XML_EXTERNAL_GENERAL_PARSED_ENTITY,
3306 literal, URI, NULL);
3307 }
3308 }
3309 }
3310 SKIP_BLANKS;
3311 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003312 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003313 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003314 "xmlParseEntityDecl: entity %s not terminated\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003315 ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003316 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003317 } else
3318 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00003319 if (orig != NULL) {
3320 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00003321 * Ugly mechanism to save the raw entity value.
Daniel Veillard011b63c1999-06-02 17:44:04 +00003322 */
3323 xmlEntityPtr cur = NULL;
3324
Daniel Veillardb05deb71999-08-10 19:04:08 +00003325 if (isParameter) {
3326 if ((ctxt->sax != NULL) &&
3327 (ctxt->sax->getParameterEntity != NULL))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003328 cur = ctxt->sax->getParameterEntity(ctxt->userData, name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003329 } else {
3330 if ((ctxt->sax != NULL) &&
3331 (ctxt->sax->getEntity != NULL))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003332 cur = ctxt->sax->getEntity(ctxt->userData, name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003333 }
3334 if (cur != NULL) {
3335 if (cur->orig != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003336 xmlFree(orig);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003337 else
3338 cur->orig = orig;
3339 } else
Daniel Veillard6454aec1999-09-02 22:04:43 +00003340 xmlFree(orig);
Daniel Veillard011b63c1999-06-02 17:44:04 +00003341 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00003342 if (name != NULL) xmlFree(name);
3343 if (value != NULL) xmlFree(value);
3344 if (URI != NULL) xmlFree(URI);
3345 if (literal != NULL) xmlFree(literal);
3346 if (ndata != NULL) xmlFree(ndata);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003347 }
3348}
3349
Daniel Veillard11e00581998-10-24 18:27:49 +00003350/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003351 * xmlParseDefaultDecl:
3352 * @ctxt: an XML parser context
3353 * @value: Receive a possible fixed default value for the attribute
3354 *
3355 * Parse an attribute default declaration
3356 *
3357 * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
3358 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003359 * [ VC: Required Attribute ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003360 * if the default declaration is the keyword #REQUIRED, then the
3361 * attribute must be specified for all elements of the type in the
3362 * attribute-list declaration.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003363 *
3364 * [ VC: Attribute Default Legal ]
3365 * The declared default value must meet the lexical constraints of
3366 * the declared attribute type c.f. xmlValidateAttributeDecl()
3367 *
3368 * [ VC: Fixed Attribute Default ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003369 * if an attribute has a default value declared with the #FIXED
3370 * keyword, instances of that attribute must match the default value.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003371 *
3372 * [ WFC: No < in Attribute Values ]
3373 * handled in xmlParseAttValue()
3374 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003375 * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
3376 * or XML_ATTRIBUTE_FIXED.
3377 */
3378
3379int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003380xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003381 int val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003382 xmlChar *ret;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003383
3384 *value = NULL;
3385 if ((CUR == '#') && (NXT(1) == 'R') &&
3386 (NXT(2) == 'E') && (NXT(3) == 'Q') &&
3387 (NXT(4) == 'U') && (NXT(5) == 'I') &&
3388 (NXT(6) == 'R') && (NXT(7) == 'E') &&
3389 (NXT(8) == 'D')) {
3390 SKIP(9);
3391 return(XML_ATTRIBUTE_REQUIRED);
3392 }
3393 if ((CUR == '#') && (NXT(1) == 'I') &&
3394 (NXT(2) == 'M') && (NXT(3) == 'P') &&
3395 (NXT(4) == 'L') && (NXT(5) == 'I') &&
3396 (NXT(6) == 'E') && (NXT(7) == 'D')) {
3397 SKIP(8);
3398 return(XML_ATTRIBUTE_IMPLIED);
3399 }
3400 val = XML_ATTRIBUTE_NONE;
3401 if ((CUR == '#') && (NXT(1) == 'F') &&
3402 (NXT(2) == 'I') && (NXT(3) == 'X') &&
3403 (NXT(4) == 'E') && (NXT(5) == 'D')) {
3404 SKIP(6);
3405 val = XML_ATTRIBUTE_FIXED;
3406 if (!IS_BLANK(CUR)) {
3407 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003408 ctxt->sax->error(ctxt->userData,
3409 "Space required after '#FIXED'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003410 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003411 ctxt->wellFormed = 0;
3412 }
3413 SKIP_BLANKS;
3414 }
3415 ret = xmlParseAttValue(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003416 ctxt->instate = XML_PARSER_DTD;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003417 if (ret == NULL) {
3418 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003419 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003420 "Attribute default value declaration error\n");
3421 ctxt->wellFormed = 0;
3422 } else
3423 *value = ret;
3424 return(val);
3425}
3426
3427/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00003428 * xmlParseNotationType:
3429 * @ctxt: an XML parser context
3430 *
3431 * parse an Notation attribute type.
3432 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003433 * Note: the leading 'NOTATION' S part has already being parsed...
3434 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003435 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
3436 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003437 * [ VC: Notation Attributes ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003438 * Values of this type must match one of the notation names included
Daniel Veillardb05deb71999-08-10 19:04:08 +00003439 * in the declaration; all notation names in the declaration must be declared.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003440 *
3441 * Returns: the notation attribute tree built while parsing
3442 */
3443
3444xmlEnumerationPtr
3445xmlParseNotationType(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003446 xmlChar *name;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003447 xmlEnumerationPtr ret = NULL, last = NULL, cur;
3448
3449 if (CUR != '(') {
3450 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003451 ctxt->sax->error(ctxt->userData,
3452 "'(' required to start 'NOTATION'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003453 ctxt->errNo = XML_ERR_NOTATION_NOT_STARTED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003454 ctxt->wellFormed = 0;
3455 return(NULL);
3456 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003457 SHRINK;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003458 do {
3459 NEXT;
3460 SKIP_BLANKS;
3461 name = xmlParseName(ctxt);
3462 if (name == NULL) {
3463 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003464 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003465 "Name expected in NOTATION declaration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003466 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003467 ctxt->wellFormed = 0;
3468 return(ret);
3469 }
3470 cur = xmlCreateEnumeration(name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003471 xmlFree(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003472 if (cur == NULL) return(ret);
3473 if (last == NULL) ret = last = cur;
3474 else {
3475 last->next = cur;
3476 last = cur;
3477 }
3478 SKIP_BLANKS;
3479 } while (CUR == '|');
3480 if (CUR != ')') {
3481 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003482 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003483 "')' required to finish NOTATION declaration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003484 ctxt->errNo = XML_ERR_NOTATION_NOT_FINISHED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003485 ctxt->wellFormed = 0;
3486 return(ret);
3487 }
3488 NEXT;
3489 return(ret);
3490}
3491
3492/**
3493 * xmlParseEnumerationType:
3494 * @ctxt: an XML parser context
3495 *
3496 * parse an Enumeration attribute type.
3497 *
3498 * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
3499 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003500 * [ VC: Enumeration ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003501 * Values of this type must match one of the Nmtoken tokens in
Daniel Veillardb05deb71999-08-10 19:04:08 +00003502 * the declaration
3503 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003504 * Returns: the enumeration attribute tree built while parsing
3505 */
3506
3507xmlEnumerationPtr
3508xmlParseEnumerationType(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003509 xmlChar *name;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003510 xmlEnumerationPtr ret = NULL, last = NULL, cur;
3511
3512 if (CUR != '(') {
3513 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003514 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003515 "'(' required to start ATTLIST enumeration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003516 ctxt->errNo = XML_ERR_ATTLIST_NOT_STARTED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003517 ctxt->wellFormed = 0;
3518 return(NULL);
3519 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003520 SHRINK;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003521 do {
3522 NEXT;
3523 SKIP_BLANKS;
3524 name = xmlParseNmtoken(ctxt);
3525 if (name == NULL) {
3526 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003527 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003528 "NmToken expected in ATTLIST enumeration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003529 ctxt->errNo = XML_ERR_NMTOKEN_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003530 ctxt->wellFormed = 0;
3531 return(ret);
3532 }
3533 cur = xmlCreateEnumeration(name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003534 xmlFree(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003535 if (cur == NULL) return(ret);
3536 if (last == NULL) ret = last = cur;
3537 else {
3538 last->next = cur;
3539 last = cur;
3540 }
3541 SKIP_BLANKS;
3542 } while (CUR == '|');
3543 if (CUR != ')') {
3544 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003545 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003546 "')' required to finish ATTLIST enumeration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003547 ctxt->errNo = XML_ERR_ATTLIST_NOT_FINISHED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003548 ctxt->wellFormed = 0;
3549 return(ret);
3550 }
3551 NEXT;
3552 return(ret);
3553}
3554
3555/**
Daniel Veillard11e00581998-10-24 18:27:49 +00003556 * xmlParseEnumeratedType:
3557 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00003558 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00003559 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003560 * parse an Enumerated attribute type.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003561 *
3562 * [57] EnumeratedType ::= NotationType | Enumeration
3563 *
3564 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
3565 *
Daniel Veillard11e00581998-10-24 18:27:49 +00003566 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003567 * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION
Daniel Veillard260a68f1998-08-13 03:39:55 +00003568 */
3569
Daniel Veillard1e346af1999-02-22 10:33:01 +00003570int
3571xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
3572 if ((CUR == 'N') && (NXT(1) == 'O') &&
3573 (NXT(2) == 'T') && (NXT(3) == 'A') &&
3574 (NXT(4) == 'T') && (NXT(5) == 'I') &&
3575 (NXT(6) == 'O') && (NXT(7) == 'N')) {
3576 SKIP(8);
3577 if (!IS_BLANK(CUR)) {
3578 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003579 ctxt->sax->error(ctxt->userData,
3580 "Space required after 'NOTATION'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003581 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003582 ctxt->wellFormed = 0;
3583 return(0);
3584 }
3585 SKIP_BLANKS;
3586 *tree = xmlParseNotationType(ctxt);
3587 if (*tree == NULL) return(0);
3588 return(XML_ATTRIBUTE_NOTATION);
3589 }
3590 *tree = xmlParseEnumerationType(ctxt);
3591 if (*tree == NULL) return(0);
3592 return(XML_ATTRIBUTE_ENUMERATION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003593}
3594
Daniel Veillard11e00581998-10-24 18:27:49 +00003595/**
3596 * xmlParseAttributeType:
3597 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00003598 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00003599 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003600 * parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00003601 *
3602 * [54] AttType ::= StringType | TokenizedType | EnumeratedType
3603 *
3604 * [55] StringType ::= 'CDATA'
3605 *
3606 * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
3607 * 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
Daniel Veillard11e00581998-10-24 18:27:49 +00003608 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003609 * Validity constraints for attribute values syntax are checked in
3610 * xmlValidateAttributeValue()
3611 *
3612 * [ VC: ID ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003613 * Values of type ID must match the Name production. A name must not
Daniel Veillardb05deb71999-08-10 19:04:08 +00003614 * appear more than once in an XML document as a value of this type;
3615 * i.e., ID values must uniquely identify the elements which bear them.
3616 *
3617 * [ VC: One ID per Element Type ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003618 * No element type may have more than one ID attribute specified.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003619 *
3620 * [ VC: ID Attribute Default ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003621 * An ID attribute must have a declared default of #IMPLIED or #REQUIRED.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003622 *
3623 * [ VC: IDREF ]
3624 * Values of type IDREF must match the Name production, and values
Daniel Veillardb96e6431999-08-29 21:02:19 +00003625 * of type IDREFS must match Names; TODO each IDREF Name must match the value
3626 * of an ID attribute on some element in the XML document; i.e. IDREF
Daniel Veillardb05deb71999-08-10 19:04:08 +00003627 * values must match the value of some ID attribute.
3628 *
3629 * [ VC: Entity Name ]
3630 * Values of type ENTITY must match the Name production, values
Daniel Veillardb96e6431999-08-29 21:02:19 +00003631 * of type ENTITIES must match Names; TODO each Entity Name must match the
3632 * name of an unparsed entity declared in the DTD.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003633 *
3634 * [ VC: Name Token ]
3635 * Values of type NMTOKEN must match the Nmtoken production; values
3636 * of type NMTOKENS must match Nmtokens.
3637 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003638 * Returns the attribute type
Daniel Veillard260a68f1998-08-13 03:39:55 +00003639 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003640int
Daniel Veillard1e346af1999-02-22 10:33:01 +00003641xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003642 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003643 if ((CUR == 'C') && (NXT(1) == 'D') &&
3644 (NXT(2) == 'A') && (NXT(3) == 'T') &&
3645 (NXT(4) == 'A')) {
3646 SKIP(5);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003647 return(XML_ATTRIBUTE_CDATA);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003648 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
3649 (NXT(2) == 'R') && (NXT(3) == 'E') &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00003650 (NXT(4) == 'F') && (NXT(5) == 'S')) {
3651 SKIP(6);
3652 return(XML_ATTRIBUTE_IDREFS);
3653 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
3654 (NXT(2) == 'R') && (NXT(3) == 'E') &&
Daniel Veillard260a68f1998-08-13 03:39:55 +00003655 (NXT(4) == 'F')) {
3656 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003657 return(XML_ATTRIBUTE_IDREF);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003658 } else if ((CUR == 'I') && (NXT(1) == 'D')) {
3659 SKIP(2);
3660 return(XML_ATTRIBUTE_ID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003661 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
3662 (NXT(2) == 'T') && (NXT(3) == 'I') &&
3663 (NXT(4) == 'T') && (NXT(5) == 'Y')) {
3664 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003665 return(XML_ATTRIBUTE_ENTITY);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003666 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
3667 (NXT(2) == 'T') && (NXT(3) == 'I') &&
3668 (NXT(4) == 'T') && (NXT(5) == 'I') &&
3669 (NXT(6) == 'E') && (NXT(7) == 'S')) {
3670 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003671 return(XML_ATTRIBUTE_ENTITIES);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003672 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
3673 (NXT(2) == 'T') && (NXT(3) == 'O') &&
3674 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00003675 (NXT(6) == 'N') && (NXT(7) == 'S')) {
3676 SKIP(8);
3677 return(XML_ATTRIBUTE_NMTOKENS);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003678 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
3679 (NXT(2) == 'T') && (NXT(3) == 'O') &&
3680 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00003681 (NXT(6) == 'N')) {
3682 SKIP(7);
3683 return(XML_ATTRIBUTE_NMTOKEN);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003684 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00003685 return(xmlParseEnumeratedType(ctxt, tree));
Daniel Veillard260a68f1998-08-13 03:39:55 +00003686}
3687
Daniel Veillard11e00581998-10-24 18:27:49 +00003688/**
3689 * xmlParseAttributeListDecl:
3690 * @ctxt: an XML parser context
3691 *
3692 * : parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00003693 *
3694 * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
3695 *
3696 * [53] AttDef ::= S Name S AttType S DefaultDecl
Daniel Veillard11e00581998-10-24 18:27:49 +00003697 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00003698 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003699void
3700xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003701 xmlChar *elemName;
3702 xmlChar *attrName;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003703 xmlEnumerationPtr tree;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003704
Daniel Veillard260a68f1998-08-13 03:39:55 +00003705 if ((CUR == '<') && (NXT(1) == '!') &&
3706 (NXT(2) == 'A') && (NXT(3) == 'T') &&
3707 (NXT(4) == 'T') && (NXT(5) == 'L') &&
3708 (NXT(6) == 'I') && (NXT(7) == 'S') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003709 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003710 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003711 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003712 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003713 ctxt->sax->error(ctxt->userData,
3714 "Space required after '<!ATTLIST'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003715 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003716 ctxt->wellFormed = 0;
3717 }
3718 SKIP_BLANKS;
3719 elemName = xmlParseName(ctxt);
3720 if (elemName == NULL) {
3721 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003722 ctxt->sax->error(ctxt->userData,
3723 "ATTLIST: no name for Element\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003724 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003725 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003726 return;
3727 }
3728 SKIP_BLANKS;
3729 while (CUR != '>') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003730 const xmlChar *check = CUR_PTR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003731 int type;
3732 int def;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003733 xmlChar *defaultValue = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003734
Daniel Veillardb05deb71999-08-10 19:04:08 +00003735 tree = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003736 attrName = xmlParseName(ctxt);
3737 if (attrName == NULL) {
3738 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003739 ctxt->sax->error(ctxt->userData,
3740 "ATTLIST: no name for Attribute\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003741 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003742 ctxt->wellFormed = 0;
3743 break;
3744 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003745 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003746 if (!IS_BLANK(CUR)) {
3747 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003748 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003749 "Space required after the attribute name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003750 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003751 ctxt->wellFormed = 0;
3752 break;
3753 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003754 SKIP_BLANKS;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003755
Daniel Veillard1e346af1999-02-22 10:33:01 +00003756 type = xmlParseAttributeType(ctxt, &tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003757 if (type <= 0) break;
3758
Daniel Veillardb05deb71999-08-10 19:04:08 +00003759 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003760 if (!IS_BLANK(CUR)) {
3761 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003762 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003763 "Space required after the attribute type\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003764 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003765 ctxt->wellFormed = 0;
3766 break;
3767 }
3768 SKIP_BLANKS;
3769
3770 def = xmlParseDefaultDecl(ctxt, &defaultValue);
3771 if (def <= 0) break;
3772
Daniel Veillardb05deb71999-08-10 19:04:08 +00003773 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003774 if (CUR != '>') {
3775 if (!IS_BLANK(CUR)) {
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 "Space required after the attribute default value\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003779 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003780 ctxt->wellFormed = 0;
3781 break;
3782 }
3783 SKIP_BLANKS;
3784 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003785 if (check == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003786 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003787 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003788 "xmlParseAttributeListDecl: detected internal error\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003789 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003790 break;
3791 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003792 if ((ctxt->sax != NULL) && (ctxt->sax->attributeDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003793 ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003794 type, def, defaultValue, tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003795 if (attrName != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003796 xmlFree(attrName);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003797 if (defaultValue != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003798 xmlFree(defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003799 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003800 }
3801 if (CUR == '>')
3802 NEXT;
3803
Daniel Veillard6454aec1999-09-02 22:04:43 +00003804 xmlFree(elemName);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003805 }
3806}
3807
Daniel Veillard11e00581998-10-24 18:27:49 +00003808/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003809 * xmlParseElementMixedContentDecl:
Daniel Veillard11e00581998-10-24 18:27:49 +00003810 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00003811 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003812 * parse the declaration for a Mixed Element content
3813 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
Daniel Veillard260a68f1998-08-13 03:39:55 +00003814 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003815 * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
3816 * '(' S? '#PCDATA' S? ')'
3817 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003818 * [ VC: Proper Group/PE Nesting ] applies to [51] too (see [49])
3819 *
3820 * [ VC: No Duplicate Types ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003821 * The same name must not appear more than once in a single
3822 * mixed-content declaration.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003823 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003824 * returns: the list of the xmlElementContentPtr describing the element choices
3825 */
3826xmlElementContentPtr
3827xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard1899e851999-02-01 12:18:54 +00003828 xmlElementContentPtr ret = NULL, cur = NULL, n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003829 xmlChar *elem = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003830
Daniel Veillardb05deb71999-08-10 19:04:08 +00003831 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003832 if ((CUR == '#') && (NXT(1) == 'P') &&
3833 (NXT(2) == 'C') && (NXT(3) == 'D') &&
3834 (NXT(4) == 'A') && (NXT(5) == 'T') &&
3835 (NXT(6) == 'A')) {
3836 SKIP(7);
3837 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003838 SHRINK;
Daniel Veillard3b9def11999-01-31 22:15:06 +00003839 if (CUR == ')') {
3840 NEXT;
3841 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
3842 return(ret);
3843 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003844 if ((CUR == '(') || (CUR == '|')) {
3845 ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
3846 if (ret == NULL) return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003847 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003848 while (CUR == '|') {
Daniel Veillard1899e851999-02-01 12:18:54 +00003849 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003850 if (elem == NULL) {
3851 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
3852 if (ret == NULL) return(NULL);
3853 ret->c1 = cur;
Daniel Veillard1899e851999-02-01 12:18:54 +00003854 cur = ret;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003855 } else {
Daniel Veillard1899e851999-02-01 12:18:54 +00003856 n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
3857 if (n == NULL) return(NULL);
3858 n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
3859 cur->c2 = n;
3860 cur = n;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003861 xmlFree(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003862 }
3863 SKIP_BLANKS;
3864 elem = xmlParseName(ctxt);
3865 if (elem == NULL) {
3866 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003867 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003868 "xmlParseElementMixedContentDecl : Name expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003869 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003870 ctxt->wellFormed = 0;
3871 xmlFreeElementContent(cur);
3872 return(NULL);
3873 }
3874 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003875 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003876 }
Daniel Veillard3b9def11999-01-31 22:15:06 +00003877 if ((CUR == ')') && (NXT(1) == '*')) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00003878 if (elem != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003879 cur->c2 = xmlNewElementContent(elem,
3880 XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003881 xmlFree(elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003882 }
Daniel Veillard1899e851999-02-01 12:18:54 +00003883 ret->ocur = XML_ELEMENT_CONTENT_MULT;
3884 SKIP(2);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003885 } else {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003886 if (elem != NULL) xmlFree(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003887 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003888 ctxt->sax->error(ctxt->userData,
Daniel Veillard3b9def11999-01-31 22:15:06 +00003889 "xmlParseElementMixedContentDecl : '|' or ')*' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003890 ctxt->errNo = XML_ERR_MIXED_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003891 ctxt->wellFormed = 0;
3892 xmlFreeElementContent(ret);
3893 return(NULL);
3894 }
3895
3896 } else {
3897 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003898 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003899 "xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003900 ctxt->errNo = XML_ERR_PCDATA_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003901 ctxt->wellFormed = 0;
3902 }
3903 return(ret);
3904}
3905
3906/**
3907 * xmlParseElementChildrenContentDecl:
3908 * @ctxt: an XML parser context
3909 *
3910 * parse the declaration for a Mixed Element content
3911 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
3912 *
3913 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00003914 * [47] children ::= (choice | seq) ('?' | '*' | '+')?
3915 *
3916 * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
3917 *
3918 * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
3919 *
3920 * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
3921 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003922 * [ VC: Proper Group/PE Nesting ] applies to [49] and [50]
3923 * TODO Parameter-entity replacement text must be properly nested
3924 * with parenthetized groups. That is to say, if either of the
3925 * opening or closing parentheses in a choice, seq, or Mixed
3926 * construct is contained in the replacement text for a parameter
3927 * entity, both must be contained in the same replacement text. For
3928 * interoperability, if a parameter-entity reference appears in a
3929 * choice, seq, or Mixed construct, its replacement text should not
3930 * be empty, and neither the first nor last non-blank character of
3931 * the replacement text should be a connector (| or ,).
3932 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003933 * returns: the tree of xmlElementContentPtr describing the element
3934 * hierarchy.
3935 */
3936xmlElementContentPtr
3937xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt) {
3938 xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003939 xmlChar *elem;
3940 xmlChar type = 0;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003941
3942 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003943 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003944 if (CUR == '(') {
3945 /* Recurse on first child */
3946 NEXT;
3947 SKIP_BLANKS;
3948 cur = ret = xmlParseElementChildrenContentDecl(ctxt);
3949 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003950 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003951 } else {
3952 elem = xmlParseName(ctxt);
3953 if (elem == NULL) {
3954 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003955 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003956 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003957 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003958 ctxt->wellFormed = 0;
3959 return(NULL);
3960 }
3961 cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003962 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003963 if (CUR == '?') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003964 cur->ocur = XML_ELEMENT_CONTENT_OPT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003965 NEXT;
3966 } else if (CUR == '*') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003967 cur->ocur = XML_ELEMENT_CONTENT_MULT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003968 NEXT;
3969 } else if (CUR == '+') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003970 cur->ocur = XML_ELEMENT_CONTENT_PLUS;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003971 NEXT;
3972 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003973 cur->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003974 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00003975 xmlFree(elem);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003976 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003977 }
3978 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003979 SHRINK;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003980 while (CUR != ')') {
3981 /*
3982 * Each loop we parse one separator and one element.
3983 */
3984 if (CUR == ',') {
3985 if (type == 0) type = CUR;
3986
3987 /*
3988 * Detect "Name | Name , Name" error
3989 */
3990 else if (type != CUR) {
3991 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003992 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003993 "xmlParseElementChildrenContentDecl : '%c' expected\n",
3994 type);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003995 ctxt->errNo = XML_ERR_SEPARATOR_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003996 ctxt->wellFormed = 0;
3997 xmlFreeElementContent(ret);
3998 return(NULL);
3999 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004000 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004001
4002 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
4003 if (op == NULL) {
4004 xmlFreeElementContent(ret);
4005 return(NULL);
4006 }
4007 if (last == NULL) {
4008 op->c1 = ret;
4009 ret = cur = op;
4010 } else {
4011 cur->c2 = op;
4012 op->c1 = last;
4013 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00004014 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004015 }
4016 } else if (CUR == '|') {
4017 if (type == 0) type = CUR;
4018
4019 /*
4020 * Detect "Name , Name | Name" error
4021 */
4022 else if (type != CUR) {
4023 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004024 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004025 "xmlParseElementChildrenContentDecl : '%c' expected\n",
4026 type);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004027 ctxt->errNo = XML_ERR_SEPARATOR_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004028 ctxt->wellFormed = 0;
4029 xmlFreeElementContent(ret);
4030 return(NULL);
4031 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004032 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004033
4034 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
4035 if (op == NULL) {
4036 xmlFreeElementContent(ret);
4037 return(NULL);
4038 }
4039 if (last == NULL) {
4040 op->c1 = ret;
4041 ret = cur = op;
4042 } else {
4043 cur->c2 = op;
4044 op->c1 = last;
4045 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00004046 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004047 }
4048 } else {
4049 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004050 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004051 "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
4052 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004053 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004054 xmlFreeElementContent(ret);
4055 return(NULL);
4056 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00004057 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004058 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004059 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004060 if (CUR == '(') {
4061 /* Recurse on second child */
4062 NEXT;
4063 SKIP_BLANKS;
Daniel Veillard1899e851999-02-01 12:18:54 +00004064 last = xmlParseElementChildrenContentDecl(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004065 SKIP_BLANKS;
4066 } else {
4067 elem = xmlParseName(ctxt);
4068 if (elem == NULL) {
4069 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004070 ctxt->sax->error(ctxt->userData,
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004071 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004072 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004073 ctxt->wellFormed = 0;
4074 return(NULL);
4075 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004076 last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004077 xmlFree(elem);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004078 if (CUR == '?') {
4079 last->ocur = XML_ELEMENT_CONTENT_OPT;
4080 NEXT;
4081 } else if (CUR == '*') {
4082 last->ocur = XML_ELEMENT_CONTENT_MULT;
4083 NEXT;
4084 } else if (CUR == '+') {
4085 last->ocur = XML_ELEMENT_CONTENT_PLUS;
4086 NEXT;
4087 } else {
4088 last->ocur = XML_ELEMENT_CONTENT_ONCE;
4089 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004090 }
4091 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004092 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004093 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004094 if ((cur != NULL) && (last != NULL)) {
4095 cur->c2 = last;
4096 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004097 NEXT;
4098 if (CUR == '?') {
4099 ret->ocur = XML_ELEMENT_CONTENT_OPT;
4100 NEXT;
4101 } else if (CUR == '*') {
4102 ret->ocur = XML_ELEMENT_CONTENT_MULT;
4103 NEXT;
4104 } else if (CUR == '+') {
4105 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
4106 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004107 }
4108 return(ret);
4109}
4110
4111/**
4112 * xmlParseElementContentDecl:
4113 * @ctxt: an XML parser context
4114 * @name: the name of the element being defined.
4115 * @result: the Element Content pointer will be stored here if any
Daniel Veillard260a68f1998-08-13 03:39:55 +00004116 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004117 * parse the declaration for an Element content either Mixed or Children,
4118 * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
4119 *
4120 * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
Daniel Veillard11e00581998-10-24 18:27:49 +00004121 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004122 * returns: the type of element content XML_ELEMENT_TYPE_xxx
Daniel Veillard260a68f1998-08-13 03:39:55 +00004123 */
4124
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004125int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004126xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, xmlChar *name,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004127 xmlElementContentPtr *result) {
4128
4129 xmlElementContentPtr tree = NULL;
4130 int res;
4131
4132 *result = NULL;
4133
4134 if (CUR != '(') {
4135 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004136 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004137 "xmlParseElementContentDecl : '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004138 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004139 ctxt->wellFormed = 0;
4140 return(-1);
4141 }
4142 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004143 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004144 SKIP_BLANKS;
4145 if ((CUR == '#') && (NXT(1) == 'P') &&
4146 (NXT(2) == 'C') && (NXT(3) == 'D') &&
4147 (NXT(4) == 'A') && (NXT(5) == 'T') &&
4148 (NXT(6) == 'A')) {
4149 tree = xmlParseElementMixedContentDecl(ctxt);
4150 res = XML_ELEMENT_TYPE_MIXED;
4151 } else {
4152 tree = xmlParseElementChildrenContentDecl(ctxt);
4153 res = XML_ELEMENT_TYPE_ELEMENT;
4154 }
4155 SKIP_BLANKS;
4156 /****************************
4157 if (CUR != ')') {
4158 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004159 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004160 "xmlParseElementContentDecl : ')' expected\n");
4161 ctxt->wellFormed = 0;
4162 return(-1);
4163 }
4164 ****************************/
Daniel Veillard3b9def11999-01-31 22:15:06 +00004165 *result = tree;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004166 return(res);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004167}
4168
Daniel Veillard11e00581998-10-24 18:27:49 +00004169/**
4170 * xmlParseElementDecl:
4171 * @ctxt: an XML parser context
4172 *
4173 * parse an Element declaration.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004174 *
4175 * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
4176 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004177 * [ VC: Unique Element Type Declaration ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004178 * No element type may be declared more than once
Daniel Veillard1e346af1999-02-22 10:33:01 +00004179 *
4180 * Returns the type of the element, or -1 in case of error
Daniel Veillard260a68f1998-08-13 03:39:55 +00004181 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004182int
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004183xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004184 xmlChar *name;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004185 int ret = -1;
4186 xmlElementContentPtr content = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004187
Daniel Veillardb05deb71999-08-10 19:04:08 +00004188 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004189 if ((CUR == '<') && (NXT(1) == '!') &&
4190 (NXT(2) == 'E') && (NXT(3) == 'L') &&
4191 (NXT(4) == 'E') && (NXT(5) == 'M') &&
4192 (NXT(6) == 'E') && (NXT(7) == 'N') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004193 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004194 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004195 if (!IS_BLANK(CUR)) {
4196 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004197 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004198 "Space required after 'ELEMENT'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004199 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004200 ctxt->wellFormed = 0;
4201 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004202 SKIP_BLANKS;
4203 name = xmlParseName(ctxt);
4204 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004205 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004206 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004207 "xmlParseElementDecl: no name for Element\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004208 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004209 ctxt->wellFormed = 0;
4210 return(-1);
4211 }
4212 if (!IS_BLANK(CUR)) {
4213 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004214 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004215 "Space required after the element name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004216 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004217 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004218 }
4219 SKIP_BLANKS;
4220 if ((CUR == 'E') && (NXT(1) == 'M') &&
4221 (NXT(2) == 'P') && (NXT(3) == 'T') &&
4222 (NXT(4) == 'Y')) {
4223 SKIP(5);
4224 /*
4225 * Element must always be empty.
4226 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004227 ret = XML_ELEMENT_TYPE_EMPTY;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004228 } else if ((CUR == 'A') && (NXT(1) == 'N') &&
4229 (NXT(2) == 'Y')) {
4230 SKIP(3);
4231 /*
4232 * Element is a generic container.
4233 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004234 ret = XML_ELEMENT_TYPE_ANY;
4235 } else if (CUR == '(') {
4236 ret = xmlParseElementContentDecl(ctxt, name, &content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004237 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004238 /*
4239 * [ WFC: PEs in Internal Subset ] error handling.
4240 */
4241 if ((CUR == '%') && (ctxt->external == 0) &&
4242 (ctxt->inputNr == 1)) {
4243 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4244 ctxt->sax->error(ctxt->userData,
4245 "PEReference: forbidden within markup decl in internal subset\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004246 ctxt->errNo = XML_ERR_PEREF_IN_INT_SUBSET;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004247 } else {
4248 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4249 ctxt->sax->error(ctxt->userData,
4250 "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004251 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004252 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004253 ctxt->wellFormed = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004254 if (name != NULL) xmlFree(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004255 return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004256 }
4257 SKIP_BLANKS;
4258 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004259 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004260 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00004261 "xmlParseElementDecl: expected '>' at the end\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004262 ctxt->errNo = XML_ERR_GT_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004263 ctxt->wellFormed = 0;
4264 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004265 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00004266 if ((ctxt->sax != NULL) && (ctxt->sax->elementDecl != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00004267 ctxt->sax->elementDecl(ctxt->userData, name, ret,
4268 content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004269 }
Daniel Veillard14fff061999-06-22 21:49:07 +00004270 if (content != NULL) {
4271 xmlFreeElementContent(content);
4272 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004273 if (name != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004274 xmlFree(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004275 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004276 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004277 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004278}
4279
Daniel Veillard11e00581998-10-24 18:27:49 +00004280/**
4281 * xmlParseMarkupDecl:
4282 * @ctxt: an XML parser context
4283 *
4284 * parse Markup declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00004285 *
4286 * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
4287 * NotationDecl | PI | Comment
4288 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004289 * [ VC: Proper Declaration/PE Nesting ]
4290 * TODO Parameter-entity replacement text must be properly nested with
4291 * markup declarations. That is to say, if either the first character
4292 * or the last character of a markup declaration (markupdecl above) is
4293 * contained in the replacement text for a parameter-entity reference,
4294 * both must be contained in the same replacement text.
4295 *
4296 * [ WFC: PEs in Internal Subset ]
4297 * In the internal DTD subset, parameter-entity references can occur
4298 * only where markup declarations can occur, not within markup declarations.
4299 * (This does not apply to references that occur in external parameter
4300 * entities or to the external subset.)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004301 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004302void
4303xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004304 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004305 xmlParseElementDecl(ctxt);
4306 xmlParseAttributeListDecl(ctxt);
4307 xmlParseEntityDecl(ctxt);
4308 xmlParseNotationDecl(ctxt);
4309 xmlParsePI(ctxt);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004310 xmlParseComment(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004311 /*
4312 * This is only for internal subset. On external entities,
4313 * the replacement is done before parsing stage
4314 */
4315 if ((ctxt->external == 0) && (ctxt->inputNr == 1))
4316 xmlParsePEReference(ctxt);
4317 ctxt->instate = XML_PARSER_DTD;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004318}
4319
Daniel Veillard11e00581998-10-24 18:27:49 +00004320/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004321 * xmlParseTextDecl:
4322 * @ctxt: an XML parser context
4323 *
4324 * parse an XML declaration header for external entities
4325 *
4326 * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
4327 *
4328 * Returns the only valuable info for an external parsed entity, the encoding
4329 */
4330
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004331xmlChar *
Daniel Veillard011b63c1999-06-02 17:44:04 +00004332xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004333 xmlChar *version;
4334 xmlChar *encoding = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004335
4336 /*
4337 * We know that '<?xml' is here.
4338 */
4339 SKIP(5);
4340
4341 if (!IS_BLANK(CUR)) {
4342 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004343 ctxt->sax->error(ctxt->userData,
4344 "Space needed after '<?xml'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004345 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004346 ctxt->wellFormed = 0;
4347 }
4348 SKIP_BLANKS;
4349
4350 /*
4351 * We may have the VersionInfo here.
4352 */
4353 version = xmlParseVersionInfo(ctxt);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004354 if (version == NULL)
4355 version = xmlCharStrdup(XML_DEFAULT_VERSION);
4356 ctxt->version = xmlStrdup(version);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004357 xmlFree(version);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004358
4359 /*
4360 * We must have the encoding declaration
4361 */
4362 if (!IS_BLANK(CUR)) {
4363 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004364 ctxt->sax->error(ctxt->userData, "Space needed here\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004365 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004366 ctxt->wellFormed = 0;
4367 }
4368 encoding = xmlParseEncodingDecl(ctxt);
4369
4370 SKIP_BLANKS;
4371 if ((CUR == '?') && (NXT(1) == '>')) {
4372 SKIP(2);
4373 } else if (CUR == '>') {
4374 /* Deprecated old WD ... */
4375 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004376 ctxt->sax->error(ctxt->userData,
4377 "XML declaration must end-up with '?>'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004378 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004379 ctxt->wellFormed = 0;
4380 NEXT;
4381 } else {
4382 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004383 ctxt->sax->error(ctxt->userData,
4384 "parsing XML declaration: '?>' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004385 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004386 ctxt->wellFormed = 0;
4387 MOVETO_ENDTAG(CUR_PTR);
4388 NEXT;
4389 }
4390 return(encoding);
4391}
4392
4393/*
4394 * xmlParseConditionalSections
4395 * @ctxt: an XML parser context
4396 *
4397 * TODO : Conditionnal section are not yet supported !
4398 *
4399 * [61] conditionalSect ::= includeSect | ignoreSect
4400 * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
4401 * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
4402 * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
4403 * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
4404 */
4405
4406void
4407xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
4408 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
4409 ctxt->sax->warning(ctxt->userData,
4410 "XML conditional section not supported\n");
4411 /*
4412 * Skip up to the end of the conditionnal section.
4413 */
4414 while ((CUR != 0) && ((CUR != ']') || (NXT(1) != ']') || (NXT(2) != '>')))
4415 NEXT;
4416 if (CUR == 0) {
4417 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4418 ctxt->sax->error(ctxt->userData,
4419 "XML conditional section not closed\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004420 ctxt->errNo = XML_ERR_CONDSEC_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004421 ctxt->wellFormed = 0;
4422 }
4423}
4424
4425/**
Daniel Veillard00fdf371999-10-08 09:40:39 +00004426 * xmlParseExternalSubset:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004427 * @ctxt: an XML parser context
Daniel Veillard00fdf371999-10-08 09:40:39 +00004428 * @ExternalID: the external identifier
4429 * @SystemID: the system identifier (or URL)
Daniel Veillard011b63c1999-06-02 17:44:04 +00004430 *
4431 * parse Markup declarations from an external subset
4432 *
4433 * [30] extSubset ::= textDecl? extSubsetDecl
4434 *
4435 * [31] extSubsetDecl ::= (markupdecl | conditionalSect | PEReference | S) *
Daniel Veillard011b63c1999-06-02 17:44:04 +00004436 */
4437void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004438xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID,
4439 const xmlChar *SystemID) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00004440 GROW;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004441 if ((CUR == '<') && (NXT(1) == '?') &&
4442 (NXT(2) == 'x') && (NXT(3) == 'm') &&
4443 (NXT(4) == 'l')) {
4444 xmlParseTextDecl(ctxt);
4445 }
4446 if (ctxt->myDoc == NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004447 ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004448 }
4449 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL))
4450 xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID);
4451
Daniel Veillardb05deb71999-08-10 19:04:08 +00004452 ctxt->instate = XML_PARSER_DTD;
4453 ctxt->external = 1;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004454 while (((CUR == '<') && (NXT(1) == '?')) ||
4455 ((CUR == '<') && (NXT(1) == '!')) ||
4456 IS_BLANK(CUR)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004457 const xmlChar *check = CUR_PTR;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004458 int cons = ctxt->input->consumed;
4459
Daniel Veillard011b63c1999-06-02 17:44:04 +00004460 if ((CUR == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
4461 xmlParseConditionalSections(ctxt);
4462 } else if (IS_BLANK(CUR)) {
4463 NEXT;
4464 } else if (CUR == '%') {
4465 xmlParsePEReference(ctxt);
4466 } else
4467 xmlParseMarkupDecl(ctxt);
4468
4469 /*
4470 * Pop-up of finished entities.
4471 */
4472 while ((CUR == 0) && (ctxt->inputNr > 1))
4473 xmlPopInput(ctxt);
4474
Daniel Veillardb96e6431999-08-29 21:02:19 +00004475 if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
4476 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4477 ctxt->sax->error(ctxt->userData,
4478 "Content error in the external subset\n");
4479 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004480 ctxt->errNo = XML_ERR_EXT_SUBSET_NOT_FINISHED;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004481 break;
4482 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004483 }
4484
4485 if (CUR != 0) {
4486 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4487 ctxt->sax->error(ctxt->userData,
4488 "Extra content at the end of the document\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004489 ctxt->errNo = XML_ERR_EXT_SUBSET_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004490 ctxt->wellFormed = 0;
4491 }
4492
4493}
4494
4495/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004496 * xmlParseReference:
4497 * @ctxt: an XML parser context
4498 *
4499 * parse and handle entity references in content, depending on the SAX
4500 * interface, this may end-up in a call to character() if this is a
4501 * CharRef, a predefined entity, if there is no reference() callback.
4502 * or if the parser was asked to switch to that mode.
4503 *
4504 * [67] Reference ::= EntityRef | CharRef
4505 */
4506void
4507xmlParseReference(xmlParserCtxtPtr ctxt) {
4508 xmlEntityPtr ent;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004509 xmlChar *val;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004510 if (CUR != '&') return;
4511
Daniel Veillardb96e6431999-08-29 21:02:19 +00004512 if (ctxt->inputNr > 1) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004513 xmlChar cur[2] = { '&' , 0 } ;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004514
4515 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
4516 ctxt->sax->characters(ctxt->userData, cur, 1);
4517 if (ctxt->token == '&')
4518 ctxt->token = 0;
4519 else {
4520 SKIP(1);
4521 }
4522 return;
4523 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004524 if (NXT(1) == '#') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004525 xmlChar out[2];
Daniel Veillard011b63c1999-06-02 17:44:04 +00004526 int val = xmlParseCharRef(ctxt);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004527 /* invalid for UTF-8 variable encoding !!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00004528 out[0] = val;
4529 out[1] = 0;
4530 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
4531 ctxt->sax->characters(ctxt->userData, out, 1);
4532 } else {
4533 ent = xmlParseEntityRef(ctxt);
4534 if (ent == NULL) return;
4535 if ((ent->name != NULL) &&
Daniel Veillardb96e6431999-08-29 21:02:19 +00004536 (ent->type != XML_INTERNAL_PREDEFINED_ENTITY)) {
4537 if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) &&
4538 (ctxt->replaceEntities == 0)) {
4539 /*
4540 * Create a node.
4541 */
4542 ctxt->sax->reference(ctxt->userData, ent->name);
4543 return;
4544 } else if (ctxt->replaceEntities) {
4545 xmlParserInputPtr input;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004546
Daniel Veillardb96e6431999-08-29 21:02:19 +00004547 input = xmlNewEntityInputStream(ctxt, ent);
4548 xmlPushInput(ctxt, input);
4549 return;
4550 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004551 }
4552 val = ent->content;
4553 if (val == NULL) return;
4554 /*
4555 * inline the entity.
4556 */
4557 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
4558 ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val));
4559 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004560}
4561
Daniel Veillard11e00581998-10-24 18:27:49 +00004562/**
4563 * xmlParseEntityRef:
4564 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00004565 *
4566 * parse ENTITY references declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00004567 *
4568 * [68] EntityRef ::= '&' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00004569 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004570 * [ WFC: Entity Declared ]
4571 * In a document without any DTD, a document with only an internal DTD
4572 * subset which contains no parameter entity references, or a document
4573 * with "standalone='yes'", the Name given in the entity reference
4574 * must match that in an entity declaration, except that well-formed
4575 * documents need not declare any of the following entities: amp, lt,
4576 * gt, apos, quot. The declaration of a parameter entity must precede
4577 * any reference to it. Similarly, the declaration of a general entity
4578 * must precede any reference to it which appears in a default value in an
4579 * attribute-list declaration. Note that if entities are declared in the
4580 * external subset or in external parameter entities, a non-validating
4581 * processor is not obligated to read and process their declarations;
4582 * for such documents, the rule that an entity must be declared is a
4583 * well-formedness constraint only if standalone='yes'.
4584 *
4585 * [ WFC: Parsed Entity ]
4586 * An entity reference must not contain the name of an unparsed entity
4587 *
Daniel Veillard011b63c1999-06-02 17:44:04 +00004588 * Returns the xmlEntityPtr if found, or NULL otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004589 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00004590xmlEntityPtr
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004591xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004592 xmlChar *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00004593 xmlEntityPtr ent = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004594
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004595 GROW;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004596
Daniel Veillard260a68f1998-08-13 03:39:55 +00004597 if (CUR == '&') {
4598 NEXT;
4599 name = xmlParseName(ctxt);
4600 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004601 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00004602 ctxt->sax->error(ctxt->userData,
4603 "xmlParseEntityRef: no name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004604 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004605 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004606 } else {
4607 if (CUR == ';') {
4608 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004609 /*
Daniel Veillard011b63c1999-06-02 17:44:04 +00004610 * Ask first SAX for entity resolution, otherwise try the
4611 * predefined set.
4612 */
4613 if (ctxt->sax != NULL) {
4614 if (ctxt->sax->getEntity != NULL)
4615 ent = ctxt->sax->getEntity(ctxt->userData, name);
4616 if (ent == NULL)
4617 ent = xmlGetPredefinedEntity(name);
4618 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004619 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00004620 * [ WFC: Entity Declared ]
4621 * In a document without any DTD, a document with only an
4622 * internal DTD subset which contains no parameter entity
4623 * references, or a document with "standalone='yes'", the
4624 * Name given in the entity reference must match that in an
4625 * entity declaration, except that well-formed documents
4626 * need not declare any of the following entities: amp, lt,
4627 * gt, apos, quot.
4628 * The declaration of a parameter entity must precede any
4629 * reference to it.
4630 * Similarly, the declaration of a general entity must
4631 * precede any reference to it which appears in a default
4632 * value in an attribute-list declaration. Note that if
4633 * entities are declared in the external subset or in
4634 * external parameter entities, a non-validating processor
4635 * is not obligated to read and process their declarations;
4636 * for such documents, the rule that an entity must be
4637 * declared is a well-formedness constraint only if
4638 * standalone='yes'.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004639 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00004640 if (ent == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004641 if ((ctxt->standalone == 1) ||
4642 ((ctxt->hasExternalSubset == 0) &&
4643 (ctxt->hasPErefs == 0))) {
4644 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00004645 ctxt->sax->error(ctxt->userData,
4646 "Entity '%s' not defined\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004647 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004648 ctxt->wellFormed = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004649 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004650 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
4651 ctxt->sax->warning(ctxt->userData,
4652 "Entity '%s' not defined\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004653 ctxt->errNo = XML_WAR_UNDECLARED_ENTITY;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004654 }
4655 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004656
4657 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00004658 * [ WFC: Parsed Entity ]
4659 * An entity reference must not contain the name of an
4660 * unparsed entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004661 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00004662 else if (ent->type == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
4663 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4664 ctxt->sax->error(ctxt->userData,
4665 "Entity reference to unparsed entity %s\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004666 ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004667 ctxt->wellFormed = 0;
4668 }
4669
4670 /*
4671 * [ WFC: No External Entity References ]
4672 * Attribute values cannot contain direct or indirect
4673 * entity references to external entities.
4674 */
4675 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
4676 (ent->type == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
4677 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4678 ctxt->sax->error(ctxt->userData,
4679 "Attribute references external entity '%s'\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004680 ctxt->errNo = XML_ERR_ENTITY_IS_EXTERNAL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004681 ctxt->wellFormed = 0;
4682 }
4683 /*
4684 * [ WFC: No < in Attribute Values ]
4685 * The replacement text of any entity referred to directly or
4686 * indirectly in an attribute value (other than "&lt;") must
4687 * not contain a <.
4688 */
4689 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
Daniel Veillardb96e6431999-08-29 21:02:19 +00004690 (ent != NULL) &&
4691 (xmlStrcmp(ent->name, BAD_CAST "lt")) &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00004692 (ent->content != NULL) &&
4693 (xmlStrchr(ent->content, '<'))) {
4694 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4695 ctxt->sax->error(ctxt->userData,
4696 "'<' in entity '%s' is not allowed in attributes values\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004697 ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004698 ctxt->wellFormed = 0;
4699 }
4700
4701 /*
4702 * Internal check, no parameter entities here ...
4703 */
4704 else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004705 switch (ent->type) {
4706 case XML_INTERNAL_PARAMETER_ENTITY:
4707 case XML_EXTERNAL_PARAMETER_ENTITY:
4708 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004709 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004710 "Attempt to reference the parameter entity '%s'\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004711 ctxt->errNo = XML_ERR_ENTITY_IS_PARAMETER;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004712 ctxt->wellFormed = 0;
4713 break;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004714 }
4715 }
4716
4717 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00004718 * [ WFC: No Recursion ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004719 * TODO A parsed entity must not contain a recursive reference
4720 * to itself, either directly or indirectly.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004721 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00004722
Daniel Veillard011b63c1999-06-02 17:44:04 +00004723 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004724 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004725 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004726 "xmlParseEntityRef: expecting ';'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004727 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004728 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004729 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00004730 xmlFree(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004731 }
4732 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004733 return(ent);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004734}
4735
Daniel Veillard11e00581998-10-24 18:27:49 +00004736/**
4737 * xmlParsePEReference:
4738 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00004739 *
4740 * parse PEReference declarations
Daniel Veillard011b63c1999-06-02 17:44:04 +00004741 * The entity content is handled directly by pushing it's content as
4742 * a new input stream.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004743 *
4744 * [69] PEReference ::= '%' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00004745 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004746 * [ WFC: No Recursion ]
4747 * TODO A parsed entity must not contain a recursive
4748 * reference to itself, either directly or indirectly.
4749 *
4750 * [ WFC: Entity Declared ]
4751 * In a document without any DTD, a document with only an internal DTD
4752 * subset which contains no parameter entity references, or a document
4753 * with "standalone='yes'", ... ... The declaration of a parameter
4754 * entity must precede any reference to it...
4755 *
4756 * [ VC: Entity Declared ]
4757 * In a document with an external subset or external parameter entities
4758 * with "standalone='no'", ... ... The declaration of a parameter entity
4759 * must precede any reference to it...
4760 *
4761 * [ WFC: In DTD ]
4762 * Parameter-entity references may only appear in the DTD.
4763 * NOTE: misleading but this is handled.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004764 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00004765void
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004766xmlParsePEReference(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004767 xmlChar *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00004768 xmlEntityPtr entity = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +00004769 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004770
4771 if (CUR == '%') {
4772 NEXT;
4773 name = xmlParseName(ctxt);
4774 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004775 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004776 ctxt->sax->error(ctxt->userData,
4777 "xmlParsePEReference: no name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004778 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004779 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004780 } else {
4781 if (CUR == ';') {
4782 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004783 if ((ctxt->sax != NULL) &&
4784 (ctxt->sax->getParameterEntity != NULL))
4785 entity = ctxt->sax->getParameterEntity(ctxt->userData,
4786 name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004787 if (entity == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004788 /*
4789 * [ WFC: Entity Declared ]
4790 * In a document without any DTD, a document with only an
4791 * internal DTD subset which contains no parameter entity
4792 * references, or a document with "standalone='yes'", ...
4793 * ... The declaration of a parameter entity must precede
4794 * any reference to it...
4795 */
4796 if ((ctxt->standalone == 1) ||
4797 ((ctxt->hasExternalSubset == 0) &&
4798 (ctxt->hasPErefs == 0))) {
4799 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4800 ctxt->sax->error(ctxt->userData,
4801 "PEReference: %%%s; not found\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004802 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004803 ctxt->wellFormed = 0;
4804 } else {
4805 /*
4806 * [ VC: Entity Declared ]
4807 * In a document with an external subset or external
4808 * parameter entities with "standalone='no'", ...
4809 * ... The declaration of a parameter entity must precede
4810 * any reference to it...
4811 */
4812 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
4813 ctxt->sax->warning(ctxt->userData,
4814 "PEReference: %%%s; not found\n", name);
4815 ctxt->valid = 0;
4816 }
Daniel Veillardccb09631998-10-27 06:21:04 +00004817 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004818 /*
4819 * Internal checking in case the entity quest barfed
4820 */
4821 if ((entity->type != XML_INTERNAL_PARAMETER_ENTITY) &&
4822 (entity->type != XML_EXTERNAL_PARAMETER_ENTITY)) {
4823 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
4824 ctxt->sax->warning(ctxt->userData,
4825 "Internal: %%%s; is not a parameter entity\n", name);
4826 } else {
4827 input = xmlNewEntityInputStream(ctxt, entity);
4828 xmlPushInput(ctxt, input);
4829 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004830 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00004831 ctxt->hasPErefs = 1;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004832 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004833 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004834 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004835 "xmlParsePEReference: expecting ';'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004836 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004837 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004838 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00004839 xmlFree(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004840 }
4841 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004842}
4843
Daniel Veillard11e00581998-10-24 18:27:49 +00004844/**
4845 * xmlParseDocTypeDecl :
4846 * @ctxt: an XML parser context
4847 *
4848 * parse a DOCTYPE declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00004849 *
4850 * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
4851 * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
Daniel Veillardb05deb71999-08-10 19:04:08 +00004852 *
4853 * [ VC: Root Element Type ]
4854 * The Name in the document type declaration must match the element
4855 * type of the root element.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004856 */
4857
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004858void
4859xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004860 xmlChar *name;
4861 xmlChar *ExternalID = NULL;
4862 xmlChar *URI = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004863
4864 /*
4865 * We know that '<!DOCTYPE' has been detected.
4866 */
4867 SKIP(9);
4868
4869 SKIP_BLANKS;
4870
4871 /*
4872 * Parse the DOCTYPE name.
4873 */
4874 name = xmlParseName(ctxt);
4875 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004876 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004877 ctxt->sax->error(ctxt->userData,
4878 "xmlParseDocTypeDecl : no DOCTYPE name !\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004879 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004880 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004881 }
4882
4883 SKIP_BLANKS;
4884
4885 /*
4886 * Check for SystemID and ExternalID
4887 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00004888 URI = xmlParseExternalID(ctxt, &ExternalID, 1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004889
4890 if ((URI != NULL) || (ExternalID != NULL)) {
4891 ctxt->hasExternalSubset = 1;
4892 }
4893
Daniel Veillard260a68f1998-08-13 03:39:55 +00004894 SKIP_BLANKS;
4895
Daniel Veillard011b63c1999-06-02 17:44:04 +00004896 /*
4897 * NOTE: the SAX callback may try to fetch the external subset
4898 * entity and fill it up !
4899 */
Daniel Veillard517752b1999-04-05 12:20:10 +00004900 if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004901 ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004902
4903 /*
4904 * Is there any DTD definition ?
4905 */
4906 if (CUR == '[') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004907 ctxt->instate = XML_PARSER_DTD;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004908 NEXT;
4909 /*
4910 * Parse the succession of Markup declarations and
4911 * PEReferences.
4912 * Subsequence (markupdecl | PEReference | S)*
4913 */
4914 while (CUR != ']') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004915 const xmlChar *check = CUR_PTR;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004916 int cons = ctxt->input->consumed;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004917
4918 SKIP_BLANKS;
4919 xmlParseMarkupDecl(ctxt);
Daniel Veillardccb09631998-10-27 06:21:04 +00004920 xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004921
Daniel Veillard011b63c1999-06-02 17:44:04 +00004922 /*
4923 * Pop-up of finished entities.
4924 */
4925 while ((CUR == 0) && (ctxt->inputNr > 1))
4926 xmlPopInput(ctxt);
4927
Daniel Veillardc26087b1999-08-30 11:23:51 +00004928 if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004929 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4930 ctxt->sax->error(ctxt->userData,
4931 "xmlParseDocTypeDecl: error detected in Markup declaration\n");
4932 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004933 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004934 break;
4935 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004936 }
4937 if (CUR == ']') NEXT;
4938 }
4939
4940 /*
4941 * We should be at the end of the DOCTYPE declaration.
4942 */
4943 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004944 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004945 ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004946 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004947 ctxt->errNo = XML_ERR_DOCTYPE_NOT_FINISHED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004948 }
4949 NEXT;
4950
4951 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00004952 * Cleanup
Daniel Veillard260a68f1998-08-13 03:39:55 +00004953 */
Daniel Veillard6454aec1999-09-02 22:04:43 +00004954 if (URI != NULL) xmlFree(URI);
4955 if (ExternalID != NULL) xmlFree(ExternalID);
4956 if (name != NULL) xmlFree(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004957}
4958
Daniel Veillard11e00581998-10-24 18:27:49 +00004959/**
4960 * xmlParseAttribute:
4961 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004962 * @value: a xmlChar ** used to store the value of the attribute
Daniel Veillard11e00581998-10-24 18:27:49 +00004963 *
4964 * parse an attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00004965 *
4966 * [41] Attribute ::= Name Eq AttValue
4967 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004968 * [ WFC: No External Entity References ]
4969 * Attribute values cannot contain direct or indirect entity references
4970 * to external entities.
4971 *
4972 * [ WFC: No < in Attribute Values ]
4973 * The replacement text of any entity referred to directly or indirectly in
4974 * an attribute value (other than "&lt;") must not contain a <.
4975 *
4976 * [ VC: Attribute Value Type ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004977 * The attribute must have been declared; the value must be of the type
Daniel Veillardb05deb71999-08-10 19:04:08 +00004978 * declared for it.
4979 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004980 * [25] Eq ::= S? '=' S?
4981 *
4982 * With namespace:
4983 *
4984 * [NS 11] Attribute ::= QName Eq AttValue
4985 *
4986 * Also the case QName == xmlns:??? is handled independently as a namespace
4987 * definition.
Daniel Veillard1e346af1999-02-22 10:33:01 +00004988 *
Daniel Veillard517752b1999-04-05 12:20:10 +00004989 * Returns the attribute name, and the value in *value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004990 */
4991
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004992xmlChar *
4993xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) {
4994 xmlChar *name, *val;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004995
Daniel Veillard517752b1999-04-05 12:20:10 +00004996 *value = NULL;
4997 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004998 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004999 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005000 ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005001 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005002 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillardccb09631998-10-27 06:21:04 +00005003 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005004 }
5005
5006 /*
5007 * read the value
5008 */
5009 SKIP_BLANKS;
5010 if (CUR == '=') {
5011 NEXT;
5012 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00005013 val = xmlParseAttValue(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005014 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005015 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005016 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005017 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005018 "Specification mandate value for attribute %s\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005019 ctxt->errNo = XML_ERR_ATTRIBUTE_WITHOUT_VALUE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005020 ctxt->wellFormed = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00005021 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005022 }
5023
Daniel Veillard517752b1999-04-05 12:20:10 +00005024 *value = val;
5025 return(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005026}
5027
Daniel Veillard11e00581998-10-24 18:27:49 +00005028/**
5029 * xmlParseStartTag:
5030 * @ctxt: an XML parser context
5031 *
5032 * parse a start of tag either for rule element or
5033 * EmptyElement. In both case we don't parse the tag closing chars.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005034 *
5035 * [40] STag ::= '<' Name (S Attribute)* S? '>'
5036 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005037 * [ WFC: Unique Att Spec ]
5038 * No attribute name may appear more than once in the same start-tag or
5039 * empty-element tag.
5040 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00005041 * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
5042 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005043 * [ WFC: Unique Att Spec ]
5044 * No attribute name may appear more than once in the same start-tag or
5045 * empty-element tag.
5046 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00005047 * With namespace:
5048 *
5049 * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
5050 *
5051 * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
Daniel Veillard14fff061999-06-22 21:49:07 +00005052 *
Daniel Veillard7f858501999-11-17 17:32:38 +00005053 * Returne the element name parsed
Daniel Veillard260a68f1998-08-13 03:39:55 +00005054 */
5055
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005056xmlChar *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005057xmlParseStartTag(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005058 xmlChar *name;
5059 xmlChar *attname;
5060 xmlChar *attvalue;
5061 const xmlChar **atts = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00005062 int nbatts = 0;
5063 int maxatts = 0;
5064 int i;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005065
Daniel Veillard14fff061999-06-22 21:49:07 +00005066 if (CUR != '<') return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005067 NEXT;
5068
Daniel Veillard517752b1999-04-05 12:20:10 +00005069 name = xmlParseName(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005070 if (name == NULL) {
5071 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005072 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005073 "xmlParseStartTag: invalid element name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005074 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005075 ctxt->wellFormed = 0;
Daniel Veillard14fff061999-06-22 21:49:07 +00005076 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005077 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005078
5079 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00005080 * Now parse the attributes, it ends up with the ending
5081 *
5082 * (S Attribute)* S?
5083 */
5084 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005085 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005086 while ((IS_CHAR(CUR)) &&
5087 (CUR != '>') &&
5088 ((CUR != '/') || (NXT(1) != '>'))) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005089 const xmlChar *q = CUR_PTR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005090 int cons = ctxt->input->consumed;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005091
Daniel Veillard517752b1999-04-05 12:20:10 +00005092 attname = xmlParseAttribute(ctxt, &attvalue);
5093 if ((attname != NULL) && (attvalue != NULL)) {
5094 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005095 * [ WFC: Unique Att Spec ]
5096 * No attribute name may appear more than once in the same
5097 * start-tag or empty-element tag.
Daniel Veillard517752b1999-04-05 12:20:10 +00005098 */
5099 for (i = 0; i < nbatts;i += 2) {
5100 if (!xmlStrcmp(atts[i], attname)) {
5101 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00005102 ctxt->sax->error(ctxt->userData,
5103 "Attribute %s redefined\n",
5104 attname);
Daniel Veillard517752b1999-04-05 12:20:10 +00005105 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005106 ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED;
Daniel Veillard6454aec1999-09-02 22:04:43 +00005107 xmlFree(attname);
5108 xmlFree(attvalue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005109 goto failed;
Daniel Veillard517752b1999-04-05 12:20:10 +00005110 }
5111 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005112
Daniel Veillard517752b1999-04-05 12:20:10 +00005113 /*
5114 * Add the pair to atts
5115 */
5116 if (atts == NULL) {
5117 maxatts = 10;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005118 atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *));
Daniel Veillard517752b1999-04-05 12:20:10 +00005119 if (atts == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00005120 fprintf(stderr, "malloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005121 maxatts * (long)sizeof(xmlChar *));
Daniel Veillard14fff061999-06-22 21:49:07 +00005122 return(NULL);
Daniel Veillard517752b1999-04-05 12:20:10 +00005123 }
Daniel Veillard51e3b151999-11-12 17:02:31 +00005124 } else if (nbatts + 4 > maxatts) {
Daniel Veillard517752b1999-04-05 12:20:10 +00005125 maxatts *= 2;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005126 atts = (const xmlChar **) xmlRealloc(atts,
5127 maxatts * sizeof(xmlChar *));
Daniel Veillard517752b1999-04-05 12:20:10 +00005128 if (atts == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00005129 fprintf(stderr, "realloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005130 maxatts * (long)sizeof(xmlChar *));
Daniel Veillard14fff061999-06-22 21:49:07 +00005131 return(NULL);
Daniel Veillard517752b1999-04-05 12:20:10 +00005132 }
5133 }
5134 atts[nbatts++] = attname;
5135 atts[nbatts++] = attvalue;
5136 atts[nbatts] = NULL;
5137 atts[nbatts + 1] = NULL;
5138 }
5139
Daniel Veillardb96e6431999-08-29 21:02:19 +00005140failed:
Daniel Veillard517752b1999-04-05 12:20:10 +00005141 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005142 if ((cons == ctxt->input->consumed) && (q == CUR_PTR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005143 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005144 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00005145 "xmlParseStartTag: problem parsing attributes\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005146 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005147 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005148 break;
5149 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005150 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005151 }
5152
5153 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00005154 * SAX: Start of Element !
5155 */
Daniel Veillard517752b1999-04-05 12:20:10 +00005156 if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005157 ctxt->sax->startElement(ctxt->userData, name, atts);
Daniel Veillard517752b1999-04-05 12:20:10 +00005158
Daniel Veillard517752b1999-04-05 12:20:10 +00005159 if (atts != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005160 for (i = 0;i < nbatts;i++) xmlFree((xmlChar *) atts[i]);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005161 xmlFree(atts);
Daniel Veillard517752b1999-04-05 12:20:10 +00005162 }
Daniel Veillard14fff061999-06-22 21:49:07 +00005163 return(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005164}
5165
Daniel Veillard11e00581998-10-24 18:27:49 +00005166/**
5167 * xmlParseEndTag:
5168 * @ctxt: an XML parser context
Daniel Veillard14fff061999-06-22 21:49:07 +00005169 * @tagname: the tag name as parsed in the opening tag.
Daniel Veillard11e00581998-10-24 18:27:49 +00005170 *
5171 * parse an end of tag
Daniel Veillard260a68f1998-08-13 03:39:55 +00005172 *
5173 * [42] ETag ::= '</' Name S? '>'
5174 *
5175 * With namespace
5176 *
Daniel Veillard517752b1999-04-05 12:20:10 +00005177 * [NS 9] ETag ::= '</' QName S? '>'
Daniel Veillard260a68f1998-08-13 03:39:55 +00005178 */
5179
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005180void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005181xmlParseEndTag(xmlParserCtxtPtr ctxt, xmlChar *tagname) {
5182 xmlChar *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005183
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005184 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005185 if ((CUR != '<') || (NXT(1) != '/')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005186 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005187 ctxt->sax->error(ctxt->userData, "xmlParseEndTag: '</' not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005188 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005189 ctxt->errNo = XML_ERR_LTSLASH_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005190 return;
5191 }
5192 SKIP(2);
5193
Daniel Veillard517752b1999-04-05 12:20:10 +00005194 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005195
5196 /*
5197 * We should definitely be at the ending "S? '>'" part
5198 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005199 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005200 SKIP_BLANKS;
5201 if ((!IS_CHAR(CUR)) || (CUR != '>')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005202 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005203 ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005204 ctxt->errNo = XML_ERR_GT_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005205 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005206 } else
5207 NEXT;
5208
Daniel Veillard517752b1999-04-05 12:20:10 +00005209 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005210 * [ WFC: Element Type Match ]
5211 * The Name in an element's end-tag must match the element type in the
5212 * start-tag.
5213 *
Daniel Veillard14fff061999-06-22 21:49:07 +00005214 */
5215 if (xmlStrcmp(name, tagname)) {
5216 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5217 ctxt->sax->error(ctxt->userData,
5218 "Opening and ending tag mismatch: %s and %s\n", tagname, name);
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005219
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005220 ctxt->errNo = XML_ERR_TAG_NAME_MISMATCH;
Daniel Veillard14fff061999-06-22 21:49:07 +00005221 ctxt->wellFormed = 0;
5222 }
5223
5224 /*
Daniel Veillard517752b1999-04-05 12:20:10 +00005225 * SAX: End of Tag
5226 */
5227 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005228 ctxt->sax->endElement(ctxt->userData, name);
Daniel Veillard517752b1999-04-05 12:20:10 +00005229
5230 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00005231 xmlFree(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00005232
Daniel Veillard260a68f1998-08-13 03:39:55 +00005233 return;
5234}
5235
Daniel Veillard11e00581998-10-24 18:27:49 +00005236/**
5237 * xmlParseCDSect:
5238 * @ctxt: an XML parser context
5239 *
5240 * Parse escaped pure raw content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005241 *
5242 * [18] CDSect ::= CDStart CData CDEnd
5243 *
5244 * [19] CDStart ::= '<![CDATA['
5245 *
5246 * [20] Data ::= (Char* - (Char* ']]>' Char*))
5247 *
5248 * [21] CDEnd ::= ']]>'
5249 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005250void
5251xmlParseCDSect(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005252 const xmlChar *base;
5253 xmlChar r, s;
5254 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005255
Daniel Veillardb05deb71999-08-10 19:04:08 +00005256 if ((NXT(0) == '<') && (NXT(1) == '!') &&
Daniel Veillard260a68f1998-08-13 03:39:55 +00005257 (NXT(2) == '[') && (NXT(3) == 'C') &&
5258 (NXT(4) == 'D') && (NXT(5) == 'A') &&
5259 (NXT(6) == 'T') && (NXT(7) == 'A') &&
5260 (NXT(8) == '[')) {
5261 SKIP(9);
5262 } else
5263 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005264
5265 ctxt->instate = XML_PARSER_CDATA_SECTION;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005266 base = CUR_PTR;
5267 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005268 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005269 ctxt->sax->error(ctxt->userData,
5270 "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005271 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005272 ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005273 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005274 return;
5275 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00005276 r = CUR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005277 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005278 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005279 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005280 ctxt->sax->error(ctxt->userData,
5281 "CData section not finished\n%.50s\n", base);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005282 ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005283 ctxt->wellFormed = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005284 ctxt->instate = XML_PARSER_CONTENT;
5285 return;
5286 }
5287 s = CUR;
5288 NEXT;
5289 cur = CUR;
5290 while (IS_CHAR(cur) &&
5291 ((r != ']') || (s != ']') || (cur != '>'))) {
5292 r = s;
5293 s = cur;
5294 NEXT;
5295 cur = CUR;
5296 }
5297 ctxt->instate = XML_PARSER_CONTENT;
5298 if (!IS_CHAR(CUR)) {
5299 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005300 ctxt->sax->error(ctxt->userData,
5301 "CData section not finished\n%.50s\n", base);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005302 ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005303 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005304 return;
5305 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005306 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005307
5308 /*
5309 * Ok the segment [base CUR_PTR] is to be consumed as chars.
5310 */
5311 if (ctxt->sax != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00005312 if (ctxt->sax->cdataBlock != NULL)
5313 ctxt->sax->cdataBlock(ctxt->userData, base, (CUR_PTR - base) - 3);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005314 }
5315}
5316
Daniel Veillard11e00581998-10-24 18:27:49 +00005317/**
5318 * xmlParseContent:
5319 * @ctxt: an XML parser context
5320 *
5321 * Parse a content:
Daniel Veillard260a68f1998-08-13 03:39:55 +00005322 *
5323 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
5324 */
5325
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005326void
5327xmlParseContent(xmlParserCtxtPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00005328 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005329 while ((CUR != '<') || (NXT(1) != '/')) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005330 const xmlChar *test = CUR_PTR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005331 int cons = ctxt->input->consumed;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005332 xmlChar tok = ctxt->token;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005333
5334 /*
5335 * First case : a Processing Instruction.
5336 */
5337 if ((CUR == '<') && (NXT(1) == '?')) {
5338 xmlParsePI(ctxt);
5339 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005340
Daniel Veillard260a68f1998-08-13 03:39:55 +00005341 /*
5342 * Second case : a CDSection
5343 */
5344 else if ((CUR == '<') && (NXT(1) == '!') &&
5345 (NXT(2) == '[') && (NXT(3) == 'C') &&
5346 (NXT(4) == 'D') && (NXT(5) == 'A') &&
5347 (NXT(6) == 'T') && (NXT(7) == 'A') &&
5348 (NXT(8) == '[')) {
5349 xmlParseCDSect(ctxt);
5350 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005351
Daniel Veillard260a68f1998-08-13 03:39:55 +00005352 /*
5353 * Third case : a comment
5354 */
5355 else if ((CUR == '<') && (NXT(1) == '!') &&
5356 (NXT(2) == '-') && (NXT(3) == '-')) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00005357 xmlParseComment(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005358 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005359 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005360
Daniel Veillard260a68f1998-08-13 03:39:55 +00005361 /*
5362 * Fourth case : a sub-element.
5363 */
5364 else if (CUR == '<') {
Daniel Veillard517752b1999-04-05 12:20:10 +00005365 xmlParseElement(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005366 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005367
Daniel Veillard260a68f1998-08-13 03:39:55 +00005368 /*
Daniel Veillardccb09631998-10-27 06:21:04 +00005369 * Fifth case : a reference. If if has not been resolved,
5370 * parsing returns it's Name, create the node
Daniel Veillard260a68f1998-08-13 03:39:55 +00005371 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00005372
Daniel Veillard260a68f1998-08-13 03:39:55 +00005373 else if (CUR == '&') {
Daniel Veillard011b63c1999-06-02 17:44:04 +00005374 xmlParseReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005375 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005376
Daniel Veillard260a68f1998-08-13 03:39:55 +00005377 /*
5378 * Last case, text. Note that References are handled directly.
5379 */
5380 else {
5381 xmlParseCharData(ctxt, 0);
5382 }
5383
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005384 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005385 /*
5386 * Pop-up of finished entities.
5387 */
Daniel Veillardbc50b591999-03-01 12:28:53 +00005388 while ((CUR == 0) && (ctxt->inputNr > 1))
5389 xmlPopInput(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005390
Daniel Veillardb96e6431999-08-29 21:02:19 +00005391 if ((cons == ctxt->input->consumed) && (test == CUR_PTR) &&
5392 (tok == ctxt->token)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005393 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005394 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005395 "detected an error in element content\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005396 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005397 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005398 break;
5399 }
5400 }
5401}
5402
Daniel Veillard11e00581998-10-24 18:27:49 +00005403/**
5404 * xmlParseElement:
5405 * @ctxt: an XML parser context
5406 *
5407 * parse an XML element, this is highly recursive
Daniel Veillard260a68f1998-08-13 03:39:55 +00005408 *
5409 * [39] element ::= EmptyElemTag | STag content ETag
5410 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005411 * [ WFC: Element Type Match ]
5412 * The Name in an element's end-tag must match the element type in the
5413 * start-tag.
5414 *
5415 * [ VC: Element Valid ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00005416 * An element is valid if there is a declaration matching elementdecl
Daniel Veillardb05deb71999-08-10 19:04:08 +00005417 * where the Name matches the element type and one of the following holds:
5418 * - The declaration matches EMPTY and the element has no content.
5419 * - The declaration matches children and the sequence of child elements
5420 * belongs to the language generated by the regular expression in the
5421 * content model, with optional white space (characters matching the
5422 * nonterminal S) between each pair of child elements.
5423 * - The declaration matches Mixed and the content consists of character
5424 * data and child elements whose types match names in the content model.
5425 * - The declaration matches ANY, and the types of any child elements have
5426 * been declared.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005427 */
5428
Daniel Veillard517752b1999-04-05 12:20:10 +00005429void
Daniel Veillard1e346af1999-02-22 10:33:01 +00005430xmlParseElement(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005431 const xmlChar *openTag = CUR_PTR;
5432 xmlChar *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005433 xmlParserNodeInfo node_info;
Daniel Veillardc26087b1999-08-30 11:23:51 +00005434 xmlNodePtr ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005435
5436 /* Capture start position */
Daniel Veillardc26087b1999-08-30 11:23:51 +00005437 if (ctxt->record_info) {
5438 node_info.begin_pos = ctxt->input->consumed +
5439 (CUR_PTR - ctxt->input->base);
5440 node_info.begin_line = ctxt->input->line;
5441 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005442
Daniel Veillard14fff061999-06-22 21:49:07 +00005443 name = xmlParseStartTag(ctxt);
5444 if (name == NULL) {
5445 return;
5446 }
Daniel Veillardc26087b1999-08-30 11:23:51 +00005447 ret = ctxt->node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005448
5449 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005450 * [ VC: Root Element Type ]
5451 * The Name in the document type declaration must match the element
5452 * type of the root element.
5453 */
5454 if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc &&
5455 ctxt->node && (ctxt->node == ctxt->myDoc->root))
5456 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
5457
5458 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00005459 * Check for an Empty Element.
5460 */
5461 if ((CUR == '/') && (NXT(1) == '>')) {
5462 SKIP(2);
Daniel Veillard517752b1999-04-05 12:20:10 +00005463 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard14fff061999-06-22 21:49:07 +00005464 ctxt->sax->endElement(ctxt->userData, name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005465 xmlFree(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00005466 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005467 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005468 if (CUR == '>') {
5469 NEXT;
5470 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005471 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005472 ctxt->sax->error(ctxt->userData,
5473 "Couldn't find end of Start Tag\n%.30s\n",
Daniel Veillard242590e1998-11-13 18:04:35 +00005474 openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005475 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005476 ctxt->errNo = XML_ERR_GT_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005477
5478 /*
5479 * end of parsing of this node.
5480 */
5481 nodePop(ctxt);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005482 xmlFree(name);
Daniel Veillardc26087b1999-08-30 11:23:51 +00005483
5484 /*
5485 * Capture end position and add node
5486 */
5487 if ( ret != NULL && ctxt->record_info ) {
5488 node_info.end_pos = ctxt->input->consumed +
5489 (CUR_PTR - ctxt->input->base);
5490 node_info.end_line = ctxt->input->line;
5491 node_info.node = ret;
5492 xmlParserAddNodeInfo(ctxt, &node_info);
5493 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005494 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005495 }
5496
5497 /*
5498 * Parse the content of the element:
5499 */
5500 xmlParseContent(ctxt);
5501 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005502 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005503 ctxt->sax->error(ctxt->userData,
Daniel Veillard242590e1998-11-13 18:04:35 +00005504 "Premature end of data in tag %.30s\n", openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005505 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005506 ctxt->errNo = XML_ERR_TAG_NOT_FINISED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005507
5508 /*
5509 * end of parsing of this node.
5510 */
5511 nodePop(ctxt);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005512 xmlFree(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00005513 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005514 }
5515
5516 /*
5517 * parse the end of tag: '</' should be here.
5518 */
Daniel Veillard14fff061999-06-22 21:49:07 +00005519 xmlParseEndTag(ctxt, name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005520 xmlFree(name);
Daniel Veillardc26087b1999-08-30 11:23:51 +00005521
5522 /*
5523 * Capture end position and add node
5524 */
5525 if ( ret != NULL && ctxt->record_info ) {
5526 node_info.end_pos = ctxt->input->consumed +
5527 (CUR_PTR - ctxt->input->base);
5528 node_info.end_line = ctxt->input->line;
5529 node_info.node = ret;
5530 xmlParserAddNodeInfo(ctxt, &node_info);
5531 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005532}
5533
Daniel Veillard11e00581998-10-24 18:27:49 +00005534/**
5535 * xmlParseVersionNum:
5536 * @ctxt: an XML parser context
5537 *
5538 * parse the XML version value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005539 *
5540 * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
Daniel Veillard1e346af1999-02-22 10:33:01 +00005541 *
5542 * Returns the string giving the XML version number, or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00005543 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005544xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005545xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005546 const xmlChar *q = CUR_PTR;
5547 xmlChar *ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005548
5549 while (IS_CHAR(CUR) &&
5550 (((CUR >= 'a') && (CUR <= 'z')) ||
5551 ((CUR >= 'A') && (CUR <= 'Z')) ||
5552 ((CUR >= '0') && (CUR <= '9')) ||
5553 (CUR == '_') || (CUR == '.') ||
5554 (CUR == ':') || (CUR == '-'))) NEXT;
5555 ret = xmlStrndup(q, CUR_PTR - q);
5556 return(ret);
5557}
5558
Daniel Veillard11e00581998-10-24 18:27:49 +00005559/**
5560 * xmlParseVersionInfo:
5561 * @ctxt: an XML parser context
5562 *
5563 * parse the XML version.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005564 *
5565 * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
5566 *
5567 * [25] Eq ::= S? '=' S?
Daniel Veillard11e00581998-10-24 18:27:49 +00005568 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005569 * Returns the version string, e.g. "1.0"
Daniel Veillard260a68f1998-08-13 03:39:55 +00005570 */
5571
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005572xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005573xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005574 xmlChar *version = NULL;
5575 const xmlChar *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005576
5577 if ((CUR == 'v') && (NXT(1) == 'e') &&
5578 (NXT(2) == 'r') && (NXT(3) == 's') &&
5579 (NXT(4) == 'i') && (NXT(5) == 'o') &&
5580 (NXT(6) == 'n')) {
5581 SKIP(7);
5582 SKIP_BLANKS;
5583 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005584 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005585 ctxt->sax->error(ctxt->userData,
5586 "xmlParseVersionInfo : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005587 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005588 ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005589 return(NULL);
5590 }
5591 NEXT;
5592 SKIP_BLANKS;
5593 if (CUR == '"') {
5594 NEXT;
5595 q = CUR_PTR;
5596 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005597 if (CUR != '"') {
5598 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005599 ctxt->sax->error(ctxt->userData,
5600 "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005601 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005602 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005603 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005604 NEXT;
5605 } else if (CUR == '\''){
5606 NEXT;
5607 q = CUR_PTR;
5608 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005609 if (CUR != '\'') {
5610 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005611 ctxt->sax->error(ctxt->userData,
5612 "String not closed\n%.50s\n", q);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005613 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005614 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005615 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005616 NEXT;
5617 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005618 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005619 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005620 "xmlParseVersionInfo : expected ' or \"\n");
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005621 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005622 ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005623 }
5624 }
5625 return(version);
5626}
5627
Daniel Veillard11e00581998-10-24 18:27:49 +00005628/**
5629 * xmlParseEncName:
5630 * @ctxt: an XML parser context
5631 *
5632 * parse the XML encoding name
Daniel Veillard260a68f1998-08-13 03:39:55 +00005633 *
5634 * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
Daniel Veillard11e00581998-10-24 18:27:49 +00005635 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005636 * Returns the encoding name value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00005637 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005638xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005639xmlParseEncName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005640 const xmlChar *q = CUR_PTR;
5641 xmlChar *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005642
5643 if (((CUR >= 'a') && (CUR <= 'z')) ||
5644 ((CUR >= 'A') && (CUR <= 'Z'))) {
5645 NEXT;
5646 while (IS_CHAR(CUR) &&
5647 (((CUR >= 'a') && (CUR <= 'z')) ||
5648 ((CUR >= 'A') && (CUR <= 'Z')) ||
5649 ((CUR >= '0') && (CUR <= '9')) ||
5650 (CUR == '-'))) NEXT;
5651 ret = xmlStrndup(q, CUR_PTR - q);
5652 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005653 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005654 ctxt->sax->error(ctxt->userData, "Invalid XML encoding name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005655 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005656 ctxt->errNo = XML_ERR_ENCODING_NAME;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005657 }
5658 return(ret);
5659}
5660
Daniel Veillard11e00581998-10-24 18:27:49 +00005661/**
5662 * xmlParseEncodingDecl:
5663 * @ctxt: an XML parser context
5664 *
5665 * parse the XML encoding declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00005666 *
5667 * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'")
Daniel Veillard11e00581998-10-24 18:27:49 +00005668 *
5669 * TODO: this should setup the conversion filters.
5670 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005671 * Returns the encoding value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00005672 */
5673
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005674xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005675xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005676 xmlChar *encoding = NULL;
5677 const xmlChar *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005678
5679 SKIP_BLANKS;
5680 if ((CUR == 'e') && (NXT(1) == 'n') &&
5681 (NXT(2) == 'c') && (NXT(3) == 'o') &&
5682 (NXT(4) == 'd') && (NXT(5) == 'i') &&
5683 (NXT(6) == 'n') && (NXT(7) == 'g')) {
5684 SKIP(8);
5685 SKIP_BLANKS;
5686 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005687 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005688 ctxt->sax->error(ctxt->userData,
5689 "xmlParseEncodingDecl : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005690 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005691 ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005692 return(NULL);
5693 }
5694 NEXT;
5695 SKIP_BLANKS;
5696 if (CUR == '"') {
5697 NEXT;
5698 q = CUR_PTR;
5699 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005700 if (CUR != '"') {
5701 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005702 ctxt->sax->error(ctxt->userData,
5703 "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005704 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005705 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005706 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005707 NEXT;
5708 } else if (CUR == '\''){
5709 NEXT;
5710 q = CUR_PTR;
5711 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005712 if (CUR != '\'') {
5713 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005714 ctxt->sax->error(ctxt->userData,
5715 "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005716 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005717 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005718 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005719 NEXT;
5720 } else if (CUR == '"'){
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005721 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005722 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005723 "xmlParseEncodingDecl : expected ' or \"\n");
5724 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005725 ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005726 }
5727 }
5728 return(encoding);
5729}
5730
Daniel Veillard11e00581998-10-24 18:27:49 +00005731/**
5732 * xmlParseSDDecl:
5733 * @ctxt: an XML parser context
5734 *
5735 * parse the XML standalone declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00005736 *
5737 * [32] SDDecl ::= S 'standalone' Eq
5738 * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00005739 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005740 * [ VC: Standalone Document Declaration ]
5741 * TODO The standalone document declaration must have the value "no"
5742 * if any external markup declarations contain declarations of:
5743 * - attributes with default values, if elements to which these
5744 * attributes apply appear in the document without specifications
5745 * of values for these attributes, or
5746 * - entities (other than amp, lt, gt, apos, quot), if references
5747 * to those entities appear in the document, or
5748 * - attributes with values subject to normalization, where the
5749 * attribute appears in the document with a value which will change
5750 * as a result of normalization, or
5751 * - element types with element content, if white space occurs directly
5752 * within any instance of those types.
5753 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005754 * Returns 1 if standalone, 0 otherwise
Daniel Veillard260a68f1998-08-13 03:39:55 +00005755 */
5756
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005757int
5758xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005759 int standalone = -1;
5760
5761 SKIP_BLANKS;
5762 if ((CUR == 's') && (NXT(1) == 't') &&
5763 (NXT(2) == 'a') && (NXT(3) == 'n') &&
5764 (NXT(4) == 'd') && (NXT(5) == 'a') &&
5765 (NXT(6) == 'l') && (NXT(7) == 'o') &&
5766 (NXT(8) == 'n') && (NXT(9) == 'e')) {
5767 SKIP(10);
Daniel Veillard011b63c1999-06-02 17:44:04 +00005768 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005769 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005770 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005771 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005772 "XML standalone declaration : expected '='\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005773 ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005774 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005775 return(standalone);
5776 }
5777 NEXT;
5778 SKIP_BLANKS;
5779 if (CUR == '\''){
5780 NEXT;
5781 if ((CUR == 'n') && (NXT(1) == 'o')) {
5782 standalone = 0;
5783 SKIP(2);
5784 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
5785 (NXT(2) == 's')) {
5786 standalone = 1;
5787 SKIP(3);
5788 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005789 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005790 ctxt->sax->error(ctxt->userData,
5791 "standalone accepts only 'yes' or 'no'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005792 ctxt->errNo = XML_ERR_STANDALONE_VALUE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005793 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005794 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005795 if (CUR != '\'') {
5796 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005797 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005798 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005799 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005800 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005801 NEXT;
5802 } else if (CUR == '"'){
5803 NEXT;
5804 if ((CUR == 'n') && (NXT(1) == 'o')) {
5805 standalone = 0;
5806 SKIP(2);
5807 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
5808 (NXT(2) == 's')) {
5809 standalone = 1;
5810 SKIP(3);
5811 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005812 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005813 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005814 "standalone accepts only 'yes' or 'no'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005815 ctxt->errNo = XML_ERR_STANDALONE_VALUE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005816 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005817 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005818 if (CUR != '"') {
5819 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005820 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005821 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005822 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005823 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00005824 NEXT;
5825 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005826 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005827 ctxt->sax->error(ctxt->userData,
5828 "Standalone value not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005829 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005830 ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005831 }
5832 }
5833 return(standalone);
5834}
5835
Daniel Veillard11e00581998-10-24 18:27:49 +00005836/**
5837 * xmlParseXMLDecl:
5838 * @ctxt: an XML parser context
5839 *
5840 * parse an XML declaration header
Daniel Veillard260a68f1998-08-13 03:39:55 +00005841 *
5842 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
5843 */
5844
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005845void
5846xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005847 xmlChar *version;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005848
5849 /*
5850 * We know that '<?xml' is here.
5851 */
5852 SKIP(5);
5853
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005854 if (!IS_BLANK(CUR)) {
5855 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005856 ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005857 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005858 ctxt->wellFormed = 0;
5859 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005860 SKIP_BLANKS;
5861
5862 /*
5863 * We should have the VersionInfo here.
5864 */
5865 version = xmlParseVersionInfo(ctxt);
5866 if (version == NULL)
5867 version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard517752b1999-04-05 12:20:10 +00005868 ctxt->version = xmlStrdup(version);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005869 xmlFree(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005870
5871 /*
5872 * We may have the encoding declaration
5873 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005874 if (!IS_BLANK(CUR)) {
5875 if ((CUR == '?') && (NXT(1) == '>')) {
5876 SKIP(2);
5877 return;
5878 }
5879 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005880 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005881 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005882 ctxt->wellFormed = 0;
5883 }
Daniel Veillard517752b1999-04-05 12:20:10 +00005884 ctxt->encoding = xmlParseEncodingDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005885
5886 /*
5887 * We may have the standalone status.
5888 */
Daniel Veillard517752b1999-04-05 12:20:10 +00005889 if ((ctxt->encoding != NULL) && (!IS_BLANK(CUR))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005890 if ((CUR == '?') && (NXT(1) == '>')) {
5891 SKIP(2);
5892 return;
5893 }
5894 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005895 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005896 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005897 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005898 }
5899 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00005900 ctxt->standalone = xmlParseSDDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005901
5902 SKIP_BLANKS;
5903 if ((CUR == '?') && (NXT(1) == '>')) {
5904 SKIP(2);
5905 } else if (CUR == '>') {
5906 /* Deprecated old WD ... */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005907 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005908 ctxt->sax->error(ctxt->userData,
5909 "XML declaration must end-up with '?>'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005910 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005911 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005912 NEXT;
5913 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005914 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005915 ctxt->sax->error(ctxt->userData,
5916 "parsing XML declaration: '?>' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005917 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005918 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005919 MOVETO_ENDTAG(CUR_PTR);
5920 NEXT;
5921 }
5922}
5923
Daniel Veillard11e00581998-10-24 18:27:49 +00005924/**
5925 * xmlParseMisc:
5926 * @ctxt: an XML parser context
5927 *
5928 * parse an XML Misc* optionnal field.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005929 *
5930 * [27] Misc ::= Comment | PI | S
5931 */
5932
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005933void
5934xmlParseMisc(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005935 while (((CUR == '<') && (NXT(1) == '?')) ||
5936 ((CUR == '<') && (NXT(1) == '!') &&
5937 (NXT(2) == '-') && (NXT(3) == '-')) ||
5938 IS_BLANK(CUR)) {
5939 if ((CUR == '<') && (NXT(1) == '?')) {
5940 xmlParsePI(ctxt);
5941 } else if (IS_BLANK(CUR)) {
5942 NEXT;
5943 } else
Daniel Veillardb96e6431999-08-29 21:02:19 +00005944 xmlParseComment(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005945 }
5946}
5947
Daniel Veillard11e00581998-10-24 18:27:49 +00005948/**
5949 * xmlParseDocument :
5950 * @ctxt: an XML parser context
5951 *
5952 * parse an XML document (and build a tree if using the standard SAX
5953 * interface).
Daniel Veillard260a68f1998-08-13 03:39:55 +00005954 *
5955 * [1] document ::= prolog element Misc*
5956 *
5957 * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
Daniel Veillard11e00581998-10-24 18:27:49 +00005958 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005959 * Returns 0, -1 in case of error. the parser context is augmented
Daniel Veillard11e00581998-10-24 18:27:49 +00005960 * as a result of the parsing.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005961 */
5962
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005963int
5964xmlParseDocument(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00005965 xmlDefaultSAXHandlerInit();
5966
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005967 GROW;
5968
Daniel Veillard260a68f1998-08-13 03:39:55 +00005969 /*
5970 * SAX: beginning of the document processing.
5971 */
Daniel Veillard517752b1999-04-05 12:20:10 +00005972 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
Daniel Veillard27d88741999-05-29 11:51:49 +00005973 ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005974
5975 /*
Daniel Veillardb96e6431999-08-29 21:02:19 +00005976 * TODO We should check for encoding here and plug-in some
5977 * conversion code !!!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00005978 */
5979
5980 /*
5981 * Wipe out everything which is before the first '<'
5982 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005983 if (IS_BLANK(CUR)) {
5984 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005985 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005986 "Extra spaces at the beginning of the document are not allowed\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005987 ctxt->errNo = XML_ERR_DOCUMENT_START;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005988 ctxt->wellFormed = 0;
5989 SKIP_BLANKS;
5990 }
5991
5992 if (CUR == 0) {
5993 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005994 ctxt->sax->error(ctxt->userData, "Document is empty\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005995 ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005996 ctxt->wellFormed = 0;
5997 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005998
5999 /*
6000 * Check for the XMLDecl in the Prolog.
6001 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006002 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006003 if ((CUR == '<') && (NXT(1) == '?') &&
6004 (NXT(2) == 'x') && (NXT(3) == 'm') &&
6005 (NXT(4) == 'l')) {
6006 xmlParseXMLDecl(ctxt);
6007 /* SKIP_EOL(cur); */
6008 SKIP_BLANKS;
6009 } else if ((CUR == '<') && (NXT(1) == '?') &&
6010 (NXT(2) == 'X') && (NXT(3) == 'M') &&
6011 (NXT(4) == 'L')) {
6012 /*
6013 * The first drafts were using <?XML and the final W3C REC
6014 * now use <?xml ...
6015 */
6016 xmlParseXMLDecl(ctxt);
6017 /* SKIP_EOL(cur); */
6018 SKIP_BLANKS;
6019 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00006020 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006021 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006022 if ((ctxt->sax) && (ctxt->sax->startDocument))
Daniel Veillard27d88741999-05-29 11:51:49 +00006023 ctxt->sax->startDocument(ctxt->userData);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006024
6025 /*
6026 * The Misc part of the Prolog
6027 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006028 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006029 xmlParseMisc(ctxt);
6030
6031 /*
6032 * Then possibly doc type declaration(s) and more Misc
6033 * (doctypedecl Misc*)?
6034 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006035 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006036 if ((CUR == '<') && (NXT(1) == '!') &&
6037 (NXT(2) == 'D') && (NXT(3) == 'O') &&
6038 (NXT(4) == 'C') && (NXT(5) == 'T') &&
6039 (NXT(6) == 'Y') && (NXT(7) == 'P') &&
6040 (NXT(8) == 'E')) {
6041 xmlParseDocTypeDecl(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006042 ctxt->instate = XML_PARSER_PROLOG;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006043 xmlParseMisc(ctxt);
6044 }
6045
6046 /*
6047 * Time to start parsing the tree itself
6048 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006049 GROW;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006050 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard517752b1999-04-05 12:20:10 +00006051 xmlParseElement(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006052 ctxt->instate = XML_PARSER_EPILOG;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006053
6054 /*
6055 * The Misc part at the end
6056 */
6057 xmlParseMisc(ctxt);
6058
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006059 if (CUR != 0) {
6060 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006061 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006062 "Extra content at the end of the document\n");
6063 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006064 ctxt->errNo = XML_ERR_DOCUMENT_END;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006065 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006066 ctxt->instate = XML_PARSER_EOF;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006067
Daniel Veillard260a68f1998-08-13 03:39:55 +00006068 /*
6069 * SAX: end of the document processing.
6070 */
Daniel Veillard517752b1999-04-05 12:20:10 +00006071 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006072 ctxt->sax->endDocument(ctxt->userData);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006073 if (! ctxt->wellFormed) return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006074 return(0);
6075}
6076
Daniel Veillardb05deb71999-08-10 19:04:08 +00006077/************************************************************************
6078 * *
Daniel Veillard7f858501999-11-17 17:32:38 +00006079 * Progressive parsing interfaces *
6080 * *
6081 ************************************************************************/
6082
6083/**
6084 * xmlParseLookupSequence:
6085 * @ctxt: an XML parser context
6086 * @first: the first char to lookup
6087 * @next: the next char to lookup
6088 *
6089 * Try to find if a sequence (first, next) or just (first) if next
6090 * is zero is available in the input stream.
6091 * Since XML-1.0 is an LALR(2) grammar a sequence of 2 char should be
6092 * enought. If this doesn't prove true this function call may change.
6093 *
6094 * Returns 1 if the full sequence is available, 0 otherwise.
6095 */
6096int
6097xmlParseLookupSequence(xmlParserCtxtPtr ctxt, xmlChar first, xmlChar next) {
6098 return(0);
6099}
6100
6101/**
6102 * xmlParseTry:
6103 * @ctxt: an XML parser context
6104 *
6105 * Try to progress on parsing
6106 *
6107 * Returns zero if no parsing was possible
6108 */
6109int
6110xmlParseTry(xmlParserCtxtPtr ctxt) {
6111 int ret = 0;
6112
6113 while (1) {
6114 switch (ctxt->instate) {
6115 case XML_PARSER_EOF:
6116 return(0);
6117 case XML_PARSER_PROLOG:
6118 case XML_PARSER_CONTENT:
6119 case XML_PARSER_ENTITY_DECL:
6120 case XML_PARSER_ENTITY_VALUE:
6121 case XML_PARSER_ATTRIBUTE_VALUE:
6122 case XML_PARSER_DTD:
6123 case XML_PARSER_EPILOG:
6124 case XML_PARSER_COMMENT:
6125 case XML_PARSER_CDATA_SECTION:
Daniel Veillarda819dac1999-11-24 18:04:22 +00006126 break;
Daniel Veillard7f858501999-11-17 17:32:38 +00006127 }
6128 }
6129 return(ret);
6130}
6131
6132/**
6133 * xmlParseChunk:
6134 * @ctxt: an XML parser context
6135 * @chunk: an char array
6136 * @size: the size in byte of the chunk
6137 * @terminate: last chunk indicator
6138 *
6139 * Parse a Chunk of memory
6140 *
6141 * Returns zero if no error, the xmlParserErrors otherwise.
6142 */
6143xmlParserErrors
6144xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
6145 int terminate) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00006146 if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
6147 (ctxt->input->buf != NULL)) {
6148 xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
Daniel Veillard7f858501999-11-17 17:32:38 +00006149 }
6150 return((xmlParserErrors) ctxt->errNo);
6151}
6152
6153/************************************************************************
6154 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00006155 * I/O front end functions to the parser *
6156 * *
6157 ************************************************************************/
6158
Daniel Veillard11e00581998-10-24 18:27:49 +00006159/**
Daniel Veillardbe70ff71999-07-05 16:50:46 +00006160 * xmlCreateDocParserCtxt :
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006161 * @cur: a pointer to an array of xmlChar
Daniel Veillardd692aa41999-02-28 21:54:31 +00006162 *
6163 * Create a parser context for an XML in-memory document.
6164 *
6165 * Returns the new parser context or NULL
6166 */
6167xmlParserCtxtPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006168xmlCreateDocParserCtxt(xmlChar *cur) {
Daniel Veillardd692aa41999-02-28 21:54:31 +00006169 xmlParserCtxtPtr ctxt;
6170 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00006171 xmlCharEncoding enc;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006172
Daniel Veillardb05deb71999-08-10 19:04:08 +00006173 ctxt = xmlNewParserCtxt();
Daniel Veillardd692aa41999-02-28 21:54:31 +00006174 if (ctxt == NULL) {
Daniel Veillardd692aa41999-02-28 21:54:31 +00006175 return(NULL);
6176 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006177 input = xmlNewInputStream(ctxt);
Daniel Veillardd692aa41999-02-28 21:54:31 +00006178 if (input == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00006179 xmlFreeParserCtxt(ctxt);
Daniel Veillardd692aa41999-02-28 21:54:31 +00006180 return(NULL);
6181 }
6182
Daniel Veillard27d88741999-05-29 11:51:49 +00006183 /*
6184 * plug some encoding conversion routines here. !!!
6185 */
6186 enc = xmlDetectCharEncoding(cur);
6187 xmlSwitchEncoding(ctxt, enc);
6188
Daniel Veillardd692aa41999-02-28 21:54:31 +00006189 input->base = cur;
6190 input->cur = cur;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006191
6192 inputPush(ctxt, input);
6193 return(ctxt);
6194}
6195
6196/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006197 * xmlSAXParseDoc :
6198 * @sax: the SAX handler block
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006199 * @cur: a pointer to an array of xmlChar
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006200 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
6201 * documents
Daniel Veillard11e00581998-10-24 18:27:49 +00006202 *
6203 * parse an XML in-memory document and build a tree.
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006204 * It use the given SAX function block to handle the parsing callback.
6205 * If sax is NULL, fallback to the default DOM tree building routines.
Daniel Veillard11e00581998-10-24 18:27:49 +00006206 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006207 * Returns the resulting document tree
Daniel Veillard260a68f1998-08-13 03:39:55 +00006208 */
6209
Daniel Veillard1e346af1999-02-22 10:33:01 +00006210xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006211xmlSAXParseDoc(xmlSAXHandlerPtr sax, xmlChar *cur, int recovery) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006212 xmlDocPtr ret;
6213 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006214
6215 if (cur == NULL) return(NULL);
6216
Daniel Veillardd692aa41999-02-28 21:54:31 +00006217
6218 ctxt = xmlCreateDocParserCtxt(cur);
6219 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00006220 if (sax != NULL) {
6221 ctxt->sax = sax;
6222 ctxt->userData = NULL;
6223 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006224
6225 xmlParseDocument(ctxt);
Daniel Veillard517752b1999-04-05 12:20:10 +00006226 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006227 else {
6228 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00006229 xmlFreeDoc(ctxt->myDoc);
6230 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006231 }
Daniel Veillard97fea181999-06-26 23:07:37 +00006232 if (sax != NULL)
6233 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006234 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006235
6236 return(ret);
6237}
6238
Daniel Veillard11e00581998-10-24 18:27:49 +00006239/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006240 * xmlParseDoc :
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006241 * @cur: a pointer to an array of xmlChar
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006242 *
6243 * parse an XML in-memory document and build a tree.
6244 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006245 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006246 */
6247
Daniel Veillard1e346af1999-02-22 10:33:01 +00006248xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006249xmlParseDoc(xmlChar *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006250 return(xmlSAXParseDoc(NULL, cur, 0));
6251}
6252
6253/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00006254 * xmlSAXParseDTD :
6255 * @sax: the SAX handler block
6256 * @ExternalID: a NAME* containing the External ID of the DTD
6257 * @SystemID: a NAME* containing the URL to the DTD
6258 *
6259 * Load and parse an external subset.
6260 *
6261 * Returns the resulting xmlDtdPtr or NULL in case of error.
6262 */
6263
6264xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006265xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID,
6266 const xmlChar *SystemID) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00006267 xmlDtdPtr ret = NULL;
6268 xmlParserCtxtPtr ctxt;
Daniel Veillard14fff061999-06-22 21:49:07 +00006269 xmlParserInputPtr input = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00006270 xmlCharEncoding enc;
6271
6272 if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL);
6273
Daniel Veillardb05deb71999-08-10 19:04:08 +00006274 ctxt = xmlNewParserCtxt();
Daniel Veillard011b63c1999-06-02 17:44:04 +00006275 if (ctxt == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00006276 return(NULL);
6277 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00006278
6279 /*
6280 * Set-up the SAX context
6281 */
6282 if (ctxt == NULL) return(NULL);
6283 if (sax != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006284 if (ctxt->sax != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00006285 xmlFree(ctxt->sax);
Daniel Veillard011b63c1999-06-02 17:44:04 +00006286 ctxt->sax = sax;
6287 ctxt->userData = NULL;
6288 }
6289
6290 /*
6291 * Ask the Entity resolver to load the damn thing
6292 */
6293
6294 if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
6295 input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, SystemID);
6296 if (input == NULL) {
Daniel Veillard97fea181999-06-26 23:07:37 +00006297 if (sax != NULL) ctxt->sax = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00006298 xmlFreeParserCtxt(ctxt);
6299 return(NULL);
6300 }
6301
6302 /*
6303 * plug some encoding conversion routines here. !!!
6304 */
6305 xmlPushInput(ctxt, input);
6306 enc = xmlDetectCharEncoding(ctxt->input->cur);
6307 xmlSwitchEncoding(ctxt, enc);
6308
Daniel Veillardb05deb71999-08-10 19:04:08 +00006309 if (input->filename == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00006310 input->filename = (char *) xmlStrdup(SystemID); /* !!!!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00006311 input->line = 1;
6312 input->col = 1;
6313 input->base = ctxt->input->cur;
6314 input->cur = ctxt->input->cur;
6315 input->free = NULL;
6316
6317 /*
6318 * let's parse that entity knowing it's an external subset.
6319 */
6320 xmlParseExternalSubset(ctxt, ExternalID, SystemID);
6321
6322 if (ctxt->myDoc != NULL) {
6323 if (ctxt->wellFormed) {
6324 ret = ctxt->myDoc->intSubset;
6325 ctxt->myDoc->intSubset = NULL;
6326 } else {
6327 ret = NULL;
6328 }
6329 xmlFreeDoc(ctxt->myDoc);
6330 ctxt->myDoc = NULL;
6331 }
Daniel Veillard97fea181999-06-26 23:07:37 +00006332 if (sax != NULL) ctxt->sax = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00006333 xmlFreeParserCtxt(ctxt);
6334
6335 return(ret);
6336}
6337
6338/**
6339 * xmlParseDTD :
6340 * @ExternalID: a NAME* containing the External ID of the DTD
6341 * @SystemID: a NAME* containing the URL to the DTD
6342 *
6343 * Load and parse an external subset.
6344 *
6345 * Returns the resulting xmlDtdPtr or NULL in case of error.
6346 */
6347
6348xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006349xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00006350 return(xmlSAXParseDTD(NULL, ExternalID, SystemID));
6351}
6352
6353/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006354 * xmlRecoverDoc :
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006355 * @cur: a pointer to an array of xmlChar
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006356 *
6357 * parse an XML in-memory document and build a tree.
6358 * In the case the document is not Well Formed, a tree is built anyway
6359 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006360 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006361 */
6362
Daniel Veillard1e346af1999-02-22 10:33:01 +00006363xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006364xmlRecoverDoc(xmlChar *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006365 return(xmlSAXParseDoc(NULL, cur, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006366}
6367
6368/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00006369 * xmlCreateFileParserCtxt :
Daniel Veillard11e00581998-10-24 18:27:49 +00006370 * @filename: the filename
6371 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006372 * Create a parser context for a file content.
6373 * Automatic support for ZLIB/Compress compressed document is provided
6374 * by default if found at compile-time.
Daniel Veillard11e00581998-10-24 18:27:49 +00006375 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006376 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00006377 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00006378xmlParserCtxtPtr
6379xmlCreateFileParserCtxt(const char *filename)
6380{
6381 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006382 xmlParserInputPtr inputStream;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006383 xmlParserInputBufferPtr buf;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006384 char *directory = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006385
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006386 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
6387 if (buf == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006388
Daniel Veillardb05deb71999-08-10 19:04:08 +00006389 ctxt = xmlNewParserCtxt();
Daniel Veillard260a68f1998-08-13 03:39:55 +00006390 if (ctxt == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006391 return(NULL);
6392 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006393
6394 inputStream = xmlNewInputStream(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006395 if (inputStream == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00006396 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006397 return(NULL);
6398 }
6399
Daniel Veillard6454aec1999-09-02 22:04:43 +00006400 inputStream->filename = xmlMemStrdup(filename);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006401 inputStream->buf = buf;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006402 inputStream->base = inputStream->buf->buffer->content;
6403 inputStream->cur = inputStream->buf->buffer->content;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006404
6405 inputPush(ctxt, inputStream);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006406 if ((ctxt->directory == NULL) && (directory == NULL))
6407 directory = xmlParserGetDirectory(filename);
6408 if ((ctxt->directory == NULL) && (directory != NULL))
6409 ctxt->directory = directory;
6410
Daniel Veillardd692aa41999-02-28 21:54:31 +00006411 return(ctxt);
6412}
6413
6414/**
6415 * xmlSAXParseFile :
6416 * @sax: the SAX handler block
6417 * @filename: the filename
6418 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
6419 * documents
6420 *
6421 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
6422 * compressed document is provided by default if found at compile-time.
6423 * It use the given SAX function block to handle the parsing callback.
6424 * If sax is NULL, fallback to the default DOM tree building routines.
6425 *
6426 * Returns the resulting document tree
6427 */
6428
Daniel Veillard011b63c1999-06-02 17:44:04 +00006429xmlDocPtr
6430xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
Daniel Veillardd692aa41999-02-28 21:54:31 +00006431 int recovery) {
6432 xmlDocPtr ret;
6433 xmlParserCtxtPtr ctxt;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006434 char *directory = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006435
6436 ctxt = xmlCreateFileParserCtxt(filename);
6437 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00006438 if (sax != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006439 if (ctxt->sax != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00006440 xmlFree(ctxt->sax);
Daniel Veillard27d88741999-05-29 11:51:49 +00006441 ctxt->sax = sax;
6442 ctxt->userData = NULL;
6443 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006444
Daniel Veillardb05deb71999-08-10 19:04:08 +00006445 if ((ctxt->directory == NULL) && (directory == NULL))
6446 directory = xmlParserGetDirectory(filename);
6447 if ((ctxt->directory == NULL) && (directory != NULL))
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006448 ctxt->directory = (char *) xmlStrdup((xmlChar *) directory); /* !!!!!!! */
Daniel Veillardb05deb71999-08-10 19:04:08 +00006449
Daniel Veillard260a68f1998-08-13 03:39:55 +00006450 xmlParseDocument(ctxt);
6451
Daniel Veillard517752b1999-04-05 12:20:10 +00006452 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006453 else {
6454 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00006455 xmlFreeDoc(ctxt->myDoc);
6456 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006457 }
Daniel Veillard97fea181999-06-26 23:07:37 +00006458 if (sax != NULL)
6459 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006460 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006461
6462 return(ret);
6463}
6464
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006465/**
6466 * xmlParseFile :
6467 * @filename: the filename
6468 *
6469 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
6470 * compressed document is provided by default if found at compile-time.
6471 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006472 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006473 */
6474
Daniel Veillard011b63c1999-06-02 17:44:04 +00006475xmlDocPtr
6476xmlParseFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006477 return(xmlSAXParseFile(NULL, filename, 0));
6478}
6479
6480/**
6481 * xmlRecoverFile :
6482 * @filename: the filename
6483 *
6484 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
6485 * compressed document is provided by default if found at compile-time.
6486 * In the case the document is not Well Formed, a tree is built anyway
6487 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006488 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006489 */
6490
Daniel Veillard011b63c1999-06-02 17:44:04 +00006491xmlDocPtr
6492xmlRecoverFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006493 return(xmlSAXParseFile(NULL, filename, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006494}
Daniel Veillard260a68f1998-08-13 03:39:55 +00006495
Daniel Veillard11e00581998-10-24 18:27:49 +00006496/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00006497 * xmlCreateMemoryParserCtxt :
Daniel Veillard1e346af1999-02-22 10:33:01 +00006498 * @buffer: an pointer to a char array
Daniel Veillard51e3b151999-11-12 17:02:31 +00006499 * @size: the size of the array
Daniel Veillard11e00581998-10-24 18:27:49 +00006500 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006501 * Create a parser context for an XML in-memory document.
Daniel Veillard11e00581998-10-24 18:27:49 +00006502 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006503 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00006504 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00006505xmlParserCtxtPtr
6506xmlCreateMemoryParserCtxt(char *buffer, int size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006507 xmlParserCtxtPtr ctxt;
6508 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00006509 xmlCharEncoding enc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006510
6511 buffer[size - 1] = '\0';
6512
Daniel Veillardb05deb71999-08-10 19:04:08 +00006513 ctxt = xmlNewParserCtxt();
Daniel Veillard260a68f1998-08-13 03:39:55 +00006514 if (ctxt == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006515 return(NULL);
6516 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006517
6518 input = xmlNewInputStream(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006519 if (input == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00006520 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006521 return(NULL);
6522 }
6523
6524 input->filename = NULL;
6525 input->line = 1;
6526 input->col = 1;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006527 input->buf = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006528 input->consumed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006529
6530 /*
Daniel Veillard27d88741999-05-29 11:51:49 +00006531 * plug some encoding conversion routines here. !!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00006532 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00006533 enc = xmlDetectCharEncoding(BAD_CAST buffer);
Daniel Veillard27d88741999-05-29 11:51:49 +00006534 xmlSwitchEncoding(ctxt, enc);
6535
Daniel Veillardb96e6431999-08-29 21:02:19 +00006536 input->base = BAD_CAST buffer;
6537 input->cur = BAD_CAST buffer;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006538 input->free = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006539
6540 inputPush(ctxt, input);
Daniel Veillardd692aa41999-02-28 21:54:31 +00006541 return(ctxt);
6542}
6543
6544/**
6545 * xmlSAXParseMemory :
6546 * @sax: the SAX handler block
6547 * @buffer: an pointer to a char array
Daniel Veillard51e3b151999-11-12 17:02:31 +00006548 * @size: the size of the array
6549 * @recovery: work in recovery mode, i.e. tries to read not Well Formed
Daniel Veillardd692aa41999-02-28 21:54:31 +00006550 * documents
6551 *
6552 * parse an XML in-memory block and use the given SAX function block
6553 * to handle the parsing callback. If sax is NULL, fallback to the default
6554 * DOM tree building routines.
6555 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00006556 * Returns the resulting document tree
6557 */
6558xmlDocPtr
6559xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
6560 xmlDocPtr ret;
6561 xmlParserCtxtPtr ctxt;
6562
6563 ctxt = xmlCreateMemoryParserCtxt(buffer, size);
6564 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00006565 if (sax != NULL) {
6566 ctxt->sax = sax;
6567 ctxt->userData = NULL;
6568 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006569
6570 xmlParseDocument(ctxt);
6571
Daniel Veillard517752b1999-04-05 12:20:10 +00006572 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006573 else {
6574 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00006575 xmlFreeDoc(ctxt->myDoc);
6576 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006577 }
Daniel Veillard97fea181999-06-26 23:07:37 +00006578 if (sax != NULL)
6579 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00006580 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006581
6582 return(ret);
6583}
6584
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006585/**
6586 * xmlParseMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00006587 * @buffer: an pointer to a char array
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006588 * @size: the size of the array
6589 *
6590 * parse an XML in-memory block and build a tree.
6591 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006592 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006593 */
6594
6595xmlDocPtr xmlParseMemory(char *buffer, int size) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006596 return(xmlSAXParseMemory(NULL, buffer, size, 0));
6597}
6598
6599/**
6600 * xmlRecoverMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00006601 * @buffer: an pointer to a char array
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006602 * @size: the size of the array
6603 *
6604 * parse an XML in-memory block and build a tree.
6605 * In the case the document is not Well Formed, a tree is built anyway
6606 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006607 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006608 */
6609
6610xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
6611 return(xmlSAXParseMemory(NULL, buffer, size, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00006612}
Daniel Veillard260a68f1998-08-13 03:39:55 +00006613
Daniel Veillard260a68f1998-08-13 03:39:55 +00006614
Daniel Veillard11e00581998-10-24 18:27:49 +00006615/**
6616 * xmlSetupParserForBuffer:
6617 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006618 * @buffer: a xmlChar * buffer
Daniel Veillard11e00581998-10-24 18:27:49 +00006619 * @filename: a file name
6620 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00006621 * Setup the parser context to parse a new buffer; Clears any prior
6622 * contents from the parser context. The buffer parameter must not be
6623 * NULL, but the filename parameter can be
6624 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006625void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006626xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer,
Daniel Veillard260a68f1998-08-13 03:39:55 +00006627 const char* filename)
6628{
Daniel Veillardb05deb71999-08-10 19:04:08 +00006629 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006630
Daniel Veillardb05deb71999-08-10 19:04:08 +00006631 input = xmlNewInputStream(ctxt);
6632 if (input == NULL) {
6633 perror("malloc");
Daniel Veillard6454aec1999-09-02 22:04:43 +00006634 xmlFree(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006635 exit(1);
6636 }
6637
6638 xmlClearParserCtxt(ctxt);
6639 if (filename != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00006640 input->filename = xmlMemStrdup(filename);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006641 input->base = buffer;
6642 input->cur = buffer;
6643 inputPush(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006644}
6645
Daniel Veillard7a66ee61999-09-26 11:31:02 +00006646/**
6647 * xmlSAXUserParseFile:
6648 * @sax: a SAX handler
6649 * @user_data: The user data returned on SAX callbacks
6650 * @filename: a file name
6651 *
6652 * parse an XML file and call the given SAX handler routines.
6653 * Automatic support for ZLIB/Compress compressed document is provided
6654 *
6655 * Returns 0 in case of success or a error number otherwise
6656 */
Daniel Veillard11a48ec1999-11-23 10:40:46 +00006657int
6658xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data,
6659 const char *filename) {
Daniel Veillard7a66ee61999-09-26 11:31:02 +00006660 int ret = 0;
6661 xmlParserCtxtPtr ctxt;
6662
6663 ctxt = xmlCreateFileParserCtxt(filename);
6664 if (ctxt == NULL) return -1;
6665 ctxt->sax = sax;
6666 ctxt->userData = user_data;
6667
6668 xmlParseDocument(ctxt);
6669
6670 if (ctxt->wellFormed)
6671 ret = 0;
6672 else {
6673 if (ctxt->errNo != 0)
6674 ret = ctxt->errNo;
6675 else
6676 ret = -1;
6677 }
6678 if (sax != NULL)
6679 ctxt->sax = NULL;
6680 xmlFreeParserCtxt(ctxt);
6681
6682 return ret;
6683}
6684
6685/**
6686 * xmlSAXUserParseMemory:
6687 * @sax: a SAX handler
6688 * @user_data: The user data returned on SAX callbacks
6689 * @buffer: an in-memory XML document input
Daniel Veillard51e3b151999-11-12 17:02:31 +00006690 * @size: the length of the XML document in bytes
Daniel Veillard7a66ee61999-09-26 11:31:02 +00006691 *
6692 * A better SAX parsing routine.
6693 * parse an XML in-memory buffer and call the given SAX handler routines.
6694 *
6695 * Returns 0 in case of success or a error number otherwise
6696 */
6697int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data,
6698 char *buffer, int size) {
6699 int ret = 0;
6700 xmlParserCtxtPtr ctxt;
6701
6702 ctxt = xmlCreateMemoryParserCtxt(buffer, size);
6703 if (ctxt == NULL) return -1;
6704 ctxt->sax = sax;
6705 ctxt->userData = user_data;
6706
6707 xmlParseDocument(ctxt);
6708
6709 if (ctxt->wellFormed)
6710 ret = 0;
6711 else {
6712 if (ctxt->errNo != 0)
6713 ret = ctxt->errNo;
6714 else
6715 ret = -1;
6716 }
6717 if (sax != NULL)
6718 ctxt->sax = NULL;
6719 xmlFreeParserCtxt(ctxt);
6720
6721 return ret;
6722}
6723
Daniel Veillard260a68f1998-08-13 03:39:55 +00006724
Daniel Veillardb05deb71999-08-10 19:04:08 +00006725/************************************************************************
6726 * *
Daniel Veillard51e3b151999-11-12 17:02:31 +00006727 * Miscellaneous *
Daniel Veillardb05deb71999-08-10 19:04:08 +00006728 * *
6729 ************************************************************************/
6730
Daniel Veillarda819dac1999-11-24 18:04:22 +00006731/**
6732 * xmlCleanupParser:
6733 *
6734 * Cleanup function for the XML parser. It tries to reclaim all
6735 * parsing related global memory allocated for the parser processing.
6736 * It doesn't deallocate any document related memory. Calling this
6737 * function should not prevent reusing the parser.
6738 */
6739
6740void
6741xmlCleanupParser(void) {
6742 xmlCleanupCharEncodingHandlers();
6743}
Daniel Veillardb05deb71999-08-10 19:04:08 +00006744
Daniel Veillard11e00581998-10-24 18:27:49 +00006745/**
6746 * xmlParserFindNodeInfo:
6747 * @ctxt: an XML parser context
6748 * @node: an XML node within the tree
6749 *
6750 * Find the parser node info struct for a given node
6751 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006752 * Returns an xmlParserNodeInfo block pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00006753 */
6754const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
6755 const xmlNode* node)
6756{
6757 unsigned long pos;
6758
6759 /* Find position where node should be at */
6760 pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
6761 if ( ctx->node_seq.buffer[pos].node == node )
6762 return &ctx->node_seq.buffer[pos];
6763 else
6764 return NULL;
6765}
6766
6767
Daniel Veillard11e00581998-10-24 18:27:49 +00006768/**
6769 * xmlInitNodeInfoSeq :
6770 * @seq: a node info sequence pointer
6771 *
6772 * -- Initialize (set to initial state) node info sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00006773 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006774void
6775xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00006776{
6777 seq->length = 0;
6778 seq->maximum = 0;
6779 seq->buffer = NULL;
6780}
6781
Daniel Veillard11e00581998-10-24 18:27:49 +00006782/**
6783 * xmlClearNodeInfoSeq :
6784 * @seq: a node info sequence pointer
6785 *
6786 * -- Clear (release memory and reinitialize) node
Daniel Veillard260a68f1998-08-13 03:39:55 +00006787 * info sequence
6788 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006789void
6790xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00006791{
6792 if ( seq->buffer != NULL )
Daniel Veillard6454aec1999-09-02 22:04:43 +00006793 xmlFree(seq->buffer);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006794 xmlInitNodeInfoSeq(seq);
6795}
6796
6797
Daniel Veillard11e00581998-10-24 18:27:49 +00006798/**
6799 * xmlParserFindNodeInfoIndex:
6800 * @seq: a node info sequence pointer
6801 * @node: an XML node pointer
6802 *
6803 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00006804 * xmlParserFindNodeInfoIndex : Find the index that the info record for
6805 * the given node is or should be at in a sorted sequence
Daniel Veillard1164e751999-02-16 16:29:17 +00006806 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006807 * Returns a long indicating the position of the record
Daniel Veillard260a68f1998-08-13 03:39:55 +00006808 */
6809unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
6810 const xmlNode* node)
6811{
6812 unsigned long upper, lower, middle;
6813 int found = 0;
6814
6815 /* Do a binary search for the key */
6816 lower = 1;
6817 upper = seq->length;
6818 middle = 0;
6819 while ( lower <= upper && !found) {
6820 middle = lower + (upper - lower) / 2;
6821 if ( node == seq->buffer[middle - 1].node )
6822 found = 1;
6823 else if ( node < seq->buffer[middle - 1].node )
6824 upper = middle - 1;
6825 else
6826 lower = middle + 1;
6827 }
6828
6829 /* Return position */
6830 if ( middle == 0 || seq->buffer[middle - 1].node < node )
6831 return middle;
6832 else
6833 return middle - 1;
6834}
6835
6836
Daniel Veillard11e00581998-10-24 18:27:49 +00006837/**
6838 * xmlParserAddNodeInfo:
6839 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00006840 * @info: a node info sequence pointer
Daniel Veillard11e00581998-10-24 18:27:49 +00006841 *
6842 * Insert node info record into the sorted sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00006843 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006844void
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006845xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
Daniel Veillard1e346af1999-02-22 10:33:01 +00006846 const xmlParserNodeInfo* info)
Daniel Veillard260a68f1998-08-13 03:39:55 +00006847{
6848 unsigned long pos;
6849 static unsigned int block_size = 5;
6850
6851 /* Find pos and check to see if node is already in the sequence */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006852 pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
6853 if ( pos < ctxt->node_seq.length
6854 && ctxt->node_seq.buffer[pos].node == info->node ) {
6855 ctxt->node_seq.buffer[pos] = *info;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006856 }
6857
6858 /* Otherwise, we need to add new node to buffer */
6859 else {
6860 /* Expand buffer by 5 if needed */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006861 if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006862 xmlParserNodeInfo* tmp_buffer;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006863 unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
6864 *(ctxt->node_seq.maximum + block_size));
Daniel Veillard260a68f1998-08-13 03:39:55 +00006865
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006866 if ( ctxt->node_seq.buffer == NULL )
Daniel Veillard6454aec1999-09-02 22:04:43 +00006867 tmp_buffer = (xmlParserNodeInfo*) xmlMalloc(byte_size);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006868 else
Daniel Veillard6454aec1999-09-02 22:04:43 +00006869 tmp_buffer = (xmlParserNodeInfo*) xmlRealloc(ctxt->node_seq.buffer, byte_size);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006870
6871 if ( tmp_buffer == NULL ) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006872 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006873 ctxt->sax->error(ctxt->userData, "Out of memory\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006874 ctxt->errNo = XML_ERR_NO_MEMORY;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006875 return;
6876 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006877 ctxt->node_seq.buffer = tmp_buffer;
6878 ctxt->node_seq.maximum += block_size;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006879 }
6880
6881 /* If position is not at end, move elements out of the way */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006882 if ( pos != ctxt->node_seq.length ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006883 unsigned long i;
6884
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006885 for ( i = ctxt->node_seq.length; i > pos; i-- )
6886 ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
Daniel Veillard260a68f1998-08-13 03:39:55 +00006887 }
6888
6889 /* Copy element and increase length */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006890 ctxt->node_seq.buffer[pos] = *info;
6891 ctxt->node_seq.length++;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006892 }
6893}
Daniel Veillard011b63c1999-06-02 17:44:04 +00006894
6895
Daniel Veillardb05deb71999-08-10 19:04:08 +00006896/**
6897 * xmlSubstituteEntitiesDefault :
6898 * @val: int 0 or 1
6899 *
6900 * Set and return the previous value for default entity support.
6901 * Initially the parser always keep entity references instead of substituting
6902 * entity values in the output. This function has to be used to change the
6903 * default parser behaviour
6904 * SAX::subtituteEntities() has to be used for changing that on a file by
6905 * file basis.
6906 *
6907 * Returns the last value for 0 for no substitution, 1 for substitution.
6908 */
6909
6910int
6911xmlSubstituteEntitiesDefault(int val) {
6912 int old = xmlSubstituteEntitiesDefaultValue;
6913
6914 xmlSubstituteEntitiesDefaultValue = val;
6915 return(old);
6916}
6917