blob: 424b3f838103a93c48d3812900ef901a0b7df9dd [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
Daniel Veillard3c558c31999-12-22 11:30:41 +000010#include "win32config.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000011#else
Daniel Veillard7f7d1111999-09-22 09:46:25 +000012#include "config.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000013#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000014
Daniel Veillard260a68f1998-08-13 03:39:55 +000015#include <stdio.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000016#include <string.h> /* for memset() only */
Daniel Veillard7f7d1111999-09-22 09:46:25 +000017#ifdef HAVE_CTYPE_H
18#include <ctype.h>
19#endif
20#ifdef HAVE_STDLIB_H
Seth Alvese7f12e61998-10-01 20:51:15 +000021#include <stdlib.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000022#endif
23#ifdef HAVE_SYS_STAT_H
Daniel Veillard260a68f1998-08-13 03:39:55 +000024#include <sys/stat.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000025#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +000026#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_ZLIB_H
33#include <zlib.h>
34#endif
35
Daniel Veillard6454aec1999-09-02 22:04:43 +000036#include "xmlmemory.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000037#include "tree.h"
38#include "parser.h"
39#include "entities.h"
Daniel Veillard27d88741999-05-29 11:51:49 +000040#include "encoding.h"
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000041#include "valid.h"
Daniel Veillard1e346af1999-02-22 10:33:01 +000042#include "parserInternals.h"
Daniel Veillarde2d034d1999-07-27 19:52:06 +000043#include "xmlIO.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000044#include "xml-error.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000045
Daniel Veillarddbfd6411999-12-28 16:35:14 +000046#define XML_PARSER_BIG_BUFFER_SIZE 1000
47#define XML_PARSER_BUFFER_SIZE 100
48
Daniel Veillard14fff061999-06-22 21:49:07 +000049const char *xmlParserVersion = LIBXML_VERSION;
50
Daniel Veillard3c558c31999-12-22 11:30:41 +000051/*
52 * List of XML prefixed PI allowed by W3C specs
53 */
54
55const char *xmlW3CPIs[] = {
56 "xml-stylesheet",
57 NULL
58};
Daniel Veillarde2d034d1999-07-27 19:52:06 +000059
60/************************************************************************
61 * *
62 * Input handling functions for progressive parsing *
63 * *
64 ************************************************************************/
65
66/* #define DEBUG_INPUT */
Daniel Veillarddbfd6411999-12-28 16:35:14 +000067/* #define DEBUG_STACK */
68/* #define DEBUG_PUSH */
69
Daniel Veillarde2d034d1999-07-27 19:52:06 +000070
Daniel Veillardb05deb71999-08-10 19:04:08 +000071#define INPUT_CHUNK 250
72/* we need to keep enough input to show errors in context */
73#define LINE_LEN 80
Daniel Veillarde2d034d1999-07-27 19:52:06 +000074
75#ifdef DEBUG_INPUT
76#define CHECK_BUFFER(in) check_buffer(in)
Daniel Veillarde2d034d1999-07-27 19:52:06 +000077
78void check_buffer(xmlParserInputPtr in) {
79 if (in->base != in->buf->buffer->content) {
80 fprintf(stderr, "xmlParserInput: base mismatch problem\n");
81 }
82 if (in->cur < in->base) {
83 fprintf(stderr, "xmlParserInput: cur < base problem\n");
84 }
85 if (in->cur > in->base + in->buf->buffer->use) {
86 fprintf(stderr, "xmlParserInput: cur > base + use problem\n");
87 }
88 fprintf(stderr,"buffer %x : content %x, cur %d, use %d, size %d\n",
89 (int) in, (int) in->buf->buffer->content, in->cur - in->base,
90 in->buf->buffer->use, in->buf->buffer->size);
91}
92
Daniel Veillardb05deb71999-08-10 19:04:08 +000093#else
94#define CHECK_BUFFER(in)
95#endif
96
Daniel Veillarde2d034d1999-07-27 19:52:06 +000097
98/**
99 * xmlParserInputRead:
100 * @in: an XML parser input
101 * @len: an indicative size for the lookahead
102 *
103 * This function refresh the input for the parser. It doesn't try to
104 * preserve pointers to the input buffer, and discard already read data
105 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000106 * Returns the number of xmlChars read, or -1 in case of error, 0 indicate the
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000107 * end of this entity
108 */
109int
110xmlParserInputRead(xmlParserInputPtr in, int len) {
111 int ret;
112 int used;
113 int index;
114
115#ifdef DEBUG_INPUT
116 fprintf(stderr, "Read\n");
117#endif
118 if (in->buf == NULL) return(-1);
119 if (in->base == NULL) return(-1);
120 if (in->cur == NULL) return(-1);
121 if (in->buf->buffer == NULL) return(-1);
122
123 CHECK_BUFFER(in);
124
125 used = in->cur - in->buf->buffer->content;
126 ret = xmlBufferShrink(in->buf->buffer, used);
127 if (ret > 0) {
128 in->cur -= ret;
129 in->consumed += ret;
130 }
131 ret = xmlParserInputBufferRead(in->buf, len);
132 if (in->base != in->buf->buffer->content) {
133 /*
134 * the buffer has been realloced
135 */
136 index = in->cur - in->base;
137 in->base = in->buf->buffer->content;
138 in->cur = &in->buf->buffer->content[index];
139 }
140
141 CHECK_BUFFER(in);
142
143 return(ret);
144}
145
146/**
147 * xmlParserInputGrow:
148 * @in: an XML parser input
149 * @len: an indicative size for the lookahead
150 *
151 * This function increase the input for the parser. It tries to
152 * preserve pointers to the input buffer, and keep already read data
153 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000154 * Returns the number of xmlChars read, or -1 in case of error, 0 indicate the
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000155 * end of this entity
156 */
157int
158xmlParserInputGrow(xmlParserInputPtr in, int len) {
159 int ret;
160 int index;
161
162#ifdef DEBUG_INPUT
163 fprintf(stderr, "Grow\n");
164#endif
165 if (in->buf == NULL) return(-1);
166 if (in->base == NULL) return(-1);
167 if (in->cur == NULL) return(-1);
168 if (in->buf->buffer == NULL) return(-1);
169
170 CHECK_BUFFER(in);
171
172 index = in->cur - in->base;
173 if (in->buf->buffer->use > index + INPUT_CHUNK) {
174
175 CHECK_BUFFER(in);
176
177 return(0);
178 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000179 if ((in->buf->netIO != NULL) || (in->buf->file != NULL) ||
180#ifdef HAVE_ZLIB_H
181 (in->buf->gzfile != NULL) ||
182#endif
183 (in->buf->fd >= 0))
184 ret = xmlParserInputBufferGrow(in->buf, len);
185 else
186 return(0);
Daniel Veillard10a2c651999-12-12 13:03:50 +0000187
188 /*
189 * NOTE : in->base may be a "dandling" i.e. freed pointer in this
190 * block, but we use it really as an integer to do some
191 * pointer arithmetic. Insure will raise it as a bug but in
192 * that specific case, that's not !
193 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000194 if (in->base != in->buf->buffer->content) {
195 /*
196 * the buffer has been realloced
197 */
198 index = in->cur - in->base;
199 in->base = in->buf->buffer->content;
200 in->cur = &in->buf->buffer->content[index];
201 }
202
203 CHECK_BUFFER(in);
204
205 return(ret);
206}
207
208/**
209 * xmlParserInputShrink:
210 * @in: an XML parser input
211 *
212 * This function removes used input for the parser.
213 */
214void
215xmlParserInputShrink(xmlParserInputPtr in) {
216 int used;
217 int ret;
218 int index;
219
220#ifdef DEBUG_INPUT
221 fprintf(stderr, "Shrink\n");
222#endif
223 if (in->buf == NULL) return;
224 if (in->base == NULL) return;
225 if (in->cur == NULL) return;
226 if (in->buf->buffer == NULL) return;
227
228 CHECK_BUFFER(in);
229
230 used = in->cur - in->buf->buffer->content;
231 if (used > INPUT_CHUNK) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000232 ret = xmlBufferShrink(in->buf->buffer, used - LINE_LEN);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000233 if (ret > 0) {
234 in->cur -= ret;
235 in->consumed += ret;
236 }
237 }
238
239 CHECK_BUFFER(in);
240
241 if (in->buf->buffer->use > INPUT_CHUNK) {
242 return;
243 }
244 xmlParserInputBufferRead(in->buf, 2 * INPUT_CHUNK);
245 if (in->base != in->buf->buffer->content) {
246 /*
247 * the buffer has been realloced
248 */
249 index = in->cur - in->base;
250 in->base = in->buf->buffer->content;
251 in->cur = &in->buf->buffer->content[index];
252 }
253
254 CHECK_BUFFER(in);
255}
256
Daniel Veillard260a68f1998-08-13 03:39:55 +0000257/************************************************************************
258 * *
259 * Parser stacks related functions and macros *
260 * *
261 ************************************************************************/
Daniel Veillard011b63c1999-06-02 17:44:04 +0000262
263int xmlSubstituteEntitiesDefaultValue = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000264int xmlDoValidityCheckingDefaultValue = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000265xmlEntityPtr xmlParseStringEntityRef(xmlParserCtxtPtr ctxt,
266 const xmlChar ** str);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000267
Daniel Veillard260a68f1998-08-13 03:39:55 +0000268/*
269 * Generic function for accessing stacks in the Parser Context
270 */
271
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000272#define PUSH_AND_POP(scope, type, name) \
273scope int name##Push(xmlParserCtxtPtr ctxt, type value) { \
Daniel Veillard260a68f1998-08-13 03:39:55 +0000274 if (ctxt->name##Nr >= ctxt->name##Max) { \
275 ctxt->name##Max *= 2; \
Daniel Veillard6454aec1999-09-02 22:04:43 +0000276 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard260a68f1998-08-13 03:39:55 +0000277 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
278 if (ctxt->name##Tab == NULL) { \
279 fprintf(stderr, "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000280 return(0); \
Daniel Veillard260a68f1998-08-13 03:39:55 +0000281 } \
282 } \
283 ctxt->name##Tab[ctxt->name##Nr] = value; \
284 ctxt->name = value; \
285 return(ctxt->name##Nr++); \
286} \
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000287scope type name##Pop(xmlParserCtxtPtr ctxt) { \
Daniel Veillardd692aa41999-02-28 21:54:31 +0000288 type ret; \
Daniel Veillard260a68f1998-08-13 03:39:55 +0000289 if (ctxt->name##Nr <= 0) return(0); \
290 ctxt->name##Nr--; \
Daniel Veillardccb09631998-10-27 06:21:04 +0000291 if (ctxt->name##Nr > 0) \
292 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
293 else \
294 ctxt->name = NULL; \
Daniel Veillardd692aa41999-02-28 21:54:31 +0000295 ret = ctxt->name##Tab[ctxt->name##Nr]; \
296 ctxt->name##Tab[ctxt->name##Nr] = 0; \
297 return(ret); \
Daniel Veillard260a68f1998-08-13 03:39:55 +0000298} \
299
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000300PUSH_AND_POP(extern, xmlParserInputPtr, input)
301PUSH_AND_POP(extern, xmlNodePtr, node)
302PUSH_AND_POP(extern, xmlChar*, name)
Daniel Veillard260a68f1998-08-13 03:39:55 +0000303
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000304/*
305 * Macros for accessing the content. Those should be used only by the parser,
306 * and not exported.
307 *
308 * Dirty macros, i.e. one need to make assumption on the context to use them
309 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000310 * CUR_PTR return the current pointer to the xmlChar to be parsed.
311 * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000312 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
313 * in UNICODE mode. This should be used internally by the parser
314 * only to compare to ASCII values otherwise it would break when
315 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000316 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000317 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000318 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000319 * strings within the parser.
320 *
Daniel Veillard011b63c1999-06-02 17:44:04 +0000321 * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000322 *
323 * CURRENT Returns the current char value, with the full decoding of
324 * UTF-8 if we are using this mode. It returns an int.
325 * NEXT Skip to the next character, this does the proper decoding
326 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillard011b63c1999-06-02 17:44:04 +0000327 * COPY(to) copy one char to *to, increment CUR_PTR and to accordingly
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000328 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000329
Daniel Veillardb05deb71999-08-10 19:04:08 +0000330#define CUR (ctxt->token ? ctxt->token : (*ctxt->input->cur))
Daniel Veillard10a2c651999-12-12 13:03:50 +0000331#define SKIP(val) ctxt->nbChars += (val),ctxt->input->cur += (val)
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000332#define NXT(val) ctxt->input->cur[(val)]
333#define CUR_PTR ctxt->input->cur
Daniel Veillardb05deb71999-08-10 19:04:08 +0000334#define SHRINK xmlParserInputShrink(ctxt->input); \
335 if ((*ctxt->input->cur == 0) && \
336 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \
337 xmlPopInput(ctxt)
338
339#define GROW xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \
340 if ((*ctxt->input->cur == 0) && \
341 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \
342 xmlPopInput(ctxt)
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000343
344#define SKIP_BLANKS \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000345 do { \
346 while (IS_BLANK(CUR)) NEXT; \
Daniel Veillard686d6b62000-01-03 11:08:02 +0000347 while ((CUR == 0) && (ctxt->inputNr > 1)) \
348 xmlPopInput(ctxt); \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000349 if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \
350 if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt); \
351 } while (IS_BLANK(CUR));
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000352
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000353#define CURRENT (*ctxt->input->cur)
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000354#define NEXT { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000355 if (ctxt->token != 0) ctxt->token = 0; \
356 else { \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000357 if ((*ctxt->input->cur == 0) && \
358 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) { \
359 xmlPopInput(ctxt); \
360 } else { \
361 if (*(ctxt->input->cur) == '\n') { \
362 ctxt->input->line++; ctxt->input->col = 1; \
363 } else ctxt->input->col++; \
364 ctxt->input->cur++; \
Daniel Veillard10a2c651999-12-12 13:03:50 +0000365 ctxt->nbChars++; \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000366 if (*ctxt->input->cur == 0) \
367 xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000368 } \
369 if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \
370 if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt); \
371}}
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000372
Daniel Veillard260a68f1998-08-13 03:39:55 +0000373
Daniel Veillardb05deb71999-08-10 19:04:08 +0000374/************************************************************************
375 * *
376 * Commodity functions to handle entities processing *
377 * *
378 ************************************************************************/
Daniel Veillard260a68f1998-08-13 03:39:55 +0000379
Daniel Veillard11e00581998-10-24 18:27:49 +0000380/**
381 * xmlPopInput:
382 * @ctxt: an XML parser context
383 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000384 * xmlPopInput: the current input pointed by ctxt->input came to an end
385 * pop it and return the next char.
386 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000387 * Returns the current xmlChar in the parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +0000388 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000389xmlChar
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000390xmlPopInput(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000391 if (ctxt->inputNr == 1) return(0); /* End of main Input */
Daniel Veillardbc50b591999-03-01 12:28:53 +0000392 xmlFreeInputStream(inputPop(ctxt));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000393 if ((*ctxt->input->cur == 0) &&
394 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))
395 return(xmlPopInput(ctxt));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000396 return(CUR);
397}
398
Daniel Veillard11e00581998-10-24 18:27:49 +0000399/**
400 * xmlPushInput:
401 * @ctxt: an XML parser context
402 * @input: an XML parser input fragment (entity, XML fragment ...).
403 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000404 * xmlPushInput: switch to a new input stream which is stacked on top
405 * of the previous one(s).
406 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000407void
408xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000409 if (input == NULL) return;
410 inputPush(ctxt, input);
411}
412
Daniel Veillard11e00581998-10-24 18:27:49 +0000413/**
Daniel Veillardd692aa41999-02-28 21:54:31 +0000414 * xmlFreeInputStream:
Daniel Veillard51e3b151999-11-12 17:02:31 +0000415 * @input: an xmlParserInputPtr
Daniel Veillardd692aa41999-02-28 21:54:31 +0000416 *
417 * Free up an input stream.
418 */
419void
420xmlFreeInputStream(xmlParserInputPtr input) {
421 if (input == NULL) return;
422
Daniel Veillard6454aec1999-09-02 22:04:43 +0000423 if (input->filename != NULL) xmlFree((char *) input->filename);
424 if (input->directory != NULL) xmlFree((char *) input->directory);
Daniel Veillardd692aa41999-02-28 21:54:31 +0000425 if ((input->free != NULL) && (input->base != NULL))
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000426 input->free((xmlChar *) input->base);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000427 if (input->buf != NULL)
428 xmlFreeParserInputBuffer(input->buf);
Daniel Veillardd692aa41999-02-28 21:54:31 +0000429 memset(input, -1, sizeof(xmlParserInput));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000430 xmlFree(input);
Daniel Veillardd692aa41999-02-28 21:54:31 +0000431}
432
433/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000434 * xmlNewInputStream:
435 * @ctxt: an XML parser context
436 *
437 * Create a new input stream structure
438 * Returns the new input stream or NULL
439 */
440xmlParserInputPtr
441xmlNewInputStream(xmlParserCtxtPtr ctxt) {
442 xmlParserInputPtr input;
443
Daniel Veillard6454aec1999-09-02 22:04:43 +0000444 input = (xmlParserInputPtr) xmlMalloc(sizeof(xmlParserInput));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000445 if (input == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000446 ctxt->errNo = XML_ERR_NO_MEMORY;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000447 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000448 ctxt->sax->error(ctxt->userData,
449 "malloc: couldn't allocate a new input stream\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000450 ctxt->errNo = XML_ERR_NO_MEMORY;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000451 return(NULL);
452 }
453 input->filename = NULL;
454 input->directory = NULL;
455 input->base = NULL;
456 input->cur = NULL;
457 input->buf = NULL;
458 input->line = 1;
459 input->col = 1;
460 input->buf = NULL;
461 input->free = NULL;
462 input->consumed = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000463 input->length = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000464 return(input);
465}
466
467/**
Daniel Veillard11e00581998-10-24 18:27:49 +0000468 * xmlNewEntityInputStream:
469 * @ctxt: an XML parser context
470 * @entity: an Entity pointer
471 *
Daniel Veillard011b63c1999-06-02 17:44:04 +0000472 * Create a new input stream based on an xmlEntityPtr
Daniel Veillardb96e6431999-08-29 21:02:19 +0000473 *
474 * Returns the new input stream or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000475 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000476xmlParserInputPtr
477xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000478 xmlParserInputPtr input;
479
480 if (entity == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000481 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000482 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000483 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000484 "internal: xmlNewEntityInputStream entity = NULL\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000485 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillardccb09631998-10-27 06:21:04 +0000486 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000487 }
488 if (entity->content == NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000489 switch (entity->type) {
490 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000491 ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000492 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
493 ctxt->sax->error(ctxt->userData,
494 "xmlNewEntityInputStream unparsed entity !\n");
495 break;
496 case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
497 case XML_EXTERNAL_PARAMETER_ENTITY:
498 return(xmlLoadExternalEntity((char *) entity->SystemID,
Daniel Veillard686d6b62000-01-03 11:08:02 +0000499 (char *) entity->ExternalID, ctxt));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000500 case XML_INTERNAL_GENERAL_ENTITY:
501 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
502 ctxt->sax->error(ctxt->userData,
503 "Internal entity %s without content !\n", entity->name);
504 break;
505 case XML_INTERNAL_PARAMETER_ENTITY:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000506 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000507 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
508 ctxt->sax->error(ctxt->userData,
509 "Internal parameter entity %s without content !\n", entity->name);
510 break;
511 case XML_INTERNAL_PREDEFINED_ENTITY:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000512 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000513 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
514 ctxt->sax->error(ctxt->userData,
515 "Predefined entity %s without content !\n", entity->name);
516 break;
517 }
Daniel Veillardccb09631998-10-27 06:21:04 +0000518 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000519 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000520 input = xmlNewInputStream(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000521 if (input == NULL) {
Daniel Veillardccb09631998-10-27 06:21:04 +0000522 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000523 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000524 input->filename = (char *) entity->SystemID; /* TODO !!! char <- xmlChar */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000525 input->base = entity->content;
526 input->cur = entity->content;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000527 input->length = entity->length;
Daniel Veillardccb09631998-10-27 06:21:04 +0000528 return(input);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000529}
530
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000531/**
532 * xmlNewStringInputStream:
533 * @ctxt: an XML parser context
Daniel Veillardb05deb71999-08-10 19:04:08 +0000534 * @buffer: an memory buffer
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000535 *
536 * Create a new input stream based on a memory buffer.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000537 * Returns the new input stream
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000538 */
539xmlParserInputPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000540xmlNewStringInputStream(xmlParserCtxtPtr ctxt, const xmlChar *buffer) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000541 xmlParserInputPtr input;
542
Daniel Veillardb05deb71999-08-10 19:04:08 +0000543 if (buffer == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000544 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000545 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000546 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000547 "internal: xmlNewStringInputStream string = NULL\n");
548 return(NULL);
549 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000550 input = xmlNewInputStream(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000551 if (input == NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000552 return(NULL);
553 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000554 input->base = buffer;
555 input->cur = buffer;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000556 input->length = xmlStrlen(buffer);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000557 return(input);
558}
559
Daniel Veillard011b63c1999-06-02 17:44:04 +0000560/**
561 * xmlNewInputFromFile:
562 * @ctxt: an XML parser context
563 * @filename: the filename to use as entity
564 *
565 * Create a new input stream based on a file.
566 *
567 * Returns the new input stream or NULL in case of error
568 */
569xmlParserInputPtr
570xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000571 xmlParserInputBufferPtr buf;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000572 xmlParserInputPtr inputStream;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000573 char *directory = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000574
Daniel Veillardb05deb71999-08-10 19:04:08 +0000575 if (ctxt == NULL) return(NULL);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000576 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000577 if (buf == NULL) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000578 char name[XML_PARSER_BIG_BUFFER_SIZE];
Daniel Veillard011b63c1999-06-02 17:44:04 +0000579
Daniel Veillardb05deb71999-08-10 19:04:08 +0000580 if ((ctxt->input != NULL) && (ctxt->input->directory != NULL)) {
581#ifdef WIN32
582 sprintf(name, "%s\\%s", ctxt->input->directory, filename);
583#else
584 sprintf(name, "%s/%s", ctxt->input->directory, filename);
585#endif
586 buf = xmlParserInputBufferCreateFilename(name,
587 XML_CHAR_ENCODING_NONE);
588 if (buf != NULL)
Daniel Veillard686d6b62000-01-03 11:08:02 +0000589 directory = xmlParserGetDirectory(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000590 }
591 if ((buf == NULL) && (ctxt->directory != NULL)) {
592#ifdef WIN32
593 sprintf(name, "%s\\%s", ctxt->directory, filename);
594#else
595 sprintf(name, "%s/%s", ctxt->directory, filename);
596#endif
597 buf = xmlParserInputBufferCreateFilename(name,
598 XML_CHAR_ENCODING_NONE);
599 if (buf != NULL)
Daniel Veillard686d6b62000-01-03 11:08:02 +0000600 directory = xmlParserGetDirectory(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000601 }
602 if (buf == NULL)
603 return(NULL);
604 }
605 if (directory == NULL)
606 directory = xmlParserGetDirectory(filename);
607
608 inputStream = xmlNewInputStream(ctxt);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000609 if (inputStream == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000610 if (directory != NULL) xmlFree((char *) directory);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000611 return(NULL);
612 }
613
Daniel Veillard6454aec1999-09-02 22:04:43 +0000614 inputStream->filename = xmlMemStrdup(filename);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000615 inputStream->directory = directory;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000616 inputStream->buf = buf;
Daniel Veillard011b63c1999-06-02 17:44:04 +0000617
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000618 inputStream->base = inputStream->buf->buffer->content;
619 inputStream->cur = inputStream->buf->buffer->content;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000620 if ((ctxt->directory == NULL) && (directory != NULL))
Daniel Veillard294cbca1999-12-03 13:19:09 +0000621 ctxt->directory = (char *) xmlStrdup((const xmlChar *) directory);
Daniel Veillard011b63c1999-06-02 17:44:04 +0000622 return(inputStream);
623}
624
625/************************************************************************
626 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000627 * Commodity functions to handle parser contexts *
628 * *
629 ************************************************************************/
630
631/**
632 * xmlInitParserCtxt:
633 * @ctxt: an XML parser context
634 *
635 * Initialize a parser context
636 */
637
638void
639xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
640{
641 xmlSAXHandler *sax;
642
Daniel Veillard6454aec1999-09-02 22:04:43 +0000643 sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000644 if (sax == NULL) {
645 fprintf(stderr, "xmlInitParserCtxt: out of memory\n");
646 }
647
648 /* Allocate the Input stack */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000649 ctxt->inputTab = (xmlParserInputPtr *) xmlMalloc(5 * sizeof(xmlParserInputPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000650 ctxt->inputNr = 0;
651 ctxt->inputMax = 5;
652 ctxt->input = NULL;
653 ctxt->version = NULL;
654 ctxt->encoding = NULL;
655 ctxt->standalone = -1;
656 ctxt->hasExternalSubset = 0;
657 ctxt->hasPErefs = 0;
658 ctxt->html = 0;
659 ctxt->external = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000660 ctxt->instate = XML_PARSER_START;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000661 ctxt->token = 0;
662 ctxt->directory = NULL;
663
664 /* Allocate the Node stack */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000665 ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(10 * sizeof(xmlNodePtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000666 ctxt->nodeNr = 0;
667 ctxt->nodeMax = 10;
668 ctxt->node = NULL;
669
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000670 /* Allocate the Name stack */
671 ctxt->nameTab = (xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
672 ctxt->nameNr = 0;
673 ctxt->nameMax = 10;
674 ctxt->name = NULL;
675
Daniel Veillardb05deb71999-08-10 19:04:08 +0000676 if (sax == NULL) ctxt->sax = &xmlDefaultSAXHandler;
677 else {
678 ctxt->sax = sax;
679 memcpy(sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
680 }
681 ctxt->userData = ctxt;
682 ctxt->myDoc = NULL;
683 ctxt->wellFormed = 1;
684 ctxt->valid = 1;
685 ctxt->validate = xmlDoValidityCheckingDefaultValue;
686 ctxt->vctxt.userData = ctxt;
687 ctxt->vctxt.error = xmlParserValidityError;
688 ctxt->vctxt.warning = xmlParserValidityWarning;
689 ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue;
690 ctxt->record_info = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000691 ctxt->nbChars = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000692 ctxt->checkIndex = 0;
693 ctxt->errNo = XML_ERR_OK;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000694 xmlInitNodeInfoSeq(&ctxt->node_seq);
695}
696
697/**
698 * xmlFreeParserCtxt:
699 * @ctxt: an XML parser context
700 *
701 * Free all the memory used by a parser context. However the parsed
702 * document in ctxt->myDoc is not freed.
703 */
704
705void
706xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
707{
708 xmlParserInputPtr input;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000709 xmlChar *oldname;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000710
711 if (ctxt == NULL) return;
712
713 while ((input = inputPop(ctxt)) != NULL) {
714 xmlFreeInputStream(input);
715 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000716 while ((oldname = namePop(ctxt)) != NULL) {
717 xmlFree(oldname);
718 }
719 if (ctxt->nameTab != NULL) xmlFree(ctxt->nameTab);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000720 if (ctxt->nodeTab != NULL) xmlFree(ctxt->nodeTab);
721 if (ctxt->inputTab != NULL) xmlFree(ctxt->inputTab);
722 if (ctxt->version != NULL) xmlFree((char *) ctxt->version);
723 if (ctxt->encoding != NULL) xmlFree((char *) ctxt->encoding);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000724 if ((ctxt->sax != NULL) && (ctxt->sax != &xmlDefaultSAXHandler))
Daniel Veillard6454aec1999-09-02 22:04:43 +0000725 xmlFree(ctxt->sax);
726 if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory);
727 xmlFree(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000728}
729
730/**
731 * xmlNewParserCtxt:
732 *
733 * Allocate and initialize a new parser context.
734 *
735 * Returns the xmlParserCtxtPtr or NULL
736 */
737
738xmlParserCtxtPtr
739xmlNewParserCtxt()
740{
741 xmlParserCtxtPtr ctxt;
742
Daniel Veillard6454aec1999-09-02 22:04:43 +0000743 ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000744 if (ctxt == NULL) {
745 fprintf(stderr, "xmlNewParserCtxt : cannot allocate context\n");
746 perror("malloc");
747 return(NULL);
748 }
749 xmlInitParserCtxt(ctxt);
750 return(ctxt);
751}
752
753/**
754 * xmlClearParserCtxt:
755 * @ctxt: an XML parser context
756 *
757 * Clear (release owned resources) and reinitialize a parser context
758 */
759
760void
761xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
762{
763 xmlClearNodeInfoSeq(&ctxt->node_seq);
764 xmlInitParserCtxt(ctxt);
765}
766
767/************************************************************************
768 * *
Daniel Veillard011b63c1999-06-02 17:44:04 +0000769 * Commodity functions to handle entities *
770 * *
771 ************************************************************************/
772
Daniel Veillardb05deb71999-08-10 19:04:08 +0000773void xmlParserHandleReference(xmlParserCtxtPtr ctxt);
774void xmlParserHandlePEReference(xmlParserCtxtPtr ctxt);
Daniel Veillard10a2c651999-12-12 13:03:50 +0000775xmlEntityPtr xmlParseStringPEReference(xmlParserCtxtPtr ctxt,
776 const xmlChar **str);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000777
778/**
779 * xmlParseCharRef:
780 * @ctxt: an XML parser context
781 *
782 * parse Reference declarations
783 *
784 * [66] CharRef ::= '&#' [0-9]+ ';' |
785 * '&#x' [0-9a-fA-F]+ ';'
786 *
787 * [ WFC: Legal Character ]
788 * Characters referred to using character references must match the
789 * production for Char.
790 *
Daniel Veillard10a2c651999-12-12 13:03:50 +0000791 * Returns the value parsed (as an int), 0 in case of error
Daniel Veillardb05deb71999-08-10 19:04:08 +0000792 */
793int
794xmlParseCharRef(xmlParserCtxtPtr ctxt) {
795 int val = 0;
796
797 if (ctxt->token != 0) {
798 val = ctxt->token;
799 ctxt->token = 0;
800 return(val);
801 }
802 if ((CUR == '&') && (NXT(1) == '#') &&
803 (NXT(2) == 'x')) {
804 SKIP(3);
805 while (CUR != ';') {
806 if ((CUR >= '0') && (CUR <= '9'))
807 val = val * 16 + (CUR - '0');
808 else if ((CUR >= 'a') && (CUR <= 'f'))
809 val = val * 16 + (CUR - 'a') + 10;
810 else if ((CUR >= 'A') && (CUR <= 'F'))
811 val = val * 16 + (CUR - 'A') + 10;
812 else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000813 ctxt->errNo = XML_ERR_INVALID_HEX_CHARREF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000814 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
815 ctxt->sax->error(ctxt->userData,
816 "xmlParseCharRef: invalid hexadecimal value\n");
817 ctxt->wellFormed = 0;
818 val = 0;
819 break;
820 }
821 NEXT;
822 }
823 if (CUR == ';')
Daniel Veillard35008381999-10-25 13:15:52 +0000824 SKIP(1); /* on purpose to avoid reentrancy problems with NEXT */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000825 } else if ((CUR == '&') && (NXT(1) == '#')) {
826 SKIP(2);
827 while (CUR != ';') {
828 if ((CUR >= '0') && (CUR <= '9'))
829 val = val * 10 + (CUR - '0');
830 else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000831 ctxt->errNo = XML_ERR_INVALID_DEC_CHARREF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000832 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
833 ctxt->sax->error(ctxt->userData,
834 "xmlParseCharRef: invalid decimal value\n");
835 ctxt->wellFormed = 0;
836 val = 0;
837 break;
838 }
839 NEXT;
840 }
841 if (CUR == ';')
Daniel Veillard35008381999-10-25 13:15:52 +0000842 SKIP(1); /* on purpose to avoid reentrancy problems with NEXT */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000843 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000844 ctxt->errNo = XML_ERR_INVALID_CHARREF;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000845 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
846 ctxt->sax->error(ctxt->userData,
847 "xmlParseCharRef: invalid value\n");
848 ctxt->wellFormed = 0;
849 }
850
851 /*
852 * [ WFC: Legal Character ]
853 * Characters referred to using character references must match the
854 * production for Char.
855 */
856 if (IS_CHAR(val)) {
857 return(val);
858 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000859 ctxt->errNo = XML_ERR_INVALID_CHAR;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000860 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000861 ctxt->sax->error(ctxt->userData, "CharRef: invalid xmlChar value %d\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000862 val);
863 ctxt->wellFormed = 0;
864 }
865 return(0);
866}
867
868/**
Daniel Veillard10a2c651999-12-12 13:03:50 +0000869 * xmlParseStringCharRef:
870 * @ctxt: an XML parser context
871 * @str: a pointer to an index in the string
872 *
873 * parse Reference declarations, variant parsing from a string rather
874 * than an an input flow.
875 *
876 * [66] CharRef ::= '&#' [0-9]+ ';' |
877 * '&#x' [0-9a-fA-F]+ ';'
878 *
879 * [ WFC: Legal Character ]
880 * Characters referred to using character references must match the
881 * production for Char.
882 *
883 * Returns the value parsed (as an int), 0 in case of error, str will be
884 * updated to the current value of the index
885 */
886int
887xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) {
888 const xmlChar *ptr;
889 xmlChar cur;
890 int val = 0;
891
892 if ((str == NULL) || (*str == NULL)) return(0);
893 ptr = *str;
894 cur = *ptr;
Daniel Veillard0caf07a1999-12-21 16:25:49 +0000895 if ((cur == '&') && (ptr[1] == '#') && (ptr[2] == 'x')) {
Daniel Veillard10a2c651999-12-12 13:03:50 +0000896 ptr += 3;
897 cur = *ptr;
898 while (cur != ';') {
899 if ((cur >= '0') && (cur <= '9'))
900 val = val * 16 + (cur - '0');
901 else if ((cur >= 'a') && (cur <= 'f'))
902 val = val * 16 + (cur - 'a') + 10;
903 else if ((cur >= 'A') && (cur <= 'F'))
904 val = val * 16 + (cur - 'A') + 10;
905 else {
906 ctxt->errNo = XML_ERR_INVALID_HEX_CHARREF;
907 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
908 ctxt->sax->error(ctxt->userData,
909 "xmlParseCharRef: invalid hexadecimal value\n");
910 ctxt->wellFormed = 0;
911 val = 0;
912 break;
913 }
914 ptr++;
915 cur = *ptr;
916 }
917 if (cur == ';')
918 ptr++;
Daniel Veillard0142b842000-01-14 14:45:24 +0000919 } else if ((cur == '&') && (ptr[1] == '#')){
Daniel Veillard10a2c651999-12-12 13:03:50 +0000920 ptr += 2;
921 cur = *ptr;
922 while (cur != ';') {
923 if ((cur >= '0') && (cur <= '9'))
924 val = val * 10 + (cur - '0');
925 else {
926 ctxt->errNo = XML_ERR_INVALID_DEC_CHARREF;
927 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
928 ctxt->sax->error(ctxt->userData,
929 "xmlParseCharRef: invalid decimal value\n");
930 ctxt->wellFormed = 0;
931 val = 0;
932 break;
933 }
934 ptr++;
935 cur = *ptr;
936 }
937 if (cur == ';')
938 ptr++;
939 } else {
940 ctxt->errNo = XML_ERR_INVALID_CHARREF;
941 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
942 ctxt->sax->error(ctxt->userData,
943 "xmlParseCharRef: invalid value\n");
944 ctxt->wellFormed = 0;
945 return(0);
946 }
947 *str = ptr;
948
949 /*
950 * [ WFC: Legal Character ]
951 * Characters referred to using character references must match the
952 * production for Char.
953 */
954 if (IS_CHAR(val)) {
955 return(val);
956 } else {
957 ctxt->errNo = XML_ERR_INVALID_CHAR;
958 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
959 ctxt->sax->error(ctxt->userData,
960 "CharRef: invalid xmlChar value %d\n", val);
961 ctxt->wellFormed = 0;
962 }
963 return(0);
964}
965
966/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000967 * xmlParserHandleReference:
968 * @ctxt: the parser context
969 *
970 * [67] Reference ::= EntityRef | CharRef
971 *
972 * [68] EntityRef ::= '&' Name ';'
973 *
974 * [ WFC: Entity Declared ]
975 * the Name given in the entity reference must match that in an entity
976 * declaration, except that well-formed documents need not declare any
977 * of the following entities: amp, lt, gt, apos, quot.
978 *
979 * [ WFC: Parsed Entity ]
980 * An entity reference must not contain the name of an unparsed entity
981 *
982 * [66] CharRef ::= '&#' [0-9]+ ';' |
983 * '&#x' [0-9a-fA-F]+ ';'
984 *
985 * A PEReference may have been detectect in the current input stream
986 * the handling is done accordingly to
987 * http://www.w3.org/TR/REC-xml#entproc
988 */
989void
990xmlParserHandleReference(xmlParserCtxtPtr ctxt) {
991 xmlParserInputPtr input;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000992 xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000993 xmlEntityPtr ent = NULL;
994
Daniel Veillard35008381999-10-25 13:15:52 +0000995 if (ctxt->token != 0) {
Daniel Veillard35008381999-10-25 13:15:52 +0000996 return;
997 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000998 if (CUR != '&') return;
999 GROW;
1000 if ((CUR == '&') && (NXT(1) == '#')) {
1001 switch(ctxt->instate) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001002 case XML_PARSER_ENTITY_DECL:
1003 case XML_PARSER_PI:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001004 case XML_PARSER_CDATA_SECTION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001005 case XML_PARSER_COMMENT:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001006 /* we just ignore it there */
1007 return;
1008 case XML_PARSER_START_TAG:
1009 return;
1010 case XML_PARSER_END_TAG:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001011 return;
1012 case XML_PARSER_EOF:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001013 ctxt->errNo = XML_ERR_CHARREF_AT_EOF;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001014 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1015 ctxt->sax->error(ctxt->userData, "CharRef at EOF\n");
1016 ctxt->wellFormed = 0;
1017 return;
1018 case XML_PARSER_PROLOG:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001019 case XML_PARSER_START:
1020 case XML_PARSER_MISC:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001021 ctxt->errNo = XML_ERR_CHARREF_IN_PROLOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001022 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1023 ctxt->sax->error(ctxt->userData, "CharRef in prolog!\n");
1024 ctxt->wellFormed = 0;
1025 return;
1026 case XML_PARSER_EPILOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001027 ctxt->errNo = XML_ERR_CHARREF_IN_EPILOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001028 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1029 ctxt->sax->error(ctxt->userData, "CharRef in epilog!\n");
1030 ctxt->wellFormed = 0;
1031 return;
1032 case XML_PARSER_DTD:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001033 ctxt->errNo = XML_ERR_CHARREF_IN_DTD;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001034 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1035 ctxt->sax->error(ctxt->userData,
1036 "CharRef are forbiden in DTDs!\n");
1037 ctxt->wellFormed = 0;
1038 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001039 case XML_PARSER_ENTITY_VALUE:
1040 /*
1041 * NOTE: in the case of entity values, we don't do the
Daniel Veillard51e3b151999-11-12 17:02:31 +00001042 * substitution here since we need the literal
Daniel Veillardb05deb71999-08-10 19:04:08 +00001043 * entity value to be able to save the internal
1044 * subset of the document.
1045 * This will be handled by xmlDecodeEntities
1046 */
1047 return;
1048 case XML_PARSER_CONTENT:
1049 case XML_PARSER_ATTRIBUTE_VALUE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001050 /* !!! this may not be Ok for UTF-8, multibyte sequence */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001051 ctxt->token = xmlParseCharRef(ctxt);
1052 return;
1053 }
1054 return;
1055 }
1056
1057 switch(ctxt->instate) {
1058 case XML_PARSER_CDATA_SECTION:
1059 return;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001060 case XML_PARSER_PI:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001061 case XML_PARSER_COMMENT:
1062 return;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001063 case XML_PARSER_START_TAG:
1064 return;
1065 case XML_PARSER_END_TAG:
1066 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001067 case XML_PARSER_EOF:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001068 ctxt->errNo = XML_ERR_ENTITYREF_AT_EOF;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001069 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1070 ctxt->sax->error(ctxt->userData, "Reference at EOF\n");
1071 ctxt->wellFormed = 0;
1072 return;
1073 case XML_PARSER_PROLOG:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001074 case XML_PARSER_START:
1075 case XML_PARSER_MISC:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001076 ctxt->errNo = XML_ERR_ENTITYREF_IN_PROLOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001077 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1078 ctxt->sax->error(ctxt->userData, "Reference in prolog!\n");
1079 ctxt->wellFormed = 0;
1080 return;
1081 case XML_PARSER_EPILOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001082 ctxt->errNo = XML_ERR_ENTITYREF_IN_EPILOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001083 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1084 ctxt->sax->error(ctxt->userData, "Reference in epilog!\n");
1085 ctxt->wellFormed = 0;
1086 return;
1087 case XML_PARSER_ENTITY_VALUE:
1088 /*
1089 * NOTE: in the case of entity values, we don't do the
Daniel Veillard51e3b151999-11-12 17:02:31 +00001090 * substitution here since we need the literal
Daniel Veillardb05deb71999-08-10 19:04:08 +00001091 * entity value to be able to save the internal
1092 * subset of the document.
1093 * This will be handled by xmlDecodeEntities
1094 */
1095 return;
1096 case XML_PARSER_ATTRIBUTE_VALUE:
1097 /*
1098 * NOTE: in the case of attributes values, we don't do the
1099 * substitution here unless we are in a mode where
1100 * the parser is explicitely asked to substitute
1101 * entities. The SAX callback is called with values
1102 * without entity substitution.
1103 * This will then be handled by xmlDecodeEntities
1104 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001105 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001106 case XML_PARSER_ENTITY_DECL:
1107 /*
1108 * we just ignore it there
1109 * the substitution will be done once the entity is referenced
1110 */
1111 return;
1112 case XML_PARSER_DTD:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001113 ctxt->errNo = XML_ERR_ENTITYREF_IN_DTD;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001114 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1115 ctxt->sax->error(ctxt->userData,
1116 "Entity references are forbiden in DTDs!\n");
1117 ctxt->wellFormed = 0;
1118 return;
1119 case XML_PARSER_CONTENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001120 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001121 }
1122
1123 NEXT;
1124 name = xmlScanName(ctxt);
1125 if (name == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001126 ctxt->errNo = XML_ERR_ENTITYREF_NO_NAME;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001127 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1128 ctxt->sax->error(ctxt->userData, "Entity reference: no name\n");
1129 ctxt->wellFormed = 0;
1130 ctxt->token = '&';
1131 return;
1132 }
1133 if (NXT(xmlStrlen(name)) != ';') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001134 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001135 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1136 ctxt->sax->error(ctxt->userData,
1137 "Entity reference: ';' expected\n");
1138 ctxt->wellFormed = 0;
1139 ctxt->token = '&';
Daniel Veillard6454aec1999-09-02 22:04:43 +00001140 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001141 return;
1142 }
1143 SKIP(xmlStrlen(name) + 1);
1144 if (ctxt->sax != NULL) {
1145 if (ctxt->sax->getEntity != NULL)
1146 ent = ctxt->sax->getEntity(ctxt->userData, name);
1147 }
1148
1149 /*
1150 * [ WFC: Entity Declared ]
1151 * the Name given in the entity reference must match that in an entity
1152 * declaration, except that well-formed documents need not declare any
1153 * of the following entities: amp, lt, gt, apos, quot.
1154 */
1155 if (ent == NULL)
1156 ent = xmlGetPredefinedEntity(name);
1157 if (ent == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001158 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001159 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1160 ctxt->sax->error(ctxt->userData,
1161 "Entity reference: entity %s not declared\n",
1162 name);
1163 ctxt->wellFormed = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001164 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001165 return;
1166 }
1167
1168 /*
1169 * [ WFC: Parsed Entity ]
1170 * An entity reference must not contain the name of an unparsed entity
1171 */
1172 if (ent->type == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001173 ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001174 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1175 ctxt->sax->error(ctxt->userData,
1176 "Entity reference to unparsed entity %s\n", name);
1177 ctxt->wellFormed = 0;
1178 }
1179
1180 if (ent->type == XML_INTERNAL_PREDEFINED_ENTITY) {
1181 ctxt->token = ent->content[0];
Daniel Veillard6454aec1999-09-02 22:04:43 +00001182 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001183 return;
1184 }
1185 input = xmlNewEntityInputStream(ctxt, ent);
1186 xmlPushInput(ctxt, input);
Daniel Veillard6454aec1999-09-02 22:04:43 +00001187 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001188 return;
1189}
1190
1191/**
1192 * xmlParserHandlePEReference:
1193 * @ctxt: the parser context
1194 *
1195 * [69] PEReference ::= '%' Name ';'
1196 *
1197 * [ WFC: No Recursion ]
1198 * TODO A parsed entity must not contain a recursive
1199 * reference to itself, either directly or indirectly.
1200 *
1201 * [ WFC: Entity Declared ]
1202 * In a document without any DTD, a document with only an internal DTD
1203 * subset which contains no parameter entity references, or a document
1204 * with "standalone='yes'", ... ... The declaration of a parameter
1205 * entity must precede any reference to it...
1206 *
1207 * [ VC: Entity Declared ]
1208 * In a document with an external subset or external parameter entities
1209 * with "standalone='no'", ... ... The declaration of a parameter entity
1210 * must precede any reference to it...
1211 *
1212 * [ WFC: In DTD ]
1213 * Parameter-entity references may only appear in the DTD.
1214 * NOTE: misleading but this is handled.
1215 *
1216 * A PEReference may have been detected in the current input stream
1217 * the handling is done accordingly to
1218 * http://www.w3.org/TR/REC-xml#entproc
1219 * i.e.
1220 * - Included in literal in entity values
1221 * - Included as Paraemeter Entity reference within DTDs
1222 */
1223void
1224xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001225 xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001226 xmlEntityPtr entity = NULL;
1227 xmlParserInputPtr input;
1228
Daniel Veillard35008381999-10-25 13:15:52 +00001229 if (ctxt->token != 0) {
Daniel Veillard35008381999-10-25 13:15:52 +00001230 return;
1231 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001232 if (CUR != '%') return;
1233 switch(ctxt->instate) {
1234 case XML_PARSER_CDATA_SECTION:
1235 return;
1236 case XML_PARSER_COMMENT:
1237 return;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001238 case XML_PARSER_START_TAG:
1239 return;
1240 case XML_PARSER_END_TAG:
1241 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001242 case XML_PARSER_EOF:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001243 ctxt->errNo = XML_ERR_PEREF_AT_EOF;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001244 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1245 ctxt->sax->error(ctxt->userData, "PEReference at EOF\n");
1246 ctxt->wellFormed = 0;
1247 return;
1248 case XML_PARSER_PROLOG:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001249 case XML_PARSER_START:
1250 case XML_PARSER_MISC:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001251 ctxt->errNo = XML_ERR_PEREF_IN_PROLOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001252 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1253 ctxt->sax->error(ctxt->userData, "PEReference in prolog!\n");
1254 ctxt->wellFormed = 0;
1255 return;
1256 case XML_PARSER_ENTITY_DECL:
1257 case XML_PARSER_CONTENT:
1258 case XML_PARSER_ATTRIBUTE_VALUE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001259 case XML_PARSER_PI:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001260 /* we just ignore it there */
1261 return;
1262 case XML_PARSER_EPILOG:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001263 ctxt->errNo = XML_ERR_PEREF_IN_EPILOG;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001264 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1265 ctxt->sax->error(ctxt->userData, "PEReference in epilog!\n");
1266 ctxt->wellFormed = 0;
1267 return;
1268 case XML_PARSER_ENTITY_VALUE:
1269 /*
1270 * NOTE: in the case of entity values, we don't do the
Daniel Veillard51e3b151999-11-12 17:02:31 +00001271 * substitution here since we need the literal
Daniel Veillardb05deb71999-08-10 19:04:08 +00001272 * entity value to be able to save the internal
1273 * subset of the document.
1274 * This will be handled by xmlDecodeEntities
1275 */
1276 return;
1277 case XML_PARSER_DTD:
1278 /*
1279 * [WFC: Well-Formedness Constraint: PEs in Internal Subset]
1280 * In the internal DTD subset, parameter-entity references
1281 * can occur only where markup declarations can occur, not
1282 * within markup declarations.
1283 * In that case this is handled in xmlParseMarkupDecl
1284 */
1285 if ((ctxt->external == 0) && (ctxt->inputNr == 1))
1286 return;
1287 }
1288
1289 NEXT;
1290 name = xmlParseName(ctxt);
1291 if (name == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001292 ctxt->errNo = XML_ERR_PEREF_NO_NAME;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001293 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1294 ctxt->sax->error(ctxt->userData, "xmlHandlePEReference: no name\n");
1295 ctxt->wellFormed = 0;
1296 } else {
1297 if (CUR == ';') {
1298 NEXT;
1299 if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL))
1300 entity = ctxt->sax->getParameterEntity(ctxt->userData, name);
1301 if (entity == NULL) {
1302
1303 /*
1304 * [ WFC: Entity Declared ]
1305 * In a document without any DTD, a document with only an
1306 * internal DTD subset which contains no parameter entity
1307 * references, or a document with "standalone='yes'", ...
1308 * ... The declaration of a parameter entity must precede
1309 * any reference to it...
1310 */
1311 if ((ctxt->standalone == 1) ||
1312 ((ctxt->hasExternalSubset == 0) &&
1313 (ctxt->hasPErefs == 0))) {
1314 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1315 ctxt->sax->error(ctxt->userData,
1316 "PEReference: %%%s; not found\n", name);
1317 ctxt->wellFormed = 0;
1318 } else {
1319 /*
1320 * [ VC: Entity Declared ]
1321 * In a document with an external subset or external
1322 * parameter entities with "standalone='no'", ...
1323 * ... The declaration of a parameter entity must precede
1324 * any reference to it...
1325 */
1326 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1327 ctxt->sax->warning(ctxt->userData,
1328 "PEReference: %%%s; not found\n", name);
1329 ctxt->valid = 0;
1330 }
1331 } else {
1332 if ((entity->type == XML_INTERNAL_PARAMETER_ENTITY) ||
1333 (entity->type == XML_EXTERNAL_PARAMETER_ENTITY)) {
1334 /*
1335 * TODO !!!! handle the extra spaces added before and after
1336 * c.f. http://www.w3.org/TR/REC-xml#as-PE
1337 * TODO !!!! Avoid quote processing in parameters value
1338 * c.f. http://www.w3.org/TR/REC-xml#inliteral
1339 */
1340 input = xmlNewEntityInputStream(ctxt, entity);
1341 xmlPushInput(ctxt, input);
1342 } else {
1343 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1344 ctxt->sax->error(ctxt->userData,
1345 "xmlHandlePEReference: %s is not a parameter entity\n",
1346 name);
1347 ctxt->wellFormed = 0;
1348 }
1349 }
1350 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001351 ctxt->errNo = XML_ERR_PEREF_SEMICOL_MISSING;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001352 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1353 ctxt->sax->error(ctxt->userData,
1354 "xmlHandlePEReference: expecting ';'\n");
1355 ctxt->wellFormed = 0;
1356 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001357 xmlFree(name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001358 }
1359}
1360
Daniel Veillard011b63c1999-06-02 17:44:04 +00001361/*
1362 * Macro used to grow the current buffer.
1363 */
1364#define growBuffer(buffer) { \
1365 buffer##_size *= 2; \
Daniel Veillard0142b842000-01-14 14:45:24 +00001366 buffer = (xmlChar *) \
1367 xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \
Daniel Veillard011b63c1999-06-02 17:44:04 +00001368 if (buffer == NULL) { \
1369 perror("realloc failed"); \
Daniel Veillard0142b842000-01-14 14:45:24 +00001370 return(NULL); \
Daniel Veillard011b63c1999-06-02 17:44:04 +00001371 } \
1372}
1373
Daniel Veillard011b63c1999-06-02 17:44:04 +00001374/**
1375 * xmlDecodeEntities:
1376 * @ctxt: the parser context
1377 * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF
1378 * @len: the len to decode (in bytes !), -1 for no size limit
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001379 * @end: an end marker xmlChar, 0 if none
1380 * @end2: an end marker xmlChar, 0 if none
1381 * @end3: an end marker xmlChar, 0 if none
Daniel Veillard011b63c1999-06-02 17:44:04 +00001382 *
1383 * [67] Reference ::= EntityRef | CharRef
1384 *
1385 * [69] PEReference ::= '%' Name ';'
1386 *
1387 * Returns A newly allocated string with the substitution done. The caller
1388 * must deallocate it !
1389 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001390xmlChar *
Daniel Veillard011b63c1999-06-02 17:44:04 +00001391xmlDecodeEntities(xmlParserCtxtPtr ctxt, int len, int what,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001392 xmlChar end, xmlChar end2, xmlChar end3) {
1393 xmlChar *buffer = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001394 int buffer_size = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001395 xmlChar *out = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001396
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001397 xmlChar *current = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001398 xmlEntityPtr ent;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001399 int nbchars = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001400 unsigned int max = (unsigned int) len;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001401 xmlChar cur;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001402
1403 /*
1404 * allocate a translation buffer.
1405 */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001406 buffer_size = XML_PARSER_BIG_BUFFER_SIZE;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001407 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
Daniel Veillard011b63c1999-06-02 17:44:04 +00001408 if (buffer == NULL) {
1409 perror("xmlDecodeEntities: malloc failed");
1410 return(NULL);
1411 }
1412 out = buffer;
1413
1414 /*
1415 * Ok loop until we reach one of the ending char or a size limit.
1416 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001417 cur = CUR;
1418 while ((nbchars < max) && (cur != end) &&
1419 (cur != end2) && (cur != end3)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001420
Daniel Veillardb05deb71999-08-10 19:04:08 +00001421 if (cur == 0) break;
1422 if ((cur == '&') && (NXT(1) == '#')) {
1423 int val = xmlParseCharRef(ctxt);
1424 *out++ = val;
1425 nbchars += 3;
1426 } else if ((cur == '&') && (what & XML_SUBSTITUTE_REF)) {
1427 ent = xmlParseEntityRef(ctxt);
1428 if ((ent != NULL) &&
1429 (ctxt->replaceEntities != 0)) {
1430 current = ent->content;
1431 while (*current != 0) {
1432 *out++ = *current++;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001433 if (out - buffer > buffer_size - XML_PARSER_BUFFER_SIZE) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001434 int index = out - buffer;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001435
Daniel Veillardb05deb71999-08-10 19:04:08 +00001436 growBuffer(buffer);
1437 out = &buffer[index];
Daniel Veillard011b63c1999-06-02 17:44:04 +00001438 }
1439 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001440 nbchars += 3 + xmlStrlen(ent->name);
1441 } else if (ent != NULL) {
1442 int i = xmlStrlen(ent->name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001443 const xmlChar *cur = ent->name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001444
1445 nbchars += i + 2;
1446 *out++ = '&';
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001447 if (out - buffer > buffer_size - i - XML_PARSER_BUFFER_SIZE) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001448 int index = out - buffer;
1449
1450 growBuffer(buffer);
1451 out = &buffer[index];
1452 }
1453 for (;i > 0;i--)
1454 *out++ = *cur++;
1455 *out++ = ';';
Daniel Veillard011b63c1999-06-02 17:44:04 +00001456 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001457 } else if (cur == '%' && (what & XML_SUBSTITUTE_PEREF)) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001458 /*
1459 * a PEReference induce to switch the entity flow,
1460 * we break here to flush the current set of chars
1461 * parsed if any. We will be called back later.
1462 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001463 if (nbchars != 0) break;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001464
1465 xmlParsePEReference(ctxt);
1466
1467 /*
1468 * Pop-up of finished entities.
1469 */
1470 while ((CUR == 0) && (ctxt->inputNr > 1))
1471 xmlPopInput(ctxt);
1472
Daniel Veillardb05deb71999-08-10 19:04:08 +00001473 break;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001474 } else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001475 /* invalid for UTF-8 , use COPY(out); !!!!!! */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001476 *out++ = cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001477 nbchars++;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001478 if (out - buffer > buffer_size - XML_PARSER_BUFFER_SIZE) {
Raph Levien05240da1999-06-15 21:27:11 +00001479 int index = out - buffer;
1480
1481 growBuffer(buffer);
1482 out = &buffer[index];
1483 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00001484 NEXT;
1485 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001486 cur = CUR;
Daniel Veillard011b63c1999-06-02 17:44:04 +00001487 }
1488 *out++ = 0;
1489 return(buffer);
1490}
1491
Daniel Veillard10a2c651999-12-12 13:03:50 +00001492/**
1493 * xmlStringDecodeEntities:
1494 * @ctxt: the parser context
1495 * @str: the input string
1496 * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF
1497 * @end: an end marker xmlChar, 0 if none
1498 * @end2: an end marker xmlChar, 0 if none
1499 * @end3: an end marker xmlChar, 0 if none
1500 *
1501 * [67] Reference ::= EntityRef | CharRef
1502 *
1503 * [69] PEReference ::= '%' Name ';'
1504 *
1505 * Returns A newly allocated string with the substitution done. The caller
1506 * must deallocate it !
1507 */
1508xmlChar *
1509xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what,
1510 xmlChar end, xmlChar end2, xmlChar end3) {
1511 xmlChar *buffer = NULL;
1512 int buffer_size = 0;
1513 xmlChar *out = NULL;
1514
1515 xmlChar *current = NULL;
1516 xmlEntityPtr ent;
1517 xmlChar cur;
1518
1519 /*
1520 * allocate a translation buffer.
1521 */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001522 buffer_size = XML_PARSER_BIG_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00001523 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
1524 if (buffer == NULL) {
1525 perror("xmlDecodeEntities: malloc failed");
1526 return(NULL);
1527 }
1528 out = buffer;
1529
1530 /*
1531 * Ok loop until we reach one of the ending char or a size limit.
1532 */
1533 cur = *str;
1534 while ((cur != 0) && (cur != end) &&
1535 (cur != end2) && (cur != end3)) {
1536
1537 if (cur == 0) break;
1538 if ((cur == '&') && (str[1] == '#')) {
1539 int val = xmlParseStringCharRef(ctxt, &str);
1540 if (val != 0)
1541 *out++ = val;
1542 } else if ((cur == '&') && (what & XML_SUBSTITUTE_REF)) {
1543 ent = xmlParseStringEntityRef(ctxt, &str);
1544 if ((ent != NULL) &&
1545 (ctxt->replaceEntities != 0)) {
1546 current = ent->content;
1547 while (*current != 0) {
1548 *out++ = *current++;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001549 if (out - buffer > buffer_size - XML_PARSER_BUFFER_SIZE) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00001550 int index = out - buffer;
1551
1552 growBuffer(buffer);
1553 out = &buffer[index];
1554 }
1555 }
1556 } else if (ent != NULL) {
1557 int i = xmlStrlen(ent->name);
1558 const xmlChar *cur = ent->name;
1559
1560 *out++ = '&';
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001561 if (out - buffer > buffer_size - i - XML_PARSER_BUFFER_SIZE) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00001562 int index = out - buffer;
1563
1564 growBuffer(buffer);
1565 out = &buffer[index];
1566 }
1567 for (;i > 0;i--)
1568 *out++ = *cur++;
1569 *out++ = ';';
1570 }
1571 } else if (cur == '%' && (what & XML_SUBSTITUTE_PEREF)) {
1572 ent = xmlParseStringPEReference(ctxt, &str);
1573 if (ent != NULL) {
1574 current = ent->content;
1575 while (*current != 0) {
1576 *out++ = *current++;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001577 if (out - buffer > buffer_size - XML_PARSER_BUFFER_SIZE) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00001578 int index = out - buffer;
1579
1580 growBuffer(buffer);
1581 out = &buffer[index];
1582 }
1583 }
1584 }
1585 } else {
1586 /* invalid for UTF-8 , use COPY(out); !!!!!! */
1587 *out++ = cur;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001588 if (out - buffer > buffer_size - XML_PARSER_BUFFER_SIZE) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00001589 int index = out - buffer;
1590
1591 growBuffer(buffer);
1592 out = &buffer[index];
1593 }
1594 str++;
1595 }
1596 cur = *str;
1597 }
1598 *out = 0;
1599 return(buffer);
1600}
1601
Daniel Veillard260a68f1998-08-13 03:39:55 +00001602
1603/************************************************************************
1604 * *
Daniel Veillard27d88741999-05-29 11:51:49 +00001605 * Commodity functions to handle encodings *
1606 * *
1607 ************************************************************************/
1608
1609/**
1610 * xmlSwitchEncoding:
1611 * @ctxt: the parser context
Daniel Veillard00fdf371999-10-08 09:40:39 +00001612 * @enc: the encoding value (number)
Daniel Veillard27d88741999-05-29 11:51:49 +00001613 *
1614 * change the input functions when discovering the character encoding
1615 * of a given entity.
Daniel Veillard27d88741999-05-29 11:51:49 +00001616 */
1617void
1618xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
1619{
1620 switch (enc) {
1621 case XML_CHAR_ENCODING_ERROR:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001622 ctxt->errNo = XML_ERR_UNKNOWN_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001623 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1624 ctxt->sax->error(ctxt->userData, "encoding unknown\n");
1625 ctxt->wellFormed = 0;
1626 break;
1627 case XML_CHAR_ENCODING_NONE:
1628 /* let's assume it's UTF-8 without the XML decl */
1629 return;
1630 case XML_CHAR_ENCODING_UTF8:
1631 /* default encoding, no conversion should be needed */
1632 return;
1633 case XML_CHAR_ENCODING_UTF16LE:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001634 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001635 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1636 ctxt->sax->error(ctxt->userData,
1637 "char encoding UTF16 little endian not supported\n");
1638 break;
1639 case XML_CHAR_ENCODING_UTF16BE:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001640 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001641 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1642 ctxt->sax->error(ctxt->userData,
1643 "char encoding UTF16 big endian not supported\n");
1644 break;
1645 case XML_CHAR_ENCODING_UCS4LE:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001646 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001647 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1648 ctxt->sax->error(ctxt->userData,
1649 "char encoding USC4 little endian not supported\n");
1650 break;
1651 case XML_CHAR_ENCODING_UCS4BE:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001652 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001653 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1654 ctxt->sax->error(ctxt->userData,
1655 "char encoding USC4 big endian not supported\n");
1656 break;
1657 case XML_CHAR_ENCODING_EBCDIC:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001658 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001659 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1660 ctxt->sax->error(ctxt->userData,
1661 "char encoding EBCDIC not supported\n");
1662 break;
1663 case XML_CHAR_ENCODING_UCS4_2143:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001664 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001665 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1666 ctxt->sax->error(ctxt->userData,
1667 "char encoding UCS4 2143 not supported\n");
1668 break;
1669 case XML_CHAR_ENCODING_UCS4_3412:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001670 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001671 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1672 ctxt->sax->error(ctxt->userData,
1673 "char encoding UCS4 3412 not supported\n");
1674 break;
1675 case XML_CHAR_ENCODING_UCS2:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001676 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001677 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1678 ctxt->sax->error(ctxt->userData,
1679 "char encoding UCS2 not supported\n");
1680 break;
1681 case XML_CHAR_ENCODING_8859_1:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001682 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001683 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1684 ctxt->sax->error(ctxt->userData,
1685 "char encoding ISO_8859_1 ISO Latin 1 not supported\n");
1686 break;
1687 case XML_CHAR_ENCODING_8859_2:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001688 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001689 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1690 ctxt->sax->error(ctxt->userData,
1691 "char encoding ISO_8859_2 ISO Latin 2 not supported\n");
1692 break;
1693 case XML_CHAR_ENCODING_8859_3:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001694 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001695 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1696 ctxt->sax->error(ctxt->userData,
1697 "char encoding ISO_8859_3 not supported\n");
1698 break;
1699 case XML_CHAR_ENCODING_8859_4:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001700 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001701 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1702 ctxt->sax->error(ctxt->userData,
1703 "char encoding ISO_8859_4 not supported\n");
1704 break;
1705 case XML_CHAR_ENCODING_8859_5:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001706 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001707 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1708 ctxt->sax->error(ctxt->userData,
1709 "char encoding ISO_8859_5 not supported\n");
1710 break;
1711 case XML_CHAR_ENCODING_8859_6:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001712 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001713 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1714 ctxt->sax->error(ctxt->userData,
1715 "char encoding ISO_8859_6 not supported\n");
1716 break;
1717 case XML_CHAR_ENCODING_8859_7:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001718 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001719 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1720 ctxt->sax->error(ctxt->userData,
1721 "char encoding ISO_8859_7 not supported\n");
1722 break;
1723 case XML_CHAR_ENCODING_8859_8:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001724 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001725 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1726 ctxt->sax->error(ctxt->userData,
1727 "char encoding ISO_8859_8 not supported\n");
1728 break;
1729 case XML_CHAR_ENCODING_8859_9:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001730 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001731 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1732 ctxt->sax->error(ctxt->userData,
1733 "char encoding ISO_8859_9 not supported\n");
1734 break;
1735 case XML_CHAR_ENCODING_2022_JP:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001736 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001737 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1738 ctxt->sax->error(ctxt->userData,
1739 "char encoding ISO-2022-JPnot supported\n");
1740 break;
1741 case XML_CHAR_ENCODING_SHIFT_JIS:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001742 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001743 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1744 ctxt->sax->error(ctxt->userData,
1745 "char encoding Shift_JISnot supported\n");
1746 break;
1747 case XML_CHAR_ENCODING_EUC_JP:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001748 ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
Daniel Veillard27d88741999-05-29 11:51:49 +00001749 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1750 ctxt->sax->error(ctxt->userData,
1751 "char encoding EUC-JPnot supported\n");
1752 break;
1753 }
1754}
1755
1756/************************************************************************
1757 * *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001758 * Commodity functions to handle xmlChars *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001759 * *
1760 ************************************************************************/
1761
Daniel Veillard11e00581998-10-24 18:27:49 +00001762/**
1763 * xmlStrndup:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001764 * @cur: the input xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001765 * @len: the len of @cur
1766 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001767 * a strndup for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001768 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001769 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001770 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001771xmlChar *
1772xmlStrndup(const xmlChar *cur, int len) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00001773 xmlChar *ret;
1774
1775 if ((cur == NULL) || (len < 0)) return(NULL);
1776 ret = xmlMalloc((len + 1) * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001777 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001778 fprintf(stderr, "malloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001779 (len + 1) * (long)sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001780 return(NULL);
1781 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001782 memcpy(ret, cur, len * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001783 ret[len] = 0;
1784 return(ret);
1785}
1786
Daniel Veillard11e00581998-10-24 18:27:49 +00001787/**
1788 * xmlStrdup:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001789 * @cur: the input xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001790 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001791 * a strdup for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001792 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001793 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001794 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001795xmlChar *
1796xmlStrdup(const xmlChar *cur) {
1797 const xmlChar *p = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001798
Daniel Veillard10a2c651999-12-12 13:03:50 +00001799 if (cur == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001800 while (IS_CHAR(*p)) p++;
1801 return(xmlStrndup(cur, p - cur));
1802}
1803
Daniel Veillard11e00581998-10-24 18:27:49 +00001804/**
1805 * xmlCharStrndup:
1806 * @cur: the input char *
1807 * @len: the len of @cur
1808 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001809 * a strndup for char's to xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001810 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001811 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001812 */
1813
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001814xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001815xmlCharStrndup(const char *cur, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001816 int i;
Daniel Veillard10a2c651999-12-12 13:03:50 +00001817 xmlChar *ret;
1818
1819 if ((cur == NULL) || (len < 0)) return(NULL);
1820 ret = xmlMalloc((len + 1) * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001821 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001822 fprintf(stderr, "malloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001823 (len + 1) * (long)sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00001824 return(NULL);
1825 }
1826 for (i = 0;i < len;i++)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001827 ret[i] = (xmlChar) cur[i];
Daniel Veillard260a68f1998-08-13 03:39:55 +00001828 ret[len] = 0;
1829 return(ret);
1830}
1831
Daniel Veillard11e00581998-10-24 18:27:49 +00001832/**
1833 * xmlCharStrdup:
1834 * @cur: the input char *
1835 * @len: the len of @cur
1836 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001837 * a strdup for char's to xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001838 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001839 * Returns a new xmlChar * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001840 */
1841
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001842xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001843xmlCharStrdup(const char *cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001844 const char *p = cur;
1845
Daniel Veillard10a2c651999-12-12 13:03:50 +00001846 if (cur == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001847 while (*p != '\0') p++;
1848 return(xmlCharStrndup(cur, p - cur));
1849}
1850
Daniel Veillard11e00581998-10-24 18:27:49 +00001851/**
1852 * xmlStrcmp:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001853 * @str1: the first xmlChar *
1854 * @str2: the second xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001855 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001856 * a strcmp for xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001857 *
1858 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +00001859 */
1860
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001861int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001862xmlStrcmp(const xmlChar *str1, const xmlChar *str2) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001863 register int tmp;
1864
Daniel Veillard10a2c651999-12-12 13:03:50 +00001865 if ((str1 == NULL) && (str2 == NULL)) return(0);
1866 if (str1 == NULL) return(-1);
1867 if (str2 == NULL) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001868 do {
1869 tmp = *str1++ - *str2++;
1870 if (tmp != 0) return(tmp);
1871 } while ((*str1 != 0) && (*str2 != 0));
1872 return (*str1 - *str2);
1873}
1874
Daniel Veillard11e00581998-10-24 18:27:49 +00001875/**
1876 * xmlStrncmp:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001877 * @str1: the first xmlChar *
1878 * @str2: the second xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00001879 * @len: the max comparison length
1880 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001881 * a strncmp for xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001882 *
1883 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +00001884 */
1885
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001886int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001887xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001888 register int tmp;
1889
1890 if (len <= 0) return(0);
Daniel Veillard10a2c651999-12-12 13:03:50 +00001891 if ((str1 == NULL) && (str2 == NULL)) return(0);
1892 if (str1 == NULL) return(-1);
1893 if (str2 == NULL) return(1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001894 do {
1895 tmp = *str1++ - *str2++;
1896 if (tmp != 0) return(tmp);
1897 len--;
1898 if (len <= 0) return(0);
1899 } while ((*str1 != 0) && (*str2 != 0));
1900 return (*str1 - *str2);
1901}
1902
Daniel Veillard11e00581998-10-24 18:27:49 +00001903/**
1904 * xmlStrchr:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001905 * @str: the xmlChar * array
1906 * @val: the xmlChar to search
Daniel Veillard11e00581998-10-24 18:27:49 +00001907 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001908 * a strchr for xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00001909 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001910 * Returns the xmlChar * for the first occurence or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001911 */
1912
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001913const xmlChar *
1914xmlStrchr(const xmlChar *str, xmlChar val) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00001915 if (str == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001916 while (*str != 0) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001917 if (*str == val) return((xmlChar *) str);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001918 str++;
1919 }
1920 return(NULL);
1921}
1922
Daniel Veillard11e00581998-10-24 18:27:49 +00001923/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001924 * xmlStrstr:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001925 * @str: the xmlChar * array (haystack)
1926 * @val: the xmlChar to search (needle)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001927 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001928 * a strstr for xmlChar's
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001929 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001930 * Returns the xmlChar * for the first occurence or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001931 */
1932
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001933const xmlChar *
1934xmlStrstr(const xmlChar *str, xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001935 int n;
1936
1937 if (str == NULL) return(NULL);
1938 if (val == NULL) return(NULL);
1939 n = xmlStrlen(val);
1940
1941 if (n == 0) return(str);
1942 while (*str != 0) {
1943 if (*str == *val) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001944 if (!xmlStrncmp(str, val, n)) return((const xmlChar *) str);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001945 }
1946 str++;
1947 }
1948 return(NULL);
1949}
1950
1951/**
1952 * xmlStrsub:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001953 * @str: the xmlChar * array (haystack)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001954 * @start: the index of the first char (zero based)
1955 * @len: the length of the substring
1956 *
1957 * Extract a substring of a given string
1958 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001959 * Returns the xmlChar * for the first occurence or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001960 */
1961
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001962xmlChar *
1963xmlStrsub(const xmlChar *str, int start, int len) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001964 int i;
1965
1966 if (str == NULL) return(NULL);
1967 if (start < 0) return(NULL);
1968 if (len < 0) return(NULL);
1969
1970 for (i = 0;i < start;i++) {
1971 if (*str == 0) return(NULL);
1972 str++;
1973 }
1974 if (*str == 0) return(NULL);
1975 return(xmlStrndup(str, len));
1976}
1977
1978/**
Daniel Veillard11e00581998-10-24 18:27:49 +00001979 * xmlStrlen:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001980 * @str: the xmlChar * array
Daniel Veillard11e00581998-10-24 18:27:49 +00001981 *
Daniel Veillard51e3b151999-11-12 17:02:31 +00001982 * length of a xmlChar's string
Daniel Veillard1e346af1999-02-22 10:33:01 +00001983 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001984 * Returns the number of xmlChar contained in the ARRAY.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001985 */
1986
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001987int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001988xmlStrlen(const xmlChar *str) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001989 int len = 0;
1990
1991 if (str == NULL) return(0);
1992 while (*str != 0) {
1993 str++;
1994 len++;
1995 }
1996 return(len);
1997}
1998
Daniel Veillard11e00581998-10-24 18:27:49 +00001999/**
2000 * xmlStrncat:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002001 * @cur: the original xmlChar * array
2002 * @add: the xmlChar * array added
Daniel Veillard11e00581998-10-24 18:27:49 +00002003 * @len: the length of @add
2004 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002005 * a strncat for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00002006 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002007 * Returns a new xmlChar * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002008 */
2009
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002010xmlChar *
2011xmlStrncat(xmlChar *cur, const xmlChar *add, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002012 int size;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002013 xmlChar *ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002014
2015 if ((add == NULL) || (len == 0))
2016 return(cur);
2017 if (cur == NULL)
2018 return(xmlStrndup(add, len));
2019
2020 size = xmlStrlen(cur);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002021 ret = xmlRealloc(cur, (size + len + 1) * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002022 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00002023 fprintf(stderr, "xmlStrncat: realloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002024 (size + len + 1) * (long)sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002025 return(cur);
2026 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002027 memcpy(&ret[size], add, len * sizeof(xmlChar));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002028 ret[size + len] = 0;
2029 return(ret);
2030}
2031
Daniel Veillard11e00581998-10-24 18:27:49 +00002032/**
2033 * xmlStrcat:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002034 * @cur: the original xmlChar * array
2035 * @add: the xmlChar * array added
Daniel Veillard11e00581998-10-24 18:27:49 +00002036 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002037 * a strcat for array of xmlChar's
Daniel Veillard1e346af1999-02-22 10:33:01 +00002038 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002039 * Returns a new xmlChar * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002040 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002041xmlChar *
2042xmlStrcat(xmlChar *cur, const xmlChar *add) {
2043 const xmlChar *p = add;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002044
2045 if (add == NULL) return(cur);
2046 if (cur == NULL)
2047 return(xmlStrdup(add));
2048
2049 while (IS_CHAR(*p)) p++;
2050 return(xmlStrncat(cur, add, p - add));
2051}
2052
2053/************************************************************************
2054 * *
2055 * Commodity functions, cleanup needed ? *
2056 * *
2057 ************************************************************************/
2058
Daniel Veillard11e00581998-10-24 18:27:49 +00002059/**
2060 * areBlanks:
2061 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002062 * @str: a xmlChar *
Daniel Veillard11e00581998-10-24 18:27:49 +00002063 * @len: the size of @str
2064 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002065 * Is this a sequence of blank chars that one can ignore ?
Daniel Veillard11e00581998-10-24 18:27:49 +00002066 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00002067 * Returns 1 if ignorable 0 otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002068 */
2069
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002070static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002071 int i, ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002072 xmlNodePtr lastChild;
2073
2074 for (i = 0;i < len;i++)
2075 if (!(IS_BLANK(str[i]))) return(0);
2076
2077 if (CUR != '<') return(0);
Daniel Veillard517752b1999-04-05 12:20:10 +00002078 if (ctxt->node == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002079 if (ctxt->myDoc != NULL) {
2080 ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name);
2081 if (ret == 0) return(1);
2082 if (ret == 1) return(0);
2083 }
2084 /*
2085 * heuristic
2086 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00002087 lastChild = xmlGetLastChild(ctxt->node);
2088 if (lastChild == NULL) {
2089 if (ctxt->node->content != NULL) return(0);
2090 } else if (xmlNodeIsText(lastChild))
2091 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002092 else if ((ctxt->node->childs != NULL) &&
2093 (xmlNodeIsText(ctxt->node->childs)))
2094 return(0);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002095 return(1);
2096}
2097
Daniel Veillard11e00581998-10-24 18:27:49 +00002098/**
2099 * xmlHandleEntity:
2100 * @ctxt: an XML parser context
2101 * @entity: an XML entity pointer.
2102 *
2103 * Default handling of defined entities, when should we define a new input
Daniel Veillard260a68f1998-08-13 03:39:55 +00002104 * stream ? When do we just handle that as a set of chars ?
Daniel Veillardb05deb71999-08-10 19:04:08 +00002105 *
2106 * OBSOLETE: to be removed at some point.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002107 */
2108
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002109void
2110xmlHandleEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002111 int len;
Daniel Veillardccb09631998-10-27 06:21:04 +00002112 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002113
2114 if (entity->content == NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002115 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002116 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002117 ctxt->sax->error(ctxt->userData, "xmlHandleEntity %s: content == NULL\n",
Daniel Veillard260a68f1998-08-13 03:39:55 +00002118 entity->name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002119 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002120 return;
2121 }
2122 len = xmlStrlen(entity->content);
2123 if (len <= 2) goto handle_as_char;
2124
2125 /*
2126 * Redefine its content as an input stream.
2127 */
Daniel Veillardccb09631998-10-27 06:21:04 +00002128 input = xmlNewEntityInputStream(ctxt, entity);
2129 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002130 return;
2131
2132handle_as_char:
2133 /*
2134 * Just handle the content as a set of chars.
2135 */
Daniel Veillard517752b1999-04-05 12:20:10 +00002136 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002137 ctxt->sax->characters(ctxt->userData, entity->content, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002138
2139}
2140
2141/*
2142 * Forward definition for recusive behaviour.
2143 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00002144void xmlParsePEReference(xmlParserCtxtPtr ctxt);
2145void xmlParseReference(xmlParserCtxtPtr ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002146
2147/************************************************************************
2148 * *
2149 * Extra stuff for namespace support *
2150 * Relates to http://www.w3.org/TR/WD-xml-names *
2151 * *
2152 ************************************************************************/
2153
Daniel Veillard11e00581998-10-24 18:27:49 +00002154/**
2155 * xmlNamespaceParseNCName:
2156 * @ctxt: an XML parser context
2157 *
2158 * parse an XML namespace name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002159 *
2160 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
2161 *
2162 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
2163 * CombiningChar | Extender
Daniel Veillard1e346af1999-02-22 10:33:01 +00002164 *
2165 * Returns the namespace name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002166 */
2167
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002168xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002169xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002170 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002171 int len = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002172
2173 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002174
2175 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2176 (CUR == '.') || (CUR == '-') ||
2177 (CUR == '_') ||
2178 (IS_COMBINING(CUR)) ||
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002179 (IS_EXTENDER(CUR))) {
2180 buf[len++] = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002181 NEXT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002182 if (len >= XML_MAX_NAMELEN) {
2183 fprintf(stderr,
2184 "xmlNamespaceParseNCName: reached XML_MAX_NAMELEN limit\n");
2185 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2186 (CUR == '.') || (CUR == '-') ||
2187 (CUR == '_') ||
2188 (IS_COMBINING(CUR)) ||
2189 (IS_EXTENDER(CUR)))
2190 NEXT;
2191 break;
2192 }
2193 }
2194 return(xmlStrndup(buf, len));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002195}
2196
Daniel Veillard11e00581998-10-24 18:27:49 +00002197/**
2198 * xmlNamespaceParseQName:
2199 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002200 * @prefix: a xmlChar **
Daniel Veillard11e00581998-10-24 18:27:49 +00002201 *
2202 * parse an XML qualified name
Daniel Veillard260a68f1998-08-13 03:39:55 +00002203 *
2204 * [NS 5] QName ::= (Prefix ':')? LocalPart
2205 *
2206 * [NS 6] Prefix ::= NCName
2207 *
2208 * [NS 7] LocalPart ::= NCName
Daniel Veillard1e346af1999-02-22 10:33:01 +00002209 *
Daniel Veillard51e3b151999-11-12 17:02:31 +00002210 * Returns the local part, and prefix is updated
Daniel Veillard11e00581998-10-24 18:27:49 +00002211 * to get the Prefix if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002212 */
2213
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002214xmlChar *
2215xmlNamespaceParseQName(xmlParserCtxtPtr ctxt, xmlChar **prefix) {
2216 xmlChar *ret = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002217
2218 *prefix = NULL;
2219 ret = xmlNamespaceParseNCName(ctxt);
2220 if (CUR == ':') {
2221 *prefix = ret;
2222 NEXT;
2223 ret = xmlNamespaceParseNCName(ctxt);
2224 }
2225
2226 return(ret);
2227}
2228
Daniel Veillard11e00581998-10-24 18:27:49 +00002229/**
Daniel Veillard517752b1999-04-05 12:20:10 +00002230 * xmlSplitQName:
2231 * @name: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002232 * @prefix: a xmlChar **
Daniel Veillard517752b1999-04-05 12:20:10 +00002233 *
2234 * parse an XML qualified name string
2235 *
2236 * [NS 5] QName ::= (Prefix ':')? LocalPart
2237 *
2238 * [NS 6] Prefix ::= NCName
2239 *
2240 * [NS 7] LocalPart ::= NCName
2241 *
Daniel Veillard51e3b151999-11-12 17:02:31 +00002242 * Returns the local part, and prefix is updated
Daniel Veillard517752b1999-04-05 12:20:10 +00002243 * to get the Prefix if any.
2244 */
2245
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002246xmlChar *
2247xmlSplitQName(const xmlChar *name, xmlChar **prefix) {
2248 xmlChar *ret = NULL;
2249 const xmlChar *q;
2250 const xmlChar *cur = name;
Daniel Veillard517752b1999-04-05 12:20:10 +00002251
2252 *prefix = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002253
2254 /* xml: prefix is not really a namespace */
2255 if ((cur[0] == 'x') && (cur[1] == 'm') &&
2256 (cur[2] == 'l') && (cur[3] == ':'))
2257 return(xmlStrdup(name));
2258
Daniel Veillard517752b1999-04-05 12:20:10 +00002259 if (!IS_LETTER(*cur) && (*cur != '_')) return(NULL);
2260 q = cur++;
2261
2262 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2263 (*cur == '.') || (*cur == '-') ||
2264 (*cur == '_') ||
2265 (IS_COMBINING(*cur)) ||
2266 (IS_EXTENDER(*cur)))
2267 cur++;
2268
2269 ret = xmlStrndup(q, cur - q);
2270
2271 if (*cur == ':') {
2272 cur++;
2273 if (!IS_LETTER(*cur) && (*cur != '_')) return(ret);
2274 *prefix = ret;
2275
2276 q = cur++;
2277
2278 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2279 (*cur == '.') || (*cur == '-') ||
2280 (*cur == '_') ||
2281 (IS_COMBINING(*cur)) ||
2282 (IS_EXTENDER(*cur)))
2283 cur++;
2284
2285 ret = xmlStrndup(q, cur - q);
2286 }
2287
2288 return(ret);
2289}
2290/**
Daniel Veillard11e00581998-10-24 18:27:49 +00002291 * xmlNamespaceParseNSDef:
2292 * @ctxt: an XML parser context
2293 *
2294 * parse a namespace prefix declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00002295 *
2296 * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral
2297 *
2298 * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)?
Daniel Veillard1e346af1999-02-22 10:33:01 +00002299 *
2300 * Returns the namespace name
Daniel Veillard260a68f1998-08-13 03:39:55 +00002301 */
2302
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002303xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002304xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002305 xmlChar *name = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002306
2307 if ((CUR == 'x') && (NXT(1) == 'm') &&
2308 (NXT(2) == 'l') && (NXT(3) == 'n') &&
2309 (NXT(4) == 's')) {
2310 SKIP(5);
2311 if (CUR == ':') {
2312 NEXT;
2313 name = xmlNamespaceParseNCName(ctxt);
2314 }
2315 }
2316 return(name);
2317}
2318
Daniel Veillard11e00581998-10-24 18:27:49 +00002319/**
2320 * xmlParseQuotedString:
2321 * @ctxt: an XML parser context
2322 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002323 * [OLD] Parse and return a string between quotes or doublequotes
Daniel Veillardb05deb71999-08-10 19:04:08 +00002324 * To be removed at next drop of binary compatibility
Daniel Veillard1e346af1999-02-22 10:33:01 +00002325 *
2326 * Returns the string parser or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002327 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002328xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002329xmlParseQuotedString(xmlParserCtxtPtr ctxt) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00002330 xmlChar *buf = NULL;
2331 int len = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002332 int size = XML_PARSER_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002333 xmlChar c;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002334
Daniel Veillard10a2c651999-12-12 13:03:50 +00002335 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
2336 if (buf == NULL) {
2337 fprintf(stderr, "malloc of %d byte failed\n", size);
2338 return(NULL);
2339 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002340 if (CUR == '"') {
2341 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002342 c = CUR;
2343 while (IS_CHAR(c) && (c != '"')) {
2344 if (len + 1 >= size) {
2345 size *= 2;
2346 buf = xmlRealloc(buf, size * sizeof(xmlChar));
2347 if (buf == NULL) {
2348 fprintf(stderr, "realloc of %d byte failed\n", size);
2349 return(NULL);
2350 }
2351 }
2352 buf[len++] = c;
2353 NEXT;
2354 c = CUR;
2355 }
2356 if (c != '"') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002357 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002358 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard10a2c651999-12-12 13:03:50 +00002359 ctxt->sax->error(ctxt->userData,
2360 "String not closed \"%.50s\"\n", buf);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002361 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002362 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002363 NEXT;
2364 }
2365 } else if (CUR == '\''){
2366 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002367 c = CUR;
2368 while (IS_CHAR(c) && (c != '\'')) {
2369 if (len + 1 >= size) {
2370 size *= 2;
2371 buf = xmlRealloc(buf, size * sizeof(xmlChar));
2372 if (buf == NULL) {
2373 fprintf(stderr, "realloc of %d byte failed\n", size);
2374 return(NULL);
2375 }
2376 }
2377 buf[len++] = c;
2378 NEXT;
2379 c = CUR;
2380 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002381 if (CUR != '\'') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002382 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002383 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard10a2c651999-12-12 13:03:50 +00002384 ctxt->sax->error(ctxt->userData,
2385 "String not closed \"%.50s\"\n", buf);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002386 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002387 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002388 NEXT;
2389 }
2390 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00002391 return(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002392}
2393
Daniel Veillard11e00581998-10-24 18:27:49 +00002394/**
2395 * xmlParseNamespace:
2396 * @ctxt: an XML parser context
2397 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002398 * [OLD] xmlParseNamespace: parse specific PI '<?namespace ...' constructs.
2399 *
2400 * This is what the older xml-name Working Draft specified, a bunch of
2401 * other stuff may still rely on it, so support is still here as
Daniel Veillard51e3b151999-11-12 17:02:31 +00002402 * if it was declared on the root of the Tree:-(
Daniel Veillardb05deb71999-08-10 19:04:08 +00002403 *
2404 * To be removed at next drop of binary compatibility
Daniel Veillard260a68f1998-08-13 03:39:55 +00002405 */
2406
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002407void
2408xmlParseNamespace(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002409 xmlChar *href = NULL;
2410 xmlChar *prefix = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002411 int garbage = 0;
2412
2413 /*
2414 * We just skipped "namespace" or "xml:namespace"
2415 */
2416 SKIP_BLANKS;
2417
2418 while (IS_CHAR(CUR) && (CUR != '>')) {
2419 /*
2420 * We can have "ns" or "prefix" attributes
2421 * Old encoding as 'href' or 'AS' attributes is still supported
2422 */
2423 if ((CUR == 'n') && (NXT(1) == 's')) {
2424 garbage = 0;
2425 SKIP(2);
2426 SKIP_BLANKS;
2427
2428 if (CUR != '=') continue;
2429 NEXT;
2430 SKIP_BLANKS;
2431
2432 href = xmlParseQuotedString(ctxt);
2433 SKIP_BLANKS;
2434 } else if ((CUR == 'h') && (NXT(1) == 'r') &&
2435 (NXT(2) == 'e') && (NXT(3) == 'f')) {
2436 garbage = 0;
2437 SKIP(4);
2438 SKIP_BLANKS;
2439
2440 if (CUR != '=') continue;
2441 NEXT;
2442 SKIP_BLANKS;
2443
2444 href = xmlParseQuotedString(ctxt);
2445 SKIP_BLANKS;
2446 } else if ((CUR == 'p') && (NXT(1) == 'r') &&
2447 (NXT(2) == 'e') && (NXT(3) == 'f') &&
2448 (NXT(4) == 'i') && (NXT(5) == 'x')) {
2449 garbage = 0;
2450 SKIP(6);
2451 SKIP_BLANKS;
2452
2453 if (CUR != '=') continue;
2454 NEXT;
2455 SKIP_BLANKS;
2456
2457 prefix = xmlParseQuotedString(ctxt);
2458 SKIP_BLANKS;
2459 } else if ((CUR == 'A') && (NXT(1) == 'S')) {
2460 garbage = 0;
2461 SKIP(2);
2462 SKIP_BLANKS;
2463
2464 if (CUR != '=') continue;
2465 NEXT;
2466 SKIP_BLANKS;
2467
2468 prefix = xmlParseQuotedString(ctxt);
2469 SKIP_BLANKS;
2470 } else if ((CUR == '?') && (NXT(1) == '>')) {
2471 garbage = 0;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002472 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002473 } else {
2474 /*
2475 * Found garbage when parsing the namespace
2476 */
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002477 if (!garbage) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002478 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002479 ctxt->sax->error(ctxt->userData,
2480 "xmlParseNamespace found garbage\n");
2481 }
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002482 ctxt->errNo = XML_ERR_NS_DECL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002483 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002484 NEXT;
2485 }
2486 }
2487
2488 MOVETO_ENDTAG(CUR_PTR);
2489 NEXT;
2490
2491 /*
2492 * Register the DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002493 if (href != NULL)
Daniel Veillard517752b1999-04-05 12:20:10 +00002494 if ((ctxt->sax != NULL) && (ctxt->sax->globalNamespace != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002495 ctxt->sax->globalNamespace(ctxt->userData, href, prefix);
Daniel Veillard517752b1999-04-05 12:20:10 +00002496 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00002497
Daniel Veillard6454aec1999-09-02 22:04:43 +00002498 if (prefix != NULL) xmlFree(prefix);
2499 if (href != NULL) xmlFree(href);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002500}
2501
2502/************************************************************************
2503 * *
2504 * The parser itself *
2505 * Relates to http://www.w3.org/TR/REC-xml *
2506 * *
2507 ************************************************************************/
2508
Daniel Veillard11e00581998-10-24 18:27:49 +00002509/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002510 * xmlScanName:
2511 * @ctxt: an XML parser context
2512 *
2513 * Trickery: parse an XML name but without consuming the input flow
2514 * Needed for rollback cases.
2515 *
2516 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
2517 * CombiningChar | Extender
2518 *
2519 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
2520 *
2521 * [6] Names ::= Name (S Name)*
2522 *
2523 * Returns the Name parsed or NULL
2524 */
2525
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002526xmlChar *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002527xmlScanName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002528 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb05deb71999-08-10 19:04:08 +00002529 int len = 0;
2530
2531 GROW;
2532 if (!IS_LETTER(CUR) && (CUR != '_') &&
2533 (CUR != ':')) {
2534 return(NULL);
2535 }
2536
2537 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
2538 (NXT(len) == '.') || (NXT(len) == '-') ||
2539 (NXT(len) == '_') || (NXT(len) == ':') ||
2540 (IS_COMBINING(NXT(len))) ||
2541 (IS_EXTENDER(NXT(len)))) {
2542 buf[len] = NXT(len);
2543 len++;
2544 if (len >= XML_MAX_NAMELEN) {
2545 fprintf(stderr,
2546 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
2547 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
2548 (NXT(len) == '.') || (NXT(len) == '-') ||
2549 (NXT(len) == '_') || (NXT(len) == ':') ||
2550 (IS_COMBINING(NXT(len))) ||
2551 (IS_EXTENDER(NXT(len))))
2552 len++;
2553 break;
2554 }
2555 }
2556 return(xmlStrndup(buf, len));
2557}
2558
2559/**
Daniel Veillard11e00581998-10-24 18:27:49 +00002560 * xmlParseName:
2561 * @ctxt: an XML parser context
2562 *
2563 * parse an XML name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002564 *
2565 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
2566 * CombiningChar | Extender
2567 *
2568 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
2569 *
2570 * [6] Names ::= Name (S Name)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00002571 *
2572 * Returns the Name parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002573 */
2574
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002575xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002576xmlParseName(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002577 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002578 int len = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002579 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002580
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002581 GROW;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002582 cur = CUR;
2583 if (!IS_LETTER(cur) && (cur != '_') &&
2584 (cur != ':')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002585 return(NULL);
2586 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002587
Daniel Veillardb05deb71999-08-10 19:04:08 +00002588 while ((IS_LETTER(cur)) || (IS_DIGIT(cur)) ||
2589 (cur == '.') || (cur == '-') ||
2590 (cur == '_') || (cur == ':') ||
2591 (IS_COMBINING(cur)) ||
2592 (IS_EXTENDER(cur))) {
2593 buf[len++] = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002594 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002595 cur = CUR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002596 if (len >= XML_MAX_NAMELEN) {
2597 fprintf(stderr,
2598 "xmlParseName: reached XML_MAX_NAMELEN limit\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00002599 while ((IS_LETTER(cur)) || (IS_DIGIT(cur)) ||
2600 (cur == '.') || (cur == '-') ||
2601 (cur == '_') || (cur == ':') ||
2602 (IS_COMBINING(cur)) ||
2603 (IS_EXTENDER(cur))) {
2604 NEXT;
2605 cur = CUR;
2606 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002607 break;
2608 }
2609 }
2610 return(xmlStrndup(buf, len));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002611}
2612
Daniel Veillard11e00581998-10-24 18:27:49 +00002613/**
Daniel Veillard10a2c651999-12-12 13:03:50 +00002614 * xmlParseStringName:
2615 * @ctxt: an XML parser context
2616 * @str: a pointer to an index in the string
2617 *
2618 * parse an XML name.
2619 *
2620 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
2621 * CombiningChar | Extender
2622 *
2623 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
2624 *
2625 * [6] Names ::= Name (S Name)*
2626 *
2627 * Returns the Name parsed or NULL. The str pointer
2628 * is updated to the current location in the string.
2629 */
2630
2631xmlChar *
2632xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) {
2633 const xmlChar *ptr;
2634 const xmlChar *start;
2635 xmlChar cur;
2636
2637 if ((str == NULL) || (*str == NULL)) return(NULL);
2638
2639 start = ptr = *str;
2640 cur = *ptr;
2641 if (!IS_LETTER(cur) && (cur != '_') &&
2642 (cur != ':')) {
2643 return(NULL);
2644 }
2645
2646 while ((IS_LETTER(cur)) || (IS_DIGIT(cur)) ||
2647 (cur == '.') || (cur == '-') ||
2648 (cur == '_') || (cur == ':') ||
2649 (IS_COMBINING(cur)) ||
2650 (IS_EXTENDER(cur))) {
2651 ptr++;
2652 cur = *ptr;
2653 }
2654 *str = ptr;
2655 return(xmlStrndup(start, ptr - start ));
2656}
2657
2658/**
Daniel Veillard11e00581998-10-24 18:27:49 +00002659 * xmlParseNmtoken:
2660 * @ctxt: an XML parser context
2661 *
2662 * parse an XML Nmtoken.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002663 *
2664 * [7] Nmtoken ::= (NameChar)+
2665 *
2666 * [8] Nmtokens ::= Nmtoken (S Nmtoken)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00002667 *
2668 * Returns the Nmtoken parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002669 */
2670
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002671xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002672xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002673 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002674 int len = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002675
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002676 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002677 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2678 (CUR == '.') || (CUR == '-') ||
2679 (CUR == '_') || (CUR == ':') ||
2680 (IS_COMBINING(CUR)) ||
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002681 (IS_EXTENDER(CUR))) {
2682 buf[len++] = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002683 NEXT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002684 if (len >= XML_MAX_NAMELEN) {
2685 fprintf(stderr,
2686 "xmlParseNmtoken: reached XML_MAX_NAMELEN limit\n");
2687 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
2688 (CUR == '.') || (CUR == '-') ||
2689 (CUR == '_') || (CUR == ':') ||
2690 (IS_COMBINING(CUR)) ||
2691 (IS_EXTENDER(CUR)))
2692 NEXT;
2693 break;
2694 }
2695 }
2696 return(xmlStrndup(buf, len));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002697}
2698
Daniel Veillard11e00581998-10-24 18:27:49 +00002699/**
2700 * xmlParseEntityValue:
2701 * @ctxt: an XML parser context
Daniel Veillard011b63c1999-06-02 17:44:04 +00002702 * @orig: if non-NULL store a copy of the original entity value
Daniel Veillard11e00581998-10-24 18:27:49 +00002703 *
2704 * parse a value for ENTITY decl.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002705 *
2706 * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
2707 * "'" ([^%&'] | PEReference | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00002708 *
Daniel Veillard011b63c1999-06-02 17:44:04 +00002709 * Returns the EntityValue parsed with reference substitued or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002710 */
2711
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002712xmlChar *
2713xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00002714 xmlChar *buf = NULL;
2715 int len = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002716 int size = XML_PARSER_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002717 xmlChar c;
2718 xmlChar stop;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002719 xmlChar *ret = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002720 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002721
Daniel Veillard10a2c651999-12-12 13:03:50 +00002722 if (CUR == '"') stop = '"';
2723 else if (CUR == '\'') stop = '\'';
2724 else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002725 ctxt->errNo = XML_ERR_ENTITY_NOT_STARTED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002726 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00002727 ctxt->sax->error(ctxt->userData, "EntityValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002728 ctxt->wellFormed = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002729 return(NULL);
2730 }
2731 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
2732 if (buf == NULL) {
2733 fprintf(stderr, "malloc of %d byte failed\n", size);
2734 return(NULL);
2735 }
2736
2737 /*
2738 * The content of the entity definition is copied in a buffer.
2739 */
2740
2741 ctxt->instate = XML_PARSER_ENTITY_VALUE;
2742 input = ctxt->input;
2743 GROW;
2744 NEXT;
2745 c = CUR;
2746 /*
2747 * NOTE: 4.4.5 Included in Literal
2748 * When a parameter entity reference appears in a literal entity
2749 * value, ... a single or double quote character in the replacement
2750 * text is always treated as a normal data character and will not
2751 * terminate the literal.
2752 * In practice it means we stop the loop only when back at parsing
2753 * the initial entity and the quote is found
2754 */
2755 while (IS_CHAR(c) && ((c != stop) || (ctxt->input != input))) {
2756 if (len + 1 >= size) {
2757 size *= 2;
2758 buf = xmlRealloc(buf, size * sizeof(xmlChar));
2759 if (buf == NULL) {
2760 fprintf(stderr, "realloc of %d byte failed\n", size);
2761 return(NULL);
2762 }
2763 }
2764 buf[len++] = c;
2765 NEXT;
2766 /*
2767 * Pop-up of finished entities.
2768 */
2769 while ((CUR == 0) && (ctxt->inputNr > 1))
2770 xmlPopInput(ctxt);
2771 c = CUR;
2772 if (c == 0) {
2773 GROW;
2774 c = CUR;
2775 }
2776 }
2777 buf[len] = 0;
2778
2779 /*
2780 * Then PEReference entities are substituted.
2781 */
2782 if (c != stop) {
2783 ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
2784 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2785 ctxt->sax->error(ctxt->userData, "EntityValue: \" expected\n");
2786 ctxt->wellFormed = 0;
2787 } else {
2788 NEXT;
2789 /*
2790 * NOTE: 4.4.7 Bypassed
2791 * When a general entity reference appears in the EntityValue in
2792 * an entity declaration, it is bypassed and left as is.
2793 * so XML_SUBSTITUTE_REF is not set.
2794 */
2795 ret = xmlStringDecodeEntities(ctxt, buf, XML_SUBSTITUTE_PEREF,
2796 0, 0, 0);
2797 if (orig != NULL)
2798 *orig = buf;
2799 else
2800 xmlFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002801 }
2802
2803 return(ret);
2804}
2805
Daniel Veillard11e00581998-10-24 18:27:49 +00002806/**
2807 * xmlParseAttValue:
2808 * @ctxt: an XML parser context
2809 *
2810 * parse a value for an attribute
Daniel Veillard011b63c1999-06-02 17:44:04 +00002811 * Note: the parser won't do substitution of entities here, this
Daniel Veillardb96e6431999-08-29 21:02:19 +00002812 * will be handled later in xmlStringGetNodeList
Daniel Veillard260a68f1998-08-13 03:39:55 +00002813 *
2814 * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
2815 * "'" ([^<&'] | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00002816 *
Daniel Veillard7f858501999-11-17 17:32:38 +00002817 * 3.3.3 Attribute-Value Normalization:
2818 * Before the value of an attribute is passed to the application or
2819 * checked for validity, the XML processor must normalize it as follows:
2820 * - a character reference is processed by appending the referenced
2821 * character to the attribute value
2822 * - an entity reference is processed by recursively processing the
2823 * replacement text of the entity
2824 * - a whitespace character (#x20, #xD, #xA, #x9) is processed by
2825 * appending #x20 to the normalized value, except that only a single
2826 * #x20 is appended for a "#xD#xA" sequence that is part of an external
2827 * parsed entity or the literal entity value of an internal parsed entity
2828 * - other characters are processed by appending them to the normalized value
Daniel Veillard07136651999-11-18 14:02:05 +00002829 * If the declared value is not CDATA, then the XML processor must further
2830 * process the normalized attribute value by discarding any leading and
2831 * trailing space (#x20) characters, and by replacing sequences of space
2832 * (#x20) characters by a single space (#x20) character.
2833 * All attributes for which no declaration has been read should be treated
2834 * by a non-validating parser as if declared CDATA.
Daniel Veillard7f858501999-11-17 17:32:38 +00002835 *
2836 * Returns the AttValue parsed or NULL. The value has to be freed by the caller.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002837 */
2838
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002839xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002840xmlParseAttValue(xmlParserCtxtPtr ctxt) {
Daniel Veillard7f858501999-11-17 17:32:38 +00002841 xmlChar limit = 0;
2842 xmlChar *buffer = NULL;
2843 int buffer_size = 0;
2844 xmlChar *out = NULL;
2845
2846 xmlChar *current = NULL;
2847 xmlEntityPtr ent;
2848 xmlChar cur;
Daniel Veillard7f858501999-11-17 17:32:38 +00002849
Daniel Veillard260a68f1998-08-13 03:39:55 +00002850
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002851 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002852 if (CUR == '"') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002853 ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
Daniel Veillard7f858501999-11-17 17:32:38 +00002854 limit = '"';
Daniel Veillard260a68f1998-08-13 03:39:55 +00002855 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002856 } else if (CUR == '\'') {
Daniel Veillard7f858501999-11-17 17:32:38 +00002857 limit = '\'';
Daniel Veillardb05deb71999-08-10 19:04:08 +00002858 ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002859 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002860 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002861 ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_STARTED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002862 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002863 ctxt->sax->error(ctxt->userData, "AttValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002864 ctxt->wellFormed = 0;
Daniel Veillard7f858501999-11-17 17:32:38 +00002865 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002866 }
2867
Daniel Veillard7f858501999-11-17 17:32:38 +00002868 /*
2869 * allocate a translation buffer.
2870 */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002871 buffer_size = XML_PARSER_BUFFER_SIZE;
Daniel Veillard7f858501999-11-17 17:32:38 +00002872 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
2873 if (buffer == NULL) {
2874 perror("xmlParseAttValue: malloc failed");
2875 return(NULL);
2876 }
2877 out = buffer;
2878
2879 /*
2880 * Ok loop until we reach one of the ending char or a size limit.
2881 */
2882 cur = CUR;
2883 while ((cur != limit) && (cur != '<')) {
Daniel Veillard7f858501999-11-17 17:32:38 +00002884 if (cur == 0) break;
2885 if ((cur == '&') && (NXT(1) == '#')) {
2886 int val = xmlParseCharRef(ctxt);
2887 *out++ = val;
Daniel Veillard7f858501999-11-17 17:32:38 +00002888 } else if (cur == '&') {
2889 ent = xmlParseEntityRef(ctxt);
2890 if ((ent != NULL) &&
2891 (ctxt->replaceEntities != 0)) {
2892 current = ent->content;
2893 while (*current != 0) {
2894 *out++ = *current++;
2895 if (out - buffer > buffer_size - 10) {
2896 int index = out - buffer;
2897
2898 growBuffer(buffer);
2899 out = &buffer[index];
2900 }
2901 }
2902 } else if (ent != NULL) {
2903 int i = xmlStrlen(ent->name);
2904 const xmlChar *cur = ent->name;
2905
2906 *out++ = '&';
2907 if (out - buffer > buffer_size - i - 10) {
2908 int index = out - buffer;
2909
2910 growBuffer(buffer);
2911 out = &buffer[index];
2912 }
2913 for (;i > 0;i--)
2914 *out++ = *cur++;
2915 *out++ = ';';
2916 }
Daniel Veillard7f858501999-11-17 17:32:38 +00002917 } else {
2918 /* invalid for UTF-8 , use COPY(out); !!!!!! */
2919 if ((cur == 0x20) || (cur == 0xD) || (cur == 0xA) || (cur == 0x9)) {
Daniel Veillard07136651999-11-18 14:02:05 +00002920 *out++ = 0x20;
2921 if (out - buffer > buffer_size - 10) {
2922 int index = out - buffer;
2923
2924 growBuffer(buffer);
2925 out = &buffer[index];
Daniel Veillard7f858501999-11-17 17:32:38 +00002926 }
Daniel Veillard7f858501999-11-17 17:32:38 +00002927 } else {
2928 *out++ = cur;
2929 if (out - buffer > buffer_size - 10) {
2930 int index = out - buffer;
2931
2932 growBuffer(buffer);
2933 out = &buffer[index];
2934 }
Daniel Veillard7f858501999-11-17 17:32:38 +00002935 }
2936 NEXT;
2937 }
2938 cur = CUR;
2939 }
2940 *out++ = 0;
2941 if (CUR == '<') {
2942 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2943 ctxt->sax->error(ctxt->userData,
2944 "Unescaped '<' not allowed in attributes values\n");
2945 ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
2946 ctxt->wellFormed = 0;
2947 } else if (CUR != limit) {
2948 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2949 ctxt->sax->error(ctxt->userData, "AttValue: ' expected\n");
2950 ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_FINISHED;
2951 ctxt->wellFormed = 0;
2952 } else
2953 NEXT;
2954 return(buffer);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002955}
2956
Daniel Veillard11e00581998-10-24 18:27:49 +00002957/**
2958 * xmlParseSystemLiteral:
2959 * @ctxt: an XML parser context
2960 *
2961 * parse an XML Literal
Daniel Veillard260a68f1998-08-13 03:39:55 +00002962 *
2963 * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
Daniel Veillard1e346af1999-02-22 10:33:01 +00002964 *
2965 * Returns the SystemLiteral parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00002966 */
2967
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002968xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002969xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00002970 xmlChar *buf = NULL;
2971 int len = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002972 int size = XML_PARSER_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002973 xmlChar cur;
2974 xmlChar stop;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002975
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002976 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002977 if (CUR == '"') {
2978 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002979 stop = '"';
Daniel Veillard260a68f1998-08-13 03:39:55 +00002980 } else if (CUR == '\'') {
2981 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002982 stop = '\'';
Daniel Veillard260a68f1998-08-13 03:39:55 +00002983 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002984 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00002985 ctxt->sax->error(ctxt->userData,
2986 "SystemLiteral \" or ' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002987 ctxt->errNo = XML_ERR_LITERAL_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002988 ctxt->wellFormed = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00002989 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002990 }
2991
Daniel Veillard10a2c651999-12-12 13:03:50 +00002992 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
2993 if (buf == NULL) {
2994 fprintf(stderr, "malloc of %d byte failed\n", size);
2995 return(NULL);
2996 }
2997 cur = CUR;
2998 while ((IS_CHAR(cur)) && (cur != stop)) {
2999 if (len + 1 >= size) {
3000 size *= 2;
3001 buf = xmlRealloc(buf, size * sizeof(xmlChar));
3002 if (buf == NULL) {
3003 fprintf(stderr, "realloc of %d byte failed\n", size);
3004 return(NULL);
3005 }
3006 }
3007 buf[len++] = cur;
3008 NEXT;
3009 cur = CUR;
3010 if (cur == 0) {
3011 GROW;
3012 SHRINK;
3013 cur = CUR;
3014 }
3015 }
3016 buf[len] = 0;
3017 if (!IS_CHAR(cur)) {
3018 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3019 ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
3020 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
3021 ctxt->wellFormed = 0;
3022 } else {
3023 NEXT;
3024 }
3025 return(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003026}
3027
Daniel Veillard11e00581998-10-24 18:27:49 +00003028/**
3029 * xmlParsePubidLiteral:
3030 * @ctxt: an XML parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +00003031 *
Daniel Veillard11e00581998-10-24 18:27:49 +00003032 * parse an XML public literal
Daniel Veillard1e346af1999-02-22 10:33:01 +00003033 *
3034 * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
3035 *
3036 * Returns the PubidLiteral parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003037 */
3038
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003039xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003040xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003041 xmlChar *buf = NULL;
3042 int len = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003043 int size = XML_PARSER_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003044 xmlChar cur;
3045 xmlChar stop;
Daniel Veillard6077d031999-10-09 09:11:45 +00003046
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003047 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003048 if (CUR == '"') {
3049 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003050 stop = '"';
Daniel Veillard260a68f1998-08-13 03:39:55 +00003051 } else if (CUR == '\'') {
3052 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003053 stop = '\'';
Daniel Veillard260a68f1998-08-13 03:39:55 +00003054 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003055 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003056 ctxt->sax->error(ctxt->userData,
3057 "SystemLiteral \" or ' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003058 ctxt->errNo = XML_ERR_LITERAL_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003059 ctxt->wellFormed = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003060 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003061 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003062 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
3063 if (buf == NULL) {
3064 fprintf(stderr, "malloc of %d byte failed\n", size);
3065 return(NULL);
3066 }
3067 cur = CUR;
3068 while ((IS_PUBIDCHAR(cur)) && (cur != stop)) {
3069 if (len + 1 >= size) {
3070 size *= 2;
3071 buf = xmlRealloc(buf, size * sizeof(xmlChar));
3072 if (buf == NULL) {
3073 fprintf(stderr, "realloc of %d byte failed\n", size);
3074 return(NULL);
3075 }
3076 }
3077 buf[len++] = cur;
3078 NEXT;
3079 cur = CUR;
3080 if (cur == 0) {
3081 GROW;
3082 SHRINK;
3083 cur = CUR;
3084 }
3085 }
3086 buf[len] = 0;
3087 if (cur != stop) {
3088 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3089 ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
3090 ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
3091 ctxt->wellFormed = 0;
3092 } else {
3093 NEXT;
3094 }
3095 return(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003096}
3097
Daniel Veillard11e00581998-10-24 18:27:49 +00003098/**
3099 * xmlParseCharData:
3100 * @ctxt: an XML parser context
3101 * @cdata: int indicating whether we are within a CDATA section
3102 *
3103 * parse a CharData section.
3104 * if we are within a CDATA section ']]>' marks an end of section.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003105 *
3106 * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
3107 */
3108
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003109void
3110xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003111 xmlChar buf[XML_PARSER_BIG_BUFFER_SIZE];
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003112 int nbchar = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003113 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003114
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003115 SHRINK;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003116 cur = CUR;
3117 while ((IS_CHAR(cur)) && (cur != '<') &&
3118 (cur != '&')) {
3119 if ((cur == ']') && (NXT(1) == ']') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003120 (NXT(2) == '>')) {
3121 if (cdata) break;
3122 else {
3123 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003124 ctxt->sax->warning(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003125 "Sequence ']]>' not allowed in content\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003126 ctxt->errNo = XML_ERR_MISPLACED_CDATA_END;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003127 }
3128 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003129 buf[nbchar++] = CUR;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003130 if (nbchar == XML_PARSER_BIG_BUFFER_SIZE) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003131 /*
3132 * Ok the segment is to be consumed as chars.
3133 */
3134 if (ctxt->sax != NULL) {
3135 if (areBlanks(ctxt, buf, nbchar)) {
3136 if (ctxt->sax->ignorableWhitespace != NULL)
3137 ctxt->sax->ignorableWhitespace(ctxt->userData,
3138 buf, nbchar);
3139 } else {
3140 if (ctxt->sax->characters != NULL)
3141 ctxt->sax->characters(ctxt->userData, buf, nbchar);
3142 }
3143 }
3144 nbchar = 0;
3145 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003146 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003147 cur = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003148 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003149 if (nbchar != 0) {
3150 /*
3151 * Ok the segment is to be consumed as chars.
3152 */
3153 if (ctxt->sax != NULL) {
3154 if (areBlanks(ctxt, buf, nbchar)) {
3155 if (ctxt->sax->ignorableWhitespace != NULL)
3156 ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar);
3157 } else {
3158 if (ctxt->sax->characters != NULL)
3159 ctxt->sax->characters(ctxt->userData, buf, nbchar);
3160 }
3161 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003162 }
3163}
3164
Daniel Veillard11e00581998-10-24 18:27:49 +00003165/**
3166 * xmlParseExternalID:
3167 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003168 * @publicID: a xmlChar** receiving PubidLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00003169 * @strict: indicate whether we should restrict parsing to only
3170 * production [75], see NOTE below
Daniel Veillard11e00581998-10-24 18:27:49 +00003171 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003172 * Parse an External ID or a Public ID
3173 *
3174 * NOTE: Productions [75] and [83] interract badly since [75] can generate
3175 * 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard260a68f1998-08-13 03:39:55 +00003176 *
3177 * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
3178 * | 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00003179 *
3180 * [83] PublicID ::= 'PUBLIC' S PubidLiteral
3181 *
3182 * Returns the function returns SystemLiteral and in the second
3183 * case publicID receives PubidLiteral, is strict is off
3184 * it is possible to return NULL and have publicID set.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003185 */
3186
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003187xmlChar *
3188xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) {
3189 xmlChar *URI = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003190
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003191 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003192 if ((CUR == 'S') && (NXT(1) == 'Y') &&
3193 (NXT(2) == 'S') && (NXT(3) == 'T') &&
3194 (NXT(4) == 'E') && (NXT(5) == 'M')) {
3195 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003196 if (!IS_BLANK(CUR)) {
3197 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003198 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003199 "Space required after 'SYSTEM'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003200 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003201 ctxt->wellFormed = 0;
3202 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003203 SKIP_BLANKS;
3204 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003205 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003206 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003207 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003208 "xmlParseExternalID: SYSTEM, no URI\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003209 ctxt->errNo = XML_ERR_URI_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003210 ctxt->wellFormed = 0;
3211 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003212 } else if ((CUR == 'P') && (NXT(1) == 'U') &&
3213 (NXT(2) == 'B') && (NXT(3) == 'L') &&
3214 (NXT(4) == 'I') && (NXT(5) == 'C')) {
3215 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003216 if (!IS_BLANK(CUR)) {
3217 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003218 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003219 "Space required after 'PUBLIC'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003220 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003221 ctxt->wellFormed = 0;
3222 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003223 SKIP_BLANKS;
3224 *publicID = xmlParsePubidLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003225 if (*publicID == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003226 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003227 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003228 "xmlParseExternalID: PUBLIC, no Public Identifier\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003229 ctxt->errNo = XML_ERR_PUBID_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003230 ctxt->wellFormed = 0;
3231 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00003232 if (strict) {
3233 /*
3234 * We don't handle [83] so "S SystemLiteral" is required.
3235 */
3236 if (!IS_BLANK(CUR)) {
3237 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003238 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003239 "Space required after the Public Identifier\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003240 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003241 ctxt->wellFormed = 0;
3242 }
3243 } else {
3244 /*
3245 * We handle [83] so we return immediately, if
3246 * "S SystemLiteral" is not detected. From a purely parsing
3247 * point of view that's a nice mess.
3248 */
Daniel Veillard10a2c651999-12-12 13:03:50 +00003249 const xmlChar *ptr;
3250 GROW;
3251
3252 ptr = CUR_PTR;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003253 if (!IS_BLANK(*ptr)) return(NULL);
3254
3255 while (IS_BLANK(*ptr)) ptr++;
3256 if ((*ptr != '\'') || (*ptr != '"')) return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003257 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003258 SKIP_BLANKS;
3259 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003260 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003261 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003262 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003263 "xmlParseExternalID: PUBLIC, no URI\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003264 ctxt->errNo = XML_ERR_URI_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003265 ctxt->wellFormed = 0;
3266 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003267 }
3268 return(URI);
3269}
3270
Daniel Veillard11e00581998-10-24 18:27:49 +00003271/**
3272 * xmlParseComment:
Daniel Veillard1e346af1999-02-22 10:33:01 +00003273 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00003274 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00003275 * Skip an XML (SGML) comment <!-- .... -->
Daniel Veillard260a68f1998-08-13 03:39:55 +00003276 * The spec says that "For compatibility, the string "--" (double-hyphen)
3277 * must not occur within comments. "
3278 *
3279 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
3280 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003281void
Daniel Veillardb96e6431999-08-29 21:02:19 +00003282xmlParseComment(xmlParserCtxtPtr ctxt) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003283 xmlChar *buf = NULL;
3284 int len = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003285 int size = XML_PARSER_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003286 xmlChar q;
3287 xmlChar r;
3288 xmlChar cur;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003289 xmlParserInputState state;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003290
3291 /*
3292 * Check that there is a comment right here.
3293 */
3294 if ((CUR != '<') || (NXT(1) != '!') ||
Daniel Veillard517752b1999-04-05 12:20:10 +00003295 (NXT(2) != '-') || (NXT(3) != '-')) return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003296
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003297 state = ctxt->instate;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003298 ctxt->instate = XML_PARSER_COMMENT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003299 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003300 SKIP(4);
Daniel Veillard10a2c651999-12-12 13:03:50 +00003301 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
3302 if (buf == NULL) {
3303 fprintf(stderr, "malloc of %d byte failed\n", size);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003304 ctxt->instate = state;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003305 return;
3306 }
3307 q = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003308 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003309 r = CUR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003310 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003311 cur = CUR;
3312 while (IS_CHAR(cur) &&
3313 ((cur != '>') ||
3314 (r != '-') || (q != '-'))) {
3315 if ((r == '-') && (q == '-')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003316 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003317 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003318 "Comment must not contain '--' (double-hyphen)`\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003319 ctxt->errNo = XML_ERR_HYPHEN_IN_COMMENT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003320 ctxt->wellFormed = 0;
3321 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003322 if (len + 1 >= size) {
3323 size *= 2;
3324 buf = xmlRealloc(buf, size * sizeof(xmlChar));
3325 if (buf == NULL) {
3326 fprintf(stderr, "realloc of %d byte failed\n", size);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003327 ctxt->instate = state;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003328 return;
3329 }
3330 }
3331 buf[len++] = q;
3332 q = r;
3333 r = cur;
3334 NEXT;
3335 cur = CUR;
3336 if (cur == 0) {
3337 SHRINK;
3338 GROW;
3339 cur = CUR;
3340 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003341 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003342 buf[len] = 0;
3343 if (!IS_CHAR(cur)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003344 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003345 ctxt->sax->error(ctxt->userData,
Daniel Veillard10a2c651999-12-12 13:03:50 +00003346 "Comment not terminated \n<!--%.50s\n", buf);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003347 ctxt->errNo = XML_ERR_COMMENT_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003348 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003349 } else {
3350 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003351 if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL))
Daniel Veillard10a2c651999-12-12 13:03:50 +00003352 ctxt->sax->comment(ctxt->userData, buf);
3353 xmlFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003354 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003355 ctxt->instate = state;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003356}
3357
Daniel Veillard11e00581998-10-24 18:27:49 +00003358/**
3359 * xmlParsePITarget:
3360 * @ctxt: an XML parser context
3361 *
3362 * parse the name of a PI
Daniel Veillard260a68f1998-08-13 03:39:55 +00003363 *
3364 * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00003365 *
3366 * Returns the PITarget name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003367 */
3368
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003369xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003370xmlParsePITarget(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003371 xmlChar *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003372
3373 name = xmlParseName(ctxt);
Daniel Veillard3c558c31999-12-22 11:30:41 +00003374 if ((name != NULL) &&
Daniel Veillard260a68f1998-08-13 03:39:55 +00003375 ((name[0] == 'x') || (name[0] == 'X')) &&
3376 ((name[1] == 'm') || (name[1] == 'M')) &&
3377 ((name[2] == 'l') || (name[2] == 'L'))) {
Daniel Veillard3c558c31999-12-22 11:30:41 +00003378 int i;
3379 for (i = 0;;i++) {
3380 if (xmlW3CPIs[i] == NULL) break;
3381 if (!xmlStrcmp(name, (const xmlChar *)xmlW3CPIs[i]))
3382 return(name);
3383 }
3384 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) {
3385 ctxt->sax->warning(ctxt->userData,
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003386 "xmlParsePItarget: invalid name prefix 'xml'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003387 ctxt->errNo = XML_ERR_RESERVED_XML_NAME;
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003388 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003389 }
3390 return(name);
3391}
3392
Daniel Veillard11e00581998-10-24 18:27:49 +00003393/**
3394 * xmlParsePI:
3395 * @ctxt: an XML parser context
3396 *
3397 * parse an XML Processing Instruction.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003398 *
3399 * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
Daniel Veillard1e346af1999-02-22 10:33:01 +00003400 *
3401 * The processing is transfered to SAX once parsed.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003402 */
3403
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003404void
3405xmlParsePI(xmlParserCtxtPtr ctxt) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003406 xmlChar *buf = NULL;
3407 int len = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003408 int size = XML_PARSER_BUFFER_SIZE;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003409 xmlChar cur;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003410 xmlChar *target;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003411 xmlParserInputState state;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003412
3413 if ((CUR == '<') && (NXT(1) == '?')) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003414 state = ctxt->instate;
3415 ctxt->instate = XML_PARSER_PI;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003416 /*
3417 * this is a Processing Instruction.
3418 */
3419 SKIP(2);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003420 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003421
3422 /*
3423 * Parse the target name and check for special support like
3424 * namespace.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003425 */
3426 target = xmlParsePITarget(ctxt);
3427 if (target != NULL) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00003428 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
3429 if (buf == NULL) {
3430 fprintf(stderr, "malloc of %d byte failed\n", size);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003431 ctxt->instate = state;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003432 return;
3433 }
3434 cur = CUR;
3435 if (!IS_BLANK(cur)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003436 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3437 ctxt->sax->error(ctxt->userData,
3438 "xmlParsePI: PI %s space expected\n", target);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003439 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003440 ctxt->wellFormed = 0;
3441 }
3442 SKIP_BLANKS;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003443 cur = CUR;
3444 while (IS_CHAR(cur) &&
3445 ((cur != '?') || (NXT(1) != '>'))) {
3446 if (len + 1 >= size) {
3447 size *= 2;
3448 buf = xmlRealloc(buf, size * sizeof(xmlChar));
3449 if (buf == NULL) {
3450 fprintf(stderr, "realloc of %d byte failed\n", size);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003451 ctxt->instate = state;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003452 return;
3453 }
3454 }
3455 buf[len++] = cur;
Daniel Veillard517752b1999-04-05 12:20:10 +00003456 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00003457 cur = CUR;
3458 if (cur == 0) {
3459 SHRINK;
3460 GROW;
3461 cur = CUR;
3462 }
3463 }
3464 buf[len] = 0;
3465 if (!IS_CHAR(cur)) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003466 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003467 ctxt->sax->error(ctxt->userData,
Daniel Veillard517752b1999-04-05 12:20:10 +00003468 "xmlParsePI: PI %s never end ...\n", target);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003469 ctxt->errNo = XML_ERR_PI_NOT_FINISHED;
Daniel Veillard517752b1999-04-05 12:20:10 +00003470 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003471 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00003472 SKIP(2);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003473
Daniel Veillard517752b1999-04-05 12:20:10 +00003474 /*
3475 * SAX: PI detected.
3476 */
3477 if ((ctxt->sax) &&
3478 (ctxt->sax->processingInstruction != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00003479 ctxt->sax->processingInstruction(ctxt->userData,
Daniel Veillard10a2c651999-12-12 13:03:50 +00003480 target, buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003481 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00003482 xmlFree(buf);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003483 xmlFree(target);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003484 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003485 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00003486 ctxt->sax->error(ctxt->userData,
3487 "xmlParsePI : no target name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003488 ctxt->errNo = XML_ERR_PI_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003489 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003490 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003491 ctxt->instate = state;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003492 }
3493}
3494
Daniel Veillard11e00581998-10-24 18:27:49 +00003495/**
3496 * xmlParseNotationDecl:
3497 * @ctxt: an XML parser context
3498 *
3499 * parse a notation declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003500 *
3501 * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
3502 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00003503 * Hence there is actually 3 choices:
3504 * 'PUBLIC' S PubidLiteral
3505 * 'PUBLIC' S PubidLiteral S SystemLiteral
3506 * and 'SYSTEM' S SystemLiteral
Daniel Veillard11e00581998-10-24 18:27:49 +00003507 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003508 * See the NOTE on xmlParseExternalID().
Daniel Veillard260a68f1998-08-13 03:39:55 +00003509 */
3510
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003511void
3512xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003513 xmlChar *name;
3514 xmlChar *Pubid;
3515 xmlChar *Systemid;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003516
3517 if ((CUR == '<') && (NXT(1) == '!') &&
3518 (NXT(2) == 'N') && (NXT(3) == 'O') &&
3519 (NXT(4) == 'T') && (NXT(5) == 'A') &&
3520 (NXT(6) == 'T') && (NXT(7) == 'I') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00003521 (NXT(8) == 'O') && (NXT(9) == 'N')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003522 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003523 SKIP(10);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003524 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003525 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003526 ctxt->sax->error(ctxt->userData,
3527 "Space required after '<!NOTATION'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003528 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003529 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003530 return;
3531 }
3532 SKIP_BLANKS;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003533
3534 name = xmlParseName(ctxt);
3535 if (name == NULL) {
3536 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003537 ctxt->sax->error(ctxt->userData,
3538 "NOTATION: Name expected here\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003539 ctxt->errNo = XML_ERR_NOTATION_NOT_STARTED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003540 ctxt->wellFormed = 0;
3541 return;
3542 }
3543 if (!IS_BLANK(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 "Space required after the NOTATION name'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003547 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003548 ctxt->wellFormed = 0;
3549 return;
3550 }
3551 SKIP_BLANKS;
3552
Daniel Veillard260a68f1998-08-13 03:39:55 +00003553 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00003554 * Parse the IDs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003555 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00003556 Systemid = xmlParseExternalID(ctxt, &Pubid, 1);
3557 SKIP_BLANKS;
3558
3559 if (CUR == '>') {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003560 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00003561 if ((ctxt->sax != NULL) && (ctxt->sax->notationDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003562 ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003563 } else {
3564 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003565 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003566 "'>' required to close NOTATION declaration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003567 ctxt->errNo = XML_ERR_NOTATION_NOT_FINISHED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003568 ctxt->wellFormed = 0;
3569 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00003570 xmlFree(name);
3571 if (Systemid != NULL) xmlFree(Systemid);
3572 if (Pubid != NULL) xmlFree(Pubid);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003573 }
3574}
3575
Daniel Veillard11e00581998-10-24 18:27:49 +00003576/**
3577 * xmlParseEntityDecl:
3578 * @ctxt: an XML parser context
3579 *
3580 * parse <!ENTITY declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00003581 *
3582 * [70] EntityDecl ::= GEDecl | PEDecl
3583 *
3584 * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
3585 *
3586 * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
3587 *
3588 * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
3589 *
3590 * [74] PEDef ::= EntityValue | ExternalID
3591 *
3592 * [76] NDataDecl ::= S 'NDATA' S Name
Daniel Veillardb05deb71999-08-10 19:04:08 +00003593 *
3594 * [ VC: Notation Declared ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003595 * The Name must match the declared name of a notation.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003596 */
3597
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003598void
3599xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003600 xmlChar *name = NULL;
3601 xmlChar *value = NULL;
3602 xmlChar *URI = NULL, *literal = NULL;
3603 xmlChar *ndata = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003604 int isParameter = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003605 xmlChar *orig = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003606
Daniel Veillardb05deb71999-08-10 19:04:08 +00003607 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003608 if ((CUR == '<') && (NXT(1) == '!') &&
3609 (NXT(2) == 'E') && (NXT(3) == 'N') &&
3610 (NXT(4) == 'T') && (NXT(5) == 'I') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003611 (NXT(6) == 'T') && (NXT(7) == 'Y')) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003612 ctxt->instate = XML_PARSER_ENTITY_DECL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003613 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003614 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003615 if (!IS_BLANK(CUR)) {
3616 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003617 ctxt->sax->error(ctxt->userData,
3618 "Space required after '<!ENTITY'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003619 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003620 ctxt->wellFormed = 0;
3621 }
3622 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003623
3624 if (CUR == '%') {
3625 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003626 if (!IS_BLANK(CUR)) {
3627 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003628 ctxt->sax->error(ctxt->userData,
3629 "Space required after '%'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003630 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003631 ctxt->wellFormed = 0;
3632 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003633 SKIP_BLANKS;
3634 isParameter = 1;
3635 }
3636
3637 name = xmlParseName(ctxt);
3638 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003639 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003640 ctxt->sax->error(ctxt->userData, "xmlParseEntityDecl: no name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003641 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003642 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003643 return;
3644 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003645 if (!IS_BLANK(CUR)) {
3646 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003647 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003648 "Space required after the entity name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003649 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003650 ctxt->wellFormed = 0;
3651 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003652 SKIP_BLANKS;
3653
3654 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00003655 * handle the various case of definitions...
Daniel Veillard260a68f1998-08-13 03:39:55 +00003656 */
3657 if (isParameter) {
3658 if ((CUR == '"') || (CUR == '\''))
Daniel Veillard011b63c1999-06-02 17:44:04 +00003659 value = xmlParseEntityValue(ctxt, &orig);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003660 if (value) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003661 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003662 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003663 XML_INTERNAL_PARAMETER_ENTITY,
3664 NULL, NULL, value);
3665 }
3666 else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00003667 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003668 if (URI) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003669 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003670 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003671 XML_EXTERNAL_PARAMETER_ENTITY,
3672 literal, URI, NULL);
3673 }
3674 }
3675 } else {
3676 if ((CUR == '"') || (CUR == '\'')) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00003677 value = xmlParseEntityValue(ctxt, &orig);
Daniel Veillard517752b1999-04-05 12:20:10 +00003678 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003679 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003680 XML_INTERNAL_GENERAL_ENTITY,
3681 NULL, NULL, value);
3682 } else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00003683 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003684 if ((CUR != '>') && (!IS_BLANK(CUR))) {
3685 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003686 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003687 "Space required before 'NDATA'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003688 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003689 ctxt->wellFormed = 0;
3690 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003691 SKIP_BLANKS;
3692 if ((CUR == 'N') && (NXT(1) == 'D') &&
3693 (NXT(2) == 'A') && (NXT(3) == 'T') &&
3694 (NXT(4) == 'A')) {
3695 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003696 if (!IS_BLANK(CUR)) {
3697 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003698 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003699 "Space required after 'NDATA'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003700 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003701 ctxt->wellFormed = 0;
3702 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003703 SKIP_BLANKS;
3704 ndata = xmlParseName(ctxt);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003705 if ((ctxt->sax != NULL) &&
3706 (ctxt->sax->unparsedEntityDecl != NULL))
3707 ctxt->sax->unparsedEntityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003708 literal, URI, ndata);
3709 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00003710 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003711 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003712 XML_EXTERNAL_GENERAL_PARSED_ENTITY,
3713 literal, URI, NULL);
3714 }
3715 }
3716 }
3717 SKIP_BLANKS;
3718 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003719 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003720 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003721 "xmlParseEntityDecl: entity %s not terminated\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003722 ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003723 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003724 } else
3725 NEXT;
Daniel Veillard011b63c1999-06-02 17:44:04 +00003726 if (orig != NULL) {
3727 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00003728 * Ugly mechanism to save the raw entity value.
Daniel Veillard011b63c1999-06-02 17:44:04 +00003729 */
3730 xmlEntityPtr cur = NULL;
3731
Daniel Veillardb05deb71999-08-10 19:04:08 +00003732 if (isParameter) {
3733 if ((ctxt->sax != NULL) &&
3734 (ctxt->sax->getParameterEntity != NULL))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003735 cur = ctxt->sax->getParameterEntity(ctxt->userData, name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003736 } else {
3737 if ((ctxt->sax != NULL) &&
3738 (ctxt->sax->getEntity != NULL))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003739 cur = ctxt->sax->getEntity(ctxt->userData, name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003740 }
3741 if (cur != NULL) {
3742 if (cur->orig != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003743 xmlFree(orig);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003744 else
3745 cur->orig = orig;
3746 } else
Daniel Veillard6454aec1999-09-02 22:04:43 +00003747 xmlFree(orig);
Daniel Veillard011b63c1999-06-02 17:44:04 +00003748 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00003749 if (name != NULL) xmlFree(name);
3750 if (value != NULL) xmlFree(value);
3751 if (URI != NULL) xmlFree(URI);
3752 if (literal != NULL) xmlFree(literal);
3753 if (ndata != NULL) xmlFree(ndata);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003754 }
3755}
3756
Daniel Veillard11e00581998-10-24 18:27:49 +00003757/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003758 * xmlParseDefaultDecl:
3759 * @ctxt: an XML parser context
3760 * @value: Receive a possible fixed default value for the attribute
3761 *
3762 * Parse an attribute default declaration
3763 *
3764 * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
3765 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003766 * [ VC: Required Attribute ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003767 * if the default declaration is the keyword #REQUIRED, then the
3768 * attribute must be specified for all elements of the type in the
3769 * attribute-list declaration.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003770 *
3771 * [ VC: Attribute Default Legal ]
3772 * The declared default value must meet the lexical constraints of
3773 * the declared attribute type c.f. xmlValidateAttributeDecl()
3774 *
3775 * [ VC: Fixed Attribute Default ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003776 * if an attribute has a default value declared with the #FIXED
3777 * keyword, instances of that attribute must match the default value.
Daniel Veillardb05deb71999-08-10 19:04:08 +00003778 *
3779 * [ WFC: No < in Attribute Values ]
3780 * handled in xmlParseAttValue()
3781 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003782 * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
3783 * or XML_ATTRIBUTE_FIXED.
3784 */
3785
3786int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003787xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003788 int val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003789 xmlChar *ret;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003790
3791 *value = NULL;
3792 if ((CUR == '#') && (NXT(1) == 'R') &&
3793 (NXT(2) == 'E') && (NXT(3) == 'Q') &&
3794 (NXT(4) == 'U') && (NXT(5) == 'I') &&
3795 (NXT(6) == 'R') && (NXT(7) == 'E') &&
3796 (NXT(8) == 'D')) {
3797 SKIP(9);
3798 return(XML_ATTRIBUTE_REQUIRED);
3799 }
3800 if ((CUR == '#') && (NXT(1) == 'I') &&
3801 (NXT(2) == 'M') && (NXT(3) == 'P') &&
3802 (NXT(4) == 'L') && (NXT(5) == 'I') &&
3803 (NXT(6) == 'E') && (NXT(7) == 'D')) {
3804 SKIP(8);
3805 return(XML_ATTRIBUTE_IMPLIED);
3806 }
3807 val = XML_ATTRIBUTE_NONE;
3808 if ((CUR == '#') && (NXT(1) == 'F') &&
3809 (NXT(2) == 'I') && (NXT(3) == 'X') &&
3810 (NXT(4) == 'E') && (NXT(5) == 'D')) {
3811 SKIP(6);
3812 val = XML_ATTRIBUTE_FIXED;
3813 if (!IS_BLANK(CUR)) {
3814 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003815 ctxt->sax->error(ctxt->userData,
3816 "Space required after '#FIXED'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003817 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003818 ctxt->wellFormed = 0;
3819 }
3820 SKIP_BLANKS;
3821 }
3822 ret = xmlParseAttValue(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003823 ctxt->instate = XML_PARSER_DTD;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003824 if (ret == NULL) {
3825 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003826 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003827 "Attribute default value declaration error\n");
3828 ctxt->wellFormed = 0;
3829 } else
3830 *value = ret;
3831 return(val);
3832}
3833
3834/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00003835 * xmlParseNotationType:
3836 * @ctxt: an XML parser context
3837 *
3838 * parse an Notation attribute type.
3839 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003840 * Note: the leading 'NOTATION' S part has already being parsed...
3841 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003842 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
3843 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003844 * [ VC: Notation Attributes ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003845 * Values of this type must match one of the notation names included
Daniel Veillardb05deb71999-08-10 19:04:08 +00003846 * in the declaration; all notation names in the declaration must be declared.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003847 *
3848 * Returns: the notation attribute tree built while parsing
3849 */
3850
3851xmlEnumerationPtr
3852xmlParseNotationType(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003853 xmlChar *name;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003854 xmlEnumerationPtr ret = NULL, last = NULL, cur;
3855
3856 if (CUR != '(') {
3857 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003858 ctxt->sax->error(ctxt->userData,
3859 "'(' required to start 'NOTATION'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003860 ctxt->errNo = XML_ERR_NOTATION_NOT_STARTED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003861 ctxt->wellFormed = 0;
3862 return(NULL);
3863 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003864 SHRINK;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003865 do {
3866 NEXT;
3867 SKIP_BLANKS;
3868 name = xmlParseName(ctxt);
3869 if (name == NULL) {
3870 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003871 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003872 "Name expected in NOTATION declaration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003873 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003874 ctxt->wellFormed = 0;
3875 return(ret);
3876 }
3877 cur = xmlCreateEnumeration(name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003878 xmlFree(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003879 if (cur == NULL) return(ret);
3880 if (last == NULL) ret = last = cur;
3881 else {
3882 last->next = cur;
3883 last = cur;
3884 }
3885 SKIP_BLANKS;
3886 } while (CUR == '|');
3887 if (CUR != ')') {
3888 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003889 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003890 "')' required to finish NOTATION declaration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003891 ctxt->errNo = XML_ERR_NOTATION_NOT_FINISHED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003892 ctxt->wellFormed = 0;
3893 return(ret);
3894 }
3895 NEXT;
3896 return(ret);
3897}
3898
3899/**
3900 * xmlParseEnumerationType:
3901 * @ctxt: an XML parser context
3902 *
3903 * parse an Enumeration attribute type.
3904 *
3905 * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
3906 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00003907 * [ VC: Enumeration ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00003908 * Values of this type must match one of the Nmtoken tokens in
Daniel Veillardb05deb71999-08-10 19:04:08 +00003909 * the declaration
3910 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003911 * Returns: the enumeration attribute tree built while parsing
3912 */
3913
3914xmlEnumerationPtr
3915xmlParseEnumerationType(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003916 xmlChar *name;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003917 xmlEnumerationPtr ret = NULL, last = NULL, cur;
3918
3919 if (CUR != '(') {
3920 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003921 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003922 "'(' required to start ATTLIST enumeration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003923 ctxt->errNo = XML_ERR_ATTLIST_NOT_STARTED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003924 ctxt->wellFormed = 0;
3925 return(NULL);
3926 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003927 SHRINK;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003928 do {
3929 NEXT;
3930 SKIP_BLANKS;
3931 name = xmlParseNmtoken(ctxt);
3932 if (name == NULL) {
3933 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003934 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003935 "NmToken expected in ATTLIST enumeration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003936 ctxt->errNo = XML_ERR_NMTOKEN_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003937 ctxt->wellFormed = 0;
3938 return(ret);
3939 }
3940 cur = xmlCreateEnumeration(name);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003941 xmlFree(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00003942 if (cur == NULL) return(ret);
3943 if (last == NULL) ret = last = cur;
3944 else {
3945 last->next = cur;
3946 last = cur;
3947 }
3948 SKIP_BLANKS;
3949 } while (CUR == '|');
3950 if (CUR != ')') {
3951 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003952 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00003953 "')' required to finish ATTLIST enumeration\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003954 ctxt->errNo = XML_ERR_ATTLIST_NOT_FINISHED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003955 ctxt->wellFormed = 0;
3956 return(ret);
3957 }
3958 NEXT;
3959 return(ret);
3960}
3961
3962/**
Daniel Veillard11e00581998-10-24 18:27:49 +00003963 * xmlParseEnumeratedType:
3964 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00003965 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00003966 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003967 * parse an Enumerated attribute type.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003968 *
3969 * [57] EnumeratedType ::= NotationType | Enumeration
3970 *
3971 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
3972 *
Daniel Veillard11e00581998-10-24 18:27:49 +00003973 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003974 * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION
Daniel Veillard260a68f1998-08-13 03:39:55 +00003975 */
3976
Daniel Veillard1e346af1999-02-22 10:33:01 +00003977int
3978xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
3979 if ((CUR == 'N') && (NXT(1) == 'O') &&
3980 (NXT(2) == 'T') && (NXT(3) == 'A') &&
3981 (NXT(4) == 'T') && (NXT(5) == 'I') &&
3982 (NXT(6) == 'O') && (NXT(7) == 'N')) {
3983 SKIP(8);
3984 if (!IS_BLANK(CUR)) {
3985 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00003986 ctxt->sax->error(ctxt->userData,
3987 "Space required after 'NOTATION'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003988 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard1e346af1999-02-22 10:33:01 +00003989 ctxt->wellFormed = 0;
3990 return(0);
3991 }
3992 SKIP_BLANKS;
3993 *tree = xmlParseNotationType(ctxt);
3994 if (*tree == NULL) return(0);
3995 return(XML_ATTRIBUTE_NOTATION);
3996 }
3997 *tree = xmlParseEnumerationType(ctxt);
3998 if (*tree == NULL) return(0);
3999 return(XML_ATTRIBUTE_ENUMERATION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004000}
4001
Daniel Veillard11e00581998-10-24 18:27:49 +00004002/**
4003 * xmlParseAttributeType:
4004 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00004005 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00004006 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004007 * parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00004008 *
4009 * [54] AttType ::= StringType | TokenizedType | EnumeratedType
4010 *
4011 * [55] StringType ::= 'CDATA'
4012 *
4013 * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
4014 * 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
Daniel Veillard11e00581998-10-24 18:27:49 +00004015 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004016 * Validity constraints for attribute values syntax are checked in
4017 * xmlValidateAttributeValue()
4018 *
4019 * [ VC: ID ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004020 * Values of type ID must match the Name production. A name must not
Daniel Veillardb05deb71999-08-10 19:04:08 +00004021 * appear more than once in an XML document as a value of this type;
4022 * i.e., ID values must uniquely identify the elements which bear them.
4023 *
4024 * [ VC: One ID per Element Type ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004025 * No element type may have more than one ID attribute specified.
Daniel Veillardb05deb71999-08-10 19:04:08 +00004026 *
4027 * [ VC: ID Attribute Default ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004028 * An ID attribute must have a declared default of #IMPLIED or #REQUIRED.
Daniel Veillardb05deb71999-08-10 19:04:08 +00004029 *
4030 * [ VC: IDREF ]
4031 * Values of type IDREF must match the Name production, and values
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004032 * of type IDREFS must match Names; each IDREF Name must match the value
Daniel Veillardb96e6431999-08-29 21:02:19 +00004033 * of an ID attribute on some element in the XML document; i.e. IDREF
Daniel Veillardb05deb71999-08-10 19:04:08 +00004034 * values must match the value of some ID attribute.
4035 *
4036 * [ VC: Entity Name ]
4037 * Values of type ENTITY must match the Name production, values
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004038 * of type ENTITIES must match Names; each Entity Name must match the
Daniel Veillardb96e6431999-08-29 21:02:19 +00004039 * name of an unparsed entity declared in the DTD.
Daniel Veillardb05deb71999-08-10 19:04:08 +00004040 *
4041 * [ VC: Name Token ]
4042 * Values of type NMTOKEN must match the Nmtoken production; values
4043 * of type NMTOKENS must match Nmtokens.
4044 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004045 * Returns the attribute type
Daniel Veillard260a68f1998-08-13 03:39:55 +00004046 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004047int
Daniel Veillard1e346af1999-02-22 10:33:01 +00004048xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004049 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004050 if ((CUR == 'C') && (NXT(1) == 'D') &&
4051 (NXT(2) == 'A') && (NXT(3) == 'T') &&
4052 (NXT(4) == 'A')) {
4053 SKIP(5);
Daniel Veillard1e346af1999-02-22 10:33:01 +00004054 return(XML_ATTRIBUTE_CDATA);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004055 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
4056 (NXT(2) == 'R') && (NXT(3) == 'E') &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00004057 (NXT(4) == 'F') && (NXT(5) == 'S')) {
4058 SKIP(6);
4059 return(XML_ATTRIBUTE_IDREFS);
4060 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
4061 (NXT(2) == 'R') && (NXT(3) == 'E') &&
Daniel Veillard260a68f1998-08-13 03:39:55 +00004062 (NXT(4) == 'F')) {
4063 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004064 return(XML_ATTRIBUTE_IDREF);
Daniel Veillard1e346af1999-02-22 10:33:01 +00004065 } else if ((CUR == 'I') && (NXT(1) == 'D')) {
4066 SKIP(2);
4067 return(XML_ATTRIBUTE_ID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004068 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
4069 (NXT(2) == 'T') && (NXT(3) == 'I') &&
4070 (NXT(4) == 'T') && (NXT(5) == 'Y')) {
4071 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004072 return(XML_ATTRIBUTE_ENTITY);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004073 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
4074 (NXT(2) == 'T') && (NXT(3) == 'I') &&
4075 (NXT(4) == 'T') && (NXT(5) == 'I') &&
4076 (NXT(6) == 'E') && (NXT(7) == 'S')) {
4077 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004078 return(XML_ATTRIBUTE_ENTITIES);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004079 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
4080 (NXT(2) == 'T') && (NXT(3) == 'O') &&
4081 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00004082 (NXT(6) == 'N') && (NXT(7) == 'S')) {
4083 SKIP(8);
4084 return(XML_ATTRIBUTE_NMTOKENS);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004085 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
4086 (NXT(2) == 'T') && (NXT(3) == 'O') &&
4087 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00004088 (NXT(6) == 'N')) {
4089 SKIP(7);
4090 return(XML_ATTRIBUTE_NMTOKEN);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004091 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00004092 return(xmlParseEnumeratedType(ctxt, tree));
Daniel Veillard260a68f1998-08-13 03:39:55 +00004093}
4094
Daniel Veillard11e00581998-10-24 18:27:49 +00004095/**
4096 * xmlParseAttributeListDecl:
4097 * @ctxt: an XML parser context
4098 *
4099 * : parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00004100 *
4101 * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
4102 *
4103 * [53] AttDef ::= S Name S AttType S DefaultDecl
Daniel Veillard11e00581998-10-24 18:27:49 +00004104 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004105 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004106void
4107xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004108 xmlChar *elemName;
4109 xmlChar *attrName;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004110 xmlEnumerationPtr tree;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004111
Daniel Veillard260a68f1998-08-13 03:39:55 +00004112 if ((CUR == '<') && (NXT(1) == '!') &&
4113 (NXT(2) == 'A') && (NXT(3) == 'T') &&
4114 (NXT(4) == 'T') && (NXT(5) == 'L') &&
4115 (NXT(6) == 'I') && (NXT(7) == 'S') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004116 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004117 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004118 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004119 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004120 ctxt->sax->error(ctxt->userData,
4121 "Space required after '<!ATTLIST'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004122 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004123 ctxt->wellFormed = 0;
4124 }
4125 SKIP_BLANKS;
4126 elemName = xmlParseName(ctxt);
4127 if (elemName == NULL) {
4128 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004129 ctxt->sax->error(ctxt->userData,
4130 "ATTLIST: no name for Element\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004131 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004132 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004133 return;
4134 }
4135 SKIP_BLANKS;
4136 while (CUR != '>') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004137 const xmlChar *check = CUR_PTR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004138 int type;
4139 int def;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004140 xmlChar *defaultValue = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004141
Daniel Veillardb05deb71999-08-10 19:04:08 +00004142 tree = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004143 attrName = xmlParseName(ctxt);
4144 if (attrName == NULL) {
4145 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004146 ctxt->sax->error(ctxt->userData,
4147 "ATTLIST: no name for Attribute\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004148 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004149 ctxt->wellFormed = 0;
4150 break;
4151 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00004152 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004153 if (!IS_BLANK(CUR)) {
4154 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004155 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004156 "Space required after the attribute name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004157 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004158 ctxt->wellFormed = 0;
4159 break;
4160 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004161 SKIP_BLANKS;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004162
Daniel Veillard1e346af1999-02-22 10:33:01 +00004163 type = xmlParseAttributeType(ctxt, &tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004164 if (type <= 0) break;
4165
Daniel Veillardb05deb71999-08-10 19:04:08 +00004166 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004167 if (!IS_BLANK(CUR)) {
4168 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004169 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004170 "Space required after the attribute type\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004171 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004172 ctxt->wellFormed = 0;
4173 break;
4174 }
4175 SKIP_BLANKS;
4176
4177 def = xmlParseDefaultDecl(ctxt, &defaultValue);
4178 if (def <= 0) break;
4179
Daniel Veillardb05deb71999-08-10 19:04:08 +00004180 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004181 if (CUR != '>') {
4182 if (!IS_BLANK(CUR)) {
4183 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004184 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004185 "Space required after the attribute default value\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004186 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004187 ctxt->wellFormed = 0;
4188 break;
4189 }
4190 SKIP_BLANKS;
4191 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004192 if (check == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004193 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004194 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004195 "xmlParseAttributeListDecl: detected internal error\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004196 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004197 break;
4198 }
Daniel Veillard517752b1999-04-05 12:20:10 +00004199 if ((ctxt->sax != NULL) && (ctxt->sax->attributeDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004200 ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName,
Daniel Veillard1e346af1999-02-22 10:33:01 +00004201 type, def, defaultValue, tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004202 if (attrName != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004203 xmlFree(attrName);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004204 if (defaultValue != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004205 xmlFree(defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004206 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004207 }
4208 if (CUR == '>')
4209 NEXT;
4210
Daniel Veillard6454aec1999-09-02 22:04:43 +00004211 xmlFree(elemName);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004212 }
4213}
4214
Daniel Veillard11e00581998-10-24 18:27:49 +00004215/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004216 * xmlParseElementMixedContentDecl:
Daniel Veillard11e00581998-10-24 18:27:49 +00004217 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00004218 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004219 * parse the declaration for a Mixed Element content
4220 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
Daniel Veillard260a68f1998-08-13 03:39:55 +00004221 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004222 * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
4223 * '(' S? '#PCDATA' S? ')'
4224 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004225 * [ VC: Proper Group/PE Nesting ] applies to [51] too (see [49])
4226 *
4227 * [ VC: No Duplicate Types ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004228 * The same name must not appear more than once in a single
4229 * mixed-content declaration.
Daniel Veillardb05deb71999-08-10 19:04:08 +00004230 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004231 * returns: the list of the xmlElementContentPtr describing the element choices
4232 */
4233xmlElementContentPtr
4234xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard1899e851999-02-01 12:18:54 +00004235 xmlElementContentPtr ret = NULL, cur = NULL, n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004236 xmlChar *elem = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004237
Daniel Veillardb05deb71999-08-10 19:04:08 +00004238 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004239 if ((CUR == '#') && (NXT(1) == 'P') &&
4240 (NXT(2) == 'C') && (NXT(3) == 'D') &&
4241 (NXT(4) == 'A') && (NXT(5) == 'T') &&
4242 (NXT(6) == 'A')) {
4243 SKIP(7);
4244 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004245 SHRINK;
Daniel Veillard3b9def11999-01-31 22:15:06 +00004246 if (CUR == ')') {
4247 NEXT;
4248 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
Daniel Veillardf600e251999-12-18 15:32:46 +00004249 if (CUR == '*') {
4250 ret->ocur = XML_ELEMENT_CONTENT_MULT;
4251 NEXT;
4252 }
Daniel Veillard3b9def11999-01-31 22:15:06 +00004253 return(ret);
4254 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004255 if ((CUR == '(') || (CUR == '|')) {
4256 ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
4257 if (ret == NULL) return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004258 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004259 while (CUR == '|') {
Daniel Veillard1899e851999-02-01 12:18:54 +00004260 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004261 if (elem == NULL) {
4262 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
4263 if (ret == NULL) return(NULL);
4264 ret->c1 = cur;
Daniel Veillard1899e851999-02-01 12:18:54 +00004265 cur = ret;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004266 } else {
Daniel Veillard1899e851999-02-01 12:18:54 +00004267 n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
4268 if (n == NULL) return(NULL);
4269 n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
4270 cur->c2 = n;
4271 cur = n;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004272 xmlFree(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004273 }
4274 SKIP_BLANKS;
4275 elem = xmlParseName(ctxt);
4276 if (elem == NULL) {
4277 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004278 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004279 "xmlParseElementMixedContentDecl : Name expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004280 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004281 ctxt->wellFormed = 0;
4282 xmlFreeElementContent(cur);
4283 return(NULL);
4284 }
4285 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004286 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004287 }
Daniel Veillard3b9def11999-01-31 22:15:06 +00004288 if ((CUR == ')') && (NXT(1) == '*')) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00004289 if (elem != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004290 cur->c2 = xmlNewElementContent(elem,
4291 XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004292 xmlFree(elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00004293 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004294 ret->ocur = XML_ELEMENT_CONTENT_MULT;
4295 SKIP(2);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004296 } else {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004297 if (elem != NULL) xmlFree(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004298 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004299 ctxt->sax->error(ctxt->userData,
Daniel Veillard3b9def11999-01-31 22:15:06 +00004300 "xmlParseElementMixedContentDecl : '|' or ')*' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004301 ctxt->errNo = XML_ERR_MIXED_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004302 ctxt->wellFormed = 0;
4303 xmlFreeElementContent(ret);
4304 return(NULL);
4305 }
4306
4307 } else {
4308 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004309 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004310 "xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004311 ctxt->errNo = XML_ERR_PCDATA_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004312 ctxt->wellFormed = 0;
4313 }
4314 return(ret);
4315}
4316
4317/**
4318 * xmlParseElementChildrenContentDecl:
4319 * @ctxt: an XML parser context
4320 *
4321 * parse the declaration for a Mixed Element content
4322 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
4323 *
4324 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004325 * [47] children ::= (choice | seq) ('?' | '*' | '+')?
4326 *
4327 * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
4328 *
4329 * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
4330 *
4331 * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
4332 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004333 * [ VC: Proper Group/PE Nesting ] applies to [49] and [50]
4334 * TODO Parameter-entity replacement text must be properly nested
4335 * with parenthetized groups. That is to say, if either of the
4336 * opening or closing parentheses in a choice, seq, or Mixed
4337 * construct is contained in the replacement text for a parameter
4338 * entity, both must be contained in the same replacement text. For
4339 * interoperability, if a parameter-entity reference appears in a
4340 * choice, seq, or Mixed construct, its replacement text should not
4341 * be empty, and neither the first nor last non-blank character of
4342 * the replacement text should be a connector (| or ,).
4343 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004344 * returns: the tree of xmlElementContentPtr describing the element
4345 * hierarchy.
4346 */
4347xmlElementContentPtr
4348xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt) {
4349 xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004350 xmlChar *elem;
4351 xmlChar type = 0;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004352
4353 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004354 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004355 if (CUR == '(') {
4356 /* Recurse on first child */
4357 NEXT;
4358 SKIP_BLANKS;
4359 cur = ret = xmlParseElementChildrenContentDecl(ctxt);
4360 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004361 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004362 } else {
4363 elem = xmlParseName(ctxt);
4364 if (elem == NULL) {
4365 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004366 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004367 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004368 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004369 ctxt->wellFormed = 0;
4370 return(NULL);
4371 }
4372 cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004373 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004374 if (CUR == '?') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004375 cur->ocur = XML_ELEMENT_CONTENT_OPT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004376 NEXT;
4377 } else if (CUR == '*') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004378 cur->ocur = XML_ELEMENT_CONTENT_MULT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004379 NEXT;
4380 } else if (CUR == '+') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004381 cur->ocur = XML_ELEMENT_CONTENT_PLUS;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004382 NEXT;
4383 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004384 cur->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004385 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00004386 xmlFree(elem);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004387 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004388 }
4389 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004390 SHRINK;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004391 while (CUR != ')') {
4392 /*
4393 * Each loop we parse one separator and one element.
4394 */
4395 if (CUR == ',') {
4396 if (type == 0) type = CUR;
4397
4398 /*
4399 * Detect "Name | Name , Name" error
4400 */
4401 else if (type != CUR) {
4402 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004403 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004404 "xmlParseElementChildrenContentDecl : '%c' expected\n",
4405 type);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004406 ctxt->errNo = XML_ERR_SEPARATOR_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004407 ctxt->wellFormed = 0;
4408 xmlFreeElementContent(ret);
4409 return(NULL);
4410 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004411 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004412
4413 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
4414 if (op == NULL) {
4415 xmlFreeElementContent(ret);
4416 return(NULL);
4417 }
4418 if (last == NULL) {
4419 op->c1 = ret;
4420 ret = cur = op;
4421 } else {
4422 cur->c2 = op;
4423 op->c1 = last;
4424 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00004425 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004426 }
4427 } else if (CUR == '|') {
4428 if (type == 0) type = CUR;
4429
4430 /*
4431 * Detect "Name , Name | Name" error
4432 */
4433 else if (type != CUR) {
4434 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004435 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004436 "xmlParseElementChildrenContentDecl : '%c' expected\n",
4437 type);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004438 ctxt->errNo = XML_ERR_SEPARATOR_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004439 ctxt->wellFormed = 0;
4440 xmlFreeElementContent(ret);
4441 return(NULL);
4442 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004443 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004444
4445 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
4446 if (op == NULL) {
4447 xmlFreeElementContent(ret);
4448 return(NULL);
4449 }
4450 if (last == NULL) {
4451 op->c1 = ret;
4452 ret = cur = op;
4453 } else {
4454 cur->c2 = op;
4455 op->c1 = last;
4456 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00004457 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004458 }
4459 } else {
4460 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004461 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004462 "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
4463 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004464 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004465 xmlFreeElementContent(ret);
4466 return(NULL);
4467 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00004468 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004469 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004470 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004471 if (CUR == '(') {
4472 /* Recurse on second child */
4473 NEXT;
4474 SKIP_BLANKS;
Daniel Veillard1899e851999-02-01 12:18:54 +00004475 last = xmlParseElementChildrenContentDecl(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004476 SKIP_BLANKS;
4477 } else {
4478 elem = xmlParseName(ctxt);
4479 if (elem == NULL) {
4480 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004481 ctxt->sax->error(ctxt->userData,
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004482 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004483 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004484 ctxt->wellFormed = 0;
4485 return(NULL);
4486 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004487 last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004488 xmlFree(elem);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004489 if (CUR == '?') {
4490 last->ocur = XML_ELEMENT_CONTENT_OPT;
4491 NEXT;
4492 } else if (CUR == '*') {
4493 last->ocur = XML_ELEMENT_CONTENT_MULT;
4494 NEXT;
4495 } else if (CUR == '+') {
4496 last->ocur = XML_ELEMENT_CONTENT_PLUS;
4497 NEXT;
4498 } else {
4499 last->ocur = XML_ELEMENT_CONTENT_ONCE;
4500 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004501 }
4502 SKIP_BLANKS;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004503 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004504 }
Daniel Veillard1899e851999-02-01 12:18:54 +00004505 if ((cur != NULL) && (last != NULL)) {
4506 cur->c2 = last;
4507 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004508 NEXT;
4509 if (CUR == '?') {
4510 ret->ocur = XML_ELEMENT_CONTENT_OPT;
4511 NEXT;
4512 } else if (CUR == '*') {
4513 ret->ocur = XML_ELEMENT_CONTENT_MULT;
4514 NEXT;
4515 } else if (CUR == '+') {
4516 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
4517 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004518 }
4519 return(ret);
4520}
4521
4522/**
4523 * xmlParseElementContentDecl:
4524 * @ctxt: an XML parser context
4525 * @name: the name of the element being defined.
4526 * @result: the Element Content pointer will be stored here if any
Daniel Veillard260a68f1998-08-13 03:39:55 +00004527 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004528 * parse the declaration for an Element content either Mixed or Children,
4529 * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
4530 *
4531 * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
Daniel Veillard11e00581998-10-24 18:27:49 +00004532 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004533 * returns: the type of element content XML_ELEMENT_TYPE_xxx
Daniel Veillard260a68f1998-08-13 03:39:55 +00004534 */
4535
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004536int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004537xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, xmlChar *name,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004538 xmlElementContentPtr *result) {
4539
4540 xmlElementContentPtr tree = NULL;
4541 int res;
4542
4543 *result = NULL;
4544
4545 if (CUR != '(') {
4546 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004547 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004548 "xmlParseElementContentDecl : '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004549 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004550 ctxt->wellFormed = 0;
4551 return(-1);
4552 }
4553 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004554 GROW;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004555 SKIP_BLANKS;
4556 if ((CUR == '#') && (NXT(1) == 'P') &&
4557 (NXT(2) == 'C') && (NXT(3) == 'D') &&
4558 (NXT(4) == 'A') && (NXT(5) == 'T') &&
4559 (NXT(6) == 'A')) {
4560 tree = xmlParseElementMixedContentDecl(ctxt);
4561 res = XML_ELEMENT_TYPE_MIXED;
4562 } else {
4563 tree = xmlParseElementChildrenContentDecl(ctxt);
4564 res = XML_ELEMENT_TYPE_ELEMENT;
4565 }
4566 SKIP_BLANKS;
4567 /****************************
4568 if (CUR != ')') {
4569 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004570 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004571 "xmlParseElementContentDecl : ')' expected\n");
4572 ctxt->wellFormed = 0;
4573 return(-1);
4574 }
4575 ****************************/
Daniel Veillard3b9def11999-01-31 22:15:06 +00004576 *result = tree;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004577 return(res);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004578}
4579
Daniel Veillard11e00581998-10-24 18:27:49 +00004580/**
4581 * xmlParseElementDecl:
4582 * @ctxt: an XML parser context
4583 *
4584 * parse an Element declaration.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004585 *
4586 * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
4587 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004588 * [ VC: Unique Element Type Declaration ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00004589 * No element type may be declared more than once
Daniel Veillard1e346af1999-02-22 10:33:01 +00004590 *
4591 * Returns the type of the element, or -1 in case of error
Daniel Veillard260a68f1998-08-13 03:39:55 +00004592 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004593int
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004594xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004595 xmlChar *name;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004596 int ret = -1;
4597 xmlElementContentPtr content = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004598
Daniel Veillardb05deb71999-08-10 19:04:08 +00004599 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004600 if ((CUR == '<') && (NXT(1) == '!') &&
4601 (NXT(2) == 'E') && (NXT(3) == 'L') &&
4602 (NXT(4) == 'E') && (NXT(5) == 'M') &&
4603 (NXT(6) == 'E') && (NXT(7) == 'N') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004604 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004605 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004606 if (!IS_BLANK(CUR)) {
4607 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004608 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004609 "Space required after 'ELEMENT'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004610 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004611 ctxt->wellFormed = 0;
4612 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004613 SKIP_BLANKS;
4614 name = xmlParseName(ctxt);
4615 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004616 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004617 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004618 "xmlParseElementDecl: no name for Element\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004619 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004620 ctxt->wellFormed = 0;
4621 return(-1);
4622 }
4623 if (!IS_BLANK(CUR)) {
4624 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004625 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004626 "Space required after the element name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004627 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004628 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004629 }
4630 SKIP_BLANKS;
4631 if ((CUR == 'E') && (NXT(1) == 'M') &&
4632 (NXT(2) == 'P') && (NXT(3) == 'T') &&
4633 (NXT(4) == 'Y')) {
4634 SKIP(5);
4635 /*
4636 * Element must always be empty.
4637 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004638 ret = XML_ELEMENT_TYPE_EMPTY;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004639 } else if ((CUR == 'A') && (NXT(1) == 'N') &&
4640 (NXT(2) == 'Y')) {
4641 SKIP(3);
4642 /*
4643 * Element is a generic container.
4644 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004645 ret = XML_ELEMENT_TYPE_ANY;
4646 } else if (CUR == '(') {
4647 ret = xmlParseElementContentDecl(ctxt, name, &content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004648 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004649 /*
4650 * [ WFC: PEs in Internal Subset ] error handling.
4651 */
4652 if ((CUR == '%') && (ctxt->external == 0) &&
4653 (ctxt->inputNr == 1)) {
4654 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4655 ctxt->sax->error(ctxt->userData,
4656 "PEReference: forbidden within markup decl in internal subset\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004657 ctxt->errNo = XML_ERR_PEREF_IN_INT_SUBSET;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004658 } else {
4659 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4660 ctxt->sax->error(ctxt->userData,
4661 "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004662 ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004663 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004664 ctxt->wellFormed = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004665 if (name != NULL) xmlFree(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004666 return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004667 }
Daniel Veillard686d6b62000-01-03 11:08:02 +00004668
Daniel Veillard260a68f1998-08-13 03:39:55 +00004669 SKIP_BLANKS;
Daniel Veillard686d6b62000-01-03 11:08:02 +00004670 /*
4671 * Pop-up of finished entities.
4672 */
4673 while ((CUR == 0) && (ctxt->inputNr > 1))
4674 xmlPopInput(ctxt);
4675 SKIP_BLANKS;
4676
Daniel Veillard260a68f1998-08-13 03:39:55 +00004677 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004678 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004679 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00004680 "xmlParseElementDecl: expected '>' at the end\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004681 ctxt->errNo = XML_ERR_GT_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004682 ctxt->wellFormed = 0;
4683 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004684 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00004685 if ((ctxt->sax != NULL) && (ctxt->sax->elementDecl != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00004686 ctxt->sax->elementDecl(ctxt->userData, name, ret,
4687 content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004688 }
Daniel Veillard14fff061999-06-22 21:49:07 +00004689 if (content != NULL) {
4690 xmlFreeElementContent(content);
4691 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004692 if (name != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004693 xmlFree(name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004694 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004695 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004696 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004697}
4698
Daniel Veillard11e00581998-10-24 18:27:49 +00004699/**
4700 * xmlParseMarkupDecl:
4701 * @ctxt: an XML parser context
4702 *
4703 * parse Markup declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00004704 *
4705 * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
4706 * NotationDecl | PI | Comment
4707 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00004708 * [ VC: Proper Declaration/PE Nesting ]
4709 * TODO Parameter-entity replacement text must be properly nested with
4710 * markup declarations. That is to say, if either the first character
4711 * or the last character of a markup declaration (markupdecl above) is
4712 * contained in the replacement text for a parameter-entity reference,
4713 * both must be contained in the same replacement text.
4714 *
4715 * [ WFC: PEs in Internal Subset ]
4716 * In the internal DTD subset, parameter-entity references can occur
4717 * only where markup declarations can occur, not within markup declarations.
4718 * (This does not apply to references that occur in external parameter
4719 * entities or to the external subset.)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004720 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004721void
4722xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00004723 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004724 xmlParseElementDecl(ctxt);
4725 xmlParseAttributeListDecl(ctxt);
4726 xmlParseEntityDecl(ctxt);
4727 xmlParseNotationDecl(ctxt);
4728 xmlParsePI(ctxt);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004729 xmlParseComment(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004730 /*
4731 * This is only for internal subset. On external entities,
4732 * the replacement is done before parsing stage
4733 */
4734 if ((ctxt->external == 0) && (ctxt->inputNr == 1))
4735 xmlParsePEReference(ctxt);
4736 ctxt->instate = XML_PARSER_DTD;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004737}
4738
Daniel Veillard11e00581998-10-24 18:27:49 +00004739/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004740 * xmlParseTextDecl:
4741 * @ctxt: an XML parser context
4742 *
4743 * parse an XML declaration header for external entities
4744 *
4745 * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
4746 *
4747 * Returns the only valuable info for an external parsed entity, the encoding
4748 */
4749
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004750xmlChar *
Daniel Veillard011b63c1999-06-02 17:44:04 +00004751xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004752 xmlChar *version;
4753 xmlChar *encoding = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004754
4755 /*
4756 * We know that '<?xml' is here.
4757 */
4758 SKIP(5);
4759
4760 if (!IS_BLANK(CUR)) {
4761 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004762 ctxt->sax->error(ctxt->userData,
4763 "Space needed after '<?xml'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004764 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004765 ctxt->wellFormed = 0;
4766 }
4767 SKIP_BLANKS;
4768
4769 /*
4770 * We may have the VersionInfo here.
4771 */
4772 version = xmlParseVersionInfo(ctxt);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004773 if (version == NULL)
4774 version = xmlCharStrdup(XML_DEFAULT_VERSION);
4775 ctxt->version = xmlStrdup(version);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004776 xmlFree(version);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004777
4778 /*
4779 * We must have the encoding declaration
4780 */
4781 if (!IS_BLANK(CUR)) {
4782 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004783 ctxt->sax->error(ctxt->userData, "Space needed here\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004784 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004785 ctxt->wellFormed = 0;
4786 }
4787 encoding = xmlParseEncodingDecl(ctxt);
4788
4789 SKIP_BLANKS;
4790 if ((CUR == '?') && (NXT(1) == '>')) {
4791 SKIP(2);
4792 } else if (CUR == '>') {
4793 /* Deprecated old WD ... */
4794 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004795 ctxt->sax->error(ctxt->userData,
4796 "XML declaration must end-up with '?>'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004797 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004798 ctxt->wellFormed = 0;
4799 NEXT;
4800 } else {
4801 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00004802 ctxt->sax->error(ctxt->userData,
4803 "parsing XML declaration: '?>' expected\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004804 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004805 ctxt->wellFormed = 0;
4806 MOVETO_ENDTAG(CUR_PTR);
4807 NEXT;
4808 }
4809 return(encoding);
4810}
4811
4812/*
4813 * xmlParseConditionalSections
4814 * @ctxt: an XML parser context
4815 *
4816 * TODO : Conditionnal section are not yet supported !
4817 *
4818 * [61] conditionalSect ::= includeSect | ignoreSect
4819 * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
4820 * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
4821 * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
4822 * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
4823 */
4824
4825void
4826xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
4827 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
4828 ctxt->sax->warning(ctxt->userData,
4829 "XML conditional section not supported\n");
4830 /*
4831 * Skip up to the end of the conditionnal section.
4832 */
Daniel Veillard71b656e2000-01-05 14:46:17 +00004833 while ((CUR != 0) && ((CUR != ']') || (NXT(1) != ']') || (NXT(2) != '>'))) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00004834 NEXT;
Daniel Veillard71b656e2000-01-05 14:46:17 +00004835 /*
4836 * Pop-up of finished entities.
4837 */
4838 while ((CUR == 0) && (ctxt->inputNr > 1))
4839 xmlPopInput(ctxt);
4840
4841 if (CUR == 0)
4842 GROW;
4843 }
4844
4845 if (CUR == 0)
4846 SHRINK;
4847
Daniel Veillard011b63c1999-06-02 17:44:04 +00004848 if (CUR == 0) {
4849 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4850 ctxt->sax->error(ctxt->userData,
4851 "XML conditional section not closed\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004852 ctxt->errNo = XML_ERR_CONDSEC_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004853 ctxt->wellFormed = 0;
Daniel Veillard71b656e2000-01-05 14:46:17 +00004854 } else {
4855 SKIP(3);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004856 }
4857}
4858
4859/**
Daniel Veillard00fdf371999-10-08 09:40:39 +00004860 * xmlParseExternalSubset:
Daniel Veillard011b63c1999-06-02 17:44:04 +00004861 * @ctxt: an XML parser context
Daniel Veillard00fdf371999-10-08 09:40:39 +00004862 * @ExternalID: the external identifier
4863 * @SystemID: the system identifier (or URL)
Daniel Veillard011b63c1999-06-02 17:44:04 +00004864 *
4865 * parse Markup declarations from an external subset
4866 *
4867 * [30] extSubset ::= textDecl? extSubsetDecl
4868 *
4869 * [31] extSubsetDecl ::= (markupdecl | conditionalSect | PEReference | S) *
Daniel Veillard011b63c1999-06-02 17:44:04 +00004870 */
4871void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004872xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID,
4873 const xmlChar *SystemID) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00004874 GROW;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004875 if ((CUR == '<') && (NXT(1) == '?') &&
4876 (NXT(2) == 'x') && (NXT(3) == 'm') &&
4877 (NXT(4) == 'l')) {
Daniel Veillard294cbca1999-12-03 13:19:09 +00004878 xmlChar *decl;
4879
4880 decl = xmlParseTextDecl(ctxt);
4881 if (decl != NULL)
4882 xmlFree(decl);
Daniel Veillard011b63c1999-06-02 17:44:04 +00004883 }
4884 if (ctxt->myDoc == NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004885 ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
Daniel Veillard011b63c1999-06-02 17:44:04 +00004886 }
4887 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL))
4888 xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID);
4889
Daniel Veillardb05deb71999-08-10 19:04:08 +00004890 ctxt->instate = XML_PARSER_DTD;
4891 ctxt->external = 1;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004892 while (((CUR == '<') && (NXT(1) == '?')) ||
4893 ((CUR == '<') && (NXT(1) == '!')) ||
4894 IS_BLANK(CUR)) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004895 const xmlChar *check = CUR_PTR;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004896 int cons = ctxt->input->consumed;
4897
Daniel Veillard011b63c1999-06-02 17:44:04 +00004898 if ((CUR == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
4899 xmlParseConditionalSections(ctxt);
4900 } else if (IS_BLANK(CUR)) {
4901 NEXT;
4902 } else if (CUR == '%') {
4903 xmlParsePEReference(ctxt);
4904 } else
4905 xmlParseMarkupDecl(ctxt);
4906
4907 /*
4908 * Pop-up of finished entities.
4909 */
4910 while ((CUR == 0) && (ctxt->inputNr > 1))
4911 xmlPopInput(ctxt);
4912
Daniel Veillardb96e6431999-08-29 21:02:19 +00004913 if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
4914 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4915 ctxt->sax->error(ctxt->userData,
4916 "Content error in the external subset\n");
4917 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004918 ctxt->errNo = XML_ERR_EXT_SUBSET_NOT_FINISHED;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004919 break;
4920 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004921 }
4922
4923 if (CUR != 0) {
4924 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4925 ctxt->sax->error(ctxt->userData,
4926 "Extra content at the end of the document\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004927 ctxt->errNo = XML_ERR_EXT_SUBSET_NOT_FINISHED;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004928 ctxt->wellFormed = 0;
4929 }
4930
4931}
4932
4933/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00004934 * xmlParseReference:
4935 * @ctxt: an XML parser context
4936 *
4937 * parse and handle entity references in content, depending on the SAX
4938 * interface, this may end-up in a call to character() if this is a
4939 * CharRef, a predefined entity, if there is no reference() callback.
4940 * or if the parser was asked to switch to that mode.
4941 *
4942 * [67] Reference ::= EntityRef | CharRef
4943 */
4944void
4945xmlParseReference(xmlParserCtxtPtr ctxt) {
4946 xmlEntityPtr ent;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004947 xmlChar *val;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004948 if (CUR != '&') return;
4949
Daniel Veillardb96e6431999-08-29 21:02:19 +00004950 if (ctxt->inputNr > 1) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004951 xmlChar cur[2] = { '&' , 0 } ;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004952
4953 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
4954 ctxt->sax->characters(ctxt->userData, cur, 1);
4955 if (ctxt->token == '&')
4956 ctxt->token = 0;
4957 else {
4958 SKIP(1);
4959 }
4960 return;
4961 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004962 if (NXT(1) == '#') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004963 xmlChar out[2];
Daniel Veillard011b63c1999-06-02 17:44:04 +00004964 int val = xmlParseCharRef(ctxt);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004965 /* invalid for UTF-8 variable encoding !!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00004966 out[0] = val;
4967 out[1] = 0;
4968 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
4969 ctxt->sax->characters(ctxt->userData, out, 1);
4970 } else {
4971 ent = xmlParseEntityRef(ctxt);
4972 if (ent == NULL) return;
4973 if ((ent->name != NULL) &&
Daniel Veillardb96e6431999-08-29 21:02:19 +00004974 (ent->type != XML_INTERNAL_PREDEFINED_ENTITY)) {
4975 if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) &&
4976 (ctxt->replaceEntities == 0)) {
4977 /*
4978 * Create a node.
4979 */
4980 ctxt->sax->reference(ctxt->userData, ent->name);
4981 return;
4982 } else if (ctxt->replaceEntities) {
4983 xmlParserInputPtr input;
Daniel Veillard011b63c1999-06-02 17:44:04 +00004984
Daniel Veillardb96e6431999-08-29 21:02:19 +00004985 input = xmlNewEntityInputStream(ctxt, ent);
4986 xmlPushInput(ctxt, input);
4987 return;
4988 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00004989 }
4990 val = ent->content;
4991 if (val == NULL) return;
4992 /*
4993 * inline the entity.
4994 */
4995 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
4996 ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val));
4997 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004998}
4999
Daniel Veillard11e00581998-10-24 18:27:49 +00005000/**
5001 * xmlParseEntityRef:
5002 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00005003 *
5004 * parse ENTITY references declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00005005 *
5006 * [68] EntityRef ::= '&' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00005007 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005008 * [ WFC: Entity Declared ]
5009 * In a document without any DTD, a document with only an internal DTD
5010 * subset which contains no parameter entity references, or a document
5011 * with "standalone='yes'", the Name given in the entity reference
5012 * must match that in an entity declaration, except that well-formed
5013 * documents need not declare any of the following entities: amp, lt,
5014 * gt, apos, quot. The declaration of a parameter entity must precede
5015 * any reference to it. Similarly, the declaration of a general entity
5016 * must precede any reference to it which appears in a default value in an
5017 * attribute-list declaration. Note that if entities are declared in the
5018 * external subset or in external parameter entities, a non-validating
5019 * processor is not obligated to read and process their declarations;
5020 * for such documents, the rule that an entity must be declared is a
5021 * well-formedness constraint only if standalone='yes'.
5022 *
5023 * [ WFC: Parsed Entity ]
5024 * An entity reference must not contain the name of an unparsed entity
5025 *
Daniel Veillard011b63c1999-06-02 17:44:04 +00005026 * Returns the xmlEntityPtr if found, or NULL otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005027 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00005028xmlEntityPtr
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005029xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005030 xmlChar *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00005031 xmlEntityPtr ent = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005032
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005033 GROW;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005034
Daniel Veillard260a68f1998-08-13 03:39:55 +00005035 if (CUR == '&') {
5036 NEXT;
5037 name = xmlParseName(ctxt);
5038 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005039 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00005040 ctxt->sax->error(ctxt->userData,
5041 "xmlParseEntityRef: no name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005042 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005043 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005044 } else {
5045 if (CUR == ';') {
5046 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005047 /*
Daniel Veillard011b63c1999-06-02 17:44:04 +00005048 * Ask first SAX for entity resolution, otherwise try the
5049 * predefined set.
5050 */
5051 if (ctxt->sax != NULL) {
5052 if (ctxt->sax->getEntity != NULL)
5053 ent = ctxt->sax->getEntity(ctxt->userData, name);
5054 if (ent == NULL)
5055 ent = xmlGetPredefinedEntity(name);
5056 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00005057 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005058 * [ WFC: Entity Declared ]
5059 * In a document without any DTD, a document with only an
5060 * internal DTD subset which contains no parameter entity
5061 * references, or a document with "standalone='yes'", the
5062 * Name given in the entity reference must match that in an
5063 * entity declaration, except that well-formed documents
5064 * need not declare any of the following entities: amp, lt,
5065 * gt, apos, quot.
5066 * The declaration of a parameter entity must precede any
5067 * reference to it.
5068 * Similarly, the declaration of a general entity must
5069 * precede any reference to it which appears in a default
5070 * value in an attribute-list declaration. Note that if
5071 * entities are declared in the external subset or in
5072 * external parameter entities, a non-validating processor
5073 * is not obligated to read and process their declarations;
5074 * for such documents, the rule that an entity must be
5075 * declared is a well-formedness constraint only if
5076 * standalone='yes'.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005077 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00005078 if (ent == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00005079 if ((ctxt->standalone == 1) ||
5080 ((ctxt->hasExternalSubset == 0) &&
5081 (ctxt->hasPErefs == 0))) {
5082 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard011b63c1999-06-02 17:44:04 +00005083 ctxt->sax->error(ctxt->userData,
5084 "Entity '%s' not defined\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005085 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
Daniel Veillard011b63c1999-06-02 17:44:04 +00005086 ctxt->wellFormed = 0;
Daniel Veillard011b63c1999-06-02 17:44:04 +00005087 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00005088 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
5089 ctxt->sax->warning(ctxt->userData,
5090 "Entity '%s' not defined\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005091 ctxt->errNo = XML_WAR_UNDECLARED_ENTITY;
Daniel Veillard011b63c1999-06-02 17:44:04 +00005092 }
5093 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005094
5095 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005096 * [ WFC: Parsed Entity ]
5097 * An entity reference must not contain the name of an
5098 * unparsed entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005099 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00005100 else if (ent->type == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
5101 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5102 ctxt->sax->error(ctxt->userData,
5103 "Entity reference to unparsed entity %s\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005104 ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005105 ctxt->wellFormed = 0;
5106 }
5107
5108 /*
5109 * [ WFC: No External Entity References ]
5110 * Attribute values cannot contain direct or indirect
5111 * entity references to external entities.
5112 */
5113 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
5114 (ent->type == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
5115 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5116 ctxt->sax->error(ctxt->userData,
5117 "Attribute references external entity '%s'\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005118 ctxt->errNo = XML_ERR_ENTITY_IS_EXTERNAL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005119 ctxt->wellFormed = 0;
5120 }
5121 /*
5122 * [ WFC: No < in Attribute Values ]
5123 * The replacement text of any entity referred to directly or
5124 * indirectly in an attribute value (other than "&lt;") must
5125 * not contain a <.
5126 */
5127 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
Daniel Veillardb96e6431999-08-29 21:02:19 +00005128 (ent != NULL) &&
5129 (xmlStrcmp(ent->name, BAD_CAST "lt")) &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00005130 (ent->content != NULL) &&
5131 (xmlStrchr(ent->content, '<'))) {
5132 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5133 ctxt->sax->error(ctxt->userData,
5134 "'<' in entity '%s' is not allowed in attributes values\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005135 ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005136 ctxt->wellFormed = 0;
5137 }
5138
5139 /*
5140 * Internal check, no parameter entities here ...
5141 */
5142 else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005143 switch (ent->type) {
5144 case XML_INTERNAL_PARAMETER_ENTITY:
5145 case XML_EXTERNAL_PARAMETER_ENTITY:
5146 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005147 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005148 "Attempt to reference the parameter entity '%s'\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005149 ctxt->errNo = XML_ERR_ENTITY_IS_PARAMETER;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005150 ctxt->wellFormed = 0;
5151 break;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005152 }
5153 }
5154
5155 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005156 * [ WFC: No Recursion ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00005157 * TODO A parsed entity must not contain a recursive reference
5158 * to itself, either directly or indirectly.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005159 */
Daniel Veillard260a68f1998-08-13 03:39:55 +00005160
Daniel Veillard011b63c1999-06-02 17:44:04 +00005161 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005162 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005163 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005164 "xmlParseEntityRef: expecting ';'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005165 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005166 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005167 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00005168 xmlFree(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005169 }
5170 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00005171 return(ent);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005172}
Daniel Veillard10a2c651999-12-12 13:03:50 +00005173/**
5174 * xmlParseStringEntityRef:
5175 * @ctxt: an XML parser context
5176 * @str: a pointer to an index in the string
5177 *
5178 * parse ENTITY references declarations, but this version parses it from
5179 * a string value.
5180 *
5181 * [68] EntityRef ::= '&' Name ';'
5182 *
5183 * [ WFC: Entity Declared ]
5184 * In a document without any DTD, a document with only an internal DTD
5185 * subset which contains no parameter entity references, or a document
5186 * with "standalone='yes'", the Name given in the entity reference
5187 * must match that in an entity declaration, except that well-formed
5188 * documents need not declare any of the following entities: amp, lt,
5189 * gt, apos, quot. The declaration of a parameter entity must precede
5190 * any reference to it. Similarly, the declaration of a general entity
5191 * must precede any reference to it which appears in a default value in an
5192 * attribute-list declaration. Note that if entities are declared in the
5193 * external subset or in external parameter entities, a non-validating
5194 * processor is not obligated to read and process their declarations;
5195 * for such documents, the rule that an entity must be declared is a
5196 * well-formedness constraint only if standalone='yes'.
5197 *
5198 * [ WFC: Parsed Entity ]
5199 * An entity reference must not contain the name of an unparsed entity
5200 *
5201 * Returns the xmlEntityPtr if found, or NULL otherwise. The str pointer
5202 * is updated to the current location in the string.
5203 */
5204xmlEntityPtr
5205xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) {
5206 xmlChar *name;
5207 const xmlChar *ptr;
5208 xmlChar cur;
5209 xmlEntityPtr ent = NULL;
5210
5211 GROW;
5212
5213 if ((str == NULL) || (*str == NULL)) return(NULL); /* !!! */
5214 ptr = *str;
5215 cur = *ptr;
5216 if (cur == '&') {
5217 ptr++;
5218 cur = *ptr;
5219 name = xmlParseStringName(ctxt, &ptr);
5220 if (name == NULL) {
5221 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5222 ctxt->sax->error(ctxt->userData,
5223 "xmlParseEntityRef: no name\n");
5224 ctxt->errNo = XML_ERR_NAME_REQUIRED;
5225 ctxt->wellFormed = 0;
5226 } else {
5227 if (CUR == ';') {
5228 NEXT;
5229 /*
5230 * Ask first SAX for entity resolution, otherwise try the
5231 * predefined set.
5232 */
5233 if (ctxt->sax != NULL) {
5234 if (ctxt->sax->getEntity != NULL)
5235 ent = ctxt->sax->getEntity(ctxt->userData, name);
5236 if (ent == NULL)
5237 ent = xmlGetPredefinedEntity(name);
5238 }
5239 /*
5240 * [ WFC: Entity Declared ]
5241 * In a document without any DTD, a document with only an
5242 * internal DTD subset which contains no parameter entity
5243 * references, or a document with "standalone='yes'", the
5244 * Name given in the entity reference must match that in an
5245 * entity declaration, except that well-formed documents
5246 * need not declare any of the following entities: amp, lt,
5247 * gt, apos, quot.
5248 * The declaration of a parameter entity must precede any
5249 * reference to it.
5250 * Similarly, the declaration of a general entity must
5251 * precede any reference to it which appears in a default
5252 * value in an attribute-list declaration. Note that if
5253 * entities are declared in the external subset or in
5254 * external parameter entities, a non-validating processor
5255 * is not obligated to read and process their declarations;
5256 * for such documents, the rule that an entity must be
5257 * declared is a well-formedness constraint only if
5258 * standalone='yes'.
5259 */
5260 if (ent == NULL) {
5261 if ((ctxt->standalone == 1) ||
5262 ((ctxt->hasExternalSubset == 0) &&
5263 (ctxt->hasPErefs == 0))) {
5264 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5265 ctxt->sax->error(ctxt->userData,
5266 "Entity '%s' not defined\n", name);
5267 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
5268 ctxt->wellFormed = 0;
5269 } else {
5270 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
5271 ctxt->sax->warning(ctxt->userData,
5272 "Entity '%s' not defined\n", name);
5273 ctxt->errNo = XML_WAR_UNDECLARED_ENTITY;
5274 }
5275 }
5276
5277 /*
5278 * [ WFC: Parsed Entity ]
5279 * An entity reference must not contain the name of an
5280 * unparsed entity
5281 */
5282 else if (ent->type == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
5283 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5284 ctxt->sax->error(ctxt->userData,
5285 "Entity reference to unparsed entity %s\n", name);
5286 ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
5287 ctxt->wellFormed = 0;
5288 }
5289
5290 /*
5291 * [ WFC: No External Entity References ]
5292 * Attribute values cannot contain direct or indirect
5293 * entity references to external entities.
5294 */
5295 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
5296 (ent->type == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
5297 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5298 ctxt->sax->error(ctxt->userData,
5299 "Attribute references external entity '%s'\n", name);
5300 ctxt->errNo = XML_ERR_ENTITY_IS_EXTERNAL;
5301 ctxt->wellFormed = 0;
5302 }
5303 /*
5304 * [ WFC: No < in Attribute Values ]
5305 * The replacement text of any entity referred to directly or
5306 * indirectly in an attribute value (other than "&lt;") must
5307 * not contain a <.
5308 */
5309 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
5310 (ent != NULL) &&
5311 (xmlStrcmp(ent->name, BAD_CAST "lt")) &&
5312 (ent->content != NULL) &&
5313 (xmlStrchr(ent->content, '<'))) {
5314 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5315 ctxt->sax->error(ctxt->userData,
5316 "'<' in entity '%s' is not allowed in attributes values\n", name);
5317 ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
5318 ctxt->wellFormed = 0;
5319 }
5320
5321 /*
5322 * Internal check, no parameter entities here ...
5323 */
5324 else {
5325 switch (ent->type) {
5326 case XML_INTERNAL_PARAMETER_ENTITY:
5327 case XML_EXTERNAL_PARAMETER_ENTITY:
5328 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5329 ctxt->sax->error(ctxt->userData,
5330 "Attempt to reference the parameter entity '%s'\n", name);
5331 ctxt->errNo = XML_ERR_ENTITY_IS_PARAMETER;
5332 ctxt->wellFormed = 0;
5333 break;
5334 }
5335 }
5336
5337 /*
5338 * [ WFC: No Recursion ]
5339 * TODO A parsed entity must not contain a recursive reference
5340 * to itself, either directly or indirectly.
5341 */
5342
5343 } else {
5344 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5345 ctxt->sax->error(ctxt->userData,
5346 "xmlParseEntityRef: expecting ';'\n");
5347 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
5348 ctxt->wellFormed = 0;
5349 }
5350 xmlFree(name);
5351 }
5352 }
5353 return(ent);
5354}
Daniel Veillard260a68f1998-08-13 03:39:55 +00005355
Daniel Veillard11e00581998-10-24 18:27:49 +00005356/**
5357 * xmlParsePEReference:
5358 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00005359 *
5360 * parse PEReference declarations
Daniel Veillard011b63c1999-06-02 17:44:04 +00005361 * The entity content is handled directly by pushing it's content as
5362 * a new input stream.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005363 *
5364 * [69] PEReference ::= '%' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00005365 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005366 * [ WFC: No Recursion ]
5367 * TODO A parsed entity must not contain a recursive
5368 * reference to itself, either directly or indirectly.
5369 *
5370 * [ WFC: Entity Declared ]
5371 * In a document without any DTD, a document with only an internal DTD
5372 * subset which contains no parameter entity references, or a document
5373 * with "standalone='yes'", ... ... The declaration of a parameter
5374 * entity must precede any reference to it...
5375 *
5376 * [ VC: Entity Declared ]
5377 * In a document with an external subset or external parameter entities
5378 * with "standalone='no'", ... ... The declaration of a parameter entity
5379 * must precede any reference to it...
5380 *
5381 * [ WFC: In DTD ]
5382 * Parameter-entity references may only appear in the DTD.
5383 * NOTE: misleading but this is handled.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005384 */
Daniel Veillard011b63c1999-06-02 17:44:04 +00005385void
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005386xmlParsePEReference(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005387 xmlChar *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00005388 xmlEntityPtr entity = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +00005389 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005390
5391 if (CUR == '%') {
5392 NEXT;
5393 name = xmlParseName(ctxt);
5394 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005395 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005396 ctxt->sax->error(ctxt->userData,
5397 "xmlParsePEReference: no name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005398 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005399 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005400 } else {
5401 if (CUR == ';') {
5402 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005403 if ((ctxt->sax != NULL) &&
5404 (ctxt->sax->getParameterEntity != NULL))
5405 entity = ctxt->sax->getParameterEntity(ctxt->userData,
5406 name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005407 if (entity == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00005408 /*
5409 * [ WFC: Entity Declared ]
5410 * In a document without any DTD, a document with only an
5411 * internal DTD subset which contains no parameter entity
5412 * references, or a document with "standalone='yes'", ...
5413 * ... The declaration of a parameter entity must precede
5414 * any reference to it...
5415 */
5416 if ((ctxt->standalone == 1) ||
5417 ((ctxt->hasExternalSubset == 0) &&
5418 (ctxt->hasPErefs == 0))) {
5419 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5420 ctxt->sax->error(ctxt->userData,
5421 "PEReference: %%%s; not found\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005422 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
Daniel Veillardb05deb71999-08-10 19:04:08 +00005423 ctxt->wellFormed = 0;
5424 } else {
5425 /*
5426 * [ VC: Entity Declared ]
5427 * In a document with an external subset or external
5428 * parameter entities with "standalone='no'", ...
5429 * ... The declaration of a parameter entity must precede
5430 * any reference to it...
5431 */
5432 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
5433 ctxt->sax->warning(ctxt->userData,
5434 "PEReference: %%%s; not found\n", name);
5435 ctxt->valid = 0;
5436 }
Daniel Veillardccb09631998-10-27 06:21:04 +00005437 } else {
Daniel Veillardb05deb71999-08-10 19:04:08 +00005438 /*
5439 * Internal checking in case the entity quest barfed
5440 */
5441 if ((entity->type != XML_INTERNAL_PARAMETER_ENTITY) &&
5442 (entity->type != XML_EXTERNAL_PARAMETER_ENTITY)) {
5443 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
5444 ctxt->sax->warning(ctxt->userData,
5445 "Internal: %%%s; is not a parameter entity\n", name);
5446 } else {
5447 input = xmlNewEntityInputStream(ctxt, entity);
5448 xmlPushInput(ctxt, input);
5449 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005450 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00005451 ctxt->hasPErefs = 1;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005452 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005453 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005454 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005455 "xmlParsePEReference: expecting ';'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005456 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005457 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005458 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00005459 xmlFree(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005460 }
5461 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005462}
5463
Daniel Veillard11e00581998-10-24 18:27:49 +00005464/**
Daniel Veillard10a2c651999-12-12 13:03:50 +00005465 * xmlParseStringPEReference:
5466 * @ctxt: an XML parser context
5467 * @str: a pointer to an index in the string
5468 *
5469 * parse PEReference declarations
5470 *
5471 * [69] PEReference ::= '%' Name ';'
5472 *
5473 * [ WFC: No Recursion ]
5474 * TODO A parsed entity must not contain a recursive
5475 * reference to itself, either directly or indirectly.
5476 *
5477 * [ WFC: Entity Declared ]
5478 * In a document without any DTD, a document with only an internal DTD
5479 * subset which contains no parameter entity references, or a document
5480 * with "standalone='yes'", ... ... The declaration of a parameter
5481 * entity must precede any reference to it...
5482 *
5483 * [ VC: Entity Declared ]
5484 * In a document with an external subset or external parameter entities
5485 * with "standalone='no'", ... ... The declaration of a parameter entity
5486 * must precede any reference to it...
5487 *
5488 * [ WFC: In DTD ]
5489 * Parameter-entity references may only appear in the DTD.
5490 * NOTE: misleading but this is handled.
5491 *
5492 * Returns the string of the entity content.
5493 * str is updated to the current value of the index
5494 */
5495xmlEntityPtr
5496xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) {
5497 const xmlChar *ptr;
5498 xmlChar cur;
5499 xmlChar *name;
5500 xmlEntityPtr entity = NULL;
5501
5502 if ((str == NULL) || (*str == NULL)) return(NULL);
5503 ptr = *str;
5504 cur = *ptr;
5505 if (cur == '%') {
5506 ptr++;
5507 cur = *ptr;
5508 name = xmlParseStringName(ctxt, &ptr);
5509 if (name == NULL) {
5510 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5511 ctxt->sax->error(ctxt->userData,
5512 "xmlParseStringPEReference: no name\n");
5513 ctxt->errNo = XML_ERR_NAME_REQUIRED;
5514 ctxt->wellFormed = 0;
5515 } else {
5516 cur = *ptr;
5517 if (cur == ';') {
5518 ptr++;
5519 cur = *ptr;
5520 if ((ctxt->sax != NULL) &&
5521 (ctxt->sax->getParameterEntity != NULL))
5522 entity = ctxt->sax->getParameterEntity(ctxt->userData,
5523 name);
5524 if (entity == NULL) {
5525 /*
5526 * [ WFC: Entity Declared ]
5527 * In a document without any DTD, a document with only an
5528 * internal DTD subset which contains no parameter entity
5529 * references, or a document with "standalone='yes'", ...
5530 * ... The declaration of a parameter entity must precede
5531 * any reference to it...
5532 */
5533 if ((ctxt->standalone == 1) ||
5534 ((ctxt->hasExternalSubset == 0) &&
5535 (ctxt->hasPErefs == 0))) {
5536 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5537 ctxt->sax->error(ctxt->userData,
5538 "PEReference: %%%s; not found\n", name);
5539 ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
5540 ctxt->wellFormed = 0;
5541 } else {
5542 /*
5543 * [ VC: Entity Declared ]
5544 * In a document with an external subset or external
5545 * parameter entities with "standalone='no'", ...
5546 * ... The declaration of a parameter entity must
5547 * precede any reference to it...
5548 */
5549 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
5550 ctxt->sax->warning(ctxt->userData,
5551 "PEReference: %%%s; not found\n", name);
5552 ctxt->valid = 0;
5553 }
5554 } else {
5555 /*
5556 * Internal checking in case the entity quest barfed
5557 */
5558 if ((entity->type != XML_INTERNAL_PARAMETER_ENTITY) &&
5559 (entity->type != XML_EXTERNAL_PARAMETER_ENTITY)) {
5560 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
5561 ctxt->sax->warning(ctxt->userData,
5562 "Internal: %%%s; is not a parameter entity\n", name);
5563 }
5564 }
5565 ctxt->hasPErefs = 1;
5566 } else {
5567 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5568 ctxt->sax->error(ctxt->userData,
5569 "xmlParseStringPEReference: expecting ';'\n");
5570 ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
5571 ctxt->wellFormed = 0;
5572 }
5573 xmlFree(name);
5574 }
5575 }
5576 *str = ptr;
5577 return(entity);
5578}
5579
5580/**
Daniel Veillard11e00581998-10-24 18:27:49 +00005581 * xmlParseDocTypeDecl :
5582 * @ctxt: an XML parser context
5583 *
5584 * parse a DOCTYPE declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00005585 *
5586 * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
5587 * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
Daniel Veillardb05deb71999-08-10 19:04:08 +00005588 *
5589 * [ VC: Root Element Type ]
5590 * The Name in the document type declaration must match the element
5591 * type of the root element.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005592 */
5593
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005594void
5595xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005596 xmlChar *name;
5597 xmlChar *ExternalID = NULL;
5598 xmlChar *URI = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005599
5600 /*
5601 * We know that '<!DOCTYPE' has been detected.
5602 */
5603 SKIP(9);
5604
5605 SKIP_BLANKS;
5606
5607 /*
5608 * Parse the DOCTYPE name.
5609 */
5610 name = xmlParseName(ctxt);
5611 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005612 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005613 ctxt->sax->error(ctxt->userData,
5614 "xmlParseDocTypeDecl : no DOCTYPE name !\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005615 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005616 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005617 }
5618
5619 SKIP_BLANKS;
5620
5621 /*
5622 * Check for SystemID and ExternalID
5623 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00005624 URI = xmlParseExternalID(ctxt, &ExternalID, 1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005625
5626 if ((URI != NULL) || (ExternalID != NULL)) {
5627 ctxt->hasExternalSubset = 1;
5628 }
5629
Daniel Veillard260a68f1998-08-13 03:39:55 +00005630 SKIP_BLANKS;
5631
Daniel Veillard011b63c1999-06-02 17:44:04 +00005632 /*
5633 * NOTE: the SAX callback may try to fetch the external subset
5634 * entity and fill it up !
5635 */
Daniel Veillard517752b1999-04-05 12:20:10 +00005636 if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005637 ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005638
5639 /*
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005640 * Cleanup
5641 */
5642 if (URI != NULL) xmlFree(URI);
5643 if (ExternalID != NULL) xmlFree(ExternalID);
5644 if (name != NULL) xmlFree(name);
5645
5646 /*
5647 * Is there any internal subset declarations ?
5648 * they are handled separately in xmlParseInternalSubset()
5649 */
5650 if (CUR == '[')
5651 return;
5652
5653 /*
5654 * We should be at the end of the DOCTYPE declaration.
5655 */
5656 if (CUR != '>') {
5657 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5658 ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
5659 ctxt->wellFormed = 0;
5660 ctxt->errNo = XML_ERR_DOCTYPE_NOT_FINISHED;
5661 }
5662 NEXT;
5663}
5664
5665/**
5666 * xmlParseInternalsubset :
5667 * @ctxt: an XML parser context
5668 *
5669 * parse the internal subset declaration
5670 *
5671 * [28 end] ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
5672 */
5673
5674void
5675xmlParseInternalSubset(xmlParserCtxtPtr ctxt) {
5676 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00005677 * Is there any DTD definition ?
5678 */
5679 if (CUR == '[') {
Daniel Veillardb05deb71999-08-10 19:04:08 +00005680 ctxt->instate = XML_PARSER_DTD;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005681 NEXT;
5682 /*
5683 * Parse the succession of Markup declarations and
5684 * PEReferences.
5685 * Subsequence (markupdecl | PEReference | S)*
5686 */
5687 while (CUR != ']') {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005688 const xmlChar *check = CUR_PTR;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005689 int cons = ctxt->input->consumed;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005690
5691 SKIP_BLANKS;
5692 xmlParseMarkupDecl(ctxt);
Daniel Veillardccb09631998-10-27 06:21:04 +00005693 xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005694
Daniel Veillard011b63c1999-06-02 17:44:04 +00005695 /*
5696 * Pop-up of finished entities.
5697 */
5698 while ((CUR == 0) && (ctxt->inputNr > 1))
5699 xmlPopInput(ctxt);
5700
Daniel Veillardc26087b1999-08-30 11:23:51 +00005701 if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00005702 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5703 ctxt->sax->error(ctxt->userData,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005704 "xmlParseInternalSubset: error detected in Markup declaration\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00005705 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005706 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005707 break;
5708 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005709 }
5710 if (CUR == ']') NEXT;
5711 }
5712
5713 /*
5714 * We should be at the end of the DOCTYPE declaration.
5715 */
5716 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005717 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005718 ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005719 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005720 ctxt->errNo = XML_ERR_DOCTYPE_NOT_FINISHED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005721 }
5722 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005723}
5724
Daniel Veillard11e00581998-10-24 18:27:49 +00005725/**
5726 * xmlParseAttribute:
5727 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005728 * @value: a xmlChar ** used to store the value of the attribute
Daniel Veillard11e00581998-10-24 18:27:49 +00005729 *
5730 * parse an attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00005731 *
5732 * [41] Attribute ::= Name Eq AttValue
5733 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005734 * [ WFC: No External Entity References ]
5735 * Attribute values cannot contain direct or indirect entity references
5736 * to external entities.
5737 *
5738 * [ WFC: No < in Attribute Values ]
5739 * The replacement text of any entity referred to directly or indirectly in
5740 * an attribute value (other than "&lt;") must not contain a <.
5741 *
5742 * [ VC: Attribute Value Type ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00005743 * The attribute must have been declared; the value must be of the type
Daniel Veillardb05deb71999-08-10 19:04:08 +00005744 * declared for it.
5745 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00005746 * [25] Eq ::= S? '=' S?
5747 *
5748 * With namespace:
5749 *
5750 * [NS 11] Attribute ::= QName Eq AttValue
5751 *
5752 * Also the case QName == xmlns:??? is handled independently as a namespace
5753 * definition.
Daniel Veillard1e346af1999-02-22 10:33:01 +00005754 *
Daniel Veillard517752b1999-04-05 12:20:10 +00005755 * Returns the attribute name, and the value in *value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005756 */
5757
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005758xmlChar *
5759xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) {
5760 xmlChar *name, *val;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005761
Daniel Veillard517752b1999-04-05 12:20:10 +00005762 *value = NULL;
5763 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005764 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005765 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005766 ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005767 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005768 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillardccb09631998-10-27 06:21:04 +00005769 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005770 }
5771
5772 /*
5773 * read the value
5774 */
5775 SKIP_BLANKS;
5776 if (CUR == '=') {
5777 NEXT;
5778 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00005779 val = xmlParseAttValue(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005780 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005781 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005782 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005783 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005784 "Specification mandate value for attribute %s\n", name);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005785 ctxt->errNo = XML_ERR_ATTRIBUTE_WITHOUT_VALUE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005786 ctxt->wellFormed = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00005787 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005788 }
5789
Daniel Veillard517752b1999-04-05 12:20:10 +00005790 *value = val;
5791 return(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005792}
5793
Daniel Veillard11e00581998-10-24 18:27:49 +00005794/**
5795 * xmlParseStartTag:
5796 * @ctxt: an XML parser context
5797 *
5798 * parse a start of tag either for rule element or
5799 * EmptyElement. In both case we don't parse the tag closing chars.
Daniel Veillard260a68f1998-08-13 03:39:55 +00005800 *
5801 * [40] STag ::= '<' Name (S Attribute)* S? '>'
5802 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005803 * [ WFC: Unique Att Spec ]
5804 * No attribute name may appear more than once in the same start-tag or
5805 * empty-element tag.
5806 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00005807 * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
5808 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00005809 * [ WFC: Unique Att Spec ]
5810 * No attribute name may appear more than once in the same start-tag or
5811 * empty-element tag.
5812 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00005813 * With namespace:
5814 *
5815 * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
5816 *
5817 * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
Daniel Veillard14fff061999-06-22 21:49:07 +00005818 *
Daniel Veillard7f858501999-11-17 17:32:38 +00005819 * Returne the element name parsed
Daniel Veillard260a68f1998-08-13 03:39:55 +00005820 */
5821
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005822xmlChar *
Daniel Veillard1e346af1999-02-22 10:33:01 +00005823xmlParseStartTag(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005824 xmlChar *name;
5825 xmlChar *attname;
5826 xmlChar *attvalue;
5827 const xmlChar **atts = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00005828 int nbatts = 0;
5829 int maxatts = 0;
5830 int i;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005831
Daniel Veillard14fff061999-06-22 21:49:07 +00005832 if (CUR != '<') return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005833 NEXT;
5834
Daniel Veillard517752b1999-04-05 12:20:10 +00005835 name = xmlParseName(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005836 if (name == NULL) {
5837 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005838 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005839 "xmlParseStartTag: invalid element name\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005840 ctxt->errNo = XML_ERR_NAME_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005841 ctxt->wellFormed = 0;
Daniel Veillard14fff061999-06-22 21:49:07 +00005842 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005843 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005844
5845 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00005846 * Now parse the attributes, it ends up with the ending
5847 *
5848 * (S Attribute)* S?
5849 */
5850 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005851 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005852 while ((IS_CHAR(CUR)) &&
5853 (CUR != '>') &&
5854 ((CUR != '/') || (NXT(1) != '>'))) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005855 const xmlChar *q = CUR_PTR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005856 int cons = ctxt->input->consumed;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005857
Daniel Veillard517752b1999-04-05 12:20:10 +00005858 attname = xmlParseAttribute(ctxt, &attvalue);
5859 if ((attname != NULL) && (attvalue != NULL)) {
5860 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005861 * [ WFC: Unique Att Spec ]
5862 * No attribute name may appear more than once in the same
5863 * start-tag or empty-element tag.
Daniel Veillard517752b1999-04-05 12:20:10 +00005864 */
5865 for (i = 0; i < nbatts;i += 2) {
5866 if (!xmlStrcmp(atts[i], attname)) {
5867 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillardb05deb71999-08-10 19:04:08 +00005868 ctxt->sax->error(ctxt->userData,
5869 "Attribute %s redefined\n",
5870 attname);
Daniel Veillard517752b1999-04-05 12:20:10 +00005871 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005872 ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED;
Daniel Veillard6454aec1999-09-02 22:04:43 +00005873 xmlFree(attname);
5874 xmlFree(attvalue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005875 goto failed;
Daniel Veillard517752b1999-04-05 12:20:10 +00005876 }
5877 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00005878
Daniel Veillard517752b1999-04-05 12:20:10 +00005879 /*
5880 * Add the pair to atts
5881 */
5882 if (atts == NULL) {
5883 maxatts = 10;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005884 atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *));
Daniel Veillard517752b1999-04-05 12:20:10 +00005885 if (atts == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00005886 fprintf(stderr, "malloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005887 maxatts * (long)sizeof(xmlChar *));
Daniel Veillard14fff061999-06-22 21:49:07 +00005888 return(NULL);
Daniel Veillard517752b1999-04-05 12:20:10 +00005889 }
Daniel Veillard51e3b151999-11-12 17:02:31 +00005890 } else if (nbatts + 4 > maxatts) {
Daniel Veillard517752b1999-04-05 12:20:10 +00005891 maxatts *= 2;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005892 atts = (const xmlChar **) xmlRealloc(atts,
5893 maxatts * sizeof(xmlChar *));
Daniel Veillard517752b1999-04-05 12:20:10 +00005894 if (atts == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00005895 fprintf(stderr, "realloc of %ld byte failed\n",
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005896 maxatts * (long)sizeof(xmlChar *));
Daniel Veillard14fff061999-06-22 21:49:07 +00005897 return(NULL);
Daniel Veillard517752b1999-04-05 12:20:10 +00005898 }
5899 }
5900 atts[nbatts++] = attname;
5901 atts[nbatts++] = attvalue;
5902 atts[nbatts] = NULL;
5903 atts[nbatts + 1] = NULL;
5904 }
5905
Daniel Veillardb96e6431999-08-29 21:02:19 +00005906failed:
Daniel Veillard517752b1999-04-05 12:20:10 +00005907 SKIP_BLANKS;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005908 if ((cons == ctxt->input->consumed) && (q == CUR_PTR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005909 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005910 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00005911 "xmlParseStartTag: problem parsing attributes\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005912 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005913 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005914 break;
5915 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005916 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005917 }
5918
5919 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00005920 * SAX: Start of Element !
5921 */
Daniel Veillard517752b1999-04-05 12:20:10 +00005922 if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005923 ctxt->sax->startElement(ctxt->userData, name, atts);
Daniel Veillard517752b1999-04-05 12:20:10 +00005924
Daniel Veillard517752b1999-04-05 12:20:10 +00005925 if (atts != NULL) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005926 for (i = 0;i < nbatts;i++) xmlFree((xmlChar *) atts[i]);
Daniel Veillard6454aec1999-09-02 22:04:43 +00005927 xmlFree(atts);
Daniel Veillard517752b1999-04-05 12:20:10 +00005928 }
Daniel Veillard14fff061999-06-22 21:49:07 +00005929 return(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005930}
5931
Daniel Veillard11e00581998-10-24 18:27:49 +00005932/**
5933 * xmlParseEndTag:
5934 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00005935 *
5936 * parse an end of tag
Daniel Veillard260a68f1998-08-13 03:39:55 +00005937 *
5938 * [42] ETag ::= '</' Name S? '>'
5939 *
5940 * With namespace
5941 *
Daniel Veillard517752b1999-04-05 12:20:10 +00005942 * [NS 9] ETag ::= '</' QName S? '>'
Daniel Veillard260a68f1998-08-13 03:39:55 +00005943 */
5944
Daniel Veillard0ba4d531998-11-01 19:34:31 +00005945void
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005946xmlParseEndTag(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005947 xmlChar *name;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005948 xmlChar *oldname;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005949
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005950 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005951 if ((CUR != '<') || (NXT(1) != '/')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005952 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005953 ctxt->sax->error(ctxt->userData, "xmlParseEndTag: '</' not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005954 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005955 ctxt->errNo = XML_ERR_LTSLASH_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005956 return;
5957 }
5958 SKIP(2);
5959
Daniel Veillard517752b1999-04-05 12:20:10 +00005960 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00005961
5962 /*
5963 * We should definitely be at the ending "S? '>'" part
5964 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005965 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005966 SKIP_BLANKS;
5967 if ((!IS_CHAR(CUR)) || (CUR != '>')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00005968 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005969 ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005970 ctxt->errNo = XML_ERR_GT_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00005971 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00005972 } else
5973 NEXT;
5974
Daniel Veillard517752b1999-04-05 12:20:10 +00005975 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00005976 * [ WFC: Element Type Match ]
5977 * The Name in an element's end-tag must match the element type in the
5978 * start-tag.
5979 *
Daniel Veillard14fff061999-06-22 21:49:07 +00005980 */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005981 if (xmlStrcmp(name, ctxt->name)) {
Daniel Veillard14fff061999-06-22 21:49:07 +00005982 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
5983 ctxt->sax->error(ctxt->userData,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005984 "Opening and ending tag mismatch: %s and %s\n", ctxt->name, name);
Daniel Veillard7f7d1111999-09-22 09:46:25 +00005985
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005986 ctxt->errNo = XML_ERR_TAG_NAME_MISMATCH;
Daniel Veillard14fff061999-06-22 21:49:07 +00005987 ctxt->wellFormed = 0;
5988 }
5989
5990 /*
Daniel Veillard517752b1999-04-05 12:20:10 +00005991 * SAX: End of Tag
5992 */
5993 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00005994 ctxt->sax->endElement(ctxt->userData, name);
Daniel Veillard517752b1999-04-05 12:20:10 +00005995
5996 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00005997 xmlFree(name);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005998 oldname = namePop(ctxt);
5999 if (oldname != NULL) {
6000#ifdef DEBUG_STACK
6001 fprintf(stderr,"Close: popped %s\n", oldname);
6002#endif
6003 xmlFree(oldname);
6004 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006005 return;
6006}
6007
Daniel Veillard11e00581998-10-24 18:27:49 +00006008/**
6009 * xmlParseCDSect:
6010 * @ctxt: an XML parser context
6011 *
6012 * Parse escaped pure raw content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00006013 *
6014 * [18] CDSect ::= CDStart CData CDEnd
6015 *
6016 * [19] CDStart ::= '<![CDATA['
6017 *
6018 * [20] Data ::= (Char* - (Char* ']]>' Char*))
6019 *
6020 * [21] CDEnd ::= ']]>'
6021 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006022void
6023xmlParseCDSect(xmlParserCtxtPtr ctxt) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00006024 xmlChar *buf = NULL;
6025 int len = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006026 int size = XML_PARSER_BUFFER_SIZE;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006027 xmlChar r, s;
6028 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006029
Daniel Veillardb05deb71999-08-10 19:04:08 +00006030 if ((NXT(0) == '<') && (NXT(1) == '!') &&
Daniel Veillard260a68f1998-08-13 03:39:55 +00006031 (NXT(2) == '[') && (NXT(3) == 'C') &&
6032 (NXT(4) == 'D') && (NXT(5) == 'A') &&
6033 (NXT(6) == 'T') && (NXT(7) == 'A') &&
6034 (NXT(8) == '[')) {
6035 SKIP(9);
6036 } else
6037 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006038
6039 ctxt->instate = XML_PARSER_CDATA_SECTION;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006040 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006041 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006042 ctxt->sax->error(ctxt->userData,
Daniel Veillard10a2c651999-12-12 13:03:50 +00006043 "CData section not finished\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006044 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006045 ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006046 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006047 return;
6048 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006049 r = CUR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006050 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006051 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006052 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006053 ctxt->sax->error(ctxt->userData,
Daniel Veillard10a2c651999-12-12 13:03:50 +00006054 "CData section not finished\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006055 ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006056 ctxt->wellFormed = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006057 ctxt->instate = XML_PARSER_CONTENT;
6058 return;
6059 }
6060 s = CUR;
6061 NEXT;
6062 cur = CUR;
Daniel Veillard10a2c651999-12-12 13:03:50 +00006063 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
6064 if (buf == NULL) {
6065 fprintf(stderr, "malloc of %d byte failed\n", size);
6066 return;
6067 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006068 while (IS_CHAR(cur) &&
6069 ((r != ']') || (s != ']') || (cur != '>'))) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00006070 if (len + 1 >= size) {
6071 size *= 2;
6072 buf = xmlRealloc(buf, size * sizeof(xmlChar));
6073 if (buf == NULL) {
6074 fprintf(stderr, "realloc of %d byte failed\n", size);
6075 return;
6076 }
6077 }
6078 buf[len++] = r;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006079 r = s;
6080 s = cur;
6081 NEXT;
6082 cur = CUR;
6083 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00006084 buf[len] = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006085 ctxt->instate = XML_PARSER_CONTENT;
6086 if (!IS_CHAR(CUR)) {
6087 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006088 ctxt->sax->error(ctxt->userData,
Daniel Veillard10a2c651999-12-12 13:03:50 +00006089 "CData section not finished\n%.50s\n", buf);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006090 ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
Daniel Veillardb05deb71999-08-10 19:04:08 +00006091 ctxt->wellFormed = 0;
Daniel Veillard10a2c651999-12-12 13:03:50 +00006092 xmlFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006093 return;
6094 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006095 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006096
6097 /*
Daniel Veillard10a2c651999-12-12 13:03:50 +00006098 * Ok the buffer is to be consumed as cdata.
Daniel Veillard260a68f1998-08-13 03:39:55 +00006099 */
6100 if (ctxt->sax != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00006101 if (ctxt->sax->cdataBlock != NULL)
Daniel Veillard10a2c651999-12-12 13:03:50 +00006102 ctxt->sax->cdataBlock(ctxt->userData, buf, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006103 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00006104 xmlFree(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006105}
6106
Daniel Veillard11e00581998-10-24 18:27:49 +00006107/**
6108 * xmlParseContent:
6109 * @ctxt: an XML parser context
6110 *
6111 * Parse a content:
Daniel Veillard260a68f1998-08-13 03:39:55 +00006112 *
6113 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
6114 */
6115
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006116void
6117xmlParseContent(xmlParserCtxtPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00006118 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006119 while ((CUR != '<') || (NXT(1) != '/')) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006120 const xmlChar *test = CUR_PTR;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006121 int cons = ctxt->input->consumed;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006122 xmlChar tok = ctxt->token;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006123
6124 /*
6125 * First case : a Processing Instruction.
6126 */
6127 if ((CUR == '<') && (NXT(1) == '?')) {
6128 xmlParsePI(ctxt);
6129 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006130
Daniel Veillard260a68f1998-08-13 03:39:55 +00006131 /*
6132 * Second case : a CDSection
6133 */
6134 else if ((CUR == '<') && (NXT(1) == '!') &&
6135 (NXT(2) == '[') && (NXT(3) == 'C') &&
6136 (NXT(4) == 'D') && (NXT(5) == 'A') &&
6137 (NXT(6) == 'T') && (NXT(7) == 'A') &&
6138 (NXT(8) == '[')) {
6139 xmlParseCDSect(ctxt);
6140 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006141
Daniel Veillard260a68f1998-08-13 03:39:55 +00006142 /*
6143 * Third case : a comment
6144 */
6145 else if ((CUR == '<') && (NXT(1) == '!') &&
6146 (NXT(2) == '-') && (NXT(3) == '-')) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00006147 xmlParseComment(ctxt);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006148 ctxt->instate = XML_PARSER_CONTENT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006149 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006150
Daniel Veillard260a68f1998-08-13 03:39:55 +00006151 /*
6152 * Fourth case : a sub-element.
6153 */
6154 else if (CUR == '<') {
Daniel Veillard517752b1999-04-05 12:20:10 +00006155 xmlParseElement(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006156 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006157
Daniel Veillard260a68f1998-08-13 03:39:55 +00006158 /*
Daniel Veillardccb09631998-10-27 06:21:04 +00006159 * Fifth case : a reference. If if has not been resolved,
6160 * parsing returns it's Name, create the node
Daniel Veillard260a68f1998-08-13 03:39:55 +00006161 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00006162
Daniel Veillard260a68f1998-08-13 03:39:55 +00006163 else if (CUR == '&') {
Daniel Veillard011b63c1999-06-02 17:44:04 +00006164 xmlParseReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006165 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006166
Daniel Veillard260a68f1998-08-13 03:39:55 +00006167 /*
6168 * Last case, text. Note that References are handled directly.
6169 */
6170 else {
6171 xmlParseCharData(ctxt, 0);
6172 }
6173
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006174 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006175 /*
6176 * Pop-up of finished entities.
6177 */
Daniel Veillardbc50b591999-03-01 12:28:53 +00006178 while ((CUR == 0) && (ctxt->inputNr > 1))
6179 xmlPopInput(ctxt);
Daniel Veillard10a2c651999-12-12 13:03:50 +00006180 SHRINK;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006181
Daniel Veillardb96e6431999-08-29 21:02:19 +00006182 if ((cons == ctxt->input->consumed) && (test == CUR_PTR) &&
6183 (tok == ctxt->token)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006184 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006185 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006186 "detected an error in element content\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006187 ctxt->errNo = XML_ERR_INTERNAL_ERROR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006188 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006189 break;
6190 }
6191 }
6192}
6193
Daniel Veillard11e00581998-10-24 18:27:49 +00006194/**
6195 * xmlParseElement:
6196 * @ctxt: an XML parser context
6197 *
6198 * parse an XML element, this is highly recursive
Daniel Veillard260a68f1998-08-13 03:39:55 +00006199 *
6200 * [39] element ::= EmptyElemTag | STag content ETag
6201 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00006202 * [ WFC: Element Type Match ]
6203 * The Name in an element's end-tag must match the element type in the
6204 * start-tag.
6205 *
6206 * [ VC: Element Valid ]
Daniel Veillardb96e6431999-08-29 21:02:19 +00006207 * An element is valid if there is a declaration matching elementdecl
Daniel Veillardb05deb71999-08-10 19:04:08 +00006208 * where the Name matches the element type and one of the following holds:
6209 * - The declaration matches EMPTY and the element has no content.
6210 * - The declaration matches children and the sequence of child elements
6211 * belongs to the language generated by the regular expression in the
6212 * content model, with optional white space (characters matching the
6213 * nonterminal S) between each pair of child elements.
6214 * - The declaration matches Mixed and the content consists of character
6215 * data and child elements whose types match names in the content model.
6216 * - The declaration matches ANY, and the types of any child elements have
6217 * been declared.
Daniel Veillard260a68f1998-08-13 03:39:55 +00006218 */
6219
Daniel Veillard517752b1999-04-05 12:20:10 +00006220void
Daniel Veillard1e346af1999-02-22 10:33:01 +00006221xmlParseElement(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006222 const xmlChar *openTag = CUR_PTR;
6223 xmlChar *name;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006224 xmlChar *oldname;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006225 xmlParserNodeInfo node_info;
Daniel Veillardc26087b1999-08-30 11:23:51 +00006226 xmlNodePtr ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006227
6228 /* Capture start position */
Daniel Veillardc26087b1999-08-30 11:23:51 +00006229 if (ctxt->record_info) {
6230 node_info.begin_pos = ctxt->input->consumed +
6231 (CUR_PTR - ctxt->input->base);
6232 node_info.begin_line = ctxt->input->line;
6233 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006234
Daniel Veillard14fff061999-06-22 21:49:07 +00006235 name = xmlParseStartTag(ctxt);
6236 if (name == NULL) {
6237 return;
6238 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006239 namePush(ctxt, name);
Daniel Veillardc26087b1999-08-30 11:23:51 +00006240 ret = ctxt->node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006241
6242 /*
Daniel Veillardb05deb71999-08-10 19:04:08 +00006243 * [ VC: Root Element Type ]
6244 * The Name in the document type declaration must match the element
6245 * type of the root element.
6246 */
6247 if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc &&
6248 ctxt->node && (ctxt->node == ctxt->myDoc->root))
6249 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
6250
6251 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00006252 * Check for an Empty Element.
6253 */
6254 if ((CUR == '/') && (NXT(1) == '>')) {
6255 SKIP(2);
Daniel Veillard517752b1999-04-05 12:20:10 +00006256 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard14fff061999-06-22 21:49:07 +00006257 ctxt->sax->endElement(ctxt->userData, name);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006258 oldname = namePop(ctxt);
6259 if (oldname != NULL) {
6260#ifdef DEBUG_STACK
6261 fprintf(stderr,"Close: popped %s\n", oldname);
6262#endif
6263 xmlFree(oldname);
6264 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006265 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006266 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006267 if (CUR == '>') {
6268 NEXT;
6269 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006270 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006271 ctxt->sax->error(ctxt->userData,
6272 "Couldn't find end of Start Tag\n%.30s\n",
Daniel Veillard242590e1998-11-13 18:04:35 +00006273 openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006274 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006275 ctxt->errNo = XML_ERR_GT_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006276
6277 /*
6278 * end of parsing of this node.
6279 */
6280 nodePop(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006281 oldname = namePop(ctxt);
6282 if (oldname != NULL) {
6283#ifdef DEBUG_STACK
6284 fprintf(stderr,"Close: popped %s\n", oldname);
6285#endif
6286 xmlFree(oldname);
6287 }
Daniel Veillardc26087b1999-08-30 11:23:51 +00006288
6289 /*
6290 * Capture end position and add node
6291 */
6292 if ( ret != NULL && ctxt->record_info ) {
6293 node_info.end_pos = ctxt->input->consumed +
6294 (CUR_PTR - ctxt->input->base);
6295 node_info.end_line = ctxt->input->line;
6296 node_info.node = ret;
6297 xmlParserAddNodeInfo(ctxt, &node_info);
6298 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006299 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006300 }
6301
6302 /*
6303 * Parse the content of the element:
6304 */
6305 xmlParseContent(ctxt);
6306 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006307 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006308 ctxt->sax->error(ctxt->userData,
Daniel Veillard242590e1998-11-13 18:04:35 +00006309 "Premature end of data in tag %.30s\n", openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006310 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006311 ctxt->errNo = XML_ERR_TAG_NOT_FINISED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006312
6313 /*
6314 * end of parsing of this node.
6315 */
6316 nodePop(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006317 oldname = namePop(ctxt);
6318 if (oldname != NULL) {
6319#ifdef DEBUG_STACK
6320 fprintf(stderr,"Close: popped %s\n", oldname);
6321#endif
6322 xmlFree(oldname);
6323 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006324 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006325 }
6326
6327 /*
6328 * parse the end of tag: '</' should be here.
6329 */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006330 xmlParseEndTag(ctxt);
Daniel Veillardc26087b1999-08-30 11:23:51 +00006331
6332 /*
6333 * Capture end position and add node
6334 */
6335 if ( ret != NULL && ctxt->record_info ) {
6336 node_info.end_pos = ctxt->input->consumed +
6337 (CUR_PTR - ctxt->input->base);
6338 node_info.end_line = ctxt->input->line;
6339 node_info.node = ret;
6340 xmlParserAddNodeInfo(ctxt, &node_info);
6341 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006342}
6343
Daniel Veillard11e00581998-10-24 18:27:49 +00006344/**
6345 * xmlParseVersionNum:
6346 * @ctxt: an XML parser context
6347 *
6348 * parse the XML version value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00006349 *
6350 * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
Daniel Veillard1e346af1999-02-22 10:33:01 +00006351 *
6352 * Returns the string giving the XML version number, or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00006353 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006354xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006355xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00006356 xmlChar *buf = NULL;
6357 int len = 0;
6358 int size = 10;
6359 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006360
Daniel Veillard10a2c651999-12-12 13:03:50 +00006361 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
6362 if (buf == NULL) {
6363 fprintf(stderr, "malloc of %d byte failed\n", size);
6364 return(NULL);
6365 }
6366 cur = CUR;
6367 while (IS_CHAR(cur) &&
6368 (((cur >= 'a') && (cur <= 'z')) ||
6369 ((cur >= 'A') && (cur <= 'Z')) ||
6370 ((cur >= '0') && (cur <= '9')) ||
6371 (cur == '_') || (cur == '.') ||
6372 (cur == ':') || (cur == '-'))) {
6373 if (len + 1 >= size) {
6374 size *= 2;
6375 buf = xmlRealloc(buf, size * sizeof(xmlChar));
6376 if (buf == NULL) {
6377 fprintf(stderr, "realloc of %d byte failed\n", size);
6378 return(NULL);
6379 }
6380 }
6381 buf[len++] = cur;
6382 NEXT;
6383 cur=CUR;
6384 }
6385 buf[len] = 0;
6386 return(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006387}
6388
Daniel Veillard11e00581998-10-24 18:27:49 +00006389/**
6390 * xmlParseVersionInfo:
6391 * @ctxt: an XML parser context
6392 *
6393 * parse the XML version.
Daniel Veillard260a68f1998-08-13 03:39:55 +00006394 *
6395 * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
6396 *
6397 * [25] Eq ::= S? '=' S?
Daniel Veillard11e00581998-10-24 18:27:49 +00006398 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006399 * Returns the version string, e.g. "1.0"
Daniel Veillard260a68f1998-08-13 03:39:55 +00006400 */
6401
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006402xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006403xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006404 xmlChar *version = NULL;
6405 const xmlChar *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006406
6407 if ((CUR == 'v') && (NXT(1) == 'e') &&
6408 (NXT(2) == 'r') && (NXT(3) == 's') &&
6409 (NXT(4) == 'i') && (NXT(5) == 'o') &&
6410 (NXT(6) == 'n')) {
6411 SKIP(7);
6412 SKIP_BLANKS;
6413 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006414 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006415 ctxt->sax->error(ctxt->userData,
6416 "xmlParseVersionInfo : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006417 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006418 ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006419 return(NULL);
6420 }
6421 NEXT;
6422 SKIP_BLANKS;
6423 if (CUR == '"') {
6424 NEXT;
6425 q = CUR_PTR;
6426 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006427 if (CUR != '"') {
6428 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006429 ctxt->sax->error(ctxt->userData,
6430 "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006431 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006432 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006433 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00006434 NEXT;
6435 } else if (CUR == '\''){
6436 NEXT;
6437 q = CUR_PTR;
6438 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006439 if (CUR != '\'') {
6440 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006441 ctxt->sax->error(ctxt->userData,
6442 "String not closed\n%.50s\n", q);
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006443 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006444 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006445 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00006446 NEXT;
6447 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006448 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006449 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006450 "xmlParseVersionInfo : expected ' or \"\n");
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006451 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006452 ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006453 }
6454 }
6455 return(version);
6456}
6457
Daniel Veillard11e00581998-10-24 18:27:49 +00006458/**
6459 * xmlParseEncName:
6460 * @ctxt: an XML parser context
6461 *
6462 * parse the XML encoding name
Daniel Veillard260a68f1998-08-13 03:39:55 +00006463 *
6464 * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
Daniel Veillard11e00581998-10-24 18:27:49 +00006465 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006466 * Returns the encoding name value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00006467 */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006468xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006469xmlParseEncName(xmlParserCtxtPtr ctxt) {
Daniel Veillard10a2c651999-12-12 13:03:50 +00006470 xmlChar *buf = NULL;
6471 int len = 0;
6472 int size = 10;
6473 xmlChar cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006474
Daniel Veillard10a2c651999-12-12 13:03:50 +00006475 cur = CUR;
6476 if (((cur >= 'a') && (cur <= 'z')) ||
6477 ((cur >= 'A') && (cur <= 'Z'))) {
6478 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
6479 if (buf == NULL) {
6480 fprintf(stderr, "malloc of %d byte failed\n", size);
6481 return(NULL);
6482 }
6483
6484 buf[len++] = cur;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006485 NEXT;
Daniel Veillard10a2c651999-12-12 13:03:50 +00006486 cur = CUR;
6487 while (IS_CHAR(cur) &&
6488 (((cur >= 'a') && (cur <= 'z')) ||
6489 ((cur >= 'A') && (cur <= 'Z')) ||
6490 ((cur >= '0') && (cur <= '9')) ||
6491 (cur == '.') || (cur == '_') ||
6492 (cur == '-'))) {
6493 if (len + 1 >= size) {
6494 size *= 2;
6495 buf = xmlRealloc(buf, size * sizeof(xmlChar));
6496 if (buf == NULL) {
6497 fprintf(stderr, "realloc of %d byte failed\n", size);
6498 return(NULL);
6499 }
6500 }
6501 buf[len++] = cur;
6502 NEXT;
6503 cur = CUR;
6504 if (cur == 0) {
6505 SHRINK;
6506 GROW;
6507 cur = CUR;
6508 }
6509 }
6510 buf[len] = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006511 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006512 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006513 ctxt->sax->error(ctxt->userData, "Invalid XML encoding name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006514 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006515 ctxt->errNo = XML_ERR_ENCODING_NAME;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006516 }
Daniel Veillard10a2c651999-12-12 13:03:50 +00006517 return(buf);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006518}
6519
Daniel Veillard11e00581998-10-24 18:27:49 +00006520/**
6521 * xmlParseEncodingDecl:
6522 * @ctxt: an XML parser context
6523 *
6524 * parse the XML encoding declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00006525 *
6526 * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'")
Daniel Veillard11e00581998-10-24 18:27:49 +00006527 *
6528 * TODO: this should setup the conversion filters.
6529 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006530 * Returns the encoding value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00006531 */
6532
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006533xmlChar *
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006534xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006535 xmlChar *encoding = NULL;
6536 const xmlChar *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006537
6538 SKIP_BLANKS;
6539 if ((CUR == 'e') && (NXT(1) == 'n') &&
6540 (NXT(2) == 'c') && (NXT(3) == 'o') &&
6541 (NXT(4) == 'd') && (NXT(5) == 'i') &&
6542 (NXT(6) == 'n') && (NXT(7) == 'g')) {
6543 SKIP(8);
6544 SKIP_BLANKS;
6545 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006546 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006547 ctxt->sax->error(ctxt->userData,
6548 "xmlParseEncodingDecl : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006549 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006550 ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006551 return(NULL);
6552 }
6553 NEXT;
6554 SKIP_BLANKS;
6555 if (CUR == '"') {
6556 NEXT;
6557 q = CUR_PTR;
6558 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006559 if (CUR != '"') {
6560 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006561 ctxt->sax->error(ctxt->userData,
6562 "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006563 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006564 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006565 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00006566 NEXT;
6567 } else if (CUR == '\''){
6568 NEXT;
6569 q = CUR_PTR;
6570 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006571 if (CUR != '\'') {
6572 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006573 ctxt->sax->error(ctxt->userData,
6574 "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006575 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006576 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006577 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00006578 NEXT;
6579 } else if (CUR == '"'){
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006580 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006581 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006582 "xmlParseEncodingDecl : expected ' or \"\n");
6583 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006584 ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006585 }
6586 }
6587 return(encoding);
6588}
6589
Daniel Veillard11e00581998-10-24 18:27:49 +00006590/**
6591 * xmlParseSDDecl:
6592 * @ctxt: an XML parser context
6593 *
6594 * parse the XML standalone declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00006595 *
6596 * [32] SDDecl ::= S 'standalone' Eq
6597 * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00006598 *
Daniel Veillardb05deb71999-08-10 19:04:08 +00006599 * [ VC: Standalone Document Declaration ]
6600 * TODO The standalone document declaration must have the value "no"
6601 * if any external markup declarations contain declarations of:
6602 * - attributes with default values, if elements to which these
6603 * attributes apply appear in the document without specifications
6604 * of values for these attributes, or
6605 * - entities (other than amp, lt, gt, apos, quot), if references
6606 * to those entities appear in the document, or
6607 * - attributes with values subject to normalization, where the
6608 * attribute appears in the document with a value which will change
6609 * as a result of normalization, or
6610 * - element types with element content, if white space occurs directly
6611 * within any instance of those types.
6612 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006613 * Returns 1 if standalone, 0 otherwise
Daniel Veillard260a68f1998-08-13 03:39:55 +00006614 */
6615
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006616int
6617xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006618 int standalone = -1;
6619
6620 SKIP_BLANKS;
6621 if ((CUR == 's') && (NXT(1) == 't') &&
6622 (NXT(2) == 'a') && (NXT(3) == 'n') &&
6623 (NXT(4) == 'd') && (NXT(5) == 'a') &&
6624 (NXT(6) == 'l') && (NXT(7) == 'o') &&
6625 (NXT(8) == 'n') && (NXT(9) == 'e')) {
6626 SKIP(10);
Daniel Veillard011b63c1999-06-02 17:44:04 +00006627 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006628 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006629 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006630 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006631 "XML standalone declaration : expected '='\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006632 ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006633 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006634 return(standalone);
6635 }
6636 NEXT;
6637 SKIP_BLANKS;
6638 if (CUR == '\''){
6639 NEXT;
6640 if ((CUR == 'n') && (NXT(1) == 'o')) {
6641 standalone = 0;
6642 SKIP(2);
6643 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
6644 (NXT(2) == 's')) {
6645 standalone = 1;
6646 SKIP(3);
6647 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006648 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006649 ctxt->sax->error(ctxt->userData,
6650 "standalone accepts only 'yes' or 'no'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006651 ctxt->errNo = XML_ERR_STANDALONE_VALUE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006652 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006653 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006654 if (CUR != '\'') {
6655 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006656 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006657 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006658 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006659 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00006660 NEXT;
6661 } else if (CUR == '"'){
6662 NEXT;
6663 if ((CUR == 'n') && (NXT(1) == 'o')) {
6664 standalone = 0;
6665 SKIP(2);
6666 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
6667 (NXT(2) == 's')) {
6668 standalone = 1;
6669 SKIP(3);
6670 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006671 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006672 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006673 "standalone accepts only 'yes' or 'no'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006674 ctxt->errNo = XML_ERR_STANDALONE_VALUE;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006675 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006676 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006677 if (CUR != '"') {
6678 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006679 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006680 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006681 ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006682 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00006683 NEXT;
6684 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006685 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006686 ctxt->sax->error(ctxt->userData,
6687 "Standalone value not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006688 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006689 ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006690 }
6691 }
6692 return(standalone);
6693}
6694
Daniel Veillard11e00581998-10-24 18:27:49 +00006695/**
6696 * xmlParseXMLDecl:
6697 * @ctxt: an XML parser context
6698 *
6699 * parse an XML declaration header
Daniel Veillard260a68f1998-08-13 03:39:55 +00006700 *
6701 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
6702 */
6703
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006704void
6705xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006706 xmlChar *version;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006707
6708 /*
6709 * We know that '<?xml' is here.
6710 */
6711 SKIP(5);
6712
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006713 if (!IS_BLANK(CUR)) {
6714 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006715 ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006716 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006717 ctxt->wellFormed = 0;
6718 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006719 SKIP_BLANKS;
6720
6721 /*
6722 * We should have the VersionInfo here.
6723 */
6724 version = xmlParseVersionInfo(ctxt);
6725 if (version == NULL)
6726 version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard517752b1999-04-05 12:20:10 +00006727 ctxt->version = xmlStrdup(version);
Daniel Veillard6454aec1999-09-02 22:04:43 +00006728 xmlFree(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006729
6730 /*
6731 * We may have the encoding declaration
6732 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006733 if (!IS_BLANK(CUR)) {
6734 if ((CUR == '?') && (NXT(1) == '>')) {
6735 SKIP(2);
6736 return;
6737 }
6738 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006739 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006740 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006741 ctxt->wellFormed = 0;
6742 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006743 ctxt->encoding = xmlParseEncodingDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006744
6745 /*
6746 * We may have the standalone status.
6747 */
Daniel Veillard517752b1999-04-05 12:20:10 +00006748 if ((ctxt->encoding != NULL) && (!IS_BLANK(CUR))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006749 if ((CUR == '?') && (NXT(1) == '>')) {
6750 SKIP(2);
6751 return;
6752 }
6753 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006754 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006755 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006756 ctxt->errNo = XML_ERR_SPACE_REQUIRED;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006757 }
6758 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00006759 ctxt->standalone = xmlParseSDDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006760
6761 SKIP_BLANKS;
6762 if ((CUR == '?') && (NXT(1) == '>')) {
6763 SKIP(2);
6764 } else if (CUR == '>') {
6765 /* Deprecated old WD ... */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006766 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006767 ctxt->sax->error(ctxt->userData,
6768 "XML declaration must end-up with '?>'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006769 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006770 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006771 NEXT;
6772 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00006773 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard7f7d1111999-09-22 09:46:25 +00006774 ctxt->sax->error(ctxt->userData,
6775 "parsing XML declaration: '?>' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006776 ctxt->wellFormed = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006777 ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006778 MOVETO_ENDTAG(CUR_PTR);
6779 NEXT;
6780 }
6781}
6782
Daniel Veillard11e00581998-10-24 18:27:49 +00006783/**
6784 * xmlParseMisc:
6785 * @ctxt: an XML parser context
6786 *
6787 * parse an XML Misc* optionnal field.
Daniel Veillard260a68f1998-08-13 03:39:55 +00006788 *
6789 * [27] Misc ::= Comment | PI | S
6790 */
6791
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006792void
6793xmlParseMisc(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006794 while (((CUR == '<') && (NXT(1) == '?')) ||
6795 ((CUR == '<') && (NXT(1) == '!') &&
6796 (NXT(2) == '-') && (NXT(3) == '-')) ||
6797 IS_BLANK(CUR)) {
6798 if ((CUR == '<') && (NXT(1) == '?')) {
6799 xmlParsePI(ctxt);
6800 } else if (IS_BLANK(CUR)) {
6801 NEXT;
6802 } else
Daniel Veillardb96e6431999-08-29 21:02:19 +00006803 xmlParseComment(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006804 }
6805}
6806
Daniel Veillard11e00581998-10-24 18:27:49 +00006807/**
6808 * xmlParseDocument :
6809 * @ctxt: an XML parser context
6810 *
6811 * parse an XML document (and build a tree if using the standard SAX
6812 * interface).
Daniel Veillard260a68f1998-08-13 03:39:55 +00006813 *
6814 * [1] document ::= prolog element Misc*
6815 *
6816 * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
Daniel Veillard11e00581998-10-24 18:27:49 +00006817 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00006818 * Returns 0, -1 in case of error. the parser context is augmented
Daniel Veillard11e00581998-10-24 18:27:49 +00006819 * as a result of the parsing.
Daniel Veillard260a68f1998-08-13 03:39:55 +00006820 */
6821
Daniel Veillard0ba4d531998-11-01 19:34:31 +00006822int
6823xmlParseDocument(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006824 xmlDefaultSAXHandlerInit();
6825
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006826 GROW;
6827
Daniel Veillard260a68f1998-08-13 03:39:55 +00006828 /*
6829 * SAX: beginning of the document processing.
6830 */
Daniel Veillard517752b1999-04-05 12:20:10 +00006831 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
Daniel Veillard27d88741999-05-29 11:51:49 +00006832 ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006833
6834 /*
Daniel Veillardb96e6431999-08-29 21:02:19 +00006835 * TODO We should check for encoding here and plug-in some
6836 * conversion code !!!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00006837 */
6838
6839 /*
6840 * Wipe out everything which is before the first '<'
6841 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006842 if (IS_BLANK(CUR)) {
6843 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006844 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006845 "Extra spaces at the beginning of the document are not allowed\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006846 ctxt->errNo = XML_ERR_DOCUMENT_START;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006847 ctxt->wellFormed = 0;
6848 SKIP_BLANKS;
6849 }
6850
6851 if (CUR == 0) {
6852 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006853 ctxt->sax->error(ctxt->userData, "Document is empty\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006854 ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006855 ctxt->wellFormed = 0;
6856 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00006857
6858 /*
6859 * Check for the XMLDecl in the Prolog.
6860 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006861 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006862 if ((CUR == '<') && (NXT(1) == '?') &&
6863 (NXT(2) == 'x') && (NXT(3) == 'm') &&
Daniel Veillard686d6b62000-01-03 11:08:02 +00006864 (NXT(4) == 'l') && (IS_BLANK(NXT(5)))) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006865 xmlParseXMLDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006866 SKIP_BLANKS;
6867 } else if ((CUR == '<') && (NXT(1) == '?') &&
6868 (NXT(2) == 'X') && (NXT(3) == 'M') &&
Daniel Veillard686d6b62000-01-03 11:08:02 +00006869 (NXT(4) == 'L') && (IS_BLANK(NXT(5)))) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00006870 /*
6871 * The first drafts were using <?XML and the final W3C REC
6872 * now use <?xml ...
6873 */
6874 xmlParseXMLDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006875 SKIP_BLANKS;
6876 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00006877 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006878 }
Daniel Veillard517752b1999-04-05 12:20:10 +00006879 if ((ctxt->sax) && (ctxt->sax->startDocument))
Daniel Veillard27d88741999-05-29 11:51:49 +00006880 ctxt->sax->startDocument(ctxt->userData);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006881
6882 /*
6883 * The Misc part of the Prolog
6884 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006885 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006886 xmlParseMisc(ctxt);
6887
6888 /*
6889 * Then possibly doc type declaration(s) and more Misc
6890 * (doctypedecl Misc*)?
6891 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006892 GROW;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006893 if ((CUR == '<') && (NXT(1) == '!') &&
6894 (NXT(2) == 'D') && (NXT(3) == 'O') &&
6895 (NXT(4) == 'C') && (NXT(5) == 'T') &&
6896 (NXT(6) == 'Y') && (NXT(7) == 'P') &&
6897 (NXT(8) == 'E')) {
6898 xmlParseDocTypeDecl(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006899 if (CUR == '[') {
6900 ctxt->instate = XML_PARSER_DTD;
6901 xmlParseInternalSubset(ctxt);
6902 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00006903 ctxt->instate = XML_PARSER_PROLOG;
Daniel Veillard260a68f1998-08-13 03:39:55 +00006904 xmlParseMisc(ctxt);
6905 }
6906
6907 /*
6908 * Time to start parsing the tree itself
6909 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006910 GROW;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006911 if (CUR != '<') {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006912 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006913 ctxt->sax->error(ctxt->userData,
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006914 "Start tag expect, '<' not found\n");
6915 ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006916 ctxt->wellFormed = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006917 ctxt->instate = XML_PARSER_EOF;
6918 } else {
6919 ctxt->instate = XML_PARSER_CONTENT;
6920 xmlParseElement(ctxt);
6921 ctxt->instate = XML_PARSER_EPILOG;
6922
6923
6924 /*
6925 * The Misc part at the end
6926 */
6927 xmlParseMisc(ctxt);
6928
6929 if (CUR != 0) {
6930 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
6931 ctxt->sax->error(ctxt->userData,
6932 "Extra content at the end of the document\n");
6933 ctxt->wellFormed = 0;
6934 ctxt->errNo = XML_ERR_DOCUMENT_END;
6935 }
6936 ctxt->instate = XML_PARSER_EOF;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006937 }
6938
Daniel Veillard260a68f1998-08-13 03:39:55 +00006939 /*
6940 * SAX: end of the document processing.
6941 */
Daniel Veillard517752b1999-04-05 12:20:10 +00006942 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00006943 ctxt->sax->endDocument(ctxt->userData);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006944 if (! ctxt->wellFormed) return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00006945 return(0);
6946}
6947
Daniel Veillardb05deb71999-08-10 19:04:08 +00006948/************************************************************************
6949 * *
Daniel Veillard7f858501999-11-17 17:32:38 +00006950 * Progressive parsing interfaces *
6951 * *
6952 ************************************************************************/
6953
6954/**
6955 * xmlParseLookupSequence:
6956 * @ctxt: an XML parser context
6957 * @first: the first char to lookup
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006958 * @next: the next char to lookup or zero
6959 * @third: the next char to lookup or zero
Daniel Veillard7f858501999-11-17 17:32:38 +00006960 *
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006961 * Try to find if a sequence (first, next, third) or just (first next) or
6962 * (first) is available in the input stream.
6963 * This function has a side effect of (possibly) incrementing ctxt->checkIndex
6964 * to avoid rescanning sequences of bytes, it DOES change the state of the
6965 * parser, do not use liberally.
Daniel Veillard7f858501999-11-17 17:32:38 +00006966 *
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006967 * Returns the index to the current parsing point if the full sequence
6968 * is available, -1 otherwise.
Daniel Veillard7f858501999-11-17 17:32:38 +00006969 */
6970int
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006971xmlParseLookupSequence(xmlParserCtxtPtr ctxt, xmlChar first,
6972 xmlChar next, xmlChar third) {
6973 int base, len;
6974 xmlParserInputPtr in;
6975 const xmlChar *buf;
6976
6977 in = ctxt->input;
6978 if (in == NULL) return(-1);
6979 base = in->cur - in->base;
6980 if (base < 0) return(-1);
6981 if (ctxt->checkIndex > base)
6982 base = ctxt->checkIndex;
6983 if (in->buf == NULL) {
6984 buf = in->base;
6985 len = in->length;
6986 } else {
6987 buf = in->buf->buffer->content;
6988 len = in->buf->buffer->use;
6989 }
6990 /* take into account the sequence length */
6991 if (third) len -= 2;
6992 else if (next) len --;
6993 for (;base < len;base++) {
6994 if (buf[base] == first) {
6995 if (third != 0) {
6996 if ((buf[base + 1] != next) ||
6997 (buf[base + 2] != third)) continue;
6998 } else if (next != 0) {
6999 if (buf[base + 1] != next) continue;
7000 }
7001 ctxt->checkIndex = 0;
7002#ifdef DEBUG_PUSH
7003 if (next == 0)
7004 fprintf(stderr, "PP: lookup '%c' found at %d\n",
7005 first, base);
7006 else if (third == 0)
7007 fprintf(stderr, "PP: lookup '%c%c' found at %d\n",
7008 first, next, base);
7009 else
7010 fprintf(stderr, "PP: lookup '%c%c%c' found at %d\n",
7011 first, next, third, base);
7012#endif
7013 return(base - (in->cur - in->base));
7014 }
7015 }
7016 ctxt->checkIndex = base;
7017#ifdef DEBUG_PUSH
7018 if (next == 0)
7019 fprintf(stderr, "PP: lookup '%c' failed\n", first);
7020 else if (third == 0)
7021 fprintf(stderr, "PP: lookup '%c%c' failed\n", first, next);
7022 else
7023 fprintf(stderr, "PP: lookup '%c%c%c' failed\n", first, next, third);
7024#endif
7025 return(-1);
Daniel Veillard7f858501999-11-17 17:32:38 +00007026}
7027
7028/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00007029 * xmlParseTryOrFinish:
Daniel Veillard7f858501999-11-17 17:32:38 +00007030 * @ctxt: an XML parser context
Daniel Veillard71b656e2000-01-05 14:46:17 +00007031 * @terminate: last chunk indicator
Daniel Veillard7f858501999-11-17 17:32:38 +00007032 *
7033 * Try to progress on parsing
7034 *
7035 * Returns zero if no parsing was possible
7036 */
7037int
Daniel Veillard71b656e2000-01-05 14:46:17 +00007038xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
Daniel Veillard7f858501999-11-17 17:32:38 +00007039 int ret = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007040 xmlParserInputPtr in;
7041 int avail;
7042 xmlChar cur, next;
7043
7044#ifdef DEBUG_PUSH
7045 switch (ctxt->instate) {
7046 case XML_PARSER_EOF:
7047 fprintf(stderr, "PP: try EOF\n"); break;
7048 case XML_PARSER_START:
7049 fprintf(stderr, "PP: try START\n"); break;
7050 case XML_PARSER_MISC:
7051 fprintf(stderr, "PP: try MISC\n");break;
7052 case XML_PARSER_COMMENT:
7053 fprintf(stderr, "PP: try COMMENT\n");break;
7054 case XML_PARSER_PROLOG:
7055 fprintf(stderr, "PP: try PROLOG\n");break;
7056 case XML_PARSER_START_TAG:
7057 fprintf(stderr, "PP: try START_TAG\n");break;
7058 case XML_PARSER_CONTENT:
7059 fprintf(stderr, "PP: try CONTENT\n");break;
7060 case XML_PARSER_CDATA_SECTION:
7061 fprintf(stderr, "PP: try CDATA_SECTION\n");break;
7062 case XML_PARSER_END_TAG:
7063 fprintf(stderr, "PP: try END_TAG\n");break;
7064 case XML_PARSER_ENTITY_DECL:
7065 fprintf(stderr, "PP: try ENTITY_DECL\n");break;
7066 case XML_PARSER_ENTITY_VALUE:
7067 fprintf(stderr, "PP: try ENTITY_VALUE\n");break;
7068 case XML_PARSER_ATTRIBUTE_VALUE:
7069 fprintf(stderr, "PP: try ATTRIBUTE_VALUE\n");break;
7070 case XML_PARSER_DTD:
7071 fprintf(stderr, "PP: try DTD\n");break;
7072 case XML_PARSER_EPILOG:
7073 fprintf(stderr, "PP: try EPILOG\n");break;
7074 case XML_PARSER_PI:
7075 fprintf(stderr, "PP: try PI\n");break;
7076 }
7077#endif
Daniel Veillard7f858501999-11-17 17:32:38 +00007078
7079 while (1) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007080 /*
7081 * Pop-up of finished entities.
7082 */
7083 while ((CUR == 0) && (ctxt->inputNr > 1))
7084 xmlPopInput(ctxt);
7085
7086 in = ctxt->input;
7087 if (in == NULL) break;
7088 if (in->buf == NULL)
7089 avail = in->length - (in->cur - in->base);
7090 else
7091 avail = in->buf->buffer->use - (in->cur - in->base);
7092 if (avail < 1)
7093 goto done;
Daniel Veillard7f858501999-11-17 17:32:38 +00007094 switch (ctxt->instate) {
7095 case XML_PARSER_EOF:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007096 /*
7097 * Document parsing is done !
7098 */
7099 goto done;
7100 case XML_PARSER_START:
7101 /*
7102 * Very first chars read from the document flow.
7103 */
7104 cur = in->cur[0];
7105 if (IS_BLANK(cur)) {
7106 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
7107 ctxt->sax->setDocumentLocator(ctxt->userData,
7108 &xmlDefaultSAXLocator);
7109 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
7110 ctxt->sax->error(ctxt->userData,
7111 "Extra spaces at the beginning of the document are not allowed\n");
7112 ctxt->errNo = XML_ERR_DOCUMENT_START;
7113 ctxt->wellFormed = 0;
7114 SKIP_BLANKS;
7115 ret++;
7116 if (in->buf == NULL)
7117 avail = in->length - (in->cur - in->base);
7118 else
7119 avail = in->buf->buffer->use - (in->cur - in->base);
7120 }
7121 if (avail < 2)
7122 goto done;
7123
7124 cur = in->cur[0];
7125 next = in->cur[1];
7126 if (cur == 0) {
7127 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
7128 ctxt->sax->setDocumentLocator(ctxt->userData,
7129 &xmlDefaultSAXLocator);
7130 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
7131 ctxt->sax->error(ctxt->userData, "Document is empty\n");
7132 ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
7133 ctxt->wellFormed = 0;
7134 ctxt->instate = XML_PARSER_EOF;
7135#ifdef DEBUG_PUSH
7136 fprintf(stderr, "PP: entering EOF\n");
7137#endif
7138 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
7139 ctxt->sax->endDocument(ctxt->userData);
7140 goto done;
7141 }
7142 if ((cur == '<') && (next == '?')) {
7143 /* PI or XML decl */
7144 if (avail < 5) return(ret);
Daniel Veillard71b656e2000-01-05 14:46:17 +00007145 if ((!terminate) &&
7146 (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007147 return(ret);
7148 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
7149 ctxt->sax->setDocumentLocator(ctxt->userData,
7150 &xmlDefaultSAXLocator);
7151 if ((in->cur[2] == 'x') &&
7152 (in->cur[3] == 'm') &&
Daniel Veillard686d6b62000-01-03 11:08:02 +00007153 (in->cur[4] == 'l') &&
7154 (IS_BLANK(in->cur[5]))) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007155 ret += 5;
7156#ifdef DEBUG_PUSH
7157 fprintf(stderr, "PP: Parsing XML Decl\n");
7158#endif
7159 xmlParseXMLDecl(ctxt);
7160 if ((ctxt->sax) && (ctxt->sax->startDocument))
7161 ctxt->sax->startDocument(ctxt->userData);
7162 ctxt->instate = XML_PARSER_MISC;
7163#ifdef DEBUG_PUSH
7164 fprintf(stderr, "PP: entering MISC\n");
7165#endif
7166 } else {
7167 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
7168 if ((ctxt->sax) && (ctxt->sax->startDocument))
7169 ctxt->sax->startDocument(ctxt->userData);
7170 ctxt->instate = XML_PARSER_MISC;
7171#ifdef DEBUG_PUSH
7172 fprintf(stderr, "PP: entering MISC\n");
7173#endif
7174 }
7175 } else {
7176 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
7177 ctxt->sax->setDocumentLocator(ctxt->userData,
7178 &xmlDefaultSAXLocator);
7179 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
7180 if ((ctxt->sax) && (ctxt->sax->startDocument))
7181 ctxt->sax->startDocument(ctxt->userData);
7182 ctxt->instate = XML_PARSER_MISC;
7183#ifdef DEBUG_PUSH
7184 fprintf(stderr, "PP: entering MISC\n");
7185#endif
7186 }
7187 break;
7188 case XML_PARSER_MISC:
7189 SKIP_BLANKS;
7190 if (in->buf == NULL)
7191 avail = in->length - (in->cur - in->base);
7192 else
7193 avail = in->buf->buffer->use - (in->cur - in->base);
7194 if (avail < 2)
7195 goto done;
7196 cur = in->cur[0];
7197 next = in->cur[1];
7198 if ((cur == '<') && (next == '?')) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007199 if ((!terminate) &&
7200 (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007201 goto done;
7202#ifdef DEBUG_PUSH
7203 fprintf(stderr, "PP: Parsing PI\n");
7204#endif
7205 xmlParsePI(ctxt);
7206 } else if ((cur == '<') && (next == '!') &&
7207 (in->cur[2] == '-') && (in->cur[3] == '-')) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007208 if ((!terminate) &&
7209 (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007210 goto done;
7211#ifdef DEBUG_PUSH
7212 fprintf(stderr, "PP: Parsing Comment\n");
7213#endif
7214 xmlParseComment(ctxt);
7215 ctxt->instate = XML_PARSER_MISC;
7216 } else if ((cur == '<') && (next == '!') &&
7217 (in->cur[2] == 'D') && (in->cur[3] == 'O') &&
7218 (in->cur[4] == 'C') && (in->cur[5] == 'T') &&
7219 (in->cur[6] == 'Y') && (in->cur[7] == 'P') &&
7220 (in->cur[8] == 'E')) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007221 if ((!terminate) &&
7222 (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007223 goto done;
7224#ifdef DEBUG_PUSH
7225 fprintf(stderr, "PP: Parsing internal subset\n");
7226#endif
7227 xmlParseDocTypeDecl(ctxt);
7228 if (CUR == '[') {
7229 ctxt->instate = XML_PARSER_DTD;
7230#ifdef DEBUG_PUSH
7231 fprintf(stderr, "PP: entering DTD\n");
7232#endif
7233 } else {
7234 ctxt->instate = XML_PARSER_PROLOG;
7235#ifdef DEBUG_PUSH
7236 fprintf(stderr, "PP: entering PROLOG\n");
7237#endif
7238 }
7239 } else if ((cur == '<') && (next == '!') &&
7240 (avail < 9)) {
7241 goto done;
7242 } else {
7243 ctxt->instate = XML_PARSER_START_TAG;
7244#ifdef DEBUG_PUSH
7245 fprintf(stderr, "PP: entering START_TAG\n");
7246#endif
7247 }
7248 break;
Daniel Veillard7f858501999-11-17 17:32:38 +00007249 case XML_PARSER_PROLOG:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007250 SKIP_BLANKS;
7251 if (in->buf == NULL)
7252 avail = in->length - (in->cur - in->base);
7253 else
7254 avail = in->buf->buffer->use - (in->cur - in->base);
7255 if (avail < 2)
7256 goto done;
7257 cur = in->cur[0];
7258 next = in->cur[1];
7259 if ((cur == '<') && (next == '?')) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007260 if ((!terminate) &&
7261 (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007262 goto done;
7263#ifdef DEBUG_PUSH
7264 fprintf(stderr, "PP: Parsing PI\n");
7265#endif
7266 xmlParsePI(ctxt);
7267 } else if ((cur == '<') && (next == '!') &&
7268 (in->cur[2] == '-') && (in->cur[3] == '-')) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007269 if ((!terminate) &&
7270 (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007271 goto done;
7272#ifdef DEBUG_PUSH
7273 fprintf(stderr, "PP: Parsing Comment\n");
7274#endif
7275 xmlParseComment(ctxt);
7276 ctxt->instate = XML_PARSER_PROLOG;
7277 } else if ((cur == '<') && (next == '!') &&
7278 (avail < 4)) {
7279 goto done;
7280 } else {
7281 ctxt->instate = XML_PARSER_START_TAG;
7282#ifdef DEBUG_PUSH
7283 fprintf(stderr, "PP: entering START_TAG\n");
7284#endif
7285 }
7286 break;
Daniel Veillard7f858501999-11-17 17:32:38 +00007287 case XML_PARSER_EPILOG:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007288 SKIP_BLANKS;
7289 if (in->buf == NULL)
7290 avail = in->length - (in->cur - in->base);
7291 else
7292 avail = in->buf->buffer->use - (in->cur - in->base);
7293 if (avail < 2)
7294 goto done;
7295 cur = in->cur[0];
7296 next = in->cur[1];
7297 if ((cur == '<') && (next == '?')) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007298 if ((!terminate) &&
7299 (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007300 goto done;
7301#ifdef DEBUG_PUSH
7302 fprintf(stderr, "PP: Parsing PI\n");
7303#endif
7304 xmlParsePI(ctxt);
7305 ctxt->instate = XML_PARSER_EPILOG;
7306 } else if ((cur == '<') && (next == '!') &&
7307 (in->cur[2] == '-') && (in->cur[3] == '-')) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007308 if ((!terminate) &&
7309 (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007310 goto done;
7311#ifdef DEBUG_PUSH
7312 fprintf(stderr, "PP: Parsing Comment\n");
7313#endif
7314 xmlParseComment(ctxt);
7315 ctxt->instate = XML_PARSER_EPILOG;
7316 } else if ((cur == '<') && (next == '!') &&
7317 (avail < 4)) {
7318 goto done;
7319 } else {
7320 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
7321 ctxt->sax->error(ctxt->userData,
7322 "Extra content at the end of the document\n");
7323 ctxt->wellFormed = 0;
7324 ctxt->errNo = XML_ERR_DOCUMENT_END;
7325 ctxt->instate = XML_PARSER_EOF;
7326#ifdef DEBUG_PUSH
7327 fprintf(stderr, "PP: entering EOF\n");
7328#endif
7329 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
7330 ctxt->sax->endDocument(ctxt->userData);
7331 goto done;
7332 }
7333 break;
7334 case XML_PARSER_START_TAG: {
7335 xmlChar *name, *oldname;
7336
7337 if (avail < 2)
7338 goto done;
7339 cur = in->cur[0];
7340 if (cur != '<') {
7341 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
7342 ctxt->sax->error(ctxt->userData,
7343 "Start tag expect, '<' not found\n");
7344 ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
7345 ctxt->wellFormed = 0;
7346 ctxt->instate = XML_PARSER_EOF;
7347#ifdef DEBUG_PUSH
7348 fprintf(stderr, "PP: entering EOF\n");
7349#endif
7350 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
7351 ctxt->sax->endDocument(ctxt->userData);
7352 goto done;
7353 }
Daniel Veillard71b656e2000-01-05 14:46:17 +00007354 if ((!terminate) &&
7355 (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007356 goto done;
7357 name = xmlParseStartTag(ctxt);
7358 if (name == NULL) {
7359 ctxt->instate = XML_PARSER_EOF;
7360#ifdef DEBUG_PUSH
7361 fprintf(stderr, "PP: entering EOF\n");
7362#endif
7363 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
7364 ctxt->sax->endDocument(ctxt->userData);
7365 goto done;
7366 }
7367 namePush(ctxt, xmlStrdup(name));
7368
7369 /*
7370 * [ VC: Root Element Type ]
7371 * The Name in the document type declaration must match
7372 * the element type of the root element.
7373 */
7374 if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc &&
7375 ctxt->node && (ctxt->node == ctxt->myDoc->root))
7376 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
7377
7378 /*
7379 * Check for an Empty Element.
7380 */
7381 if ((CUR == '/') && (NXT(1) == '>')) {
7382 SKIP(2);
7383 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
7384 ctxt->sax->endElement(ctxt->userData, name);
7385 xmlFree(name);
7386 oldname = namePop(ctxt);
7387 if (oldname != NULL) {
7388#ifdef DEBUG_STACK
7389 fprintf(stderr,"Close: popped %s\n", oldname);
7390#endif
7391 xmlFree(oldname);
7392 }
7393 if (ctxt->name == NULL) {
7394 ctxt->instate = XML_PARSER_EPILOG;
7395#ifdef DEBUG_PUSH
7396 fprintf(stderr, "PP: entering EPILOG\n");
7397#endif
7398 } else {
7399 ctxt->instate = XML_PARSER_CONTENT;
7400#ifdef DEBUG_PUSH
7401 fprintf(stderr, "PP: entering CONTENT\n");
7402#endif
7403 }
7404 break;
7405 }
7406 if (CUR == '>') {
7407 NEXT;
7408 } else {
7409 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
7410 ctxt->sax->error(ctxt->userData,
7411 "Couldn't find end of Start Tag %s\n",
7412 name);
7413 ctxt->wellFormed = 0;
7414 ctxt->errNo = XML_ERR_GT_REQUIRED;
7415
7416 /*
7417 * end of parsing of this node.
7418 */
7419 nodePop(ctxt);
7420 oldname = namePop(ctxt);
7421 if (oldname != NULL) {
7422#ifdef DEBUG_STACK
7423 fprintf(stderr,"Close: popped %s\n", oldname);
7424#endif
7425 xmlFree(oldname);
7426 }
7427 }
7428 xmlFree(name);
7429 ctxt->instate = XML_PARSER_CONTENT;
7430#ifdef DEBUG_PUSH
7431 fprintf(stderr, "PP: entering CONTENT\n");
7432#endif
7433 break;
7434 }
7435 case XML_PARSER_CONTENT:
7436 /*
7437 * Handle preparsed entities and charRef
7438 */
7439 if (ctxt->token != 0) {
7440 xmlChar cur[2] = { 0 , 0 } ;
7441
7442 cur[0] = (xmlChar) ctxt->token;
7443 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
7444 ctxt->sax->characters(ctxt->userData, cur, 1);
7445 ctxt->token = 0;
7446 }
7447 if (avail < 2)
7448 goto done;
7449 cur = in->cur[0];
7450 next = in->cur[1];
7451 if ((cur == '<') && (next == '?')) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007452 if ((!terminate) &&
7453 (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007454 goto done;
7455#ifdef DEBUG_PUSH
7456 fprintf(stderr, "PP: Parsing PI\n");
7457#endif
7458 xmlParsePI(ctxt);
7459 } else if ((cur == '<') && (next == '!') &&
7460 (in->cur[2] == '-') && (in->cur[3] == '-')) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007461 if ((!terminate) &&
7462 (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007463 goto done;
7464#ifdef DEBUG_PUSH
7465 fprintf(stderr, "PP: Parsing Comment\n");
7466#endif
7467 xmlParseComment(ctxt);
7468 ctxt->instate = XML_PARSER_CONTENT;
7469 } else if ((cur == '<') && (in->cur[1] == '!') &&
7470 (in->cur[2] == '[') && (NXT(3) == 'C') &&
7471 (in->cur[4] == 'D') && (NXT(5) == 'A') &&
7472 (in->cur[6] == 'T') && (NXT(7) == 'A') &&
7473 (in->cur[8] == '[')) {
7474 SKIP(9);
7475 ctxt->instate = XML_PARSER_CDATA_SECTION;
7476#ifdef DEBUG_PUSH
7477 fprintf(stderr, "PP: entering CDATA_SECTION\n");
7478#endif
7479 break;
7480 } else if ((cur == '<') && (next == '!') &&
7481 (avail < 9)) {
7482 goto done;
7483 } else if ((cur == '<') && (next == '/')) {
7484 ctxt->instate = XML_PARSER_END_TAG;
7485#ifdef DEBUG_PUSH
7486 fprintf(stderr, "PP: entering END_TAG\n");
7487#endif
7488 break;
7489 } else if (cur == '<') {
7490 ctxt->instate = XML_PARSER_START_TAG;
7491#ifdef DEBUG_PUSH
7492 fprintf(stderr, "PP: entering START_TAG\n");
7493#endif
7494 break;
7495 } else if (cur == '&') {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007496 if ((!terminate) &&
7497 (xmlParseLookupSequence(ctxt, ';', 0, 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007498 goto done;
7499#ifdef DEBUG_PUSH
7500 fprintf(stderr, "PP: Parsing Reference\n");
7501#endif
7502 /* TODO: check generation of subtrees if noent !!! */
7503 xmlParseReference(ctxt);
7504 } else {
7505 /* TODO Avoid the extra copy, handle directly !!!!!! */
7506 /*
7507 * Goal of the following test is :
7508 * - minimize calls to the SAX 'character' callback
7509 * when they are mergeable
7510 * - handle an problem for isBlank when we only parse
7511 * a sequence of blank chars and the next one is
7512 * not available to check against '<' presence.
7513 * - tries to homogenize the differences in SAX
7514 * callbacks beween the push and pull versions
7515 * of the parser.
7516 */
7517 if ((ctxt->inputNr == 1) &&
7518 (avail < XML_PARSER_BIG_BUFFER_SIZE)) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00007519 if ((!terminate) &&
7520 (xmlParseLookupSequence(ctxt, '<', 0, 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007521 goto done;
7522 }
7523 ctxt->checkIndex = 0;
7524#ifdef DEBUG_PUSH
7525 fprintf(stderr, "PP: Parsing char data\n");
7526#endif
7527 xmlParseCharData(ctxt, 0);
7528 }
7529 /*
7530 * Pop-up of finished entities.
7531 */
7532 while ((CUR == 0) && (ctxt->inputNr > 1))
7533 xmlPopInput(ctxt);
7534 break;
7535 case XML_PARSER_CDATA_SECTION: {
7536 /*
7537 * The Push mode need to have the SAX callback for
7538 * cdataBlock merge back contiguous callbacks.
7539 */
7540 int base;
7541
7542 in = ctxt->input;
7543 base = xmlParseLookupSequence(ctxt, ']', ']', '>');
7544 if (base < 0) {
7545 if (avail >= XML_PARSER_BIG_BUFFER_SIZE + 2) {
7546 if (ctxt->sax != NULL) {
7547 if (ctxt->sax->cdataBlock != NULL)
7548 ctxt->sax->cdataBlock(ctxt->userData, in->cur,
7549 XML_PARSER_BIG_BUFFER_SIZE);
7550 }
7551 SKIP(XML_PARSER_BIG_BUFFER_SIZE);
7552 ctxt->checkIndex = 0;
7553 }
7554 goto done;
7555 } else {
7556 if ((ctxt->sax != NULL) && (base > 0)) {
7557 if (ctxt->sax->cdataBlock != NULL)
7558 ctxt->sax->cdataBlock(ctxt->userData,
7559 in->cur, base);
7560 }
7561 SKIP(base + 3);
7562 ctxt->checkIndex = 0;
7563 ctxt->instate = XML_PARSER_CONTENT;
7564#ifdef DEBUG_PUSH
7565 fprintf(stderr, "PP: entering CONTENT\n");
7566#endif
7567 }
7568 break;
7569 }
Daniel Veillard5e5c6231999-12-29 12:49:06 +00007570 case XML_PARSER_END_TAG:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007571 if (avail < 2)
7572 goto done;
Daniel Veillard71b656e2000-01-05 14:46:17 +00007573 if ((!terminate) &&
7574 (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007575 goto done;
7576 xmlParseEndTag(ctxt);
7577 if (ctxt->name == NULL) {
7578 ctxt->instate = XML_PARSER_EPILOG;
7579#ifdef DEBUG_PUSH
7580 fprintf(stderr, "PP: entering EPILOG\n");
7581#endif
7582 } else {
7583 ctxt->instate = XML_PARSER_CONTENT;
7584#ifdef DEBUG_PUSH
7585 fprintf(stderr, "PP: entering CONTENT\n");
7586#endif
7587 }
7588 break;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007589 case XML_PARSER_DTD: {
7590 /*
7591 * Sorry but progressive parsing of the internal subset
7592 * is not expected to be supported. We first check that
7593 * the full content of the internal subset is available and
7594 * the parsing is launched only at that point.
7595 * Internal subset ends up with "']' S? '>'" in an unescaped
7596 * section and not in a ']]>' sequence which are conditional
7597 * sections (whoever argued to keep that crap in XML deserve
7598 * a place in hell !).
7599 */
7600 int base, i;
7601 xmlChar *buf;
7602 xmlChar quote = 0;
7603
7604 base = in->cur - in->base;
7605 if (base < 0) return(0);
7606 if (ctxt->checkIndex > base)
7607 base = ctxt->checkIndex;
7608 buf = in->buf->buffer->content;
7609 for (;base < in->buf->buffer->use;base++) {
7610 if (quote != 0) {
7611 if (buf[base] == quote)
7612 quote = 0;
7613 continue;
7614 }
7615 if (buf[base] == '"') {
7616 quote = '"';
7617 continue;
7618 }
7619 if (buf[base] == '\'') {
7620 quote = '\'';
7621 continue;
7622 }
7623 if (buf[base] == ']') {
7624 if (base +1 >= in->buf->buffer->use)
7625 break;
7626 if (buf[base + 1] == ']') {
7627 /* conditional crap, skip both ']' ! */
7628 base++;
7629 continue;
7630 }
7631 for (i = 0;base + i < in->buf->buffer->use;i++) {
7632 if (buf[base + i] == '>')
7633 goto found_end_int_subset;
7634 }
7635 break;
7636 }
7637 }
7638 /*
7639 * We didn't found the end of the Internal subset
7640 */
7641 if (quote == 0)
7642 ctxt->checkIndex = base;
7643#ifdef DEBUG_PUSH
7644 if (next == 0)
7645 fprintf(stderr, "PP: lookup of int subset end filed\n");
7646#endif
7647 goto done;
7648
7649found_end_int_subset:
7650 xmlParseInternalSubset(ctxt);
7651 ctxt->instate = XML_PARSER_PROLOG;
7652 ctxt->checkIndex = 0;
7653#ifdef DEBUG_PUSH
7654 fprintf(stderr, "PP: entering PROLOG\n");
7655#endif
7656 break;
7657 }
Daniel Veillard7f858501999-11-17 17:32:38 +00007658 case XML_PARSER_COMMENT:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007659 fprintf(stderr, "PP: internal error, state == COMMENT\n");
7660 ctxt->instate = XML_PARSER_CONTENT;
7661#ifdef DEBUG_PUSH
7662 fprintf(stderr, "PP: entering CONTENT\n");
7663#endif
7664 break;
7665 case XML_PARSER_PI:
7666 fprintf(stderr, "PP: internal error, state == PI\n");
7667 ctxt->instate = XML_PARSER_CONTENT;
7668#ifdef DEBUG_PUSH
7669 fprintf(stderr, "PP: entering CONTENT\n");
7670#endif
7671 break;
7672 case XML_PARSER_ENTITY_DECL:
7673 fprintf(stderr, "PP: internal error, state == ENTITY_DECL\n");
7674 ctxt->instate = XML_PARSER_DTD;
7675#ifdef DEBUG_PUSH
7676 fprintf(stderr, "PP: entering DTD\n");
7677#endif
7678 break;
7679 case XML_PARSER_ENTITY_VALUE:
7680 fprintf(stderr, "PP: internal error, state == ENTITY_VALUE\n");
7681 ctxt->instate = XML_PARSER_CONTENT;
7682#ifdef DEBUG_PUSH
7683 fprintf(stderr, "PP: entering DTD\n");
7684#endif
7685 break;
7686 case XML_PARSER_ATTRIBUTE_VALUE:
7687 fprintf(stderr, "PP: internal error, state == ATTRIBUTE_VALUE\n");
7688 ctxt->instate = XML_PARSER_START_TAG;
7689#ifdef DEBUG_PUSH
7690 fprintf(stderr, "PP: entering START_TAG\n");
7691#endif
7692 break;
Daniel Veillard7f858501999-11-17 17:32:38 +00007693 }
7694 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007695done:
7696#ifdef DEBUG_PUSH
7697 fprintf(stderr, "PP: done %d\n", ret);
7698#endif
Daniel Veillard7f858501999-11-17 17:32:38 +00007699 return(ret);
7700}
7701
7702/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00007703 * xmlParseTry:
7704 * @ctxt: an XML parser context
7705 *
7706 * Try to progress on parsing
7707 *
7708 * Returns zero if no parsing was possible
7709 */
7710int
7711xmlParseTry(xmlParserCtxtPtr ctxt) {
7712 return(xmlParseTryOrFinish(ctxt, 0));
7713}
7714
7715/**
Daniel Veillard7f858501999-11-17 17:32:38 +00007716 * xmlParseChunk:
7717 * @ctxt: an XML parser context
7718 * @chunk: an char array
7719 * @size: the size in byte of the chunk
7720 * @terminate: last chunk indicator
7721 *
7722 * Parse a Chunk of memory
7723 *
7724 * Returns zero if no error, the xmlParserErrors otherwise.
7725 */
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007726int
Daniel Veillard7f858501999-11-17 17:32:38 +00007727xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
7728 int terminate) {
Daniel Veillarda819dac1999-11-24 18:04:22 +00007729 if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007730 (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF)) {
7731 int base = ctxt->input->base - ctxt->input->buf->buffer->content;
7732 int cur = ctxt->input->cur - ctxt->input->base;
7733
Daniel Veillarda819dac1999-11-24 18:04:22 +00007734 xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007735 ctxt->input->base = ctxt->input->buf->buffer->content + base;
7736 ctxt->input->cur = ctxt->input->base + cur;
7737#ifdef DEBUG_PUSH
7738 fprintf(stderr, "PP: pushed %d\n", size);
7739#endif
7740
Daniel Veillard71b656e2000-01-05 14:46:17 +00007741 xmlParseTryOrFinish(ctxt, terminate);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007742 } else if (ctxt->instate != XML_PARSER_EOF)
Daniel Veillard71b656e2000-01-05 14:46:17 +00007743 xmlParseTryOrFinish(ctxt, terminate);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007744 if (terminate) {
7745 if ((ctxt->instate != XML_PARSER_EOF) &&
7746 (ctxt->instate != XML_PARSER_EPILOG)) {
7747 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
7748 ctxt->sax->error(ctxt->userData,
7749 "Extra content at the end of the document\n");
7750 ctxt->wellFormed = 0;
7751 ctxt->errNo = XML_ERR_DOCUMENT_END;
7752 }
7753 if (ctxt->instate != XML_PARSER_EOF) {
7754 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
7755 ctxt->sax->endDocument(ctxt->userData);
7756 }
7757 ctxt->instate = XML_PARSER_EOF;
Daniel Veillard7f858501999-11-17 17:32:38 +00007758 }
7759 return((xmlParserErrors) ctxt->errNo);
7760}
7761
7762/************************************************************************
7763 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00007764 * I/O front end functions to the parser *
7765 * *
7766 ************************************************************************/
7767
Daniel Veillard11e00581998-10-24 18:27:49 +00007768/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +00007769 * xmlCreatePushParserCtxt :
7770 * @sax: a SAX handler
7771 * @user_data: The user data returned on SAX callbacks
7772 * @chunk: a pointer to an array of chars
7773 * @size: number of chars in the array
7774 * @filename: an optional file name or URI
7775 *
7776 * Create a parser context for using the XML parser in push mode
7777 * To allow content encoding detection, @size should be >= 4
7778 * The value of @filename is used for fetching external entities
7779 * and error/warning reports.
7780 *
7781 * Returns the new parser context or NULL
7782 */
7783xmlParserCtxtPtr
7784xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
7785 const char *chunk, int size, const char *filename) {
7786 xmlParserCtxtPtr ctxt;
7787 xmlParserInputPtr inputStream;
7788 xmlParserInputBufferPtr buf;
7789 xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
7790
7791 /*
7792 * plug some encoding conversion routines here. !!!
7793 */
7794 if ((chunk != NULL) && (size >= 4))
7795 enc = xmlDetectCharEncoding((const xmlChar *) chunk);
7796
7797 buf = xmlAllocParserInputBuffer(enc);
7798 if (buf == NULL) return(NULL);
7799
7800 ctxt = xmlNewParserCtxt();
7801 if (ctxt == NULL) {
7802 xmlFree(buf);
7803 return(NULL);
7804 }
7805 if (sax != NULL) {
7806 if (ctxt->sax != &xmlDefaultSAXHandler)
7807 xmlFree(ctxt->sax);
7808 ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler));
7809 if (ctxt->sax == NULL) {
7810 xmlFree(buf);
7811 xmlFree(ctxt);
7812 return(NULL);
7813 }
7814 memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler));
7815 if (user_data != NULL)
7816 ctxt->userData = user_data;
7817 }
7818 if (filename == NULL) {
7819 ctxt->directory = NULL;
7820 } else {
7821 ctxt->directory = xmlParserGetDirectory(filename);
7822 }
7823
7824 inputStream = xmlNewInputStream(ctxt);
7825 if (inputStream == NULL) {
7826 xmlFreeParserCtxt(ctxt);
7827 return(NULL);
7828 }
7829
7830 if (filename == NULL)
7831 inputStream->filename = NULL;
7832 else
7833 inputStream->filename = xmlMemStrdup(filename);
7834 inputStream->buf = buf;
7835 inputStream->base = inputStream->buf->buffer->content;
7836 inputStream->cur = inputStream->buf->buffer->content;
7837
7838 inputPush(ctxt, inputStream);
7839
7840 if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
7841 (ctxt->input->buf != NULL)) {
7842 xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
7843#ifdef DEBUG_PUSH
7844 fprintf(stderr, "PP: pushed %d\n", size);
7845#endif
7846 }
7847
7848 return(ctxt);
7849}
7850
7851/**
Daniel Veillardbe70ff71999-07-05 16:50:46 +00007852 * xmlCreateDocParserCtxt :
Daniel Veillarddd6b3671999-09-23 22:19:22 +00007853 * @cur: a pointer to an array of xmlChar
Daniel Veillardd692aa41999-02-28 21:54:31 +00007854 *
7855 * Create a parser context for an XML in-memory document.
7856 *
7857 * Returns the new parser context or NULL
7858 */
7859xmlParserCtxtPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00007860xmlCreateDocParserCtxt(xmlChar *cur) {
Daniel Veillardd692aa41999-02-28 21:54:31 +00007861 xmlParserCtxtPtr ctxt;
7862 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00007863 xmlCharEncoding enc;
Daniel Veillardd692aa41999-02-28 21:54:31 +00007864
Daniel Veillardb05deb71999-08-10 19:04:08 +00007865 ctxt = xmlNewParserCtxt();
Daniel Veillardd692aa41999-02-28 21:54:31 +00007866 if (ctxt == NULL) {
Daniel Veillardd692aa41999-02-28 21:54:31 +00007867 return(NULL);
7868 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00007869 input = xmlNewInputStream(ctxt);
Daniel Veillardd692aa41999-02-28 21:54:31 +00007870 if (input == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00007871 xmlFreeParserCtxt(ctxt);
Daniel Veillardd692aa41999-02-28 21:54:31 +00007872 return(NULL);
7873 }
7874
Daniel Veillard27d88741999-05-29 11:51:49 +00007875 /*
7876 * plug some encoding conversion routines here. !!!
7877 */
7878 enc = xmlDetectCharEncoding(cur);
7879 xmlSwitchEncoding(ctxt, enc);
7880
Daniel Veillardd692aa41999-02-28 21:54:31 +00007881 input->base = cur;
7882 input->cur = cur;
Daniel Veillardd692aa41999-02-28 21:54:31 +00007883
7884 inputPush(ctxt, input);
7885 return(ctxt);
7886}
7887
7888/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00007889 * xmlSAXParseDoc :
7890 * @sax: the SAX handler block
Daniel Veillarddd6b3671999-09-23 22:19:22 +00007891 * @cur: a pointer to an array of xmlChar
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00007892 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
7893 * documents
Daniel Veillard11e00581998-10-24 18:27:49 +00007894 *
7895 * parse an XML in-memory document and build a tree.
Daniel Veillard42dc9b31998-11-09 01:17:21 +00007896 * It use the given SAX function block to handle the parsing callback.
7897 * If sax is NULL, fallback to the default DOM tree building routines.
Daniel Veillard11e00581998-10-24 18:27:49 +00007898 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00007899 * Returns the resulting document tree
Daniel Veillard260a68f1998-08-13 03:39:55 +00007900 */
7901
Daniel Veillard1e346af1999-02-22 10:33:01 +00007902xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00007903xmlSAXParseDoc(xmlSAXHandlerPtr sax, xmlChar *cur, int recovery) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00007904 xmlDocPtr ret;
7905 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00007906
7907 if (cur == NULL) return(NULL);
7908
Daniel Veillardd692aa41999-02-28 21:54:31 +00007909
7910 ctxt = xmlCreateDocParserCtxt(cur);
7911 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00007912 if (sax != NULL) {
7913 ctxt->sax = sax;
7914 ctxt->userData = NULL;
7915 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00007916
7917 xmlParseDocument(ctxt);
Daniel Veillard517752b1999-04-05 12:20:10 +00007918 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00007919 else {
7920 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00007921 xmlFreeDoc(ctxt->myDoc);
7922 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00007923 }
Daniel Veillard97fea181999-06-26 23:07:37 +00007924 if (sax != NULL)
7925 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00007926 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00007927
7928 return(ret);
7929}
7930
Daniel Veillard11e00581998-10-24 18:27:49 +00007931/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00007932 * xmlParseDoc :
Daniel Veillarddd6b3671999-09-23 22:19:22 +00007933 * @cur: a pointer to an array of xmlChar
Daniel Veillard42dc9b31998-11-09 01:17:21 +00007934 *
7935 * parse an XML in-memory document and build a tree.
7936 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00007937 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00007938 */
7939
Daniel Veillard1e346af1999-02-22 10:33:01 +00007940xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00007941xmlParseDoc(xmlChar *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00007942 return(xmlSAXParseDoc(NULL, cur, 0));
7943}
7944
7945/**
Daniel Veillard011b63c1999-06-02 17:44:04 +00007946 * xmlSAXParseDTD :
7947 * @sax: the SAX handler block
7948 * @ExternalID: a NAME* containing the External ID of the DTD
7949 * @SystemID: a NAME* containing the URL to the DTD
7950 *
7951 * Load and parse an external subset.
7952 *
7953 * Returns the resulting xmlDtdPtr or NULL in case of error.
7954 */
7955
7956xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00007957xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID,
7958 const xmlChar *SystemID) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00007959 xmlDtdPtr ret = NULL;
7960 xmlParserCtxtPtr ctxt;
Daniel Veillard14fff061999-06-22 21:49:07 +00007961 xmlParserInputPtr input = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00007962 xmlCharEncoding enc;
7963
7964 if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL);
7965
Daniel Veillardb05deb71999-08-10 19:04:08 +00007966 ctxt = xmlNewParserCtxt();
Daniel Veillard011b63c1999-06-02 17:44:04 +00007967 if (ctxt == NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00007968 return(NULL);
7969 }
Daniel Veillard011b63c1999-06-02 17:44:04 +00007970
7971 /*
7972 * Set-up the SAX context
7973 */
7974 if (ctxt == NULL) return(NULL);
7975 if (sax != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00007976 if (ctxt->sax != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00007977 xmlFree(ctxt->sax);
Daniel Veillard011b63c1999-06-02 17:44:04 +00007978 ctxt->sax = sax;
7979 ctxt->userData = NULL;
7980 }
7981
7982 /*
7983 * Ask the Entity resolver to load the damn thing
7984 */
7985
7986 if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
7987 input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, SystemID);
7988 if (input == NULL) {
Daniel Veillard97fea181999-06-26 23:07:37 +00007989 if (sax != NULL) ctxt->sax = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00007990 xmlFreeParserCtxt(ctxt);
7991 return(NULL);
7992 }
7993
7994 /*
7995 * plug some encoding conversion routines here. !!!
7996 */
7997 xmlPushInput(ctxt, input);
7998 enc = xmlDetectCharEncoding(ctxt->input->cur);
7999 xmlSwitchEncoding(ctxt, enc);
8000
Daniel Veillardb05deb71999-08-10 19:04:08 +00008001 if (input->filename == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00008002 input->filename = (char *) xmlStrdup(SystemID); /* !!!!!!! */
Daniel Veillard011b63c1999-06-02 17:44:04 +00008003 input->line = 1;
8004 input->col = 1;
8005 input->base = ctxt->input->cur;
8006 input->cur = ctxt->input->cur;
8007 input->free = NULL;
8008
8009 /*
8010 * let's parse that entity knowing it's an external subset.
8011 */
8012 xmlParseExternalSubset(ctxt, ExternalID, SystemID);
8013
8014 if (ctxt->myDoc != NULL) {
8015 if (ctxt->wellFormed) {
8016 ret = ctxt->myDoc->intSubset;
8017 ctxt->myDoc->intSubset = NULL;
8018 } else {
8019 ret = NULL;
8020 }
8021 xmlFreeDoc(ctxt->myDoc);
8022 ctxt->myDoc = NULL;
8023 }
Daniel Veillard97fea181999-06-26 23:07:37 +00008024 if (sax != NULL) ctxt->sax = NULL;
Daniel Veillard011b63c1999-06-02 17:44:04 +00008025 xmlFreeParserCtxt(ctxt);
8026
8027 return(ret);
8028}
8029
8030/**
8031 * xmlParseDTD :
8032 * @ExternalID: a NAME* containing the External ID of the DTD
8033 * @SystemID: a NAME* containing the URL to the DTD
8034 *
8035 * Load and parse an external subset.
8036 *
8037 * Returns the resulting xmlDtdPtr or NULL in case of error.
8038 */
8039
8040xmlDtdPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00008041xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00008042 return(xmlSAXParseDTD(NULL, ExternalID, SystemID));
8043}
8044
8045/**
Daniel Veillard0142b842000-01-14 14:45:24 +00008046 * xmlSAXParseBalancedChunk :
8047 * @ctx: an XML parser context (possibly NULL)
8048 * @sax: the SAX handler bloc (possibly NULL)
8049 * @user_data: The user data returned on SAX callbacks (possibly NULL)
8050 * @input: a parser input stream
8051 * @enc: the encoding
8052 *
8053 * Parse a well-balanced chunk of an XML document
8054 * The user has to provide SAX callback block whose routines will be
8055 * called by the parser
8056 * The allowed sequence for the Well Balanced Chunk is the one defined by
8057 * the content production in the XML grammar:
8058 *
8059 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
8060 *
8061 * Returns 0 id the chunk is well balanced, -1 in case of args problem and
8062 * the error code otherwise
8063 */
8064
8065int
8066xmlSAXParseBalancedChunk(xmlParserCtxtPtr ctx, xmlSAXHandlerPtr sax,
8067 void *user_data, xmlParserInputPtr input,
8068 xmlCharEncoding enc) {
8069 xmlParserCtxtPtr ctxt;
8070 int ret;
8071
8072 if (input == NULL) return(-1);
8073
8074 if (ctx != NULL)
8075 ctxt = ctx;
8076 else {
8077 ctxt = xmlNewParserCtxt();
8078 if (ctxt == NULL)
8079 return(-1);
8080 if (sax == NULL)
8081 ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
8082 }
8083
8084 /*
8085 * Set-up the SAX context
8086 */
8087 if (sax != NULL) {
8088 if (ctxt->sax != NULL)
8089 xmlFree(ctxt->sax);
8090 ctxt->sax = sax;
8091 ctxt->userData = user_data;
8092 }
8093
8094 /*
8095 * plug some encoding conversion routines here.
8096 */
8097 xmlPushInput(ctxt, input);
8098 if (enc != XML_CHAR_ENCODING_NONE)
8099 xmlSwitchEncoding(ctxt, enc);
8100
8101 /*
8102 * let's parse that entity knowing it's an external subset.
8103 */
8104 xmlParseContent(ctxt);
8105 ret = ctxt->errNo;
8106
8107 if (ctx == NULL) {
8108 if (sax != NULL)
8109 ctxt->sax = NULL;
8110 else
8111 xmlFreeDoc(ctxt->myDoc);
8112 xmlFreeParserCtxt(ctxt);
8113 }
8114 return(ret);
8115}
8116
8117/**
8118 * xmlParseBalancedChunk :
8119 * @doc: the document the chunk pertains to
8120 * @node: the node defining the context in which informations will be added
8121 *
8122 * Parse a well-balanced chunk of an XML document present in memory
8123 *
8124 * Returns the resulting list of nodes resulting from the parsing,
8125 * they are not added to @node
8126 */
8127
8128xmlNodePtr
8129xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlNodePtr node) {
8130}
8131
8132/**
8133 * xmlParseBalancedChunkFile :
8134 * @doc: the document the chunk pertains to
8135 *
8136 * Parse a well-balanced chunk of an XML document contained in a file
8137 *
8138 * Returns the resulting list of nodes resulting from the parsing,
8139 * they are not added to @node
8140 */
8141
8142xmlNodePtr
8143xmlParseBalancedChunkFile(xmlDocPtr doc, xmlNodePtr node) {
8144}
8145
8146/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008147 * xmlRecoverDoc :
Daniel Veillarddd6b3671999-09-23 22:19:22 +00008148 * @cur: a pointer to an array of xmlChar
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008149 *
8150 * parse an XML in-memory document and build a tree.
8151 * In the case the document is not Well Formed, a tree is built anyway
8152 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00008153 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008154 */
8155
Daniel Veillard1e346af1999-02-22 10:33:01 +00008156xmlDocPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00008157xmlRecoverDoc(xmlChar *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008158 return(xmlSAXParseDoc(NULL, cur, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00008159}
8160
8161/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00008162 * xmlCreateFileParserCtxt :
Daniel Veillard11e00581998-10-24 18:27:49 +00008163 * @filename: the filename
8164 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00008165 * Create a parser context for a file content.
8166 * Automatic support for ZLIB/Compress compressed document is provided
8167 * by default if found at compile-time.
Daniel Veillard11e00581998-10-24 18:27:49 +00008168 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00008169 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00008170 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00008171xmlParserCtxtPtr
8172xmlCreateFileParserCtxt(const char *filename)
8173{
8174 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008175 xmlParserInputPtr inputStream;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00008176 xmlParserInputBufferPtr buf;
Daniel Veillardb05deb71999-08-10 19:04:08 +00008177 char *directory = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008178
Daniel Veillarde2d034d1999-07-27 19:52:06 +00008179 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
8180 if (buf == NULL) return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008181
Daniel Veillardb05deb71999-08-10 19:04:08 +00008182 ctxt = xmlNewParserCtxt();
Daniel Veillard260a68f1998-08-13 03:39:55 +00008183 if (ctxt == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00008184 return(NULL);
8185 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00008186
8187 inputStream = xmlNewInputStream(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008188 if (inputStream == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00008189 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008190 return(NULL);
8191 }
8192
Daniel Veillard6454aec1999-09-02 22:04:43 +00008193 inputStream->filename = xmlMemStrdup(filename);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00008194 inputStream->buf = buf;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00008195 inputStream->base = inputStream->buf->buffer->content;
8196 inputStream->cur = inputStream->buf->buffer->content;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008197
8198 inputPush(ctxt, inputStream);
Daniel Veillardb05deb71999-08-10 19:04:08 +00008199 if ((ctxt->directory == NULL) && (directory == NULL))
8200 directory = xmlParserGetDirectory(filename);
8201 if ((ctxt->directory == NULL) && (directory != NULL))
8202 ctxt->directory = directory;
8203
Daniel Veillardd692aa41999-02-28 21:54:31 +00008204 return(ctxt);
8205}
8206
8207/**
8208 * xmlSAXParseFile :
8209 * @sax: the SAX handler block
8210 * @filename: the filename
8211 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
8212 * documents
8213 *
8214 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
8215 * compressed document is provided by default if found at compile-time.
8216 * It use the given SAX function block to handle the parsing callback.
8217 * If sax is NULL, fallback to the default DOM tree building routines.
8218 *
8219 * Returns the resulting document tree
8220 */
8221
Daniel Veillard011b63c1999-06-02 17:44:04 +00008222xmlDocPtr
8223xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
Daniel Veillardd692aa41999-02-28 21:54:31 +00008224 int recovery) {
8225 xmlDocPtr ret;
8226 xmlParserCtxtPtr ctxt;
Daniel Veillardb05deb71999-08-10 19:04:08 +00008227 char *directory = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00008228
8229 ctxt = xmlCreateFileParserCtxt(filename);
8230 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00008231 if (sax != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00008232 if (ctxt->sax != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00008233 xmlFree(ctxt->sax);
Daniel Veillard27d88741999-05-29 11:51:49 +00008234 ctxt->sax = sax;
8235 ctxt->userData = NULL;
8236 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00008237
Daniel Veillardb05deb71999-08-10 19:04:08 +00008238 if ((ctxt->directory == NULL) && (directory == NULL))
8239 directory = xmlParserGetDirectory(filename);
8240 if ((ctxt->directory == NULL) && (directory != NULL))
Daniel Veillarddd6b3671999-09-23 22:19:22 +00008241 ctxt->directory = (char *) xmlStrdup((xmlChar *) directory); /* !!!!!!! */
Daniel Veillardb05deb71999-08-10 19:04:08 +00008242
Daniel Veillard260a68f1998-08-13 03:39:55 +00008243 xmlParseDocument(ctxt);
8244
Daniel Veillard517752b1999-04-05 12:20:10 +00008245 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008246 else {
8247 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00008248 xmlFreeDoc(ctxt->myDoc);
8249 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008250 }
Daniel Veillard97fea181999-06-26 23:07:37 +00008251 if (sax != NULL)
8252 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00008253 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008254
8255 return(ret);
8256}
8257
Daniel Veillard42dc9b31998-11-09 01:17:21 +00008258/**
8259 * xmlParseFile :
8260 * @filename: the filename
8261 *
8262 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
8263 * compressed document is provided by default if found at compile-time.
8264 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00008265 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00008266 */
8267
Daniel Veillard011b63c1999-06-02 17:44:04 +00008268xmlDocPtr
8269xmlParseFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008270 return(xmlSAXParseFile(NULL, filename, 0));
8271}
8272
8273/**
8274 * xmlRecoverFile :
8275 * @filename: the filename
8276 *
8277 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
8278 * compressed document is provided by default if found at compile-time.
8279 * In the case the document is not Well Formed, a tree is built anyway
8280 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00008281 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008282 */
8283
Daniel Veillard011b63c1999-06-02 17:44:04 +00008284xmlDocPtr
8285xmlRecoverFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008286 return(xmlSAXParseFile(NULL, filename, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00008287}
Daniel Veillard260a68f1998-08-13 03:39:55 +00008288
Daniel Veillard11e00581998-10-24 18:27:49 +00008289/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00008290 * xmlCreateMemoryParserCtxt :
Daniel Veillard1e346af1999-02-22 10:33:01 +00008291 * @buffer: an pointer to a char array
Daniel Veillard51e3b151999-11-12 17:02:31 +00008292 * @size: the size of the array
Daniel Veillard11e00581998-10-24 18:27:49 +00008293 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00008294 * Create a parser context for an XML in-memory document.
Daniel Veillard11e00581998-10-24 18:27:49 +00008295 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00008296 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00008297 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00008298xmlParserCtxtPtr
8299xmlCreateMemoryParserCtxt(char *buffer, int size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00008300 xmlParserCtxtPtr ctxt;
8301 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00008302 xmlCharEncoding enc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008303
8304 buffer[size - 1] = '\0';
8305
Daniel Veillardb05deb71999-08-10 19:04:08 +00008306 ctxt = xmlNewParserCtxt();
Daniel Veillard260a68f1998-08-13 03:39:55 +00008307 if (ctxt == NULL) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00008308 return(NULL);
8309 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00008310
8311 input = xmlNewInputStream(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008312 if (input == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00008313 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008314 return(NULL);
8315 }
8316
8317 input->filename = NULL;
8318 input->line = 1;
8319 input->col = 1;
Daniel Veillardb05deb71999-08-10 19:04:08 +00008320 input->buf = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00008321 input->consumed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008322
8323 /*
Daniel Veillard27d88741999-05-29 11:51:49 +00008324 * plug some encoding conversion routines here. !!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00008325 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00008326 enc = xmlDetectCharEncoding(BAD_CAST buffer);
Daniel Veillard27d88741999-05-29 11:51:49 +00008327 xmlSwitchEncoding(ctxt, enc);
8328
Daniel Veillardb96e6431999-08-29 21:02:19 +00008329 input->base = BAD_CAST buffer;
8330 input->cur = BAD_CAST buffer;
Daniel Veillardd692aa41999-02-28 21:54:31 +00008331 input->free = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008332
8333 inputPush(ctxt, input);
Daniel Veillardd692aa41999-02-28 21:54:31 +00008334 return(ctxt);
8335}
8336
8337/**
8338 * xmlSAXParseMemory :
8339 * @sax: the SAX handler block
8340 * @buffer: an pointer to a char array
Daniel Veillard51e3b151999-11-12 17:02:31 +00008341 * @size: the size of the array
8342 * @recovery: work in recovery mode, i.e. tries to read not Well Formed
Daniel Veillardd692aa41999-02-28 21:54:31 +00008343 * documents
8344 *
8345 * parse an XML in-memory block and use the given SAX function block
8346 * to handle the parsing callback. If sax is NULL, fallback to the default
8347 * DOM tree building routines.
8348 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00008349 * Returns the resulting document tree
8350 */
8351xmlDocPtr
8352xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
8353 xmlDocPtr ret;
8354 xmlParserCtxtPtr ctxt;
8355
8356 ctxt = xmlCreateMemoryParserCtxt(buffer, size);
8357 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00008358 if (sax != NULL) {
8359 ctxt->sax = sax;
8360 ctxt->userData = NULL;
8361 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00008362
8363 xmlParseDocument(ctxt);
8364
Daniel Veillard517752b1999-04-05 12:20:10 +00008365 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008366 else {
8367 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00008368 xmlFreeDoc(ctxt->myDoc);
8369 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008370 }
Daniel Veillard97fea181999-06-26 23:07:37 +00008371 if (sax != NULL)
8372 ctxt->sax = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00008373 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008374
8375 return(ret);
8376}
8377
Daniel Veillard42dc9b31998-11-09 01:17:21 +00008378/**
8379 * xmlParseMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00008380 * @buffer: an pointer to a char array
Daniel Veillard42dc9b31998-11-09 01:17:21 +00008381 * @size: the size of the array
8382 *
8383 * parse an XML in-memory block and build a tree.
8384 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00008385 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00008386 */
8387
8388xmlDocPtr xmlParseMemory(char *buffer, int size) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008389 return(xmlSAXParseMemory(NULL, buffer, size, 0));
8390}
8391
8392/**
8393 * xmlRecoverMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00008394 * @buffer: an pointer to a char array
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008395 * @size: the size of the array
8396 *
8397 * parse an XML in-memory block and build a tree.
8398 * In the case the document is not Well Formed, a tree is built anyway
8399 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00008400 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00008401 */
8402
8403xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
8404 return(xmlSAXParseMemory(NULL, buffer, size, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00008405}
Daniel Veillard260a68f1998-08-13 03:39:55 +00008406
Daniel Veillard260a68f1998-08-13 03:39:55 +00008407
Daniel Veillard11e00581998-10-24 18:27:49 +00008408/**
8409 * xmlSetupParserForBuffer:
8410 * @ctxt: an XML parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00008411 * @buffer: a xmlChar * buffer
Daniel Veillard11e00581998-10-24 18:27:49 +00008412 * @filename: a file name
8413 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00008414 * Setup the parser context to parse a new buffer; Clears any prior
8415 * contents from the parser context. The buffer parameter must not be
8416 * NULL, but the filename parameter can be
8417 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00008418void
Daniel Veillarddd6b3671999-09-23 22:19:22 +00008419xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer,
Daniel Veillard260a68f1998-08-13 03:39:55 +00008420 const char* filename)
8421{
Daniel Veillardb05deb71999-08-10 19:04:08 +00008422 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008423
Daniel Veillardb05deb71999-08-10 19:04:08 +00008424 input = xmlNewInputStream(ctxt);
8425 if (input == NULL) {
8426 perror("malloc");
Daniel Veillard6454aec1999-09-02 22:04:43 +00008427 xmlFree(ctxt);
Daniel Veillard0142b842000-01-14 14:45:24 +00008428 return;
Daniel Veillardb05deb71999-08-10 19:04:08 +00008429 }
8430
8431 xmlClearParserCtxt(ctxt);
8432 if (filename != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00008433 input->filename = xmlMemStrdup(filename);
Daniel Veillardb05deb71999-08-10 19:04:08 +00008434 input->base = buffer;
8435 input->cur = buffer;
8436 inputPush(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008437}
8438
Daniel Veillard7a66ee61999-09-26 11:31:02 +00008439/**
8440 * xmlSAXUserParseFile:
8441 * @sax: a SAX handler
8442 * @user_data: The user data returned on SAX callbacks
8443 * @filename: a file name
8444 *
8445 * parse an XML file and call the given SAX handler routines.
8446 * Automatic support for ZLIB/Compress compressed document is provided
8447 *
8448 * Returns 0 in case of success or a error number otherwise
8449 */
Daniel Veillard11a48ec1999-11-23 10:40:46 +00008450int
8451xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data,
8452 const char *filename) {
Daniel Veillard7a66ee61999-09-26 11:31:02 +00008453 int ret = 0;
8454 xmlParserCtxtPtr ctxt;
8455
8456 ctxt = xmlCreateFileParserCtxt(filename);
8457 if (ctxt == NULL) return -1;
Daniel Veillard294cbca1999-12-03 13:19:09 +00008458 if (ctxt->sax != &xmlDefaultSAXHandler)
8459 xmlFree(ctxt->sax);
Daniel Veillard7a66ee61999-09-26 11:31:02 +00008460 ctxt->sax = sax;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00008461 if (user_data != NULL)
8462 ctxt->userData = user_data;
Daniel Veillard7a66ee61999-09-26 11:31:02 +00008463
8464 xmlParseDocument(ctxt);
8465
8466 if (ctxt->wellFormed)
8467 ret = 0;
8468 else {
8469 if (ctxt->errNo != 0)
8470 ret = ctxt->errNo;
8471 else
8472 ret = -1;
8473 }
8474 if (sax != NULL)
8475 ctxt->sax = NULL;
8476 xmlFreeParserCtxt(ctxt);
8477
8478 return ret;
8479}
8480
8481/**
8482 * xmlSAXUserParseMemory:
8483 * @sax: a SAX handler
8484 * @user_data: The user data returned on SAX callbacks
8485 * @buffer: an in-memory XML document input
Daniel Veillard51e3b151999-11-12 17:02:31 +00008486 * @size: the length of the XML document in bytes
Daniel Veillard7a66ee61999-09-26 11:31:02 +00008487 *
8488 * A better SAX parsing routine.
8489 * parse an XML in-memory buffer and call the given SAX handler routines.
8490 *
8491 * Returns 0 in case of success or a error number otherwise
8492 */
8493int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data,
8494 char *buffer, int size) {
8495 int ret = 0;
8496 xmlParserCtxtPtr ctxt;
8497
8498 ctxt = xmlCreateMemoryParserCtxt(buffer, size);
8499 if (ctxt == NULL) return -1;
8500 ctxt->sax = sax;
8501 ctxt->userData = user_data;
8502
8503 xmlParseDocument(ctxt);
8504
8505 if (ctxt->wellFormed)
8506 ret = 0;
8507 else {
8508 if (ctxt->errNo != 0)
8509 ret = ctxt->errNo;
8510 else
8511 ret = -1;
8512 }
8513 if (sax != NULL)
8514 ctxt->sax = NULL;
8515 xmlFreeParserCtxt(ctxt);
8516
8517 return ret;
8518}
8519
Daniel Veillard260a68f1998-08-13 03:39:55 +00008520
Daniel Veillardb05deb71999-08-10 19:04:08 +00008521/************************************************************************
8522 * *
Daniel Veillard51e3b151999-11-12 17:02:31 +00008523 * Miscellaneous *
Daniel Veillardb05deb71999-08-10 19:04:08 +00008524 * *
8525 ************************************************************************/
8526
Daniel Veillarda819dac1999-11-24 18:04:22 +00008527/**
8528 * xmlCleanupParser:
8529 *
8530 * Cleanup function for the XML parser. It tries to reclaim all
8531 * parsing related global memory allocated for the parser processing.
8532 * It doesn't deallocate any document related memory. Calling this
8533 * function should not prevent reusing the parser.
8534 */
8535
8536void
8537xmlCleanupParser(void) {
8538 xmlCleanupCharEncodingHandlers();
Daniel Veillardf5c2c871999-12-01 09:51:45 +00008539 xmlCleanupPredefinedEntities();
Daniel Veillarda819dac1999-11-24 18:04:22 +00008540}
Daniel Veillardb05deb71999-08-10 19:04:08 +00008541
Daniel Veillard11e00581998-10-24 18:27:49 +00008542/**
8543 * xmlParserFindNodeInfo:
8544 * @ctxt: an XML parser context
8545 * @node: an XML node within the tree
8546 *
8547 * Find the parser node info struct for a given node
8548 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00008549 * Returns an xmlParserNodeInfo block pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00008550 */
8551const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
8552 const xmlNode* node)
8553{
8554 unsigned long pos;
8555
8556 /* Find position where node should be at */
8557 pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
8558 if ( ctx->node_seq.buffer[pos].node == node )
8559 return &ctx->node_seq.buffer[pos];
8560 else
8561 return NULL;
8562}
8563
8564
Daniel Veillard11e00581998-10-24 18:27:49 +00008565/**
8566 * xmlInitNodeInfoSeq :
8567 * @seq: a node info sequence pointer
8568 *
8569 * -- Initialize (set to initial state) node info sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00008570 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00008571void
8572xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00008573{
8574 seq->length = 0;
8575 seq->maximum = 0;
8576 seq->buffer = NULL;
8577}
8578
Daniel Veillard11e00581998-10-24 18:27:49 +00008579/**
8580 * xmlClearNodeInfoSeq :
8581 * @seq: a node info sequence pointer
8582 *
8583 * -- Clear (release memory and reinitialize) node
Daniel Veillard260a68f1998-08-13 03:39:55 +00008584 * info sequence
8585 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00008586void
8587xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00008588{
8589 if ( seq->buffer != NULL )
Daniel Veillard6454aec1999-09-02 22:04:43 +00008590 xmlFree(seq->buffer);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008591 xmlInitNodeInfoSeq(seq);
8592}
8593
8594
Daniel Veillard11e00581998-10-24 18:27:49 +00008595/**
8596 * xmlParserFindNodeInfoIndex:
8597 * @seq: a node info sequence pointer
8598 * @node: an XML node pointer
8599 *
8600 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00008601 * xmlParserFindNodeInfoIndex : Find the index that the info record for
8602 * the given node is or should be at in a sorted sequence
Daniel Veillard1164e751999-02-16 16:29:17 +00008603 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00008604 * Returns a long indicating the position of the record
Daniel Veillard260a68f1998-08-13 03:39:55 +00008605 */
8606unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
8607 const xmlNode* node)
8608{
8609 unsigned long upper, lower, middle;
8610 int found = 0;
8611
8612 /* Do a binary search for the key */
8613 lower = 1;
8614 upper = seq->length;
8615 middle = 0;
8616 while ( lower <= upper && !found) {
8617 middle = lower + (upper - lower) / 2;
8618 if ( node == seq->buffer[middle - 1].node )
8619 found = 1;
8620 else if ( node < seq->buffer[middle - 1].node )
8621 upper = middle - 1;
8622 else
8623 lower = middle + 1;
8624 }
8625
8626 /* Return position */
8627 if ( middle == 0 || seq->buffer[middle - 1].node < node )
8628 return middle;
8629 else
8630 return middle - 1;
8631}
8632
8633
Daniel Veillard11e00581998-10-24 18:27:49 +00008634/**
8635 * xmlParserAddNodeInfo:
8636 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00008637 * @info: a node info sequence pointer
Daniel Veillard11e00581998-10-24 18:27:49 +00008638 *
8639 * Insert node info record into the sorted sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00008640 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00008641void
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008642xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
Daniel Veillard1e346af1999-02-22 10:33:01 +00008643 const xmlParserNodeInfo* info)
Daniel Veillard260a68f1998-08-13 03:39:55 +00008644{
8645 unsigned long pos;
8646 static unsigned int block_size = 5;
8647
8648 /* Find pos and check to see if node is already in the sequence */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008649 pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
8650 if ( pos < ctxt->node_seq.length
8651 && ctxt->node_seq.buffer[pos].node == info->node ) {
8652 ctxt->node_seq.buffer[pos] = *info;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008653 }
8654
8655 /* Otherwise, we need to add new node to buffer */
8656 else {
8657 /* Expand buffer by 5 if needed */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008658 if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00008659 xmlParserNodeInfo* tmp_buffer;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008660 unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
8661 *(ctxt->node_seq.maximum + block_size));
Daniel Veillard260a68f1998-08-13 03:39:55 +00008662
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008663 if ( ctxt->node_seq.buffer == NULL )
Daniel Veillard6454aec1999-09-02 22:04:43 +00008664 tmp_buffer = (xmlParserNodeInfo*) xmlMalloc(byte_size);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008665 else
Daniel Veillard6454aec1999-09-02 22:04:43 +00008666 tmp_buffer = (xmlParserNodeInfo*) xmlRealloc(ctxt->node_seq.buffer, byte_size);
Daniel Veillard260a68f1998-08-13 03:39:55 +00008667
8668 if ( tmp_buffer == NULL ) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008669 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00008670 ctxt->sax->error(ctxt->userData, "Out of memory\n");
Daniel Veillarddd6b3671999-09-23 22:19:22 +00008671 ctxt->errNo = XML_ERR_NO_MEMORY;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008672 return;
8673 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008674 ctxt->node_seq.buffer = tmp_buffer;
8675 ctxt->node_seq.maximum += block_size;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008676 }
8677
8678 /* If position is not at end, move elements out of the way */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008679 if ( pos != ctxt->node_seq.length ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00008680 unsigned long i;
8681
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008682 for ( i = ctxt->node_seq.length; i > pos; i-- )
8683 ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
Daniel Veillard260a68f1998-08-13 03:39:55 +00008684 }
8685
8686 /* Copy element and increase length */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00008687 ctxt->node_seq.buffer[pos] = *info;
8688 ctxt->node_seq.length++;
Daniel Veillard260a68f1998-08-13 03:39:55 +00008689 }
8690}
Daniel Veillard011b63c1999-06-02 17:44:04 +00008691
8692
Daniel Veillardb05deb71999-08-10 19:04:08 +00008693/**
8694 * xmlSubstituteEntitiesDefault :
8695 * @val: int 0 or 1
8696 *
8697 * Set and return the previous value for default entity support.
8698 * Initially the parser always keep entity references instead of substituting
8699 * entity values in the output. This function has to be used to change the
8700 * default parser behaviour
8701 * SAX::subtituteEntities() has to be used for changing that on a file by
8702 * file basis.
8703 *
8704 * Returns the last value for 0 for no substitution, 1 for substitution.
8705 */
8706
8707int
8708xmlSubstituteEntitiesDefault(int val) {
8709 int old = xmlSubstituteEntitiesDefaultValue;
8710
8711 xmlSubstituteEntitiesDefaultValue = val;
8712 return(old);
8713}
8714