blob: 9a24110ccb379af016f5fa62bc58773d82cc3872 [file] [log] [blame]
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001/*
2 * xmlreader.c: implements the xmlTextReader streaming node API
3 *
Daniel Veillard67df8092002-12-16 22:04:11 +00004 * NOTE:
5 * XmlTextReader.Normalization Property won't be supported, since
6 * it makes the parser non compliant to the XML recommendation
7 *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00008 * See Copyright for the status of this software.
9 *
10 * daniel@veillard.com
11 */
12
Daniel Veillard7704fb12003-01-03 16:19:51 +000013/*
14 * TODOs:
Daniel Veillard7704fb12003-01-03 16:19:51 +000015 * - provide an API to preserve part of the tree
16 * - Streaming XInclude support
Daniel Veillard067bae52003-01-05 01:27:54 +000017 * - validation against a provided DTD
18 * - XML Schemas validation
Daniel Veillard7704fb12003-01-03 16:19:51 +000019 * - setting(s) for NoBlanks
20 * - performances and tuning ...
21 */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000022#define IN_LIBXML
23#include "libxml.h"
24
25#include <string.h> /* for memset() only ! */
Daniel Veillard26f70262003-01-16 22:45:08 +000026#include <stdarg.h>
Daniel Veillarde1ca5032002-12-09 14:13:43 +000027
28#ifdef HAVE_CTYPE_H
29#include <ctype.h>
30#endif
31#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
34
35#include <libxml/xmlmemory.h>
36#include <libxml/xmlIO.h>
37#include <libxml/xmlreader.h>
Daniel Veillardf4e55762003-04-15 23:32:22 +000038#include <libxml/relaxng.h>
Daniel Veillarde1ca5032002-12-09 14:13:43 +000039
40/* #define DEBUG_CALLBACKS */
41/* #define DEBUG_READER */
42
43/**
44 * TODO:
45 *
46 * macro to flag unimplemented blocks
47 */
48#define TODO \
49 xmlGenericError(xmlGenericErrorContext, \
50 "Unimplemented block at %s:%d\n", \
51 __FILE__, __LINE__);
52
53#ifdef DEBUG_READER
54#define DUMP_READER xmlTextReaderDebug(reader);
55#else
56#define DUMP_READER
57#endif
58
Daniel Veillarda880b122003-04-21 21:36:41 +000059#define CHUNK_SIZE 512
Daniel Veillarde1ca5032002-12-09 14:13:43 +000060/************************************************************************
61 * *
62 * The parser: maps the Text Reader API on top of the existing *
63 * parsing routines building a tree *
64 * *
65 ************************************************************************/
66
67#define XML_TEXTREADER_INPUT 1
68#define XML_TEXTREADER_CTXT 2
69
70typedef enum {
Daniel Veillard67df8092002-12-16 22:04:11 +000071 XML_TEXTREADER_MODE_INITIAL = 0,
72 XML_TEXTREADER_MODE_INTERACTIVE = 1,
73 XML_TEXTREADER_MODE_ERROR = 2,
74 XML_TEXTREADER_MODE_EOF =3,
75 XML_TEXTREADER_MODE_CLOSED = 4,
76 XML_TEXTREADER_MODE_READING = 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000077} xmlTextReaderMode;
78
79typedef enum {
80 XML_TEXTREADER_NONE = -1,
81 XML_TEXTREADER_START= 0,
82 XML_TEXTREADER_ELEMENT= 1,
83 XML_TEXTREADER_END= 2,
84 XML_TEXTREADER_EMPTY= 3,
Daniel Veillardea7751d2002-12-20 00:16:24 +000085 XML_TEXTREADER_BACKTRACK= 4,
86 XML_TEXTREADER_DONE= 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000087} xmlTextReaderState;
88
Daniel Veillardf4e55762003-04-15 23:32:22 +000089typedef enum {
90 XML_TEXTREADER_NOT_VALIDATE = 0,
91 XML_TEXTREADER_VALIDATE_DTD = 1,
92 XML_TEXTREADER_VALIDATE_RNG = 2
93} xmlTextReaderValidate;
94
Daniel Veillarde1ca5032002-12-09 14:13:43 +000095struct _xmlTextReader {
96 int mode; /* the parsing mode */
Daniel Veillardf4e55762003-04-15 23:32:22 +000097 xmlTextReaderValidate validate;/* is there any validation */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000098 int allocs; /* what structure were deallocated */
99 xmlTextReaderState state;
100 xmlParserCtxtPtr ctxt; /* the parser context */
101 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
102 xmlParserInputBufferPtr input; /* the input */
103 startElementSAXFunc startElement;/* initial SAX callbacks */
104 endElementSAXFunc endElement; /* idem */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000105 charactersSAXFunc characters;
106 cdataBlockSAXFunc cdataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000107 unsigned int base; /* base of the segment in the input */
108 unsigned int cur; /* current position in the input */
109 xmlNodePtr node; /* current node */
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000110 xmlNodePtr curnode;/* current attribute node */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000111 int depth; /* depth of the current node */
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000112 xmlNodePtr faketext;/* fake xmlNs chld */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000113
114 /* entity stack when traversing entities content */
115 xmlNodePtr ent; /* Current Entity Ref Node */
116 int entNr; /* Depth of the entities stack */
117 int entMax; /* Max depth of the entities stack */
118 xmlNodePtr *entTab; /* array of entities */
Daniel Veillard26f70262003-01-16 22:45:08 +0000119
120 /* error handling */
121 xmlTextReaderErrorFunc errorFunc; /* callback function */
122 void *errorFuncArg; /* callback function user argument */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000123
124#ifdef LIBXML_SCHEMAS_ENABLED
125 /* Handling of RelaxNG validation */
126 xmlRelaxNGPtr rngSchemas; /* The Relax NG schemas */
127 xmlRelaxNGValidCtxtPtr rngValidCtxt; /* The Relax NG validation context */
128 int rngValidErrors; /* The number of errors detected */
129 xmlNodePtr rngFullNode; /* the node if RNG not progressive */
130#endif
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000131};
132
Daniel Veillard067bae52003-01-05 01:27:54 +0000133static const char *xmlTextReaderIsEmpty = "This element is empty";
134
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000135#ifdef DEBUG_READER
136static void
137xmlTextReaderDebug(xmlTextReaderPtr reader) {
138 if ((reader == NULL) || (reader->ctxt == NULL)) {
139 fprintf(stderr, "xmlTextReader NULL\n");
140 return;
141 }
142 fprintf(stderr, "xmlTextReader: state %d depth %d ",
143 reader->state, reader->depth);
144 if (reader->node == NULL) {
145 fprintf(stderr, "node = NULL\n");
146 } else {
147 fprintf(stderr, "node %s\n", reader->node->name);
148 }
149 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
150 reader->base, reader->cur, reader->ctxt->nodeNr);
151 if (reader->input->buffer == NULL) {
152 fprintf(stderr, "buffer is NULL\n");
153 } else {
154#ifdef LIBXML_DEBUG_ENABLED
155 xmlDebugDumpString(stderr,
156 &reader->input->buffer->content[reader->cur]);
157#endif
158 fprintf(stderr, "\n");
159 }
160}
161#endif
162
163/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000164 * xmlTextReaderEntPush:
165 * @reader: the xmlTextReaderPtr used
166 * @value: the entity reference node
167 *
168 * Pushes a new entity reference node on top of the entities stack
169 *
170 * Returns 0 in case of error, the index in the stack otherwise
171 */
172static int
173xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
174{
175 if (reader->entMax <= 0) {
176 reader->entMax = 10;
177 reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
178 sizeof(reader->entTab[0]));
179 if (reader->entTab == NULL) {
180 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
181 return (0);
182 }
183 }
184 if (reader->entNr >= reader->entMax) {
185 reader->entMax *= 2;
186 reader->entTab =
187 (xmlNodePtr *) xmlRealloc(reader->entTab,
188 reader->entMax *
189 sizeof(reader->entTab[0]));
190 if (reader->entTab == NULL) {
191 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
192 return (0);
193 }
194 }
195 reader->entTab[reader->entNr] = value;
196 reader->ent = value;
197 return (reader->entNr++);
198}
199
200/**
201 * xmlTextReaderEntPop:
202 * @reader: the xmlTextReaderPtr used
203 *
204 * Pops the top element entity from the entities stack
205 *
206 * Returns the entity just removed
207 */
208static xmlNodePtr
209xmlTextReaderEntPop(xmlTextReaderPtr reader)
210{
211 xmlNodePtr ret;
212
213 if (reader->entNr <= 0)
214 return (0);
215 reader->entNr--;
216 if (reader->entNr > 0)
217 reader->ent = reader->entTab[reader->entNr - 1];
218 else
219 reader->ent = NULL;
220 ret = reader->entTab[reader->entNr];
221 reader->entTab[reader->entNr] = 0;
222 return (ret);
223}
224
225/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000226 * xmlTextReaderStartElement:
227 * @ctx: the user data (XML parser context)
228 * @fullname: The element name, including namespace prefix
229 * @atts: An array of name/value attributes pairs, NULL terminated
230 *
231 * called when an opening tag has been processed.
232 */
233static void
234xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
235 const xmlChar **atts) {
236 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000237 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000238 xmlTextReaderPtr reader = ctxt->_private;
239
240#ifdef DEBUG_CALLBACKS
241 printf("xmlTextReaderStartElement(%s)\n", fullname);
242#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000243 if ((reader != NULL) && (reader->startElement != NULL)) {
Daniel Veillardd5896142002-12-31 14:45:26 +0000244 /*
245 * when processing an entity, the context may have been changed
246 */
247 origctxt = reader->ctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000248 reader->startElement(ctx, fullname, atts);
Daniel Veillard067bae52003-01-05 01:27:54 +0000249 if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
250 (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
251 (ctxt->input->cur[1] == '>'))
252 ctxt->node->_private = (void *) xmlTextReaderIsEmpty;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000253 }
Daniel Veillard9e395c22003-01-01 14:50:44 +0000254 if (reader != NULL)
255 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000256}
257
258/**
259 * xmlTextReaderEndElement:
260 * @ctx: the user data (XML parser context)
261 * @fullname: The element name, including namespace prefix
262 *
263 * called when an ending tag has been processed.
264 */
265static void
266xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
267 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000268 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000269 xmlTextReaderPtr reader = ctxt->_private;
270
271#ifdef DEBUG_CALLBACKS
272 printf("xmlTextReaderEndElement(%s)\n", fullname);
273#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000274 if ((reader != NULL) && (reader->endElement != NULL)) {
Daniel Veillardd5896142002-12-31 14:45:26 +0000275 /*
276 * when processing an entity, the context may have been changed
277 */
278 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000279
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000280 reader->endElement(ctx, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000282}
283
284/**
Daniel Veillardea7751d2002-12-20 00:16:24 +0000285 * xmlTextReaderCharacters:
286 * @ctx: the user data (XML parser context)
287 * @ch: a xmlChar string
288 * @len: the number of xmlChar
289 *
290 * receiving some chars from the parser.
291 */
292static void
293xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
294{
295 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000296 xmlParserCtxtPtr origctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000297 xmlTextReaderPtr reader = ctxt->_private;
298
299#ifdef DEBUG_CALLBACKS
300 printf("xmlTextReaderCharacters()\n");
301#endif
302 if ((reader != NULL) && (reader->characters != NULL)) {
303 reader->characters(ctx, ch, len);
Daniel Veillardd5896142002-12-31 14:45:26 +0000304 /*
305 * when processing an entity, the context may have been changed
306 */
307 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000308 }
309}
310
311/**
312 * xmlTextReaderCDataBlock:
313 * @ctx: the user data (XML parser context)
314 * @value: The pcdata content
315 * @len: the block length
316 *
317 * called when a pcdata block has been parsed
318 */
319static void
320xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
321{
322 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
323 xmlTextReaderPtr reader = ctxt->_private;
324
325#ifdef DEBUG_CALLBACKS
326 printf("xmlTextReaderCDataBlock()\n");
327#endif
328 if ((reader != NULL) && (reader->cdataBlock != NULL)) {
329 reader->cdataBlock(ctx, ch, len);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000330 }
331}
332
333/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000334 * xmlTextReaderPushData:
335 * @reader: the xmlTextReaderPtr used
336 *
337 * Push data down the progressive parser until a significant callback
338 * got raised.
339 *
340 * Returns -1 in case of failure, 0 otherwise
341 */
342static int
343xmlTextReaderPushData(xmlTextReaderPtr reader) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000344 xmlBufferPtr inbuf;
Daniel Veillarda880b122003-04-21 21:36:41 +0000345 int val, s;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000346 int oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000347
348 if ((reader->input == NULL) || (reader->input->buffer == NULL))
349 return(-1);
350
Daniel Veillardea7751d2002-12-20 00:16:24 +0000351 oldstate = reader->state;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000352 reader->state = XML_TEXTREADER_NONE;
353 inbuf = reader->input->buffer;
Daniel Veillarda880b122003-04-21 21:36:41 +0000354
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000355 while (reader->state == XML_TEXTREADER_NONE) {
Daniel Veillarda880b122003-04-21 21:36:41 +0000356 if (inbuf->use < reader->cur + CHUNK_SIZE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000357 /*
358 * Refill the buffer unless we are at the end of the stream
359 */
360 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
361 val = xmlParserInputBufferRead(reader->input, 4096);
362 if (val <= 0) {
363 reader->mode = XML_TEXTREADER_MODE_EOF;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000364 reader->state = oldstate;
Daniel Veillardaaa105b2002-12-30 11:42:17 +0000365 if ((oldstate != XML_TEXTREADER_START) ||
366 (reader->ctxt->myDoc != NULL))
367 return(val);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000368 }
Daniel Veillarda880b122003-04-21 21:36:41 +0000369
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000370 } else
371 break;
372 }
Daniel Veillard067bae52003-01-05 01:27:54 +0000373 /*
Daniel Veillarda880b122003-04-21 21:36:41 +0000374 * parse by block of CHUNK_SIZE bytes, various tests show that
375 * it's the best tradeoff at least on a 1.2GH Duron
Daniel Veillard067bae52003-01-05 01:27:54 +0000376 */
Daniel Veillarda880b122003-04-21 21:36:41 +0000377 if (inbuf->use >= reader->cur + CHUNK_SIZE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000378 val = xmlParseChunk(reader->ctxt,
379 (const char *) &inbuf->content[reader->cur],
Daniel Veillarda880b122003-04-21 21:36:41 +0000380 CHUNK_SIZE, 0);
381 reader->cur += CHUNK_SIZE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000382 if (val != 0)
383 return(-1);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000384 } else {
Daniel Veillarda880b122003-04-21 21:36:41 +0000385 s = inbuf->use - reader->cur;
386 val = xmlParseChunk(reader->ctxt,
387 (const char *) &inbuf->content[reader->cur],
388 s, 0);
389 reader->cur += s;
390 if (val != 0)
391 return(-1);
392 break;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000393 }
394 }
Daniel Veillarda880b122003-04-21 21:36:41 +0000395
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000396 /*
397 * Discard the consumed input when needed and possible
398 */
Daniel Veillard67df8092002-12-16 22:04:11 +0000399 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
Daniel Veillarda880b122003-04-21 21:36:41 +0000400 if (reader->cur >= 4096) {
401 val = xmlBufferShrink(inbuf, reader->cur);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000402 if (val >= 0) {
403 reader->cur -= val;
404 }
405 }
406 }
407
408 /*
409 * At the end of the stream signal that the work is done to the Push
410 * parser.
411 */
Daniel Veillarda880b122003-04-21 21:36:41 +0000412 else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000413 if (reader->mode != XML_TEXTREADER_DONE) {
Daniel Veillarda880b122003-04-21 21:36:41 +0000414 s = inbuf->use - reader->cur;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000415 val = xmlParseChunk(reader->ctxt,
Daniel Veillard067bae52003-01-05 01:27:54 +0000416 (const char *) &inbuf->content[reader->cur],
Daniel Veillarda880b122003-04-21 21:36:41 +0000417 s, 1);
418 reader->cur = inbuf->use;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000419 reader->mode = XML_TEXTREADER_DONE;
420 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000421 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000422 reader->state = oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000423 return(0);
424}
425
426/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000427 * xmlTextReaderValidatePush:
428 * @reader: the xmlTextReaderPtr used
429 *
430 * Push the current node for validation
431 */
432static void
433xmlTextReaderValidatePush(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000434#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000435 xmlNodePtr node = reader->node;
436
Daniel Veillardf4e55762003-04-15 23:32:22 +0000437 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
438 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
439 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
440 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
441 reader->ctxt->myDoc, node, node->name);
442 } else {
443 /* TODO use the BuildQName interface */
444 xmlChar *qname;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000445
Daniel Veillardf4e55762003-04-15 23:32:22 +0000446 qname = xmlStrdup(node->ns->prefix);
447 qname = xmlStrcat(qname, BAD_CAST ":");
448 qname = xmlStrcat(qname, node->name);
449 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
450 reader->ctxt->myDoc, node, qname);
451 if (qname != NULL)
452 xmlFree(qname);
453 }
454#ifdef LIBXML_SCHEMAS_ENABLED
455 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
456 (reader->rngValidCtxt != NULL)) {
457 int ret;
458
459 if (reader->rngFullNode != NULL) return;
460 ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
461 reader->ctxt->myDoc,
462 node);
463 if (ret == 0) {
464 /*
465 * this element requires a full tree
466 */
467 node = xmlTextReaderExpand(reader);
468 if (node == NULL) {
469printf("Expand failed !\n");
470 ret = -1;
471 } else {
472 ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt,
473 reader->ctxt->myDoc,
474 node);
475 reader->rngFullNode = node;
476 }
477 }
478 if (ret != 1)
479 reader->rngValidErrors++;
480#endif
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000481 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000482#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000483}
Daniel Veillardf4e55762003-04-15 23:32:22 +0000484
485/**
486 * xmlTextReaderValidateCData:
487 * @reader: the xmlTextReaderPtr used
488 * @data: pointer to the CData
489 * @len: lenght of the CData block in bytes.
490 *
491 * Push some CData for validation
492 */
493static void
494xmlTextReaderValidateCData(xmlTextReaderPtr reader,
495 const xmlChar *data, int len) {
496#ifdef LIBXML_REGEXP_ENABLED
497 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
498 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
499 reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt,
500 data, len);
501#ifdef LIBXML_SCHEMAS_ENABLED
502 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
503 (reader->rngValidCtxt != NULL)) {
504 int ret;
505
506 if (reader->rngFullNode != NULL) return;
507 ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len);
508 if (ret != 1)
509 reader->rngValidErrors++;
510#endif
511 }
512#endif /* LIBXML_REGEXP_ENABLED */
513}
514
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000515/**
516 * xmlTextReaderValidatePop:
517 * @reader: the xmlTextReaderPtr used
518 *
519 * Pop the current node from validation
520 */
521static void
522xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000523#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000524 xmlNodePtr node = reader->node;
525
Daniel Veillardf4e55762003-04-15 23:32:22 +0000526 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
527 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
528 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
529 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
530 reader->ctxt->myDoc, node, node->name);
531 } else {
532 /* TODO use the BuildQName interface */
533 xmlChar *qname;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000534
Daniel Veillardf4e55762003-04-15 23:32:22 +0000535 qname = xmlStrdup(node->ns->prefix);
536 qname = xmlStrcat(qname, BAD_CAST ":");
537 qname = xmlStrcat(qname, node->name);
538 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
539 reader->ctxt->myDoc, node, qname);
540 if (qname != NULL)
541 xmlFree(qname);
542 }
543#ifdef LIBXML_SCHEMAS_ENABLED
544 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
545 (reader->rngValidCtxt != NULL)) {
546 int ret;
547
548 if (reader->rngFullNode != NULL) {
549 if (node == reader->rngFullNode)
550 reader->rngFullNode = NULL;
551 return;
552 }
553 ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
554 reader->ctxt->myDoc,
555 node);
556 if (ret != 1)
557 reader->rngValidErrors++;
558#endif
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000559 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000560#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000561}
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000562/**
563 * xmlTextReaderValidateEntity:
564 * @reader: the xmlTextReaderPtr used
565 *
566 * Handle the validation when an entity reference is encountered and
567 * entity substitution is not activated. As a result the parser interface
568 * must walk through the entity and do the validation calls
569 */
570static void
571xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000572#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000573 xmlNodePtr oldnode = reader->node;
574 xmlNodePtr node = reader->node;
575 xmlParserCtxtPtr ctxt = reader->ctxt;
576
577 do {
578 if (node->type == XML_ENTITY_REF_NODE) {
579 /*
580 * Case where the underlying tree is not availble, lookup the entity
581 * and walk it.
582 */
583 if ((node->children == NULL) && (ctxt->sax != NULL) &&
584 (ctxt->sax->getEntity != NULL)) {
585 node->children = (xmlNodePtr)
586 ctxt->sax->getEntity(ctxt, node->name);
587 }
588
589 if ((node->children != NULL) &&
590 (node->children->type == XML_ENTITY_DECL) &&
591 (node->children->children != NULL)) {
592 xmlTextReaderEntPush(reader, node);
593 node = node->children->children;
594 continue;
595 } else {
596 /*
597 * The error has probably be raised already.
598 */
599 if (node == oldnode)
600 break;
601 node = node->next;
602 }
603 } else if (node->type == XML_ELEMENT_NODE) {
604 reader->node = node;
605 xmlTextReaderValidatePush(reader);
606 } else if ((node->type == XML_TEXT_NODE) ||
607 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillardf4e55762003-04-15 23:32:22 +0000608 xmlTextReaderValidateCData(reader, node->content,
609 xmlStrlen(node->content));
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000610 }
611
612 /*
613 * go to next node
614 */
615 if (node->children != NULL) {
616 node = node->children;
617 continue;
Daniel Veillardef8dd7b2003-03-23 12:02:56 +0000618 } else if (node->type == XML_ELEMENT_NODE) {
619 xmlTextReaderValidatePop(reader);
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000620 }
621 if (node->next != NULL) {
622 node = node->next;
623 continue;
624 }
625 do {
626 node = node->parent;
627 if (node->type == XML_ELEMENT_NODE) {
628 reader->node = node;
629 xmlTextReaderValidatePop(reader);
630 }
631 if ((node->type == XML_ENTITY_DECL) &&
632 (reader->ent != NULL) && (reader->ent->children == node)) {
633 node = xmlTextReaderEntPop(reader);
634 }
635 if (node == oldnode)
636 break;
637 if (node->next != NULL) {
638 node = node->next;
639 break;
640 }
641 } while ((node != NULL) && (node != oldnode));
642 } while ((node != NULL) && (node != oldnode));
643 reader->node = oldnode;
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000644#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000645}
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000646
647
648/**
Daniel Veillardc6cae7b2003-04-11 09:02:11 +0000649 * xmlTextReaderGetSuccessor:
650 * @cur: the current node
651 *
652 * Get the successor of a node if available.
653 *
654 * Returns the successor node or NULL
655 */
656static xmlNodePtr
657xmlTextReaderGetSuccessor(xmlNodePtr cur) {
658 if (cur == NULL) return(NULL) ; /* ERROR */
659 if (cur->next != NULL) return(cur->next) ;
660 do {
661 cur = cur->parent;
662 if (cur == NULL) return(NULL);
663 if (cur->next != NULL) return(cur->next);
664 } while (cur != NULL);
665 return(cur);
666}
667
668/**
669 * xmlTextReaderDoExpand:
670 * @reader: the xmlTextReaderPtr used
671 *
672 * Makes sure that the current node is fully read as well as all its
673 * descendant. It means the full DOM subtree must be available at the
674 * end of the call.
675 *
676 * Returns 1 if the node was expanded successfully, 0 if there is no more
677 * nodes to read, or -1 in case of error
678 */
679static int
680xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
681 int val;
682
683 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
684 return(-1);
685
686 do {
687 if (xmlTextReaderGetSuccessor(reader->node) != NULL)
688 return(1);
689 if (reader->mode == XML_TEXTREADER_MODE_EOF)
690 return(1);
691 val = xmlTextReaderPushData(reader);
692 if (val < 0)
693 return(-1);
694 } while(reader->mode != XML_TEXTREADER_MODE_EOF);
695 return(1);
696}
697
698/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000699 * xmlTextReaderRead:
700 * @reader: the xmlTextReaderPtr used
701 *
702 * Moves the position of the current instance to the next node in
703 * the stream, exposing its properties.
704 *
705 * Returns 1 if the node was read successfully, 0 if there is no more
706 * nodes to read, or -1 in case of error
707 */
708int
709xmlTextReaderRead(xmlTextReaderPtr reader) {
Daniel Veillard067bae52003-01-05 01:27:54 +0000710 int val, olddepth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000711 xmlTextReaderState oldstate = 0;
712 xmlNodePtr oldnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000713
714 if ((reader == NULL) || (reader->ctxt == NULL))
715 return(-1);
716 if (reader->ctxt->wellFormed != 1)
717 return(-1);
718
719#ifdef DEBUG_READER
720 fprintf(stderr, "\nREAD ");
721 DUMP_READER
722#endif
Daniel Veillard29b3e282002-12-29 11:14:41 +0000723 reader->curnode = NULL;
Daniel Veillard67df8092002-12-16 22:04:11 +0000724 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
725 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000726 /*
727 * Initial state
728 */
729 do {
730 val = xmlTextReaderPushData(reader);
731 if (val < 0)
732 return(-1);
733 } while ((reader->ctxt->node == NULL) &&
Daniel Veillard067bae52003-01-05 01:27:54 +0000734 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
735 (reader->mode != XML_TEXTREADER_DONE)));
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000736 if (reader->ctxt->node == NULL) {
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000737 if (reader->ctxt->myDoc != NULL) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000738 reader->node = reader->ctxt->myDoc->children;
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000739 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000740 if (reader->node == NULL)
741 return(-1);
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000742 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000743 } else {
Daniel Veillard48ef4c92003-03-22 12:38:15 +0000744 if (reader->ctxt->myDoc != NULL) {
745 reader->node = reader->ctxt->myDoc->children;
746 }
747 if (reader->node == NULL)
748 reader->node = reader->ctxt->nodeTab[0];
Daniel Veillarde59494f2003-01-04 16:35:29 +0000749 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000750 }
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000751 reader->depth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000752 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000753 }
754 oldstate = reader->state;
755 olddepth = reader->ctxt->nodeNr;
756 oldnode = reader->node;
Daniel Veillarddf512f42002-12-23 15:56:21 +0000757
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000758get_next_node:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000759 /*
760 * If we are not backtracking on ancestors or examined nodes,
761 * that the parser didn't finished or that we arent at the end
762 * of stream, continue processing.
763 */
Daniel Veillarda880b122003-04-21 21:36:41 +0000764 while ((reader->node->next == NULL) &&
765 (reader->ctxt->nodeNr == olddepth) &&
766 ((oldstate == XML_TEXTREADER_BACKTRACK) ||
Daniel Veillardea7751d2002-12-20 00:16:24 +0000767 (reader->node->children == NULL) ||
768 (reader->node->type == XML_ENTITY_REF_NODE) ||
Daniel Veillard4dbe77a2003-01-14 00:17:42 +0000769 (reader->node->type == XML_DTD_NODE) ||
770 (reader->node->type == XML_DOCUMENT_NODE) ||
771 (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
Daniel Veillard4dbe77a2003-01-14 00:17:42 +0000772 ((reader->ctxt->node == NULL) ||
773 (reader->ctxt->node == reader->node) ||
774 (reader->ctxt->node == reader->node->parent)) &&
Daniel Veillardea7751d2002-12-20 00:16:24 +0000775 (reader->ctxt->instate != XML_PARSER_EOF)) {
776 val = xmlTextReaderPushData(reader);
777 if (val < 0)
778 return(-1);
779 if (reader->node == NULL)
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000780 goto node_end;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000781 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000782 if (oldstate != XML_TEXTREADER_BACKTRACK) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000783 if ((reader->node->children != NULL) &&
784 (reader->node->type != XML_ENTITY_REF_NODE) &&
785 (reader->node->type != XML_DTD_NODE)) {
786 reader->node = reader->node->children;
787 reader->depth++;
Daniel Veillarddf512f42002-12-23 15:56:21 +0000788 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000789 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000790 }
791 }
792 if (reader->node->next != NULL) {
793 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillarddf512f42002-12-23 15:56:21 +0000794 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +0000795 (reader->node->children == NULL) &&
796 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000797 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000798 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000799 }
Daniel Veillardf4e55762003-04-15 23:32:22 +0000800 if ((reader->validate) &&
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000801 (reader->node->type == XML_ELEMENT_NODE))
802 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000803 reader->node = reader->node->next;
804 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000805
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000806 /*
807 * Cleanup of the old node
808 */
Daniel Veillard4dbe77a2003-01-14 00:17:42 +0000809 if ((reader->node->prev != NULL) &&
810 (reader->node->prev->type != XML_DTD_NODE)) {
811 xmlNodePtr tmp = reader->node->prev;
812 xmlUnlinkNode(tmp);
813 xmlFreeNode(tmp);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000814 }
815
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000816 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000817 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000818 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillard571b8892002-12-30 12:37:59 +0000819 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +0000820 (reader->node->children == NULL) &&
821 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000822 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000823 goto node_found;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000824 }
Daniel Veillardf4e55762003-04-15 23:32:22 +0000825 if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE))
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000826 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000827 reader->node = reader->node->parent;
828 if ((reader->node == NULL) ||
829 (reader->node->type == XML_DOCUMENT_NODE) ||
830#ifdef LIBXML_DOCB_ENABLED
831 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
832#endif
833 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000834 if (reader->mode != XML_TEXTREADER_DONE) {
835 val = xmlParseChunk(reader->ctxt, "", 0, 1);
836 reader->mode = XML_TEXTREADER_DONE;
837 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000838 reader->node = NULL;
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000839 reader->depth = -1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000840
841 /*
842 * Cleanup of the old node
843 */
844 if (oldnode->type != XML_DTD_NODE) {
845 xmlUnlinkNode(oldnode);
846 xmlFreeNode(oldnode);
847 }
848
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000849 goto node_end;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000850 }
851 reader->depth--;
852 reader->state = XML_TEXTREADER_BACKTRACK;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000853
854node_found:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000855 DUMP_READER
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000856
857 /*
Daniel Veillarda880b122003-04-21 21:36:41 +0000858 * If we are in the middle of a piece of CDATA make sure it's finished
859 */
860 if ((reader->node != NULL) &&
861 ((reader->node->type == XML_TEXT_NODE) ||
862 (reader->node->type == XML_CDATA_SECTION_NODE))) {
863 xmlTextReaderExpand(reader);
864 }
865
866 /*
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000867 * Handle entities enter and exit when in entity replacement mode
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000868 */
869 if ((reader->node != NULL) &&
870 (reader->node->type == XML_ENTITY_REF_NODE) &&
871 (reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
872 /*
873 * Case where the underlying tree is not availble, lookup the entity
874 * and walk it.
875 */
876 if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
877 (reader->ctxt->sax->getEntity != NULL)) {
878 reader->node->children = (xmlNodePtr)
879 reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
880 }
881
882 if ((reader->node->children != NULL) &&
883 (reader->node->children->type == XML_ENTITY_DECL) &&
884 (reader->node->children->children != NULL)) {
885 xmlTextReaderEntPush(reader, reader->node);
886 reader->node = reader->node->children->children;
887 }
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000888 } else if ((reader->node != NULL) &&
889 (reader->node->type == XML_ENTITY_REF_NODE) &&
Daniel Veillardf4e55762003-04-15 23:32:22 +0000890 (reader->ctxt != NULL) && (reader->validate)) {
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000891 xmlTextReaderValidateEntity(reader);
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000892 }
893 if ((reader->node != NULL) &&
894 (reader->node->type == XML_ENTITY_DECL) &&
895 (reader->ent != NULL) && (reader->ent->children == reader->node)) {
896 reader->node = xmlTextReaderEntPop(reader);
897 reader->depth++;
898 goto get_next_node;
899 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000900#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardf4e55762003-04-15 23:32:22 +0000901 if ((reader->validate) && (reader->node != NULL)) {
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000902 xmlNodePtr node = reader->node;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000903
904 if ((node->type == XML_ELEMENT_NODE) &&
905 ((reader->state != XML_TEXTREADER_END) &&
906 (reader->state != XML_TEXTREADER_BACKTRACK))) {
907 xmlTextReaderValidatePush(reader);
908 } else if ((node->type == XML_TEXT_NODE) ||
909 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillardf4e55762003-04-15 23:32:22 +0000910 xmlTextReaderValidateCData(reader, node->content,
911 xmlStrlen(node->content));
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000912 }
913 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000914#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000915 return(1);
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000916node_end:
Daniel Veillardc6cae7b2003-04-11 09:02:11 +0000917 reader->mode = XML_TEXTREADER_DONE;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000918 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000919}
920
Daniel Veillard67df8092002-12-16 22:04:11 +0000921/**
922 * xmlTextReaderReadState:
923 * @reader: the xmlTextReaderPtr used
924 *
925 * Gets the read state of the reader.
926 *
927 * Returns the state value, or -1 in case of error
928 */
929int
930xmlTextReaderReadState(xmlTextReaderPtr reader) {
931 if (reader == NULL)
932 return(-1);
933 return(reader->mode);
934}
935
936/**
Daniel Veillardc6cae7b2003-04-11 09:02:11 +0000937 * xmlTextReaderExpand:
938 * @reader: the xmlTextReaderPtr used
939 *
940 * Reads the contents of the current node and the full subtree. It then makes
941 * the subtree availsble until the next xmlTextReaderRead() call
942 *
943 * Returns a node pointer valid until the next xmlTextReaderRead() call
944 * or NULL in case of error.
945 */
946xmlNodePtr
947xmlTextReaderExpand(xmlTextReaderPtr reader) {
948 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
949 return(NULL);
950 if (xmlTextReaderDoExpand(reader) < 0)
951 return(NULL);
952 return(reader->node);
953}
954
955/**
956 * xmlTextReaderNext:
957 * @reader: the xmlTextReaderPtr used
958 *
959 * Skip to the node following the current one in document order while
960 * avoiding the subtree if any.
961 *
962 * Returns 1 if the node was read successfully, 0 if there is no more
963 * nodes to read, or -1 in case of error
964 */
965int
966xmlTextReaderNext(xmlTextReaderPtr reader) {
967 int ret;
968 xmlNodePtr cur;
969
970 if (reader == NULL)
971 return(-1);
972 cur = reader->node;
973 if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
974 return(xmlTextReaderRead(reader));
975 if (reader->state == XML_TEXTREADER_END)
976 return(xmlTextReaderRead(reader));
977 if (cur->_private == (void *)xmlTextReaderIsEmpty)
978 return(xmlTextReaderRead(reader));
979 do {
980 ret = xmlTextReaderRead(reader);
981 if (ret != 1)
982 return(ret);
983 } while (reader->node != cur);
984 return(xmlTextReaderRead(reader));
985}
986
987/**
Daniel Veillard67df8092002-12-16 22:04:11 +0000988 * xmlTextReaderReadInnerXml:
989 * @reader: the xmlTextReaderPtr used
990 *
991 * Reads the contents of the current node, including child nodes and markup.
992 *
993 * Returns a string containing the XML content, or NULL if the current node
994 * is neither an element nor attribute, or has no child nodes. The
995 * string must be deallocated by the caller.
996 */
997xmlChar *
Daniel Veillard33300b42003-04-17 09:09:19 +0000998xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
Daniel Veillard67df8092002-12-16 22:04:11 +0000999 TODO
1000 return(NULL);
1001}
1002
1003/**
1004 * xmlTextReaderReadOuterXml:
1005 * @reader: the xmlTextReaderPtr used
1006 *
1007 * Reads the contents of the current node, including child nodes and markup.
1008 *
1009 * Returns a string containing the XML content, or NULL if the current node
1010 * is neither an element nor attribute, or has no child nodes. The
1011 * string must be deallocated by the caller.
1012 */
1013xmlChar *
Daniel Veillard33300b42003-04-17 09:09:19 +00001014xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
Daniel Veillard67df8092002-12-16 22:04:11 +00001015 TODO
1016 return(NULL);
1017}
1018
1019/**
1020 * xmlTextReaderReadString:
1021 * @reader: the xmlTextReaderPtr used
1022 *
1023 * Reads the contents of an element or a text node as a string.
1024 *
1025 * Returns a string containing the contents of the Element or Text node,
1026 * or NULL if the reader is positioned on any other type of node.
1027 * The string must be deallocated by the caller.
1028 */
1029xmlChar *
Daniel Veillard33300b42003-04-17 09:09:19 +00001030xmlTextReaderReadString(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
Daniel Veillard67df8092002-12-16 22:04:11 +00001031 TODO
1032 return(NULL);
1033}
1034
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001035/**
1036 * xmlTextReaderReadBase64:
1037 * @reader: the xmlTextReaderPtr used
1038 * @array: a byte array to store the content.
1039 * @offset: the zero-based index into array where the method should
1040 * begin to write.
1041 * @len: the number of bytes to write.
1042 *
1043 * Reads and decodes the Base64 encoded contents of an element and
1044 * stores the result in a byte buffer.
1045 *
1046 * Returns the number of bytes written to array, or zero if the current
1047 * instance is not positioned on an element or -1 in case of error.
1048 */
1049int
1050xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
1051 int offset, int len) {
1052 if ((reader == NULL) || (reader->ctxt == NULL))
1053 return(-1);
1054 if (reader->ctxt->wellFormed != 1)
1055 return(-1);
1056
1057 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1058 return(0);
1059 TODO
1060 return(0);
1061}
1062
1063/**
1064 * xmlTextReaderReadBinHex:
1065 * @reader: the xmlTextReaderPtr used
1066 * @array: a byte array to store the content.
1067 * @offset: the zero-based index into array where the method should
1068 * begin to write.
1069 * @len: the number of bytes to write.
1070 *
1071 * Reads and decodes the BinHex encoded contents of an element and
1072 * stores the result in a byte buffer.
1073 *
1074 * Returns the number of bytes written to array, or zero if the current
1075 * instance is not positioned on an element or -1 in case of error.
1076 */
1077int
1078xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
1079 int offset, int len) {
1080 if ((reader == NULL) || (reader->ctxt == NULL))
1081 return(-1);
1082 if (reader->ctxt->wellFormed != 1)
1083 return(-1);
1084
1085 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1086 return(0);
1087 TODO
1088 return(0);
1089}
1090
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001091/************************************************************************
1092 * *
1093 * Constructor and destructors *
1094 * *
1095 ************************************************************************/
1096/**
1097 * xmlNewTextReader:
1098 * @input: the xmlParserInputBufferPtr used to read data
Daniel Veillardea7751d2002-12-20 00:16:24 +00001099 * @URI: the URI information for the source if available
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001100 *
1101 * Create an xmlTextReader structure fed with @input
1102 *
1103 * Returns the new xmlTextReaderPtr or NULL in case of error
1104 */
1105xmlTextReaderPtr
Daniel Veillardea7751d2002-12-20 00:16:24 +00001106xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001107 xmlTextReaderPtr ret;
1108 int val;
1109
1110 if (input == NULL)
1111 return(NULL);
1112 ret = xmlMalloc(sizeof(xmlTextReader));
1113 if (ret == NULL) {
1114 xmlGenericError(xmlGenericErrorContext,
1115 "xmlNewTextReader : malloc failed\n");
1116 return(NULL);
1117 }
1118 memset(ret, 0, sizeof(xmlTextReader));
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001119 ret->entTab = NULL;
1120 ret->entMax = 0;
1121 ret->entNr = 0;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001122 ret->input = input;
1123 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
1124 if (ret->sax == NULL) {
1125 xmlFree(ret);
1126 xmlGenericError(xmlGenericErrorContext,
1127 "xmlNewTextReader : malloc failed\n");
1128 return(NULL);
1129 }
1130 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
1131 ret->startElement = ret->sax->startElement;
1132 ret->sax->startElement = xmlTextReaderStartElement;
1133 ret->endElement = ret->sax->endElement;
1134 ret->sax->endElement = xmlTextReaderEndElement;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001135 ret->characters = ret->sax->characters;
1136 ret->sax->characters = xmlTextReaderCharacters;
1137 ret->cdataBlock = ret->sax->cdataBlock;
1138 ret->sax->cdataBlock = xmlTextReaderCDataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001139
Daniel Veillard67df8092002-12-16 22:04:11 +00001140 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001141 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001142 ret->curnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001143 val = xmlParserInputBufferRead(input, 4);
1144 if (val >= 4) {
1145 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
Daniel Veillardea7751d2002-12-20 00:16:24 +00001146 (const char *) ret->input->buffer->content, 4, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001147 ret->base = 0;
1148 ret->cur = 4;
1149 } else {
Daniel Veillardea7751d2002-12-20 00:16:24 +00001150 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001151 ret->base = 0;
1152 ret->cur = 0;
1153 }
1154 ret->ctxt->_private = ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001155 ret->ctxt->linenumbers = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001156 ret->allocs = XML_TEXTREADER_CTXT;
1157 return(ret);
1158
1159}
1160
1161/**
1162 * xmlNewTextReaderFilename:
1163 * @URI: the URI of the resource to process
1164 *
1165 * Create an xmlTextReader structure fed with the resource at @URI
1166 *
1167 * Returns the new xmlTextReaderPtr or NULL in case of error
1168 */
1169xmlTextReaderPtr
1170xmlNewTextReaderFilename(const char *URI) {
1171 xmlParserInputBufferPtr input;
1172 xmlTextReaderPtr ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001173 char *directory = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001174
1175 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
1176 if (input == NULL)
1177 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00001178 ret = xmlNewTextReader(input, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001179 if (ret == NULL) {
1180 xmlFreeParserInputBuffer(input);
1181 return(NULL);
1182 }
1183 ret->allocs |= XML_TEXTREADER_INPUT;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001184 if (ret->ctxt->directory == NULL)
1185 directory = xmlParserGetDirectory(URI);
1186 if ((ret->ctxt->directory == NULL) && (directory != NULL))
1187 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
1188 if (directory != NULL)
1189 xmlFree(directory);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001190 return(ret);
1191}
1192
1193/**
1194 * xmlFreeTextReader:
1195 * @reader: the xmlTextReaderPtr
1196 *
1197 * Deallocate all the resources associated to the reader
1198 */
1199void
1200xmlFreeTextReader(xmlTextReaderPtr reader) {
1201 if (reader == NULL)
1202 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00001203 if (reader->rngSchemas != NULL) {
1204 xmlRelaxNGFree(reader->rngSchemas);
1205 reader->rngSchemas = NULL;
1206 }
1207 if (reader->rngValidCtxt != NULL) {
1208 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
1209 reader->rngValidCtxt = NULL;
1210 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001211 if (reader->ctxt != NULL) {
1212 if (reader->ctxt->myDoc != NULL) {
1213 xmlFreeDoc(reader->ctxt->myDoc);
1214 reader->ctxt->myDoc = NULL;
1215 }
Daniel Veillard336fc7d2002-12-27 19:37:04 +00001216 if ((reader->ctxt->vctxt.vstateTab != NULL) &&
1217 (reader->ctxt->vctxt.vstateMax > 0)){
1218 xmlFree(reader->ctxt->vctxt.vstateTab);
1219 reader->ctxt->vctxt.vstateTab = 0;
1220 reader->ctxt->vctxt.vstateMax = 0;
1221 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001222 if (reader->allocs & XML_TEXTREADER_CTXT)
1223 xmlFreeParserCtxt(reader->ctxt);
1224 }
1225 if (reader->sax != NULL)
1226 xmlFree(reader->sax);
1227 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
1228 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001229 if (reader->faketext != NULL) {
1230 xmlFreeNode(reader->faketext);
1231 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001232 if (reader->entTab != NULL)
1233 xmlFree(reader->entTab);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001234 xmlFree(reader);
1235}
1236
1237/************************************************************************
1238 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001239 * Methods for XmlTextReader *
1240 * *
1241 ************************************************************************/
1242/**
1243 * xmlTextReaderClose:
1244 * @reader: the xmlTextReaderPtr used
1245 *
1246 * This method releases any resources allocated by the current instance
1247 * changes the state to Closed and close any underlying input.
1248 *
1249 * Returns 0 or -1 in case of error
1250 */
1251int
1252xmlTextReaderClose(xmlTextReaderPtr reader) {
1253 if (reader == NULL)
1254 return(-1);
1255 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001256 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001257 reader->mode = XML_TEXTREADER_MODE_CLOSED;
1258 if (reader->ctxt != NULL) {
1259 if (reader->ctxt->myDoc != NULL) {
1260 xmlFreeDoc(reader->ctxt->myDoc);
1261 reader->ctxt->myDoc = NULL;
1262 }
1263 if (reader->allocs & XML_TEXTREADER_CTXT) {
1264 xmlFreeParserCtxt(reader->ctxt);
1265 reader->allocs -= XML_TEXTREADER_CTXT;
1266 }
1267 }
1268 if (reader->sax != NULL) {
1269 xmlFree(reader->sax);
1270 reader->sax = NULL;
1271 }
1272 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
1273 xmlFreeParserInputBuffer(reader->input);
1274 reader->allocs -= XML_TEXTREADER_INPUT;
1275 }
1276 return(0);
1277}
1278
1279/**
1280 * xmlTextReaderGetAttributeNo:
1281 * @reader: the xmlTextReaderPtr used
1282 * @no: the zero-based index of the attribute relative to the containing element
1283 *
1284 * Provides the value of the attribute with the specified index relative
1285 * to the containing element.
1286 *
1287 * Returns a string containing the value of the specified attribute, or NULL
1288 * in case of error. The string must be deallocated by the caller.
1289 */
1290xmlChar *
1291xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
1292 xmlChar *ret;
1293 int i;
1294 xmlAttrPtr cur;
1295 xmlNsPtr ns;
1296
1297 if (reader == NULL)
1298 return(NULL);
1299 if (reader->node == NULL)
1300 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001301 if (reader->curnode != NULL)
1302 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001303 /* TODO: handle the xmlDecl */
1304 if (reader->node->type != XML_ELEMENT_NODE)
1305 return(NULL);
1306
1307 ns = reader->node->nsDef;
1308 for (i = 0;(i < no) && (ns != NULL);i++) {
1309 ns = ns->next;
1310 }
1311 if (ns != NULL)
1312 return(xmlStrdup(ns->href));
1313
1314 cur = reader->node->properties;
1315 if (cur == NULL)
1316 return(NULL);
1317 for (;i < no;i++) {
1318 cur = cur->next;
1319 if (cur == NULL)
1320 return(NULL);
1321 }
1322 /* TODO walk the DTD if present */
1323
1324 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
1325 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
1326 return(ret);
1327}
1328
1329/**
1330 * xmlTextReaderGetAttribute:
1331 * @reader: the xmlTextReaderPtr used
1332 * @name: the qualified name of the attribute.
1333 *
1334 * Provides the value of the attribute with the specified qualified name.
1335 *
1336 * Returns a string containing the value of the specified attribute, or NULL
1337 * in case of error. The string must be deallocated by the caller.
1338 */
1339xmlChar *
1340xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1341 xmlChar *prefix = NULL;
1342 xmlChar *localname;
1343 xmlNsPtr ns;
1344 xmlChar *ret = NULL;
1345
1346 if ((reader == NULL) || (name == NULL))
1347 return(NULL);
1348 if (reader->node == NULL)
1349 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001350 if (reader->curnode != NULL)
1351 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001352
1353 /* TODO: handle the xmlDecl */
1354 if (reader->node->type != XML_ELEMENT_NODE)
1355 return(NULL);
1356
1357 localname = xmlSplitQName2(name, &prefix);
1358 if (localname == NULL)
1359 return(xmlGetProp(reader->node, name));
1360
1361 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1362 if (ns != NULL)
1363 ret = xmlGetNsProp(reader->node, localname, ns->href);
1364
1365 if (localname != NULL)
1366 xmlFree(localname);
1367 if (prefix != NULL)
1368 xmlFree(prefix);
1369 return(ret);
1370}
1371
1372
1373/**
1374 * xmlTextReaderGetAttributeNs:
1375 * @reader: the xmlTextReaderPtr used
1376 * @localName: the local name of the attribute.
1377 * @namespaceURI: the namespace URI of the attribute.
1378 *
1379 * Provides the value of the specified attribute
1380 *
1381 * Returns a string containing the value of the specified attribute, or NULL
1382 * in case of error. The string must be deallocated by the caller.
1383 */
1384xmlChar *
1385xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
1386 const xmlChar *namespaceURI) {
1387 if ((reader == NULL) || (localName == NULL))
1388 return(NULL);
1389 if (reader->node == NULL)
1390 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001391 if (reader->curnode != NULL)
1392 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001393
1394 /* TODO: handle the xmlDecl */
1395 if (reader->node->type != XML_ELEMENT_NODE)
1396 return(NULL);
1397
1398 return(xmlGetNsProp(reader->node, localName, namespaceURI));
1399}
1400
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001401/**
1402 * xmlTextReaderGetRemainder:
1403 * @reader: the xmlTextReaderPtr used
1404 *
1405 * Method to get the remainder of the buffered XML. this method stops the
1406 * parser, set its state to End Of File and return the input stream with
1407 * what is left that the parser did not use.
1408 *
1409 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
1410 * in case of error.
1411 */
1412xmlParserInputBufferPtr
1413xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
1414 xmlParserInputBufferPtr ret = NULL;
1415
1416 if (reader == NULL)
1417 return(NULL);
1418 if (reader->node == NULL)
1419 return(NULL);
1420
1421 reader->node = NULL;
1422 reader->curnode = NULL;
1423 reader->mode = XML_TEXTREADER_MODE_EOF;
1424 if (reader->ctxt != NULL) {
1425 if (reader->ctxt->myDoc != NULL) {
1426 xmlFreeDoc(reader->ctxt->myDoc);
1427 reader->ctxt->myDoc = NULL;
1428 }
1429 if (reader->allocs & XML_TEXTREADER_CTXT) {
1430 xmlFreeParserCtxt(reader->ctxt);
1431 reader->allocs -= XML_TEXTREADER_CTXT;
1432 }
1433 }
1434 if (reader->sax != NULL) {
1435 xmlFree(reader->sax);
1436 reader->sax = NULL;
1437 }
1438 if (reader->allocs & XML_TEXTREADER_INPUT) {
1439 ret = reader->input;
1440 reader->allocs -= XML_TEXTREADER_INPUT;
1441 } else {
1442 /*
1443 * Hum, one may need to duplicate the data structure because
1444 * without reference counting the input may be freed twice:
1445 * - by the layer which allocated it.
1446 * - by the layer to which would have been returned to.
1447 */
1448 TODO
1449 return(NULL);
1450 }
1451 return(ret);
1452}
1453
1454/**
1455 * xmlTextReaderLookupNamespace:
1456 * @reader: the xmlTextReaderPtr used
1457 * @prefix: the prefix whose namespace URI is to be resolved. To return
1458 * the default namespace, specify NULL
1459 *
1460 * Resolves a namespace prefix in the scope of the current element.
1461 *
1462 * Returns a string containing the namespace URI to which the prefix maps
1463 * or NULL in case of error. The string must be deallocated by the caller.
1464 */
1465xmlChar *
1466xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
1467 xmlNsPtr ns;
1468
1469 if (reader == NULL)
1470 return(NULL);
1471 if (reader->node == NULL)
1472 return(NULL);
1473
1474 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1475 if (ns == NULL)
1476 return(NULL);
1477 return(xmlStrdup(ns->href));
1478}
1479
1480/**
1481 * xmlTextReaderMoveToAttributeNo:
1482 * @reader: the xmlTextReaderPtr used
1483 * @no: the zero-based index of the attribute relative to the containing
1484 * element.
1485 *
1486 * Moves the position of the current instance to the attribute with
1487 * the specified index relative to the containing element.
1488 *
1489 * Returns 1 in case of success, -1 in case of error, 0 if not found
1490 */
1491int
1492xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
1493 int i;
1494 xmlAttrPtr cur;
1495 xmlNsPtr ns;
1496
1497 if (reader == NULL)
1498 return(-1);
1499 if (reader->node == NULL)
1500 return(-1);
1501 /* TODO: handle the xmlDecl */
1502 if (reader->node->type != XML_ELEMENT_NODE)
1503 return(-1);
1504
1505 reader->curnode = NULL;
1506
1507 ns = reader->node->nsDef;
1508 for (i = 0;(i < no) && (ns != NULL);i++) {
1509 ns = ns->next;
1510 }
1511 if (ns != NULL) {
1512 reader->curnode = (xmlNodePtr) ns;
1513 return(1);
1514 }
1515
1516 cur = reader->node->properties;
1517 if (cur == NULL)
1518 return(0);
1519 for (;i < no;i++) {
1520 cur = cur->next;
1521 if (cur == NULL)
1522 return(0);
1523 }
1524 /* TODO walk the DTD if present */
1525
1526 reader->curnode = (xmlNodePtr) cur;
1527 return(1);
1528}
1529
1530/**
1531 * xmlTextReaderMoveToAttribute:
1532 * @reader: the xmlTextReaderPtr used
1533 * @name: the qualified name of the attribute.
1534 *
1535 * Moves the position of the current instance to the attribute with
1536 * the specified qualified name.
1537 *
1538 * Returns 1 in case of success, -1 in case of error, 0 if not found
1539 */
1540int
1541xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1542 xmlChar *prefix = NULL;
1543 xmlChar *localname;
1544 xmlNsPtr ns;
1545 xmlAttrPtr prop;
1546
1547 if ((reader == NULL) || (name == NULL))
1548 return(-1);
1549 if (reader->node == NULL)
1550 return(-1);
1551
1552 /* TODO: handle the xmlDecl */
1553 if (reader->node->type != XML_ELEMENT_NODE)
1554 return(0);
1555
1556 localname = xmlSplitQName2(name, &prefix);
1557 if (localname == NULL) {
1558 /*
1559 * Namespace default decl
1560 */
1561 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1562 ns = reader->node->nsDef;
1563 while (ns != NULL) {
1564 if (ns->prefix == NULL) {
1565 reader->curnode = (xmlNodePtr) ns;
1566 return(1);
1567 }
1568 ns = ns->next;
1569 }
1570 return(0);
1571 }
1572
1573 prop = reader->node->properties;
1574 while (prop != NULL) {
1575 /*
1576 * One need to have
1577 * - same attribute names
1578 * - and the attribute carrying that namespace
1579 */
1580 if ((xmlStrEqual(prop->name, name)) &&
1581 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
1582 reader->curnode = (xmlNodePtr) prop;
1583 return(1);
1584 }
1585 prop = prop->next;
1586 }
1587 return(0);
1588 }
1589
1590 /*
1591 * Namespace default decl
1592 */
1593 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
1594 ns = reader->node->nsDef;
1595 while (ns != NULL) {
1596 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
1597 reader->curnode = (xmlNodePtr) ns;
1598 goto found;
1599 }
1600 ns = ns->next;
1601 }
1602 goto not_found;
1603 }
1604 prop = reader->node->properties;
1605 while (prop != NULL) {
1606 /*
1607 * One need to have
1608 * - same attribute names
1609 * - and the attribute carrying that namespace
1610 */
1611 if ((xmlStrEqual(prop->name, localname)) &&
1612 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
1613 reader->curnode = (xmlNodePtr) prop;
1614 goto found;
1615 }
1616 prop = prop->next;
1617 }
1618not_found:
1619 if (localname != NULL)
1620 xmlFree(localname);
1621 if (prefix != NULL)
1622 xmlFree(prefix);
1623 return(0);
1624
1625found:
1626 if (localname != NULL)
1627 xmlFree(localname);
1628 if (prefix != NULL)
1629 xmlFree(prefix);
1630 return(1);
1631}
1632
1633/**
1634 * xmlTextReaderMoveToAttributeNs:
1635 * @reader: the xmlTextReaderPtr used
1636 * @localName: the local name of the attribute.
1637 * @namespaceURI: the namespace URI of the attribute.
1638 *
1639 * Moves the position of the current instance to the attribute with the
1640 * specified local name and namespace URI.
1641 *
1642 * Returns 1 in case of success, -1 in case of error, 0 if not found
1643 */
1644int
1645xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1646 const xmlChar *localName, const xmlChar *namespaceURI) {
1647 xmlAttrPtr prop;
1648 xmlNodePtr node;
1649
1650 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1651 return(-1);
1652 if (reader->node == NULL)
1653 return(-1);
1654 if (reader->node->type != XML_ELEMENT_NODE)
1655 return(0);
1656 node = reader->node;
1657
1658 /*
1659 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1660 * namespace name associated to "xmlns"
1661 */
1662 prop = node->properties;
1663 while (prop != NULL) {
1664 /*
1665 * One need to have
1666 * - same attribute names
1667 * - and the attribute carrying that namespace
1668 */
1669 if (xmlStrEqual(prop->name, localName) &&
1670 ((prop->ns != NULL) &&
1671 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1672 reader->curnode = (xmlNodePtr) prop;
1673 return(1);
1674 }
1675 prop = prop->next;
1676 }
1677 return(0);
1678}
1679
1680/**
1681 * xmlTextReaderMoveToFirstAttribute:
1682 * @reader: the xmlTextReaderPtr used
1683 *
1684 * Moves the position of the current instance to the first attribute
1685 * associated with the current node.
1686 *
1687 * Returns 1 in case of success, -1 in case of error, 0 if not found
1688 */
1689int
1690xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1691 if (reader == NULL)
1692 return(-1);
1693 if (reader->node == NULL)
1694 return(-1);
1695 if (reader->node->type != XML_ELEMENT_NODE)
1696 return(0);
1697
1698 if (reader->node->nsDef != NULL) {
1699 reader->curnode = (xmlNodePtr) reader->node->nsDef;
1700 return(1);
1701 }
1702 if (reader->node->properties != NULL) {
1703 reader->curnode = (xmlNodePtr) reader->node->properties;
1704 return(1);
1705 }
1706 return(0);
1707}
1708
1709/**
1710 * xmlTextReaderMoveToNextAttribute:
1711 * @reader: the xmlTextReaderPtr used
1712 *
1713 * Moves the position of the current instance to the next attribute
1714 * associated with the current node.
1715 *
1716 * Returns 1 in case of success, -1 in case of error, 0 if not found
1717 */
1718int
1719xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1720 if (reader == NULL)
1721 return(-1);
1722 if (reader->node == NULL)
1723 return(-1);
1724 if (reader->node->type != XML_ELEMENT_NODE)
1725 return(0);
1726 if (reader->curnode == NULL)
1727 return(xmlTextReaderMoveToFirstAttribute(reader));
1728
1729 if (reader->curnode->type == XML_NAMESPACE_DECL) {
1730 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1731 if (ns->next != NULL) {
1732 reader->curnode = (xmlNodePtr) ns->next;
1733 return(1);
1734 }
1735 if (reader->node->properties != NULL) {
1736 reader->curnode = (xmlNodePtr) reader->node->properties;
1737 return(1);
1738 }
1739 return(0);
1740 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1741 (reader->curnode->next != NULL)) {
1742 reader->curnode = reader->curnode->next;
1743 return(1);
1744 }
1745 return(0);
1746}
1747
1748/**
1749 * xmlTextReaderMoveToElement:
1750 * @reader: the xmlTextReaderPtr used
1751 *
1752 * Moves the position of the current instance to the node that
1753 * contains the current Attribute node.
1754 *
1755 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1756 */
1757int
1758xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
1759 if (reader == NULL)
1760 return(-1);
1761 if (reader->node == NULL)
1762 return(-1);
1763 if (reader->node->type != XML_ELEMENT_NODE)
1764 return(0);
1765 if (reader->curnode != NULL) {
1766 reader->curnode = NULL;
1767 return(1);
1768 }
1769 return(0);
1770}
1771
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001772/**
1773 * xmlTextReaderReadAttributeValue:
1774 * @reader: the xmlTextReaderPtr used
1775 *
1776 * Parses an attribute value into one or more Text and EntityReference nodes.
1777 *
1778 * Returns 1 in case of success, 0 if the reader was not positionned on an
1779 * ttribute node or all the attribute values have been read, or -1
1780 * in case of error.
1781 */
1782int
1783xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1784 if (reader == NULL)
1785 return(-1);
1786 if (reader->node == NULL)
1787 return(-1);
1788 if (reader->curnode == NULL)
1789 return(0);
1790 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1791 if (reader->curnode->children == NULL)
1792 return(0);
1793 reader->curnode = reader->curnode->children;
1794 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1795 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1796
1797 if (reader->faketext == NULL) {
1798 reader->faketext = xmlNewDocText(reader->node->doc,
1799 ns->href);
1800 } else {
1801 if (reader->faketext->content != NULL)
1802 xmlFree(reader->faketext->content);
1803 reader->faketext->content = xmlStrdup(ns->href);
1804 }
1805 reader->curnode = reader->faketext;
1806 } else {
1807 if (reader->curnode->next == NULL)
1808 return(0);
1809 reader->curnode = reader->curnode->next;
1810 }
1811 return(1);
1812}
1813
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001814/************************************************************************
1815 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001816 * Acces API to the current node *
1817 * *
1818 ************************************************************************/
1819/**
1820 * xmlTextReaderAttributeCount:
1821 * @reader: the xmlTextReaderPtr used
1822 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001823 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001824 *
1825 * Returns 0 i no attributes, -1 in case of error or the attribute count
1826 */
1827int
1828xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1829 int ret;
1830 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00001831 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001832 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001833
1834 if (reader == NULL)
1835 return(-1);
1836 if (reader->node == NULL)
1837 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001838
1839 if (reader->curnode != NULL)
1840 node = reader->curnode;
1841 else
1842 node = reader->node;
1843
1844 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001845 return(0);
1846 if ((reader->state == XML_TEXTREADER_END) ||
1847 (reader->state == XML_TEXTREADER_BACKTRACK))
1848 return(0);
1849 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001850 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001851 while (attr != NULL) {
1852 ret++;
1853 attr = attr->next;
1854 }
Daniel Veillard67df8092002-12-16 22:04:11 +00001855 ns = node->nsDef;
1856 while (ns != NULL) {
1857 ret++;
1858 ns = ns->next;
1859 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001860 return(ret);
1861}
1862
1863/**
1864 * xmlTextReaderNodeType:
1865 * @reader: the xmlTextReaderPtr used
1866 *
1867 * Get the node type of the current node
1868 * Reference:
1869 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1870 *
1871 * Returns the xmlNodeType of the current node or -1 in case of error
1872 */
1873int
1874xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001875 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001876 if (reader == NULL)
1877 return(-1);
1878 if (reader->node == NULL)
1879 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001880 if (reader->curnode != NULL)
1881 node = reader->curnode;
1882 else
1883 node = reader->node;
1884 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001885 case XML_ELEMENT_NODE:
1886 if ((reader->state == XML_TEXTREADER_END) ||
1887 (reader->state == XML_TEXTREADER_BACKTRACK))
1888 return(15);
1889 return(1);
Daniel Veillardecaba492002-12-30 10:55:29 +00001890 case XML_NAMESPACE_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001891 case XML_ATTRIBUTE_NODE:
1892 return(2);
1893 case XML_TEXT_NODE:
1894 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1895 case XML_CDATA_SECTION_NODE:
1896 return(4);
1897 case XML_ENTITY_REF_NODE:
1898 return(5);
1899 case XML_ENTITY_NODE:
1900 return(6);
1901 case XML_PI_NODE:
1902 return(7);
1903 case XML_COMMENT_NODE:
1904 return(8);
1905 case XML_DOCUMENT_NODE:
1906 case XML_HTML_DOCUMENT_NODE:
1907#ifdef LIBXML_DOCB_ENABLED
1908 case XML_DOCB_DOCUMENT_NODE:
1909#endif
1910 return(9);
1911 case XML_DOCUMENT_FRAG_NODE:
1912 return(11);
1913 case XML_NOTATION_NODE:
1914 return(12);
1915 case XML_DOCUMENT_TYPE_NODE:
1916 case XML_DTD_NODE:
1917 return(10);
1918
1919 case XML_ELEMENT_DECL:
1920 case XML_ATTRIBUTE_DECL:
1921 case XML_ENTITY_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001922 case XML_XINCLUDE_START:
1923 case XML_XINCLUDE_END:
1924 return(0);
1925 }
1926 return(-1);
1927}
1928
1929/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001930 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001931 * @reader: the xmlTextReaderPtr used
1932 *
1933 * Check if the current node is empty
1934 *
1935 * Returns 1 if empty, 0 if not and -1 in case of error
1936 */
1937int
1938xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1939 if ((reader == NULL) || (reader->node == NULL))
1940 return(-1);
Daniel Veillarddf512f42002-12-23 15:56:21 +00001941 if (reader->node->type != XML_ELEMENT_NODE)
1942 return(0);
Daniel Veillarde3c036e2003-01-01 15:11:05 +00001943 if (reader->curnode != NULL)
1944 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001945 if (reader->node->children != NULL)
1946 return(0);
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001947 if (reader->state == XML_TEXTREADER_END)
1948 return(0);
Daniel Veillard067bae52003-01-05 01:27:54 +00001949 return(reader->node->_private == (void *)xmlTextReaderIsEmpty);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001950}
1951
1952/**
1953 * xmlTextReaderLocalName:
1954 * @reader: the xmlTextReaderPtr used
1955 *
1956 * The local name of the node.
1957 *
1958 * Returns the local name or NULL if not available
1959 */
1960xmlChar *
1961xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001962 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001963 if ((reader == NULL) || (reader->node == NULL))
1964 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001965 if (reader->curnode != NULL)
1966 node = reader->curnode;
1967 else
1968 node = reader->node;
1969 if (node->type == XML_NAMESPACE_DECL) {
1970 xmlNsPtr ns = (xmlNsPtr) node;
1971 if (ns->prefix == NULL)
1972 return(xmlStrdup(BAD_CAST "xmlns"));
1973 else
1974 return(xmlStrdup(ns->prefix));
1975 }
1976 if ((node->type != XML_ELEMENT_NODE) &&
1977 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001978 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001979 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001980}
1981
1982/**
1983 * xmlTextReaderName:
1984 * @reader: the xmlTextReaderPtr used
1985 *
1986 * The qualified name of the node, equal to Prefix :LocalName.
1987 *
1988 * Returns the local name or NULL if not available
1989 */
1990xmlChar *
1991xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001992 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001993 xmlChar *ret;
1994
1995 if ((reader == NULL) || (reader->node == NULL))
1996 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001997 if (reader->curnode != NULL)
1998 node = reader->curnode;
1999 else
2000 node = reader->node;
2001 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002002 case XML_ELEMENT_NODE:
2003 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002004 if ((node->ns == NULL) ||
2005 (node->ns->prefix == NULL))
2006 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002007
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002008 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002009 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002010 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002011 return(ret);
2012 case XML_TEXT_NODE:
2013 return(xmlStrdup(BAD_CAST "#text"));
2014 case XML_CDATA_SECTION_NODE:
2015 return(xmlStrdup(BAD_CAST "#cdata-section"));
2016 case XML_ENTITY_NODE:
2017 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002018 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002019 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002020 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002021 case XML_COMMENT_NODE:
2022 return(xmlStrdup(BAD_CAST "#comment"));
2023 case XML_DOCUMENT_NODE:
2024 case XML_HTML_DOCUMENT_NODE:
2025#ifdef LIBXML_DOCB_ENABLED
2026 case XML_DOCB_DOCUMENT_NODE:
2027#endif
2028 return(xmlStrdup(BAD_CAST "#document"));
2029 case XML_DOCUMENT_FRAG_NODE:
2030 return(xmlStrdup(BAD_CAST "#document-fragment"));
2031 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002032 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002033 case XML_DOCUMENT_TYPE_NODE:
2034 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002035 return(xmlStrdup(node->name));
2036 case XML_NAMESPACE_DECL: {
2037 xmlNsPtr ns = (xmlNsPtr) node;
2038
2039 ret = xmlStrdup(BAD_CAST "xmlns");
2040 if (ns->prefix == NULL)
2041 return(ret);
2042 ret = xmlStrcat(ret, BAD_CAST ":");
2043 ret = xmlStrcat(ret, ns->prefix);
2044 return(ret);
2045 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002046
2047 case XML_ELEMENT_DECL:
2048 case XML_ATTRIBUTE_DECL:
2049 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002050 case XML_XINCLUDE_START:
2051 case XML_XINCLUDE_END:
2052 return(NULL);
2053 }
2054 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002055}
2056
2057/**
2058 * xmlTextReaderPrefix:
2059 * @reader: the xmlTextReaderPtr used
2060 *
2061 * A shorthand reference to the namespace associated with the node.
2062 *
2063 * Returns the prefix or NULL if not available
2064 */
2065xmlChar *
2066xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002067 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002068 if ((reader == NULL) || (reader->node == NULL))
2069 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002070 if (reader->curnode != NULL)
2071 node = reader->curnode;
2072 else
2073 node = reader->node;
2074 if (node->type == XML_NAMESPACE_DECL) {
2075 xmlNsPtr ns = (xmlNsPtr) node;
2076 if (ns->prefix == NULL)
2077 return(NULL);
2078 return(xmlStrdup(BAD_CAST "xmlns"));
2079 }
2080 if ((node->type != XML_ELEMENT_NODE) &&
2081 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002082 return(NULL);
Daniel Veillard952379b2003-03-17 15:37:12 +00002083 if ((node->ns != NULL) && (node->ns->prefix != NULL))
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002084 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002085 return(NULL);
2086}
2087
2088/**
2089 * xmlTextReaderNamespaceUri:
2090 * @reader: the xmlTextReaderPtr used
2091 *
2092 * The URI defining the namespace associated with the node.
2093 *
2094 * Returns the namespace URI or NULL if not available
2095 */
2096xmlChar *
2097xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002098 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002099 if ((reader == NULL) || (reader->node == NULL))
2100 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002101 if (reader->curnode != NULL)
2102 node = reader->curnode;
2103 else
2104 node = reader->node;
Daniel Veillardecaba492002-12-30 10:55:29 +00002105 if (node->type == XML_NAMESPACE_DECL)
2106 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002107 if ((node->type != XML_ELEMENT_NODE) &&
2108 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002109 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002110 if (node->ns != NULL)
2111 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002112 return(NULL);
2113}
2114
2115/**
2116 * xmlTextReaderBaseUri:
2117 * @reader: the xmlTextReaderPtr used
2118 *
2119 * The base URI of the node.
2120 *
2121 * Returns the base URI or NULL if not available
2122 */
2123xmlChar *
2124xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
2125 if ((reader == NULL) || (reader->node == NULL))
2126 return(NULL);
2127 return(xmlNodeGetBase(NULL, reader->node));
2128}
2129
2130/**
2131 * xmlTextReaderDepth:
2132 * @reader: the xmlTextReaderPtr used
2133 *
2134 * The depth of the node in the tree.
2135 *
2136 * Returns the depth or -1 in case of error
2137 */
2138int
2139xmlTextReaderDepth(xmlTextReaderPtr reader) {
2140 if (reader == NULL)
2141 return(-1);
2142 if (reader->node == NULL)
2143 return(0);
2144
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002145 if (reader->curnode != NULL) {
2146 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
2147 (reader->curnode->type == XML_NAMESPACE_DECL))
2148 return(reader->depth + 1);
2149 return(reader->depth + 2);
2150 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002151 return(reader->depth);
2152}
2153
2154/**
2155 * xmlTextReaderHasAttributes:
2156 * @reader: the xmlTextReaderPtr used
2157 *
2158 * Whether the node has attributes.
2159 *
2160 * Returns 1 if true, 0 if false, and -1 in case or error
2161 */
2162int
2163xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002164 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002165 if (reader == NULL)
2166 return(-1);
2167 if (reader->node == NULL)
2168 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002169 if (reader->curnode != NULL)
2170 node = reader->curnode;
2171 else
2172 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002173
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002174 if ((node->type == XML_ELEMENT_NODE) &&
2175 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002176 return(1);
2177 /* TODO: handle the xmlDecl */
2178 return(0);
2179}
2180
2181/**
2182 * xmlTextReaderHasValue:
2183 * @reader: the xmlTextReaderPtr used
2184 *
2185 * Whether the node can have a text value.
2186 *
2187 * Returns 1 if true, 0 if false, and -1 in case or error
2188 */
2189int
2190xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002191 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002192 if (reader == NULL)
2193 return(-1);
2194 if (reader->node == NULL)
2195 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002196 if (reader->curnode != NULL)
2197 node = reader->curnode;
2198 else
2199 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002200
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002201 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002202 case XML_ATTRIBUTE_NODE:
2203 case XML_TEXT_NODE:
2204 case XML_CDATA_SECTION_NODE:
2205 case XML_PI_NODE:
2206 case XML_COMMENT_NODE:
Daniel Veillard9e077102003-04-10 13:36:54 +00002207 case XML_NAMESPACE_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002208 return(1);
2209 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002210 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002211 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002212 return(0);
2213}
2214
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002215/**
2216 * xmlTextReaderValue:
2217 * @reader: the xmlTextReaderPtr used
2218 *
2219 * Provides the text value of the node if present
2220 *
2221 * Returns the string or NULL if not available. The retsult must be deallocated
2222 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002223 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002224xmlChar *
2225xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002226 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002227 if (reader == NULL)
2228 return(NULL);
2229 if (reader->node == NULL)
2230 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002231 if (reader->curnode != NULL)
2232 node = reader->curnode;
2233 else
2234 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002235
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002236 switch (node->type) {
2237 case XML_NAMESPACE_DECL:
2238 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002239 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002240 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002241
2242 if (attr->parent != NULL)
2243 return (xmlNodeListGetString
2244 (attr->parent->doc, attr->children, 1));
2245 else
2246 return (xmlNodeListGetString(NULL, attr->children, 1));
2247 break;
2248 }
2249 case XML_TEXT_NODE:
2250 case XML_CDATA_SECTION_NODE:
2251 case XML_PI_NODE:
2252 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002253 if (node->content != NULL)
2254 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002255 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002256 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002257 }
2258 return(NULL);
2259}
2260
2261/**
2262 * xmlTextReaderIsDefault:
2263 * @reader: the xmlTextReaderPtr used
2264 *
2265 * Whether an Attribute node was generated from the default value
2266 * defined in the DTD or schema.
2267 *
2268 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
2269 */
2270int
2271xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
2272 if (reader == NULL)
2273 return(-1);
2274 return(0);
2275}
2276
2277/**
2278 * xmlTextReaderQuoteChar:
2279 * @reader: the xmlTextReaderPtr used
2280 *
2281 * The quotation mark character used to enclose the value of an attribute.
2282 *
2283 * Returns " or ' and -1 in case of error
2284 */
2285int
2286xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
2287 if (reader == NULL)
2288 return(-1);
2289 /* TODO maybe lookup the attribute value for " first */
2290 return((int) '"');
2291}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002292
2293/**
2294 * xmlTextReaderXmlLang:
2295 * @reader: the xmlTextReaderPtr used
2296 *
2297 * The xml:lang scope within which the node resides.
2298 *
2299 * Returns the xml:lang value or NULL if none exists.
2300 */
2301xmlChar *
2302xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
2303 if (reader == NULL)
2304 return(NULL);
2305 if (reader->node == NULL)
2306 return(NULL);
2307 return(xmlNodeGetLang(reader->node));
2308}
2309
Daniel Veillard67df8092002-12-16 22:04:11 +00002310/**
2311 * xmlTextReaderNormalization:
2312 * @reader: the xmlTextReaderPtr used
2313 *
2314 * The value indicating whether to normalize white space and attribute values.
2315 * Since attribute value and end of line normalizations are a MUST in the XML
2316 * specification only the value true is accepted. The broken bahaviour of
2317 * accepting out of range character entities like &#0; is of course not
2318 * supported either.
2319 *
2320 * Returns 1 or -1 in case of error.
2321 */
2322int
2323xmlTextReaderNormalization(xmlTextReaderPtr reader) {
2324 if (reader == NULL)
2325 return(-1);
2326 return(1);
2327}
2328
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002329/************************************************************************
2330 * *
2331 * Extensions to the base APIs *
2332 * *
2333 ************************************************************************/
2334
2335/**
2336 * xmlTextReaderSetParserProp:
2337 * @reader: the xmlTextReaderPtr used
2338 * @prop: the xmlParserProperties to set
2339 * @value: usually 0 or 1 to (de)activate it
2340 *
2341 * Change the parser processing behaviour by changing some of its internal
2342 * properties. Note that some properties can only be changed before any
2343 * read has been done.
2344 *
2345 * Returns 0 if the call was successful, or -1 in case of error
2346 */
2347int
2348xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
2349 xmlParserProperties p = (xmlParserProperties) prop;
2350 xmlParserCtxtPtr ctxt;
2351
2352 if ((reader == NULL) || (reader->ctxt == NULL))
2353 return(-1);
2354 ctxt = reader->ctxt;
2355
2356 switch (p) {
2357 case XML_PARSER_LOADDTD:
2358 if (value != 0) {
2359 if (ctxt->loadsubset == 0) {
2360 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2361 return(-1);
2362 ctxt->loadsubset = XML_DETECT_IDS;
2363 }
2364 } else {
2365 ctxt->loadsubset = 0;
2366 }
2367 return(0);
2368 case XML_PARSER_DEFAULTATTRS:
2369 if (value != 0) {
2370 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
2371 } else {
2372 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2373 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
2374 }
2375 return(0);
2376 case XML_PARSER_VALIDATE:
2377 if (value != 0) {
2378 ctxt->validate = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00002379 reader->validate = XML_TEXTREADER_VALIDATE_DTD;
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002380 } else {
2381 ctxt->validate = 0;
2382 }
2383 return(0);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002384 case XML_PARSER_SUBST_ENTITIES:
2385 if (value != 0) {
2386 ctxt->replaceEntities = 1;
2387 } else {
2388 ctxt->replaceEntities = 0;
2389 }
2390 return(0);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002391 }
2392 return(-1);
2393}
2394
2395/**
2396 * xmlTextReaderGetParserProp:
2397 * @reader: the xmlTextReaderPtr used
2398 * @prop: the xmlParserProperties to get
2399 *
2400 * Read the parser internal property.
2401 *
2402 * Returns the value, usually 0 or 1, or -1 in case of error.
2403 */
2404int
2405xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
2406 xmlParserProperties p = (xmlParserProperties) prop;
2407 xmlParserCtxtPtr ctxt;
2408
2409 if ((reader == NULL) || (reader->ctxt == NULL))
2410 return(-1);
2411 ctxt = reader->ctxt;
2412
2413 switch (p) {
2414 case XML_PARSER_LOADDTD:
2415 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
2416 return(1);
2417 return(0);
2418 case XML_PARSER_DEFAULTATTRS:
2419 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2420 return(1);
2421 return(0);
2422 case XML_PARSER_VALIDATE:
Daniel Veillardf4e55762003-04-15 23:32:22 +00002423 return(reader->validate);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002424 case XML_PARSER_SUBST_ENTITIES:
2425 return(ctxt->replaceEntities);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002426 }
2427 return(-1);
2428}
2429
Daniel Veillarde18fc182002-12-28 22:56:33 +00002430/**
2431 * xmlTextReaderCurrentNode:
2432 * @reader: the xmlTextReaderPtr used
2433 *
2434 * Hacking interface allowing to get the xmlNodePtr correponding to the
2435 * current node being accessed by the xmlTextReader. This is dangerous
2436 * because the underlying node may be destroyed on the next Reads.
2437 *
2438 * Returns the xmlNodePtr or NULL in case of error.
2439 */
2440xmlNodePtr
2441xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
2442 if (reader == NULL)
2443 return(NULL);
2444
2445 if (reader->curnode != NULL)
2446 return(reader->curnode);
2447 return(reader->node);
2448}
2449
2450/**
2451 * xmlTextReaderCurrentDoc:
2452 * @reader: the xmlTextReaderPtr used
2453 *
2454 * Hacking interface allowing to get the xmlDocPtr correponding to the
2455 * current document being accessed by the xmlTextReader. This is dangerous
2456 * because the associated node may be destroyed on the next Reads.
2457 *
2458 * Returns the xmlDocPtr or NULL in case of error.
2459 */
2460xmlDocPtr
2461xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
2462 if ((reader == NULL) || (reader->ctxt == NULL))
2463 return(NULL);
2464
2465 return(reader->ctxt->myDoc);
2466}
2467
Daniel Veillardf4e55762003-04-15 23:32:22 +00002468/**
Daniel Veillard33300b42003-04-17 09:09:19 +00002469 * xmlTextReaderRelaxNGSetSchema:
2470 * @reader: the xmlTextReaderPtr used
2471 * @schema: a precompiled RelaxNG schema
2472 *
2473 * Use RelaxNG to validate the document as it is processed.
2474 * Activation is only possible before the first Read().
2475 * if @schema is NULL, then RelaxNG validation is desactivated.
2476 @ The @schema should not be freed until the reader is deallocated
2477 * or its use has been deactivated.
2478 *
2479 * Returns 0 in case the RelaxNG validation could be (des)activated and
2480 * -1 in case of error.
2481 */
2482int
2483xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
2484 if (schema == NULL) {
2485 if (reader->rngSchemas != NULL) {
2486 xmlRelaxNGFree(reader->rngSchemas);
2487 reader->rngSchemas = NULL;
2488 }
2489 if (reader->rngValidCtxt != NULL) {
2490 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2491 reader->rngValidCtxt = NULL;
2492 }
2493 return(0);
2494 }
2495 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2496 return(-1);
2497 if (reader->rngSchemas != NULL) {
2498 xmlRelaxNGFree(reader->rngSchemas);
2499 reader->rngSchemas = NULL;
2500 }
2501 if (reader->rngValidCtxt != NULL) {
2502 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2503 reader->rngValidCtxt = NULL;
2504 }
2505 reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
2506 if (reader->rngValidCtxt == NULL)
2507 return(-1);
2508 if (reader->errorFunc != NULL) {
2509 xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
2510 (xmlRelaxNGValidityErrorFunc)reader->errorFunc,
2511 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
2512 reader->errorFuncArg);
2513 }
2514 reader->rngValidErrors = 0;
2515 reader->rngFullNode = NULL;
2516 reader->validate = XML_TEXTREADER_VALIDATE_RNG;
2517 return(0);
2518}
2519
2520/**
Daniel Veillardf4e55762003-04-15 23:32:22 +00002521 * xmlTextReaderRelaxNGValidate:
2522 * @reader: the xmlTextReaderPtr used
2523 * @rng: the path to a RelaxNG schema or NULL
2524 *
2525 * Use RelaxNG to validate the document as it is processed.
2526 * Activation is only possible before the first Read().
2527 * if @rng is NULL, then RelaxNG validation is desactivated.
2528 *
2529 * Returns 0 in case the RelaxNG validation could be (des)activated and
2530 * -1 in case of error.
2531 */
2532int
2533xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
2534 xmlRelaxNGParserCtxtPtr ctxt;
2535
2536 if (reader == NULL)
2537 return(-1);
2538
2539 if (rng == NULL) {
2540 if (reader->rngSchemas != NULL) {
2541 xmlRelaxNGFree(reader->rngSchemas);
2542 reader->rngSchemas = NULL;
2543 }
2544 if (reader->rngValidCtxt != NULL) {
2545 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2546 reader->rngValidCtxt = NULL;
2547 }
2548 return(0);
2549 }
2550 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2551 return(-1);
Daniel Veillard33300b42003-04-17 09:09:19 +00002552 if (reader->rngSchemas != NULL) {
2553 xmlRelaxNGFree(reader->rngSchemas);
2554 reader->rngSchemas = NULL;
2555 }
2556 if (reader->rngValidCtxt != NULL) {
2557 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2558 reader->rngValidCtxt = NULL;
2559 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00002560 ctxt = xmlRelaxNGNewParserCtxt(rng);
2561 if (reader->errorFunc != NULL) {
2562 xmlRelaxNGSetParserErrors(ctxt,
2563 (xmlRelaxNGValidityErrorFunc) reader->errorFunc,
2564 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
2565 reader->errorFuncArg);
2566 }
2567 reader->rngSchemas = xmlRelaxNGParse(ctxt);
2568 xmlRelaxNGFreeParserCtxt(ctxt);
2569 if (reader->rngSchemas == NULL)
2570 return(-1);
2571 reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
2572 if (reader->rngValidCtxt == NULL)
2573 return(-1);
2574 if (reader->errorFunc != NULL) {
2575 xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
2576 (xmlRelaxNGValidityErrorFunc)reader->errorFunc,
2577 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
2578 reader->errorFuncArg);
2579 }
2580 reader->rngValidErrors = 0;
2581 reader->rngFullNode = NULL;
2582 reader->validate = XML_TEXTREADER_VALIDATE_RNG;
2583 return(0);
2584}
2585
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002586/************************************************************************
2587 * *
Daniel Veillard26f70262003-01-16 22:45:08 +00002588 * Error Handling Extensions *
2589 * *
2590 ************************************************************************/
2591
2592/* helper to build a xmlMalloc'ed string from a format and va_list */
2593static char *
2594xmlTextReaderBuildMessage(const char *msg, va_list ap) {
2595 int size;
2596 int chars;
2597 char *larger;
2598 char *str;
2599
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002600 str = (char *) xmlMallocAtomic(150);
Daniel Veillard26f70262003-01-16 22:45:08 +00002601 if (str == NULL) {
2602 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
2603 return NULL;
2604 }
2605
2606 size = 150;
2607
2608 while (1) {
2609 chars = vsnprintf(str, size, msg, ap);
2610 if ((chars > -1) && (chars < size))
2611 break;
2612 if (chars > -1)
2613 size += chars + 1;
2614 else
2615 size += 100;
2616 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
2617 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
2618 xmlFree(str);
2619 return NULL;
2620 }
2621 str = larger;
2622 }
2623
2624 return str;
2625}
2626
Daniel Veillard417be3a2003-01-20 21:26:34 +00002627/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00002628 * xmlTextReaderLocatorLineNumber:
Daniel Veillard417be3a2003-01-20 21:26:34 +00002629 * @locator: the xmlTextReaderLocatorPtr used
2630 *
2631 * Obtain the line number for the given locator.
2632 *
2633 * Returns the line number or -1 in case of error.
2634 */
2635int
2636xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
2637 /* we know that locator is a xmlParserCtxtPtr */
2638 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
2639 int ret = -1;
2640
2641 if (ctx->node != NULL) {
2642 ret = xmlGetLineNo(ctx->node);
2643 }
2644 else {
2645 /* inspired from error.c */
2646 xmlParserInputPtr input;
2647 input = ctx->input;
2648 if ((input->filename == NULL) && (ctx->inputNr > 1))
2649 input = ctx->inputTab[ctx->inputNr - 2];
2650 if (input != NULL) {
2651 ret = input->line;
2652 }
2653 else {
2654 ret = -1;
2655 }
2656 }
2657
2658 return ret;
2659}
2660
2661/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00002662 * xmlTextReaderLocatorBaseURI:
Daniel Veillard417be3a2003-01-20 21:26:34 +00002663 * @locator: the xmlTextReaderLocatorPtr used
2664 *
2665 * Obtain the base URI for the given locator.
2666 *
2667 * Returns the base URI or NULL in case of error.
2668 */
2669xmlChar *
2670xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
2671 /* we know that locator is a xmlParserCtxtPtr */
2672 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
2673 xmlChar *ret = NULL;
2674
2675 if (ctx->node != NULL) {
2676 ret = xmlNodeGetBase(NULL,ctx->node);
2677 }
2678 else {
2679 /* inspired from error.c */
2680 xmlParserInputPtr input;
2681 input = ctx->input;
2682 if ((input->filename == NULL) && (ctx->inputNr > 1))
2683 input = ctx->inputTab[ctx->inputNr - 2];
2684 if (input != NULL) {
Daniel Veillard580ced82003-03-21 21:22:48 +00002685 ret = xmlStrdup(BAD_CAST input->filename);
Daniel Veillard417be3a2003-01-20 21:26:34 +00002686 }
2687 else {
2688 ret = NULL;
2689 }
2690 }
2691
2692 return ret;
2693}
2694
Daniel Veillard26f70262003-01-16 22:45:08 +00002695static void
2696xmlTextReaderGenericError(void *ctxt, int severity, char *str) {
2697 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
2698 xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private;
2699
2700 if (str != NULL) {
2701 reader->errorFunc(reader->errorFuncArg,
2702 str,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002703 severity,
2704 (xmlTextReaderLocatorPtr)ctx);
Daniel Veillard26f70262003-01-16 22:45:08 +00002705 xmlFree(str);
2706 }
2707}
2708
2709static void
2710xmlTextReaderError(void *ctxt, const char *msg, ...) {
2711 va_list ap;
2712
2713 va_start(ap,msg);
2714 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002715 XML_PARSER_SEVERITY_ERROR,
Daniel Veillard26f70262003-01-16 22:45:08 +00002716 xmlTextReaderBuildMessage(msg,ap));
2717 va_end(ap);
2718
2719}
2720
2721static void
2722xmlTextReaderWarning(void *ctxt, const char *msg, ...) {
2723 va_list ap;
2724
2725 va_start(ap,msg);
2726 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002727 XML_PARSER_SEVERITY_WARNING,
Daniel Veillard26f70262003-01-16 22:45:08 +00002728 xmlTextReaderBuildMessage(msg,ap));
2729 va_end(ap);
2730}
2731
2732static void
2733xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
2734 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00002735 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00002736
Daniel Veillard417be3a2003-01-20 21:26:34 +00002737 if ((len > 1) && (msg[len - 2] != ':')) {
2738 /*
2739 * some callbacks only report locator information:
2740 * skip them (mimicking behaviour in error.c)
2741 */
2742 va_start(ap,msg);
2743 xmlTextReaderGenericError(ctxt,
2744 XML_PARSER_SEVERITY_VALIDITY_ERROR,
2745 xmlTextReaderBuildMessage(msg,ap));
2746 va_end(ap);
2747 }
Daniel Veillard26f70262003-01-16 22:45:08 +00002748}
2749
2750static void
2751xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
2752 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00002753 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00002754
Daniel Veillard417be3a2003-01-20 21:26:34 +00002755 if ((len != 0) && (msg[len - 1] != ':')) {
2756 /*
2757 * some callbacks only report locator information:
2758 * skip them (mimicking behaviour in error.c)
2759 */
2760 va_start(ap,msg);
2761 xmlTextReaderGenericError(ctxt,
2762 XML_PARSER_SEVERITY_VALIDITY_WARNING,
2763 xmlTextReaderBuildMessage(msg,ap));
2764 va_end(ap);
2765 }
Daniel Veillard26f70262003-01-16 22:45:08 +00002766}
2767
2768/**
2769 * xmlTextReaderSetErrorHandler:
2770 * @reader: the xmlTextReaderPtr used
2771 * @f: the callback function to call on error and warnings
2772 * @arg: a user argument to pass to the callback function
2773 *
Daniel Veillard417be3a2003-01-20 21:26:34 +00002774 * Register a callback function that will be called on error and warnings.
2775 *
Daniel Veillard26f70262003-01-16 22:45:08 +00002776 * If @f is NULL, the default error and warning handlers are restored.
2777 */
2778void
2779xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
2780 xmlTextReaderErrorFunc f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002781 void *arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00002782 if (f != NULL) {
2783 reader->ctxt->sax->error = xmlTextReaderError;
2784 reader->ctxt->vctxt.error = xmlTextReaderValidityError;
2785 reader->ctxt->sax->warning = xmlTextReaderWarning;
2786 reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
2787 reader->errorFunc = f;
2788 reader->errorFuncArg = arg;
2789 }
2790 else {
2791 /* restore defaults */
2792 reader->ctxt->sax->error = xmlParserError;
2793 reader->ctxt->vctxt.error = xmlParserValidityError;
2794 reader->ctxt->sax->warning = xmlParserWarning;
2795 reader->ctxt->vctxt.warning = xmlParserValidityWarning;
2796 reader->errorFunc = NULL;
2797 reader->errorFuncArg = NULL;
2798 }
2799}
2800
Daniel Veillard417be3a2003-01-20 21:26:34 +00002801/**
Daniel Veillardf6bad792003-04-11 19:38:54 +00002802 * xmlTextReaderIsValid:
2803 * @reader: the xmlTextReaderPtr used
2804 *
2805 * Retrieve the validity status from the parser context
2806 *
2807 * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
2808 */
2809int
2810xmlTextReaderIsValid(xmlTextReaderPtr reader) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00002811 if (reader == NULL) return(-1);
2812#ifdef LIBXML_SCHEMAS_ENABLED
2813 if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
2814 return(reader->rngValidErrors == 0);
2815#endif
2816 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
2817 (reader->ctxt != NULL))
2818 return(reader->ctxt->valid);
2819 return(0);
Daniel Veillardf6bad792003-04-11 19:38:54 +00002820}
2821
2822/**
Daniel Veillard417be3a2003-01-20 21:26:34 +00002823 * xmlTextReaderGetErrorHandler:
2824 * @reader: the xmlTextReaderPtr used
2825 * @f: the callback function or NULL is no callback has been registered
2826 * @arg: a user argument
2827 *
2828 * Retrieve the error callback function and user argument.
2829 */
Daniel Veillard26f70262003-01-16 22:45:08 +00002830void
2831xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
2832 xmlTextReaderErrorFunc *f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002833 void **arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00002834 *f = reader->errorFunc;
2835 *arg = reader->errorFuncArg;
2836}
2837
2838/************************************************************************
2839 * *
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002840 * Utilities *
2841 * *
2842 ************************************************************************/
2843/**
2844 * xmlBase64Decode:
2845 * @in: the input buffer
2846 * @inlen: the size of the input (in), the size read from it (out)
2847 * @to: the output buffer
2848 * @tolen: the size of the output (in), the size written to (out)
2849 *
2850 * Base64 decoder, reads from @in and save in @to
Daniel Veillardd4310742003-02-18 21:12:46 +00002851 * TODO: tell jody when this is actually exported
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002852 *
2853 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
2854 * 2 if there wasn't enough space on the output or -1 in case of error.
2855 */
2856static int
2857xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
2858 unsigned char *to, unsigned long *tolen) {
2859 unsigned long incur; /* current index in in[] */
2860 unsigned long inblk; /* last block index in in[] */
2861 unsigned long outcur; /* current index in out[] */
2862 unsigned long inmax; /* size of in[] */
2863 unsigned long outmax; /* size of out[] */
2864 unsigned char cur; /* the current value read from in[] */
2865 unsigned char intmp[3], outtmp[4]; /* temporary buffers for the convert */
2866 int nbintmp; /* number of byte in intmp[] */
2867 int is_ignore; /* cur should be ignored */
2868 int is_end = 0; /* the end of the base64 was found */
2869 int retval = 1;
2870 int i;
2871
2872 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
2873 return(-1);
2874
2875 incur = 0;
2876 inblk = 0;
2877 outcur = 0;
2878 inmax = *inlen;
2879 outmax = *tolen;
2880 nbintmp = 0;
2881
2882 while (1) {
2883 if (incur >= inmax)
2884 break;
2885 cur = in[incur++];
2886 is_ignore = 0;
2887 if ((cur >= 'A') && (cur <= 'Z'))
2888 cur = cur - 'A';
2889 else if ((cur >= 'a') && (cur <= 'z'))
2890 cur = cur - 'a' + 26;
2891 else if ((cur >= '0') && (cur <= '9'))
2892 cur = cur - '0' + 52;
2893 else if (cur == '+')
2894 cur = 62;
2895 else if (cur == '/')
2896 cur = 63;
2897 else if (cur == '.')
2898 cur = 0;
2899 else if (cur == '=') /*no op , end of the base64 stream */
2900 is_end = 1;
2901 else {
2902 is_ignore = 1;
2903 if (nbintmp == 0)
2904 inblk = incur;
2905 }
2906
2907 if (!is_ignore) {
2908 int nbouttmp = 3;
2909 int is_break = 0;
2910
2911 if (is_end) {
2912 if (nbintmp == 0)
2913 break;
2914 if ((nbintmp == 1) || (nbintmp == 2))
2915 nbouttmp = 1;
2916 else
2917 nbouttmp = 2;
2918 nbintmp = 3;
2919 is_break = 1;
2920 }
2921 intmp[nbintmp++] = cur;
2922 /*
2923 * if intmp is full, push the 4byte sequence as a 3 byte
2924 * sequence out
2925 */
2926 if (nbintmp == 4) {
2927 nbintmp = 0;
2928 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
2929 outtmp[1] =
2930 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
2931 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
2932 if (outcur + 3 >= outmax) {
2933 retval = 2;
2934 break;
2935 }
2936
2937 for (i = 0; i < nbouttmp; i++)
2938 to[outcur++] = outtmp[i];
2939 inblk = incur;
2940 }
2941
2942 if (is_break) {
2943 retval = 0;
2944 break;
2945 }
2946 }
2947 }
2948
2949 *tolen = outcur;
2950 *inlen = inblk;
2951 return (retval);
2952}
2953
2954/*
2955 * Test routine for the xmlBase64Decode function
2956 */
2957#if 0
2958int main(int argc, char **argv) {
2959 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
2960 char output[100];
2961 char output2[100];
2962 char output3[100];
2963 unsigned long inlen = strlen(input);
2964 unsigned long outlen = 100;
2965 int ret;
2966 unsigned long cons, tmp, tmp2, prod;
2967
2968 /*
2969 * Direct
2970 */
2971 ret = xmlBase64Decode(input, &inlen, output, &outlen);
2972
2973 output[outlen] = 0;
2974 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
2975
2976 /*
2977 * output chunking
2978 */
2979 cons = 0;
2980 prod = 0;
2981 while (cons < inlen) {
2982 tmp = 5;
2983 tmp2 = inlen - cons;
2984
2985 printf("%ld %ld\n", cons, prod);
2986 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
2987 cons += tmp2;
2988 prod += tmp;
2989 printf("%ld %ld\n", cons, prod);
2990 }
2991 output2[outlen] = 0;
2992 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
2993
2994 /*
2995 * input chunking
2996 */
2997 cons = 0;
2998 prod = 0;
2999 while (cons < inlen) {
3000 tmp = 100 - prod;
3001 tmp2 = inlen - cons;
3002 if (tmp2 > 5)
3003 tmp2 = 5;
3004
3005 printf("%ld %ld\n", cons, prod);
3006 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
3007 cons += tmp2;
3008 prod += tmp;
3009 printf("%ld %ld\n", cons, prod);
3010 }
3011 output3[outlen] = 0;
3012 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
3013 return(0);
3014
3015}
3016#endif