blob: 671bf73d9baeb0230fa7673558db32b70bfa95e6 [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 Veillard39a1f9a1999-01-17 19:11:59 +000033#include "valid.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000034
35/************************************************************************
36 * *
37 * Parser stacks related functions and macros *
38 * *
39 ************************************************************************/
40/*
41 * Generic function for accessing stacks in the Parser Context
42 */
43
44#define PUSH_AND_POP(type, name) \
45int name##Push(xmlParserCtxtPtr ctxt, type value) { \
46 if (ctxt->name##Nr >= ctxt->name##Max) { \
47 ctxt->name##Max *= 2; \
48 ctxt->name##Tab = (void *) realloc(ctxt->name##Tab, \
49 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
50 if (ctxt->name##Tab == NULL) { \
51 fprintf(stderr, "realloc failed !\n"); \
52 exit(1); \
53 } \
54 } \
55 ctxt->name##Tab[ctxt->name##Nr] = value; \
56 ctxt->name = value; \
57 return(ctxt->name##Nr++); \
58} \
59type name##Pop(xmlParserCtxtPtr ctxt) { \
60 if (ctxt->name##Nr <= 0) return(0); \
61 ctxt->name##Nr--; \
Daniel Veillardccb09631998-10-27 06:21:04 +000062 if (ctxt->name##Nr > 0) \
63 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
64 else \
65 ctxt->name = NULL; \
Daniel Veillard260a68f1998-08-13 03:39:55 +000066 return(ctxt->name); \
67} \
68
69PUSH_AND_POP(xmlParserInputPtr, input)
70PUSH_AND_POP(xmlNodePtr, node)
71
Daniel Veillard0ba4d531998-11-01 19:34:31 +000072/*
73 * Macros for accessing the content. Those should be used only by the parser,
74 * and not exported.
75 *
76 * Dirty macros, i.e. one need to make assumption on the context to use them
77 *
78 * CUR_PTR return the current pointer to the CHAR to be parsed.
79 * CUR returns the current CHAR value, i.e. a 8 bit value if compiled
80 * in ISO-Latin or UTF-8, and the current 16 bit value if compiled
81 * in UNICODE mode. This should be used internally by the parser
82 * only to compare to ASCII values otherwise it would break when
83 * running with UTF-8 encoding.
84 * NXT(n) returns the n'th next CHAR. Same as CUR is should be used only
85 * to compare on ASCII based substring.
86 * SKIP(n) Skip n CHAR, and must also be used only to skip ASCII defined
87 * strings within the parser.
88 *
89 * Clean macros, not dependent of an ASCII context.
90 *
91 * CURRENT Returns the current char value, with the full decoding of
92 * UTF-8 if we are using this mode. It returns an int.
93 * NEXT Skip to the next character, this does the proper decoding
94 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
95 * It returns the pointer to the current CHAR.
96 */
Daniel Veillard260a68f1998-08-13 03:39:55 +000097
98#define CUR (*ctxt->input->cur)
Daniel Veillard0ba4d531998-11-01 19:34:31 +000099#define SKIP(val) ctxt->input->cur += (val)
100#define NXT(val) ctxt->input->cur[(val)]
101#define CUR_PTR ctxt->input->cur
102
103#define SKIP_BLANKS \
104 while (IS_BLANK(*(ctxt->input->cur))) NEXT
105
106#ifndef USE_UTF_8
107#define CURRENT (*ctxt->input->cur)
Daniel Veillard260a68f1998-08-13 03:39:55 +0000108#define NEXT ((*ctxt->input->cur) ? \
109 (((*(ctxt->input->cur) == '\n') ? \
110 (ctxt->input->line++, ctxt->input->col = 1) : \
111 (ctxt->input->col++)), ctxt->input->cur++) : \
112 (xmlPopInput(ctxt), ctxt->input->cur))
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000113#else
114#endif
Daniel Veillard260a68f1998-08-13 03:39:55 +0000115
116
Daniel Veillard11e00581998-10-24 18:27:49 +0000117/**
118 * xmlPopInput:
119 * @ctxt: an XML parser context
120 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000121 * xmlPopInput: the current input pointed by ctxt->input came to an end
122 * pop it and return the next char.
123 *
124 * TODO A deallocation of the popped Input structure is needed
Daniel Veillard11e00581998-10-24 18:27:49 +0000125 * return values: the current CHAR in the parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +0000126 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000127CHAR
128xmlPopInput(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000129 if (ctxt->inputNr == 1) return(0); /* End of main Input */
130 inputPop(ctxt);
131 return(CUR);
132}
133
Daniel Veillard11e00581998-10-24 18:27:49 +0000134/**
135 * xmlPushInput:
136 * @ctxt: an XML parser context
137 * @input: an XML parser input fragment (entity, XML fragment ...).
138 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000139 * xmlPushInput: switch to a new input stream which is stacked on top
140 * of the previous one(s).
141 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000142void
143xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000144 if (input == NULL) return;
145 inputPush(ctxt, input);
146}
147
Daniel Veillard11e00581998-10-24 18:27:49 +0000148/**
149 * xmlNewEntityInputStream:
150 * @ctxt: an XML parser context
151 * @entity: an Entity pointer
152 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000153 * Create a new input stream based on a memory buffer.
Daniel Veillardccb09631998-10-27 06:21:04 +0000154 * return vakues: the new input stream
Daniel Veillard260a68f1998-08-13 03:39:55 +0000155 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000156xmlParserInputPtr
157xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000158 xmlParserInputPtr input;
159
160 if (entity == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000161 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
162 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000163 "internal: xmlNewEntityInputStream entity = NULL\n");
Daniel Veillardccb09631998-10-27 06:21:04 +0000164 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000165 }
166 if (entity->content == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000167 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
168 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000169 "internal: xmlNewEntityInputStream entity->input = NULL\n");
Daniel Veillardccb09631998-10-27 06:21:04 +0000170 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000171 }
172 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
173 if (input == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000174 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
175 ctxt->sax->error(ctxt, "malloc: couldn't allocate a new input stream\n");
Daniel Veillardccb09631998-10-27 06:21:04 +0000176 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000177 }
178 input->filename = entity->SystemID; /* TODO !!! char <- CHAR */
179 input->base = entity->content;
180 input->cur = entity->content;
181 input->line = 1;
182 input->col = 1;
Daniel Veillardccb09631998-10-27 06:21:04 +0000183 return(input);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000184}
185
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000186/**
187 * xmlNewStringInputStream:
188 * @ctxt: an XML parser context
189 * @entity: an Entity pointer
190 *
191 * Create a new input stream based on a memory buffer.
192 * return vakues: the new input stream
193 */
194xmlParserInputPtr
195xmlNewStringInputStream(xmlParserCtxtPtr ctxt, CHAR *string) {
196 xmlParserInputPtr input;
197
198 if (string == NULL) {
199 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
200 ctxt->sax->error(ctxt,
201 "internal: xmlNewStringInputStream string = NULL\n");
202 return(NULL);
203 }
204 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
205 if (input == NULL) {
206 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
207 ctxt->sax->error(ctxt, "malloc: couldn't allocate a new input stream\n");
208 return(NULL);
209 }
210 input->filename = NULL;
211 input->base = string;
212 input->cur = string;
213 input->line = 1;
214 input->col = 1;
215 return(input);
216}
217
Daniel Veillard260a68f1998-08-13 03:39:55 +0000218/*
219 * A few macros needed to help building the parser.
220 */
221
222#ifdef UNICODE
223/************************************************************************
224 * *
225 * UNICODE version of the macros. *
226 * *
227 ************************************************************************/
228/*
229 * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
230 * | [#x10000-#x10FFFF]
231 * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
232 */
233#define IS_CHAR(c) \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000234 ((((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
235 (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF))) && \
236 (((c) <= 0xD7FF) || ((c) >= 0xE000)) && ((c) >= 0) && \
237 ((c) <= 0x10FFFF))
Daniel Veillard260a68f1998-08-13 03:39:55 +0000238
239/*
240 * [3] S ::= (#x20 | #x9 | #xD | #xA)+
241 */
242#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xa) || \
243 ((c) == 0x0D))
244
245/*
246 * [85] BaseChar ::= ... long list see REC ...
247 *
248 * VI is your friend !
249 * :1,$ s/\[#x\([0-9A-Z]*\)-#x\([0-9A-Z]*\)\]/ (((c) >= 0x\1) \&\& ((c) <= 0x\2)) ||/
250 * and
251 * :1,$ s/#x\([0-9A-Z]*\)/ ((c) == 0x\1) ||/
252 */
253#define IS_BASECHAR(c) \
254 ((((c) >= 0x0041) && ((c) <= 0x005A)) || \
255 (((c) >= 0x0061) && ((c) <= 0x007A)) || \
256 (((c) >= 0x00C0) && ((c) <= 0x00D6)) || \
257 (((c) >= 0x00D8) && ((c) <= 0x00F6)) || \
258 (((c) >= 0x00F8) && ((c) <= 0x00FF)) || \
259 (((c) >= 0x0100) && ((c) <= 0x0131)) || \
260 (((c) >= 0x0134) && ((c) <= 0x013E)) || \
261 (((c) >= 0x0141) && ((c) <= 0x0148)) || \
262 (((c) >= 0x014A) && ((c) <= 0x017E)) || \
263 (((c) >= 0x0180) && ((c) <= 0x01C3)) || \
264 (((c) >= 0x01CD) && ((c) <= 0x01F0)) || \
265 (((c) >= 0x01F4) && ((c) <= 0x01F5)) || \
266 (((c) >= 0x01FA) && ((c) <= 0x0217)) || \
267 (((c) >= 0x0250) && ((c) <= 0x02A8)) || \
268 (((c) >= 0x02BB) && ((c) <= 0x02C1)) || \
269 ((c) == 0x0386) || \
270 (((c) >= 0x0388) && ((c) <= 0x038A)) || \
271 ((c) == 0x038C) || \
272 (((c) >= 0x038E) && ((c) <= 0x03A1)) || \
273 (((c) >= 0x03A3) && ((c) <= 0x03CE)) || \
274 (((c) >= 0x03D0) && ((c) <= 0x03D6)) || \
275 ((c) == 0x03DA) || \
276 ((c) == 0x03DC) || \
277 ((c) == 0x03DE) || \
278 ((c) == 0x03E0) || \
279 (((c) >= 0x03E2) && ((c) <= 0x03F3)) || \
280 (((c) >= 0x0401) && ((c) <= 0x040C)) || \
281 (((c) >= 0x040E) && ((c) <= 0x044F)) || \
282 (((c) >= 0x0451) && ((c) <= 0x045C)) || \
283 (((c) >= 0x045E) && ((c) <= 0x0481)) || \
284 (((c) >= 0x0490) && ((c) <= 0x04C4)) || \
285 (((c) >= 0x04C7) && ((c) <= 0x04C8)) || \
286 (((c) >= 0x04CB) && ((c) <= 0x04CC)) || \
287 (((c) >= 0x04D0) && ((c) <= 0x04EB)) || \
288 (((c) >= 0x04EE) && ((c) <= 0x04F5)) || \
289 (((c) >= 0x04F8) && ((c) <= 0x04F9)) || \
290 (((c) >= 0x0531) && ((c) <= 0x0556)) || \
291 ((c) == 0x0559) || \
292 (((c) >= 0x0561) && ((c) <= 0x0586)) || \
293 (((c) >= 0x05D0) && ((c) <= 0x05EA)) || \
294 (((c) >= 0x05F0) && ((c) <= 0x05F2)) || \
295 (((c) >= 0x0621) && ((c) <= 0x063A)) || \
296 (((c) >= 0x0641) && ((c) <= 0x064A)) || \
297 (((c) >= 0x0671) && ((c) <= 0x06B7)) || \
298 (((c) >= 0x06BA) && ((c) <= 0x06BE)) || \
299 (((c) >= 0x06C0) && ((c) <= 0x06CE)) || \
300 (((c) >= 0x06D0) && ((c) <= 0x06D3)) || \
301 ((c) == 0x06D5) || \
302 (((c) >= 0x06E5) && ((c) <= 0x06E6)) || \
303 (((c) >= 0x0905) && ((c) <= 0x0939)) || \
304 ((c) == 0x093D) || \
305 (((c) >= 0x0958) && ((c) <= 0x0961)) || \
306 (((c) >= 0x0985) && ((c) <= 0x098C)) || \
307 (((c) >= 0x098F) && ((c) <= 0x0990)) || \
308 (((c) >= 0x0993) && ((c) <= 0x09A8)) || \
309 (((c) >= 0x09AA) && ((c) <= 0x09B0)) || \
310 ((c) == 0x09B2) || \
311 (((c) >= 0x09B6) && ((c) <= 0x09B9)) || \
312 (((c) >= 0x09DC) && ((c) <= 0x09DD)) || \
313 (((c) >= 0x09DF) && ((c) <= 0x09E1)) || \
314 (((c) >= 0x09F0) && ((c) <= 0x09F1)) || \
315 (((c) >= 0x0A05) && ((c) <= 0x0A0A)) || \
316 (((c) >= 0x0A0F) && ((c) <= 0x0A10)) || \
317 (((c) >= 0x0A13) && ((c) <= 0x0A28)) || \
318 (((c) >= 0x0A2A) && ((c) <= 0x0A30)) || \
319 (((c) >= 0x0A32) && ((c) <= 0x0A33)) || \
320 (((c) >= 0x0A35) && ((c) <= 0x0A36)) || \
321 (((c) >= 0x0A38) && ((c) <= 0x0A39)) || \
322 (((c) >= 0x0A59) && ((c) <= 0x0A5C)) || \
323 ((c) == 0x0A5E) || \
324 (((c) >= 0x0A72) && ((c) <= 0x0A74)) || \
325 (((c) >= 0x0A85) && ((c) <= 0x0A8B)) || \
326 ((c) == 0x0A8D) || \
327 (((c) >= 0x0A8F) && ((c) <= 0x0A91)) || \
328 (((c) >= 0x0A93) && ((c) <= 0x0AA8)) || \
329 (((c) >= 0x0AAA) && ((c) <= 0x0AB0)) || \
330 (((c) >= 0x0AB2) && ((c) <= 0x0AB3)) || \
331 (((c) >= 0x0AB5) && ((c) <= 0x0AB9)) || \
332 ((c) == 0x0ABD) || \
333 ((c) == 0x0AE0) || \
334 (((c) >= 0x0B05) && ((c) <= 0x0B0C)) || \
335 (((c) >= 0x0B0F) && ((c) <= 0x0B10)) || \
336 (((c) >= 0x0B13) && ((c) <= 0x0B28)) || \
337 (((c) >= 0x0B2A) && ((c) <= 0x0B30)) || \
338 (((c) >= 0x0B32) && ((c) <= 0x0B33)) || \
339 (((c) >= 0x0B36) && ((c) <= 0x0B39)) || \
340 ((c) == 0x0B3D) || \
341 (((c) >= 0x0B5C) && ((c) <= 0x0B5D)) || \
342 (((c) >= 0x0B5F) && ((c) <= 0x0B61)) || \
343 (((c) >= 0x0B85) && ((c) <= 0x0B8A)) || \
344 (((c) >= 0x0B8E) && ((c) <= 0x0B90)) || \
345 (((c) >= 0x0B92) && ((c) <= 0x0B95)) || \
346 (((c) >= 0x0B99) && ((c) <= 0x0B9A)) || \
347 ((c) == 0x0B9C) || \
348 (((c) >= 0x0B9E) && ((c) <= 0x0B9F)) || \
349 (((c) >= 0x0BA3) && ((c) <= 0x0BA4)) || \
350 (((c) >= 0x0BA8) && ((c) <= 0x0BAA)) || \
351 (((c) >= 0x0BAE) && ((c) <= 0x0BB5)) || \
352 (((c) >= 0x0BB7) && ((c) <= 0x0BB9)) || \
353 (((c) >= 0x0C05) && ((c) <= 0x0C0C)) || \
354 (((c) >= 0x0C0E) && ((c) <= 0x0C10)) || \
355 (((c) >= 0x0C12) && ((c) <= 0x0C28)) || \
356 (((c) >= 0x0C2A) && ((c) <= 0x0C33)) || \
357 (((c) >= 0x0C35) && ((c) <= 0x0C39)) || \
358 (((c) >= 0x0C60) && ((c) <= 0x0C61)) || \
359 (((c) >= 0x0C85) && ((c) <= 0x0C8C)) || \
360 (((c) >= 0x0C8E) && ((c) <= 0x0C90)) || \
361 (((c) >= 0x0C92) && ((c) <= 0x0CA8)) || \
362 (((c) >= 0x0CAA) && ((c) <= 0x0CB3)) || \
363 (((c) >= 0x0CB5) && ((c) <= 0x0CB9)) || \
364 ((c) == 0x0CDE) || \
365 (((c) >= 0x0CE0) && ((c) <= 0x0CE1)) || \
366 (((c) >= 0x0D05) && ((c) <= 0x0D0C)) || \
367 (((c) >= 0x0D0E) && ((c) <= 0x0D10)) || \
368 (((c) >= 0x0D12) && ((c) <= 0x0D28)) || \
369 (((c) >= 0x0D2A) && ((c) <= 0x0D39)) || \
370 (((c) >= 0x0D60) && ((c) <= 0x0D61)) || \
371 (((c) >= 0x0E01) && ((c) <= 0x0E2E)) || \
372 ((c) == 0x0E30) || \
373 (((c) >= 0x0E32) && ((c) <= 0x0E33)) || \
374 (((c) >= 0x0E40) && ((c) <= 0x0E45)) || \
375 (((c) >= 0x0E81) && ((c) <= 0x0E82)) || \
376 ((c) == 0x0E84) || \
377 (((c) >= 0x0E87) && ((c) <= 0x0E88)) || \
378 ((c) == 0x0E8A) || \
379 ((c) == 0x0E8D) || \
380 (((c) >= 0x0E94) && ((c) <= 0x0E97)) || \
381 (((c) >= 0x0E99) && ((c) <= 0x0E9F)) || \
382 (((c) >= 0x0EA1) && ((c) <= 0x0EA3)) || \
383 ((c) == 0x0EA5) || \
384 ((c) == 0x0EA7) || \
385 (((c) >= 0x0EAA) && ((c) <= 0x0EAB)) || \
386 (((c) >= 0x0EAD) && ((c) <= 0x0EAE)) || \
387 ((c) == 0x0EB0) || \
388 (((c) >= 0x0EB2) && ((c) <= 0x0EB3)) || \
389 ((c) == 0x0EBD) || \
390 (((c) >= 0x0EC0) && ((c) <= 0x0EC4)) || \
391 (((c) >= 0x0F40) && ((c) <= 0x0F47)) || \
392 (((c) >= 0x0F49) && ((c) <= 0x0F69)) || \
393 (((c) >= 0x10A0) && ((c) <= 0x10C5)) || \
394 (((c) >= 0x10D0) && ((c) <= 0x10F6)) || \
395 ((c) == 0x1100) || \
396 (((c) >= 0x1102) && ((c) <= 0x1103)) || \
397 (((c) >= 0x1105) && ((c) <= 0x1107)) || \
398 ((c) == 0x1109) || \
399 (((c) >= 0x110B) && ((c) <= 0x110C)) || \
400 (((c) >= 0x110E) && ((c) <= 0x1112)) || \
401 ((c) == 0x113C) || \
402 ((c) == 0x113E) || \
403 ((c) == 0x1140) || \
404 ((c) == 0x114C) || \
405 ((c) == 0x114E) || \
406 ((c) == 0x1150) || \
407 (((c) >= 0x1154) && ((c) <= 0x1155)) || \
408 ((c) == 0x1159) || \
409 (((c) >= 0x115F) && ((c) <= 0x1161)) || \
410 ((c) == 0x1163) || \
411 ((c) == 0x1165) || \
412 ((c) == 0x1167) || \
413 ((c) == 0x1169) || \
414 (((c) >= 0x116D) && ((c) <= 0x116E)) || \
415 (((c) >= 0x1172) && ((c) <= 0x1173)) || \
416 ((c) == 0x1175) || \
417 ((c) == 0x119E) || \
418 ((c) == 0x11A8) || \
419 ((c) == 0x11AB) || \
420 (((c) >= 0x11AE) && ((c) <= 0x11AF)) || \
421 (((c) >= 0x11B7) && ((c) <= 0x11B8)) || \
422 ((c) == 0x11BA) || \
423 (((c) >= 0x11BC) && ((c) <= 0x11C2)) || \
424 ((c) == 0x11EB) || \
425 ((c) == 0x11F0) || \
426 ((c) == 0x11F9) || \
427 (((c) >= 0x1E00) && ((c) <= 0x1E9B)) || \
428 (((c) >= 0x1EA0) && ((c) <= 0x1EF9)) || \
429 (((c) >= 0x1F00) && ((c) <= 0x1F15)) || \
430 (((c) >= 0x1F18) && ((c) <= 0x1F1D)) || \
431 (((c) >= 0x1F20) && ((c) <= 0x1F45)) || \
432 (((c) >= 0x1F48) && ((c) <= 0x1F4D)) || \
433 (((c) >= 0x1F50) && ((c) <= 0x1F57)) || \
434 ((c) == 0x1F59) || \
435 ((c) == 0x1F5B) || \
436 ((c) == 0x1F5D) || \
437 (((c) >= 0x1F5F) && ((c) <= 0x1F7D)) || \
438 (((c) >= 0x1F80) && ((c) <= 0x1FB4)) || \
439 (((c) >= 0x1FB6) && ((c) <= 0x1FBC)) || \
440 ((c) == 0x1FBE) || \
441 (((c) >= 0x1FC2) && ((c) <= 0x1FC4)) || \
442 (((c) >= 0x1FC6) && ((c) <= 0x1FCC)) || \
443 (((c) >= 0x1FD0) && ((c) <= 0x1FD3)) || \
444 (((c) >= 0x1FD6) && ((c) <= 0x1FDB)) || \
445 (((c) >= 0x1FE0) && ((c) <= 0x1FEC)) || \
446 (((c) >= 0x1FF2) && ((c) <= 0x1FF4)) || \
447 (((c) >= 0x1FF6) && ((c) <= 0x1FFC)) || \
448 ((c) == 0x2126) || \
449 (((c) >= 0x212A) && ((c) <= 0x212B)) || \
450 ((c) == 0x212E) || \
451 (((c) >= 0x2180) && ((c) <= 0x2182)) || \
452 (((c) >= 0x3041) && ((c) <= 0x3094)) || \
453 (((c) >= 0x30A1) && ((c) <= 0x30FA)) || \
454 (((c) >= 0x3105) && ((c) <= 0x312C)) || \
455 (((c) >= 0xAC00) && ((c) <= 0xD7A3)))
456
457/*
458 * [88] Digit ::= ... long list see REC ...
459 */
460#define IS_DIGIT(c) \
461 ((((c) >= 0x0030) && ((c) <= 0x0039)) || \
462 (((c) >= 0x0660) && ((c) <= 0x0669)) || \
463 (((c) >= 0x06F0) && ((c) <= 0x06F9)) || \
464 (((c) >= 0x0966) && ((c) <= 0x096F)) || \
465 (((c) >= 0x09E6) && ((c) <= 0x09EF)) || \
466 (((c) >= 0x0A66) && ((c) <= 0x0A6F)) || \
467 (((c) >= 0x0AE6) && ((c) <= 0x0AEF)) || \
468 (((c) >= 0x0B66) && ((c) <= 0x0B6F)) || \
469 (((c) >= 0x0BE7) && ((c) <= 0x0BEF)) || \
470 (((c) >= 0x0C66) && ((c) <= 0x0C6F)) || \
471 (((c) >= 0x0CE6) && ((c) <= 0x0CEF)) || \
472 (((c) >= 0x0D66) && ((c) <= 0x0D6F)) || \
473 (((c) >= 0x0E50) && ((c) <= 0x0E59)) || \
474 (((c) >= 0x0ED0) && ((c) <= 0x0ED9)) || \
475 (((c) >= 0x0F20) && ((c) <= 0x0F29)))
476
477/*
478 * [87] CombiningChar ::= ... long list see REC ...
479 */
480#define IS_COMBINING(c) \
481 ((((c) >= 0x0300) && ((c) <= 0x0345)) || \
482 (((c) >= 0x0360) && ((c) <= 0x0361)) || \
483 (((c) >= 0x0483) && ((c) <= 0x0486)) || \
484 (((c) >= 0x0591) && ((c) <= 0x05A1)) || \
485 (((c) >= 0x05A3) && ((c) <= 0x05B9)) || \
486 (((c) >= 0x05BB) && ((c) <= 0x05BD)) || \
487 ((c) == 0x05BF) || \
488 (((c) >= 0x05C1) && ((c) <= 0x05C2)) || \
489 ((c) == 0x05C4) || \
490 (((c) >= 0x064B) && ((c) <= 0x0652)) || \
491 ((c) == 0x0670) || \
492 (((c) >= 0x06D6) && ((c) <= 0x06DC)) || \
493 (((c) >= 0x06DD) && ((c) <= 0x06DF)) || \
494 (((c) >= 0x06E0) && ((c) <= 0x06E4)) || \
495 (((c) >= 0x06E7) && ((c) <= 0x06E8)) || \
496 (((c) >= 0x06EA) && ((c) <= 0x06ED)) || \
497 (((c) >= 0x0901) && ((c) <= 0x0903)) || \
498 ((c) == 0x093C) || \
499 (((c) >= 0x093E) && ((c) <= 0x094C)) || \
500 ((c) == 0x094D) || \
501 (((c) >= 0x0951) && ((c) <= 0x0954)) || \
502 (((c) >= 0x0962) && ((c) <= 0x0963)) || \
503 (((c) >= 0x0981) && ((c) <= 0x0983)) || \
504 ((c) == 0x09BC) || \
505 ((c) == 0x09BE) || \
506 ((c) == 0x09BF) || \
507 (((c) >= 0x09C0) && ((c) <= 0x09C4)) || \
508 (((c) >= 0x09C7) && ((c) <= 0x09C8)) || \
509 (((c) >= 0x09CB) && ((c) <= 0x09CD)) || \
510 ((c) == 0x09D7) || \
511 (((c) >= 0x09E2) && ((c) <= 0x09E3)) || \
512 ((c) == 0x0A02) || \
513 ((c) == 0x0A3C) || \
514 ((c) == 0x0A3E) || \
515 ((c) == 0x0A3F) || \
516 (((c) >= 0x0A40) && ((c) <= 0x0A42)) || \
517 (((c) >= 0x0A47) && ((c) <= 0x0A48)) || \
518 (((c) >= 0x0A4B) && ((c) <= 0x0A4D)) || \
519 (((c) >= 0x0A70) && ((c) <= 0x0A71)) || \
520 (((c) >= 0x0A81) && ((c) <= 0x0A83)) || \
521 ((c) == 0x0ABC) || \
522 (((c) >= 0x0ABE) && ((c) <= 0x0AC5)) || \
523 (((c) >= 0x0AC7) && ((c) <= 0x0AC9)) || \
524 (((c) >= 0x0ACB) && ((c) <= 0x0ACD)) || \
525 (((c) >= 0x0B01) && ((c) <= 0x0B03)) || \
526 ((c) == 0x0B3C) || \
527 (((c) >= 0x0B3E) && ((c) <= 0x0B43)) || \
528 (((c) >= 0x0B47) && ((c) <= 0x0B48)) || \
529 (((c) >= 0x0B4B) && ((c) <= 0x0B4D)) || \
530 (((c) >= 0x0B56) && ((c) <= 0x0B57)) || \
531 (((c) >= 0x0B82) && ((c) <= 0x0B83)) || \
532 (((c) >= 0x0BBE) && ((c) <= 0x0BC2)) || \
533 (((c) >= 0x0BC6) && ((c) <= 0x0BC8)) || \
534 (((c) >= 0x0BCA) && ((c) <= 0x0BCD)) || \
535 ((c) == 0x0BD7) || \
536 (((c) >= 0x0C01) && ((c) <= 0x0C03)) || \
537 (((c) >= 0x0C3E) && ((c) <= 0x0C44)) || \
538 (((c) >= 0x0C46) && ((c) <= 0x0C48)) || \
539 (((c) >= 0x0C4A) && ((c) <= 0x0C4D)) || \
540 (((c) >= 0x0C55) && ((c) <= 0x0C56)) || \
541 (((c) >= 0x0C82) && ((c) <= 0x0C83)) || \
542 (((c) >= 0x0CBE) && ((c) <= 0x0CC4)) || \
543 (((c) >= 0x0CC6) && ((c) <= 0x0CC8)) || \
544 (((c) >= 0x0CCA) && ((c) <= 0x0CCD)) || \
545 (((c) >= 0x0CD5) && ((c) <= 0x0CD6)) || \
546 (((c) >= 0x0D02) && ((c) <= 0x0D03)) || \
547 (((c) >= 0x0D3E) && ((c) <= 0x0D43)) || \
548 (((c) >= 0x0D46) && ((c) <= 0x0D48)) || \
549 (((c) >= 0x0D4A) && ((c) <= 0x0D4D)) || \
550 ((c) == 0x0D57) || \
551 ((c) == 0x0E31) || \
552 (((c) >= 0x0E34) && ((c) <= 0x0E3A)) || \
553 (((c) >= 0x0E47) && ((c) <= 0x0E4E)) || \
554 ((c) == 0x0EB1) || \
555 (((c) >= 0x0EB4) && ((c) <= 0x0EB9)) || \
556 (((c) >= 0x0EBB) && ((c) <= 0x0EBC)) || \
557 (((c) >= 0x0EC8) && ((c) <= 0x0ECD)) || \
558 (((c) >= 0x0F18) && ((c) <= 0x0F19)) || \
559 ((c) == 0x0F35) || \
560 ((c) == 0x0F37) || \
561 ((c) == 0x0F39) || \
562 ((c) == 0x0F3E) || \
563 ((c) == 0x0F3F) || \
564 (((c) >= 0x0F71) && ((c) <= 0x0F84)) || \
565 (((c) >= 0x0F86) && ((c) <= 0x0F8B)) || \
566 (((c) >= 0x0F90) && ((c) <= 0x0F95)) || \
567 ((c) == 0x0F97) || \
568 (((c) >= 0x0F99) && ((c) <= 0x0FAD)) || \
569 (((c) >= 0x0FB1) && ((c) <= 0x0FB7)) || \
570 ((c) == 0x0FB9) || \
571 (((c) >= 0x20D0) && ((c) <= 0x20DC)) || \
572 ((c) == 0x20E1) || \
573 (((c) >= 0x302A) && ((c) <= 0x302F)) || \
574 ((c) == 0x3099) || \
575 ((c) == 0x309A))
576
577/*
578 * [89] Extender ::= #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 |
579 * #x0E46 | #x0EC6 | #x3005 | [#x3031-#x3035] |
580 * [#x309D-#x309E] | [#x30FC-#x30FE]
581 */
582#define IS_EXTENDER(c) \
583 (((c) == 0xb7) || ((c) == 0x2d0) || ((c) == 0x2d1) || \
584 ((c) == 0x387) || ((c) == 0x640) || ((c) == 0xe46) || \
585 ((c) == 0xec6) || ((c) == 0x3005) \
586 (((c) >= 0x3031) && ((c) <= 0x3035)) || \
587 (((c) >= 0x309b) && ((c) <= 0x309e)) || \
588 (((c) >= 0x30fc) && ((c) <= 0x30fe)))
589
590/*
591 * [86] Ideographic ::= [#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029]
592 */
593#define IS_IDEOGRAPHIC(c) \
594 ((((c) >= 0x4e00) && ((c) <= 0x9fa5)) || \
595 (((c) >= 0xf900) && ((c) <= 0xfa2d)) || \
596 (((c) >= 0x3021) && ((c) <= 0x3029)) || \
597 ((c) == 0x3007))
598
599/*
600 * [84] Letter ::= BaseChar | Ideographic
601 */
602#define IS_LETTER(c) (IS_BASECHAR(c) || IS_IDEOGRAPHIC(c))
603
604#else
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000605#ifndef USE_UTF_8
Daniel Veillard260a68f1998-08-13 03:39:55 +0000606/************************************************************************
607 * *
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000608 * 8bits / ISO-Latin version of the macros. *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000609 * *
610 ************************************************************************/
611/*
612 * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
613 * | [#x10000-#x10FFFF]
614 * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
615 */
616#define IS_CHAR(c) \
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000617 ((((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
618 (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF))) && \
619 (((c) <= 0xD7FF) || ((c) >= 0xE000)) && ((c) <= 0x10FFFF))
Daniel Veillard260a68f1998-08-13 03:39:55 +0000620
621/*
622 * [85] BaseChar ::= ... long list see REC ...
623 */
624#define IS_BASECHAR(c) \
625 ((((c) >= 0x41) && ((c) <= 0x5a)) || \
626 (((c) >= 0x61) && ((c) <= 0x7a)) || \
627 (((c) >= 0xaa) && ((c) <= 0x5b)) || \
628 (((c) >= 0xc0) && ((c) <= 0xd6)) || \
629 (((c) >= 0xd8) && ((c) <= 0xf6)) || \
630 (((c) >= 0xf8) && ((c) <= 0xff)) || \
631 ((c) == 0xba))
632
633/*
634 * [88] Digit ::= ... long list see REC ...
635 */
636#define IS_DIGIT(c) (((c) >= 0x30) && ((c) <= 0x39))
637
638/*
639 * [84] Letter ::= BaseChar | Ideographic
640 */
641#define IS_LETTER(c) IS_BASECHAR(c)
642
643
644/*
645 * [87] CombiningChar ::= ... long list see REC ...
646 */
647#define IS_COMBINING(c) 0
648
649/*
650 * [89] Extender ::= #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 |
651 * #x0E46 | #x0EC6 | #x3005 | [#x3031-#x3035] |
652 * [#x309D-#x309E] | [#x30FC-#x30FE]
653 */
654#define IS_EXTENDER(c) ((c) == 0xb7)
655
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000656#else /* USE_UTF_8 */
657/************************************************************************
658 * *
659 * 8bits / UTF-8 version of the macros. *
660 * *
661 ************************************************************************/
662
663TODO !!!
664#endif /* USE_UTF_8 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000665#endif /* !UNICODE */
666
667/*
668 * Blank chars.
669 *
670 * [3] S ::= (#x20 | #x9 | #xD | #xA)+
671 */
672#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xa) || \
673 ((c) == 0x0D))
674
675/*
676 * [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
677 */
678#define IS_PUBIDCHAR(c) \
679 (((c) == 0x20) || ((c) == 0x0D) || ((c) == 0x0A) || \
680 (((c) >= 'a') && ((c) <= 'z')) || \
681 (((c) >= 'A') && ((c) <= 'Z')) || \
682 (((c) >= '0') && ((c) <= '9')) || \
683 ((c) == '-') || ((c) == '\'') || ((c) == '(') || ((c) == ')') || \
684 ((c) == '+') || ((c) == ',') || ((c) == '.') || ((c) == '/') || \
685 ((c) == ':') || ((c) == '=') || ((c) == '?') || ((c) == ';') || \
686 ((c) == '!') || ((c) == '*') || ((c) == '#') || ((c) == '@') || \
687 ((c) == '$') || ((c) == '_') || ((c) == '%'))
688
689#define SKIP_EOL(p) \
690 if (*(p) == 0x13) { p++ ; if (*(p) == 0x10) p++; } \
691 if (*(p) == 0x10) { p++ ; if (*(p) == 0x13) p++; }
692
693#define MOVETO_ENDTAG(p) \
694 while (IS_CHAR(*p) && (*(p) != '>')) (p)++
695
696#define MOVETO_STARTTAG(p) \
697 while (IS_CHAR(*p) && (*(p) != '<')) (p)++
698
699/************************************************************************
700 * *
701 * Commodity functions to handle CHARs *
702 * *
703 ************************************************************************/
704
Daniel Veillard11e00581998-10-24 18:27:49 +0000705/**
706 * xmlStrndup:
707 * @cur: the input CHAR *
708 * @len: the len of @cur
709 *
710 * a strndup for array of CHAR's
711 * return values: a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000712 */
713
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000714CHAR *
715xmlStrndup(const CHAR *cur, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000716 CHAR *ret = malloc((len + 1) * sizeof(CHAR));
717
718 if (ret == NULL) {
719 fprintf(stderr, "malloc of %d byte failed\n",
720 (len + 1) * sizeof(CHAR));
721 return(NULL);
722 }
723 memcpy(ret, cur, len * sizeof(CHAR));
724 ret[len] = 0;
725 return(ret);
726}
727
Daniel Veillard11e00581998-10-24 18:27:49 +0000728/**
729 * xmlStrdup:
730 * @cur: the input CHAR *
731 *
732 * a strdup for array of CHAR's
733 * return values: a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000734 */
735
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000736CHAR *
737xmlStrdup(const CHAR *cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000738 const CHAR *p = cur;
739
740 while (IS_CHAR(*p)) p++;
741 return(xmlStrndup(cur, p - cur));
742}
743
Daniel Veillard11e00581998-10-24 18:27:49 +0000744/**
745 * xmlCharStrndup:
746 * @cur: the input char *
747 * @len: the len of @cur
748 *
749 * a strndup for char's to CHAR's
750 * return values: a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000751 */
752
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000753CHAR *
754xmlCharStrndup(const char *cur, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000755 int i;
756 CHAR *ret = malloc((len + 1) * sizeof(CHAR));
757
758 if (ret == NULL) {
759 fprintf(stderr, "malloc of %d byte failed\n",
760 (len + 1) * sizeof(CHAR));
761 return(NULL);
762 }
763 for (i = 0;i < len;i++)
764 ret[i] = (CHAR) cur[i];
765 ret[len] = 0;
766 return(ret);
767}
768
Daniel Veillard11e00581998-10-24 18:27:49 +0000769/**
770 * xmlCharStrdup:
771 * @cur: the input char *
772 * @len: the len of @cur
773 *
774 * a strdup for char's to CHAR's
775 * return values: a new CHAR * or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +0000776 */
777
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000778CHAR *
779xmlCharStrdup(const char *cur) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000780 const char *p = cur;
781
782 while (*p != '\0') p++;
783 return(xmlCharStrndup(cur, p - cur));
784}
785
Daniel Veillard11e00581998-10-24 18:27:49 +0000786/**
787 * xmlStrcmp:
788 * @str1: the first CHAR *
789 * @str2: the second CHAR *
790 *
791 * a strcmp for CHAR's
792 * return values: the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +0000793 */
794
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000795int
796xmlStrcmp(const CHAR *str1, const CHAR *str2) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000797 register int tmp;
798
799 do {
800 tmp = *str1++ - *str2++;
801 if (tmp != 0) return(tmp);
802 } while ((*str1 != 0) && (*str2 != 0));
803 return (*str1 - *str2);
804}
805
Daniel Veillard11e00581998-10-24 18:27:49 +0000806/**
807 * xmlStrncmp:
808 * @str1: the first CHAR *
809 * @str2: the second CHAR *
810 * @len: the max comparison length
811 *
812 * a strncmp for CHAR's
813 * return values: the integer result of the comparison
Daniel Veillard260a68f1998-08-13 03:39:55 +0000814 */
815
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000816int
817xmlStrncmp(const CHAR *str1, const CHAR *str2, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000818 register int tmp;
819
820 if (len <= 0) return(0);
821 do {
822 tmp = *str1++ - *str2++;
823 if (tmp != 0) return(tmp);
824 len--;
825 if (len <= 0) return(0);
826 } while ((*str1 != 0) && (*str2 != 0));
827 return (*str1 - *str2);
828}
829
Daniel Veillard11e00581998-10-24 18:27:49 +0000830/**
831 * xmlStrchr:
832 * @str: the CHAR * array
833 * @val: the CHAR to search
834 *
835 * a strchr for CHAR's
836 * return values: the CHAR * for the first occurence or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000837 */
838
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000839CHAR *
840xmlStrchr(const CHAR *str, CHAR val) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000841 while (*str != 0) {
842 if (*str == val) return((CHAR *) str);
843 str++;
844 }
845 return(NULL);
846}
847
Daniel Veillard11e00581998-10-24 18:27:49 +0000848/**
849 * xmlStrlen:
850 * @str: the CHAR * array
851 *
852 * lenght of a CHAR's string
853 * return values: the number of CHAR contained in the ARRAY.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000854 */
855
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000856int
857xmlStrlen(const CHAR *str) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000858 int len = 0;
859
860 if (str == NULL) return(0);
861 while (*str != 0) {
862 str++;
863 len++;
864 }
865 return(len);
866}
867
Daniel Veillard11e00581998-10-24 18:27:49 +0000868/**
869 * xmlStrncat:
870 * @first: the original CHAR * array
871 * @add: the CHAR * array added
872 * @len: the length of @add
873 *
874 * a strncat for array of CHAR's
875 * return values: a new CHAR * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000876 */
877
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000878CHAR *
879xmlStrncat(CHAR *cur, const CHAR *add, int len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000880 int size;
881 CHAR *ret;
882
883 if ((add == NULL) || (len == 0))
884 return(cur);
885 if (cur == NULL)
886 return(xmlStrndup(add, len));
887
888 size = xmlStrlen(cur);
889 ret = realloc(cur, (size + len + 1) * sizeof(CHAR));
890 if (ret == NULL) {
891 fprintf(stderr, "xmlStrncat: realloc of %d byte failed\n",
892 (size + len + 1) * sizeof(CHAR));
893 return(cur);
894 }
895 memcpy(&ret[size], add, len * sizeof(CHAR));
896 ret[size + len] = 0;
897 return(ret);
898}
899
Daniel Veillard11e00581998-10-24 18:27:49 +0000900/**
901 * xmlStrcat:
902 * @first: the original CHAR * array
903 * @add: the CHAR * array added
904 *
905 * a strcat for array of CHAR's
906 * return values: a new CHAR * containing the concatenated string.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000907 */
908
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000909CHAR *
910xmlStrcat(CHAR *cur, const CHAR *add) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000911 const CHAR *p = add;
912
913 if (add == NULL) return(cur);
914 if (cur == NULL)
915 return(xmlStrdup(add));
916
917 while (IS_CHAR(*p)) p++;
918 return(xmlStrncat(cur, add, p - add));
919}
920
921/************************************************************************
922 * *
923 * Commodity functions, cleanup needed ? *
924 * *
925 ************************************************************************/
926
Daniel Veillard11e00581998-10-24 18:27:49 +0000927/**
928 * areBlanks:
929 * @ctxt: an XML parser context
930 * @str: a CHAR *
931 * @len: the size of @str
932 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000933 * Is this a sequence of blank chars that one can ignore ?
Daniel Veillard11e00581998-10-24 18:27:49 +0000934 *
935 * TODO: to be corrected accodingly to DTD information if available
936 * return values: 1 if ignorable 0 otherwise.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000937 */
938
939static int areBlanks(xmlParserCtxtPtr ctxt, const CHAR *str, int len) {
940 int i;
941 xmlNodePtr lastChild;
942
943 for (i = 0;i < len;i++)
944 if (!(IS_BLANK(str[i]))) return(0);
945
946 if (CUR != '<') return(0);
947 lastChild = xmlGetLastChild(ctxt->node);
948 if (lastChild == NULL) {
949 if (ctxt->node->content != NULL) return(0);
950 } else if (xmlNodeIsText(lastChild))
951 return(0);
952 return(1);
953}
954
Daniel Veillard11e00581998-10-24 18:27:49 +0000955/**
956 * xmlHandleEntity:
957 * @ctxt: an XML parser context
958 * @entity: an XML entity pointer.
959 *
960 * Default handling of defined entities, when should we define a new input
Daniel Veillard260a68f1998-08-13 03:39:55 +0000961 * stream ? When do we just handle that as a set of chars ?
Daniel Veillard11e00581998-10-24 18:27:49 +0000962 * TODO: we should call the SAX handler here and have it resolve the issue
Daniel Veillard260a68f1998-08-13 03:39:55 +0000963 */
964
Daniel Veillard0ba4d531998-11-01 19:34:31 +0000965void
966xmlHandleEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
Daniel Veillard260a68f1998-08-13 03:39:55 +0000967 int len;
Daniel Veillardccb09631998-10-27 06:21:04 +0000968 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000969
970 if (entity->content == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +0000971 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
972 ctxt->sax->error(ctxt, "xmlHandleEntity %s: content == NULL\n",
Daniel Veillard260a68f1998-08-13 03:39:55 +0000973 entity->name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000974 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000975 return;
976 }
977 len = xmlStrlen(entity->content);
978 if (len <= 2) goto handle_as_char;
979
980 /*
981 * Redefine its content as an input stream.
982 */
Daniel Veillardccb09631998-10-27 06:21:04 +0000983 input = xmlNewEntityInputStream(ctxt, entity);
984 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000985 return;
986
987handle_as_char:
988 /*
989 * Just handle the content as a set of chars.
990 */
991 if (ctxt->sax != NULL)
992 ctxt->sax->characters(ctxt, entity->content, 0, len);
993
994}
995
996/*
997 * Forward definition for recusive behaviour.
998 */
999xmlNodePtr xmlParseElement(xmlParserCtxtPtr ctxt);
Daniel Veillardccb09631998-10-27 06:21:04 +00001000CHAR *xmlParsePEReference(xmlParserCtxtPtr ctxt);
1001CHAR *xmlParseReference(xmlParserCtxtPtr ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001002
1003/************************************************************************
1004 * *
1005 * Extra stuff for namespace support *
1006 * Relates to http://www.w3.org/TR/WD-xml-names *
1007 * *
1008 ************************************************************************/
1009
Daniel Veillard11e00581998-10-24 18:27:49 +00001010/**
1011 * xmlNamespaceParseNCName:
1012 * @ctxt: an XML parser context
1013 *
1014 * parse an XML namespace name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001015 *
1016 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
1017 *
1018 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
1019 * CombiningChar | Extender
Daniel Veillard11e00581998-10-24 18:27:49 +00001020 * return values: the namespace name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001021 */
1022
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001023CHAR *
1024xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001025 const CHAR *q;
1026 CHAR *ret = NULL;
1027
1028 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
1029 q = NEXT;
1030
1031 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1032 (CUR == '.') || (CUR == '-') ||
1033 (CUR == '_') ||
1034 (IS_COMBINING(CUR)) ||
1035 (IS_EXTENDER(CUR)))
1036 NEXT;
1037
1038 ret = xmlStrndup(q, CUR_PTR - q);
1039
1040 return(ret);
1041}
1042
Daniel Veillard11e00581998-10-24 18:27:49 +00001043/**
1044 * xmlNamespaceParseQName:
1045 * @ctxt: an XML parser context
1046 * @prefix: a CHAR **
1047 *
1048 * parse an XML qualified name
Daniel Veillard260a68f1998-08-13 03:39:55 +00001049 *
1050 * [NS 5] QName ::= (Prefix ':')? LocalPart
1051 *
1052 * [NS 6] Prefix ::= NCName
1053 *
1054 * [NS 7] LocalPart ::= NCName
Daniel Veillard11e00581998-10-24 18:27:49 +00001055 * return values: the function returns the local part, and prefix is updated
1056 * to get the Prefix if any.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001057 */
1058
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001059CHAR *
1060xmlNamespaceParseQName(xmlParserCtxtPtr ctxt, CHAR **prefix) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001061 CHAR *ret = NULL;
1062
1063 *prefix = NULL;
1064 ret = xmlNamespaceParseNCName(ctxt);
1065 if (CUR == ':') {
1066 *prefix = ret;
1067 NEXT;
1068 ret = xmlNamespaceParseNCName(ctxt);
1069 }
1070
1071 return(ret);
1072}
1073
Daniel Veillard11e00581998-10-24 18:27:49 +00001074/**
1075 * xmlNamespaceParseNSDef:
1076 * @ctxt: an XML parser context
1077 *
1078 * parse a namespace prefix declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00001079 *
1080 * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral
1081 *
1082 * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)?
Daniel Veillard11e00581998-10-24 18:27:49 +00001083 * return values: the namespace name
Daniel Veillard260a68f1998-08-13 03:39:55 +00001084 */
1085
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001086CHAR *
1087xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001088 CHAR *name = NULL;
1089
1090 if ((CUR == 'x') && (NXT(1) == 'm') &&
1091 (NXT(2) == 'l') && (NXT(3) == 'n') &&
1092 (NXT(4) == 's')) {
1093 SKIP(5);
1094 if (CUR == ':') {
1095 NEXT;
1096 name = xmlNamespaceParseNCName(ctxt);
1097 }
1098 }
1099 return(name);
1100}
1101
Daniel Veillard11e00581998-10-24 18:27:49 +00001102/**
1103 * xmlParseQuotedString:
1104 * @ctxt: an XML parser context
1105 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001106 * [OLD] Parse and return a string between quotes or doublequotes
Daniel Veillard11e00581998-10-24 18:27:49 +00001107 * return values: the string parser or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001108 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001109CHAR *
1110xmlParseQuotedString(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001111 CHAR *ret = NULL;
1112 const CHAR *q;
1113
1114 if (CUR == '"') {
1115 NEXT;
1116 q = CUR_PTR;
1117 while (IS_CHAR(CUR) && (CUR != '"')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001118 if (CUR != '"') {
1119 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00001120 ctxt->sax->error(ctxt, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001121 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001122 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001123 ret = xmlStrndup(q, CUR_PTR - q);
1124 NEXT;
1125 }
1126 } else if (CUR == '\''){
1127 NEXT;
1128 q = CUR_PTR;
1129 while (IS_CHAR(CUR) && (CUR != '\'')) NEXT;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001130 if (CUR != '\'') {
1131 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00001132 ctxt->sax->error(ctxt, "String not closed \"%.50s\"\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001133 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001134 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001135 ret = xmlStrndup(q, CUR_PTR - q);
1136 NEXT;
1137 }
1138 }
1139 return(ret);
1140}
1141
Daniel Veillard11e00581998-10-24 18:27:49 +00001142/**
1143 * xmlParseNamespace:
1144 * @ctxt: an XML parser context
1145 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001146 * [OLD] xmlParseNamespace: parse specific PI '<?namespace ...' constructs.
1147 *
1148 * This is what the older xml-name Working Draft specified, a bunch of
1149 * other stuff may still rely on it, so support is still here as
1150 * if ot was declared on the root of the Tree:-(
1151 */
1152
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001153void
1154xmlParseNamespace(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001155 CHAR *href = NULL;
1156 CHAR *prefix = NULL;
1157 int garbage = 0;
1158
1159 /*
1160 * We just skipped "namespace" or "xml:namespace"
1161 */
1162 SKIP_BLANKS;
1163
1164 while (IS_CHAR(CUR) && (CUR != '>')) {
1165 /*
1166 * We can have "ns" or "prefix" attributes
1167 * Old encoding as 'href' or 'AS' attributes is still supported
1168 */
1169 if ((CUR == 'n') && (NXT(1) == 's')) {
1170 garbage = 0;
1171 SKIP(2);
1172 SKIP_BLANKS;
1173
1174 if (CUR != '=') continue;
1175 NEXT;
1176 SKIP_BLANKS;
1177
1178 href = xmlParseQuotedString(ctxt);
1179 SKIP_BLANKS;
1180 } else if ((CUR == 'h') && (NXT(1) == 'r') &&
1181 (NXT(2) == 'e') && (NXT(3) == 'f')) {
1182 garbage = 0;
1183 SKIP(4);
1184 SKIP_BLANKS;
1185
1186 if (CUR != '=') continue;
1187 NEXT;
1188 SKIP_BLANKS;
1189
1190 href = xmlParseQuotedString(ctxt);
1191 SKIP_BLANKS;
1192 } else if ((CUR == 'p') && (NXT(1) == 'r') &&
1193 (NXT(2) == 'e') && (NXT(3) == 'f') &&
1194 (NXT(4) == 'i') && (NXT(5) == 'x')) {
1195 garbage = 0;
1196 SKIP(6);
1197 SKIP_BLANKS;
1198
1199 if (CUR != '=') continue;
1200 NEXT;
1201 SKIP_BLANKS;
1202
1203 prefix = xmlParseQuotedString(ctxt);
1204 SKIP_BLANKS;
1205 } else if ((CUR == 'A') && (NXT(1) == 'S')) {
1206 garbage = 0;
1207 SKIP(2);
1208 SKIP_BLANKS;
1209
1210 if (CUR != '=') continue;
1211 NEXT;
1212 SKIP_BLANKS;
1213
1214 prefix = xmlParseQuotedString(ctxt);
1215 SKIP_BLANKS;
1216 } else if ((CUR == '?') && (NXT(1) == '>')) {
1217 garbage = 0;
1218 CUR_PTR ++;
1219 } else {
1220 /*
1221 * Found garbage when parsing the namespace
1222 */
1223 if (!garbage)
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001224 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1225 ctxt->sax->error(ctxt, "xmlParseNamespace found garbage\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001226 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001227 NEXT;
1228 }
1229 }
1230
1231 MOVETO_ENDTAG(CUR_PTR);
1232 NEXT;
1233
1234 /*
1235 * Register the DTD.
1236 */
1237 if (href != NULL)
1238 xmlNewGlobalNs(ctxt->doc, href, prefix);
1239
1240 if (prefix != NULL) free(prefix);
1241 if (href != NULL) free(href);
1242}
1243
1244/************************************************************************
1245 * *
1246 * The parser itself *
1247 * Relates to http://www.w3.org/TR/REC-xml *
1248 * *
1249 ************************************************************************/
1250
Daniel Veillard11e00581998-10-24 18:27:49 +00001251/**
1252 * xmlParseName:
1253 * @ctxt: an XML parser context
1254 *
1255 * parse an XML name.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001256 *
1257 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
1258 * CombiningChar | Extender
1259 *
1260 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
1261 *
1262 * [6] Names ::= Name (S Name)*
Daniel Veillard11e00581998-10-24 18:27:49 +00001263 * return values: the Name parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001264 */
1265
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001266CHAR *
1267xmlParseName(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001268 const CHAR *q;
1269 CHAR *ret = NULL;
1270
1271 if (!IS_LETTER(CUR) && (CUR != '_') &&
1272 (CUR != ':')) return(NULL);
1273 q = NEXT;
1274
1275 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1276 (CUR == '.') || (CUR == '-') ||
1277 (CUR == '_') || (CUR == ':') ||
1278 (IS_COMBINING(CUR)) ||
1279 (IS_EXTENDER(CUR)))
1280 NEXT;
1281
1282 ret = xmlStrndup(q, CUR_PTR - q);
1283
1284 return(ret);
1285}
1286
Daniel Veillard11e00581998-10-24 18:27:49 +00001287/**
1288 * xmlParseNmtoken:
1289 * @ctxt: an XML parser context
1290 *
1291 * parse an XML Nmtoken.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001292 *
1293 * [7] Nmtoken ::= (NameChar)+
1294 *
1295 * [8] Nmtokens ::= Nmtoken (S Nmtoken)*
Daniel Veillard11e00581998-10-24 18:27:49 +00001296 * return values: the Nmtoken parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001297 */
1298
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001299CHAR *
1300xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001301 const CHAR *q;
1302 CHAR *ret = NULL;
1303
1304 q = NEXT;
1305
1306 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
1307 (CUR == '.') || (CUR == '-') ||
1308 (CUR == '_') || (CUR == ':') ||
1309 (IS_COMBINING(CUR)) ||
1310 (IS_EXTENDER(CUR)))
1311 NEXT;
1312
1313 ret = xmlStrndup(q, CUR_PTR - q);
1314
1315 return(ret);
1316}
1317
Daniel Veillard11e00581998-10-24 18:27:49 +00001318/**
1319 * xmlParseEntityValue:
1320 * @ctxt: an XML parser context
1321 *
1322 * parse a value for ENTITY decl.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001323 *
1324 * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
1325 * "'" ([^%&'] | PEReference | Reference)* "'"
Daniel Veillard11e00581998-10-24 18:27:49 +00001326 * return values: the EntityValue parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001327 */
1328
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001329CHAR *
1330xmlParseEntityValue(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001331 CHAR *ret = NULL, *cur;
1332 const CHAR *q;
1333
1334 if (CUR == '"') {
1335 NEXT;
1336
1337 q = CUR_PTR;
1338 while ((IS_CHAR(CUR)) && (CUR != '"')) {
1339 if (CUR == '%') {
1340 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001341 cur = xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001342 ret = xmlStrcat(ret, cur);
1343 q = CUR_PTR;
1344 } else if (CUR == '&') {
1345 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001346 cur = xmlParseReference(ctxt);
1347 if (cur != NULL) {
1348 CHAR buf[2];
1349 buf[0] = '&';
1350 buf[1] = 0;
1351 ret = xmlStrncat(ret, buf, 1);
1352 ret = xmlStrcat(ret, cur);
1353 buf[0] = ';';
1354 buf[1] = 0;
1355 ret = xmlStrncat(ret, buf, 1);
1356 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001357 q = CUR_PTR;
1358 } else
1359 NEXT;
1360 }
1361 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001362 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1363 ctxt->sax->error(ctxt, "Unfinished EntityValue\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001364 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001365 } else {
1366 ret = xmlStrncat(ret, q, CUR_PTR - q);
1367 NEXT;
1368 }
1369 } else if (CUR == '\'') {
1370 NEXT;
1371 q = CUR_PTR;
1372 while ((IS_CHAR(CUR)) && (CUR != '\'')) {
1373 if (CUR == '%') {
1374 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001375 cur = xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001376 ret = xmlStrcat(ret, cur);
1377 q = CUR_PTR;
1378 } else if (CUR == '&') {
1379 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001380 cur = xmlParseReference(ctxt);
1381 if (cur != NULL) {
1382 CHAR buf[2];
1383 buf[0] = '&';
1384 buf[1] = 0;
1385 ret = xmlStrncat(ret, buf, 1);
1386 ret = xmlStrcat(ret, cur);
1387 buf[0] = ';';
1388 buf[1] = 0;
1389 ret = xmlStrncat(ret, buf, 1);
1390 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001391 q = CUR_PTR;
1392 } else
1393 NEXT;
1394 }
1395 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001396 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1397 ctxt->sax->error(ctxt, "Unfinished EntityValue\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001398 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001399 } else {
1400 ret = xmlStrncat(ret, q, CUR_PTR - q);
1401 NEXT;
1402 }
1403 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001404 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1405 ctxt->sax->error(ctxt, "xmlParseEntityValue \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001406 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001407 }
1408
1409 return(ret);
1410}
1411
Daniel Veillard11e00581998-10-24 18:27:49 +00001412/**
1413 * xmlParseAttValue:
1414 * @ctxt: an XML parser context
1415 *
1416 * parse a value for an attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00001417 *
1418 * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
1419 * "'" ([^<&'] | Reference)* "'"
Daniel Veillard11e00581998-10-24 18:27:49 +00001420 * return values: the AttValue parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001421 */
1422
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001423CHAR *
1424xmlParseAttValue(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001425 CHAR *ret = NULL, *cur;
1426 const CHAR *q;
1427
1428 if (CUR == '"') {
1429 NEXT;
1430
1431 q = CUR_PTR;
1432 while ((IS_CHAR(CUR)) && (CUR != '"')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001433 if (CUR == '<') {
1434 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1435 ctxt->sax->error(ctxt,
1436 "Unescaped '<' not allowed in attributes values\n");
1437 ctxt->wellFormed = 0;
1438 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001439 if (CUR == '&') {
1440 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001441 cur = xmlParseReference(ctxt);
1442 if (cur != NULL) {
1443 /*
1444 * Special case for '&amp;', we don't want to
1445 * resolve it here since it will break later
1446 * when searching entities in the string.
1447 */
1448 if ((cur[0] == '&') && (cur[1] == 0)) {
1449 CHAR buf[6] = { '&', 'a', 'm', 'p', ';', 0 };
1450 ret = xmlStrncat(ret, buf, 5);
1451 } else
1452 ret = xmlStrcat(ret, cur);
1453 free(cur);
1454 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001455 q = CUR_PTR;
1456 } else
1457 NEXT;
Daniel Veillardccb09631998-10-27 06:21:04 +00001458 /*
1459 * Pop out finished entity references.
1460 */
1461 while ((CUR == 0) && (ctxt->inputNr > 1)) {
1462 if (CUR_PTR != q)
1463 ret = xmlStrncat(ret, q, CUR_PTR - q);
1464 xmlPopInput(ctxt);
1465 q = CUR_PTR;
1466 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001467 }
1468 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001469 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1470 ctxt->sax->error(ctxt, "Unfinished AttValue\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001471 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001472 } else {
1473 ret = xmlStrncat(ret, q, CUR_PTR - q);
1474 NEXT;
1475 }
1476 } else if (CUR == '\'') {
1477 NEXT;
1478 q = CUR_PTR;
1479 while ((IS_CHAR(CUR)) && (CUR != '\'')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001480 if (CUR == '<') {
1481 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1482 ctxt->sax->error(ctxt,
1483 "Unescaped '<' not allowed in attributes values\n");
1484 ctxt->wellFormed = 0;
1485 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001486 if (CUR == '&') {
1487 ret = xmlStrncat(ret, q, CUR_PTR - q);
Daniel Veillardccb09631998-10-27 06:21:04 +00001488 cur = xmlParseReference(ctxt);
1489 if (cur != NULL) {
1490 /*
1491 * Special case for '&amp;', we don't want to
1492 * resolve it here since it will break later
1493 * when searching entities in the string.
1494 */
1495 if ((cur[0] == '&') && (cur[1] == 0)) {
1496 CHAR buf[6] = { '&', 'a', 'm', 'p', ';', 0 };
1497 ret = xmlStrncat(ret, buf, 5);
1498 } else
1499 ret = xmlStrcat(ret, cur);
1500 free(cur);
1501 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001502 q = CUR_PTR;
1503 } else
1504 NEXT;
Daniel Veillardccb09631998-10-27 06:21:04 +00001505 /*
1506 * Pop out finished entity references.
1507 */
1508 while ((CUR == 0) && (ctxt->inputNr > 1)) {
1509 if (CUR_PTR != q)
1510 ret = xmlStrncat(ret, q, CUR_PTR - q);
1511 xmlPopInput(ctxt);
1512 q = CUR_PTR;
1513 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001514 }
1515 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001516 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1517 ctxt->sax->error(ctxt, "Unfinished AttValue\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001518 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001519 } else {
1520 ret = xmlStrncat(ret, q, CUR_PTR - q);
1521 NEXT;
1522 }
1523 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001524 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1525 ctxt->sax->error(ctxt, "AttValue: \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001526 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001527 }
1528
1529 return(ret);
1530}
1531
Daniel Veillard11e00581998-10-24 18:27:49 +00001532/**
1533 * xmlParseSystemLiteral:
1534 * @ctxt: an XML parser context
1535 *
1536 * parse an XML Literal
Daniel Veillard260a68f1998-08-13 03:39:55 +00001537 *
1538 * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
Daniel Veillard11e00581998-10-24 18:27:49 +00001539 * return values: the SystemLiteral parsed or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001540 */
1541
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001542CHAR *
1543xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001544 const CHAR *q;
1545 CHAR *ret = NULL;
1546
1547 if (CUR == '"') {
1548 NEXT;
1549 q = CUR_PTR;
1550 while ((IS_CHAR(CUR)) && (CUR != '"'))
1551 NEXT;
1552 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001553 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1554 ctxt->sax->error(ctxt, "Unfinished SystemLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001555 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001556 } else {
1557 ret = xmlStrndup(q, CUR_PTR - q);
1558 NEXT;
1559 }
1560 } else if (CUR == '\'') {
1561 NEXT;
1562 q = CUR_PTR;
1563 while ((IS_CHAR(CUR)) && (CUR != '\''))
1564 NEXT;
1565 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001566 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1567 ctxt->sax->error(ctxt, "Unfinished SystemLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001568 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001569 } else {
1570 ret = xmlStrndup(q, CUR_PTR - q);
1571 NEXT;
1572 }
1573 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001574 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1575 ctxt->sax->error(ctxt, "SystemLiteral \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001576 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001577 }
1578
1579 return(ret);
1580}
1581
Daniel Veillard11e00581998-10-24 18:27:49 +00001582/**
1583 * xmlParsePubidLiteral:
1584 * @ctxt: an XML parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +00001585 *
Daniel Veillard11e00581998-10-24 18:27:49 +00001586 * parse an XML public literal
1587 * return values: the PubidLiteral parsed or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001588 */
1589
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001590CHAR *
1591xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001592 const CHAR *q;
1593 CHAR *ret = NULL;
1594 /*
1595 * Name ::= (Letter | '_') (NameChar)*
1596 */
1597 if (CUR == '"') {
1598 NEXT;
1599 q = CUR_PTR;
1600 while (IS_PUBIDCHAR(CUR)) NEXT;
1601 if (CUR != '"') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001602 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1603 ctxt->sax->error(ctxt, "Unfinished PubidLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001604 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001605 } else {
1606 ret = xmlStrndup(q, CUR_PTR - q);
1607 NEXT;
1608 }
1609 } else if (CUR == '\'') {
1610 NEXT;
1611 q = CUR_PTR;
1612 while ((IS_LETTER(CUR)) && (CUR != '\''))
1613 NEXT;
1614 if (!IS_LETTER(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001615 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1616 ctxt->sax->error(ctxt, "Unfinished PubidLiteral\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001617 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001618 } else {
1619 ret = xmlStrndup(q, CUR_PTR - q);
1620 NEXT;
1621 }
1622 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001623 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1624 ctxt->sax->error(ctxt, "SystemLiteral \" or ' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001625 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001626 }
1627
1628 return(ret);
1629}
1630
Daniel Veillard11e00581998-10-24 18:27:49 +00001631/**
1632 * xmlParseCharData:
1633 * @ctxt: an XML parser context
1634 * @cdata: int indicating whether we are within a CDATA section
1635 *
1636 * parse a CharData section.
1637 * if we are within a CDATA section ']]>' marks an end of section.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001638 *
1639 * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
Daniel Veillard11e00581998-10-24 18:27:49 +00001640 * return values:
Daniel Veillard260a68f1998-08-13 03:39:55 +00001641 */
1642
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001643void
1644xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001645 const CHAR *q;
1646
1647 q = CUR_PTR;
1648 while ((IS_CHAR(CUR)) && (CUR != '<') &&
1649 (CUR != '&')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001650 if ((CUR == ']') && (NXT(1) == ']') &&
1651 (NXT(2) == '>')) {
1652 if (cdata) break;
1653 else {
1654 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1655 ctxt->sax->error(ctxt,
1656 "Sequence ']]>' not allowed in content\n");
1657 ctxt->wellFormed = 0;
1658 }
1659 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001660 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001661 }
1662 if (q == CUR_PTR) return;
1663
1664 /*
1665 * Ok the segment [q CUR_PTR] is to be consumed as chars.
1666 */
1667 if (ctxt->sax != NULL) {
1668 if (areBlanks(ctxt, q, CUR_PTR - q))
1669 ctxt->sax->ignorableWhitespace(ctxt, q, 0, CUR_PTR - q);
1670 else
1671 ctxt->sax->characters(ctxt, q, 0, CUR_PTR - q);
1672 }
1673}
1674
Daniel Veillard11e00581998-10-24 18:27:49 +00001675/**
1676 * xmlParseExternalID:
1677 * @ctxt: an XML parser context
1678 * @publicID: a CHAR** receiving PubidLiteral
1679 *
1680 * Parse an External ID
Daniel Veillard260a68f1998-08-13 03:39:55 +00001681 *
1682 * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
1683 * | 'PUBLIC' S PubidLiteral S SystemLiteral
Daniel Veillard11e00581998-10-24 18:27:49 +00001684 * return values: the function returns SystemLiteral and in the second
1685 * case publicID receives PubidLiteral
Daniel Veillard260a68f1998-08-13 03:39:55 +00001686 */
1687
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001688CHAR *
1689xmlParseExternalID(xmlParserCtxtPtr ctxt, CHAR **publicID) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001690 CHAR *URI = NULL;
1691
1692 if ((CUR == 'S') && (NXT(1) == 'Y') &&
1693 (NXT(2) == 'S') && (NXT(3) == 'T') &&
1694 (NXT(4) == 'E') && (NXT(5) == 'M')) {
1695 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001696 if (!IS_BLANK(CUR)) {
1697 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1698 ctxt->sax->error(ctxt,
1699 "Space required after 'SYSTEM'\n");
1700 ctxt->wellFormed = 0;
1701 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001702 SKIP_BLANKS;
1703 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001704 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001705 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1706 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001707 "xmlParseExternalID: SYSTEM, no URI\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001708 ctxt->wellFormed = 0;
1709 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001710 } else if ((CUR == 'P') && (NXT(1) == 'U') &&
1711 (NXT(2) == 'B') && (NXT(3) == 'L') &&
1712 (NXT(4) == 'I') && (NXT(5) == 'C')) {
1713 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001714 if (!IS_BLANK(CUR)) {
1715 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1716 ctxt->sax->error(ctxt,
1717 "Space required after 'PUBLIC'\n");
1718 ctxt->wellFormed = 0;
1719 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001720 SKIP_BLANKS;
1721 *publicID = xmlParsePubidLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001722 if (*publicID == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001723 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1724 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001725 "xmlParseExternalID: PUBLIC, no Public Identifier\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001726 ctxt->wellFormed = 0;
1727 }
1728 if (!IS_BLANK(CUR)) {
1729 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1730 ctxt->sax->error(ctxt,
1731 "Space required after the Public Identifier\n");
1732 ctxt->wellFormed = 0;
1733 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001734 SKIP_BLANKS;
1735 URI = xmlParseSystemLiteral(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001736 if (URI == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001737 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1738 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001739 "xmlParseExternalID: PUBLIC, no URI\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001740 ctxt->wellFormed = 0;
1741 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001742 }
1743 return(URI);
1744}
1745
Daniel Veillard11e00581998-10-24 18:27:49 +00001746/**
1747 * xmlParseComment:
1748 * @create: should we create a node
1749 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00001750 * Skip an XML (SGML) comment <!-- .... -->
1751 * This may or may not create a node (depending on the context)
1752 * The spec says that "For compatibility, the string "--" (double-hyphen)
1753 * must not occur within comments. "
1754 *
1755 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
Daniel Veillard11e00581998-10-24 18:27:49 +00001756 *
1757 * TODO: this should call a SAX function which will handle (or not) the
1758 * creation of the comment !
1759 * return values:
Daniel Veillard260a68f1998-08-13 03:39:55 +00001760 */
1761xmlNodePtr xmlParseComment(xmlParserCtxtPtr ctxt, int create) {
1762 xmlNodePtr ret = NULL;
1763 const CHAR *q, *start;
1764 const CHAR *r;
1765 CHAR *val;
1766
1767 /*
1768 * Check that there is a comment right here.
1769 */
1770 if ((CUR != '<') || (NXT(1) != '!') ||
1771 (NXT(2) != '-') || (NXT(3) != '-')) return(NULL);
1772
1773 SKIP(4);
1774 start = q = CUR_PTR;
1775 NEXT;
1776 r = CUR_PTR;
1777 NEXT;
1778 while (IS_CHAR(CUR) &&
1779 ((CUR == ':') || (CUR != '>') ||
1780 (*r != '-') || (*q != '-'))) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001781 if ((*r == '-') && (*q == '-')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001782 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1783 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001784 "Comment must not contain '--' (double-hyphen)`\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001785 ctxt->wellFormed = 0;
1786 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00001787 NEXT;r++;q++;
1788 }
1789 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001790 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1791 ctxt->sax->error(ctxt, "Comment not terminated \n<!--%.50s\n", start);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001792 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001793 } else {
1794 NEXT;
1795 if (create) {
1796 val = xmlStrndup(start, q - start);
Daniel Veillard0bef1311998-10-14 02:36:47 +00001797 ret = xmlNewDocComment(ctxt->doc, val);
Daniel Veillard260a68f1998-08-13 03:39:55 +00001798 free(val);
1799 }
1800 }
1801 return(ret);
1802}
1803
Daniel Veillard11e00581998-10-24 18:27:49 +00001804/**
1805 * xmlParsePITarget:
1806 * @ctxt: an XML parser context
1807 *
1808 * parse the name of a PI
Daniel Veillard260a68f1998-08-13 03:39:55 +00001809 *
1810 * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
Daniel Veillard11e00581998-10-24 18:27:49 +00001811 * return values: the PITarget name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001812 */
1813
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001814CHAR *
1815xmlParsePITarget(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001816 CHAR *name;
1817
1818 name = xmlParseName(ctxt);
1819 if ((name != NULL) && (name[3] == 0) &&
1820 ((name[0] == 'x') || (name[0] == 'X')) &&
1821 ((name[1] == 'm') || (name[1] == 'M')) &&
1822 ((name[2] == 'l') || (name[2] == 'L'))) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001823 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1824 ctxt->sax->error(ctxt, "xmlParsePItarget: invalid name prefix 'xml'\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00001825 return(NULL);
1826 }
1827 return(name);
1828}
1829
Daniel Veillard11e00581998-10-24 18:27:49 +00001830/**
1831 * xmlParsePI:
1832 * @ctxt: an XML parser context
1833 *
1834 * parse an XML Processing Instruction.
Daniel Veillard260a68f1998-08-13 03:39:55 +00001835 *
1836 * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
Daniel Veillard11e00581998-10-24 18:27:49 +00001837 * return values: the PI name or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00001838 */
1839
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001840void
1841xmlParsePI(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001842 CHAR *target;
1843
1844 if ((CUR == '<') && (NXT(1) == '?')) {
1845 /*
1846 * this is a Processing Instruction.
1847 */
1848 SKIP(2);
1849
1850 /*
1851 * Parse the target name and check for special support like
1852 * namespace.
1853 *
1854 * TODO : PI handling should be dynamically redefinable using an
1855 * API. Only namespace should be in the code IMHO ...
1856 */
1857 target = xmlParsePITarget(ctxt);
1858 if (target != NULL) {
1859 /*
1860 * Support for the old Processing Instruction related to namespace.
1861 */
1862 if ((target[0] == 'n') && (target[1] == 'a') &&
1863 (target[2] == 'm') && (target[3] == 'e') &&
1864 (target[4] == 's') && (target[5] == 'p') &&
1865 (target[6] == 'a') && (target[7] == 'c') &&
1866 (target[8] == 'e')) {
1867 xmlParseNamespace(ctxt);
1868 } else if ((target[0] == 'x') && (target[1] == 'm') &&
1869 (target[2] == 'l') && (target[3] == ':') &&
1870 (target[4] == 'n') && (target[5] == 'a') &&
1871 (target[6] == 'm') && (target[7] == 'e') &&
1872 (target[8] == 's') && (target[9] == 'p') &&
1873 (target[10] == 'a') && (target[11] == 'c') &&
1874 (target[12] == 'e')) {
1875 xmlParseNamespace(ctxt);
1876 } else {
1877 const CHAR *q = CUR_PTR;
1878
1879 while (IS_CHAR(CUR) &&
1880 ((CUR != '?') || (NXT(1) != '>')))
1881 NEXT;
1882 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001883 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001884 ctxt->sax->error(ctxt,
1885 "xmlParsePI: PI %s never end ...\n", target);
1886 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001887 } else {
1888 CHAR *data;
1889
1890 data = xmlStrndup(CUR_PTR, CUR_PTR - q);
1891 SKIP(2);
1892
1893 /*
1894 * SAX: PI detected.
1895 */
1896 if (ctxt->sax)
1897 ctxt->sax->processingInstruction(ctxt, target, data);
1898 /*
1899 * Unknown PI, ignore it !
1900 */
1901 else
1902 xmlParserWarning(ctxt,
1903 "xmlParsePI : skipping unknown PI %s\n",
1904 target);
1905 free(data);
1906 }
1907 }
1908 free(target);
1909 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001910 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1911 ctxt->sax->error(ctxt, "xmlParsePI : no target name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001912 ctxt->wellFormed = 0;
1913
Daniel Veillard260a68f1998-08-13 03:39:55 +00001914 /********* Should we try to complete parsing the PI ???
1915 while (IS_CHAR(CUR) &&
1916 (CUR != '?') && (CUR != '>'))
1917 NEXT;
1918 if (!IS_CHAR(CUR)) {
1919 fprintf(stderr, "xmlParsePI: PI %s never end ...\n",
1920 target);
1921 }
1922 ********************************************************/
1923 }
1924 }
1925}
1926
Daniel Veillard11e00581998-10-24 18:27:49 +00001927/**
1928 * xmlParseNotationDecl:
1929 * @ctxt: an XML parser context
1930 *
1931 * parse a notation declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00001932 *
1933 * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
1934 *
1935 * [83] PublicID ::= 'PUBLIC' S PubidLiteral
1936 *
1937 * NOTE: Actually [75] and [83] interract badly since [75] can generate
1938 * 'PUBLIC' S PubidLiteral S SystemLiteral
1939 *
1940 * Hence there is actually 3 choices:
1941 * 'PUBLIC' S PubidLiteral
1942 * 'PUBLIC' S PubidLiteral S SystemLiteral
1943 * and 'SYSTEM' S SystemLiteral
Daniel Veillard11e00581998-10-24 18:27:49 +00001944 *
1945 * TODO: no handling of the values parsed !
Daniel Veillard260a68f1998-08-13 03:39:55 +00001946 */
1947
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001948void
1949xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00001950 CHAR *name;
1951
1952 if ((CUR == '<') && (NXT(1) == '!') &&
1953 (NXT(2) == 'N') && (NXT(3) == 'O') &&
1954 (NXT(4) == 'T') && (NXT(5) == 'A') &&
1955 (NXT(6) == 'T') && (NXT(7) == 'I') &&
1956 (NXT(8) == 'O') && (NXT(9) == 'N') &&
1957 (IS_BLANK(NXT(10)))) {
1958 SKIP(10);
1959 SKIP_BLANKS;
1960
1961 name = xmlParseName(ctxt);
1962 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00001963 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1964 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00001965 "xmlParseAttributeListDecl: no name for Element\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001966 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00001967 return;
1968 }
1969 SKIP_BLANKS;
1970 /*
1971 * TODO !!!
1972 */
1973 while ((IS_CHAR(CUR)) && (CUR != '>'))
1974 NEXT;
1975 free(name);
1976 }
1977}
1978
Daniel Veillard11e00581998-10-24 18:27:49 +00001979/**
1980 * xmlParseEntityDecl:
1981 * @ctxt: an XML parser context
1982 *
1983 * parse <!ENTITY declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00001984 *
1985 * [70] EntityDecl ::= GEDecl | PEDecl
1986 *
1987 * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
1988 *
1989 * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
1990 *
1991 * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
1992 *
1993 * [74] PEDef ::= EntityValue | ExternalID
1994 *
1995 * [76] NDataDecl ::= S 'NDATA' S Name
1996 */
1997
Daniel Veillard0ba4d531998-11-01 19:34:31 +00001998void
1999xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002000 CHAR *name = NULL;
2001 CHAR *value = NULL;
2002 CHAR *URI = NULL, *literal = NULL;
2003 CHAR *ndata = NULL;
2004 int isParameter = 0;
2005
2006 if ((CUR == '<') && (NXT(1) == '!') &&
2007 (NXT(2) == 'E') && (NXT(3) == 'N') &&
2008 (NXT(4) == 'T') && (NXT(5) == 'I') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002009 (NXT(6) == 'T') && (NXT(7) == 'Y')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002010 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002011 if (!IS_BLANK(CUR)) {
2012 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2013 ctxt->sax->error(ctxt, "Space required after '<!ENTITY'\n");
2014 ctxt->wellFormed = 0;
2015 }
2016 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002017
2018 if (CUR == '%') {
2019 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002020 if (!IS_BLANK(CUR)) {
2021 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2022 ctxt->sax->error(ctxt, "Space required after '%'\n");
2023 ctxt->wellFormed = 0;
2024 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002025 SKIP_BLANKS;
2026 isParameter = 1;
2027 }
2028
2029 name = xmlParseName(ctxt);
2030 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002031 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2032 ctxt->sax->error(ctxt, "xmlParseEntityDecl: no name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002033 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002034 return;
2035 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002036 if (!IS_BLANK(CUR)) {
2037 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2038 ctxt->sax->error(ctxt,
2039 "Space required after the entity name\n");
2040 ctxt->wellFormed = 0;
2041 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002042 SKIP_BLANKS;
2043
2044 /*
2045 * TODO handle the various case of definitions...
2046 */
2047 if (isParameter) {
2048 if ((CUR == '"') || (CUR == '\''))
2049 value = xmlParseEntityValue(ctxt);
2050 if (value) {
2051 xmlAddDocEntity(ctxt->doc, name,
2052 XML_INTERNAL_PARAMETER_ENTITY,
2053 NULL, NULL, value);
2054 }
2055 else {
2056 URI = xmlParseExternalID(ctxt, &literal);
2057 if (URI) {
2058 xmlAddDocEntity(ctxt->doc, name,
2059 XML_EXTERNAL_PARAMETER_ENTITY,
2060 literal, URI, NULL);
2061 }
2062 }
2063 } else {
2064 if ((CUR == '"') || (CUR == '\'')) {
2065 value = xmlParseEntityValue(ctxt);
2066 xmlAddDocEntity(ctxt->doc, name,
2067 XML_INTERNAL_GENERAL_ENTITY,
2068 NULL, NULL, value);
2069 } else {
2070 URI = xmlParseExternalID(ctxt, &literal);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002071 if ((CUR != '>') && (!IS_BLANK(CUR))) {
2072 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2073 ctxt->sax->error(ctxt,
2074 "Space required before 'NDATA'\n");
2075 ctxt->wellFormed = 0;
2076 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002077 SKIP_BLANKS;
2078 if ((CUR == 'N') && (NXT(1) == 'D') &&
2079 (NXT(2) == 'A') && (NXT(3) == 'T') &&
2080 (NXT(4) == 'A')) {
2081 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002082 if (!IS_BLANK(CUR)) {
2083 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2084 ctxt->sax->error(ctxt,
2085 "Space required after 'NDATA'\n");
2086 ctxt->wellFormed = 0;
2087 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002088 SKIP_BLANKS;
2089 ndata = xmlParseName(ctxt);
2090 xmlAddDocEntity(ctxt->doc, name,
2091 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
2092 literal, URI, ndata);
2093 } else {
2094 xmlAddDocEntity(ctxt->doc, name,
2095 XML_EXTERNAL_GENERAL_PARSED_ENTITY,
2096 literal, URI, NULL);
2097 }
2098 }
2099 }
2100 SKIP_BLANKS;
2101 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002102 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2103 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002104 "xmlParseEntityDecl: entity %s not terminated\n", name);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002105 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002106 } else
2107 NEXT;
2108 if (name != NULL) free(name);
2109 if (value != NULL) free(value);
2110 if (URI != NULL) free(URI);
2111 if (literal != NULL) free(literal);
2112 if (ndata != NULL) free(ndata);
2113 }
2114}
2115
Daniel Veillard11e00581998-10-24 18:27:49 +00002116/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002117 * xmlParseDefaultDecl:
2118 * @ctxt: an XML parser context
2119 * @value: Receive a possible fixed default value for the attribute
2120 *
2121 * Parse an attribute default declaration
2122 *
2123 * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
2124 *
2125 * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
2126 * or XML_ATTRIBUTE_FIXED.
2127 */
2128
2129int
2130xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, CHAR **value) {
2131 int val;
2132 CHAR *ret;
2133
2134 *value = NULL;
2135 if ((CUR == '#') && (NXT(1) == 'R') &&
2136 (NXT(2) == 'E') && (NXT(3) == 'Q') &&
2137 (NXT(4) == 'U') && (NXT(5) == 'I') &&
2138 (NXT(6) == 'R') && (NXT(7) == 'E') &&
2139 (NXT(8) == 'D')) {
2140 SKIP(9);
2141 return(XML_ATTRIBUTE_REQUIRED);
2142 }
2143 if ((CUR == '#') && (NXT(1) == 'I') &&
2144 (NXT(2) == 'M') && (NXT(3) == 'P') &&
2145 (NXT(4) == 'L') && (NXT(5) == 'I') &&
2146 (NXT(6) == 'E') && (NXT(7) == 'D')) {
2147 SKIP(8);
2148 return(XML_ATTRIBUTE_IMPLIED);
2149 }
2150 val = XML_ATTRIBUTE_NONE;
2151 if ((CUR == '#') && (NXT(1) == 'F') &&
2152 (NXT(2) == 'I') && (NXT(3) == 'X') &&
2153 (NXT(4) == 'E') && (NXT(5) == 'D')) {
2154 SKIP(6);
2155 val = XML_ATTRIBUTE_FIXED;
2156 if (!IS_BLANK(CUR)) {
2157 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2158 ctxt->sax->error(ctxt, "Space required after '#FIXED'\n");
2159 ctxt->wellFormed = 0;
2160 }
2161 SKIP_BLANKS;
2162 }
2163 ret = xmlParseAttValue(ctxt);
2164 if (ret == NULL) {
2165 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2166 ctxt->sax->error(ctxt,
2167 "Attribute default value declaration error\n");
2168 ctxt->wellFormed = 0;
2169 } else
2170 *value = ret;
2171 return(val);
2172}
2173
2174/**
Daniel Veillard11e00581998-10-24 18:27:49 +00002175 * xmlParseEnumeratedType:
2176 * @ctxt: an XML parser context
2177 * @name: ???
2178 * @:
2179 *
2180 * parse and Enumerated attribute type.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002181 *
2182 * [57] EnumeratedType ::= NotationType | Enumeration
2183 *
2184 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
2185 *
2186 * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
Daniel Veillard11e00581998-10-24 18:27:49 +00002187 *
2188 * TODO: not implemented !!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00002189 */
2190
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002191void
2192xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002193 /*
2194 * TODO !!!
2195 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002196 fprintf(stderr, "Production [57] EnumeratedType not yet supported\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002197 while ((IS_CHAR(CUR)) && (CUR != '>'))
2198 NEXT;
2199}
2200
Daniel Veillard11e00581998-10-24 18:27:49 +00002201/**
2202 * xmlParseAttributeType:
2203 * @ctxt: an XML parser context
2204 * @name: ???
2205 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002206 * parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00002207 *
2208 * [54] AttType ::= StringType | TokenizedType | EnumeratedType
2209 *
2210 * [55] StringType ::= 'CDATA'
2211 *
2212 * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
2213 * 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
Daniel Veillard11e00581998-10-24 18:27:49 +00002214 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002215 * Returns: the attribute type
Daniel Veillard260a68f1998-08-13 03:39:55 +00002216 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002217int
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002218xmlParseAttributeType(xmlParserCtxtPtr ctxt, CHAR *name) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002219 /* TODO !!! */
2220 if ((CUR == 'C') && (NXT(1) == 'D') &&
2221 (NXT(2) == 'A') && (NXT(3) == 'T') &&
2222 (NXT(4) == 'A')) {
2223 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002224 return(XML_ATTRIBUTE_STRING);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002225 } else if ((CUR == 'I') && (NXT(1) == 'D')) {
2226 SKIP(2);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002227 return(XML_ATTRIBUTE_ID);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002228 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
2229 (NXT(2) == 'R') && (NXT(3) == 'E') &&
2230 (NXT(4) == 'F')) {
2231 SKIP(5);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002232 return(XML_ATTRIBUTE_IDREF);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002233 } else if ((CUR == 'I') && (NXT(1) == 'D') &&
2234 (NXT(2) == 'R') && (NXT(3) == 'E') &&
2235 (NXT(4) == 'F') && (NXT(5) == 'S')) {
2236 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002237 return(XML_ATTRIBUTE_IDREFS);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002238 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
2239 (NXT(2) == 'T') && (NXT(3) == 'I') &&
2240 (NXT(4) == 'T') && (NXT(5) == 'Y')) {
2241 SKIP(6);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002242 return(XML_ATTRIBUTE_ENTITY);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002243 } else if ((CUR == 'E') && (NXT(1) == 'N') &&
2244 (NXT(2) == 'T') && (NXT(3) == 'I') &&
2245 (NXT(4) == 'T') && (NXT(5) == 'I') &&
2246 (NXT(6) == 'E') && (NXT(7) == 'S')) {
2247 SKIP(8);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002248 return(XML_ATTRIBUTE_ENTITIES);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002249 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
2250 (NXT(2) == 'T') && (NXT(3) == 'O') &&
2251 (NXT(4) == 'K') && (NXT(5) == 'E') &&
2252 (NXT(6) == 'N')) {
2253 SKIP(7);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002254 return(XML_ATTRIBUTE_NMTOKEN);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002255 } else if ((CUR == 'N') && (NXT(1) == 'M') &&
2256 (NXT(2) == 'T') && (NXT(3) == 'O') &&
2257 (NXT(4) == 'K') && (NXT(5) == 'E') &&
2258 (NXT(6) == 'N') && (NXT(7) == 'S')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002259 return(XML_ATTRIBUTE_NMTOKENS);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002260 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002261 xmlParseEnumeratedType(ctxt, name);
2262 return(XML_ATTRIBUTE_ENUMERATED);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002263}
2264
Daniel Veillard11e00581998-10-24 18:27:49 +00002265/**
2266 * xmlParseAttributeListDecl:
2267 * @ctxt: an XML parser context
2268 *
2269 * : parse the Attribute list def for an element
Daniel Veillard260a68f1998-08-13 03:39:55 +00002270 *
2271 * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
2272 *
2273 * [53] AttDef ::= S Name S AttType S DefaultDecl
Daniel Veillard11e00581998-10-24 18:27:49 +00002274 *
2275 * TODO: not implemented !!!
Daniel Veillard260a68f1998-08-13 03:39:55 +00002276 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002277void
2278xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002279 CHAR *elemName;
2280 CHAR *attrName;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002281
2282 /* TODO !!! */
2283 if ((CUR == '<') && (NXT(1) == '!') &&
2284 (NXT(2) == 'A') && (NXT(3) == 'T') &&
2285 (NXT(4) == 'T') && (NXT(5) == 'L') &&
2286 (NXT(6) == 'I') && (NXT(7) == 'S') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002287 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002288 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002289 if (!IS_BLANK(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002290 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002291 ctxt->sax->error(ctxt, "Space required after '<!ATTLIST'\n");
2292 ctxt->wellFormed = 0;
2293 }
2294 SKIP_BLANKS;
2295 elemName = xmlParseName(ctxt);
2296 if (elemName == NULL) {
2297 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2298 ctxt->sax->error(ctxt, "ATTLIST: no name for Element\n");
2299 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002300 return;
2301 }
2302 SKIP_BLANKS;
2303 while (CUR != '>') {
2304 const CHAR *check = CUR_PTR;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002305 int type;
2306 int def;
2307 CHAR *defaultValue = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002308
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002309 attrName = xmlParseName(ctxt);
2310 if (attrName == NULL) {
2311 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2312 ctxt->sax->error(ctxt, "ATTLIST: no name for Attribute\n");
2313 ctxt->wellFormed = 0;
2314 break;
2315 }
2316 if (!IS_BLANK(CUR)) {
2317 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2318 ctxt->sax->error(ctxt,
2319 "Space required after the attribute name\n");
2320 ctxt->wellFormed = 0;
2321 break;
2322 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002323 SKIP_BLANKS;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002324
2325 type = xmlParseAttributeType(ctxt, attrName);
2326 if (type <= 0) break;
2327
2328 if (!IS_BLANK(CUR)) {
2329 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2330 ctxt->sax->error(ctxt,
2331 "Space required after the attribute type\n");
2332 ctxt->wellFormed = 0;
2333 break;
2334 }
2335 SKIP_BLANKS;
2336
2337 def = xmlParseDefaultDecl(ctxt, &defaultValue);
2338 if (def <= 0) break;
2339
2340 if (CUR != '>') {
2341 if (!IS_BLANK(CUR)) {
2342 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2343 ctxt->sax->error(ctxt,
2344 "Space required after the attribute default value\n");
2345 ctxt->wellFormed = 0;
2346 break;
2347 }
2348 SKIP_BLANKS;
2349 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002350 if (check == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002351 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2352 ctxt->sax->error(ctxt,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002353 "xmlParseAttributeListDecl: detected internal error\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00002354 break;
2355 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002356 if (attrName != NULL)
2357 free(attrName);
2358 if (defaultValue != NULL)
2359 free(defaultValue);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002360 }
2361 if (CUR == '>')
2362 NEXT;
2363
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002364 free(elemName);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002365 }
2366}
2367
Daniel Veillard11e00581998-10-24 18:27:49 +00002368/**
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002369 * xmlParseElementMixedContentDecl:
Daniel Veillard11e00581998-10-24 18:27:49 +00002370 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002371 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002372 * parse the declaration for a Mixed Element content
2373 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
Daniel Veillard260a68f1998-08-13 03:39:55 +00002374 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002375 * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
2376 * '(' S? '#PCDATA' S? ')'
2377 *
2378 * returns: the list of the xmlElementContentPtr describing the element choices
2379 */
2380xmlElementContentPtr
2381xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard1899e851999-02-01 12:18:54 +00002382 xmlElementContentPtr ret = NULL, cur = NULL, n;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002383 CHAR *elem = NULL;
2384
2385 if ((CUR == '#') && (NXT(1) == 'P') &&
2386 (NXT(2) == 'C') && (NXT(3) == 'D') &&
2387 (NXT(4) == 'A') && (NXT(5) == 'T') &&
2388 (NXT(6) == 'A')) {
2389 SKIP(7);
2390 SKIP_BLANKS;
Daniel Veillard3b9def11999-01-31 22:15:06 +00002391 if (CUR == ')') {
2392 NEXT;
2393 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
2394 return(ret);
2395 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002396 if ((CUR == '(') || (CUR == '|')) {
2397 ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
2398 if (ret == NULL) return(NULL);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002399 } /********** else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002400 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2401 ctxt->sax->error(ctxt,
2402 "xmlParseElementMixedContentDecl : '|' or ')' expected\n");
2403 ctxt->wellFormed = 0;
2404 return(NULL);
Daniel Veillard3b9def11999-01-31 22:15:06 +00002405 } **********/
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002406 while (CUR == '|') {
Daniel Veillard1899e851999-02-01 12:18:54 +00002407 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002408 if (elem == NULL) {
2409 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2410 if (ret == NULL) return(NULL);
2411 ret->c1 = cur;
Daniel Veillard1899e851999-02-01 12:18:54 +00002412 cur = ret;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002413 } else {
Daniel Veillard1899e851999-02-01 12:18:54 +00002414 n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2415 if (n == NULL) return(NULL);
2416 n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
2417 cur->c2 = n;
2418 cur = n;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002419 }
2420 SKIP_BLANKS;
2421 elem = xmlParseName(ctxt);
2422 if (elem == NULL) {
2423 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2424 ctxt->sax->error(ctxt,
2425 "xmlParseElementMixedContentDecl : Name expected\n");
2426 ctxt->wellFormed = 0;
2427 xmlFreeElementContent(cur);
2428 return(NULL);
2429 }
2430 SKIP_BLANKS;
2431 }
Daniel Veillard3b9def11999-01-31 22:15:06 +00002432 if ((CUR == ')') && (NXT(1) == '*')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002433 if (elem != NULL)
2434 cur->c2 = xmlNewElementContent(elem,
2435 XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard1899e851999-02-01 12:18:54 +00002436 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2437 SKIP(2);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002438 } else {
2439 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2440 ctxt->sax->error(ctxt,
Daniel Veillard3b9def11999-01-31 22:15:06 +00002441 "xmlParseElementMixedContentDecl : '|' or ')*' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002442 ctxt->wellFormed = 0;
2443 xmlFreeElementContent(ret);
2444 return(NULL);
2445 }
2446
2447 } else {
2448 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2449 ctxt->sax->error(ctxt,
2450 "xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
2451 ctxt->wellFormed = 0;
2452 }
2453 return(ret);
2454}
2455
2456/**
2457 * xmlParseElementChildrenContentDecl:
2458 * @ctxt: an XML parser context
2459 *
2460 * parse the declaration for a Mixed Element content
2461 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
2462 *
2463 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002464 * [47] children ::= (choice | seq) ('?' | '*' | '+')?
2465 *
2466 * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
2467 *
2468 * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
2469 *
2470 * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
2471 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002472 * returns: the tree of xmlElementContentPtr describing the element
2473 * hierarchy.
2474 */
2475xmlElementContentPtr
2476xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt) {
2477 xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
2478 CHAR *elem;
2479 CHAR type = 0;
2480
2481 SKIP_BLANKS;
2482 if (CUR == '(') {
2483 /* Recurse on first child */
2484 NEXT;
2485 SKIP_BLANKS;
2486 cur = ret = xmlParseElementChildrenContentDecl(ctxt);
2487 SKIP_BLANKS;
2488 } else {
2489 elem = xmlParseName(ctxt);
2490 if (elem == NULL) {
2491 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2492 ctxt->sax->error(ctxt,
2493 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
2494 ctxt->wellFormed = 0;
2495 return(NULL);
2496 }
2497 cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
2498 if (CUR == '?') {
2499 ret->ocur = XML_ELEMENT_CONTENT_OPT;
2500 NEXT;
2501 } else if (CUR == '*') {
2502 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2503 NEXT;
2504 } else if (CUR == '+') {
2505 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2506 NEXT;
2507 } else {
2508 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2509 }
2510 }
2511 SKIP_BLANKS;
2512 while (CUR != ')') {
2513 /*
2514 * Each loop we parse one separator and one element.
2515 */
2516 if (CUR == ',') {
2517 if (type == 0) type = CUR;
2518
2519 /*
2520 * Detect "Name | Name , Name" error
2521 */
2522 else if (type != CUR) {
2523 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2524 ctxt->sax->error(ctxt,
2525 "xmlParseElementChildrenContentDecl : '%c' expected\n",
2526 type);
2527 ctxt->wellFormed = 0;
2528 xmlFreeElementContent(ret);
2529 return(NULL);
2530 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002531 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002532
2533 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
2534 if (op == NULL) {
2535 xmlFreeElementContent(ret);
2536 return(NULL);
2537 }
2538 if (last == NULL) {
2539 op->c1 = ret;
2540 ret = cur = op;
2541 } else {
2542 cur->c2 = op;
2543 op->c1 = last;
2544 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00002545 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002546 }
2547 } else if (CUR == '|') {
2548 if (type == 0) type = CUR;
2549
2550 /*
2551 * Detect "Name , Name | Name" error
2552 */
2553 else if (type != CUR) {
2554 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2555 ctxt->sax->error(ctxt,
2556 "xmlParseElementChildrenContentDecl : '%c' expected\n",
2557 type);
2558 ctxt->wellFormed = 0;
2559 xmlFreeElementContent(ret);
2560 return(NULL);
2561 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002562 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002563
2564 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
2565 if (op == NULL) {
2566 xmlFreeElementContent(ret);
2567 return(NULL);
2568 }
2569 if (last == NULL) {
2570 op->c1 = ret;
2571 ret = cur = op;
2572 } else {
2573 cur->c2 = op;
2574 op->c1 = last;
2575 cur =op;
Daniel Veillard1899e851999-02-01 12:18:54 +00002576 last = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002577 }
2578 } else {
2579 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2580 ctxt->sax->error(ctxt,
2581 "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
2582 ctxt->wellFormed = 0;
2583 xmlFreeElementContent(ret);
2584 return(NULL);
2585 }
2586 SKIP_BLANKS;
2587 if (CUR == '(') {
2588 /* Recurse on second child */
2589 NEXT;
2590 SKIP_BLANKS;
Daniel Veillard1899e851999-02-01 12:18:54 +00002591 last = xmlParseElementChildrenContentDecl(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002592 SKIP_BLANKS;
2593 } else {
2594 elem = xmlParseName(ctxt);
2595 if (elem == NULL) {
2596 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2597 ctxt->sax->error(ctxt,
2598 "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
2599 ctxt->wellFormed = 0;
2600 return(NULL);
2601 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002602 last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002603 }
2604 if (CUR == '?') {
2605 ret->ocur = XML_ELEMENT_CONTENT_OPT;
2606 NEXT;
2607 } else if (CUR == '*') {
2608 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2609 NEXT;
2610 } else if (CUR == '+') {
2611 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2612 NEXT;
2613 } else {
2614 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2615 }
2616 SKIP_BLANKS;
2617 }
Daniel Veillard1899e851999-02-01 12:18:54 +00002618 if ((cur != NULL) && (last != NULL)) {
2619 cur->c2 = last;
2620 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002621 NEXT;
2622 if (CUR == '?') {
2623 ret->ocur = XML_ELEMENT_CONTENT_OPT;
2624 NEXT;
2625 } else if (CUR == '*') {
2626 ret->ocur = XML_ELEMENT_CONTENT_MULT;
2627 NEXT;
2628 } else if (CUR == '+') {
2629 ret->ocur = XML_ELEMENT_CONTENT_PLUS;
2630 NEXT;
2631 } else {
2632 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
2633 }
2634 return(ret);
2635}
2636
2637/**
2638 * xmlParseElementContentDecl:
2639 * @ctxt: an XML parser context
2640 * @name: the name of the element being defined.
2641 * @result: the Element Content pointer will be stored here if any
Daniel Veillard260a68f1998-08-13 03:39:55 +00002642 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002643 * parse the declaration for an Element content either Mixed or Children,
2644 * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
2645 *
2646 * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
Daniel Veillard11e00581998-10-24 18:27:49 +00002647 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002648 * returns: the type of element content XML_ELEMENT_TYPE_xxx
Daniel Veillard260a68f1998-08-13 03:39:55 +00002649 */
2650
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002651int
2652xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, CHAR *name,
2653 xmlElementContentPtr *result) {
2654
2655 xmlElementContentPtr tree = NULL;
2656 int res;
2657
2658 *result = NULL;
2659
2660 if (CUR != '(') {
2661 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2662 ctxt->sax->error(ctxt,
2663 "xmlParseElementContentDecl : '(' expected\n");
2664 ctxt->wellFormed = 0;
2665 return(-1);
2666 }
2667 NEXT;
2668 SKIP_BLANKS;
2669 if ((CUR == '#') && (NXT(1) == 'P') &&
2670 (NXT(2) == 'C') && (NXT(3) == 'D') &&
2671 (NXT(4) == 'A') && (NXT(5) == 'T') &&
2672 (NXT(6) == 'A')) {
2673 tree = xmlParseElementMixedContentDecl(ctxt);
2674 res = XML_ELEMENT_TYPE_MIXED;
2675 } else {
2676 tree = xmlParseElementChildrenContentDecl(ctxt);
2677 res = XML_ELEMENT_TYPE_ELEMENT;
2678 }
2679 SKIP_BLANKS;
2680 /****************************
2681 if (CUR != ')') {
2682 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2683 ctxt->sax->error(ctxt,
2684 "xmlParseElementContentDecl : ')' expected\n");
2685 ctxt->wellFormed = 0;
2686 return(-1);
2687 }
2688 ****************************/
Daniel Veillard3b9def11999-01-31 22:15:06 +00002689 *result = tree;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002690 return(res);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002691}
2692
Daniel Veillard11e00581998-10-24 18:27:49 +00002693/**
2694 * xmlParseElementDecl:
2695 * @ctxt: an XML parser context
2696 *
2697 * parse an Element declaration.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002698 *
2699 * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
2700 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00002701 * TODO There is a check [ VC: Unique Element Type Declaration ]
2702 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002703int
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002704xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002705 CHAR *name;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002706 int ret = -1;
2707 xmlElementContentPtr content = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002708
2709 if ((CUR == '<') && (NXT(1) == '!') &&
2710 (NXT(2) == 'E') && (NXT(3) == 'L') &&
2711 (NXT(4) == 'E') && (NXT(5) == 'M') &&
2712 (NXT(6) == 'E') && (NXT(7) == 'N') &&
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002713 (NXT(8) == 'T')) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002714 SKIP(9);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002715 if (!IS_BLANK(CUR)) {
2716 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2717 ctxt->sax->error(ctxt,
2718 "Space required after 'ELEMENT'\n");
2719 ctxt->wellFormed = 0;
2720 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002721 SKIP_BLANKS;
2722 name = xmlParseName(ctxt);
2723 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002724 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002725 ctxt->sax->error(ctxt,
2726 "xmlParseElementDecl: no name for Element\n");
2727 ctxt->wellFormed = 0;
2728 return(-1);
2729 }
2730 if (!IS_BLANK(CUR)) {
2731 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2732 ctxt->sax->error(ctxt,
2733 "Space required after the element name\n");
2734 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002735 }
2736 SKIP_BLANKS;
2737 if ((CUR == 'E') && (NXT(1) == 'M') &&
2738 (NXT(2) == 'P') && (NXT(3) == 'T') &&
2739 (NXT(4) == 'Y')) {
2740 SKIP(5);
2741 /*
2742 * Element must always be empty.
2743 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002744 ret = XML_ELEMENT_TYPE_EMPTY;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002745 } else if ((CUR == 'A') && (NXT(1) == 'N') &&
2746 (NXT(2) == 'Y')) {
2747 SKIP(3);
2748 /*
2749 * Element is a generic container.
2750 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002751 ret = XML_ELEMENT_TYPE_ANY;
2752 } else if (CUR == '(') {
2753 ret = xmlParseElementContentDecl(ctxt, name, &content);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002754 } else {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002755 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2756 ctxt->sax->error(ctxt,
2757 "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
2758 ctxt->wellFormed = 0;
2759 if (name != NULL) free(name);
2760 return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002761 }
2762 SKIP_BLANKS;
2763 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002764 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2765 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00002766 "xmlParseElementDecl: expected '>' at the end\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002767 ctxt->wellFormed = 0;
2768 } else {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002769 NEXT;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002770 xmlAddElementDecl(ctxt->doc->intSubset, name, ret, content);
2771 }
2772 if (name != NULL) {
2773 free(name);
2774 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00002775 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002776 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002777}
2778
Daniel Veillard11e00581998-10-24 18:27:49 +00002779/**
2780 * xmlParseMarkupDecl:
2781 * @ctxt: an XML parser context
2782 *
2783 * parse Markup declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002784 *
2785 * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
2786 * NotationDecl | PI | Comment
2787 *
2788 * TODO There is a check [ VC: Proper Declaration/PE Nesting ]
2789 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002790void
2791xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002792 xmlParseElementDecl(ctxt);
2793 xmlParseAttributeListDecl(ctxt);
2794 xmlParseEntityDecl(ctxt);
2795 xmlParseNotationDecl(ctxt);
2796 xmlParsePI(ctxt);
2797 xmlParseComment(ctxt, 0);
2798}
2799
Daniel Veillard11e00581998-10-24 18:27:49 +00002800/**
2801 * xmlParseCharRef:
2802 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002803 *
2804 * parse Reference declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002805 *
2806 * [66] CharRef ::= '&#' [0-9]+ ';' |
2807 * '&#x' [0-9a-fA-F]+ ';'
Daniel Veillard11e00581998-10-24 18:27:49 +00002808 * return values: the value parsed
Daniel Veillard260a68f1998-08-13 03:39:55 +00002809 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002810CHAR *
2811xmlParseCharRef(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002812 int val = 0;
2813 CHAR buf[2];
2814
2815 if ((CUR == '&') && (NXT(1) == '#') &&
2816 (NXT(2) == 'x')) {
2817 SKIP(3);
2818 while (CUR != ';') {
2819 if ((CUR >= '0') && (CUR <= '9'))
2820 val = val * 16 + (CUR - '0');
2821 else if ((CUR >= 'a') && (CUR <= 'f'))
2822 val = val * 16 + (CUR - 'a') + 10;
2823 else if ((CUR >= 'A') && (CUR <= 'F'))
2824 val = val * 16 + (CUR - 'A') + 10;
2825 else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002826 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00002827 ctxt->sax->error(ctxt,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002828 "xmlParseCharRef: invalid hexadecimal value\n");
2829 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002830 val = 0;
2831 break;
2832 }
Daniel Veillard845664d1998-08-13 04:43:19 +00002833 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002834 }
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002835 if (CUR == ';')
Daniel Veillard260a68f1998-08-13 03:39:55 +00002836 NEXT;
2837 } else if ((CUR == '&') && (NXT(1) == '#')) {
2838 SKIP(2);
2839 while (CUR != ';') {
2840 if ((CUR >= '0') && (CUR <= '9'))
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002841 val = val * 10 + (CUR - '0');
Daniel Veillard260a68f1998-08-13 03:39:55 +00002842 else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002843 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00002844 ctxt->sax->error(ctxt,
2845 "xmlParseCharRef: invalid decimal value\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002846 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002847 val = 0;
2848 break;
2849 }
Daniel Veillard845664d1998-08-13 04:43:19 +00002850 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002851 }
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002852 if (CUR == ';')
Daniel Veillard260a68f1998-08-13 03:39:55 +00002853 NEXT;
2854 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002855 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2856 ctxt->sax->error(ctxt, "xmlParseCharRef: invalid value\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002857 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002858 }
2859 /*
2860 * Check the value IS_CHAR ...
2861 */
2862 if (IS_CHAR(val)) {
2863 buf[0] = (CHAR) val;
2864 buf[1] = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00002865 return(xmlStrndup(buf, 1));
Daniel Veillard260a68f1998-08-13 03:39:55 +00002866 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002867 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00002868 ctxt->sax->error(ctxt, "xmlParseCharRef: invalid CHAR value %d\n",
2869 val);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002870 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002871 }
2872 return(NULL);
2873}
2874
Daniel Veillard11e00581998-10-24 18:27:49 +00002875/**
2876 * xmlParseEntityRef:
2877 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002878 *
2879 * parse ENTITY references declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002880 *
2881 * [68] EntityRef ::= '&' Name ';'
Daniel Veillardccb09631998-10-27 06:21:04 +00002882 * return values: the entity ref string or NULL if directly as input stream.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002883 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002884CHAR *
2885xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002886 CHAR *ret = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +00002887 const CHAR *q;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002888 CHAR *name;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002889 xmlEntityPtr ent;
Daniel Veillardccb09631998-10-27 06:21:04 +00002890 xmlParserInputPtr input = NULL;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002891
Daniel Veillardccb09631998-10-27 06:21:04 +00002892 q = CUR_PTR;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002893 if (CUR == '&') {
2894 NEXT;
2895 name = xmlParseName(ctxt);
2896 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002897 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2898 ctxt->sax->error(ctxt, "xmlParseEntityRef: no name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002899 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002900 } else {
2901 if (CUR == ';') {
2902 NEXT;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002903 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002904 * Well Formedness Constraint if:
2905 * - standalone
2906 * or
2907 * - no external subset and no external parameter entities
2908 * referenced
2909 * then
2910 * the entity referenced must have been declared
2911 *
2912 * TODO: to be double checked !!!
2913 */
2914 ent = xmlGetDocEntity(ctxt->doc, name);
2915 if ((ctxt->doc->standalone) ||
2916 ((ctxt->doc->intSubset == NULL) &&
2917 (ctxt->doc->extSubset == NULL))) {
2918 if (ent == NULL) {
2919 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2920 ctxt->sax->error(ctxt,
2921 "Entity '%s' not defined\n", name);
2922 ctxt->wellFormed = 0;
2923 }
2924 }
2925
2926 /*
2927 * Well Formedness Constraint :
2928 * The referenced entity must be a parsed entity.
2929 */
2930 if (ent != NULL) {
2931 switch (ent->type) {
2932 case XML_INTERNAL_PARAMETER_ENTITY:
2933 case XML_EXTERNAL_PARAMETER_ENTITY:
2934 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2935 ctxt->sax->error(ctxt,
2936 "Attempt to reference the parameter entity '%s'\n", name);
2937 ctxt->wellFormed = 0;
2938 break;
2939
2940 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
2941 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
2942 ctxt->sax->error(ctxt,
2943 "Attempt to reference unparsed entity '%s'\n", name);
2944 ctxt->wellFormed = 0;
2945 break;
2946 }
2947 }
2948
2949 /*
2950 * Well Formedness Constraint :
2951 * The referenced entity must not lead to recursion !
2952 */
2953
2954 /*
Daniel Veillardccb09631998-10-27 06:21:04 +00002955 * We parsed the entity reference correctly, call SAX
2956 * interface for the proper behaviour:
2957 * - get a new input stream
2958 * - or keep the reference inline
Daniel Veillard260a68f1998-08-13 03:39:55 +00002959 */
Daniel Veillardccb09631998-10-27 06:21:04 +00002960 if (ctxt->sax)
2961 input = ctxt->sax->resolveEntity(ctxt, NULL, name);
2962 if (input != NULL)
2963 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002964 else {
Daniel Veillardccb09631998-10-27 06:21:04 +00002965 ret = xmlStrndup(q, CUR_PTR - q);
Daniel Veillard260a68f1998-08-13 03:39:55 +00002966 }
2967 } else {
2968 char cst[2] = { '&', 0 };
2969
Daniel Veillarde3bffb91998-11-08 14:40:56 +00002970 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002971 ctxt->sax->error(ctxt,
2972 "xmlParseEntityRef: expecting ';'\n");
2973 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00002974 ret = xmlStrndup(cst, 1);
2975 ret = xmlStrcat(ret, name);
2976 }
2977 free(name);
2978 }
2979 }
2980 return(ret);
2981}
2982
Daniel Veillard11e00581998-10-24 18:27:49 +00002983/**
2984 * xmlParseReference:
2985 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00002986 *
2987 * parse Reference declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00002988 *
2989 * [67] Reference ::= EntityRef | CharRef
Daniel Veillardccb09631998-10-27 06:21:04 +00002990 * return values: the entity string or NULL if handled directly by pushing
2991 * the entity value as the input.
Daniel Veillard260a68f1998-08-13 03:39:55 +00002992 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00002993CHAR *
2994xmlParseReference(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00002995 if ((CUR == '&') && (NXT(1) == '#')) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00002996 CHAR *val = xmlParseCharRef(ctxt);
2997 xmlParserInputPtr in;
2998
2999 if (val != NULL) {
3000 in = xmlNewStringInputStream(ctxt, val);
3001 xmlPushInput(ctxt, in);
3002 }
3003 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003004 } else if (CUR == '&') {
Daniel Veillardccb09631998-10-27 06:21:04 +00003005 return(xmlParseEntityRef(ctxt));
Daniel Veillard260a68f1998-08-13 03:39:55 +00003006 }
3007 return(NULL);
3008}
3009
Daniel Veillard11e00581998-10-24 18:27:49 +00003010/**
3011 * xmlParsePEReference:
3012 * @ctxt: an XML parser context
Daniel Veillard11e00581998-10-24 18:27:49 +00003013 *
3014 * parse PEReference declarations
Daniel Veillard260a68f1998-08-13 03:39:55 +00003015 *
3016 * [69] PEReference ::= '%' Name ';'
Daniel Veillardccb09631998-10-27 06:21:04 +00003017 * return values: the entity content or NULL if handled directly.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003018 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003019CHAR *
3020xmlParsePEReference(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003021 CHAR *ret = NULL;
3022 CHAR *name;
3023 xmlEntityPtr entity;
Daniel Veillardccb09631998-10-27 06:21:04 +00003024 xmlParserInputPtr input;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003025
3026 if (CUR == '%') {
3027 NEXT;
3028 name = xmlParseName(ctxt);
3029 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003030 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3031 ctxt->sax->error(ctxt, "xmlParsePEReference: no name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003032 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003033 } else {
3034 if (CUR == ';') {
3035 NEXT;
3036 entity = xmlGetDtdEntity(ctxt->doc, name);
3037 if (entity == NULL) {
Daniel Veillard42dc9b31998-11-09 01:17:21 +00003038 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
3039 ctxt->sax->warning(ctxt,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003040 "xmlParsePEReference: %%%s; not found\n", name);
Daniel Veillardccb09631998-10-27 06:21:04 +00003041 } else {
3042 input = xmlNewEntityInputStream(ctxt, entity);
3043 xmlPushInput(ctxt, input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003044 }
3045 } else {
Daniel Veillardccb09631998-10-27 06:21:04 +00003046 char cst[2] = { '%', 0 };
Daniel Veillard260a68f1998-08-13 03:39:55 +00003047
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003048 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003049 ctxt->sax->error(ctxt,
3050 "xmlParsePEReference: expecting ';'\n");
3051 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003052 ret = xmlStrndup(cst, 1);
3053 ret = xmlStrcat(ret, name);
3054 }
3055 free(name);
3056 }
3057 }
3058 return(ret);
3059}
3060
Daniel Veillard11e00581998-10-24 18:27:49 +00003061/**
3062 * xmlParseDocTypeDecl :
3063 * @ctxt: an XML parser context
3064 *
3065 * parse a DOCTYPE declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003066 *
3067 * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
3068 * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
3069 */
3070
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003071void
3072xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003073 xmlDtdPtr dtd;
3074 CHAR *name;
3075 CHAR *ExternalID = NULL;
3076 CHAR *URI = NULL;
3077
3078 /*
3079 * We know that '<!DOCTYPE' has been detected.
3080 */
3081 SKIP(9);
3082
3083 SKIP_BLANKS;
3084
3085 /*
3086 * Parse the DOCTYPE name.
3087 */
3088 name = xmlParseName(ctxt);
3089 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003090 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3091 ctxt->sax->error(ctxt, "xmlParseDocTypeDecl : no DOCTYPE name !\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003092 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003093 }
3094
3095 SKIP_BLANKS;
3096
3097 /*
3098 * Check for SystemID and ExternalID
3099 */
3100 URI = xmlParseExternalID(ctxt, &ExternalID);
3101 SKIP_BLANKS;
3102
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003103 dtd = xmlCreateIntSubset(ctxt->doc, name, ExternalID, URI);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003104
3105 /*
3106 * Is there any DTD definition ?
3107 */
3108 if (CUR == '[') {
3109 NEXT;
3110 /*
3111 * Parse the succession of Markup declarations and
3112 * PEReferences.
3113 * Subsequence (markupdecl | PEReference | S)*
3114 */
3115 while (CUR != ']') {
3116 const CHAR *check = CUR_PTR;
3117
3118 SKIP_BLANKS;
3119 xmlParseMarkupDecl(ctxt);
Daniel Veillardccb09631998-10-27 06:21:04 +00003120 xmlParsePEReference(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003121
3122 if (CUR_PTR == check) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003123 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3124 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003125 "xmlParseDocTypeDecl: error detected in Markup declaration\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003126 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003127 break;
3128 }
3129 }
3130 if (CUR == ']') NEXT;
3131 }
3132
3133 /*
3134 * We should be at the end of the DOCTYPE declaration.
3135 */
3136 if (CUR != '>') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003137 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3138 ctxt->sax->error(ctxt, "DOCTYPE unproperly terminated\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003139 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003140 /* We shouldn't try to resynchronize ... */
3141 }
3142 NEXT;
3143
3144 /*
3145 * Cleanup, since we don't use all those identifiers
3146 * TODO : the DOCTYPE if available should be stored !
3147 */
3148 if (URI != NULL) free(URI);
3149 if (ExternalID != NULL) free(ExternalID);
3150 if (name != NULL) free(name);
3151}
3152
Daniel Veillard11e00581998-10-24 18:27:49 +00003153/**
3154 * xmlParseAttribute:
3155 * @ctxt: an XML parser context
3156 * @node: the node carrying the attribute
3157 *
3158 * parse an attribute
Daniel Veillard260a68f1998-08-13 03:39:55 +00003159 *
3160 * [41] Attribute ::= Name Eq AttValue
3161 *
3162 * [25] Eq ::= S? '=' S?
3163 *
3164 * With namespace:
3165 *
3166 * [NS 11] Attribute ::= QName Eq AttValue
3167 *
3168 * Also the case QName == xmlns:??? is handled independently as a namespace
3169 * definition.
3170 */
3171
Daniel Veillardccb09631998-10-27 06:21:04 +00003172xmlAttrPtr xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003173 CHAR *name, *val;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003174 CHAR *ns;
Daniel Veillardccb09631998-10-27 06:21:04 +00003175 CHAR *value = NULL;
3176 xmlAttrPtr ret;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003177
3178 name = xmlNamespaceParseQName(ctxt, &ns);
3179 if (name == NULL) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003180 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3181 ctxt->sax->error(ctxt, "error parsing attribute name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003182 ctxt->wellFormed = 0;
Daniel Veillardccb09631998-10-27 06:21:04 +00003183 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003184 }
3185
3186 /*
3187 * read the value
3188 */
3189 SKIP_BLANKS;
3190 if (CUR == '=') {
3191 NEXT;
3192 SKIP_BLANKS;
3193 value = xmlParseAttValue(ctxt);
3194 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003195 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003196 ctxt->sax->error(ctxt,
3197 "Specification mandate value for attribute %s\n", name);
3198 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003199 }
3200
3201 /*
3202 * Check whether it's a namespace definition
3203 */
3204 if ((ns == NULL) &&
3205 (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
3206 (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
3207 /* a default namespace definition */
3208 xmlNewNs(node, value, NULL);
3209 if (name != NULL)
3210 free(name);
3211 if (value != NULL)
3212 free(value);
Daniel Veillardccb09631998-10-27 06:21:04 +00003213 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003214 }
3215 if ((ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
3216 (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
3217 /* a standard namespace definition */
3218 xmlNewNs(node, value, name);
Daniel Veillardccb09631998-10-27 06:21:04 +00003219 free(ns);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003220 if (name != NULL)
3221 free(name);
3222 if (value != NULL)
3223 free(value);
Daniel Veillardccb09631998-10-27 06:21:04 +00003224 return(NULL);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003225 }
3226
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003227 /*
3228 * Well formedness requires at most one declaration of an attribute
3229 */
3230 if ((val = xmlGetProp(ctxt->node, name)) != NULL) {
3231 free(val);
3232 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3233 ctxt->sax->error(ctxt, "Attribute %s redefined\n", name);
3234 ctxt->wellFormed = 0;
3235 ret = NULL;
3236 } else {
3237 ret = xmlNewProp(ctxt->node, name, NULL);
3238 if (ret != NULL)
3239 ret->val = xmlStringGetNodeList(ctxt->doc, value);
3240 }
Daniel Veillardccb09631998-10-27 06:21:04 +00003241
3242 if (ns != NULL)
3243 free(ns);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003244 if (value != NULL)
Daniel Veillardccb09631998-10-27 06:21:04 +00003245 free(value);
3246 free(name);
3247 return(ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003248}
3249
Daniel Veillard11e00581998-10-24 18:27:49 +00003250/**
3251 * xmlParseStartTag:
3252 * @ctxt: an XML parser context
3253 *
3254 * parse a start of tag either for rule element or
3255 * EmptyElement. In both case we don't parse the tag closing chars.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003256 *
3257 * [40] STag ::= '<' Name (S Attribute)* S? '>'
3258 *
3259 * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
3260 *
3261 * With namespace:
3262 *
3263 * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
3264 *
3265 * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
Daniel Veillard11e00581998-10-24 18:27:49 +00003266 *
3267 * return values: the XML new node or NULL.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003268 */
3269
3270xmlNodePtr xmlParseStartTag(xmlParserCtxtPtr ctxt) {
3271 CHAR *namespace, *name;
3272 xmlNsPtr ns = NULL;
3273 xmlNodePtr ret = NULL;
Daniel Veillardccb09631998-10-27 06:21:04 +00003274 xmlNodePtr parent = ctxt->node;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003275
3276 if (CUR != '<') return(NULL);
3277 NEXT;
3278
3279 name = xmlNamespaceParseQName(ctxt, &namespace);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003280 if (name == NULL) {
3281 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3282 ctxt->sax->error(ctxt,
3283 "xmlParseStartTag: invalid element name\n");
3284 ctxt->wellFormed = 0;
3285 return(NULL);
3286 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003287
3288 /*
3289 * Note : the namespace resolution is deferred until the end of the
3290 * attributes parsing, since local namespace can be defined as
3291 * an attribute at this level.
3292 */
Daniel Veillard0bef1311998-10-14 02:36:47 +00003293 ret = xmlNewDocNode(ctxt->doc, ns, name, NULL);
Daniel Veillardccb09631998-10-27 06:21:04 +00003294 if (ret == NULL) {
3295 if (namespace != NULL)
3296 free(namespace);
3297 free(name);
3298 return(NULL);
3299 }
3300
3301 /*
3302 * We are parsing a new node.
3303 */
3304 nodePush(ctxt, ret);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003305
3306 /*
3307 * Now parse the attributes, it ends up with the ending
3308 *
3309 * (S Attribute)* S?
3310 */
3311 SKIP_BLANKS;
3312 while ((IS_CHAR(CUR)) &&
3313 (CUR != '>') &&
3314 ((CUR != '/') || (NXT(1) != '>'))) {
3315 const CHAR *q = CUR_PTR;
3316
3317 xmlParseAttribute(ctxt, ret);
3318 SKIP_BLANKS;
3319
3320 if (q == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003321 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3322 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003323 "xmlParseStartTag: problem parsing attributes\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003324 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003325 break;
3326 }
3327 }
3328
3329 /*
3330 * Search the namespace
3331 */
3332 ns = xmlSearchNs(ctxt->doc, ret, namespace);
3333 if (ns == NULL) /* ret still doesn't have a parent yet ! */
Daniel Veillardccb09631998-10-27 06:21:04 +00003334 ns = xmlSearchNs(ctxt->doc, parent, namespace);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003335 xmlSetNs(ret, ns);
3336 if (namespace != NULL)
3337 free(namespace);
3338
3339 /*
Daniel Veillard260a68f1998-08-13 03:39:55 +00003340 * SAX: Start of Element !
3341 */
3342 if (ctxt->sax != NULL)
3343 ctxt->sax->startElement(ctxt, name);
Daniel Veillardccb09631998-10-27 06:21:04 +00003344 free(name);
3345
3346 /*
3347 * Link the child element
3348 */
3349 if (ctxt->nodeNr < 2) return(ret);
3350 parent = ctxt->nodeTab[ctxt->nodeNr - 2];
3351 if (parent != NULL)
3352 xmlAddChild(parent, ctxt->node);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003353
3354 return(ret);
3355}
3356
Daniel Veillard11e00581998-10-24 18:27:49 +00003357/**
3358 * xmlParseEndTag:
3359 * @ctxt: an XML parser context
3360 * @nsPtr: the current node namespace definition
3361 * @tagPtr: CHAR** receive the tag value
3362 *
3363 * parse an end of tag
Daniel Veillard260a68f1998-08-13 03:39:55 +00003364 *
3365 * [42] ETag ::= '</' Name S? '>'
3366 *
3367 * With namespace
3368 *
3369 * [9] ETag ::= '</' QName S? '>'
Daniel Veillard11e00581998-10-24 18:27:49 +00003370 *
3371 * return values: tagPtr receive the tag name just read
Daniel Veillard260a68f1998-08-13 03:39:55 +00003372 */
3373
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003374void
3375xmlParseEndTag(xmlParserCtxtPtr ctxt, xmlNsPtr *nsPtr, CHAR **tagPtr) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003376 CHAR *namespace, *name;
3377 xmlNsPtr ns = NULL;
3378
3379 *nsPtr = NULL;
3380 *tagPtr = NULL;
3381
3382 if ((CUR != '<') || (NXT(1) != '/')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003383 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3384 ctxt->sax->error(ctxt, "xmlParseEndTag: '</' not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003385 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003386 return;
3387 }
3388 SKIP(2);
3389
3390 name = xmlNamespaceParseQName(ctxt, &namespace);
3391
3392 /*
3393 * Search the namespace
3394 */
3395 ns = xmlSearchNs(ctxt->doc, ctxt->node, namespace);
3396 if (namespace != NULL)
3397 free(namespace);
3398
3399 *nsPtr = ns;
3400 *tagPtr = name;
3401
3402 /*
3403 * We should definitely be at the ending "S? '>'" part
3404 */
3405 SKIP_BLANKS;
3406 if ((!IS_CHAR(CUR)) || (CUR != '>')) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003407 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3408 ctxt->sax->error(ctxt, "End tag : expected '>'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003409 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003410 } else
3411 NEXT;
3412
3413 return;
3414}
3415
Daniel Veillard11e00581998-10-24 18:27:49 +00003416/**
3417 * xmlParseCDSect:
3418 * @ctxt: an XML parser context
3419 *
3420 * Parse escaped pure raw content.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003421 *
3422 * [18] CDSect ::= CDStart CData CDEnd
3423 *
3424 * [19] CDStart ::= '<![CDATA['
3425 *
3426 * [20] Data ::= (Char* - (Char* ']]>' Char*))
3427 *
3428 * [21] CDEnd ::= ']]>'
3429 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003430void
3431xmlParseCDSect(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003432 const CHAR *r, *s, *base;
3433
3434 if ((CUR == '<') && (NXT(1) == '!') &&
3435 (NXT(2) == '[') && (NXT(3) == 'C') &&
3436 (NXT(4) == 'D') && (NXT(5) == 'A') &&
3437 (NXT(6) == 'T') && (NXT(7) == 'A') &&
3438 (NXT(8) == '[')) {
3439 SKIP(9);
3440 } else
3441 return;
3442 base = CUR_PTR;
3443 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003444 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3445 ctxt->sax->error(ctxt, "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003446 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003447 return;
3448 }
3449 r = NEXT;
3450 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003451 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3452 ctxt->sax->error(ctxt, "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003453 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003454 return;
3455 }
3456 s = NEXT;
3457 while (IS_CHAR(CUR) &&
3458 ((*r != ']') || (*s != ']') || (CUR != '>'))) {
3459 r++;s++;NEXT;
3460 }
3461 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003462 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3463 ctxt->sax->error(ctxt, "CData section not finished\n%.50s\n", base);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003464 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003465 return;
3466 }
3467
3468 /*
3469 * Ok the segment [base CUR_PTR] is to be consumed as chars.
3470 */
3471 if (ctxt->sax != NULL) {
3472 if (areBlanks(ctxt, base, CUR_PTR - base))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003473 ctxt->sax->ignorableWhitespace(ctxt, base, 0, (CUR_PTR - base) - 2);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003474 else
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003475 ctxt->sax->characters(ctxt, base, 0, (CUR_PTR - base) - 2);
Daniel Veillard260a68f1998-08-13 03:39:55 +00003476 }
3477}
3478
Daniel Veillard11e00581998-10-24 18:27:49 +00003479/**
3480 * xmlParseContent:
3481 * @ctxt: an XML parser context
3482 *
3483 * Parse a content:
Daniel Veillard260a68f1998-08-13 03:39:55 +00003484 *
3485 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
3486 */
3487
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003488void
3489xmlParseContent(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003490 xmlNodePtr ret = NULL;
3491
3492 while ((CUR != '<') || (NXT(1) != '/')) {
3493 const CHAR *test = CUR_PTR;
3494 ret = NULL;
3495
3496 /*
3497 * First case : a Processing Instruction.
3498 */
3499 if ((CUR == '<') && (NXT(1) == '?')) {
3500 xmlParsePI(ctxt);
3501 }
3502 /*
3503 * Second case : a CDSection
3504 */
3505 else if ((CUR == '<') && (NXT(1) == '!') &&
3506 (NXT(2) == '[') && (NXT(3) == 'C') &&
3507 (NXT(4) == 'D') && (NXT(5) == 'A') &&
3508 (NXT(6) == 'T') && (NXT(7) == 'A') &&
3509 (NXT(8) == '[')) {
3510 xmlParseCDSect(ctxt);
3511 }
3512 /*
3513 * Third case : a comment
3514 */
3515 else if ((CUR == '<') && (NXT(1) == '!') &&
3516 (NXT(2) == '-') && (NXT(3) == '-')) {
3517 ret = xmlParseComment(ctxt, 1);
3518 }
3519 /*
3520 * Fourth case : a sub-element.
3521 */
3522 else if (CUR == '<') {
3523 ret = xmlParseElement(ctxt);
3524 }
3525 /*
Daniel Veillardccb09631998-10-27 06:21:04 +00003526 * Fifth case : a reference. If if has not been resolved,
3527 * parsing returns it's Name, create the node
Daniel Veillard260a68f1998-08-13 03:39:55 +00003528 */
3529 else if (CUR == '&') {
Daniel Veillardccb09631998-10-27 06:21:04 +00003530 CHAR *val = xmlParseReference(ctxt);
3531 if (val != NULL) {
3532 if (val[0] != '&') {
3533 /*
3534 * inline predefined entity.
3535 */
3536 if (ctxt->sax != NULL)
3537 ctxt->sax->characters(ctxt, val, 0, xmlStrlen(val));
3538 } else {
3539 /*
3540 * user defined entity, create a node.
3541 */
3542 ret = xmlNewReference(ctxt->doc, val);
3543 xmlAddChild(ctxt->node, ret);
3544 }
3545 free(val);
3546 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003547 }
3548 /*
3549 * Last case, text. Note that References are handled directly.
3550 */
3551 else {
3552 xmlParseCharData(ctxt, 0);
3553 }
3554
3555 /*
3556 * Pop-up of finished entities.
3557 */
3558 while ((CUR == 0) && (ctxt->inputNr > 1)) xmlPopInput(ctxt);
3559
3560 if (test == CUR_PTR) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003561 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003562 ctxt->sax->error(ctxt,
3563 "detected an error in element content\n");
3564 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003565 break;
3566 }
3567 }
3568}
3569
Daniel Veillard11e00581998-10-24 18:27:49 +00003570/**
3571 * xmlParseElement:
3572 * @ctxt: an XML parser context
3573 *
3574 * parse an XML element, this is highly recursive
Daniel Veillard260a68f1998-08-13 03:39:55 +00003575 *
3576 * [39] element ::= EmptyElemTag | STag content ETag
3577 *
3578 * [41] Attribute ::= Name Eq AttValue
Daniel Veillard11e00581998-10-24 18:27:49 +00003579 * return values: the XML new node or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003580 */
3581
3582
3583xmlNodePtr xmlParseElement(xmlParserCtxtPtr ctxt) {
3584 xmlNodePtr ret;
3585 const CHAR *openTag = CUR_PTR;
3586 xmlParserNodeInfo node_info;
3587 CHAR *endTag;
3588 xmlNsPtr endNs;
3589
3590 /* Capture start position */
3591 node_info.begin_pos = CUR_PTR - ctxt->input->base;
3592 node_info.begin_line = ctxt->input->line;
3593
3594 ret = xmlParseStartTag(ctxt);
3595 if (ret == NULL) {
3596 return(NULL);
3597 }
3598
3599 /*
3600 * Check for an Empty Element.
3601 */
3602 if ((CUR == '/') && (NXT(1) == '>')) {
3603 SKIP(2);
3604 if (ctxt->sax != NULL)
3605 ctxt->sax->endElement(ctxt, ret->name);
3606
3607 /*
3608 * end of parsing of this node.
3609 */
3610 nodePop(ctxt);
3611
3612 return(ret);
3613 }
3614 if (CUR == '>') NEXT;
3615 else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003616 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard242590e1998-11-13 18:04:35 +00003617 ctxt->sax->error(ctxt, "Couldn't find end of Start Tag\n%.30s\n",
3618 openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003619 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003620
3621 /*
3622 * end of parsing of this node.
3623 */
3624 nodePop(ctxt);
3625
3626 return(NULL);
3627 }
3628
3629 /*
3630 * Parse the content of the element:
3631 */
3632 xmlParseContent(ctxt);
3633 if (!IS_CHAR(CUR)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003634 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard242590e1998-11-13 18:04:35 +00003635 ctxt->sax->error(ctxt,
3636 "Premature end of data in tag %.30s\n", openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003637 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003638
3639 /*
3640 * end of parsing of this node.
3641 */
3642 nodePop(ctxt);
3643
3644 return(NULL);
3645 }
3646
3647 /*
3648 * parse the end of tag: '</' should be here.
3649 */
3650 xmlParseEndTag(ctxt, &endNs, &endTag);
3651
3652 /*
3653 * Check that the Name in the ETag is the same as in the STag.
3654 */
3655 if (endNs != ret->ns) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003656 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3657 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003658 "Start and End tags don't use the same namespace\n%.30s\n%.30s\n",
3659 openTag, endTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003660 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003661 }
3662 if (endTag == NULL ) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003663 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3664 ctxt->sax->error(ctxt, "The End tag has no name\n%.30s\n", openTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003665 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003666 } else if (xmlStrcmp(ret->name, endTag)) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003667 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3668 ctxt->sax->error(ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00003669 "Start and End tags don't use the same name\n%.30s\n%.30s\n",
3670 openTag, endTag);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003671 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003672 }
3673 /*
3674 * SAX: End of Tag
3675 */
3676 else if (ctxt->sax != NULL)
3677 ctxt->sax->endElement(ctxt, endTag);
3678
3679 if (endTag != NULL)
3680 free(endTag);
3681
3682 /* Capture end position and add node */
3683 if ( ret != NULL && ctxt->record_info ) {
3684 node_info.end_pos = CUR_PTR - ctxt->input->base;
3685 node_info.end_line = ctxt->input->line;
3686 node_info.node = ret;
3687 xmlParserAddNodeInfo(ctxt, &node_info);
3688 }
3689
3690 /*
3691 * end of parsing of this node.
3692 */
3693 nodePop(ctxt);
3694
3695 return(ret);
3696}
3697
Daniel Veillard11e00581998-10-24 18:27:49 +00003698/**
3699 * xmlParseVersionNum:
3700 * @ctxt: an XML parser context
3701 *
3702 * parse the XML version value.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003703 *
3704 * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
Daniel Veillard11e00581998-10-24 18:27:49 +00003705 * return values: the string giving the XML version number, or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003706 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003707CHAR *
3708xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003709 const CHAR *q = CUR_PTR;
3710 CHAR *ret;
3711
3712 while (IS_CHAR(CUR) &&
3713 (((CUR >= 'a') && (CUR <= 'z')) ||
3714 ((CUR >= 'A') && (CUR <= 'Z')) ||
3715 ((CUR >= '0') && (CUR <= '9')) ||
3716 (CUR == '_') || (CUR == '.') ||
3717 (CUR == ':') || (CUR == '-'))) NEXT;
3718 ret = xmlStrndup(q, CUR_PTR - q);
3719 return(ret);
3720}
3721
Daniel Veillard11e00581998-10-24 18:27:49 +00003722/**
3723 * xmlParseVersionInfo:
3724 * @ctxt: an XML parser context
3725 *
3726 * parse the XML version.
Daniel Veillard260a68f1998-08-13 03:39:55 +00003727 *
3728 * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
3729 *
3730 * [25] Eq ::= S? '=' S?
Daniel Veillard11e00581998-10-24 18:27:49 +00003731 *
3732 * return values: the version string, e.g. "1.0"
Daniel Veillard260a68f1998-08-13 03:39:55 +00003733 */
3734
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003735CHAR *
3736xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003737 CHAR *version = NULL;
3738 const CHAR *q;
3739
3740 if ((CUR == 'v') && (NXT(1) == 'e') &&
3741 (NXT(2) == 'r') && (NXT(3) == 's') &&
3742 (NXT(4) == 'i') && (NXT(5) == 'o') &&
3743 (NXT(6) == 'n')) {
3744 SKIP(7);
3745 SKIP_BLANKS;
3746 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003747 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3748 ctxt->sax->error(ctxt, "xmlParseVersionInfo : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003749 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003750 return(NULL);
3751 }
3752 NEXT;
3753 SKIP_BLANKS;
3754 if (CUR == '"') {
3755 NEXT;
3756 q = CUR_PTR;
3757 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003758 if (CUR != '"') {
3759 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3760 ctxt->sax->error(ctxt, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003761 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003762 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003763 NEXT;
3764 } else if (CUR == '\''){
3765 NEXT;
3766 q = CUR_PTR;
3767 version = xmlParseVersionNum(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003768 if (CUR != '\'') {
3769 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3770 ctxt->sax->error(ctxt, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003771 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003772 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003773 NEXT;
3774 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003775 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003776 ctxt->sax->error(ctxt,
3777 "xmlParseVersionInfo : expected ' or \"\n");
3778 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003779 }
3780 }
3781 return(version);
3782}
3783
Daniel Veillard11e00581998-10-24 18:27:49 +00003784/**
3785 * xmlParseEncName:
3786 * @ctxt: an XML parser context
3787 *
3788 * parse the XML encoding name
Daniel Veillard260a68f1998-08-13 03:39:55 +00003789 *
3790 * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
Daniel Veillard11e00581998-10-24 18:27:49 +00003791 *
3792 * return values: the encoding name value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003793 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003794CHAR *
3795xmlParseEncName(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003796 const CHAR *q = CUR_PTR;
3797 CHAR *ret = NULL;
3798
3799 if (((CUR >= 'a') && (CUR <= 'z')) ||
3800 ((CUR >= 'A') && (CUR <= 'Z'))) {
3801 NEXT;
3802 while (IS_CHAR(CUR) &&
3803 (((CUR >= 'a') && (CUR <= 'z')) ||
3804 ((CUR >= 'A') && (CUR <= 'Z')) ||
3805 ((CUR >= '0') && (CUR <= '9')) ||
3806 (CUR == '-'))) NEXT;
3807 ret = xmlStrndup(q, CUR_PTR - q);
3808 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003809 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3810 ctxt->sax->error(ctxt, "Invalid XML encoding name\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003811 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003812 }
3813 return(ret);
3814}
3815
Daniel Veillard11e00581998-10-24 18:27:49 +00003816/**
3817 * xmlParseEncodingDecl:
3818 * @ctxt: an XML parser context
3819 *
3820 * parse the XML encoding declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003821 *
3822 * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'")
Daniel Veillard11e00581998-10-24 18:27:49 +00003823 *
3824 * TODO: this should setup the conversion filters.
3825 *
3826 * return values: the encoding value or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00003827 */
3828
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003829CHAR *
3830xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003831 CHAR *encoding = NULL;
3832 const CHAR *q;
3833
3834 SKIP_BLANKS;
3835 if ((CUR == 'e') && (NXT(1) == 'n') &&
3836 (NXT(2) == 'c') && (NXT(3) == 'o') &&
3837 (NXT(4) == 'd') && (NXT(5) == 'i') &&
3838 (NXT(6) == 'n') && (NXT(7) == 'g')) {
3839 SKIP(8);
3840 SKIP_BLANKS;
3841 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003842 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3843 ctxt->sax->error(ctxt, "xmlParseEncodingDecl : expected '='\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003844 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003845 return(NULL);
3846 }
3847 NEXT;
3848 SKIP_BLANKS;
3849 if (CUR == '"') {
3850 NEXT;
3851 q = CUR_PTR;
3852 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003853 if (CUR != '"') {
3854 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3855 ctxt->sax->error(ctxt, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003856 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003857 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003858 NEXT;
3859 } else if (CUR == '\''){
3860 NEXT;
3861 q = CUR_PTR;
3862 encoding = xmlParseEncName(ctxt);
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003863 if (CUR != '\'') {
3864 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3865 ctxt->sax->error(ctxt, "String not closed\n%.50s\n", q);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003866 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003867 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003868 NEXT;
3869 } else if (CUR == '"'){
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003870 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003871 ctxt->sax->error(ctxt,
3872 "xmlParseEncodingDecl : expected ' or \"\n");
3873 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003874 }
3875 }
3876 return(encoding);
3877}
3878
Daniel Veillard11e00581998-10-24 18:27:49 +00003879/**
3880 * xmlParseSDDecl:
3881 * @ctxt: an XML parser context
3882 *
3883 * parse the XML standalone declaration
Daniel Veillard260a68f1998-08-13 03:39:55 +00003884 *
3885 * [32] SDDecl ::= S 'standalone' Eq
3886 * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"'))
Daniel Veillard11e00581998-10-24 18:27:49 +00003887 * return values: 1 if standalone, 0 otherwise
Daniel Veillard260a68f1998-08-13 03:39:55 +00003888 */
3889
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003890int
3891xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003892 int standalone = -1;
3893
3894 SKIP_BLANKS;
3895 if ((CUR == 's') && (NXT(1) == 't') &&
3896 (NXT(2) == 'a') && (NXT(3) == 'n') &&
3897 (NXT(4) == 'd') && (NXT(5) == 'a') &&
3898 (NXT(6) == 'l') && (NXT(7) == 'o') &&
3899 (NXT(8) == 'n') && (NXT(9) == 'e')) {
3900 SKIP(10);
3901 if (CUR != '=') {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003902 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003903 ctxt->sax->error(ctxt,
3904 "XML standalone declaration : expected '='\n");
3905 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003906 return(standalone);
3907 }
3908 NEXT;
3909 SKIP_BLANKS;
3910 if (CUR == '\''){
3911 NEXT;
3912 if ((CUR == 'n') && (NXT(1) == 'o')) {
3913 standalone = 0;
3914 SKIP(2);
3915 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
3916 (NXT(2) == 's')) {
3917 standalone = 1;
3918 SKIP(3);
3919 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003920 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3921 ctxt->sax->error(ctxt, "standalone accepts only 'yes' or 'no'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003922 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003923 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003924 if (CUR != '\'') {
3925 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3926 ctxt->sax->error(ctxt, "String not closed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003927 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003928 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003929 NEXT;
3930 } else if (CUR == '"'){
3931 NEXT;
3932 if ((CUR == 'n') && (NXT(1) == 'o')) {
3933 standalone = 0;
3934 SKIP(2);
3935 } else if ((CUR == 'y') && (NXT(1) == 'e') &&
3936 (NXT(2) == 's')) {
3937 standalone = 1;
3938 SKIP(3);
3939 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003940 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003941 ctxt->sax->error(ctxt,
3942 "standalone accepts only 'yes' or 'no'\n");
3943 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003944 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003945 if (CUR != '"') {
3946 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3947 ctxt->sax->error(ctxt, "String not closed\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003948 ctxt->wellFormed = 0;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003949 } else
Daniel Veillard260a68f1998-08-13 03:39:55 +00003950 NEXT;
3951 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00003952 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3953 ctxt->sax->error(ctxt, "Standalone value not found\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003954 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00003955 }
3956 }
3957 return(standalone);
3958}
3959
Daniel Veillard11e00581998-10-24 18:27:49 +00003960/**
3961 * xmlParseXMLDecl:
3962 * @ctxt: an XML parser context
3963 *
3964 * parse an XML declaration header
Daniel Veillard260a68f1998-08-13 03:39:55 +00003965 *
3966 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
3967 */
3968
Daniel Veillard0ba4d531998-11-01 19:34:31 +00003969void
3970xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00003971 CHAR *version;
3972
3973 /*
3974 * We know that '<?xml' is here.
3975 */
3976 SKIP(5);
3977
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003978 if (!IS_BLANK(CUR)) {
3979 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
3980 ctxt->sax->error(ctxt, "Blank needed after '<?xml'\n");
3981 ctxt->wellFormed = 0;
3982 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00003983 SKIP_BLANKS;
3984
3985 /*
3986 * We should have the VersionInfo here.
3987 */
3988 version = xmlParseVersionInfo(ctxt);
3989 if (version == NULL)
3990 version = xmlCharStrdup(XML_DEFAULT_VERSION);
3991 ctxt->doc = xmlNewDoc(version);
3992 free(version);
3993
3994 /*
3995 * We may have the encoding declaration
3996 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00003997 if (!IS_BLANK(CUR)) {
3998 if ((CUR == '?') && (NXT(1) == '>')) {
3999 SKIP(2);
4000 return;
4001 }
4002 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4003 ctxt->sax->error(ctxt, "Blank needed here\n");
4004 ctxt->wellFormed = 0;
4005 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004006 ctxt->doc->encoding = xmlParseEncodingDecl(ctxt);
4007
4008 /*
4009 * We may have the standalone status.
4010 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004011 if ((ctxt->doc->encoding != NULL) && (!IS_BLANK(CUR))) {
4012 if ((CUR == '?') && (NXT(1) == '>')) {
4013 SKIP(2);
4014 return;
4015 }
4016 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4017 ctxt->sax->error(ctxt, "Blank needed here\n");
4018 ctxt->wellFormed = 0;
4019 }
4020 SKIP_BLANKS;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004021 ctxt->doc->standalone = xmlParseSDDecl(ctxt);
4022
4023 SKIP_BLANKS;
4024 if ((CUR == '?') && (NXT(1) == '>')) {
4025 SKIP(2);
4026 } else if (CUR == '>') {
4027 /* Deprecated old WD ... */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004028 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4029 ctxt->sax->error(ctxt, "XML declaration must end-up with '?>'\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004030 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004031 NEXT;
4032 } else {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004033 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4034 ctxt->sax->error(ctxt, "parsing XML declaration: '?>' expected\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004035 ctxt->wellFormed = 0;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004036 MOVETO_ENDTAG(CUR_PTR);
4037 NEXT;
4038 }
4039}
4040
Daniel Veillard11e00581998-10-24 18:27:49 +00004041/**
4042 * xmlParseMisc:
4043 * @ctxt: an XML parser context
4044 *
4045 * parse an XML Misc* optionnal field.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004046 *
4047 * [27] Misc ::= Comment | PI | S
4048 */
4049
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004050void
4051xmlParseMisc(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004052 while (((CUR == '<') && (NXT(1) == '?')) ||
4053 ((CUR == '<') && (NXT(1) == '!') &&
4054 (NXT(2) == '-') && (NXT(3) == '-')) ||
4055 IS_BLANK(CUR)) {
4056 if ((CUR == '<') && (NXT(1) == '?')) {
4057 xmlParsePI(ctxt);
4058 } else if (IS_BLANK(CUR)) {
4059 NEXT;
4060 } else
4061 xmlParseComment(ctxt, 0);
4062 }
4063}
4064
Daniel Veillard11e00581998-10-24 18:27:49 +00004065/**
4066 * xmlParseDocument :
4067 * @ctxt: an XML parser context
4068 *
4069 * parse an XML document (and build a tree if using the standard SAX
4070 * interface).
Daniel Veillard260a68f1998-08-13 03:39:55 +00004071 *
4072 * [1] document ::= prolog element Misc*
4073 *
4074 * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
Daniel Veillard11e00581998-10-24 18:27:49 +00004075 *
4076 * return values: 0, -1 in case of error. the parser context is augmented
4077 * as a result of the parsing.
Daniel Veillard260a68f1998-08-13 03:39:55 +00004078 */
4079
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004080int
4081xmlParseDocument(xmlParserCtxtPtr ctxt) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004082 xmlDefaultSAXHandlerInit();
4083
4084 /*
4085 * SAX: beginning of the document processing.
4086 */
4087 if (ctxt->sax)
4088 ctxt->sax->setDocumentLocator(ctxt, &xmlDefaultSAXLocator);
4089 if (ctxt->sax)
4090 ctxt->sax->startDocument(ctxt);
4091
4092 /*
4093 * We should check for encoding here and plug-in some
4094 * conversion code TODO !!!!
4095 */
4096
4097 /*
4098 * Wipe out everything which is before the first '<'
4099 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004100 if (IS_BLANK(CUR)) {
4101 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4102 ctxt->sax->error(ctxt,
4103 "Extra spaces at the beginning of the document are not allowed\n");
4104 ctxt->wellFormed = 0;
4105 SKIP_BLANKS;
4106 }
4107
4108 if (CUR == 0) {
4109 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4110 ctxt->sax->error(ctxt, "Document is empty\n");
4111 ctxt->wellFormed = 0;
4112 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004113
4114 /*
4115 * Check for the XMLDecl in the Prolog.
4116 */
4117 if ((CUR == '<') && (NXT(1) == '?') &&
4118 (NXT(2) == 'x') && (NXT(3) == 'm') &&
4119 (NXT(4) == 'l')) {
4120 xmlParseXMLDecl(ctxt);
4121 /* SKIP_EOL(cur); */
4122 SKIP_BLANKS;
4123 } else if ((CUR == '<') && (NXT(1) == '?') &&
4124 (NXT(2) == 'X') && (NXT(3) == 'M') &&
4125 (NXT(4) == 'L')) {
4126 /*
4127 * The first drafts were using <?XML and the final W3C REC
4128 * now use <?xml ...
4129 */
4130 xmlParseXMLDecl(ctxt);
4131 /* SKIP_EOL(cur); */
4132 SKIP_BLANKS;
4133 } else {
4134 CHAR *version;
4135
4136 version = xmlCharStrdup(XML_DEFAULT_VERSION);
4137 ctxt->doc = xmlNewDoc(version);
4138 free(version);
4139 }
4140
4141 /*
4142 * The Misc part of the Prolog
4143 */
4144 xmlParseMisc(ctxt);
4145
4146 /*
4147 * Then possibly doc type declaration(s) and more Misc
4148 * (doctypedecl Misc*)?
4149 */
4150 if ((CUR == '<') && (NXT(1) == '!') &&
4151 (NXT(2) == 'D') && (NXT(3) == 'O') &&
4152 (NXT(4) == 'C') && (NXT(5) == 'T') &&
4153 (NXT(6) == 'Y') && (NXT(7) == 'P') &&
4154 (NXT(8) == 'E')) {
4155 xmlParseDocTypeDecl(ctxt);
4156 xmlParseMisc(ctxt);
4157 }
4158
4159 /*
4160 * Time to start parsing the tree itself
4161 */
4162 ctxt->doc->root = xmlParseElement(ctxt);
4163
4164 /*
4165 * The Misc part at the end
4166 */
4167 xmlParseMisc(ctxt);
4168
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004169 if (CUR != 0) {
4170 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
4171 ctxt->sax->error(ctxt,
4172 "Extra content at the end of the document\n");
4173 ctxt->wellFormed = 0;
4174 }
4175
Daniel Veillard260a68f1998-08-13 03:39:55 +00004176 /*
4177 * SAX: end of the document processing.
4178 */
4179 if (ctxt->sax)
4180 ctxt->sax->endDocument(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004181 if (! ctxt->wellFormed) return(-1);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004182 return(0);
4183}
4184
Daniel Veillard11e00581998-10-24 18:27:49 +00004185/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004186 * xmlSAXParseDoc :
4187 * @sax: the SAX handler block
Daniel Veillard11e00581998-10-24 18:27:49 +00004188 * @cur: a pointer to an array of CHAR
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004189 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4190 * documents
Daniel Veillard11e00581998-10-24 18:27:49 +00004191 *
4192 * parse an XML in-memory document and build a tree.
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004193 * It use the given SAX function block to handle the parsing callback.
4194 * If sax is NULL, fallback to the default DOM tree building routines.
Daniel Veillard11e00581998-10-24 18:27:49 +00004195 *
4196 * return values: the resulting document tree
Daniel Veillard260a68f1998-08-13 03:39:55 +00004197 */
4198
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004199xmlDocPtr xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur, int recovery) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004200 xmlDocPtr ret;
4201 xmlParserCtxtPtr ctxt;
4202 xmlParserInputPtr input;
4203
4204 if (cur == NULL) return(NULL);
4205
4206 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4207 if (ctxt == NULL) {
4208 perror("malloc");
4209 return(NULL);
4210 }
4211 xmlInitParserCtxt(ctxt);
Daniel Veillard242590e1998-11-13 18:04:35 +00004212 if (sax != NULL) ctxt->sax = sax;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004213 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4214 if (input == NULL) {
4215 perror("malloc");
4216 free(ctxt);
4217 return(NULL);
4218 }
4219
4220 input->filename = NULL;
4221 input->line = 1;
4222 input->col = 1;
4223 input->base = cur;
4224 input->cur = cur;
4225
4226 inputPush(ctxt, input);
4227
4228
4229 xmlParseDocument(ctxt);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004230 if ((ctxt->wellFormed) || recovery) ret = ctxt->doc;
4231 else {
4232 ret = NULL;
4233 xmlFreeDoc(ctxt->doc);
4234 ctxt->doc = NULL;
4235 }
Daniel Veillardccb09631998-10-27 06:21:04 +00004236 free(ctxt->nodeTab);
4237 free(ctxt->inputTab);
4238 if (input->filename != NULL)
4239 free((char *)input->filename);
4240 free(input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004241 free(ctxt);
4242
4243 return(ret);
4244}
4245
Daniel Veillard11e00581998-10-24 18:27:49 +00004246/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004247 * xmlParseDoc :
4248 * @cur: a pointer to an array of CHAR
4249 *
4250 * parse an XML in-memory document and build a tree.
4251 *
4252 * return values: the resulting document tree
4253 */
4254
4255xmlDocPtr xmlParseDoc(CHAR *cur) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004256 return(xmlSAXParseDoc(NULL, cur, 0));
4257}
4258
4259/**
4260 * xmlRecoverDoc :
4261 * @cur: a pointer to an array of CHAR
4262 *
4263 * parse an XML in-memory document and build a tree.
4264 * In the case the document is not Well Formed, a tree is built anyway
4265 *
4266 * return values: the resulting document tree
4267 */
4268
4269xmlDocPtr xmlRecoverDoc(CHAR *cur) {
4270 return(xmlSAXParseDoc(NULL, cur, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004271}
4272
4273/**
4274 * xmlSAXParseFile :
4275 * @sax: the SAX handler block
Daniel Veillard11e00581998-10-24 18:27:49 +00004276 * @filename: the filename
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004277 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4278 * documents
Daniel Veillard11e00581998-10-24 18:27:49 +00004279 *
4280 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4281 * compressed document is provided by default if found at compile-time.
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004282 * It use the given SAX function block to handle the parsing callback.
4283 * If sax is NULL, fallback to the default DOM tree building routines.
Daniel Veillard11e00581998-10-24 18:27:49 +00004284 *
4285 * return values: the resulting document tree
Daniel Veillard260a68f1998-08-13 03:39:55 +00004286 */
4287
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004288xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
4289 int recovery) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004290 xmlDocPtr ret;
4291#ifdef HAVE_ZLIB_H
4292 gzFile input;
4293#else
4294 int input;
4295#endif
4296 int res;
Daniel Veillard27271681998-10-30 06:39:40 +00004297 int len;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004298 struct stat buf;
4299 char *buffer;
4300 xmlParserCtxtPtr ctxt;
4301 xmlParserInputPtr inputStream;
4302
4303 res = stat(filename, &buf);
4304 if (res < 0) return(NULL);
4305
4306#ifdef HAVE_ZLIB_H
Daniel Veillard27271681998-10-30 06:39:40 +00004307 len = (buf.st_size * 8) + 1000;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004308retry_bigger:
Daniel Veillard27271681998-10-30 06:39:40 +00004309 buffer = malloc(len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004310#else
Daniel Veillard27271681998-10-30 06:39:40 +00004311 len = buf.st_size + 100;
4312 buffer = malloc(len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004313#endif
4314 if (buffer == NULL) {
4315 perror("malloc");
4316 return(NULL);
4317 }
4318
Daniel Veillard27271681998-10-30 06:39:40 +00004319 memset(buffer, 0, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004320#ifdef HAVE_ZLIB_H
4321 input = gzopen (filename, "r");
4322 if (input == NULL) {
4323 fprintf (stderr, "Cannot read file %s :\n", filename);
4324 perror ("gzopen failed");
4325 return(NULL);
4326 }
4327#else
4328 input = open (filename, O_RDONLY);
4329 if (input < 0) {
4330 fprintf (stderr, "Cannot read file %s :\n", filename);
4331 perror ("open failed");
4332 return(NULL);
4333 }
4334#endif
4335#ifdef HAVE_ZLIB_H
Daniel Veillard27271681998-10-30 06:39:40 +00004336 res = gzread(input, buffer, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004337#else
4338 res = read(input, buffer, buf.st_size);
4339#endif
4340 if (res < 0) {
4341 fprintf (stderr, "Cannot read file %s :\n", filename);
4342#ifdef HAVE_ZLIB_H
4343 perror ("gzread failed");
4344#else
4345 perror ("read failed");
4346#endif
4347 return(NULL);
4348 }
4349#ifdef HAVE_ZLIB_H
4350 gzclose(input);
Daniel Veillard27271681998-10-30 06:39:40 +00004351 if (res >= len) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004352 free(buffer);
Daniel Veillard27271681998-10-30 06:39:40 +00004353 len *= 2;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004354 goto retry_bigger;
4355 }
4356 buf.st_size = res;
4357#else
4358 close(input);
4359#endif
4360
4361 buffer[buf.st_size] = '\0';
4362
4363 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4364 if (ctxt == NULL) {
4365 perror("malloc");
4366 return(NULL);
4367 }
4368 xmlInitParserCtxt(ctxt);
Daniel Veillard242590e1998-11-13 18:04:35 +00004369 if (sax != NULL) ctxt->sax = sax;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004370 inputStream = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4371 if (inputStream == NULL) {
4372 perror("malloc");
4373 free(ctxt);
4374 return(NULL);
4375 }
4376
4377 inputStream->filename = strdup(filename);
4378 inputStream->line = 1;
4379 inputStream->col = 1;
4380
4381 /*
4382 * TODO : plug some encoding conversion routines here. !!!
4383 */
4384 inputStream->base = buffer;
4385 inputStream->cur = buffer;
4386
4387 inputPush(ctxt, inputStream);
4388
4389 xmlParseDocument(ctxt);
4390
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004391 if ((ctxt->wellFormed) || recovery) ret = ctxt->doc;
4392 else {
4393 ret = NULL;
4394 xmlFreeDoc(ctxt->doc);
4395 ctxt->doc = NULL;
4396 }
Daniel Veillard260a68f1998-08-13 03:39:55 +00004397 free(buffer);
Daniel Veillardccb09631998-10-27 06:21:04 +00004398 free(ctxt->nodeTab);
4399 free(ctxt->inputTab);
4400 if (inputStream->filename != NULL)
4401 free((char *)inputStream->filename);
4402 free(inputStream);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004403 free(ctxt);
4404
4405 return(ret);
4406}
4407
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004408/**
4409 * xmlParseFile :
4410 * @filename: the filename
4411 *
4412 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4413 * compressed document is provided by default if found at compile-time.
4414 *
4415 * return values: the resulting document tree
4416 */
4417
4418xmlDocPtr xmlParseFile(const char *filename) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004419 return(xmlSAXParseFile(NULL, filename, 0));
4420}
4421
4422/**
4423 * xmlRecoverFile :
4424 * @filename: the filename
4425 *
4426 * parse an XML file and build a tree. Automatic support for ZLIB/Compress
4427 * compressed document is provided by default if found at compile-time.
4428 * In the case the document is not Well Formed, a tree is built anyway
4429 *
4430 * return values: the resulting document tree
4431 */
4432
4433xmlDocPtr xmlRecoverFile(const char *filename) {
4434 return(xmlSAXParseFile(NULL, filename, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004435}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004436
Daniel Veillard11e00581998-10-24 18:27:49 +00004437/**
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004438 * xmlSAXParseMemory :
4439 * @sax: the SAX handler block
Daniel Veillard11e00581998-10-24 18:27:49 +00004440 * @cur: an pointer to a char array
4441 * @size: the siwe of the array
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004442 * @recovery: work in recovery mode, i.e. tries to read no Well Formed
4443 * documents
Daniel Veillard11e00581998-10-24 18:27:49 +00004444 *
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004445 * parse an XML in-memory block and use the given SAX function block
4446 * to handle the parsing callback. If sax is NULL, fallback to the default
4447 * DOM tree building routines.
Daniel Veillard11e00581998-10-24 18:27:49 +00004448 *
4449 * TODO : plug some encoding conversion routines here. !!!
4450 *
4451 * return values: the resulting document tree
Daniel Veillard260a68f1998-08-13 03:39:55 +00004452 */
Daniel Veillard11e00581998-10-24 18:27:49 +00004453
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004454xmlDocPtr xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size,
4455 int recovery) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004456 xmlDocPtr ret;
4457 xmlParserCtxtPtr ctxt;
4458 xmlParserInputPtr input;
4459
4460 buffer[size - 1] = '\0';
4461
4462 ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
4463 if (ctxt == NULL) {
4464 perror("malloc");
4465 return(NULL);
4466 }
4467 xmlInitParserCtxt(ctxt);
Daniel Veillard242590e1998-11-13 18:04:35 +00004468 if (sax != NULL) ctxt->sax = sax;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004469 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4470 if (input == NULL) {
4471 perror("malloc");
Daniel Veillardccb09631998-10-27 06:21:04 +00004472 free(ctxt->nodeTab);
4473 free(ctxt->inputTab);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004474 free(ctxt);
4475 return(NULL);
4476 }
4477
4478 input->filename = NULL;
4479 input->line = 1;
4480 input->col = 1;
4481
4482 /*
4483 * TODO : plug some encoding conversion routines here. !!!
4484 */
4485 input->base = buffer;
4486 input->cur = buffer;
4487
4488 inputPush(ctxt, input);
4489
4490 xmlParseDocument(ctxt);
4491
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004492 if ((ctxt->wellFormed) || recovery) ret = ctxt->doc;
4493 else {
4494 ret = NULL;
4495 xmlFreeDoc(ctxt->doc);
4496 ctxt->doc = NULL;
4497 }
Daniel Veillardccb09631998-10-27 06:21:04 +00004498 free(ctxt->nodeTab);
4499 free(ctxt->inputTab);
4500 if (input->filename != NULL)
4501 free((char *)input->filename);
4502 free(input);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004503 free(ctxt);
4504
4505 return(ret);
4506}
4507
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004508/**
4509 * xmlParseMemory :
4510 * @cur: an pointer to a char array
4511 * @size: the size of the array
4512 *
4513 * parse an XML in-memory block and build a tree.
4514 *
4515 * return values: the resulting document tree
4516 */
4517
4518xmlDocPtr xmlParseMemory(char *buffer, int size) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004519 return(xmlSAXParseMemory(NULL, buffer, size, 0));
4520}
4521
4522/**
4523 * xmlRecoverMemory :
4524 * @cur: an pointer to a char array
4525 * @size: the size of the array
4526 *
4527 * parse an XML in-memory block and build a tree.
4528 * In the case the document is not Well Formed, a tree is built anyway
4529 *
4530 * return values: the resulting document tree
4531 */
4532
4533xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
4534 return(xmlSAXParseMemory(NULL, buffer, size, 1));
Daniel Veillard42dc9b31998-11-09 01:17:21 +00004535}
Daniel Veillard260a68f1998-08-13 03:39:55 +00004536
Daniel Veillard11e00581998-10-24 18:27:49 +00004537/**
4538 * xmlInitParserCtxt:
4539 * @ctxt: an XML parser context
4540 *
4541 * Initialize a parser context
4542 */
4543
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004544void
4545xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004546{
4547 /* Allocate the Input stack */
4548 ctxt->inputTab = (xmlParserInputPtr *) malloc(5 * sizeof(xmlParserInputPtr));
4549 ctxt->inputNr = 0;
4550 ctxt->inputMax = 5;
4551 ctxt->input = NULL;
4552
4553 /* Allocate the Node stack */
4554 ctxt->nodeTab = (xmlNodePtr *) malloc(10 * sizeof(xmlNodePtr));
4555 ctxt->nodeNr = 0;
4556 ctxt->nodeMax = 10;
4557 ctxt->node = NULL;
4558
4559 ctxt->sax = &xmlDefaultSAXHandler;
4560 ctxt->doc = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004561 ctxt->wellFormed = 1;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004562 ctxt->record_info = 0;
4563 xmlInitNodeInfoSeq(&ctxt->node_seq);
4564}
4565
Daniel Veillard11e00581998-10-24 18:27:49 +00004566/**
4567 * xmlClearParserCtxt:
4568 * @ctxt: an XML parser context
4569 *
4570 * Clear (release owned resources) and reinitialize a parser context
Daniel Veillard260a68f1998-08-13 03:39:55 +00004571 */
Daniel Veillard11e00581998-10-24 18:27:49 +00004572
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004573void
4574xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004575{
4576 xmlClearNodeInfoSeq(&ctxt->node_seq);
4577 xmlInitParserCtxt(ctxt);
4578}
4579
4580
Daniel Veillard11e00581998-10-24 18:27:49 +00004581/**
4582 * xmlSetupParserForBuffer:
4583 * @ctxt: an XML parser context
4584 * @buffer: a CHAR * buffer
4585 * @filename: a file name
4586 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004587 * Setup the parser context to parse a new buffer; Clears any prior
4588 * contents from the parser context. The buffer parameter must not be
4589 * NULL, but the filename parameter can be
4590 */
Daniel Veillard11e00581998-10-24 18:27:49 +00004591
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004592void
4593xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const CHAR* buffer,
Daniel Veillard260a68f1998-08-13 03:39:55 +00004594 const char* filename)
4595{
4596 xmlParserInputPtr input;
4597
4598 input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
4599 if (input == NULL) {
4600 perror("malloc");
4601 free(ctxt);
4602 exit(1);
4603 }
4604
4605 xmlClearParserCtxt(ctxt);
4606 if (input->filename != NULL)
4607 input->filename = strdup(filename);
4608 else
4609 input->filename = NULL;
4610 input->line = 1;
4611 input->col = 1;
4612 input->base = buffer;
4613 input->cur = buffer;
4614
4615 inputPush(ctxt, input);
4616}
4617
4618
Daniel Veillard11e00581998-10-24 18:27:49 +00004619/**
4620 * xmlParserFindNodeInfo:
4621 * @ctxt: an XML parser context
4622 * @node: an XML node within the tree
4623 *
4624 * Find the parser node info struct for a given node
4625 *
4626 * return values: an xmlParserNodeInfo block pointer or NULL
Daniel Veillard260a68f1998-08-13 03:39:55 +00004627 */
4628const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
4629 const xmlNode* node)
4630{
4631 unsigned long pos;
4632
4633 /* Find position where node should be at */
4634 pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
4635 if ( ctx->node_seq.buffer[pos].node == node )
4636 return &ctx->node_seq.buffer[pos];
4637 else
4638 return NULL;
4639}
4640
4641
Daniel Veillard11e00581998-10-24 18:27:49 +00004642/**
4643 * xmlInitNodeInfoSeq :
4644 * @seq: a node info sequence pointer
4645 *
4646 * -- Initialize (set to initial state) node info sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00004647 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004648void
4649xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004650{
4651 seq->length = 0;
4652 seq->maximum = 0;
4653 seq->buffer = NULL;
4654}
4655
Daniel Veillard11e00581998-10-24 18:27:49 +00004656/**
4657 * xmlClearNodeInfoSeq :
4658 * @seq: a node info sequence pointer
4659 *
4660 * -- Clear (release memory and reinitialize) node
Daniel Veillard260a68f1998-08-13 03:39:55 +00004661 * info sequence
4662 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004663void
4664xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
Daniel Veillard260a68f1998-08-13 03:39:55 +00004665{
4666 if ( seq->buffer != NULL )
4667 free(seq->buffer);
4668 xmlInitNodeInfoSeq(seq);
4669}
4670
4671
Daniel Veillard11e00581998-10-24 18:27:49 +00004672/**
4673 * xmlParserFindNodeInfoIndex:
4674 * @seq: a node info sequence pointer
4675 * @node: an XML node pointer
4676 *
4677 *
Daniel Veillard260a68f1998-08-13 03:39:55 +00004678 * xmlParserFindNodeInfoIndex : Find the index that the info record for
4679 * the given node is or should be at in a sorted sequence
Daniel Veillard1164e751999-02-16 16:29:17 +00004680 *
Daniel Veillard11e00581998-10-24 18:27:49 +00004681 * return values: a long indicating the position of the record
Daniel Veillard260a68f1998-08-13 03:39:55 +00004682 */
4683unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
4684 const xmlNode* node)
4685{
4686 unsigned long upper, lower, middle;
4687 int found = 0;
4688
4689 /* Do a binary search for the key */
4690 lower = 1;
4691 upper = seq->length;
4692 middle = 0;
4693 while ( lower <= upper && !found) {
4694 middle = lower + (upper - lower) / 2;
4695 if ( node == seq->buffer[middle - 1].node )
4696 found = 1;
4697 else if ( node < seq->buffer[middle - 1].node )
4698 upper = middle - 1;
4699 else
4700 lower = middle + 1;
4701 }
4702
4703 /* Return position */
4704 if ( middle == 0 || seq->buffer[middle - 1].node < node )
4705 return middle;
4706 else
4707 return middle - 1;
4708}
4709
4710
Daniel Veillard11e00581998-10-24 18:27:49 +00004711/**
4712 * xmlParserAddNodeInfo:
4713 * @ctxt: an XML parser context
4714 * @seq: a node info sequence pointer
4715 *
4716 * Insert node info record into the sorted sequence
Daniel Veillard260a68f1998-08-13 03:39:55 +00004717 */
Daniel Veillard0ba4d531998-11-01 19:34:31 +00004718void
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004719xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
Daniel Veillard260a68f1998-08-13 03:39:55 +00004720 const xmlParserNodeInfo* info)
4721{
4722 unsigned long pos;
4723 static unsigned int block_size = 5;
4724
4725 /* Find pos and check to see if node is already in the sequence */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004726 pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
4727 if ( pos < ctxt->node_seq.length
4728 && ctxt->node_seq.buffer[pos].node == info->node ) {
4729 ctxt->node_seq.buffer[pos] = *info;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004730 }
4731
4732 /* Otherwise, we need to add new node to buffer */
4733 else {
4734 /* Expand buffer by 5 if needed */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004735 if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004736 xmlParserNodeInfo* tmp_buffer;
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004737 unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
4738 *(ctxt->node_seq.maximum + block_size));
Daniel Veillard260a68f1998-08-13 03:39:55 +00004739
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004740 if ( ctxt->node_seq.buffer == NULL )
Daniel Veillard260a68f1998-08-13 03:39:55 +00004741 tmp_buffer = (xmlParserNodeInfo*)malloc(byte_size);
4742 else
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004743 tmp_buffer = (xmlParserNodeInfo*)realloc(ctxt->node_seq.buffer, byte_size);
Daniel Veillard260a68f1998-08-13 03:39:55 +00004744
4745 if ( tmp_buffer == NULL ) {
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004746 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
Daniel Veillard8cc0d1f1998-11-16 01:04:26 +00004747 ctxt->sax->error(ctxt, "Out of memory\n");
Daniel Veillard260a68f1998-08-13 03:39:55 +00004748 return;
4749 }
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004750 ctxt->node_seq.buffer = tmp_buffer;
4751 ctxt->node_seq.maximum += block_size;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004752 }
4753
4754 /* If position is not at end, move elements out of the way */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004755 if ( pos != ctxt->node_seq.length ) {
Daniel Veillard260a68f1998-08-13 03:39:55 +00004756 unsigned long i;
4757
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004758 for ( i = ctxt->node_seq.length; i > pos; i-- )
4759 ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
Daniel Veillard260a68f1998-08-13 03:39:55 +00004760 }
4761
4762 /* Copy element and increase length */
Daniel Veillarde3bffb91998-11-08 14:40:56 +00004763 ctxt->node_seq.buffer[pos] = *info;
4764 ctxt->node_seq.length++;
Daniel Veillard260a68f1998-08-13 03:39:55 +00004765 }
4766}