blob: d934f824033c3fe26a00198cf77058d7dcca5a18 [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * parser.c : an XML 1.0 non-verifying parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00006 * Daniel.Veillard@w3.org
Daniel Veillard260a68f1998-08-13 03:39:55 +00007 */
8
9#ifdef WIN32
10#define HAVE_FCNTL_H
11#include <io.h>
12#else
13#include <config.h>
14#endif
15#include <stdio.h>
16#include <ctype.h>
17#include <string.h> /* for memset() only */
Seth Alvese7f12e61998-10-01 20:51:15 +000018#include <stdlib.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000019#include <sys/stat.h>
20#ifdef HAVE_FCNTL_H
21#include <fcntl.h>
22#endif
23#ifdef HAVE_UNISTD_H
24#include <unistd.h>
25#endif
26#ifdef HAVE_ZLIB_H
27#include <zlib.h>
28#endif
29
30#include "tree.h"
31#include "parser.h"
32#include "entities.h"
Daniel Veillard27d88741999-05-29 11:51:49 +000033#include "encoding.h"
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000034#include "valid.h"
Daniel Veillard1e346af1999-02-22 10:33:01 +000035#include "parserInternals.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000036
37/************************************************************************
38 * *
39 * Parser stacks related functions and macros *
40 * *
41 ************************************************************************/
42/*
43 * Generic function for accessing stacks in the Parser Context
44 */
45
46#define PUSH_AND_POP(type, name) \
Daniel Veillard517752b1999-04-05 12:20:10 +000047extern int name##Push(xmlParserCtxtPtr ctxt, type value) { \
Daniel Veillard260a68f1998-08-13 03:39:55 +000048 if (ctxt->name##Nr >= ctxt->name##Max) { \
49 ctxt->name##Max *= 2; \
50 ctxt->name##Tab = (void *) realloc(ctxt->name##Tab, \
51 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
52 if (ctxt->name##Tab == NULL) { \
53 fprintf(stderr, "realloc failed !\n"); \
54 exit(1); \
55 } \
56 } \
57 ctxt->name##Tab[ctxt->name##Nr] = value; \
58 ctxt->name = value; \
59 return(ctxt->name##Nr++); \
60} \
Daniel Veillard517752b1999-04-05 12:20:10 +000061extern type name##Pop(xmlParserCtxtPtr ctxt) { \
Daniel Veillardd692aa41999-02-28 21:54:31 +000062 type ret; \
Daniel Veillard260a68f1998-08-13 03:39:55 +000063 if (ctxt->name##Nr <= 0) return(0); \
64 ctxt->name##Nr--; \
Daniel Veillardccb09631998-10-27 06:21:04 +000065 if (ctxt->name##Nr > 0) \
66 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
67 else \
68 ctxt->name = NULL; \
Daniel Veillardd692aa41999-02-28 21:54:31 +000069 ret = ctxt->name##Tab[ctxt->name##Nr]; \
70 ctxt->name##Tab[ctxt->name##Nr] = 0; \
71 return(ret); \
Daniel Veillard260a68f1998-08-13 03:39:55 +000072} \
73
74PUSH_AND_POP(xmlParserInputPtr, input)
75PUSH_AND_POP(xmlNodePtr, node)
76
Daniel Veillard0ba4d531998-11-01 19:34:31 +000077/*
78 * Macros for accessing the content. Those should be used only by the parser,
79 * and not exported.
80 *
81 * Dirty macros, i.e. one need to make assumption on the context to use them
82 *
83 * CUR_PTR return the current pointer to the CHAR to be parsed.
84 * CUR returns the current CHAR value, i.e. a 8 bit value if compiled
85 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
86 * in UNICODE mode. This should be used internally by the parser
87 * only to compare to ASCII values otherwise it would break when
88 * running with UTF-8 encoding.
89 * NXT(n) returns the n'th next CHAR. Same as CUR is should be used only
90 * to compare on ASCII based substring.
91 * SKIP(n) Skip n CHAR, and must also be used only to skip ASCII defined
92 * strings within the parser.
93 *
94 * Clean macros, not dependent of an ASCII context.
95 *
96 * CURRENT Returns the current char value, with the full decoding of
97 * UTF-8 if we are using this mode. It returns an int.
98 * NEXT Skip to the next character, this does the proper decoding
99 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
100 * It returns the pointer to the current CHAR.
101 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000102
103#define CUR (*ctxt->input->cur)
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000104#define SKIP(val) ctxt->input->cur += (val)
105#define NXT(val) ctxt->input->cur[(val)]
106#define CUR_PTR ctxt->input->cur
107
108#define SKIP_BLANKS \
109 while (IS_BLANK(*(ctxt->input->cur))) NEXT
110
111#ifndef USE_UTF_8
112#define CURRENT (*ctxt->input->cur)
Daniel Veillard260a68f1998-08-13 03:39:55 +0000113#define NEXT ((*ctxt->input->cur) ? \
114 (((*(ctxt->input->cur) == '\n') ? \
115 (ctxt->input->line++, ctxt->input->col = 1) : \
116 (ctxt->input->col++)), ctxt->input->cur++) : \
117 (xmlPopInput(ctxt), ctxt->input->cur))
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000118#else
119#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000120
121
Daniel Veillard11e00581998-10-24 18:27:49 +0000122/**
123 * xmlPopInput:
124 * @ctxt: an XML parser context
125 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000126 * xmlPopInput: the current input pointed by ctxt->input came to an end
127 * pop it and return the next char.
128 *
129 * TODO A deallocation of the popped Input structure is needed
Daniel Veillard1e346af1999-02-22 10:33:01 +0000130 *
131 * Returns the current CHAR in the parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +0000132 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000133CHAR
134xmlPopInput(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000135 if (ctxt->inputNr == 1) return(0); /* End of main Input */
Daniel Veillardbc50b591999-03-01 12:28:53 +0000136 xmlFreeInputStream(inputPop(ctxt));
Daniel Veillard260a68f1998-08-13 03:39:55 +0000137 return(CUR);
138}
139
Daniel Veillard11e00581998-10-24 18:27:49 +0000140/**
141 * xmlPushInput:
142 * @ctxt: an XML parser context
143 * @input: an XML parser input fragment (entity, XML fragment ...).
144 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000145 * xmlPushInput: switch to a new input stream which is stacked on top
146 * of the previous one(s).
147 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000148void
149xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000150 if (input == NULL) return;
151 inputPush(ctxt, input);
152}
153
Daniel Veillard11e00581998-10-24 18:27:49 +0000154/**
Daniel Veillardd692aa41999-02-28 21:54:31 +0000155 * xmlFreeInputStream:
156 * @input: an xmlParserInputPtr
157 *
158 * Free up an input stream.
159 */
160void
161xmlFreeInputStream(xmlParserInputPtr input) {
162 if (input == NULL) return;
163
Daniel Veillardbc50b591999-03-01 12:28:53 +0000164 if (input->filename != NULL) free((char *) input->filename);
Daniel Veillardd692aa41999-02-28 21:54:31 +0000165 if ((input->free != NULL) && (input->base != NULL))
166 input->free((char *) input->base);
167 memset(input, -1, sizeof(xmlParserInput));
168 free(input);
169}
170
171/**
Daniel Veillard11e00581998-10-24 18:27:49 +0000172 * xmlNewEntityInputStream:
173 * @ctxt: an XML parser context
174 * @entity: an Entity pointer
175 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000176 * Create a new input stream based on a memory buffer.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000177 * Returns the new input stream
Daniel Veillard260a68f1998-08-13 03:39:55 +0000178 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000179xmlParserInputPtr
180xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000181 xmlParserInputPtr input;
182
183 if (entity == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000184 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000185 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000186 "internal: xmlNewEntityInputStream entity = NULL\n");
Daniel Veillardccb09631998-10-27 06:21:04 +0000187 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000188 }
189 if (entity->content == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000190 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000191 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000192 "internal: xmlNewEntityInputStream entity->input = NULL\n");
Daniel Veillardccb09631998-10-27 06:21:04 +0000193 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000194 }
195 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
196 if (input == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000197 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000198 ctxt->sax->error(ctxt->userData, "malloc: couldn't allocate a new input stream\n");
Daniel Veillardccb09631998-10-27 06:21:04 +0000199 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000200 }
201 input->filename = entity->SystemID; /* TODO !!! char <- CHAR */
202 input->base = entity->content;
203 input->cur = entity->content;
204 input->line = 1;
205 input->col = 1;
Daniel Veillardd692aa41999-02-28 21:54:31 +0000206 input->free = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +0000207 return(input);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000208}
209
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000210/**
211 * xmlNewStringInputStream:
212 * @ctxt: an XML parser context
213 * @entity: an Entity pointer
214 *
215 * Create a new input stream based on a memory buffer.
Daniel Veillard1e346af1999-02-22 10:33:01 +0000216 * Returns the new input stream
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000217 */
218xmlParserInputPtr
219xmlNewStringInputStream(xmlParserCtxtPtr ctxt, CHAR *string) {
220 xmlParserInputPtr input;
221
222 if (string == NULL) {
223 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000224 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000225 "internal: xmlNewStringInputStream string = NULL\n");
226 return(NULL);
227 }
228 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
229 if (input == NULL) {
230 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000231 ctxt->sax->error(ctxt->userData, "malloc: couldn't allocate a new input stream\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000232 return(NULL);
233 }
234 input->filename = NULL;
235 input->base = string;
236 input->cur = string;
237 input->line = 1;
238 input->col = 1;
Daniel Veillardd692aa41999-02-28 21:54:31 +0000239 input->free = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000240 return(input);
241}
242
Daniel Veillard260a68f1998-08-13 03:39:55 +0000243
244/************************************************************************
245 * *
Daniel Veillard27d88741999-05-29 11:51:49 +0000246 * Commodity functions to handle encodings *
247 * *
248 ************************************************************************/
249
250/**
251 * xmlSwitchEncoding:
252 * @ctxt: the parser context
253 * @len: the len of @cur
254 *
255 * change the input functions when discovering the character encoding
256 * of a given entity.
257 *
258 */
259void
260xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
261{
262 switch (enc) {
263 case XML_CHAR_ENCODING_ERROR:
264 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
265 ctxt->sax->error(ctxt->userData, "encoding unknown\n");
266 ctxt->wellFormed = 0;
267 break;
268 case XML_CHAR_ENCODING_NONE:
269 /* let's assume it's UTF-8 without the XML decl */
270 return;
271 case XML_CHAR_ENCODING_UTF8:
272 /* default encoding, no conversion should be needed */
273 return;
274 case XML_CHAR_ENCODING_UTF16LE:
275 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
276 ctxt->sax->error(ctxt->userData,
277 "char encoding UTF16 little endian not supported\n");
278 break;
279 case XML_CHAR_ENCODING_UTF16BE:
280 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
281 ctxt->sax->error(ctxt->userData,
282 "char encoding UTF16 big endian not supported\n");
283 break;
284 case XML_CHAR_ENCODING_UCS4LE:
285 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
286 ctxt->sax->error(ctxt->userData,
287 "char encoding USC4 little endian not supported\n");
288 break;
289 case XML_CHAR_ENCODING_UCS4BE:
290 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
291 ctxt->sax->error(ctxt->userData,
292 "char encoding USC4 big endian not supported\n");
293 break;
294 case XML_CHAR_ENCODING_EBCDIC:
295 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
296 ctxt->sax->error(ctxt->userData,
297 "char encoding EBCDIC not supported\n");
298 break;
299 case XML_CHAR_ENCODING_UCS4_2143:
300 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
301 ctxt->sax->error(ctxt->userData,
302 "char encoding UCS4 2143 not supported\n");
303 break;
304 case XML_CHAR_ENCODING_UCS4_3412:
305 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
306 ctxt->sax->error(ctxt->userData,
307 "char encoding UCS4 3412 not supported\n");
308 break;
309 case XML_CHAR_ENCODING_UCS2:
310 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
311 ctxt->sax->error(ctxt->userData,
312 "char encoding UCS2 not supported\n");
313 break;
314 case XML_CHAR_ENCODING_8859_1:
315 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
316 ctxt->sax->error(ctxt->userData,
317 "char encoding ISO_8859_1 ISO Latin 1 not supported\n");
318 break;
319 case XML_CHAR_ENCODING_8859_2:
320 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
321 ctxt->sax->error(ctxt->userData,
322 "char encoding ISO_8859_2 ISO Latin 2 not supported\n");
323 break;
324 case XML_CHAR_ENCODING_8859_3:
325 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
326 ctxt->sax->error(ctxt->userData,
327 "char encoding ISO_8859_3 not supported\n");
328 break;
329 case XML_CHAR_ENCODING_8859_4:
330 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
331 ctxt->sax->error(ctxt->userData,
332 "char encoding ISO_8859_4 not supported\n");
333 break;
334 case XML_CHAR_ENCODING_8859_5:
335 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
336 ctxt->sax->error(ctxt->userData,
337 "char encoding ISO_8859_5 not supported\n");
338 break;
339 case XML_CHAR_ENCODING_8859_6:
340 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
341 ctxt->sax->error(ctxt->userData,
342 "char encoding ISO_8859_6 not supported\n");
343 break;
344 case XML_CHAR_ENCODING_8859_7:
345 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
346 ctxt->sax->error(ctxt->userData,
347 "char encoding ISO_8859_7 not supported\n");
348 break;
349 case XML_CHAR_ENCODING_8859_8:
350 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
351 ctxt->sax->error(ctxt->userData,
352 "char encoding ISO_8859_8 not supported\n");
353 break;
354 case XML_CHAR_ENCODING_8859_9:
355 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
356 ctxt->sax->error(ctxt->userData,
357 "char encoding ISO_8859_9 not supported\n");
358 break;
359 case XML_CHAR_ENCODING_2022_JP:
360 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
361 ctxt->sax->error(ctxt->userData,
362 "char encoding ISO-2022-JPnot supported\n");
363 break;
364 case XML_CHAR_ENCODING_SHIFT_JIS:
365 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
366 ctxt->sax->error(ctxt->userData,
367 "char encoding Shift_JISnot supported\n");
368 break;
369 case XML_CHAR_ENCODING_EUC_JP:
370 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
371 ctxt->sax->error(ctxt->userData,
372 "char encoding EUC-JPnot supported\n");
373 break;
374 }
375}
376
377/************************************************************************
378 * *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000379 * Commodity functions to handle CHARs *
380 * *
381 ************************************************************************/
382
Daniel Veillard11e00581998-10-24 18:27:49 +0000383/**
384 * xmlStrndup:
385 * @cur: the input CHAR *
386 * @len: the len of @cur
387 *
388 * a strndup for array of CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000389 *
390 * Returns a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000391 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000392CHAR *
393xmlStrndup(const CHAR *cur, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000394 CHAR *ret = malloc((len + 1) * sizeof(CHAR));
395
396 if (ret == NULL) {
397 fprintf(stderr, "malloc of %d byte failed\n",
398 (len + 1) * sizeof(CHAR));
399 return(NULL);
400 }
401 memcpy(ret, cur, len * sizeof(CHAR));
402 ret[len] = 0;
403 return(ret);
404}
405
Daniel Veillard11e00581998-10-24 18:27:49 +0000406/**
407 * xmlStrdup:
408 * @cur: the input CHAR *
409 *
410 * a strdup for array of CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000411 *
412 * Returns a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000413 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000414CHAR *
415xmlStrdup(const CHAR *cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000416 const CHAR *p = cur;
417
418 while (IS_CHAR(*p)) p++;
419 return(xmlStrndup(cur, p - cur));
420}
421
Daniel Veillard11e00581998-10-24 18:27:49 +0000422/**
423 * xmlCharStrndup:
424 * @cur: the input char *
425 * @len: the len of @cur
426 *
427 * a strndup for char's to CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000428 *
429 * Returns a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000430 */
431
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000432CHAR *
433xmlCharStrndup(const char *cur, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000434 int i;
435 CHAR *ret = malloc((len + 1) * sizeof(CHAR));
436
437 if (ret == NULL) {
438 fprintf(stderr, "malloc of %d byte failed\n",
439 (len + 1) * sizeof(CHAR));
440 return(NULL);
441 }
442 for (i = 0;i < len;i++)
443 ret[i] = (CHAR) cur[i];
444 ret[len] = 0;
445 return(ret);
446}
447
Daniel Veillard11e00581998-10-24 18:27:49 +0000448/**
449 * xmlCharStrdup:
450 * @cur: the input char *
451 * @len: the len of @cur
452 *
453 * a strdup for char's to CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000454 *
455 * Returns a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000456 */
457
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000458CHAR *
459xmlCharStrdup(const char *cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000460 const char *p = cur;
461
462 while (*p != '\0') p++;
463 return(xmlCharStrndup(cur, p - cur));
464}
465
Daniel Veillard11e00581998-10-24 18:27:49 +0000466/**
467 * xmlStrcmp:
468 * @str1: the first CHAR *
469 * @str2: the second CHAR *
470 *
471 * a strcmp for CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000472 *
473 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +0000474 */
475
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000476int
477xmlStrcmp(const CHAR *str1, const CHAR *str2) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000478 register int tmp;
479
480 do {
481 tmp = *str1++ - *str2++;
482 if (tmp != 0) return(tmp);
483 } while ((*str1 != 0) && (*str2 != 0));
484 return (*str1 - *str2);
485}
486
Daniel Veillard11e00581998-10-24 18:27:49 +0000487/**
488 * xmlStrncmp:
489 * @str1: the first CHAR *
490 * @str2: the second CHAR *
491 * @len: the max comparison length
492 *
493 * a strncmp for CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000494 *
495 * Returns the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +0000496 */
497
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000498int
499xmlStrncmp(const CHAR *str1, const CHAR *str2, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000500 register int tmp;
501
502 if (len <= 0) return(0);
503 do {
504 tmp = *str1++ - *str2++;
505 if (tmp != 0) return(tmp);
506 len--;
507 if (len <= 0) return(0);
508 } while ((*str1 != 0) && (*str2 != 0));
509 return (*str1 - *str2);
510}
511
Daniel Veillard11e00581998-10-24 18:27:49 +0000512/**
513 * xmlStrchr:
514 * @str: the CHAR * array
515 * @val: the CHAR to search
516 *
517 * a strchr for CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000518 *
519 * Returns the CHAR * for the first occurence or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000520 */
521
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000522CHAR *
523xmlStrchr(const CHAR *str, CHAR val) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000524 while (*str != 0) {
525 if (*str == val) return((CHAR *) str);
526 str++;
527 }
528 return(NULL);
529}
530
Daniel Veillard11e00581998-10-24 18:27:49 +0000531/**
532 * xmlStrlen:
533 * @str: the CHAR * array
534 *
535 * lenght of a CHAR's string
Daniel Veillard1e346af1999-02-22 10:33:01 +0000536 *
537 * Returns the number of CHAR contained in the ARRAY.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000538 */
539
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000540int
541xmlStrlen(const CHAR *str) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000542 int len = 0;
543
544 if (str == NULL) return(0);
545 while (*str != 0) {
546 str++;
547 len++;
548 }
549 return(len);
550}
551
Daniel Veillard11e00581998-10-24 18:27:49 +0000552/**
553 * xmlStrncat:
Daniel Veillard1e346af1999-02-22 10:33:01 +0000554 * @cur: the original CHAR * array
Daniel Veillard11e00581998-10-24 18:27:49 +0000555 * @add: the CHAR * array added
556 * @len: the length of @add
557 *
558 * a strncat for array of CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000559 *
560 * Returns a new CHAR * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000561 */
562
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000563CHAR *
564xmlStrncat(CHAR *cur, const CHAR *add, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000565 int size;
566 CHAR *ret;
567
568 if ((add == NULL) || (len == 0))
569 return(cur);
570 if (cur == NULL)
571 return(xmlStrndup(add, len));
572
573 size = xmlStrlen(cur);
574 ret = realloc(cur, (size + len + 1) * sizeof(CHAR));
575 if (ret == NULL) {
576 fprintf(stderr, "xmlStrncat: realloc of %d byte failed\n",
577 (size + len + 1) * sizeof(CHAR));
578 return(cur);
579 }
580 memcpy(&ret[size], add, len * sizeof(CHAR));
581 ret[size + len] = 0;
582 return(ret);
583}
584
Daniel Veillard11e00581998-10-24 18:27:49 +0000585/**
586 * xmlStrcat:
Daniel Veillard1e346af1999-02-22 10:33:01 +0000587 * @cur: the original CHAR * array
Daniel Veillard11e00581998-10-24 18:27:49 +0000588 * @add: the CHAR * array added
589 *
590 * a strcat for array of CHAR's
Daniel Veillard1e346af1999-02-22 10:33:01 +0000591 *
592 * Returns a new CHAR * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000593 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000594CHAR *
595xmlStrcat(CHAR *cur, const CHAR *add) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000596 const CHAR *p = add;
597
598 if (add == NULL) return(cur);
599 if (cur == NULL)
600 return(xmlStrdup(add));
601
602 while (IS_CHAR(*p)) p++;
603 return(xmlStrncat(cur, add, p - add));
604}
605
606/************************************************************************
607 * *
608 * Commodity functions, cleanup needed ? *
609 * *
610 ************************************************************************/
611
Daniel Veillard11e00581998-10-24 18:27:49 +0000612/**
613 * areBlanks:
614 * @ctxt: an XML parser context
615 * @str: a CHAR *
616 * @len: the size of @str
617 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000618 * Is this a sequence of blank chars that one can ignore ?
Daniel Veillard11e00581998-10-24 18:27:49 +0000619 *
620 * TODO: to be corrected accodingly to DTD information if available
Daniel Veillard1e346af1999-02-22 10:33:01 +0000621 *
622 * Returns 1 if ignorable 0 otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000623 */
624
625static int areBlanks(xmlParserCtxtPtr ctxt, const CHAR *str, int len) {
626 int i;
627 xmlNodePtr lastChild;
628
629 for (i = 0;i < len;i++)
630 if (!(IS_BLANK(str[i]))) return(0);
631
632 if (CUR != '<') return(0);
Daniel Veillard517752b1999-04-05 12:20:10 +0000633 if (ctxt->node == NULL) return(0);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000634 lastChild = xmlGetLastChild(ctxt->node);
635 if (lastChild == NULL) {
636 if (ctxt->node->content != NULL) return(0);
637 } else if (xmlNodeIsText(lastChild))
638 return(0);
639 return(1);
640}
641
Daniel Veillard11e00581998-10-24 18:27:49 +0000642/**
643 * xmlHandleEntity:
644 * @ctxt: an XML parser context
645 * @entity: an XML entity pointer.
646 *
647 * Default handling of defined entities, when should we define a new input
Daniel Veillard260a68f1998-08-13 03:39:55 +0000648 * stream ? When do we just handle that as a set of chars ?
Daniel Veillard11e00581998-10-24 18:27:49 +0000649 * TODO: we should call the SAX handler here and have it resolve the issue
Daniel Veillard260a68f1998-08-13 03:39:55 +0000650 */
651
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000652void
653xmlHandleEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000654 int len;
Daniel Veillardccb09631998-10-27 06:21:04 +0000655 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000656
657 if (entity->content == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000658 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000659 ctxt->sax->error(ctxt->userData, "xmlHandleEntity %s: content == NULL\n",
Daniel Veillard260a68f1998-08-13 03:39:55 +0000660 entity->name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000661 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000662 return;
663 }
664 len = xmlStrlen(entity->content);
665 if (len <= 2) goto handle_as_char;
666
667 /*
668 * Redefine its content as an input stream.
669 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000670 input = xmlNewEntityInputStream(ctxt, entity);
671 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000672 return;
673
674handle_as_char:
675 /*
676 * Just handle the content as a set of chars.
677 */
Daniel Veillard517752b1999-04-05 12:20:10 +0000678 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000679 ctxt->sax->characters(ctxt->userData, entity->content, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000680
681}
682
683/*
684 * Forward definition for recusive behaviour.
685 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000686CHAR *xmlParsePEReference(xmlParserCtxtPtr ctxt);
687CHAR *xmlParseReference(xmlParserCtxtPtr ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000688
689/************************************************************************
690 * *
691 * Extra stuff for namespace support *
692 * Relates to http://www.w3.org/TR/WD-xml-names *
693 * *
694 ************************************************************************/
695
Daniel Veillard11e00581998-10-24 18:27:49 +0000696/**
697 * xmlNamespaceParseNCName:
698 * @ctxt: an XML parser context
699 *
700 * parse an XML namespace name.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000701 *
702 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
703 *
704 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
705 * CombiningChar | Extender
Daniel Veillard1e346af1999-02-22 10:33:01 +0000706 *
707 * Returns the namespace name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000708 */
709
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000710CHAR *
711xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000712 const CHAR *q;
713 CHAR *ret = NULL;
714
715 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
716 q = NEXT;
717
718 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
719 (CUR == '.') || (CUR == '-') ||
720 (CUR == '_') ||
721 (IS_COMBINING(CUR)) ||
722 (IS_EXTENDER(CUR)))
723 NEXT;
724
725 ret = xmlStrndup(q, CUR_PTR - q);
726
727 return(ret);
728}
729
Daniel Veillard11e00581998-10-24 18:27:49 +0000730/**
731 * xmlNamespaceParseQName:
732 * @ctxt: an XML parser context
733 * @prefix: a CHAR **
734 *
735 * parse an XML qualified name
Daniel Veillard260a68f1998-08-13 03:39:55 +0000736 *
737 * [NS 5] QName ::= (Prefix ':')? LocalPart
738 *
739 * [NS 6] Prefix ::= NCName
740 *
741 * [NS 7] LocalPart ::= NCName
Daniel Veillard1e346af1999-02-22 10:33:01 +0000742 *
743 * Returns the function returns the local part, and prefix is updated
Daniel Veillard11e00581998-10-24 18:27:49 +0000744 * to get the Prefix if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000745 */
746
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000747CHAR *
748xmlNamespaceParseQName(xmlParserCtxtPtr ctxt, CHAR **prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000749 CHAR *ret = NULL;
750
751 *prefix = NULL;
752 ret = xmlNamespaceParseNCName(ctxt);
753 if (CUR == ':') {
754 *prefix = ret;
755 NEXT;
756 ret = xmlNamespaceParseNCName(ctxt);
757 }
758
759 return(ret);
760}
761
Daniel Veillard11e00581998-10-24 18:27:49 +0000762/**
Daniel Veillard517752b1999-04-05 12:20:10 +0000763 * xmlSplitQName:
764 * @name: an XML parser context
765 * @prefix: a CHAR **
766 *
767 * parse an XML qualified name string
768 *
769 * [NS 5] QName ::= (Prefix ':')? LocalPart
770 *
771 * [NS 6] Prefix ::= NCName
772 *
773 * [NS 7] LocalPart ::= NCName
774 *
775 * Returns the function returns the local part, and prefix is updated
776 * to get the Prefix if any.
777 */
778
779CHAR *
780xmlSplitQName(const CHAR *name, CHAR **prefix) {
781 CHAR *ret = NULL;
782 const CHAR *q;
783 const CHAR *cur = name;
784
785 *prefix = NULL;
786 if (!IS_LETTER(*cur) && (*cur != '_')) return(NULL);
787 q = cur++;
788
789 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
790 (*cur == '.') || (*cur == '-') ||
791 (*cur == '_') ||
792 (IS_COMBINING(*cur)) ||
793 (IS_EXTENDER(*cur)))
794 cur++;
795
796 ret = xmlStrndup(q, cur - q);
797
798 if (*cur == ':') {
799 cur++;
800 if (!IS_LETTER(*cur) && (*cur != '_')) return(ret);
801 *prefix = ret;
802
803 q = cur++;
804
805 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
806 (*cur == '.') || (*cur == '-') ||
807 (*cur == '_') ||
808 (IS_COMBINING(*cur)) ||
809 (IS_EXTENDER(*cur)))
810 cur++;
811
812 ret = xmlStrndup(q, cur - q);
813 }
814
815 return(ret);
816}
817/**
Daniel Veillard11e00581998-10-24 18:27:49 +0000818 * xmlNamespaceParseNSDef:
819 * @ctxt: an XML parser context
820 *
821 * parse a namespace prefix declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +0000822 *
823 * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral
824 *
825 * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)?
Daniel Veillard1e346af1999-02-22 10:33:01 +0000826 *
827 * Returns the namespace name
Daniel Veillard260a68f1998-08-13 03:39:55 +0000828 */
829
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000830CHAR *
831xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000832 CHAR *name = NULL;
833
834 if ((CUR == 'x') && (NXT(1) == 'm') &&
835 (NXT(2) == 'l') && (NXT(3) == 'n') &&
836 (NXT(4) == 's')) {
837 SKIP(5);
838 if (CUR == ':') {
839 NEXT;
840 name = xmlNamespaceParseNCName(ctxt);
841 }
842 }
843 return(name);
844}
845
Daniel Veillard11e00581998-10-24 18:27:49 +0000846/**
847 * xmlParseQuotedString:
848 * @ctxt: an XML parser context
849 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000850 * [OLD] Parse and return a string between quotes or doublequotes
Daniel Veillard1e346af1999-02-22 10:33:01 +0000851 *
852 * Returns the string parser or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000853 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000854CHAR *
855xmlParseQuotedString(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000856 CHAR *ret = NULL;
857 const CHAR *q;
858
859 if (CUR == '"') {
860 NEXT;
861 q = CUR_PTR;
862 while (IS_CHAR(CUR) && (CUR != '"')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000863 if (CUR != '"') {
864 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000865 ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000866 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000867 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000868 ret = xmlStrndup(q, CUR_PTR - q);
869 NEXT;
870 }
871 } else if (CUR == '\''){
872 NEXT;
873 q = CUR_PTR;
874 while (IS_CHAR(CUR) && (CUR != '\'')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000875 if (CUR != '\'') {
876 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000877 ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000878 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000879 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000880 ret = xmlStrndup(q, CUR_PTR - q);
881 NEXT;
882 }
883 }
884 return(ret);
885}
886
Daniel Veillard11e00581998-10-24 18:27:49 +0000887/**
888 * xmlParseNamespace:
889 * @ctxt: an XML parser context
890 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000891 * [OLD] xmlParseNamespace: parse specific PI '<?namespace ...' constructs.
892 *
893 * This is what the older xml-name Working Draft specified, a bunch of
894 * other stuff may still rely on it, so support is still here as
895 * if ot was declared on the root of the Tree:-(
896 */
897
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000898void
899xmlParseNamespace(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000900 CHAR *href = NULL;
901 CHAR *prefix = NULL;
902 int garbage = 0;
903
904 /*
905 * We just skipped "namespace" or "xml:namespace"
906 */
907 SKIP_BLANKS;
908
909 while (IS_CHAR(CUR) && (CUR != '>')) {
910 /*
911 * We can have "ns" or "prefix" attributes
912 * Old encoding as 'href' or 'AS' attributes is still supported
913 */
914 if ((CUR == 'n') && (NXT(1) == 's')) {
915 garbage = 0;
916 SKIP(2);
917 SKIP_BLANKS;
918
919 if (CUR != '=') continue;
920 NEXT;
921 SKIP_BLANKS;
922
923 href = xmlParseQuotedString(ctxt);
924 SKIP_BLANKS;
925 } else if ((CUR == 'h') && (NXT(1) == 'r') &&
926 (NXT(2) == 'e') && (NXT(3) == 'f')) {
927 garbage = 0;
928 SKIP(4);
929 SKIP_BLANKS;
930
931 if (CUR != '=') continue;
932 NEXT;
933 SKIP_BLANKS;
934
935 href = xmlParseQuotedString(ctxt);
936 SKIP_BLANKS;
937 } else if ((CUR == 'p') && (NXT(1) == 'r') &&
938 (NXT(2) == 'e') && (NXT(3) == 'f') &&
939 (NXT(4) == 'i') && (NXT(5) == 'x')) {
940 garbage = 0;
941 SKIP(6);
942 SKIP_BLANKS;
943
944 if (CUR != '=') continue;
945 NEXT;
946 SKIP_BLANKS;
947
948 prefix = xmlParseQuotedString(ctxt);
949 SKIP_BLANKS;
950 } else if ((CUR == 'A') && (NXT(1) == 'S')) {
951 garbage = 0;
952 SKIP(2);
953 SKIP_BLANKS;
954
955 if (CUR != '=') continue;
956 NEXT;
957 SKIP_BLANKS;
958
959 prefix = xmlParseQuotedString(ctxt);
960 SKIP_BLANKS;
961 } else if ((CUR == '?') && (NXT(1) == '>')) {
962 garbage = 0;
963 CUR_PTR ++;
964 } else {
965 /*
966 * Found garbage when parsing the namespace
967 */
968 if (!garbage)
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000969 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000970 ctxt->sax->error(ctxt->userData, "xmlParseNamespace found garbage\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000971 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000972 NEXT;
973 }
974 }
975
976 MOVETO_ENDTAG(CUR_PTR);
977 NEXT;
978
979 /*
980 * Register the DTD.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000981 if (href != NULL)
Daniel Veillard517752b1999-04-05 12:20:10 +0000982 if ((ctxt->sax != NULL) && (ctxt->sax->globalNamespace != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +0000983 ctxt->sax->globalNamespace(ctxt->userData, href, prefix);
Daniel Veillard517752b1999-04-05 12:20:10 +0000984 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000985
986 if (prefix != NULL) free(prefix);
987 if (href != NULL) free(href);
988}
989
990/************************************************************************
991 * *
992 * The parser itself *
993 * Relates to http://www.w3.org/TR/REC-xml *
994 * *
995 ************************************************************************/
996
Daniel Veillard11e00581998-10-24 18:27:49 +0000997/**
998 * xmlParseName:
999 * @ctxt: an XML parser context
1000 *
1001 * parse an XML name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001002 *
1003 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
1004 * CombiningChar | Extender
1005 *
1006 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
1007 *
1008 * [6] Names ::= Name (S Name)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00001009 *
1010 * Returns the Name parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001011 */
1012
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001013CHAR *
1014xmlParseName(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001015 const CHAR *q;
1016 CHAR *ret = NULL;
1017
1018 if (!IS_LETTER(CUR) && (CUR != '_') &&
1019 (CUR != ':')) return(NULL);
1020 q = NEXT;
1021
1022 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1023 (CUR == '.') || (CUR == '-') ||
1024 (CUR == '_') || (CUR == ':') ||
1025 (IS_COMBINING(CUR)) ||
1026 (IS_EXTENDER(CUR)))
1027 NEXT;
1028
1029 ret = xmlStrndup(q, CUR_PTR - q);
1030
1031 return(ret);
1032}
1033
Daniel Veillard11e00581998-10-24 18:27:49 +00001034/**
1035 * xmlParseNmtoken:
1036 * @ctxt: an XML parser context
1037 *
1038 * parse an XML Nmtoken.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001039 *
1040 * [7] Nmtoken ::= (NameChar)+
1041 *
1042 * [8] Nmtokens ::= Nmtoken (S Nmtoken)*
Daniel Veillard1e346af1999-02-22 10:33:01 +00001043 *
1044 * Returns the Nmtoken parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001045 */
1046
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001047CHAR *
1048xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001049 const CHAR *q;
1050 CHAR *ret = NULL;
1051
1052 q = NEXT;
1053
1054 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1055 (CUR == '.') || (CUR == '-') ||
1056 (CUR == '_') || (CUR == ':') ||
1057 (IS_COMBINING(CUR)) ||
1058 (IS_EXTENDER(CUR)))
1059 NEXT;
1060
1061 ret = xmlStrndup(q, CUR_PTR - q);
1062
1063 return(ret);
1064}
1065
Daniel Veillard11e00581998-10-24 18:27:49 +00001066/**
1067 * xmlParseEntityValue:
1068 * @ctxt: an XML parser context
1069 *
1070 * parse a value for ENTITY decl.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001071 *
1072 * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
1073 * "'" ([^%&'] | PEReference | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00001074 *
1075 * Returns the EntityValue parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001076 */
1077
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001078CHAR *
1079xmlParseEntityValue(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001080 CHAR *ret = NULL, *cur;
1081 const CHAR *q;
1082
1083 if (CUR == '"') {
1084 NEXT;
1085
1086 q = CUR_PTR;
1087 while ((IS_CHAR(CUR)) && (CUR != '"')) {
1088 if (CUR == '%') {
1089 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001090 cur = xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001091 ret = xmlStrcat(ret, cur);
1092 q = CUR_PTR;
1093 } else if (CUR == '&') {
1094 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001095 cur = xmlParseReference(ctxt);
1096 if (cur != NULL) {
1097 CHAR buf[2];
1098 buf[0] = '&';
1099 buf[1] = 0;
1100 ret = xmlStrncat(ret, buf, 1);
1101 ret = xmlStrcat(ret, cur);
1102 buf[0] = ';';
1103 buf[1] = 0;
1104 ret = xmlStrncat(ret, buf, 1);
1105 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001106 q = CUR_PTR;
1107 } else
1108 NEXT;
1109 }
1110 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001111 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001112 ctxt->sax->error(ctxt->userData, "Unfinished EntityValue\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001113 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001114 } else {
1115 ret = xmlStrncat(ret, q, CUR_PTR - q);
1116 NEXT;
1117 }
1118 } else if (CUR == '\'') {
1119 NEXT;
1120 q = CUR_PTR;
1121 while ((IS_CHAR(CUR)) && (CUR != '\'')) {
1122 if (CUR == '%') {
1123 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001124 cur = xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001125 ret = xmlStrcat(ret, cur);
1126 q = CUR_PTR;
1127 } else if (CUR == '&') {
1128 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001129 cur = xmlParseReference(ctxt);
1130 if (cur != NULL) {
1131 CHAR buf[2];
1132 buf[0] = '&';
1133 buf[1] = 0;
1134 ret = xmlStrncat(ret, buf, 1);
1135 ret = xmlStrcat(ret, cur);
1136 buf[0] = ';';
1137 buf[1] = 0;
1138 ret = xmlStrncat(ret, buf, 1);
1139 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001140 q = CUR_PTR;
1141 } else
1142 NEXT;
1143 }
1144 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001145 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001146 ctxt->sax->error(ctxt->userData, "Unfinished EntityValue\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001147 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001148 } else {
1149 ret = xmlStrncat(ret, q, CUR_PTR - q);
1150 NEXT;
1151 }
1152 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001153 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001154 ctxt->sax->error(ctxt->userData, "xmlParseEntityValue \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001155 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001156 }
1157
1158 return(ret);
1159}
1160
Daniel Veillard11e00581998-10-24 18:27:49 +00001161/**
1162 * xmlParseAttValue:
1163 * @ctxt: an XML parser context
1164 *
1165 * parse a value for an attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00001166 *
1167 * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
1168 * "'" ([^<&'] | Reference)* "'"
Daniel Veillard1e346af1999-02-22 10:33:01 +00001169 *
1170 * Returns the AttValue parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001171 */
1172
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001173CHAR *
1174xmlParseAttValue(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001175 CHAR *ret = NULL, *cur;
1176 const CHAR *q;
1177
1178 if (CUR == '"') {
1179 NEXT;
1180
1181 q = CUR_PTR;
1182 while ((IS_CHAR(CUR)) && (CUR != '"')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001183 if (CUR == '<') {
1184 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001185 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001186 "Unescaped '<' not allowed in attributes values\n");
1187 ctxt->wellFormed = 0;
1188 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001189 if (CUR == '&') {
1190 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001191 cur = xmlParseReference(ctxt);
1192 if (cur != NULL) {
1193 /*
1194 * Special case for '&amp;', we don't want to
1195 * resolve it here since it will break later
1196 * when searching entities in the string.
1197 */
1198 if ((cur[0] == '&') && (cur[1] == 0)) {
1199 CHAR buf[6] = { '&', 'a', 'm', 'p', ';', 0 };
1200 ret = xmlStrncat(ret, buf, 5);
1201 } else
1202 ret = xmlStrcat(ret, cur);
1203 free(cur);
1204 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001205 q = CUR_PTR;
1206 } else
1207 NEXT;
Daniel Veillardccb09631998-10-27 06:21:04 +00001208 /*
1209 * Pop out finished entity references.
1210 */
1211 while ((CUR == 0) && (ctxt->inputNr > 1)) {
1212 if (CUR_PTR != q)
1213 ret = xmlStrncat(ret, q, CUR_PTR - q);
1214 xmlPopInput(ctxt);
1215 q = CUR_PTR;
1216 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001217 }
1218 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001219 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001220 ctxt->sax->error(ctxt->userData, "Unfinished AttValue\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001221 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001222 } else {
1223 ret = xmlStrncat(ret, q, CUR_PTR - q);
1224 NEXT;
1225 }
1226 } else if (CUR == '\'') {
1227 NEXT;
1228 q = CUR_PTR;
1229 while ((IS_CHAR(CUR)) && (CUR != '\'')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001230 if (CUR == '<') {
1231 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001232 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001233 "Unescaped '<' not allowed in attributes values\n");
1234 ctxt->wellFormed = 0;
1235 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001236 if (CUR == '&') {
1237 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001238 cur = xmlParseReference(ctxt);
1239 if (cur != NULL) {
1240 /*
1241 * Special case for '&amp;', we don't want to
1242 * resolve it here since it will break later
1243 * when searching entities in the string.
1244 */
1245 if ((cur[0] == '&') && (cur[1] == 0)) {
1246 CHAR buf[6] = { '&', 'a', 'm', 'p', ';', 0 };
1247 ret = xmlStrncat(ret, buf, 5);
1248 } else
1249 ret = xmlStrcat(ret, cur);
1250 free(cur);
1251 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001252 q = CUR_PTR;
1253 } else
1254 NEXT;
Daniel Veillardccb09631998-10-27 06:21:04 +00001255 /*
1256 * Pop out finished entity references.
1257 */
1258 while ((CUR == 0) && (ctxt->inputNr > 1)) {
1259 if (CUR_PTR != q)
1260 ret = xmlStrncat(ret, q, CUR_PTR - q);
1261 xmlPopInput(ctxt);
1262 q = CUR_PTR;
1263 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001264 }
1265 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001266 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001267 ctxt->sax->error(ctxt->userData, "Unfinished AttValue\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001268 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001269 } else {
1270 ret = xmlStrncat(ret, q, CUR_PTR - q);
1271 NEXT;
1272 }
1273 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001274 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001275 ctxt->sax->error(ctxt->userData, "AttValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001276 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001277 }
1278
1279 return(ret);
1280}
1281
Daniel Veillard11e00581998-10-24 18:27:49 +00001282/**
1283 * xmlParseSystemLiteral:
1284 * @ctxt: an XML parser context
1285 *
1286 * parse an XML Literal
Daniel Veillard260a68f1998-08-13 03:39:55 +00001287 *
1288 * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
Daniel Veillard1e346af1999-02-22 10:33:01 +00001289 *
1290 * Returns the SystemLiteral parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001291 */
1292
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001293CHAR *
1294xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001295 const CHAR *q;
1296 CHAR *ret = NULL;
1297
1298 if (CUR == '"') {
1299 NEXT;
1300 q = CUR_PTR;
1301 while ((IS_CHAR(CUR)) && (CUR != '"'))
1302 NEXT;
1303 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001304 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001305 ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001306 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001307 } else {
1308 ret = xmlStrndup(q, CUR_PTR - q);
1309 NEXT;
1310 }
1311 } else if (CUR == '\'') {
1312 NEXT;
1313 q = CUR_PTR;
1314 while ((IS_CHAR(CUR)) && (CUR != '\''))
1315 NEXT;
1316 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001317 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001318 ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001319 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001320 } else {
1321 ret = xmlStrndup(q, CUR_PTR - q);
1322 NEXT;
1323 }
1324 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001325 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001326 ctxt->sax->error(ctxt->userData, "SystemLiteral \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001327 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001328 }
1329
1330 return(ret);
1331}
1332
Daniel Veillard11e00581998-10-24 18:27:49 +00001333/**
1334 * xmlParsePubidLiteral:
1335 * @ctxt: an XML parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +00001336 *
Daniel Veillard11e00581998-10-24 18:27:49 +00001337 * parse an XML public literal
Daniel Veillard1e346af1999-02-22 10:33:01 +00001338 *
1339 * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1340 *
1341 * Returns the PubidLiteral parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001342 */
1343
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001344CHAR *
1345xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001346 const CHAR *q;
1347 CHAR *ret = NULL;
1348 /*
1349 * Name ::= (Letter | '_') (NameChar)*
1350 */
1351 if (CUR == '"') {
1352 NEXT;
1353 q = CUR_PTR;
1354 while (IS_PUBIDCHAR(CUR)) NEXT;
1355 if (CUR != '"') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001356 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001357 ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001358 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001359 } else {
1360 ret = xmlStrndup(q, CUR_PTR - q);
1361 NEXT;
1362 }
1363 } else if (CUR == '\'') {
1364 NEXT;
1365 q = CUR_PTR;
1366 while ((IS_LETTER(CUR)) && (CUR != '\''))
1367 NEXT;
1368 if (!IS_LETTER(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001369 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001370 ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001371 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001372 } else {
1373 ret = xmlStrndup(q, CUR_PTR - q);
1374 NEXT;
1375 }
1376 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001377 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001378 ctxt->sax->error(ctxt->userData, "SystemLiteral \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001379 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001380 }
1381
1382 return(ret);
1383}
1384
Daniel Veillard11e00581998-10-24 18:27:49 +00001385/**
1386 * xmlParseCharData:
1387 * @ctxt: an XML parser context
1388 * @cdata: int indicating whether we are within a CDATA section
1389 *
1390 * parse a CharData section.
1391 * if we are within a CDATA section ']]>' marks an end of section.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001392 *
1393 * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
1394 */
1395
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001396void
1397xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001398 const CHAR *q;
1399
1400 q = CUR_PTR;
1401 while ((IS_CHAR(CUR)) && (CUR != '<') &&
1402 (CUR != '&')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001403 if ((CUR == ']') && (NXT(1) == ']') &&
1404 (NXT(2) == '>')) {
1405 if (cdata) break;
1406 else {
1407 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001408 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001409 "Sequence ']]>' not allowed in content\n");
1410 ctxt->wellFormed = 0;
1411 }
1412 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001413 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001414 }
1415 if (q == CUR_PTR) return;
1416
1417 /*
1418 * Ok the segment [q CUR_PTR] is to be consumed as chars.
1419 */
1420 if (ctxt->sax != NULL) {
Daniel Veillard517752b1999-04-05 12:20:10 +00001421 if (areBlanks(ctxt, q, CUR_PTR - q)) {
1422 if (ctxt->sax->ignorableWhitespace != NULL)
Daniel Veillard27d88741999-05-29 11:51:49 +00001423 ctxt->sax->ignorableWhitespace(ctxt->userData, q, CUR_PTR - q);
Daniel Veillard517752b1999-04-05 12:20:10 +00001424 } else {
1425 if (ctxt->sax->characters != NULL)
Daniel Veillard27d88741999-05-29 11:51:49 +00001426 ctxt->sax->characters(ctxt->userData, q, CUR_PTR - q);
Daniel Veillard517752b1999-04-05 12:20:10 +00001427 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001428 }
1429}
1430
Daniel Veillard11e00581998-10-24 18:27:49 +00001431/**
1432 * xmlParseExternalID:
1433 * @ctxt: an XML parser context
1434 * @publicID: a CHAR** receiving PubidLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00001435 * @strict: indicate whether we should restrict parsing to only
1436 * production [75], see NOTE below
Daniel Veillard11e00581998-10-24 18:27:49 +00001437 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001438 * Parse an External ID or a Public ID
1439 *
1440 * NOTE: Productions [75] and [83] interract badly since [75] can generate
1441 * 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard260a68f1998-08-13 03:39:55 +00001442 *
1443 * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
1444 * | 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard1e346af1999-02-22 10:33:01 +00001445 *
1446 * [83] PublicID ::= 'PUBLIC' S PubidLiteral
1447 *
1448 * Returns the function returns SystemLiteral and in the second
1449 * case publicID receives PubidLiteral, is strict is off
1450 * it is possible to return NULL and have publicID set.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001451 */
1452
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001453CHAR *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001454xmlParseExternalID(xmlParserCtxtPtr ctxt, CHAR **publicID, int strict) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001455 CHAR *URI = NULL;
1456
1457 if ((CUR == 'S') && (NXT(1) == 'Y') &&
1458 (NXT(2) == 'S') && (NXT(3) == 'T') &&
1459 (NXT(4) == 'E') && (NXT(5) == 'M')) {
1460 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001461 if (!IS_BLANK(CUR)) {
1462 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001463 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001464 "Space required after 'SYSTEM'\n");
1465 ctxt->wellFormed = 0;
1466 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001467 SKIP_BLANKS;
1468 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001469 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001470 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001471 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001472 "xmlParseExternalID: SYSTEM, no URI\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001473 ctxt->wellFormed = 0;
1474 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001475 } else if ((CUR == 'P') && (NXT(1) == 'U') &&
1476 (NXT(2) == 'B') && (NXT(3) == 'L') &&
1477 (NXT(4) == 'I') && (NXT(5) == 'C')) {
1478 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001479 if (!IS_BLANK(CUR)) {
1480 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001481 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001482 "Space required after 'PUBLIC'\n");
1483 ctxt->wellFormed = 0;
1484 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001485 SKIP_BLANKS;
1486 *publicID = xmlParsePubidLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001487 if (*publicID == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001488 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001489 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001490 "xmlParseExternalID: PUBLIC, no Public Identifier\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001491 ctxt->wellFormed = 0;
1492 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001493 if (strict) {
1494 /*
1495 * We don't handle [83] so "S SystemLiteral" is required.
1496 */
1497 if (!IS_BLANK(CUR)) {
1498 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001499 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00001500 "Space required after the Public Identifier\n");
1501 ctxt->wellFormed = 0;
1502 }
1503 } else {
1504 /*
1505 * We handle [83] so we return immediately, if
1506 * "S SystemLiteral" is not detected. From a purely parsing
1507 * point of view that's a nice mess.
1508 */
1509 const CHAR *ptr = CUR_PTR;
1510 if (!IS_BLANK(*ptr)) return(NULL);
1511
1512 while (IS_BLANK(*ptr)) ptr++;
1513 if ((*ptr != '\'') || (*ptr != '"')) return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001514 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001515 SKIP_BLANKS;
1516 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001517 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001518 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001519 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001520 "xmlParseExternalID: PUBLIC, no URI\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001521 ctxt->wellFormed = 0;
1522 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001523 }
1524 return(URI);
1525}
1526
Daniel Veillard11e00581998-10-24 18:27:49 +00001527/**
1528 * xmlParseComment:
Daniel Veillard1e346af1999-02-22 10:33:01 +00001529 * @ctxt: an XML parser context
1530 * @create: should we create a node, or just skip the content
Daniel Veillard11e00581998-10-24 18:27:49 +00001531 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001532 * Skip an XML (SGML) comment <!-- .... -->
1533 * This may or may not create a node (depending on the context)
1534 * The spec says that "For compatibility, the string "--" (double-hyphen)
1535 * must not occur within comments. "
1536 *
1537 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
1538 */
Daniel Veillard517752b1999-04-05 12:20:10 +00001539void
Daniel Veillard1e346af1999-02-22 10:33:01 +00001540xmlParseComment(xmlParserCtxtPtr ctxt, int create) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001541 const CHAR *q, *start;
1542 const CHAR *r;
1543 CHAR *val;
1544
1545 /*
1546 * Check that there is a comment right here.
1547 */
1548 if ((CUR != '<') || (NXT(1) != '!') ||
Daniel Veillard517752b1999-04-05 12:20:10 +00001549 (NXT(2) != '-') || (NXT(3) != '-')) return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001550
1551 SKIP(4);
1552 start = q = CUR_PTR;
1553 NEXT;
1554 r = CUR_PTR;
1555 NEXT;
1556 while (IS_CHAR(CUR) &&
1557 ((CUR == ':') || (CUR != '>') ||
1558 (*r != '-') || (*q != '-'))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001559 if ((*r == '-') && (*q == '-')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001560 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001561 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001562 "Comment must not contain '--' (double-hyphen)`\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001563 ctxt->wellFormed = 0;
1564 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001565 NEXT;r++;q++;
1566 }
1567 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001568 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001569 ctxt->sax->error(ctxt->userData, "Comment not terminated \n<!--%.50s\n", start);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001570 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001571 } else {
1572 NEXT;
1573 if (create) {
1574 val = xmlStrndup(start, q - start);
Daniel Veillard517752b1999-04-05 12:20:10 +00001575 if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001576 ctxt->sax->comment(ctxt->userData, val);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001577 free(val);
1578 }
1579 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001580}
1581
Daniel Veillard11e00581998-10-24 18:27:49 +00001582/**
1583 * xmlParsePITarget:
1584 * @ctxt: an XML parser context
1585 *
1586 * parse the name of a PI
Daniel Veillard260a68f1998-08-13 03:39:55 +00001587 *
1588 * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00001589 *
1590 * Returns the PITarget name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001591 */
1592
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001593CHAR *
1594xmlParsePITarget(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001595 CHAR *name;
1596
1597 name = xmlParseName(ctxt);
1598 if ((name != NULL) && (name[3] == 0) &&
1599 ((name[0] == 'x') || (name[0] == 'X')) &&
1600 ((name[1] == 'm') || (name[1] == 'M')) &&
1601 ((name[2] == 'l') || (name[2] == 'L'))) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001602 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001603 ctxt->sax->error(ctxt->userData, "xmlParsePItarget: invalid name prefix 'xml'\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001604 return(NULL);
1605 }
1606 return(name);
1607}
1608
Daniel Veillard11e00581998-10-24 18:27:49 +00001609/**
1610 * xmlParsePI:
1611 * @ctxt: an XML parser context
1612 *
1613 * parse an XML Processing Instruction.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001614 *
1615 * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
Daniel Veillard1e346af1999-02-22 10:33:01 +00001616 *
1617 * The processing is transfered to SAX once parsed.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001618 */
1619
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001620void
1621xmlParsePI(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001622 CHAR *target;
1623
1624 if ((CUR == '<') && (NXT(1) == '?')) {
1625 /*
1626 * this is a Processing Instruction.
1627 */
1628 SKIP(2);
1629
1630 /*
1631 * Parse the target name and check for special support like
1632 * namespace.
1633 *
1634 * TODO : PI handling should be dynamically redefinable using an
1635 * API. Only namespace should be in the code IMHO ...
1636 */
1637 target = xmlParsePITarget(ctxt);
1638 if (target != NULL) {
Daniel Veillard517752b1999-04-05 12:20:10 +00001639 const CHAR *q = CUR_PTR;
1640
1641 while (IS_CHAR(CUR) &&
1642 ((CUR != '?') || (NXT(1) != '>')))
1643 NEXT;
1644 if (!IS_CHAR(CUR)) {
1645 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001646 ctxt->sax->error(ctxt->userData,
Daniel Veillard517752b1999-04-05 12:20:10 +00001647 "xmlParsePI: PI %s never end ...\n", target);
1648 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001649 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00001650 CHAR *data;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001651
Daniel Veillard517752b1999-04-05 12:20:10 +00001652 data = xmlStrndup(q, CUR_PTR - q);
1653 SKIP(2);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001654
Daniel Veillard517752b1999-04-05 12:20:10 +00001655 /*
1656 * SAX: PI detected.
1657 */
1658 if ((ctxt->sax) &&
1659 (ctxt->sax->processingInstruction != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001660 ctxt->sax->processingInstruction(ctxt->userData, target, data);
Daniel Veillard517752b1999-04-05 12:20:10 +00001661 free(data);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001662 }
1663 free(target);
1664 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001665 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001666 ctxt->sax->error(ctxt->userData, "xmlParsePI : no target name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001667 ctxt->wellFormed = 0;
1668
Daniel Veillard260a68f1998-08-13 03:39:55 +00001669 /********* Should we try to complete parsing the PI ???
1670 while (IS_CHAR(CUR) &&
1671 (CUR != '?') && (CUR != '>'))
1672 NEXT;
1673 if (!IS_CHAR(CUR)) {
1674 fprintf(stderr, "xmlParsePI: PI %s never end ...\n",
1675 target);
1676 }
1677 ********************************************************/
1678 }
1679 }
1680}
1681
Daniel Veillard11e00581998-10-24 18:27:49 +00001682/**
1683 * xmlParseNotationDecl:
1684 * @ctxt: an XML parser context
1685 *
1686 * parse a notation declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00001687 *
1688 * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
1689 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001690 * Hence there is actually 3 choices:
1691 * 'PUBLIC' S PubidLiteral
1692 * 'PUBLIC' S PubidLiteral S SystemLiteral
1693 * and 'SYSTEM' S SystemLiteral
Daniel Veillard11e00581998-10-24 18:27:49 +00001694 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00001695 * See the NOTE on xmlParseExternalID().
Daniel Veillard260a68f1998-08-13 03:39:55 +00001696 */
1697
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001698void
1699xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001700 CHAR *name;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001701 CHAR *Pubid;
1702 CHAR *Systemid;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001703
1704 if ((CUR == '<') && (NXT(1) == '!') &&
1705 (NXT(2) == 'N') && (NXT(3) == 'O') &&
1706 (NXT(4) == 'T') && (NXT(5) == 'A') &&
1707 (NXT(6) == 'T') && (NXT(7) == 'I') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00001708 (NXT(8) == 'O') && (NXT(9) == 'N')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001709 SKIP(10);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001710 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001711 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001712 ctxt->sax->error(ctxt->userData, "Space required after '<!NOTATION'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001713 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001714 return;
1715 }
1716 SKIP_BLANKS;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001717
1718 name = xmlParseName(ctxt);
1719 if (name == NULL) {
1720 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001721 ctxt->sax->error(ctxt->userData, "NOTATION: Name expected here\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001722 ctxt->wellFormed = 0;
1723 return;
1724 }
1725 if (!IS_BLANK(CUR)) {
1726 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001727 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00001728 "Space required after the NOTATION name'\n");
1729 ctxt->wellFormed = 0;
1730 return;
1731 }
1732 SKIP_BLANKS;
1733
Daniel Veillard260a68f1998-08-13 03:39:55 +00001734 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00001735 * Parse the IDs.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001736 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001737 Systemid = xmlParseExternalID(ctxt, &Pubid, 1);
1738 SKIP_BLANKS;
1739
1740 if (CUR == '>') {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001741 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00001742 if ((ctxt->sax != NULL) && (ctxt->sax->notationDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001743 ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001744 } else {
1745 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001746 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00001747 "'>' required to close NOTATION declaration\n");
1748 ctxt->wellFormed = 0;
1749 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001750 free(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001751 if (Systemid != NULL) free(Systemid);
1752 if (Pubid != NULL) free(Pubid);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001753 }
1754}
1755
Daniel Veillard11e00581998-10-24 18:27:49 +00001756/**
1757 * xmlParseEntityDecl:
1758 * @ctxt: an XML parser context
1759 *
1760 * parse <!ENTITY declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00001761 *
1762 * [70] EntityDecl ::= GEDecl | PEDecl
1763 *
1764 * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
1765 *
1766 * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
1767 *
1768 * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
1769 *
1770 * [74] PEDef ::= EntityValue | ExternalID
1771 *
1772 * [76] NDataDecl ::= S 'NDATA' S Name
1773 */
1774
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001775void
1776xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001777 CHAR *name = NULL;
1778 CHAR *value = NULL;
1779 CHAR *URI = NULL, *literal = NULL;
1780 CHAR *ndata = NULL;
1781 int isParameter = 0;
1782
1783 if ((CUR == '<') && (NXT(1) == '!') &&
1784 (NXT(2) == 'E') && (NXT(3) == 'N') &&
1785 (NXT(4) == 'T') && (NXT(5) == 'I') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001786 (NXT(6) == 'T') && (NXT(7) == 'Y')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001787 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001788 if (!IS_BLANK(CUR)) {
1789 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001790 ctxt->sax->error(ctxt->userData, "Space required after '<!ENTITY'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001791 ctxt->wellFormed = 0;
1792 }
1793 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001794
1795 if (CUR == '%') {
1796 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001797 if (!IS_BLANK(CUR)) {
1798 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001799 ctxt->sax->error(ctxt->userData, "Space required after '%'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001800 ctxt->wellFormed = 0;
1801 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001802 SKIP_BLANKS;
1803 isParameter = 1;
1804 }
1805
1806 name = xmlParseName(ctxt);
1807 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001808 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001809 ctxt->sax->error(ctxt->userData, "xmlParseEntityDecl: no name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001810 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001811 return;
1812 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001813 if (!IS_BLANK(CUR)) {
1814 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001815 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001816 "Space required after the entity name\n");
1817 ctxt->wellFormed = 0;
1818 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001819 SKIP_BLANKS;
1820
1821 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +00001822 * handle the various case of definitions...
Daniel Veillard260a68f1998-08-13 03:39:55 +00001823 */
1824 if (isParameter) {
1825 if ((CUR == '"') || (CUR == '\''))
1826 value = xmlParseEntityValue(ctxt);
1827 if (value) {
Daniel Veillard517752b1999-04-05 12:20:10 +00001828 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001829 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001830 XML_INTERNAL_PARAMETER_ENTITY,
1831 NULL, NULL, value);
1832 }
1833 else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001834 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001835 if (URI) {
Daniel Veillard517752b1999-04-05 12:20:10 +00001836 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001837 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001838 XML_EXTERNAL_PARAMETER_ENTITY,
1839 literal, URI, NULL);
1840 }
1841 }
1842 } else {
1843 if ((CUR == '"') || (CUR == '\'')) {
1844 value = xmlParseEntityValue(ctxt);
Daniel Veillard517752b1999-04-05 12:20:10 +00001845 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001846 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001847 XML_INTERNAL_GENERAL_ENTITY,
1848 NULL, NULL, value);
1849 } else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001850 URI = xmlParseExternalID(ctxt, &literal, 1);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001851 if ((CUR != '>') && (!IS_BLANK(CUR))) {
1852 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001853 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001854 "Space required before 'NDATA'\n");
1855 ctxt->wellFormed = 0;
1856 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001857 SKIP_BLANKS;
1858 if ((CUR == 'N') && (NXT(1) == 'D') &&
1859 (NXT(2) == 'A') && (NXT(3) == 'T') &&
1860 (NXT(4) == 'A')) {
1861 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001862 if (!IS_BLANK(CUR)) {
1863 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001864 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001865 "Space required after 'NDATA'\n");
1866 ctxt->wellFormed = 0;
1867 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001868 SKIP_BLANKS;
1869 ndata = xmlParseName(ctxt);
Daniel Veillard517752b1999-04-05 12:20:10 +00001870 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001871 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001872 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
1873 literal, URI, ndata);
1874 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00001875 if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001876 ctxt->sax->entityDecl(ctxt->userData, name,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001877 XML_EXTERNAL_GENERAL_PARSED_ENTITY,
1878 literal, URI, NULL);
1879 }
1880 }
1881 }
1882 SKIP_BLANKS;
1883 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001884 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001885 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001886 "xmlParseEntityDecl: entity %s not terminated\n", name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001887 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001888 } else
1889 NEXT;
1890 if (name != NULL) free(name);
1891 if (value != NULL) free(value);
1892 if (URI != NULL) free(URI);
1893 if (literal != NULL) free(literal);
1894 if (ndata != NULL) free(ndata);
1895 }
1896}
1897
Daniel Veillard11e00581998-10-24 18:27:49 +00001898/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001899 * xmlParseDefaultDecl:
1900 * @ctxt: an XML parser context
1901 * @value: Receive a possible fixed default value for the attribute
1902 *
1903 * Parse an attribute default declaration
1904 *
1905 * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
1906 *
1907 * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
1908 * or XML_ATTRIBUTE_FIXED.
1909 */
1910
1911int
1912xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, CHAR **value) {
1913 int val;
1914 CHAR *ret;
1915
1916 *value = NULL;
1917 if ((CUR == '#') && (NXT(1) == 'R') &&
1918 (NXT(2) == 'E') && (NXT(3) == 'Q') &&
1919 (NXT(4) == 'U') && (NXT(5) == 'I') &&
1920 (NXT(6) == 'R') && (NXT(7) == 'E') &&
1921 (NXT(8) == 'D')) {
1922 SKIP(9);
1923 return(XML_ATTRIBUTE_REQUIRED);
1924 }
1925 if ((CUR == '#') && (NXT(1) == 'I') &&
1926 (NXT(2) == 'M') && (NXT(3) == 'P') &&
1927 (NXT(4) == 'L') && (NXT(5) == 'I') &&
1928 (NXT(6) == 'E') && (NXT(7) == 'D')) {
1929 SKIP(8);
1930 return(XML_ATTRIBUTE_IMPLIED);
1931 }
1932 val = XML_ATTRIBUTE_NONE;
1933 if ((CUR == '#') && (NXT(1) == 'F') &&
1934 (NXT(2) == 'I') && (NXT(3) == 'X') &&
1935 (NXT(4) == 'E') && (NXT(5) == 'D')) {
1936 SKIP(6);
1937 val = XML_ATTRIBUTE_FIXED;
1938 if (!IS_BLANK(CUR)) {
1939 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001940 ctxt->sax->error(ctxt->userData, "Space required after '#FIXED'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001941 ctxt->wellFormed = 0;
1942 }
1943 SKIP_BLANKS;
1944 }
1945 ret = xmlParseAttValue(ctxt);
1946 if (ret == NULL) {
1947 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001948 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001949 "Attribute default value declaration error\n");
1950 ctxt->wellFormed = 0;
1951 } else
1952 *value = ret;
1953 return(val);
1954}
1955
1956/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001957 * xmlParseNotationType:
1958 * @ctxt: an XML parser context
1959 *
1960 * parse an Notation attribute type.
1961 *
1962 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
1963 *
1964 * Note: the leading 'NOTATION' S part has already being parsed...
1965 *
1966 * Returns: the notation attribute tree built while parsing
1967 */
1968
1969xmlEnumerationPtr
1970xmlParseNotationType(xmlParserCtxtPtr ctxt) {
1971 CHAR *name;
1972 xmlEnumerationPtr ret = NULL, last = NULL, cur;
1973
1974 if (CUR != '(') {
1975 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001976 ctxt->sax->error(ctxt->userData, "'(' required to start 'NOTATION'\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001977 ctxt->wellFormed = 0;
1978 return(NULL);
1979 }
1980 do {
1981 NEXT;
1982 SKIP_BLANKS;
1983 name = xmlParseName(ctxt);
1984 if (name == NULL) {
1985 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00001986 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00001987 "Name expected in NOTATION declaration\n");
1988 ctxt->wellFormed = 0;
1989 return(ret);
1990 }
1991 cur = xmlCreateEnumeration(name);
1992 free(name);
1993 if (cur == NULL) return(ret);
1994 if (last == NULL) ret = last = cur;
1995 else {
1996 last->next = cur;
1997 last = cur;
1998 }
1999 SKIP_BLANKS;
2000 } while (CUR == '|');
2001 if (CUR != ')') {
2002 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002003 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002004 "')' required to finish NOTATION declaration\n");
2005 ctxt->wellFormed = 0;
2006 return(ret);
2007 }
2008 NEXT;
2009 return(ret);
2010}
2011
2012/**
2013 * xmlParseEnumerationType:
2014 * @ctxt: an XML parser context
2015 *
2016 * parse an Enumeration attribute type.
2017 *
2018 * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
2019 *
2020 * Returns: the enumeration attribute tree built while parsing
2021 */
2022
2023xmlEnumerationPtr
2024xmlParseEnumerationType(xmlParserCtxtPtr ctxt) {
2025 CHAR *name;
2026 xmlEnumerationPtr ret = NULL, last = NULL, cur;
2027
2028 if (CUR != '(') {
2029 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002030 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002031 "'(' required to start ATTLIST enumeration\n");
2032 ctxt->wellFormed = 0;
2033 return(NULL);
2034 }
2035 do {
2036 NEXT;
2037 SKIP_BLANKS;
2038 name = xmlParseNmtoken(ctxt);
2039 if (name == NULL) {
2040 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002041 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002042 "NmToken expected in ATTLIST enumeration\n");
2043 ctxt->wellFormed = 0;
2044 return(ret);
2045 }
2046 cur = xmlCreateEnumeration(name);
2047 free(name);
2048 if (cur == NULL) return(ret);
2049 if (last == NULL) ret = last = cur;
2050 else {
2051 last->next = cur;
2052 last = cur;
2053 }
2054 SKIP_BLANKS;
2055 } while (CUR == '|');
2056 if (CUR != ')') {
2057 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002058 ctxt->sax->error(ctxt->userData,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002059 "')' required to finish ATTLIST enumeration\n");
2060 ctxt->wellFormed = 0;
2061 return(ret);
2062 }
2063 NEXT;
2064 return(ret);
2065}
2066
2067/**
Daniel Veillard11e00581998-10-24 18:27:49 +00002068 * xmlParseEnumeratedType:
2069 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00002070 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00002071 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00002072 * parse an Enumerated attribute type.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002073 *
2074 * [57] EnumeratedType ::= NotationType | Enumeration
2075 *
2076 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
2077 *
Daniel Veillard11e00581998-10-24 18:27:49 +00002078 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00002079 * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION
Daniel Veillard260a68f1998-08-13 03:39:55 +00002080 */
2081
Daniel Veillard1e346af1999-02-22 10:33:01 +00002082int
2083xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
2084 if ((CUR == 'N') && (NXT(1) == 'O') &&
2085 (NXT(2) == 'T') && (NXT(3) == 'A') &&
2086 (NXT(4) == 'T') && (NXT(5) == 'I') &&
2087 (NXT(6) == 'O') && (NXT(7) == 'N')) {
2088 SKIP(8);
2089 if (!IS_BLANK(CUR)) {
2090 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002091 ctxt->sax->error(ctxt->userData, "Space required after 'NOTATION'\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00002092 ctxt->wellFormed = 0;
2093 return(0);
2094 }
2095 SKIP_BLANKS;
2096 *tree = xmlParseNotationType(ctxt);
2097 if (*tree == NULL) return(0);
2098 return(XML_ATTRIBUTE_NOTATION);
2099 }
2100 *tree = xmlParseEnumerationType(ctxt);
2101 if (*tree == NULL) return(0);
2102 return(XML_ATTRIBUTE_ENUMERATION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002103}
2104
Daniel Veillard11e00581998-10-24 18:27:49 +00002105/**
2106 * xmlParseAttributeType:
2107 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00002108 * @tree: the enumeration tree built while parsing
Daniel Veillard11e00581998-10-24 18:27:49 +00002109 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002110 * parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00002111 *
2112 * [54] AttType ::= StringType | TokenizedType | EnumeratedType
2113 *
2114 * [55] StringType ::= 'CDATA'
2115 *
2116 * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
2117 * 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
Daniel Veillard11e00581998-10-24 18:27:49 +00002118 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00002119 * Returns the attribute type
Daniel Veillard260a68f1998-08-13 03:39:55 +00002120 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002121int
Daniel Veillard1e346af1999-02-22 10:33:01 +00002122xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002123 if ((CUR == 'C') && (NXT(1) == 'D') &&
2124 (NXT(2) == 'A') && (NXT(3) == 'T') &&
2125 (NXT(4) == 'A')) {
2126 SKIP(5);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002127 return(XML_ATTRIBUTE_CDATA);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002128 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
2129 (NXT(2) == 'R') && (NXT(3) == 'E') &&
2130 (NXT(4) == 'F')) {
2131 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002132 return(XML_ATTRIBUTE_IDREF);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002133 } else if ((CUR == 'I') && (NXT(1) == 'D')) {
2134 SKIP(2);
2135 return(XML_ATTRIBUTE_ID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002136 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
2137 (NXT(2) == 'R') && (NXT(3) == 'E') &&
2138 (NXT(4) == 'F') && (NXT(5) == 'S')) {
2139 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002140 return(XML_ATTRIBUTE_IDREFS);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002141 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
2142 (NXT(2) == 'T') && (NXT(3) == 'I') &&
2143 (NXT(4) == 'T') && (NXT(5) == 'Y')) {
2144 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002145 return(XML_ATTRIBUTE_ENTITY);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002146 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
2147 (NXT(2) == 'T') && (NXT(3) == 'I') &&
2148 (NXT(4) == 'T') && (NXT(5) == 'I') &&
2149 (NXT(6) == 'E') && (NXT(7) == 'S')) {
2150 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002151 return(XML_ATTRIBUTE_ENTITIES);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002152 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
2153 (NXT(2) == 'T') && (NXT(3) == 'O') &&
2154 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00002155 (NXT(6) == 'N') && (NXT(7) == 'S')) {
2156 SKIP(8);
2157 return(XML_ATTRIBUTE_NMTOKENS);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002158 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
2159 (NXT(2) == 'T') && (NXT(3) == 'O') &&
2160 (NXT(4) == 'K') && (NXT(5) == 'E') &&
Daniel Veillard1e346af1999-02-22 10:33:01 +00002161 (NXT(6) == 'N')) {
2162 SKIP(7);
2163 return(XML_ATTRIBUTE_NMTOKEN);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002164 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002165 return(xmlParseEnumeratedType(ctxt, tree));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002166}
2167
Daniel Veillard11e00581998-10-24 18:27:49 +00002168/**
2169 * xmlParseAttributeListDecl:
2170 * @ctxt: an XML parser context
2171 *
2172 * : parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00002173 *
2174 * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
2175 *
2176 * [53] AttDef ::= S Name S AttType S DefaultDecl
Daniel Veillard11e00581998-10-24 18:27:49 +00002177 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002178 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002179void
2180xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002181 CHAR *elemName;
2182 CHAR *attrName;
Daniel Veillard1e346af1999-02-22 10:33:01 +00002183 xmlEnumerationPtr tree = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002184
Daniel Veillard260a68f1998-08-13 03:39:55 +00002185 if ((CUR == '<') && (NXT(1) == '!') &&
2186 (NXT(2) == 'A') && (NXT(3) == 'T') &&
2187 (NXT(4) == 'T') && (NXT(5) == 'L') &&
2188 (NXT(6) == 'I') && (NXT(7) == 'S') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002189 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002190 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002191 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002192 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002193 ctxt->sax->error(ctxt->userData, "Space required after '<!ATTLIST'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002194 ctxt->wellFormed = 0;
2195 }
2196 SKIP_BLANKS;
2197 elemName = xmlParseName(ctxt);
2198 if (elemName == NULL) {
2199 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002200 ctxt->sax->error(ctxt->userData, "ATTLIST: no name for Element\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002201 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002202 return;
2203 }
2204 SKIP_BLANKS;
2205 while (CUR != '>') {
2206 const CHAR *check = CUR_PTR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002207 int type;
2208 int def;
2209 CHAR *defaultValue = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002210
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002211 attrName = xmlParseName(ctxt);
2212 if (attrName == NULL) {
2213 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002214 ctxt->sax->error(ctxt->userData, "ATTLIST: no name for Attribute\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002215 ctxt->wellFormed = 0;
2216 break;
2217 }
2218 if (!IS_BLANK(CUR)) {
2219 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002220 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002221 "Space required after the attribute name\n");
2222 ctxt->wellFormed = 0;
2223 break;
2224 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002225 SKIP_BLANKS;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002226
Daniel Veillard1e346af1999-02-22 10:33:01 +00002227 type = xmlParseAttributeType(ctxt, &tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002228 if (type <= 0) break;
2229
2230 if (!IS_BLANK(CUR)) {
2231 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002232 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002233 "Space required after the attribute type\n");
2234 ctxt->wellFormed = 0;
2235 break;
2236 }
2237 SKIP_BLANKS;
2238
2239 def = xmlParseDefaultDecl(ctxt, &defaultValue);
2240 if (def <= 0) break;
2241
2242 if (CUR != '>') {
2243 if (!IS_BLANK(CUR)) {
2244 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002245 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002246 "Space required after the attribute default value\n");
2247 ctxt->wellFormed = 0;
2248 break;
2249 }
2250 SKIP_BLANKS;
2251 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002252 if (check == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002253 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002254 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002255 "xmlParseAttributeListDecl: detected internal error\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002256 break;
2257 }
Daniel Veillard517752b1999-04-05 12:20:10 +00002258 if ((ctxt->sax != NULL) && (ctxt->sax->attributeDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002259 ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName,
Daniel Veillard1e346af1999-02-22 10:33:01 +00002260 type, def, defaultValue, tree);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002261 if (attrName != NULL)
2262 free(attrName);
2263 if (defaultValue != NULL)
2264 free(defaultValue);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002265 }
2266 if (CUR == '>')
2267 NEXT;
2268
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002269 free(elemName);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002270 }
2271}
2272
Daniel Veillard11e00581998-10-24 18:27:49 +00002273/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002274 * xmlParseElementMixedContentDecl:
Daniel Veillard11e00581998-10-24 18:27:49 +00002275 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002276 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002277 * parse the declaration for a Mixed Element content
2278 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
Daniel Veillard260a68f1998-08-13 03:39:55 +00002279 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002280 * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
2281 * '(' S? '#PCDATA' S? ')'
2282 *
2283 * returns: the list of the xmlElementContentPtr describing the element choices
2284 */
2285xmlElementContentPtr
2286xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard1899e851999-02-01 12:18:54 +00002287 xmlElementContentPtr ret = NULL, cur = NULL, n;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002288 CHAR *elem = NULL;
2289
2290 if ((CUR == '#') && (NXT(1) == 'P') &&
2291 (NXT(2) == 'C') && (NXT(3) == 'D') &&
2292 (NXT(4) == 'A') && (NXT(5) == 'T') &&
2293 (NXT(6) == 'A')) {
2294 SKIP(7);
2295 SKIP_BLANKS;
Daniel Veillard3b9def11999-01-31 22:15:06 +00002296 if (CUR == ')') {
2297 NEXT;
2298 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
2299 return(ret);
2300 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002301 if ((CUR == '(') || (CUR == '|')) {
2302 ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
2303 if (ret == NULL) return(NULL);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002304 } /********** else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002305 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002306 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002307 "xmlParseElementMixedContentDecl : '|' or ')' expected\n");
2308 ctxt->wellFormed = 0;
2309 return(NULL);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002310 } **********/
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002311 while (CUR == '|') {
Daniel Veillard1899e851999-02-01 12:18:54 +00002312 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002313 if (elem == NULL) {
2314 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2315 if (ret == NULL) return(NULL);
2316 ret->c1 = cur;
Daniel Veillard1899e851999-02-01 12:18:54 +00002317 cur = ret;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002318 } else {
Daniel Veillard1899e851999-02-01 12:18:54 +00002319 n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2320 if (n == NULL) return(NULL);
2321 n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
2322 cur->c2 = n;
2323 cur = n;
Daniel Veillard1e346af1999-02-22 10:33:01 +00002324 free(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002325 }
2326 SKIP_BLANKS;
2327 elem = xmlParseName(ctxt);
2328 if (elem == NULL) {
2329 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002330 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002331 "xmlParseElementMixedContentDecl : Name expected\n");
2332 ctxt->wellFormed = 0;
2333 xmlFreeElementContent(cur);
2334 return(NULL);
2335 }
2336 SKIP_BLANKS;
2337 }
Daniel Veillard3b9def11999-01-31 22:15:06 +00002338 if ((CUR == ')') && (NXT(1) == '*')) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00002339 if (elem != NULL) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002340 cur->c2 = xmlNewElementContent(elem,
2341 XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002342 free(elem);
2343 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002344 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2345 SKIP(2);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002346 } else {
Daniel Veillard1e346af1999-02-22 10:33:01 +00002347 if (elem != NULL) free(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002348 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002349 ctxt->sax->error(ctxt->userData,
Daniel Veillard3b9def11999-01-31 22:15:06 +00002350 "xmlParseElementMixedContentDecl : '|' or ')*' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002351 ctxt->wellFormed = 0;
2352 xmlFreeElementContent(ret);
2353 return(NULL);
2354 }
2355
2356 } else {
2357 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002358 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002359 "xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
2360 ctxt->wellFormed = 0;
2361 }
2362 return(ret);
2363}
2364
2365/**
2366 * xmlParseElementChildrenContentDecl:
2367 * @ctxt: an XML parser context
2368 *
2369 * parse the declaration for a Mixed Element content
2370 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
2371 *
2372 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002373 * [47] children ::= (choice | seq) ('?' | '*' | '+')?
2374 *
2375 * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
2376 *
2377 * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
2378 *
2379 * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
2380 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002381 * returns: the tree of xmlElementContentPtr describing the element
2382 * hierarchy.
2383 */
2384xmlElementContentPtr
2385xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt) {
2386 xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
2387 CHAR *elem;
2388 CHAR type = 0;
2389
2390 SKIP_BLANKS;
2391 if (CUR == '(') {
2392 /* Recurse on first child */
2393 NEXT;
2394 SKIP_BLANKS;
2395 cur = ret = xmlParseElementChildrenContentDecl(ctxt);
2396 SKIP_BLANKS;
2397 } else {
2398 elem = xmlParseName(ctxt);
2399 if (elem == NULL) {
2400 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002401 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002402 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
2403 ctxt->wellFormed = 0;
2404 return(NULL);
2405 }
2406 cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
2407 if (CUR == '?') {
2408 ret->ocur = XML_ELEMENT_CONTENT_OPT;
2409 NEXT;
2410 } else if (CUR == '*') {
2411 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2412 NEXT;
2413 } else if (CUR == '+') {
2414 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2415 NEXT;
2416 } else {
2417 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2418 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00002419 free(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002420 }
2421 SKIP_BLANKS;
2422 while (CUR != ')') {
2423 /*
2424 * Each loop we parse one separator and one element.
2425 */
2426 if (CUR == ',') {
2427 if (type == 0) type = CUR;
2428
2429 /*
2430 * Detect "Name | Name , Name" error
2431 */
2432 else if (type != CUR) {
2433 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002434 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002435 "xmlParseElementChildrenContentDecl : '%c' expected\n",
2436 type);
2437 ctxt->wellFormed = 0;
2438 xmlFreeElementContent(ret);
2439 return(NULL);
2440 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002441 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002442
2443 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
2444 if (op == NULL) {
2445 xmlFreeElementContent(ret);
2446 return(NULL);
2447 }
2448 if (last == NULL) {
2449 op->c1 = ret;
2450 ret = cur = op;
2451 } else {
2452 cur->c2 = op;
2453 op->c1 = last;
2454 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00002455 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002456 }
2457 } else if (CUR == '|') {
2458 if (type == 0) type = CUR;
2459
2460 /*
2461 * Detect "Name , Name | Name" error
2462 */
2463 else if (type != CUR) {
2464 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002465 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002466 "xmlParseElementChildrenContentDecl : '%c' expected\n",
2467 type);
2468 ctxt->wellFormed = 0;
2469 xmlFreeElementContent(ret);
2470 return(NULL);
2471 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002472 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002473
2474 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2475 if (op == NULL) {
2476 xmlFreeElementContent(ret);
2477 return(NULL);
2478 }
2479 if (last == NULL) {
2480 op->c1 = ret;
2481 ret = cur = op;
2482 } else {
2483 cur->c2 = op;
2484 op->c1 = last;
2485 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00002486 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002487 }
2488 } else {
2489 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002490 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002491 "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
2492 ctxt->wellFormed = 0;
2493 xmlFreeElementContent(ret);
2494 return(NULL);
2495 }
2496 SKIP_BLANKS;
2497 if (CUR == '(') {
2498 /* Recurse on second child */
2499 NEXT;
2500 SKIP_BLANKS;
Daniel Veillard1899e851999-02-01 12:18:54 +00002501 last = xmlParseElementChildrenContentDecl(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002502 SKIP_BLANKS;
2503 } else {
2504 elem = xmlParseName(ctxt);
2505 if (elem == NULL) {
2506 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002507 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002508 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
2509 ctxt->wellFormed = 0;
2510 return(NULL);
2511 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002512 last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard1e346af1999-02-22 10:33:01 +00002513 free(elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002514 }
2515 if (CUR == '?') {
2516 ret->ocur = XML_ELEMENT_CONTENT_OPT;
2517 NEXT;
2518 } else if (CUR == '*') {
2519 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2520 NEXT;
2521 } else if (CUR == '+') {
2522 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2523 NEXT;
2524 } else {
2525 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2526 }
2527 SKIP_BLANKS;
2528 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002529 if ((cur != NULL) && (last != NULL)) {
2530 cur->c2 = last;
2531 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002532 NEXT;
2533 if (CUR == '?') {
2534 ret->ocur = XML_ELEMENT_CONTENT_OPT;
2535 NEXT;
2536 } else if (CUR == '*') {
2537 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2538 NEXT;
2539 } else if (CUR == '+') {
2540 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2541 NEXT;
2542 } else {
2543 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2544 }
2545 return(ret);
2546}
2547
2548/**
2549 * xmlParseElementContentDecl:
2550 * @ctxt: an XML parser context
2551 * @name: the name of the element being defined.
2552 * @result: the Element Content pointer will be stored here if any
Daniel Veillard260a68f1998-08-13 03:39:55 +00002553 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002554 * parse the declaration for an Element content either Mixed or Children,
2555 * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
2556 *
2557 * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
Daniel Veillard11e00581998-10-24 18:27:49 +00002558 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002559 * returns: the type of element content XML_ELEMENT_TYPE_xxx
Daniel Veillard260a68f1998-08-13 03:39:55 +00002560 */
2561
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002562int
2563xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, CHAR *name,
2564 xmlElementContentPtr *result) {
2565
2566 xmlElementContentPtr tree = NULL;
2567 int res;
2568
2569 *result = NULL;
2570
2571 if (CUR != '(') {
2572 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002573 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002574 "xmlParseElementContentDecl : '(' expected\n");
2575 ctxt->wellFormed = 0;
2576 return(-1);
2577 }
2578 NEXT;
2579 SKIP_BLANKS;
2580 if ((CUR == '#') && (NXT(1) == 'P') &&
2581 (NXT(2) == 'C') && (NXT(3) == 'D') &&
2582 (NXT(4) == 'A') && (NXT(5) == 'T') &&
2583 (NXT(6) == 'A')) {
2584 tree = xmlParseElementMixedContentDecl(ctxt);
2585 res = XML_ELEMENT_TYPE_MIXED;
2586 } else {
2587 tree = xmlParseElementChildrenContentDecl(ctxt);
2588 res = XML_ELEMENT_TYPE_ELEMENT;
2589 }
2590 SKIP_BLANKS;
2591 /****************************
2592 if (CUR != ')') {
2593 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002594 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002595 "xmlParseElementContentDecl : ')' expected\n");
2596 ctxt->wellFormed = 0;
2597 return(-1);
2598 }
2599 ****************************/
Daniel Veillard3b9def11999-01-31 22:15:06 +00002600 *result = tree;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002601 return(res);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002602}
2603
Daniel Veillard11e00581998-10-24 18:27:49 +00002604/**
2605 * xmlParseElementDecl:
2606 * @ctxt: an XML parser context
2607 *
2608 * parse an Element declaration.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002609 *
2610 * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
2611 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002612 * TODO There is a check [ VC: Unique Element Type Declaration ]
Daniel Veillard1e346af1999-02-22 10:33:01 +00002613 *
2614 * Returns the type of the element, or -1 in case of error
Daniel Veillard260a68f1998-08-13 03:39:55 +00002615 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002616int
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002617xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002618 CHAR *name;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002619 int ret = -1;
2620 xmlElementContentPtr content = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002621
2622 if ((CUR == '<') && (NXT(1) == '!') &&
2623 (NXT(2) == 'E') && (NXT(3) == 'L') &&
2624 (NXT(4) == 'E') && (NXT(5) == 'M') &&
2625 (NXT(6) == 'E') && (NXT(7) == 'N') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002626 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002627 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002628 if (!IS_BLANK(CUR)) {
2629 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002630 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002631 "Space required after 'ELEMENT'\n");
2632 ctxt->wellFormed = 0;
2633 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002634 SKIP_BLANKS;
2635 name = xmlParseName(ctxt);
2636 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002637 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002638 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002639 "xmlParseElementDecl: no name for Element\n");
2640 ctxt->wellFormed = 0;
2641 return(-1);
2642 }
2643 if (!IS_BLANK(CUR)) {
2644 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002645 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002646 "Space required after the element name\n");
2647 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002648 }
2649 SKIP_BLANKS;
2650 if ((CUR == 'E') && (NXT(1) == 'M') &&
2651 (NXT(2) == 'P') && (NXT(3) == 'T') &&
2652 (NXT(4) == 'Y')) {
2653 SKIP(5);
2654 /*
2655 * Element must always be empty.
2656 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002657 ret = XML_ELEMENT_TYPE_EMPTY;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002658 } else if ((CUR == 'A') && (NXT(1) == 'N') &&
2659 (NXT(2) == 'Y')) {
2660 SKIP(3);
2661 /*
2662 * Element is a generic container.
2663 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002664 ret = XML_ELEMENT_TYPE_ANY;
2665 } else if (CUR == '(') {
2666 ret = xmlParseElementContentDecl(ctxt, name, &content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002667 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002668 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002669 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002670 "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
2671 ctxt->wellFormed = 0;
2672 if (name != NULL) free(name);
2673 return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002674 }
2675 SKIP_BLANKS;
2676 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002677 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002678 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002679 "xmlParseElementDecl: expected '>' at the end\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002680 ctxt->wellFormed = 0;
2681 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002682 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00002683 if ((ctxt->sax != NULL) && (ctxt->sax->elementDecl != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002684 ctxt->sax->elementDecl(ctxt->userData, name, ret, content);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002685 }
2686 if (name != NULL) {
2687 free(name);
2688 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002689 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002690 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002691}
2692
Daniel Veillard11e00581998-10-24 18:27:49 +00002693/**
2694 * xmlParseMarkupDecl:
2695 * @ctxt: an XML parser context
2696 *
2697 * parse Markup declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002698 *
2699 * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
2700 * NotationDecl | PI | Comment
2701 *
2702 * TODO There is a check [ VC: Proper Declaration/PE Nesting ]
2703 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002704void
2705xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002706 xmlParseElementDecl(ctxt);
2707 xmlParseAttributeListDecl(ctxt);
2708 xmlParseEntityDecl(ctxt);
2709 xmlParseNotationDecl(ctxt);
2710 xmlParsePI(ctxt);
2711 xmlParseComment(ctxt, 0);
2712}
2713
Daniel Veillard11e00581998-10-24 18:27:49 +00002714/**
2715 * xmlParseCharRef:
2716 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002717 *
2718 * parse Reference declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002719 *
2720 * [66] CharRef ::= '&#' [0-9]+ ';' |
2721 * '&#x' [0-9a-fA-F]+ ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00002722 *
2723 * Returns the value parsed
Daniel Veillard260a68f1998-08-13 03:39:55 +00002724 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002725CHAR *
2726xmlParseCharRef(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002727 int val = 0;
2728 CHAR buf[2];
2729
2730 if ((CUR == '&') && (NXT(1) == '#') &&
2731 (NXT(2) == 'x')) {
2732 SKIP(3);
2733 while (CUR != ';') {
2734 if ((CUR >= '0') && (CUR <= '9'))
2735 val = val * 16 + (CUR - '0');
2736 else if ((CUR >= 'a') && (CUR <= 'f'))
2737 val = val * 16 + (CUR - 'a') + 10;
2738 else if ((CUR >= 'A') && (CUR <= 'F'))
2739 val = val * 16 + (CUR - 'A') + 10;
2740 else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002741 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002742 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002743 "xmlParseCharRef: invalid hexadecimal value\n");
2744 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002745 val = 0;
2746 break;
2747 }
Daniel Veillard845664d1998-08-13 04:43:19 +00002748 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002749 }
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002750 if (CUR == ';')
Daniel Veillard260a68f1998-08-13 03:39:55 +00002751 NEXT;
2752 } else if ((CUR == '&') && (NXT(1) == '#')) {
2753 SKIP(2);
2754 while (CUR != ';') {
2755 if ((CUR >= '0') && (CUR <= '9'))
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002756 val = val * 10 + (CUR - '0');
Daniel Veillard260a68f1998-08-13 03:39:55 +00002757 else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002758 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002759 ctxt->sax->error(ctxt->userData,
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00002760 "xmlParseCharRef: invalid decimal value\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002761 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002762 val = 0;
2763 break;
2764 }
Daniel Veillard845664d1998-08-13 04:43:19 +00002765 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002766 }
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002767 if (CUR == ';')
Daniel Veillard260a68f1998-08-13 03:39:55 +00002768 NEXT;
2769 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002770 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002771 ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid value\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002772 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002773 }
2774 /*
2775 * Check the value IS_CHAR ...
2776 */
2777 if (IS_CHAR(val)) {
2778 buf[0] = (CHAR) val;
2779 buf[1] = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00002780 return(xmlStrndup(buf, 1));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002781 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002782 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002783 ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid CHAR value %d\n",
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00002784 val);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002785 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002786 }
2787 return(NULL);
2788}
2789
Daniel Veillard11e00581998-10-24 18:27:49 +00002790/**
2791 * xmlParseEntityRef:
2792 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002793 *
2794 * parse ENTITY references declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002795 *
2796 * [68] EntityRef ::= '&' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00002797 *
2798 * Returns the entity ref string or NULL if directly as input stream.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002799 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002800CHAR *
2801xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002802 CHAR *ret = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +00002803 const CHAR *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002804 CHAR *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00002805 xmlEntityPtr ent = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +00002806 xmlParserInputPtr input = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002807
Daniel Veillardccb09631998-10-27 06:21:04 +00002808 q = CUR_PTR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002809 if (CUR == '&') {
2810 NEXT;
2811 name = xmlParseName(ctxt);
2812 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002813 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002814 ctxt->sax->error(ctxt->userData, "xmlParseEntityRef: no name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002815 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002816 } else {
2817 if (CUR == ';') {
2818 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002819 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002820 * Well Formedness Constraint if:
2821 * - standalone
2822 * or
2823 * - no external subset and no external parameter entities
2824 * referenced
2825 * then
2826 * the entity referenced must have been declared
2827 *
Daniel Veillard517752b1999-04-05 12:20:10 +00002828 * TODO: to be double checked !!! This is wrong !
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002829 */
Daniel Veillard517752b1999-04-05 12:20:10 +00002830 if (ctxt->sax != NULL) {
2831 if (ctxt->sax->getEntity != NULL)
Daniel Veillard27d88741999-05-29 11:51:49 +00002832 ent = ctxt->sax->getEntity(ctxt->userData, name);
Daniel Veillard517752b1999-04-05 12:20:10 +00002833
2834 if (((ctxt->sax->isStandalone != NULL) &&
Daniel Veillard27d88741999-05-29 11:51:49 +00002835 ctxt->sax->isStandalone(ctxt->userData) == 1) ||
Daniel Veillard517752b1999-04-05 12:20:10 +00002836 (((ctxt->sax->hasInternalSubset == NULL) ||
Daniel Veillard27d88741999-05-29 11:51:49 +00002837 ctxt->sax->hasInternalSubset(ctxt->userData) == 0) &&
Daniel Veillard517752b1999-04-05 12:20:10 +00002838 ((ctxt->sax->hasExternalSubset == NULL) ||
Daniel Veillard27d88741999-05-29 11:51:49 +00002839 ctxt->sax->hasExternalSubset(ctxt->userData) == 0))) {
Daniel Veillard517752b1999-04-05 12:20:10 +00002840 if (ent == NULL) {
2841 if ((ctxt->sax != NULL) &&
2842 (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002843 ctxt->sax->error(ctxt->userData,
Daniel Veillard517752b1999-04-05 12:20:10 +00002844 "Entity '%s' not defined\n", name);
2845 ctxt->wellFormed = 0;
2846 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002847 }
Daniel Veillard517752b1999-04-05 12:20:10 +00002848 } else
2849 ctxt->wellFormed = 0;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002850
2851 /*
2852 * Well Formedness Constraint :
2853 * The referenced entity must be a parsed entity.
2854 */
2855 if (ent != NULL) {
2856 switch (ent->type) {
2857 case XML_INTERNAL_PARAMETER_ENTITY:
2858 case XML_EXTERNAL_PARAMETER_ENTITY:
2859 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002860 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002861 "Attempt to reference the parameter entity '%s'\n", name);
2862 ctxt->wellFormed = 0;
2863 break;
2864
2865 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
2866 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002867 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002868 "Attempt to reference unparsed entity '%s'\n", name);
2869 ctxt->wellFormed = 0;
2870 break;
2871 }
2872 }
2873
2874 /*
2875 * Well Formedness Constraint :
2876 * The referenced entity must not lead to recursion !
2877 */
2878
2879 /*
Daniel Veillardccb09631998-10-27 06:21:04 +00002880 * We parsed the entity reference correctly, call SAX
2881 * interface for the proper behaviour:
2882 * - get a new input stream
2883 * - or keep the reference inline
Daniel Veillard260a68f1998-08-13 03:39:55 +00002884 */
Daniel Veillard517752b1999-04-05 12:20:10 +00002885 if ((ctxt->sax) && (ctxt->sax->resolveEntity != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002886 input = ctxt->sax->resolveEntity(ctxt->userData, NULL, name);
Daniel Veillardccb09631998-10-27 06:21:04 +00002887 if (input != NULL)
2888 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002889 else {
Daniel Veillardccb09631998-10-27 06:21:04 +00002890 ret = xmlStrndup(q, CUR_PTR - q);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002891 }
2892 } else {
2893 char cst[2] = { '&', 0 };
2894
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002895 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002896 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002897 "xmlParseEntityRef: expecting ';'\n");
2898 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002899 ret = xmlStrndup(cst, 1);
2900 ret = xmlStrcat(ret, name);
2901 }
2902 free(name);
2903 }
2904 }
2905 return(ret);
2906}
2907
Daniel Veillard11e00581998-10-24 18:27:49 +00002908/**
2909 * xmlParseReference:
2910 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002911 *
2912 * parse Reference declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002913 *
2914 * [67] Reference ::= EntityRef | CharRef
Daniel Veillard1e346af1999-02-22 10:33:01 +00002915 *
2916 * Returns the entity string or NULL if handled directly by pushing
Daniel Veillardccb09631998-10-27 06:21:04 +00002917 * the entity value as the input.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002918 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002919CHAR *
2920xmlParseReference(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002921 if ((CUR == '&') && (NXT(1) == '#')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002922 CHAR *val = xmlParseCharRef(ctxt);
2923 xmlParserInputPtr in;
2924
2925 if (val != NULL) {
2926 in = xmlNewStringInputStream(ctxt, val);
2927 xmlPushInput(ctxt, in);
2928 }
2929 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002930 } else if (CUR == '&') {
Daniel Veillardccb09631998-10-27 06:21:04 +00002931 return(xmlParseEntityRef(ctxt));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002932 }
2933 return(NULL);
2934}
2935
Daniel Veillard11e00581998-10-24 18:27:49 +00002936/**
2937 * xmlParsePEReference:
2938 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002939 *
2940 * parse PEReference declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002941 *
2942 * [69] PEReference ::= '%' Name ';'
Daniel Veillard1e346af1999-02-22 10:33:01 +00002943 *
2944 * Returns the entity content or NULL if handled directly.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002945 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002946CHAR *
2947xmlParsePEReference(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002948 CHAR *ret = NULL;
2949 CHAR *name;
Daniel Veillard517752b1999-04-05 12:20:10 +00002950 xmlEntityPtr entity = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +00002951 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002952
2953 if (CUR == '%') {
2954 NEXT;
2955 name = xmlParseName(ctxt);
2956 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002957 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002958 ctxt->sax->error(ctxt->userData, "xmlParsePEReference: no name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002959 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002960 } else {
2961 if (CUR == ';') {
2962 NEXT;
Daniel Veillard517752b1999-04-05 12:20:10 +00002963 if ((ctxt->sax != NULL) && (ctxt->sax->getEntity != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002964 entity = ctxt->sax->getEntity(ctxt->userData, name);
Daniel Veillard517752b1999-04-05 12:20:10 +00002965 /* TODO !!!! Must check that it's of the proper type !!! */
Daniel Veillard260a68f1998-08-13 03:39:55 +00002966 if (entity == NULL) {
Daniel Veillard42dc9b31998-11-09 01:17:21 +00002967 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002968 ctxt->sax->warning(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002969 "xmlParsePEReference: %%%s; not found\n", name);
Daniel Veillardccb09631998-10-27 06:21:04 +00002970 } else {
2971 input = xmlNewEntityInputStream(ctxt, entity);
2972 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002973 }
2974 } else {
Daniel Veillardccb09631998-10-27 06:21:04 +00002975 char cst[2] = { '%', 0 };
Daniel Veillard260a68f1998-08-13 03:39:55 +00002976
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002977 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00002978 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002979 "xmlParsePEReference: expecting ';'\n");
2980 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002981 ret = xmlStrndup(cst, 1);
2982 ret = xmlStrcat(ret, name);
2983 }
2984 free(name);
2985 }
2986 }
2987 return(ret);
2988}
2989
Daniel Veillard11e00581998-10-24 18:27:49 +00002990/**
2991 * xmlParseDocTypeDecl :
2992 * @ctxt: an XML parser context
2993 *
2994 * parse a DOCTYPE declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00002995 *
2996 * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
2997 * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
2998 */
2999
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003000void
3001xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003002 CHAR *name;
3003 CHAR *ExternalID = NULL;
3004 CHAR *URI = NULL;
3005
3006 /*
3007 * We know that '<!DOCTYPE' has been detected.
3008 */
3009 SKIP(9);
3010
3011 SKIP_BLANKS;
3012
3013 /*
3014 * Parse the DOCTYPE name.
3015 */
3016 name = xmlParseName(ctxt);
3017 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003018 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003019 ctxt->sax->error(ctxt->userData, "xmlParseDocTypeDecl : no DOCTYPE name !\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003020 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003021 }
3022
3023 SKIP_BLANKS;
3024
3025 /*
3026 * Check for SystemID and ExternalID
3027 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00003028 URI = xmlParseExternalID(ctxt, &ExternalID, 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003029 SKIP_BLANKS;
3030
Daniel Veillard517752b1999-04-05 12:20:10 +00003031 if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003032 ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003033
3034 /*
3035 * Is there any DTD definition ?
3036 */
3037 if (CUR == '[') {
3038 NEXT;
3039 /*
3040 * Parse the succession of Markup declarations and
3041 * PEReferences.
3042 * Subsequence (markupdecl | PEReference | S)*
3043 */
3044 while (CUR != ']') {
3045 const CHAR *check = CUR_PTR;
3046
3047 SKIP_BLANKS;
3048 xmlParseMarkupDecl(ctxt);
Daniel Veillardccb09631998-10-27 06:21:04 +00003049 xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003050
3051 if (CUR_PTR == check) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003052 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003053 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003054 "xmlParseDocTypeDecl: error detected in Markup declaration\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003055 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003056 break;
3057 }
3058 }
3059 if (CUR == ']') NEXT;
3060 }
3061
3062 /*
3063 * We should be at the end of the DOCTYPE declaration.
3064 */
3065 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003066 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003067 ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003068 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003069 /* We shouldn't try to resynchronize ... */
3070 }
3071 NEXT;
3072
3073 /*
3074 * Cleanup, since we don't use all those identifiers
3075 * TODO : the DOCTYPE if available should be stored !
3076 */
3077 if (URI != NULL) free(URI);
3078 if (ExternalID != NULL) free(ExternalID);
3079 if (name != NULL) free(name);
3080}
3081
Daniel Veillard11e00581998-10-24 18:27:49 +00003082/**
3083 * xmlParseAttribute:
3084 * @ctxt: an XML parser context
Daniel Veillard517752b1999-04-05 12:20:10 +00003085 * @value: a CHAR ** used to store the value of the attribute
Daniel Veillard11e00581998-10-24 18:27:49 +00003086 *
3087 * parse an attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00003088 *
3089 * [41] Attribute ::= Name Eq AttValue
3090 *
3091 * [25] Eq ::= S? '=' S?
3092 *
3093 * With namespace:
3094 *
3095 * [NS 11] Attribute ::= QName Eq AttValue
3096 *
3097 * Also the case QName == xmlns:??? is handled independently as a namespace
3098 * definition.
Daniel Veillard1e346af1999-02-22 10:33:01 +00003099 *
Daniel Veillard517752b1999-04-05 12:20:10 +00003100 * Returns the attribute name, and the value in *value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003101 */
3102
Daniel Veillard517752b1999-04-05 12:20:10 +00003103CHAR *
3104xmlParseAttribute(xmlParserCtxtPtr ctxt, CHAR **value) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003105 CHAR *name, *val;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003106
Daniel Veillard517752b1999-04-05 12:20:10 +00003107 *value = NULL;
3108 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003109 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003110 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003111 ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003112 ctxt->wellFormed = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00003113 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003114 }
3115
3116 /*
3117 * read the value
3118 */
3119 SKIP_BLANKS;
3120 if (CUR == '=') {
3121 NEXT;
3122 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00003123 val = xmlParseAttValue(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003124 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003125 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003126 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003127 "Specification mandate value for attribute %s\n", name);
3128 ctxt->wellFormed = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00003129 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003130 }
3131
Daniel Veillard517752b1999-04-05 12:20:10 +00003132 *value = val;
3133 return(name);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003134}
3135
Daniel Veillard11e00581998-10-24 18:27:49 +00003136/**
3137 * xmlParseStartTag:
3138 * @ctxt: an XML parser context
3139 *
3140 * parse a start of tag either for rule element or
3141 * EmptyElement. In both case we don't parse the tag closing chars.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003142 *
3143 * [40] STag ::= '<' Name (S Attribute)* S? '>'
3144 *
3145 * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
3146 *
3147 * With namespace:
3148 *
3149 * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
3150 *
3151 * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
3152 */
3153
Daniel Veillard517752b1999-04-05 12:20:10 +00003154void
Daniel Veillard1e346af1999-02-22 10:33:01 +00003155xmlParseStartTag(xmlParserCtxtPtr ctxt) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003156 CHAR *name;
3157 CHAR *attname;
3158 CHAR *attvalue;
3159 const CHAR **atts = NULL;
3160 int nbatts = 0;
3161 int maxatts = 0;
3162 int i;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003163
Daniel Veillard517752b1999-04-05 12:20:10 +00003164 if (CUR != '<') return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003165 NEXT;
3166
Daniel Veillard517752b1999-04-05 12:20:10 +00003167 name = xmlParseName(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003168 if (name == NULL) {
3169 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003170 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003171 "xmlParseStartTag: invalid element name\n");
3172 ctxt->wellFormed = 0;
Daniel Veillard517752b1999-04-05 12:20:10 +00003173 return;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003174 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003175
3176 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00003177 * Now parse the attributes, it ends up with the ending
3178 *
3179 * (S Attribute)* S?
3180 */
3181 SKIP_BLANKS;
3182 while ((IS_CHAR(CUR)) &&
3183 (CUR != '>') &&
3184 ((CUR != '/') || (NXT(1) != '>'))) {
3185 const CHAR *q = CUR_PTR;
3186
Daniel Veillard517752b1999-04-05 12:20:10 +00003187 attname = xmlParseAttribute(ctxt, &attvalue);
3188 if ((attname != NULL) && (attvalue != NULL)) {
3189 /*
3190 * Well formedness requires at most one declaration of an attribute
3191 */
3192 for (i = 0; i < nbatts;i += 2) {
3193 if (!xmlStrcmp(atts[i], attname)) {
3194 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003195 ctxt->sax->error(ctxt->userData, "Attribute %s redefined\n",
Daniel Veillard517752b1999-04-05 12:20:10 +00003196 name);
3197 ctxt->wellFormed = 0;
3198 free(attname);
3199 free(attvalue);
3200 break;
3201 }
3202 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003203
Daniel Veillard517752b1999-04-05 12:20:10 +00003204 /*
3205 * Add the pair to atts
3206 */
3207 if (atts == NULL) {
3208 maxatts = 10;
3209 atts = (const CHAR **) malloc(maxatts * sizeof(CHAR *));
3210 if (atts == NULL) {
3211 fprintf(stderr, "malloc of %d byte failed\n",
3212 maxatts * sizeof(CHAR *));
3213 return;
3214 }
3215 } else if (nbatts + 2 < maxatts) {
3216 maxatts *= 2;
3217 atts = (const CHAR **) realloc(atts, maxatts * sizeof(CHAR *));
3218 if (atts == NULL) {
3219 fprintf(stderr, "realloc of %d byte failed\n",
3220 maxatts * sizeof(CHAR *));
3221 return;
3222 }
3223 }
3224 atts[nbatts++] = attname;
3225 atts[nbatts++] = attvalue;
3226 atts[nbatts] = NULL;
3227 atts[nbatts + 1] = NULL;
3228 }
3229
3230 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003231 if (q == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003232 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003233 ctxt->sax->error(ctxt->userData,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003234 "xmlParseStartTag: problem parsing attributes\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003235 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003236 break;
3237 }
3238 }
3239
3240 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00003241 * SAX: Start of Element !
3242 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003243 if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003244 ctxt->sax->startElement(ctxt->userData, name, atts);
Daniel Veillard517752b1999-04-05 12:20:10 +00003245
Daniel Veillardccb09631998-10-27 06:21:04 +00003246 free(name);
Daniel Veillard517752b1999-04-05 12:20:10 +00003247 if (atts != NULL) {
3248 for (i = 0;i < nbatts;i++) free((CHAR *) atts[i]);
3249 free(atts);
3250 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003251}
3252
Daniel Veillard11e00581998-10-24 18:27:49 +00003253/**
3254 * xmlParseEndTag:
3255 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00003256 *
3257 * parse an end of tag
Daniel Veillard260a68f1998-08-13 03:39:55 +00003258 *
3259 * [42] ETag ::= '</' Name S? '>'
3260 *
3261 * With namespace
3262 *
Daniel Veillard517752b1999-04-05 12:20:10 +00003263 * [NS 9] ETag ::= '</' QName S? '>'
Daniel Veillard260a68f1998-08-13 03:39:55 +00003264 */
3265
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003266void
Daniel Veillard517752b1999-04-05 12:20:10 +00003267xmlParseEndTag(xmlParserCtxtPtr ctxt) {
3268 CHAR *name;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003269
3270 if ((CUR != '<') || (NXT(1) != '/')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003271 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003272 ctxt->sax->error(ctxt->userData, "xmlParseEndTag: '</' not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003273 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003274 return;
3275 }
3276 SKIP(2);
3277
Daniel Veillard517752b1999-04-05 12:20:10 +00003278 name = xmlParseName(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003279
3280 /*
3281 * We should definitely be at the ending "S? '>'" part
3282 */
3283 SKIP_BLANKS;
3284 if ((!IS_CHAR(CUR)) || (CUR != '>')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003285 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003286 ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003287 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003288 } else
3289 NEXT;
3290
Daniel Veillard517752b1999-04-05 12:20:10 +00003291 /*
3292 * SAX: End of Tag
3293 */
3294 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003295 ctxt->sax->endElement(ctxt->userData, name);
Daniel Veillard517752b1999-04-05 12:20:10 +00003296
3297 if (name != NULL)
3298 free(name);
3299
Daniel Veillard260a68f1998-08-13 03:39:55 +00003300 return;
3301}
3302
Daniel Veillard11e00581998-10-24 18:27:49 +00003303/**
3304 * xmlParseCDSect:
3305 * @ctxt: an XML parser context
3306 *
3307 * Parse escaped pure raw content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003308 *
3309 * [18] CDSect ::= CDStart CData CDEnd
3310 *
3311 * [19] CDStart ::= '<![CDATA['
3312 *
3313 * [20] Data ::= (Char* - (Char* ']]>' Char*))
3314 *
3315 * [21] CDEnd ::= ']]>'
3316 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003317void
3318xmlParseCDSect(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003319 const CHAR *r, *s, *base;
3320
3321 if ((CUR == '<') && (NXT(1) == '!') &&
3322 (NXT(2) == '[') && (NXT(3) == 'C') &&
3323 (NXT(4) == 'D') && (NXT(5) == 'A') &&
3324 (NXT(6) == 'T') && (NXT(7) == 'A') &&
3325 (NXT(8) == '[')) {
3326 SKIP(9);
3327 } else
3328 return;
3329 base = CUR_PTR;
3330 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003331 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003332 ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003333 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003334 return;
3335 }
3336 r = NEXT;
3337 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003338 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003339 ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003340 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003341 return;
3342 }
3343 s = NEXT;
3344 while (IS_CHAR(CUR) &&
3345 ((*r != ']') || (*s != ']') || (CUR != '>'))) {
3346 r++;s++;NEXT;
3347 }
3348 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003349 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003350 ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003351 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003352 return;
3353 }
3354
3355 /*
3356 * Ok the segment [base CUR_PTR] is to be consumed as chars.
3357 */
3358 if (ctxt->sax != NULL) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003359 if (areBlanks(ctxt, base, CUR_PTR - base)) {
3360 if (ctxt->sax->ignorableWhitespace != NULL)
Daniel Veillard27d88741999-05-29 11:51:49 +00003361 ctxt->sax->ignorableWhitespace(ctxt->userData, base,
Daniel Veillard517752b1999-04-05 12:20:10 +00003362 (CUR_PTR - base) - 2);
3363 } else {
3364 if (ctxt->sax->characters != NULL)
Daniel Veillard27d88741999-05-29 11:51:49 +00003365 ctxt->sax->characters(ctxt->userData, base, (CUR_PTR - base) - 2);
Daniel Veillard517752b1999-04-05 12:20:10 +00003366 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003367 }
3368}
3369
Daniel Veillard11e00581998-10-24 18:27:49 +00003370/**
3371 * xmlParseContent:
3372 * @ctxt: an XML parser context
3373 *
3374 * Parse a content:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003375 *
3376 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
3377 */
3378
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003379void
3380xmlParseContent(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003381 while ((CUR != '<') || (NXT(1) != '/')) {
3382 const CHAR *test = CUR_PTR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003383
3384 /*
3385 * First case : a Processing Instruction.
3386 */
3387 if ((CUR == '<') && (NXT(1) == '?')) {
3388 xmlParsePI(ctxt);
3389 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003390
Daniel Veillard260a68f1998-08-13 03:39:55 +00003391 /*
3392 * Second case : a CDSection
3393 */
3394 else if ((CUR == '<') && (NXT(1) == '!') &&
3395 (NXT(2) == '[') && (NXT(3) == 'C') &&
3396 (NXT(4) == 'D') && (NXT(5) == 'A') &&
3397 (NXT(6) == 'T') && (NXT(7) == 'A') &&
3398 (NXT(8) == '[')) {
3399 xmlParseCDSect(ctxt);
3400 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003401
Daniel Veillard260a68f1998-08-13 03:39:55 +00003402 /*
3403 * Third case : a comment
3404 */
3405 else if ((CUR == '<') && (NXT(1) == '!') &&
3406 (NXT(2) == '-') && (NXT(3) == '-')) {
Daniel Veillard517752b1999-04-05 12:20:10 +00003407 xmlParseComment(ctxt, 1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003408 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003409
Daniel Veillard260a68f1998-08-13 03:39:55 +00003410 /*
3411 * Fourth case : a sub-element.
3412 */
3413 else if (CUR == '<') {
Daniel Veillard517752b1999-04-05 12:20:10 +00003414 xmlParseElement(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003415 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003416
Daniel Veillard260a68f1998-08-13 03:39:55 +00003417 /*
Daniel Veillardccb09631998-10-27 06:21:04 +00003418 * Fifth case : a reference. If if has not been resolved,
3419 * parsing returns it's Name, create the node
Daniel Veillard260a68f1998-08-13 03:39:55 +00003420 */
3421 else if (CUR == '&') {
Daniel Veillardccb09631998-10-27 06:21:04 +00003422 CHAR *val = xmlParseReference(ctxt);
3423 if (val != NULL) {
3424 if (val[0] != '&') {
3425 /*
3426 * inline predefined entity.
3427 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003428 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003429 ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val));
Daniel Veillardccb09631998-10-27 06:21:04 +00003430 } else {
3431 /*
3432 * user defined entity, create a node.
3433 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003434 if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003435 ctxt->sax->reference(ctxt->userData, val);
Daniel Veillardccb09631998-10-27 06:21:04 +00003436 }
3437 free(val);
3438 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003439 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003440
Daniel Veillard260a68f1998-08-13 03:39:55 +00003441 /*
3442 * Last case, text. Note that References are handled directly.
3443 */
3444 else {
3445 xmlParseCharData(ctxt, 0);
3446 }
3447
3448 /*
3449 * Pop-up of finished entities.
3450 */
Daniel Veillardbc50b591999-03-01 12:28:53 +00003451 while ((CUR == 0) && (ctxt->inputNr > 1))
3452 xmlPopInput(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003453
3454 if (test == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003455 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003456 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003457 "detected an error in element content\n");
3458 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003459 break;
3460 }
3461 }
3462}
3463
Daniel Veillard11e00581998-10-24 18:27:49 +00003464/**
3465 * xmlParseElement:
3466 * @ctxt: an XML parser context
3467 *
3468 * parse an XML element, this is highly recursive
Daniel Veillard260a68f1998-08-13 03:39:55 +00003469 *
3470 * [39] element ::= EmptyElemTag | STag content ETag
3471 *
3472 * [41] Attribute ::= Name Eq AttValue
3473 */
3474
Daniel Veillard517752b1999-04-05 12:20:10 +00003475void
Daniel Veillard1e346af1999-02-22 10:33:01 +00003476xmlParseElement(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003477 const CHAR *openTag = CUR_PTR;
3478 xmlParserNodeInfo node_info;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003479
3480 /* Capture start position */
3481 node_info.begin_pos = CUR_PTR - ctxt->input->base;
3482 node_info.begin_line = ctxt->input->line;
3483
Daniel Veillard517752b1999-04-05 12:20:10 +00003484 xmlParseStartTag(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003485
3486 /*
3487 * Check for an Empty Element.
3488 */
3489 if ((CUR == '/') && (NXT(1) == '>')) {
3490 SKIP(2);
Daniel Veillard517752b1999-04-05 12:20:10 +00003491 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003492 ctxt->sax->endElement(ctxt->userData, NULL);
Daniel Veillard517752b1999-04-05 12:20:10 +00003493 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003494 }
3495 if (CUR == '>') NEXT;
3496 else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003497 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003498 ctxt->sax->error(ctxt->userData, "Couldn't find end of Start Tag\n%.30s\n",
Daniel Veillard242590e1998-11-13 18:04:35 +00003499 openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003500 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003501
3502 /*
3503 * end of parsing of this node.
Daniel Veillard517752b1999-04-05 12:20:10 +00003504 * TODO !!!!!!!! check the macro in case of non DOM parsing
Daniel Veillard260a68f1998-08-13 03:39:55 +00003505 */
3506 nodePop(ctxt);
3507
Daniel Veillard517752b1999-04-05 12:20:10 +00003508 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003509 }
3510
3511 /*
3512 * Parse the content of the element:
3513 */
3514 xmlParseContent(ctxt);
3515 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003516 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003517 ctxt->sax->error(ctxt->userData,
Daniel Veillard242590e1998-11-13 18:04:35 +00003518 "Premature end of data in tag %.30s\n", openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003519 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003520
3521 /*
3522 * end of parsing of this node.
Daniel Veillard517752b1999-04-05 12:20:10 +00003523 * TODO !!!!!!!! check the macro in case of non DOM parsing
Daniel Veillard260a68f1998-08-13 03:39:55 +00003524 */
3525 nodePop(ctxt);
3526
Daniel Veillard517752b1999-04-05 12:20:10 +00003527 return;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003528 }
3529
3530 /*
3531 * parse the end of tag: '</' should be here.
3532 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003533 xmlParseEndTag(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003534}
3535
Daniel Veillard11e00581998-10-24 18:27:49 +00003536/**
3537 * xmlParseVersionNum:
3538 * @ctxt: an XML parser context
3539 *
3540 * parse the XML version value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003541 *
3542 * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
Daniel Veillard1e346af1999-02-22 10:33:01 +00003543 *
3544 * Returns the string giving the XML version number, or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003545 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003546CHAR *
3547xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003548 const CHAR *q = CUR_PTR;
3549 CHAR *ret;
3550
3551 while (IS_CHAR(CUR) &&
3552 (((CUR >= 'a') && (CUR <= 'z')) ||
3553 ((CUR >= 'A') && (CUR <= 'Z')) ||
3554 ((CUR >= '0') && (CUR <= '9')) ||
3555 (CUR == '_') || (CUR == '.') ||
3556 (CUR == ':') || (CUR == '-'))) NEXT;
3557 ret = xmlStrndup(q, CUR_PTR - q);
3558 return(ret);
3559}
3560
Daniel Veillard11e00581998-10-24 18:27:49 +00003561/**
3562 * xmlParseVersionInfo:
3563 * @ctxt: an XML parser context
3564 *
3565 * parse the XML version.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003566 *
3567 * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
3568 *
3569 * [25] Eq ::= S? '=' S?
Daniel Veillard11e00581998-10-24 18:27:49 +00003570 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003571 * Returns the version string, e.g. "1.0"
Daniel Veillard260a68f1998-08-13 03:39:55 +00003572 */
3573
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003574CHAR *
3575xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003576 CHAR *version = NULL;
3577 const CHAR *q;
3578
3579 if ((CUR == 'v') && (NXT(1) == 'e') &&
3580 (NXT(2) == 'r') && (NXT(3) == 's') &&
3581 (NXT(4) == 'i') && (NXT(5) == 'o') &&
3582 (NXT(6) == 'n')) {
3583 SKIP(7);
3584 SKIP_BLANKS;
3585 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003586 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003587 ctxt->sax->error(ctxt->userData, "xmlParseVersionInfo : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003588 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003589 return(NULL);
3590 }
3591 NEXT;
3592 SKIP_BLANKS;
3593 if (CUR == '"') {
3594 NEXT;
3595 q = CUR_PTR;
3596 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003597 if (CUR != '"') {
3598 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003599 ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003600 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003601 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003602 NEXT;
3603 } else if (CUR == '\''){
3604 NEXT;
3605 q = CUR_PTR;
3606 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003607 if (CUR != '\'') {
3608 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003609 ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003610 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003611 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003612 NEXT;
3613 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003614 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003615 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003616 "xmlParseVersionInfo : expected ' or \"\n");
3617 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003618 }
3619 }
3620 return(version);
3621}
3622
Daniel Veillard11e00581998-10-24 18:27:49 +00003623/**
3624 * xmlParseEncName:
3625 * @ctxt: an XML parser context
3626 *
3627 * parse the XML encoding name
Daniel Veillard260a68f1998-08-13 03:39:55 +00003628 *
3629 * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
Daniel Veillard11e00581998-10-24 18:27:49 +00003630 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003631 * Returns the encoding name value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003632 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003633CHAR *
3634xmlParseEncName(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003635 const CHAR *q = CUR_PTR;
3636 CHAR *ret = NULL;
3637
3638 if (((CUR >= 'a') && (CUR <= 'z')) ||
3639 ((CUR >= 'A') && (CUR <= 'Z'))) {
3640 NEXT;
3641 while (IS_CHAR(CUR) &&
3642 (((CUR >= 'a') && (CUR <= 'z')) ||
3643 ((CUR >= 'A') && (CUR <= 'Z')) ||
3644 ((CUR >= '0') && (CUR <= '9')) ||
3645 (CUR == '-'))) NEXT;
3646 ret = xmlStrndup(q, CUR_PTR - q);
3647 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003648 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003649 ctxt->sax->error(ctxt->userData, "Invalid XML encoding name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003650 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003651 }
3652 return(ret);
3653}
3654
Daniel Veillard11e00581998-10-24 18:27:49 +00003655/**
3656 * xmlParseEncodingDecl:
3657 * @ctxt: an XML parser context
3658 *
3659 * parse the XML encoding declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003660 *
3661 * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'")
Daniel Veillard11e00581998-10-24 18:27:49 +00003662 *
3663 * TODO: this should setup the conversion filters.
3664 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003665 * Returns the encoding value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003666 */
3667
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003668CHAR *
3669xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003670 CHAR *encoding = NULL;
3671 const CHAR *q;
3672
3673 SKIP_BLANKS;
3674 if ((CUR == 'e') && (NXT(1) == 'n') &&
3675 (NXT(2) == 'c') && (NXT(3) == 'o') &&
3676 (NXT(4) == 'd') && (NXT(5) == 'i') &&
3677 (NXT(6) == 'n') && (NXT(7) == 'g')) {
3678 SKIP(8);
3679 SKIP_BLANKS;
3680 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003681 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003682 ctxt->sax->error(ctxt->userData, "xmlParseEncodingDecl : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003683 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003684 return(NULL);
3685 }
3686 NEXT;
3687 SKIP_BLANKS;
3688 if (CUR == '"') {
3689 NEXT;
3690 q = CUR_PTR;
3691 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003692 if (CUR != '"') {
3693 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003694 ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003695 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003696 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003697 NEXT;
3698 } else if (CUR == '\''){
3699 NEXT;
3700 q = CUR_PTR;
3701 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003702 if (CUR != '\'') {
3703 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003704 ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003705 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003706 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003707 NEXT;
3708 } else if (CUR == '"'){
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003709 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003710 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003711 "xmlParseEncodingDecl : expected ' or \"\n");
3712 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003713 }
3714 }
3715 return(encoding);
3716}
3717
Daniel Veillard11e00581998-10-24 18:27:49 +00003718/**
3719 * xmlParseSDDecl:
3720 * @ctxt: an XML parser context
3721 *
3722 * parse the XML standalone declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003723 *
3724 * [32] SDDecl ::= S 'standalone' Eq
3725 * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"'))
Daniel Veillard1e346af1999-02-22 10:33:01 +00003726 *
3727 * Returns 1 if standalone, 0 otherwise
Daniel Veillard260a68f1998-08-13 03:39:55 +00003728 */
3729
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003730int
3731xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003732 int standalone = -1;
3733
3734 SKIP_BLANKS;
3735 if ((CUR == 's') && (NXT(1) == 't') &&
3736 (NXT(2) == 'a') && (NXT(3) == 'n') &&
3737 (NXT(4) == 'd') && (NXT(5) == 'a') &&
3738 (NXT(6) == 'l') && (NXT(7) == 'o') &&
3739 (NXT(8) == 'n') && (NXT(9) == 'e')) {
3740 SKIP(10);
3741 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003742 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003743 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003744 "XML standalone declaration : expected '='\n");
3745 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003746 return(standalone);
3747 }
3748 NEXT;
3749 SKIP_BLANKS;
3750 if (CUR == '\''){
3751 NEXT;
3752 if ((CUR == 'n') && (NXT(1) == 'o')) {
3753 standalone = 0;
3754 SKIP(2);
3755 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
3756 (NXT(2) == 's')) {
3757 standalone = 1;
3758 SKIP(3);
3759 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003760 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003761 ctxt->sax->error(ctxt->userData, "standalone accepts only 'yes' or 'no'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003762 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003763 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003764 if (CUR != '\'') {
3765 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003766 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003767 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003768 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003769 NEXT;
3770 } else if (CUR == '"'){
3771 NEXT;
3772 if ((CUR == 'n') && (NXT(1) == 'o')) {
3773 standalone = 0;
3774 SKIP(2);
3775 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
3776 (NXT(2) == 's')) {
3777 standalone = 1;
3778 SKIP(3);
3779 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003780 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003781 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003782 "standalone accepts only 'yes' or 'no'\n");
3783 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003784 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003785 if (CUR != '"') {
3786 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003787 ctxt->sax->error(ctxt->userData, "String not closed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003788 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003789 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003790 NEXT;
3791 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003792 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003793 ctxt->sax->error(ctxt->userData, "Standalone value not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003794 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003795 }
3796 }
3797 return(standalone);
3798}
3799
Daniel Veillard11e00581998-10-24 18:27:49 +00003800/**
3801 * xmlParseXMLDecl:
3802 * @ctxt: an XML parser context
3803 *
3804 * parse an XML declaration header
Daniel Veillard260a68f1998-08-13 03:39:55 +00003805 *
3806 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
3807 */
3808
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003809void
3810xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003811 CHAR *version;
3812
3813 /*
3814 * We know that '<?xml' is here.
3815 */
3816 SKIP(5);
3817
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003818 if (!IS_BLANK(CUR)) {
3819 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003820 ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003821 ctxt->wellFormed = 0;
3822 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003823 SKIP_BLANKS;
3824
3825 /*
3826 * We should have the VersionInfo here.
3827 */
3828 version = xmlParseVersionInfo(ctxt);
3829 if (version == NULL)
3830 version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard517752b1999-04-05 12:20:10 +00003831 ctxt->version = xmlStrdup(version);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003832 free(version);
3833
3834 /*
3835 * We may have the encoding declaration
3836 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003837 if (!IS_BLANK(CUR)) {
3838 if ((CUR == '?') && (NXT(1) == '>')) {
3839 SKIP(2);
3840 return;
3841 }
3842 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003843 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003844 ctxt->wellFormed = 0;
3845 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003846 ctxt->encoding = xmlParseEncodingDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003847
3848 /*
3849 * We may have the standalone status.
3850 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003851 if ((ctxt->encoding != NULL) && (!IS_BLANK(CUR))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003852 if ((CUR == '?') && (NXT(1) == '>')) {
3853 SKIP(2);
3854 return;
3855 }
3856 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003857 ctxt->sax->error(ctxt->userData, "Blank needed here\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003858 ctxt->wellFormed = 0;
3859 }
3860 SKIP_BLANKS;
Daniel Veillard517752b1999-04-05 12:20:10 +00003861 ctxt->standalone = xmlParseSDDecl(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003862
3863 SKIP_BLANKS;
3864 if ((CUR == '?') && (NXT(1) == '>')) {
3865 SKIP(2);
3866 } else if (CUR == '>') {
3867 /* Deprecated old WD ... */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003868 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003869 ctxt->sax->error(ctxt->userData, "XML declaration must end-up with '?>'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003870 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003871 NEXT;
3872 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003873 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003874 ctxt->sax->error(ctxt->userData, "parsing XML declaration: '?>' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003875 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003876 MOVETO_ENDTAG(CUR_PTR);
3877 NEXT;
3878 }
3879}
3880
Daniel Veillard11e00581998-10-24 18:27:49 +00003881/**
3882 * xmlParseMisc:
3883 * @ctxt: an XML parser context
3884 *
3885 * parse an XML Misc* optionnal field.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003886 *
3887 * [27] Misc ::= Comment | PI | S
3888 */
3889
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003890void
3891xmlParseMisc(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003892 while (((CUR == '<') && (NXT(1) == '?')) ||
3893 ((CUR == '<') && (NXT(1) == '!') &&
3894 (NXT(2) == '-') && (NXT(3) == '-')) ||
3895 IS_BLANK(CUR)) {
3896 if ((CUR == '<') && (NXT(1) == '?')) {
3897 xmlParsePI(ctxt);
3898 } else if (IS_BLANK(CUR)) {
3899 NEXT;
3900 } else
3901 xmlParseComment(ctxt, 0);
3902 }
3903}
3904
Daniel Veillard11e00581998-10-24 18:27:49 +00003905/**
3906 * xmlParseDocument :
3907 * @ctxt: an XML parser context
3908 *
3909 * parse an XML document (and build a tree if using the standard SAX
3910 * interface).
Daniel Veillard260a68f1998-08-13 03:39:55 +00003911 *
3912 * [1] document ::= prolog element Misc*
3913 *
3914 * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
Daniel Veillard11e00581998-10-24 18:27:49 +00003915 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00003916 * Returns 0, -1 in case of error. the parser context is augmented
Daniel Veillard11e00581998-10-24 18:27:49 +00003917 * as a result of the parsing.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003918 */
3919
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003920int
3921xmlParseDocument(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003922 xmlDefaultSAXHandlerInit();
3923
3924 /*
3925 * SAX: beginning of the document processing.
3926 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003927 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
Daniel Veillard27d88741999-05-29 11:51:49 +00003928 ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003929
3930 /*
3931 * We should check for encoding here and plug-in some
3932 * conversion code TODO !!!!
3933 */
3934
3935 /*
3936 * Wipe out everything which is before the first '<'
3937 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003938 if (IS_BLANK(CUR)) {
3939 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003940 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003941 "Extra spaces at the beginning of the document are not allowed\n");
3942 ctxt->wellFormed = 0;
3943 SKIP_BLANKS;
3944 }
3945
3946 if (CUR == 0) {
3947 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00003948 ctxt->sax->error(ctxt->userData, "Document is empty\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003949 ctxt->wellFormed = 0;
3950 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003951
3952 /*
3953 * Check for the XMLDecl in the Prolog.
3954 */
3955 if ((CUR == '<') && (NXT(1) == '?') &&
3956 (NXT(2) == 'x') && (NXT(3) == 'm') &&
3957 (NXT(4) == 'l')) {
3958 xmlParseXMLDecl(ctxt);
3959 /* SKIP_EOL(cur); */
3960 SKIP_BLANKS;
3961 } else if ((CUR == '<') && (NXT(1) == '?') &&
3962 (NXT(2) == 'X') && (NXT(3) == 'M') &&
3963 (NXT(4) == 'L')) {
3964 /*
3965 * The first drafts were using <?XML and the final W3C REC
3966 * now use <?xml ...
3967 */
3968 xmlParseXMLDecl(ctxt);
3969 /* SKIP_EOL(cur); */
3970 SKIP_BLANKS;
3971 } else {
Daniel Veillard517752b1999-04-05 12:20:10 +00003972 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003973 }
Daniel Veillard517752b1999-04-05 12:20:10 +00003974 if ((ctxt->sax) && (ctxt->sax->startDocument))
Daniel Veillard27d88741999-05-29 11:51:49 +00003975 ctxt->sax->startDocument(ctxt->userData);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003976
3977 /*
3978 * The Misc part of the Prolog
3979 */
3980 xmlParseMisc(ctxt);
3981
3982 /*
3983 * Then possibly doc type declaration(s) and more Misc
3984 * (doctypedecl Misc*)?
3985 */
3986 if ((CUR == '<') && (NXT(1) == '!') &&
3987 (NXT(2) == 'D') && (NXT(3) == 'O') &&
3988 (NXT(4) == 'C') && (NXT(5) == 'T') &&
3989 (NXT(6) == 'Y') && (NXT(7) == 'P') &&
3990 (NXT(8) == 'E')) {
3991 xmlParseDocTypeDecl(ctxt);
3992 xmlParseMisc(ctxt);
3993 }
3994
3995 /*
3996 * Time to start parsing the tree itself
3997 */
Daniel Veillard517752b1999-04-05 12:20:10 +00003998 xmlParseElement(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003999
4000 /*
4001 * The Misc part at the end
4002 */
4003 xmlParseMisc(ctxt);
4004
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004005 if (CUR != 0) {
4006 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004007 ctxt->sax->error(ctxt->userData,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004008 "Extra content at the end of the document\n");
4009 ctxt->wellFormed = 0;
4010 }
4011
Daniel Veillard260a68f1998-08-13 03:39:55 +00004012 /*
4013 * SAX: end of the document processing.
4014 */
Daniel Veillard517752b1999-04-05 12:20:10 +00004015 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004016 ctxt->sax->endDocument(ctxt->userData);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004017 if (! ctxt->wellFormed) return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004018 return(0);
4019}
4020
Daniel Veillard11e00581998-10-24 18:27:49 +00004021/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00004022 * xmlCreateFileParserCtxt :
4023 * @cur: a pointer to an array of CHAR
4024 *
4025 * Create a parser context for an XML in-memory document.
4026 *
4027 * Returns the new parser context or NULL
4028 */
4029xmlParserCtxtPtr
4030xmlCreateDocParserCtxt(CHAR *cur) {
4031 xmlParserCtxtPtr ctxt;
4032 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00004033 xmlCharEncoding enc;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004034
4035 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4036 if (ctxt == NULL) {
4037 perror("malloc");
4038 return(NULL);
4039 }
4040 xmlInitParserCtxt(ctxt);
4041 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4042 if (input == NULL) {
4043 perror("malloc");
4044 free(ctxt);
4045 return(NULL);
4046 }
4047
Daniel Veillard27d88741999-05-29 11:51:49 +00004048 /*
4049 * plug some encoding conversion routines here. !!!
4050 */
4051 enc = xmlDetectCharEncoding(cur);
4052 xmlSwitchEncoding(ctxt, enc);
4053
Daniel Veillardd692aa41999-02-28 21:54:31 +00004054 input->filename = NULL;
4055 input->line = 1;
4056 input->col = 1;
4057 input->base = cur;
4058 input->cur = cur;
4059 input->free = NULL;
4060
4061 inputPush(ctxt, input);
4062 return(ctxt);
4063}
4064
4065/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004066 * xmlSAXParseDoc :
4067 * @sax: the SAX handler block
Daniel Veillard11e00581998-10-24 18:27:49 +00004068 * @cur: a pointer to an array of CHAR
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004069 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4070 * documents
Daniel Veillard11e00581998-10-24 18:27:49 +00004071 *
4072 * parse an XML in-memory document and build a tree.
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004073 * It use the given SAX function block to handle the parsing callback.
4074 * If sax is NULL, fallback to the default DOM tree building routines.
Daniel Veillard11e00581998-10-24 18:27:49 +00004075 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004076 * Returns the resulting document tree
Daniel Veillard260a68f1998-08-13 03:39:55 +00004077 */
4078
Daniel Veillard1e346af1999-02-22 10:33:01 +00004079xmlDocPtr
4080xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur, int recovery) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004081 xmlDocPtr ret;
4082 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004083
4084 if (cur == NULL) return(NULL);
4085
Daniel Veillardd692aa41999-02-28 21:54:31 +00004086
4087 ctxt = xmlCreateDocParserCtxt(cur);
4088 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00004089 if (sax != NULL) {
4090 ctxt->sax = sax;
4091 ctxt->userData = NULL;
4092 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004093
4094 xmlParseDocument(ctxt);
Daniel Veillard517752b1999-04-05 12:20:10 +00004095 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004096 else {
4097 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00004098 xmlFreeDoc(ctxt->myDoc);
4099 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004100 }
Daniel Veillardd692aa41999-02-28 21:54:31 +00004101 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004102
4103 return(ret);
4104}
4105
Daniel Veillard11e00581998-10-24 18:27:49 +00004106/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004107 * xmlParseDoc :
4108 * @cur: a pointer to an array of CHAR
4109 *
4110 * parse an XML in-memory document and build a tree.
4111 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004112 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004113 */
4114
Daniel Veillard1e346af1999-02-22 10:33:01 +00004115xmlDocPtr
4116xmlParseDoc(CHAR *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004117 return(xmlSAXParseDoc(NULL, cur, 0));
4118}
4119
4120/**
4121 * xmlRecoverDoc :
4122 * @cur: a pointer to an array of CHAR
4123 *
4124 * parse an XML in-memory document and build a tree.
4125 * In the case the document is not Well Formed, a tree is built anyway
4126 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004127 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004128 */
4129
Daniel Veillard1e346af1999-02-22 10:33:01 +00004130xmlDocPtr
4131xmlRecoverDoc(CHAR *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004132 return(xmlSAXParseDoc(NULL, cur, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004133}
4134
4135/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00004136 * xmlCreateFileParserCtxt :
Daniel Veillard11e00581998-10-24 18:27:49 +00004137 * @filename: the filename
4138 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004139 * Create a parser context for a file content.
4140 * Automatic support for ZLIB/Compress compressed document is provided
4141 * by default if found at compile-time.
Daniel Veillard11e00581998-10-24 18:27:49 +00004142 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004143 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00004144 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00004145xmlParserCtxtPtr
4146xmlCreateFileParserCtxt(const char *filename)
4147{
4148 xmlParserCtxtPtr ctxt;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004149#ifdef HAVE_ZLIB_H
4150 gzFile input;
4151#else
4152 int input;
4153#endif
4154 int res;
Daniel Veillard27271681998-10-30 06:39:40 +00004155 int len;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004156 struct stat buf;
4157 char *buffer;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004158 xmlParserInputPtr inputStream;
Daniel Veillard27d88741999-05-29 11:51:49 +00004159 xmlCharEncoding enc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004160
4161 res = stat(filename, &buf);
4162 if (res < 0) return(NULL);
4163
4164#ifdef HAVE_ZLIB_H
Daniel Veillard27271681998-10-30 06:39:40 +00004165 len = (buf.st_size * 8) + 1000;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004166retry_bigger:
Daniel Veillard27271681998-10-30 06:39:40 +00004167 buffer = malloc(len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004168#else
Daniel Veillard27271681998-10-30 06:39:40 +00004169 len = buf.st_size + 100;
4170 buffer = malloc(len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004171#endif
4172 if (buffer == NULL) {
4173 perror("malloc");
4174 return(NULL);
4175 }
4176
Daniel Veillard27271681998-10-30 06:39:40 +00004177 memset(buffer, 0, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004178#ifdef HAVE_ZLIB_H
4179 input = gzopen (filename, "r");
4180 if (input == NULL) {
4181 fprintf (stderr, "Cannot read file %s :\n", filename);
4182 perror ("gzopen failed");
4183 return(NULL);
4184 }
4185#else
Daniel Veillard64068b31999-03-24 20:42:16 +00004186#ifdef WIN32
4187 input = _open (filename, O_RDONLY | _O_BINARY);
4188#else
Daniel Veillard260a68f1998-08-13 03:39:55 +00004189 input = open (filename, O_RDONLY);
Daniel Veillard64068b31999-03-24 20:42:16 +00004190#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +00004191 if (input < 0) {
4192 fprintf (stderr, "Cannot read file %s :\n", filename);
4193 perror ("open failed");
4194 return(NULL);
4195 }
4196#endif
4197#ifdef HAVE_ZLIB_H
Daniel Veillard27271681998-10-30 06:39:40 +00004198 res = gzread(input, buffer, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004199#else
4200 res = read(input, buffer, buf.st_size);
4201#endif
4202 if (res < 0) {
4203 fprintf (stderr, "Cannot read file %s :\n", filename);
4204#ifdef HAVE_ZLIB_H
4205 perror ("gzread failed");
4206#else
4207 perror ("read failed");
4208#endif
4209 return(NULL);
4210 }
4211#ifdef HAVE_ZLIB_H
4212 gzclose(input);
Daniel Veillard27271681998-10-30 06:39:40 +00004213 if (res >= len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004214 free(buffer);
Daniel Veillard27271681998-10-30 06:39:40 +00004215 len *= 2;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004216 goto retry_bigger;
4217 }
4218 buf.st_size = res;
4219#else
4220 close(input);
4221#endif
4222
4223 buffer[buf.st_size] = '\0';
4224
4225 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4226 if (ctxt == NULL) {
4227 perror("malloc");
4228 return(NULL);
4229 }
4230 xmlInitParserCtxt(ctxt);
4231 inputStream = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4232 if (inputStream == NULL) {
4233 perror("malloc");
4234 free(ctxt);
4235 return(NULL);
4236 }
4237
4238 inputStream->filename = strdup(filename);
4239 inputStream->line = 1;
4240 inputStream->col = 1;
4241
4242 /*
Daniel Veillard27d88741999-05-29 11:51:49 +00004243 * plug some encoding conversion routines here. !!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00004244 */
Daniel Veillard27d88741999-05-29 11:51:49 +00004245 enc = xmlDetectCharEncoding(buffer);
4246 xmlSwitchEncoding(ctxt, enc);
4247
Daniel Veillard260a68f1998-08-13 03:39:55 +00004248 inputStream->base = buffer;
4249 inputStream->cur = buffer;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004250 inputStream->free = (xmlParserInputDeallocate) free;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004251
4252 inputPush(ctxt, inputStream);
Daniel Veillardd692aa41999-02-28 21:54:31 +00004253 return(ctxt);
4254}
4255
4256/**
4257 * xmlSAXParseFile :
4258 * @sax: the SAX handler block
4259 * @filename: the filename
4260 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4261 * documents
4262 *
4263 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4264 * compressed document is provided by default if found at compile-time.
4265 * It use the given SAX function block to handle the parsing callback.
4266 * If sax is NULL, fallback to the default DOM tree building routines.
4267 *
4268 * Returns the resulting document tree
4269 */
4270
4271xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
4272 int recovery) {
4273 xmlDocPtr ret;
4274 xmlParserCtxtPtr ctxt;
4275
4276 ctxt = xmlCreateFileParserCtxt(filename);
4277 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00004278 if (sax != NULL) {
4279 ctxt->sax = sax;
4280 ctxt->userData = NULL;
4281 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004282
4283 xmlParseDocument(ctxt);
4284
Daniel Veillard517752b1999-04-05 12:20:10 +00004285 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004286 else {
4287 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00004288 xmlFreeDoc(ctxt->myDoc);
4289 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004290 }
Daniel Veillardd692aa41999-02-28 21:54:31 +00004291 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004292
4293 return(ret);
4294}
4295
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004296/**
4297 * xmlParseFile :
4298 * @filename: the filename
4299 *
4300 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4301 * compressed document is provided by default if found at compile-time.
4302 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004303 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004304 */
4305
4306xmlDocPtr xmlParseFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004307 return(xmlSAXParseFile(NULL, filename, 0));
4308}
4309
4310/**
4311 * xmlRecoverFile :
4312 * @filename: the filename
4313 *
4314 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4315 * compressed document is provided by default if found at compile-time.
4316 * In the case the document is not Well Formed, a tree is built anyway
4317 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004318 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004319 */
4320
4321xmlDocPtr xmlRecoverFile(const char *filename) {
4322 return(xmlSAXParseFile(NULL, filename, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004323}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004324
Daniel Veillard11e00581998-10-24 18:27:49 +00004325/**
Daniel Veillardd692aa41999-02-28 21:54:31 +00004326 * xmlCreateMemoryParserCtxt :
Daniel Veillard1e346af1999-02-22 10:33:01 +00004327 * @buffer: an pointer to a char array
Daniel Veillard11e00581998-10-24 18:27:49 +00004328 * @size: the siwe of the array
4329 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004330 * Create a parser context for an XML in-memory document.
Daniel Veillard11e00581998-10-24 18:27:49 +00004331 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004332 * Returns the new parser context or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00004333 */
Daniel Veillardd692aa41999-02-28 21:54:31 +00004334xmlParserCtxtPtr
4335xmlCreateMemoryParserCtxt(char *buffer, int size) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004336 xmlParserCtxtPtr ctxt;
4337 xmlParserInputPtr input;
Daniel Veillard27d88741999-05-29 11:51:49 +00004338 xmlCharEncoding enc;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004339
4340 buffer[size - 1] = '\0';
4341
4342 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4343 if (ctxt == NULL) {
4344 perror("malloc");
4345 return(NULL);
4346 }
4347 xmlInitParserCtxt(ctxt);
4348 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4349 if (input == NULL) {
4350 perror("malloc");
Daniel Veillardccb09631998-10-27 06:21:04 +00004351 free(ctxt->nodeTab);
4352 free(ctxt->inputTab);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004353 free(ctxt);
4354 return(NULL);
4355 }
4356
4357 input->filename = NULL;
4358 input->line = 1;
4359 input->col = 1;
4360
4361 /*
Daniel Veillard27d88741999-05-29 11:51:49 +00004362 * plug some encoding conversion routines here. !!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00004363 */
Daniel Veillard27d88741999-05-29 11:51:49 +00004364 enc = xmlDetectCharEncoding(buffer);
4365 xmlSwitchEncoding(ctxt, enc);
4366
Daniel Veillard260a68f1998-08-13 03:39:55 +00004367 input->base = buffer;
4368 input->cur = buffer;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004369 input->free = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004370
4371 inputPush(ctxt, input);
Daniel Veillardd692aa41999-02-28 21:54:31 +00004372 return(ctxt);
4373}
4374
4375/**
4376 * xmlSAXParseMemory :
4377 * @sax: the SAX handler block
4378 * @buffer: an pointer to a char array
4379 * @size: the siwe of the array
4380 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4381 * documents
4382 *
4383 * parse an XML in-memory block and use the given SAX function block
4384 * to handle the parsing callback. If sax is NULL, fallback to the default
4385 * DOM tree building routines.
4386 *
Daniel Veillardd692aa41999-02-28 21:54:31 +00004387 * Returns the resulting document tree
4388 */
4389xmlDocPtr
4390xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
4391 xmlDocPtr ret;
4392 xmlParserCtxtPtr ctxt;
4393
4394 ctxt = xmlCreateMemoryParserCtxt(buffer, size);
4395 if (ctxt == NULL) return(NULL);
Daniel Veillard27d88741999-05-29 11:51:49 +00004396 if (sax != NULL) {
4397 ctxt->sax = sax;
4398 ctxt->userData = NULL;
4399 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004400
4401 xmlParseDocument(ctxt);
4402
Daniel Veillard517752b1999-04-05 12:20:10 +00004403 if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004404 else {
4405 ret = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00004406 xmlFreeDoc(ctxt->myDoc);
4407 ctxt->myDoc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004408 }
Daniel Veillardd692aa41999-02-28 21:54:31 +00004409 xmlFreeParserCtxt(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004410
4411 return(ret);
4412}
4413
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004414/**
4415 * xmlParseMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00004416 * @buffer: an pointer to a char array
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004417 * @size: the size of the array
4418 *
4419 * parse an XML in-memory block and build a tree.
4420 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004421 * Returns the resulting document tree
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004422 */
4423
4424xmlDocPtr xmlParseMemory(char *buffer, int size) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004425 return(xmlSAXParseMemory(NULL, buffer, size, 0));
4426}
4427
4428/**
4429 * xmlRecoverMemory :
Daniel Veillard1e346af1999-02-22 10:33:01 +00004430 * @buffer: an pointer to a char array
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004431 * @size: the size of the array
4432 *
4433 * parse an XML in-memory block and build a tree.
4434 * In the case the document is not Well Formed, a tree is built anyway
4435 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004436 * Returns the resulting document tree
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004437 */
4438
4439xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
4440 return(xmlSAXParseMemory(NULL, buffer, size, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004441}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004442
Daniel Veillard11e00581998-10-24 18:27:49 +00004443/**
4444 * xmlInitParserCtxt:
4445 * @ctxt: an XML parser context
4446 *
4447 * Initialize a parser context
4448 */
4449
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004450void
4451xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004452{
Daniel Veillardd692aa41999-02-28 21:54:31 +00004453 /* Allocate the Input stack */
4454 ctxt->inputTab = (xmlParserInputPtr *) malloc(5 * sizeof(xmlParserInputPtr));
4455 ctxt->inputNr = 0;
4456 ctxt->inputMax = 5;
4457 ctxt->input = NULL;
Daniel Veillard517752b1999-04-05 12:20:10 +00004458 ctxt->version = NULL;
4459 ctxt->encoding = NULL;
4460 ctxt->standalone = -1;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004461
Daniel Veillardd692aa41999-02-28 21:54:31 +00004462 /* Allocate the Node stack */
4463 ctxt->nodeTab = (xmlNodePtr *) malloc(10 * sizeof(xmlNodePtr));
4464 ctxt->nodeNr = 0;
4465 ctxt->nodeMax = 10;
4466 ctxt->node = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004467
Daniel Veillardd692aa41999-02-28 21:54:31 +00004468 ctxt->sax = &xmlDefaultSAXHandler;
Daniel Veillard27d88741999-05-29 11:51:49 +00004469 ctxt->userData = ctxt;
Daniel Veillard517752b1999-04-05 12:20:10 +00004470 ctxt->myDoc = NULL;
Daniel Veillardd692aa41999-02-28 21:54:31 +00004471 ctxt->wellFormed = 1;
4472 ctxt->record_info = 0;
4473 xmlInitNodeInfoSeq(&ctxt->node_seq);
4474}
4475
4476/**
4477 * xmlFreeParserCtxt:
4478 * @ctxt: an XML parser context
4479 *
4480 * Free all the memory used by a parser context. However the parsed
Daniel Veillard517752b1999-04-05 12:20:10 +00004481 * document in ctxt->myDoc is not freed.
Daniel Veillardd692aa41999-02-28 21:54:31 +00004482 */
4483
4484void
4485xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
4486{
4487 xmlParserInputPtr input;
4488
4489 if (ctxt == NULL) return;
4490
4491 while ((input = inputPop(ctxt)) != NULL) {
4492 xmlFreeInputStream(input);
4493 }
4494
4495 if (ctxt->nodeTab != NULL) free(ctxt->nodeTab);
4496 if (ctxt->inputTab != NULL) free(ctxt->inputTab);
Daniel Veillard5099ae81999-04-21 20:12:07 +00004497 if (ctxt->version != NULL) free((char *) ctxt->version);
Daniel Veillardd692aa41999-02-28 21:54:31 +00004498 free(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004499}
4500
Daniel Veillard11e00581998-10-24 18:27:49 +00004501/**
4502 * xmlClearParserCtxt:
4503 * @ctxt: an XML parser context
4504 *
4505 * Clear (release owned resources) and reinitialize a parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +00004506 */
Daniel Veillard11e00581998-10-24 18:27:49 +00004507
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004508void
4509xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004510{
4511 xmlClearNodeInfoSeq(&ctxt->node_seq);
4512 xmlInitParserCtxt(ctxt);
4513}
4514
4515
Daniel Veillard11e00581998-10-24 18:27:49 +00004516/**
4517 * xmlSetupParserForBuffer:
4518 * @ctxt: an XML parser context
4519 * @buffer: a CHAR * buffer
4520 * @filename: a file name
4521 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004522 * Setup the parser context to parse a new buffer; Clears any prior
4523 * contents from the parser context. The buffer parameter must not be
4524 * NULL, but the filename parameter can be
4525 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004526void
4527xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const CHAR* buffer,
Daniel Veillard260a68f1998-08-13 03:39:55 +00004528 const char* filename)
4529{
4530 xmlParserInputPtr input;
4531
4532 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4533 if (input == NULL) {
4534 perror("malloc");
4535 free(ctxt);
4536 exit(1);
4537 }
4538
4539 xmlClearParserCtxt(ctxt);
4540 if (input->filename != NULL)
4541 input->filename = strdup(filename);
4542 else
4543 input->filename = NULL;
4544 input->line = 1;
4545 input->col = 1;
4546 input->base = buffer;
4547 input->cur = buffer;
4548
4549 inputPush(ctxt, input);
4550}
4551
4552
Daniel Veillard11e00581998-10-24 18:27:49 +00004553/**
4554 * xmlParserFindNodeInfo:
4555 * @ctxt: an XML parser context
4556 * @node: an XML node within the tree
4557 *
4558 * Find the parser node info struct for a given node
4559 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004560 * Returns an xmlParserNodeInfo block pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00004561 */
4562const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
4563 const xmlNode* node)
4564{
4565 unsigned long pos;
4566
4567 /* Find position where node should be at */
4568 pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
4569 if ( ctx->node_seq.buffer[pos].node == node )
4570 return &ctx->node_seq.buffer[pos];
4571 else
4572 return NULL;
4573}
4574
4575
Daniel Veillard11e00581998-10-24 18:27:49 +00004576/**
4577 * xmlInitNodeInfoSeq :
4578 * @seq: a node info sequence pointer
4579 *
4580 * -- Initialize (set to initial state) node info sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00004581 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004582void
4583xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004584{
4585 seq->length = 0;
4586 seq->maximum = 0;
4587 seq->buffer = NULL;
4588}
4589
Daniel Veillard11e00581998-10-24 18:27:49 +00004590/**
4591 * xmlClearNodeInfoSeq :
4592 * @seq: a node info sequence pointer
4593 *
4594 * -- Clear (release memory and reinitialize) node
Daniel Veillard260a68f1998-08-13 03:39:55 +00004595 * info sequence
4596 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004597void
4598xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004599{
4600 if ( seq->buffer != NULL )
4601 free(seq->buffer);
4602 xmlInitNodeInfoSeq(seq);
4603}
4604
4605
Daniel Veillard11e00581998-10-24 18:27:49 +00004606/**
4607 * xmlParserFindNodeInfoIndex:
4608 * @seq: a node info sequence pointer
4609 * @node: an XML node pointer
4610 *
4611 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004612 * xmlParserFindNodeInfoIndex : Find the index that the info record for
4613 * the given node is or should be at in a sorted sequence
Daniel Veillard1164e751999-02-16 16:29:17 +00004614 *
Daniel Veillard1e346af1999-02-22 10:33:01 +00004615 * Returns a long indicating the position of the record
Daniel Veillard260a68f1998-08-13 03:39:55 +00004616 */
4617unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
4618 const xmlNode* node)
4619{
4620 unsigned long upper, lower, middle;
4621 int found = 0;
4622
4623 /* Do a binary search for the key */
4624 lower = 1;
4625 upper = seq->length;
4626 middle = 0;
4627 while ( lower <= upper && !found) {
4628 middle = lower + (upper - lower) / 2;
4629 if ( node == seq->buffer[middle - 1].node )
4630 found = 1;
4631 else if ( node < seq->buffer[middle - 1].node )
4632 upper = middle - 1;
4633 else
4634 lower = middle + 1;
4635 }
4636
4637 /* Return position */
4638 if ( middle == 0 || seq->buffer[middle - 1].node < node )
4639 return middle;
4640 else
4641 return middle - 1;
4642}
4643
4644
Daniel Veillard11e00581998-10-24 18:27:49 +00004645/**
4646 * xmlParserAddNodeInfo:
4647 * @ctxt: an XML parser context
Daniel Veillard1e346af1999-02-22 10:33:01 +00004648 * @info: a node info sequence pointer
Daniel Veillard11e00581998-10-24 18:27:49 +00004649 *
4650 * Insert node info record into the sorted sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00004651 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004652void
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004653xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
Daniel Veillard1e346af1999-02-22 10:33:01 +00004654 const xmlParserNodeInfo* info)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004655{
4656 unsigned long pos;
4657 static unsigned int block_size = 5;
4658
4659 /* Find pos and check to see if node is already in the sequence */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004660 pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
4661 if ( pos < ctxt->node_seq.length
4662 && ctxt->node_seq.buffer[pos].node == info->node ) {
4663 ctxt->node_seq.buffer[pos] = *info;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004664 }
4665
4666 /* Otherwise, we need to add new node to buffer */
4667 else {
4668 /* Expand buffer by 5 if needed */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004669 if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004670 xmlParserNodeInfo* tmp_buffer;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004671 unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
4672 *(ctxt->node_seq.maximum + block_size));
Daniel Veillard260a68f1998-08-13 03:39:55 +00004673
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004674 if ( ctxt->node_seq.buffer == NULL )
Daniel Veillard260a68f1998-08-13 03:39:55 +00004675 tmp_buffer = (xmlParserNodeInfo*)malloc(byte_size);
4676 else
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004677 tmp_buffer = (xmlParserNodeInfo*)realloc(ctxt->node_seq.buffer, byte_size);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004678
4679 if ( tmp_buffer == NULL ) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004680 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard27d88741999-05-29 11:51:49 +00004681 ctxt->sax->error(ctxt->userData, "Out of memory\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004682 return;
4683 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004684 ctxt->node_seq.buffer = tmp_buffer;
4685 ctxt->node_seq.maximum += block_size;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004686 }
4687
4688 /* If position is not at end, move elements out of the way */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004689 if ( pos != ctxt->node_seq.length ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004690 unsigned long i;
4691
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004692 for ( i = ctxt->node_seq.length; i > pos; i-- )
4693 ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
Daniel Veillard260a68f1998-08-13 03:39:55 +00004694 }
4695
4696 /* Copy element and increase length */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004697 ctxt->node_seq.buffer[pos] = *info;
4698 ctxt->node_seq.length++;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004699 }
4700}