blob: 4821b2a93c604faccaaaba29e9a45676f24739b7 [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:
15 * - provide an API to expand part of the tree
16 * - provide an API to preserve part of the tree
17 * - Streaming XInclude support
Daniel Veillard067bae52003-01-05 01:27:54 +000018 * - validation against a provided DTD
19 * - XML Schemas validation
Daniel Veillard7704fb12003-01-03 16:19:51 +000020 * - setting(s) for NoBlanks
21 * - performances and tuning ...
22 */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000023#define IN_LIBXML
24#include "libxml.h"
25
26#include <string.h> /* for memset() only ! */
Daniel Veillard26f70262003-01-16 22:45:08 +000027#include <stdarg.h>
Daniel Veillarde1ca5032002-12-09 14:13:43 +000028
29#ifdef HAVE_CTYPE_H
30#include <ctype.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35
36#include <libxml/xmlmemory.h>
37#include <libxml/xmlIO.h>
38#include <libxml/xmlreader.h>
39
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
59/************************************************************************
60 * *
61 * The parser: maps the Text Reader API on top of the existing *
62 * parsing routines building a tree *
63 * *
64 ************************************************************************/
65
66#define XML_TEXTREADER_INPUT 1
67#define XML_TEXTREADER_CTXT 2
68
69typedef enum {
Daniel Veillard67df8092002-12-16 22:04:11 +000070 XML_TEXTREADER_MODE_INITIAL = 0,
71 XML_TEXTREADER_MODE_INTERACTIVE = 1,
72 XML_TEXTREADER_MODE_ERROR = 2,
73 XML_TEXTREADER_MODE_EOF =3,
74 XML_TEXTREADER_MODE_CLOSED = 4,
75 XML_TEXTREADER_MODE_READING = 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000076} xmlTextReaderMode;
77
78typedef enum {
79 XML_TEXTREADER_NONE = -1,
80 XML_TEXTREADER_START= 0,
81 XML_TEXTREADER_ELEMENT= 1,
82 XML_TEXTREADER_END= 2,
83 XML_TEXTREADER_EMPTY= 3,
Daniel Veillardea7751d2002-12-20 00:16:24 +000084 XML_TEXTREADER_BACKTRACK= 4,
85 XML_TEXTREADER_DONE= 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000086} xmlTextReaderState;
87
88struct _xmlTextReader {
89 int mode; /* the parsing mode */
90 int allocs; /* what structure were deallocated */
91 xmlTextReaderState state;
92 xmlParserCtxtPtr ctxt; /* the parser context */
93 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
94 xmlParserInputBufferPtr input; /* the input */
95 startElementSAXFunc startElement;/* initial SAX callbacks */
96 endElementSAXFunc endElement; /* idem */
Daniel Veillardea7751d2002-12-20 00:16:24 +000097 charactersSAXFunc characters;
98 cdataBlockSAXFunc cdataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +000099 unsigned int base; /* base of the segment in the input */
100 unsigned int cur; /* current position in the input */
101 xmlNodePtr node; /* current node */
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000102 xmlNodePtr curnode;/* current attribute node */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000103 int depth; /* depth of the current node */
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000104 xmlNodePtr faketext;/* fake xmlNs chld */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000105
106 /* entity stack when traversing entities content */
107 xmlNodePtr ent; /* Current Entity Ref Node */
108 int entNr; /* Depth of the entities stack */
109 int entMax; /* Max depth of the entities stack */
110 xmlNodePtr *entTab; /* array of entities */
Daniel Veillard26f70262003-01-16 22:45:08 +0000111
112 /* error handling */
113 xmlTextReaderErrorFunc errorFunc; /* callback function */
114 void *errorFuncArg; /* callback function user argument */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000115};
116
Daniel Veillard067bae52003-01-05 01:27:54 +0000117static const char *xmlTextReaderIsEmpty = "This element is empty";
118
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000119#ifdef DEBUG_READER
120static void
121xmlTextReaderDebug(xmlTextReaderPtr reader) {
122 if ((reader == NULL) || (reader->ctxt == NULL)) {
123 fprintf(stderr, "xmlTextReader NULL\n");
124 return;
125 }
126 fprintf(stderr, "xmlTextReader: state %d depth %d ",
127 reader->state, reader->depth);
128 if (reader->node == NULL) {
129 fprintf(stderr, "node = NULL\n");
130 } else {
131 fprintf(stderr, "node %s\n", reader->node->name);
132 }
133 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
134 reader->base, reader->cur, reader->ctxt->nodeNr);
135 if (reader->input->buffer == NULL) {
136 fprintf(stderr, "buffer is NULL\n");
137 } else {
138#ifdef LIBXML_DEBUG_ENABLED
139 xmlDebugDumpString(stderr,
140 &reader->input->buffer->content[reader->cur]);
141#endif
142 fprintf(stderr, "\n");
143 }
144}
145#endif
146
147/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000148 * xmlTextReaderEntPush:
149 * @reader: the xmlTextReaderPtr used
150 * @value: the entity reference node
151 *
152 * Pushes a new entity reference node on top of the entities stack
153 *
154 * Returns 0 in case of error, the index in the stack otherwise
155 */
156static int
157xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
158{
159 if (reader->entMax <= 0) {
160 reader->entMax = 10;
161 reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
162 sizeof(reader->entTab[0]));
163 if (reader->entTab == NULL) {
164 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
165 return (0);
166 }
167 }
168 if (reader->entNr >= reader->entMax) {
169 reader->entMax *= 2;
170 reader->entTab =
171 (xmlNodePtr *) xmlRealloc(reader->entTab,
172 reader->entMax *
173 sizeof(reader->entTab[0]));
174 if (reader->entTab == NULL) {
175 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
176 return (0);
177 }
178 }
179 reader->entTab[reader->entNr] = value;
180 reader->ent = value;
181 return (reader->entNr++);
182}
183
184/**
185 * xmlTextReaderEntPop:
186 * @reader: the xmlTextReaderPtr used
187 *
188 * Pops the top element entity from the entities stack
189 *
190 * Returns the entity just removed
191 */
192static xmlNodePtr
193xmlTextReaderEntPop(xmlTextReaderPtr reader)
194{
195 xmlNodePtr ret;
196
197 if (reader->entNr <= 0)
198 return (0);
199 reader->entNr--;
200 if (reader->entNr > 0)
201 reader->ent = reader->entTab[reader->entNr - 1];
202 else
203 reader->ent = NULL;
204 ret = reader->entTab[reader->entNr];
205 reader->entTab[reader->entNr] = 0;
206 return (ret);
207}
208
209/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000210 * xmlTextReaderStartElement:
211 * @ctx: the user data (XML parser context)
212 * @fullname: The element name, including namespace prefix
213 * @atts: An array of name/value attributes pairs, NULL terminated
214 *
215 * called when an opening tag has been processed.
216 */
217static void
218xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
219 const xmlChar **atts) {
220 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000221 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000222 xmlTextReaderPtr reader = ctxt->_private;
223
224#ifdef DEBUG_CALLBACKS
225 printf("xmlTextReaderStartElement(%s)\n", fullname);
226#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000227 if ((reader != NULL) && (reader->startElement != NULL)) {
Daniel Veillardd5896142002-12-31 14:45:26 +0000228 /*
229 * when processing an entity, the context may have been changed
230 */
231 origctxt = reader->ctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000232 reader->startElement(ctx, fullname, atts);
Daniel Veillard067bae52003-01-05 01:27:54 +0000233 if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
234 (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
235 (ctxt->input->cur[1] == '>'))
236 ctxt->node->_private = (void *) xmlTextReaderIsEmpty;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000237 }
Daniel Veillard9e395c22003-01-01 14:50:44 +0000238 if (reader != NULL)
239 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000240}
241
242/**
243 * xmlTextReaderEndElement:
244 * @ctx: the user data (XML parser context)
245 * @fullname: The element name, including namespace prefix
246 *
247 * called when an ending tag has been processed.
248 */
249static void
250xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
251 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000252 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000253 xmlTextReaderPtr reader = ctxt->_private;
254
255#ifdef DEBUG_CALLBACKS
256 printf("xmlTextReaderEndElement(%s)\n", fullname);
257#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000258 if ((reader != NULL) && (reader->endElement != NULL)) {
Daniel Veillardd5896142002-12-31 14:45:26 +0000259 /*
260 * when processing an entity, the context may have been changed
261 */
262 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000263
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000264 reader->endElement(ctx, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000265 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000266}
267
268/**
Daniel Veillardea7751d2002-12-20 00:16:24 +0000269 * xmlTextReaderCharacters:
270 * @ctx: the user data (XML parser context)
271 * @ch: a xmlChar string
272 * @len: the number of xmlChar
273 *
274 * receiving some chars from the parser.
275 */
276static void
277xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
278{
279 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000280 xmlParserCtxtPtr origctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 xmlTextReaderPtr reader = ctxt->_private;
282
283#ifdef DEBUG_CALLBACKS
284 printf("xmlTextReaderCharacters()\n");
285#endif
286 if ((reader != NULL) && (reader->characters != NULL)) {
287 reader->characters(ctx, ch, len);
Daniel Veillardd5896142002-12-31 14:45:26 +0000288 /*
289 * when processing an entity, the context may have been changed
290 */
291 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000292 }
293}
294
295/**
296 * xmlTextReaderCDataBlock:
297 * @ctx: the user data (XML parser context)
298 * @value: The pcdata content
299 * @len: the block length
300 *
301 * called when a pcdata block has been parsed
302 */
303static void
304xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
305{
306 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
307 xmlTextReaderPtr reader = ctxt->_private;
308
309#ifdef DEBUG_CALLBACKS
310 printf("xmlTextReaderCDataBlock()\n");
311#endif
312 if ((reader != NULL) && (reader->cdataBlock != NULL)) {
313 reader->cdataBlock(ctx, ch, len);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000314 }
315}
316
317/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000318 * xmlTextReaderPushData:
319 * @reader: the xmlTextReaderPtr used
320 *
321 * Push data down the progressive parser until a significant callback
322 * got raised.
323 *
324 * Returns -1 in case of failure, 0 otherwise
325 */
326static int
327xmlTextReaderPushData(xmlTextReaderPtr reader) {
328 unsigned int cur = reader->cur;
329 xmlBufferPtr inbuf;
330 int val;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000331 int oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000332
333 if ((reader->input == NULL) || (reader->input->buffer == NULL))
334 return(-1);
335
Daniel Veillardea7751d2002-12-20 00:16:24 +0000336 oldstate = reader->state;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000337 reader->state = XML_TEXTREADER_NONE;
338 inbuf = reader->input->buffer;
339 while (reader->state == XML_TEXTREADER_NONE) {
340 if (cur >= inbuf->use) {
341 /*
342 * Refill the buffer unless we are at the end of the stream
343 */
344 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
345 val = xmlParserInputBufferRead(reader->input, 4096);
346 if (val <= 0) {
347 reader->mode = XML_TEXTREADER_MODE_EOF;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000348 reader->state = oldstate;
Daniel Veillardaaa105b2002-12-30 11:42:17 +0000349 if ((oldstate != XML_TEXTREADER_START) ||
350 (reader->ctxt->myDoc != NULL))
351 return(val);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000352 }
353 } else
354 break;
355 }
Daniel Veillard067bae52003-01-05 01:27:54 +0000356 /*
357 * parse by block of 512 bytes
358 */
359 if ((cur >= reader->cur + 512) || (cur >= inbuf->use)) {
360 if (cur < inbuf->use)
361 cur = cur + 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000362 val = xmlParseChunk(reader->ctxt,
363 (const char *) &inbuf->content[reader->cur],
364 cur - reader->cur, 0);
365 if (val != 0)
366 return(-1);
367 reader->cur = cur;
368 break;
369 } else {
370 cur = cur + 1;
371
372 /*
373 * One may have to force a flush at some point when parsing really
374 * large CDATA sections
375 */
376 if ((cur - reader->cur > 4096) && (reader->base == 0) &&
Daniel Veillard67df8092002-12-16 22:04:11 +0000377 (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000378 cur = cur + 1;
379 val = xmlParseChunk(reader->ctxt,
380 (const char *) &inbuf->content[reader->cur],
381 cur - reader->cur, 0);
382 if (val != 0)
383 return(-1);
384 reader->cur = cur;
385 }
386 }
387 }
388 /*
389 * Discard the consumed input when needed and possible
390 */
Daniel Veillard67df8092002-12-16 22:04:11 +0000391 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000392 if ((reader->cur >= 4096) && (reader->base == 0)) {
393 val = xmlBufferShrink(inbuf, cur);
394 if (val >= 0) {
395 reader->cur -= val;
396 }
397 }
398 }
399
400 /*
401 * At the end of the stream signal that the work is done to the Push
402 * parser.
403 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000404 if (reader->mode == XML_TEXTREADER_MODE_EOF) {
405 if (reader->mode != XML_TEXTREADER_DONE) {
406 val = xmlParseChunk(reader->ctxt,
Daniel Veillard067bae52003-01-05 01:27:54 +0000407 (const char *) &inbuf->content[reader->cur],
408 cur - reader->cur, 1);
409 reader->cur = cur;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000410 reader->mode = XML_TEXTREADER_DONE;
411 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000412 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000413 reader->state = oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000414 return(0);
415}
416
417/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000418 * xmlTextReaderValidatePush:
419 * @reader: the xmlTextReaderPtr used
420 *
421 * Push the current node for validation
422 */
423static void
424xmlTextReaderValidatePush(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000425#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000426 xmlNodePtr node = reader->node;
427
428 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
429 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
430 reader->ctxt->myDoc, node, node->name);
431 } else {
432 xmlChar *qname;
433
434 qname = xmlStrdup(node->ns->prefix);
435 qname = xmlStrcat(qname, BAD_CAST ":");
436 qname = xmlStrcat(qname, node->name);
437 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
438 reader->ctxt->myDoc, node, qname);
439 if (qname != NULL)
440 xmlFree(qname);
441 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000442#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000443}
444/**
445 * xmlTextReaderValidatePop:
446 * @reader: the xmlTextReaderPtr used
447 *
448 * Pop the current node from validation
449 */
450static void
451xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000452#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000453 xmlNodePtr node = reader->node;
454
455 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
456 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
457 reader->ctxt->myDoc, node, node->name);
458 } else {
459 xmlChar *qname;
460
461 qname = xmlStrdup(node->ns->prefix);
462 qname = xmlStrcat(qname, BAD_CAST ":");
463 qname = xmlStrcat(qname, node->name);
464 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
465 reader->ctxt->myDoc, node, qname);
466 if (qname != NULL)
467 xmlFree(qname);
468 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000469#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000470}
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000471/**
472 * xmlTextReaderValidateEntity:
473 * @reader: the xmlTextReaderPtr used
474 *
475 * Handle the validation when an entity reference is encountered and
476 * entity substitution is not activated. As a result the parser interface
477 * must walk through the entity and do the validation calls
478 */
479static void
480xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000481#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000482 xmlNodePtr oldnode = reader->node;
483 xmlNodePtr node = reader->node;
484 xmlParserCtxtPtr ctxt = reader->ctxt;
485
486 do {
487 if (node->type == XML_ENTITY_REF_NODE) {
488 /*
489 * Case where the underlying tree is not availble, lookup the entity
490 * and walk it.
491 */
492 if ((node->children == NULL) && (ctxt->sax != NULL) &&
493 (ctxt->sax->getEntity != NULL)) {
494 node->children = (xmlNodePtr)
495 ctxt->sax->getEntity(ctxt, node->name);
496 }
497
498 if ((node->children != NULL) &&
499 (node->children->type == XML_ENTITY_DECL) &&
500 (node->children->children != NULL)) {
501 xmlTextReaderEntPush(reader, node);
502 node = node->children->children;
503 continue;
504 } else {
505 /*
506 * The error has probably be raised already.
507 */
508 if (node == oldnode)
509 break;
510 node = node->next;
511 }
512 } else if (node->type == XML_ELEMENT_NODE) {
513 reader->node = node;
514 xmlTextReaderValidatePush(reader);
515 } else if ((node->type == XML_TEXT_NODE) ||
516 (node->type == XML_CDATA_SECTION_NODE)) {
517 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt,
518 node->content, xmlStrlen(node->content));
519 }
520
521 /*
522 * go to next node
523 */
524 if (node->children != NULL) {
525 node = node->children;
526 continue;
Daniel Veillardef8dd7b2003-03-23 12:02:56 +0000527 } else if (node->type == XML_ELEMENT_NODE) {
528 xmlTextReaderValidatePop(reader);
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000529 }
530 if (node->next != NULL) {
531 node = node->next;
532 continue;
533 }
534 do {
535 node = node->parent;
536 if (node->type == XML_ELEMENT_NODE) {
537 reader->node = node;
538 xmlTextReaderValidatePop(reader);
539 }
540 if ((node->type == XML_ENTITY_DECL) &&
541 (reader->ent != NULL) && (reader->ent->children == node)) {
542 node = xmlTextReaderEntPop(reader);
543 }
544 if (node == oldnode)
545 break;
546 if (node->next != NULL) {
547 node = node->next;
548 break;
549 }
550 } while ((node != NULL) && (node != oldnode));
551 } while ((node != NULL) && (node != oldnode));
552 reader->node = oldnode;
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000553#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000554}
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000555
556
557/**
Daniel Veillardc6cae7b2003-04-11 09:02:11 +0000558 * xmlTextReaderGetSuccessor:
559 * @cur: the current node
560 *
561 * Get the successor of a node if available.
562 *
563 * Returns the successor node or NULL
564 */
565static xmlNodePtr
566xmlTextReaderGetSuccessor(xmlNodePtr cur) {
567 if (cur == NULL) return(NULL) ; /* ERROR */
568 if (cur->next != NULL) return(cur->next) ;
569 do {
570 cur = cur->parent;
571 if (cur == NULL) return(NULL);
572 if (cur->next != NULL) return(cur->next);
573 } while (cur != NULL);
574 return(cur);
575}
576
577/**
578 * xmlTextReaderDoExpand:
579 * @reader: the xmlTextReaderPtr used
580 *
581 * Makes sure that the current node is fully read as well as all its
582 * descendant. It means the full DOM subtree must be available at the
583 * end of the call.
584 *
585 * Returns 1 if the node was expanded successfully, 0 if there is no more
586 * nodes to read, or -1 in case of error
587 */
588static int
589xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
590 int val;
591
592 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
593 return(-1);
594
595 do {
596 if (xmlTextReaderGetSuccessor(reader->node) != NULL)
597 return(1);
598 if (reader->mode == XML_TEXTREADER_MODE_EOF)
599 return(1);
600 val = xmlTextReaderPushData(reader);
601 if (val < 0)
602 return(-1);
603 } while(reader->mode != XML_TEXTREADER_MODE_EOF);
604 return(1);
605}
606
607/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000608 * xmlTextReaderRead:
609 * @reader: the xmlTextReaderPtr used
610 *
611 * Moves the position of the current instance to the next node in
612 * the stream, exposing its properties.
613 *
614 * Returns 1 if the node was read successfully, 0 if there is no more
615 * nodes to read, or -1 in case of error
616 */
617int
618xmlTextReaderRead(xmlTextReaderPtr reader) {
Daniel Veillard067bae52003-01-05 01:27:54 +0000619 int val, olddepth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000620 xmlTextReaderState oldstate = 0;
621 xmlNodePtr oldnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000622
623 if ((reader == NULL) || (reader->ctxt == NULL))
624 return(-1);
625 if (reader->ctxt->wellFormed != 1)
626 return(-1);
627
628#ifdef DEBUG_READER
629 fprintf(stderr, "\nREAD ");
630 DUMP_READER
631#endif
Daniel Veillard29b3e282002-12-29 11:14:41 +0000632 reader->curnode = NULL;
Daniel Veillard67df8092002-12-16 22:04:11 +0000633 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
634 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000635 /*
636 * Initial state
637 */
638 do {
639 val = xmlTextReaderPushData(reader);
640 if (val < 0)
641 return(-1);
642 } while ((reader->ctxt->node == NULL) &&
Daniel Veillard067bae52003-01-05 01:27:54 +0000643 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
644 (reader->mode != XML_TEXTREADER_DONE)));
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000645 if (reader->ctxt->node == NULL) {
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000646 if (reader->ctxt->myDoc != NULL) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000647 reader->node = reader->ctxt->myDoc->children;
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000648 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000649 if (reader->node == NULL)
650 return(-1);
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000651 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000652 } else {
Daniel Veillard48ef4c92003-03-22 12:38:15 +0000653 if (reader->ctxt->myDoc != NULL) {
654 reader->node = reader->ctxt->myDoc->children;
655 }
656 if (reader->node == NULL)
657 reader->node = reader->ctxt->nodeTab[0];
Daniel Veillarde59494f2003-01-04 16:35:29 +0000658 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000659 }
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000660 reader->depth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000661 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000662 }
663 oldstate = reader->state;
664 olddepth = reader->ctxt->nodeNr;
665 oldnode = reader->node;
Daniel Veillarddf512f42002-12-23 15:56:21 +0000666
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000667get_next_node:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000668 /*
669 * If we are not backtracking on ancestors or examined nodes,
670 * that the parser didn't finished or that we arent at the end
671 * of stream, continue processing.
672 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000673 while (((oldstate == XML_TEXTREADER_BACKTRACK) ||
674 (reader->node->children == NULL) ||
675 (reader->node->type == XML_ENTITY_REF_NODE) ||
Daniel Veillard4dbe77a2003-01-14 00:17:42 +0000676 (reader->node->type == XML_DTD_NODE) ||
677 (reader->node->type == XML_DOCUMENT_NODE) ||
678 (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
Daniel Veillardea7751d2002-12-20 00:16:24 +0000679 (reader->node->next == NULL) &&
Daniel Veillard4dbe77a2003-01-14 00:17:42 +0000680 ((reader->ctxt->node == NULL) ||
681 (reader->ctxt->node == reader->node) ||
682 (reader->ctxt->node == reader->node->parent)) &&
Daniel Veillardea7751d2002-12-20 00:16:24 +0000683 (reader->ctxt->nodeNr == olddepth) &&
684 (reader->ctxt->instate != XML_PARSER_EOF)) {
685 val = xmlTextReaderPushData(reader);
686 if (val < 0)
687 return(-1);
688 if (reader->node == NULL)
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000689 goto node_end;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000690 }
Daniel Veillard120e8eb2003-03-22 01:00:34 +0000691 /*
692 * If we are in the middle of a piece of CDATA make sure it's finished
693 * Maybe calling a function checking that a non-character() callback was
694 * received would be cleaner for the loop exit.
695 */
696 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
697 (reader->ctxt->instate == XML_PARSER_CDATA_SECTION)) {
698 while ((reader->ctxt->instate == XML_PARSER_CDATA_SECTION) &&
699 (((reader->node->content == NULL) &&
700 (reader->node->next != NULL) &&
701 (reader->node->next->type == XML_CDATA_SECTION_NODE) &&
702 (reader->node->next->next == NULL) &&
703 (reader->node->parent->next == NULL)) ||
704 ((reader->node->children != NULL) &&
705 (reader->node->children->type == XML_CDATA_SECTION_NODE) &&
706 (reader->node->children->next == NULL) &&
707 (reader->node->children->next == NULL)))) {
708 val = xmlTextReaderPushData(reader);
709 if (val < 0)
710 return(-1);
711 }
712 }
713 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
714 (reader->ctxt->instate == XML_PARSER_CONTENT)) {
715 while ((reader->ctxt->instate == XML_PARSER_CONTENT) &&
716 (((reader->node->content == NULL) &&
717 (reader->node->next != NULL) &&
718 (reader->node->next->type == XML_TEXT_NODE) &&
719 (reader->node->next->next == NULL) &&
720 (reader->node->parent->next == NULL)) ||
721 ((reader->node->children != NULL) &&
722 (reader->node->children->type == XML_TEXT_NODE) &&
723 (reader->node->children->next == NULL) &&
724 (reader->node->children->next == NULL)))) {
725 val = xmlTextReaderPushData(reader);
726 if (val < 0)
727 return(-1);
728 }
729 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000730 if (oldstate != XML_TEXTREADER_BACKTRACK) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000731 if ((reader->node->children != NULL) &&
732 (reader->node->type != XML_ENTITY_REF_NODE) &&
733 (reader->node->type != XML_DTD_NODE)) {
734 reader->node = reader->node->children;
735 reader->depth++;
Daniel Veillarddf512f42002-12-23 15:56:21 +0000736 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000737 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000738 }
739 }
740 if (reader->node->next != NULL) {
741 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillarddf512f42002-12-23 15:56:21 +0000742 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +0000743 (reader->node->children == NULL) &&
744 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000745 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000746 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000747 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000748 if ((reader->ctxt->validate) &&
749 (reader->node->type == XML_ELEMENT_NODE))
750 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000751 reader->node = reader->node->next;
752 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000753
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000754 /*
755 * Cleanup of the old node
756 */
Daniel Veillard4dbe77a2003-01-14 00:17:42 +0000757 if ((reader->node->prev != NULL) &&
758 (reader->node->prev->type != XML_DTD_NODE)) {
759 xmlNodePtr tmp = reader->node->prev;
760 xmlUnlinkNode(tmp);
761 xmlFreeNode(tmp);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000762 }
763
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000764 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000765 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000766 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillard571b8892002-12-30 12:37:59 +0000767 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +0000768 (reader->node->children == NULL) &&
769 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000770 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000771 goto node_found;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000772 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000773 if ((reader->ctxt->validate) && (reader->node->type == XML_ELEMENT_NODE))
774 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000775 reader->node = reader->node->parent;
776 if ((reader->node == NULL) ||
777 (reader->node->type == XML_DOCUMENT_NODE) ||
778#ifdef LIBXML_DOCB_ENABLED
779 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
780#endif
781 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000782 if (reader->mode != XML_TEXTREADER_DONE) {
783 val = xmlParseChunk(reader->ctxt, "", 0, 1);
784 reader->mode = XML_TEXTREADER_DONE;
785 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000786 reader->node = NULL;
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000787 reader->depth = -1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000788
789 /*
790 * Cleanup of the old node
791 */
792 if (oldnode->type != XML_DTD_NODE) {
793 xmlUnlinkNode(oldnode);
794 xmlFreeNode(oldnode);
795 }
796
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000797 goto node_end;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000798 }
799 reader->depth--;
800 reader->state = XML_TEXTREADER_BACKTRACK;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000801
802node_found:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000803 DUMP_READER
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000804
805 /*
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000806 * Handle entities enter and exit when in entity replacement mode
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000807 */
808 if ((reader->node != NULL) &&
809 (reader->node->type == XML_ENTITY_REF_NODE) &&
810 (reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
811 /*
812 * Case where the underlying tree is not availble, lookup the entity
813 * and walk it.
814 */
815 if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
816 (reader->ctxt->sax->getEntity != NULL)) {
817 reader->node->children = (xmlNodePtr)
818 reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
819 }
820
821 if ((reader->node->children != NULL) &&
822 (reader->node->children->type == XML_ENTITY_DECL) &&
823 (reader->node->children->children != NULL)) {
824 xmlTextReaderEntPush(reader, reader->node);
825 reader->node = reader->node->children->children;
826 }
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000827 } else if ((reader->node != NULL) &&
828 (reader->node->type == XML_ENTITY_REF_NODE) &&
829 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
830 xmlTextReaderValidateEntity(reader);
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000831 }
832 if ((reader->node != NULL) &&
833 (reader->node->type == XML_ENTITY_DECL) &&
834 (reader->ent != NULL) && (reader->ent->children == reader->node)) {
835 reader->node = xmlTextReaderEntPop(reader);
836 reader->depth++;
837 goto get_next_node;
838 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000839#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000840 if ((reader->ctxt->validate) && (reader->node != NULL)) {
841 xmlNodePtr node = reader->node;
842 xmlParserCtxtPtr ctxt = reader->ctxt;
843
844 if ((node->type == XML_ELEMENT_NODE) &&
845 ((reader->state != XML_TEXTREADER_END) &&
846 (reader->state != XML_TEXTREADER_BACKTRACK))) {
847 xmlTextReaderValidatePush(reader);
848 } else if ((node->type == XML_TEXT_NODE) ||
849 (node->type == XML_CDATA_SECTION_NODE)) {
850 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt,
851 node->content, xmlStrlen(node->content));
852 }
853 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000854#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000855 return(1);
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000856node_end:
Daniel Veillardc6cae7b2003-04-11 09:02:11 +0000857 reader->mode = XML_TEXTREADER_DONE;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000858 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000859}
860
Daniel Veillard67df8092002-12-16 22:04:11 +0000861/**
862 * xmlTextReaderReadState:
863 * @reader: the xmlTextReaderPtr used
864 *
865 * Gets the read state of the reader.
866 *
867 * Returns the state value, or -1 in case of error
868 */
869int
870xmlTextReaderReadState(xmlTextReaderPtr reader) {
871 if (reader == NULL)
872 return(-1);
873 return(reader->mode);
874}
875
876/**
Daniel Veillardc6cae7b2003-04-11 09:02:11 +0000877 * xmlTextReaderExpand:
878 * @reader: the xmlTextReaderPtr used
879 *
880 * Reads the contents of the current node and the full subtree. It then makes
881 * the subtree availsble until the next xmlTextReaderRead() call
882 *
883 * Returns a node pointer valid until the next xmlTextReaderRead() call
884 * or NULL in case of error.
885 */
886xmlNodePtr
887xmlTextReaderExpand(xmlTextReaderPtr reader) {
888 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
889 return(NULL);
890 if (xmlTextReaderDoExpand(reader) < 0)
891 return(NULL);
892 return(reader->node);
893}
894
895/**
896 * xmlTextReaderNext:
897 * @reader: the xmlTextReaderPtr used
898 *
899 * Skip to the node following the current one in document order while
900 * avoiding the subtree if any.
901 *
902 * Returns 1 if the node was read successfully, 0 if there is no more
903 * nodes to read, or -1 in case of error
904 */
905int
906xmlTextReaderNext(xmlTextReaderPtr reader) {
907 int ret;
908 xmlNodePtr cur;
909
910 if (reader == NULL)
911 return(-1);
912 cur = reader->node;
913 if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
914 return(xmlTextReaderRead(reader));
915 if (reader->state == XML_TEXTREADER_END)
916 return(xmlTextReaderRead(reader));
917 if (cur->_private == (void *)xmlTextReaderIsEmpty)
918 return(xmlTextReaderRead(reader));
919 do {
920 ret = xmlTextReaderRead(reader);
921 if (ret != 1)
922 return(ret);
923 } while (reader->node != cur);
924 return(xmlTextReaderRead(reader));
925}
926
927/**
Daniel Veillard67df8092002-12-16 22:04:11 +0000928 * xmlTextReaderReadInnerXml:
929 * @reader: the xmlTextReaderPtr used
930 *
931 * Reads the contents of the current node, including child nodes and markup.
932 *
933 * Returns a string containing the XML content, or NULL if the current node
934 * is neither an element nor attribute, or has no child nodes. The
935 * string must be deallocated by the caller.
936 */
937xmlChar *
938xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) {
939 TODO
940 return(NULL);
941}
942
943/**
944 * xmlTextReaderReadOuterXml:
945 * @reader: the xmlTextReaderPtr used
946 *
947 * Reads the contents of the current node, including child nodes and markup.
948 *
949 * Returns a string containing the XML content, or NULL if the current node
950 * is neither an element nor attribute, or has no child nodes. The
951 * string must be deallocated by the caller.
952 */
953xmlChar *
954xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) {
955 TODO
956 return(NULL);
957}
958
959/**
960 * xmlTextReaderReadString:
961 * @reader: the xmlTextReaderPtr used
962 *
963 * Reads the contents of an element or a text node as a string.
964 *
965 * Returns a string containing the contents of the Element or Text node,
966 * or NULL if the reader is positioned on any other type of node.
967 * The string must be deallocated by the caller.
968 */
969xmlChar *
970xmlTextReaderReadString(xmlTextReaderPtr reader) {
971 TODO
972 return(NULL);
973}
974
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000975/**
976 * xmlTextReaderReadBase64:
977 * @reader: the xmlTextReaderPtr used
978 * @array: a byte array to store the content.
979 * @offset: the zero-based index into array where the method should
980 * begin to write.
981 * @len: the number of bytes to write.
982 *
983 * Reads and decodes the Base64 encoded contents of an element and
984 * stores the result in a byte buffer.
985 *
986 * Returns the number of bytes written to array, or zero if the current
987 * instance is not positioned on an element or -1 in case of error.
988 */
989int
990xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
991 int offset, int len) {
992 if ((reader == NULL) || (reader->ctxt == NULL))
993 return(-1);
994 if (reader->ctxt->wellFormed != 1)
995 return(-1);
996
997 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
998 return(0);
999 TODO
1000 return(0);
1001}
1002
1003/**
1004 * xmlTextReaderReadBinHex:
1005 * @reader: the xmlTextReaderPtr used
1006 * @array: a byte array to store the content.
1007 * @offset: the zero-based index into array where the method should
1008 * begin to write.
1009 * @len: the number of bytes to write.
1010 *
1011 * Reads and decodes the BinHex encoded contents of an element and
1012 * stores the result in a byte buffer.
1013 *
1014 * Returns the number of bytes written to array, or zero if the current
1015 * instance is not positioned on an element or -1 in case of error.
1016 */
1017int
1018xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
1019 int offset, int len) {
1020 if ((reader == NULL) || (reader->ctxt == NULL))
1021 return(-1);
1022 if (reader->ctxt->wellFormed != 1)
1023 return(-1);
1024
1025 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1026 return(0);
1027 TODO
1028 return(0);
1029}
1030
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001031/************************************************************************
1032 * *
1033 * Constructor and destructors *
1034 * *
1035 ************************************************************************/
1036/**
1037 * xmlNewTextReader:
1038 * @input: the xmlParserInputBufferPtr used to read data
Daniel Veillardea7751d2002-12-20 00:16:24 +00001039 * @URI: the URI information for the source if available
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001040 *
1041 * Create an xmlTextReader structure fed with @input
1042 *
1043 * Returns the new xmlTextReaderPtr or NULL in case of error
1044 */
1045xmlTextReaderPtr
Daniel Veillardea7751d2002-12-20 00:16:24 +00001046xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001047 xmlTextReaderPtr ret;
1048 int val;
1049
1050 if (input == NULL)
1051 return(NULL);
1052 ret = xmlMalloc(sizeof(xmlTextReader));
1053 if (ret == NULL) {
1054 xmlGenericError(xmlGenericErrorContext,
1055 "xmlNewTextReader : malloc failed\n");
1056 return(NULL);
1057 }
1058 memset(ret, 0, sizeof(xmlTextReader));
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001059 ret->entTab = NULL;
1060 ret->entMax = 0;
1061 ret->entNr = 0;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001062 ret->input = input;
1063 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
1064 if (ret->sax == NULL) {
1065 xmlFree(ret);
1066 xmlGenericError(xmlGenericErrorContext,
1067 "xmlNewTextReader : malloc failed\n");
1068 return(NULL);
1069 }
1070 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
1071 ret->startElement = ret->sax->startElement;
1072 ret->sax->startElement = xmlTextReaderStartElement;
1073 ret->endElement = ret->sax->endElement;
1074 ret->sax->endElement = xmlTextReaderEndElement;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001075 ret->characters = ret->sax->characters;
1076 ret->sax->characters = xmlTextReaderCharacters;
1077 ret->cdataBlock = ret->sax->cdataBlock;
1078 ret->sax->cdataBlock = xmlTextReaderCDataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001079
Daniel Veillard67df8092002-12-16 22:04:11 +00001080 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001081 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001082 ret->curnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001083 val = xmlParserInputBufferRead(input, 4);
1084 if (val >= 4) {
1085 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
Daniel Veillardea7751d2002-12-20 00:16:24 +00001086 (const char *) ret->input->buffer->content, 4, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001087 ret->base = 0;
1088 ret->cur = 4;
1089 } else {
Daniel Veillardea7751d2002-12-20 00:16:24 +00001090 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001091 ret->base = 0;
1092 ret->cur = 0;
1093 }
1094 ret->ctxt->_private = ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001095 ret->ctxt->linenumbers = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001096 ret->allocs = XML_TEXTREADER_CTXT;
1097 return(ret);
1098
1099}
1100
1101/**
1102 * xmlNewTextReaderFilename:
1103 * @URI: the URI of the resource to process
1104 *
1105 * Create an xmlTextReader structure fed with the resource at @URI
1106 *
1107 * Returns the new xmlTextReaderPtr or NULL in case of error
1108 */
1109xmlTextReaderPtr
1110xmlNewTextReaderFilename(const char *URI) {
1111 xmlParserInputBufferPtr input;
1112 xmlTextReaderPtr ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001113 char *directory = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001114
1115 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
1116 if (input == NULL)
1117 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00001118 ret = xmlNewTextReader(input, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001119 if (ret == NULL) {
1120 xmlFreeParserInputBuffer(input);
1121 return(NULL);
1122 }
1123 ret->allocs |= XML_TEXTREADER_INPUT;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001124 if (ret->ctxt->directory == NULL)
1125 directory = xmlParserGetDirectory(URI);
1126 if ((ret->ctxt->directory == NULL) && (directory != NULL))
1127 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
1128 if (directory != NULL)
1129 xmlFree(directory);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001130 return(ret);
1131}
1132
1133/**
1134 * xmlFreeTextReader:
1135 * @reader: the xmlTextReaderPtr
1136 *
1137 * Deallocate all the resources associated to the reader
1138 */
1139void
1140xmlFreeTextReader(xmlTextReaderPtr reader) {
1141 if (reader == NULL)
1142 return;
1143 if (reader->ctxt != NULL) {
1144 if (reader->ctxt->myDoc != NULL) {
1145 xmlFreeDoc(reader->ctxt->myDoc);
1146 reader->ctxt->myDoc = NULL;
1147 }
Daniel Veillard336fc7d2002-12-27 19:37:04 +00001148 if ((reader->ctxt->vctxt.vstateTab != NULL) &&
1149 (reader->ctxt->vctxt.vstateMax > 0)){
1150 xmlFree(reader->ctxt->vctxt.vstateTab);
1151 reader->ctxt->vctxt.vstateTab = 0;
1152 reader->ctxt->vctxt.vstateMax = 0;
1153 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001154 if (reader->allocs & XML_TEXTREADER_CTXT)
1155 xmlFreeParserCtxt(reader->ctxt);
1156 }
1157 if (reader->sax != NULL)
1158 xmlFree(reader->sax);
1159 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
1160 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001161 if (reader->faketext != NULL) {
1162 xmlFreeNode(reader->faketext);
1163 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001164 if (reader->entTab != NULL)
1165 xmlFree(reader->entTab);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001166 xmlFree(reader);
1167}
1168
1169/************************************************************************
1170 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001171 * Methods for XmlTextReader *
1172 * *
1173 ************************************************************************/
1174/**
1175 * xmlTextReaderClose:
1176 * @reader: the xmlTextReaderPtr used
1177 *
1178 * This method releases any resources allocated by the current instance
1179 * changes the state to Closed and close any underlying input.
1180 *
1181 * Returns 0 or -1 in case of error
1182 */
1183int
1184xmlTextReaderClose(xmlTextReaderPtr reader) {
1185 if (reader == NULL)
1186 return(-1);
1187 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001188 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001189 reader->mode = XML_TEXTREADER_MODE_CLOSED;
1190 if (reader->ctxt != NULL) {
1191 if (reader->ctxt->myDoc != NULL) {
1192 xmlFreeDoc(reader->ctxt->myDoc);
1193 reader->ctxt->myDoc = NULL;
1194 }
1195 if (reader->allocs & XML_TEXTREADER_CTXT) {
1196 xmlFreeParserCtxt(reader->ctxt);
1197 reader->allocs -= XML_TEXTREADER_CTXT;
1198 }
1199 }
1200 if (reader->sax != NULL) {
1201 xmlFree(reader->sax);
1202 reader->sax = NULL;
1203 }
1204 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
1205 xmlFreeParserInputBuffer(reader->input);
1206 reader->allocs -= XML_TEXTREADER_INPUT;
1207 }
1208 return(0);
1209}
1210
1211/**
1212 * xmlTextReaderGetAttributeNo:
1213 * @reader: the xmlTextReaderPtr used
1214 * @no: the zero-based index of the attribute relative to the containing element
1215 *
1216 * Provides the value of the attribute with the specified index relative
1217 * to the containing element.
1218 *
1219 * Returns a string containing the value of the specified attribute, or NULL
1220 * in case of error. The string must be deallocated by the caller.
1221 */
1222xmlChar *
1223xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
1224 xmlChar *ret;
1225 int i;
1226 xmlAttrPtr cur;
1227 xmlNsPtr ns;
1228
1229 if (reader == NULL)
1230 return(NULL);
1231 if (reader->node == NULL)
1232 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001233 if (reader->curnode != NULL)
1234 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001235 /* TODO: handle the xmlDecl */
1236 if (reader->node->type != XML_ELEMENT_NODE)
1237 return(NULL);
1238
1239 ns = reader->node->nsDef;
1240 for (i = 0;(i < no) && (ns != NULL);i++) {
1241 ns = ns->next;
1242 }
1243 if (ns != NULL)
1244 return(xmlStrdup(ns->href));
1245
1246 cur = reader->node->properties;
1247 if (cur == NULL)
1248 return(NULL);
1249 for (;i < no;i++) {
1250 cur = cur->next;
1251 if (cur == NULL)
1252 return(NULL);
1253 }
1254 /* TODO walk the DTD if present */
1255
1256 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
1257 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
1258 return(ret);
1259}
1260
1261/**
1262 * xmlTextReaderGetAttribute:
1263 * @reader: the xmlTextReaderPtr used
1264 * @name: the qualified name of the attribute.
1265 *
1266 * Provides the value of the attribute with the specified qualified name.
1267 *
1268 * Returns a string containing the value of the specified attribute, or NULL
1269 * in case of error. The string must be deallocated by the caller.
1270 */
1271xmlChar *
1272xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1273 xmlChar *prefix = NULL;
1274 xmlChar *localname;
1275 xmlNsPtr ns;
1276 xmlChar *ret = NULL;
1277
1278 if ((reader == NULL) || (name == NULL))
1279 return(NULL);
1280 if (reader->node == NULL)
1281 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001282 if (reader->curnode != NULL)
1283 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001284
1285 /* TODO: handle the xmlDecl */
1286 if (reader->node->type != XML_ELEMENT_NODE)
1287 return(NULL);
1288
1289 localname = xmlSplitQName2(name, &prefix);
1290 if (localname == NULL)
1291 return(xmlGetProp(reader->node, name));
1292
1293 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1294 if (ns != NULL)
1295 ret = xmlGetNsProp(reader->node, localname, ns->href);
1296
1297 if (localname != NULL)
1298 xmlFree(localname);
1299 if (prefix != NULL)
1300 xmlFree(prefix);
1301 return(ret);
1302}
1303
1304
1305/**
1306 * xmlTextReaderGetAttributeNs:
1307 * @reader: the xmlTextReaderPtr used
1308 * @localName: the local name of the attribute.
1309 * @namespaceURI: the namespace URI of the attribute.
1310 *
1311 * Provides the value of the specified attribute
1312 *
1313 * Returns a string containing the value of the specified attribute, or NULL
1314 * in case of error. The string must be deallocated by the caller.
1315 */
1316xmlChar *
1317xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
1318 const xmlChar *namespaceURI) {
1319 if ((reader == NULL) || (localName == NULL))
1320 return(NULL);
1321 if (reader->node == NULL)
1322 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001323 if (reader->curnode != NULL)
1324 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001325
1326 /* TODO: handle the xmlDecl */
1327 if (reader->node->type != XML_ELEMENT_NODE)
1328 return(NULL);
1329
1330 return(xmlGetNsProp(reader->node, localName, namespaceURI));
1331}
1332
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001333/**
1334 * xmlTextReaderGetRemainder:
1335 * @reader: the xmlTextReaderPtr used
1336 *
1337 * Method to get the remainder of the buffered XML. this method stops the
1338 * parser, set its state to End Of File and return the input stream with
1339 * what is left that the parser did not use.
1340 *
1341 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
1342 * in case of error.
1343 */
1344xmlParserInputBufferPtr
1345xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
1346 xmlParserInputBufferPtr ret = NULL;
1347
1348 if (reader == NULL)
1349 return(NULL);
1350 if (reader->node == NULL)
1351 return(NULL);
1352
1353 reader->node = NULL;
1354 reader->curnode = NULL;
1355 reader->mode = XML_TEXTREADER_MODE_EOF;
1356 if (reader->ctxt != NULL) {
1357 if (reader->ctxt->myDoc != NULL) {
1358 xmlFreeDoc(reader->ctxt->myDoc);
1359 reader->ctxt->myDoc = NULL;
1360 }
1361 if (reader->allocs & XML_TEXTREADER_CTXT) {
1362 xmlFreeParserCtxt(reader->ctxt);
1363 reader->allocs -= XML_TEXTREADER_CTXT;
1364 }
1365 }
1366 if (reader->sax != NULL) {
1367 xmlFree(reader->sax);
1368 reader->sax = NULL;
1369 }
1370 if (reader->allocs & XML_TEXTREADER_INPUT) {
1371 ret = reader->input;
1372 reader->allocs -= XML_TEXTREADER_INPUT;
1373 } else {
1374 /*
1375 * Hum, one may need to duplicate the data structure because
1376 * without reference counting the input may be freed twice:
1377 * - by the layer which allocated it.
1378 * - by the layer to which would have been returned to.
1379 */
1380 TODO
1381 return(NULL);
1382 }
1383 return(ret);
1384}
1385
1386/**
1387 * xmlTextReaderLookupNamespace:
1388 * @reader: the xmlTextReaderPtr used
1389 * @prefix: the prefix whose namespace URI is to be resolved. To return
1390 * the default namespace, specify NULL
1391 *
1392 * Resolves a namespace prefix in the scope of the current element.
1393 *
1394 * Returns a string containing the namespace URI to which the prefix maps
1395 * or NULL in case of error. The string must be deallocated by the caller.
1396 */
1397xmlChar *
1398xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
1399 xmlNsPtr ns;
1400
1401 if (reader == NULL)
1402 return(NULL);
1403 if (reader->node == NULL)
1404 return(NULL);
1405
1406 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1407 if (ns == NULL)
1408 return(NULL);
1409 return(xmlStrdup(ns->href));
1410}
1411
1412/**
1413 * xmlTextReaderMoveToAttributeNo:
1414 * @reader: the xmlTextReaderPtr used
1415 * @no: the zero-based index of the attribute relative to the containing
1416 * element.
1417 *
1418 * Moves the position of the current instance to the attribute with
1419 * the specified index relative to the containing element.
1420 *
1421 * Returns 1 in case of success, -1 in case of error, 0 if not found
1422 */
1423int
1424xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
1425 int i;
1426 xmlAttrPtr cur;
1427 xmlNsPtr ns;
1428
1429 if (reader == NULL)
1430 return(-1);
1431 if (reader->node == NULL)
1432 return(-1);
1433 /* TODO: handle the xmlDecl */
1434 if (reader->node->type != XML_ELEMENT_NODE)
1435 return(-1);
1436
1437 reader->curnode = NULL;
1438
1439 ns = reader->node->nsDef;
1440 for (i = 0;(i < no) && (ns != NULL);i++) {
1441 ns = ns->next;
1442 }
1443 if (ns != NULL) {
1444 reader->curnode = (xmlNodePtr) ns;
1445 return(1);
1446 }
1447
1448 cur = reader->node->properties;
1449 if (cur == NULL)
1450 return(0);
1451 for (;i < no;i++) {
1452 cur = cur->next;
1453 if (cur == NULL)
1454 return(0);
1455 }
1456 /* TODO walk the DTD if present */
1457
1458 reader->curnode = (xmlNodePtr) cur;
1459 return(1);
1460}
1461
1462/**
1463 * xmlTextReaderMoveToAttribute:
1464 * @reader: the xmlTextReaderPtr used
1465 * @name: the qualified name of the attribute.
1466 *
1467 * Moves the position of the current instance to the attribute with
1468 * the specified qualified name.
1469 *
1470 * Returns 1 in case of success, -1 in case of error, 0 if not found
1471 */
1472int
1473xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1474 xmlChar *prefix = NULL;
1475 xmlChar *localname;
1476 xmlNsPtr ns;
1477 xmlAttrPtr prop;
1478
1479 if ((reader == NULL) || (name == NULL))
1480 return(-1);
1481 if (reader->node == NULL)
1482 return(-1);
1483
1484 /* TODO: handle the xmlDecl */
1485 if (reader->node->type != XML_ELEMENT_NODE)
1486 return(0);
1487
1488 localname = xmlSplitQName2(name, &prefix);
1489 if (localname == NULL) {
1490 /*
1491 * Namespace default decl
1492 */
1493 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1494 ns = reader->node->nsDef;
1495 while (ns != NULL) {
1496 if (ns->prefix == NULL) {
1497 reader->curnode = (xmlNodePtr) ns;
1498 return(1);
1499 }
1500 ns = ns->next;
1501 }
1502 return(0);
1503 }
1504
1505 prop = reader->node->properties;
1506 while (prop != NULL) {
1507 /*
1508 * One need to have
1509 * - same attribute names
1510 * - and the attribute carrying that namespace
1511 */
1512 if ((xmlStrEqual(prop->name, name)) &&
1513 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
1514 reader->curnode = (xmlNodePtr) prop;
1515 return(1);
1516 }
1517 prop = prop->next;
1518 }
1519 return(0);
1520 }
1521
1522 /*
1523 * Namespace default decl
1524 */
1525 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
1526 ns = reader->node->nsDef;
1527 while (ns != NULL) {
1528 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
1529 reader->curnode = (xmlNodePtr) ns;
1530 goto found;
1531 }
1532 ns = ns->next;
1533 }
1534 goto not_found;
1535 }
1536 prop = reader->node->properties;
1537 while (prop != NULL) {
1538 /*
1539 * One need to have
1540 * - same attribute names
1541 * - and the attribute carrying that namespace
1542 */
1543 if ((xmlStrEqual(prop->name, localname)) &&
1544 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
1545 reader->curnode = (xmlNodePtr) prop;
1546 goto found;
1547 }
1548 prop = prop->next;
1549 }
1550not_found:
1551 if (localname != NULL)
1552 xmlFree(localname);
1553 if (prefix != NULL)
1554 xmlFree(prefix);
1555 return(0);
1556
1557found:
1558 if (localname != NULL)
1559 xmlFree(localname);
1560 if (prefix != NULL)
1561 xmlFree(prefix);
1562 return(1);
1563}
1564
1565/**
1566 * xmlTextReaderMoveToAttributeNs:
1567 * @reader: the xmlTextReaderPtr used
1568 * @localName: the local name of the attribute.
1569 * @namespaceURI: the namespace URI of the attribute.
1570 *
1571 * Moves the position of the current instance to the attribute with the
1572 * specified local name and namespace URI.
1573 *
1574 * Returns 1 in case of success, -1 in case of error, 0 if not found
1575 */
1576int
1577xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1578 const xmlChar *localName, const xmlChar *namespaceURI) {
1579 xmlAttrPtr prop;
1580 xmlNodePtr node;
1581
1582 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1583 return(-1);
1584 if (reader->node == NULL)
1585 return(-1);
1586 if (reader->node->type != XML_ELEMENT_NODE)
1587 return(0);
1588 node = reader->node;
1589
1590 /*
1591 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1592 * namespace name associated to "xmlns"
1593 */
1594 prop = node->properties;
1595 while (prop != NULL) {
1596 /*
1597 * One need to have
1598 * - same attribute names
1599 * - and the attribute carrying that namespace
1600 */
1601 if (xmlStrEqual(prop->name, localName) &&
1602 ((prop->ns != NULL) &&
1603 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1604 reader->curnode = (xmlNodePtr) prop;
1605 return(1);
1606 }
1607 prop = prop->next;
1608 }
1609 return(0);
1610}
1611
1612/**
1613 * xmlTextReaderMoveToFirstAttribute:
1614 * @reader: the xmlTextReaderPtr used
1615 *
1616 * Moves the position of the current instance to the first attribute
1617 * associated with the current node.
1618 *
1619 * Returns 1 in case of success, -1 in case of error, 0 if not found
1620 */
1621int
1622xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1623 if (reader == NULL)
1624 return(-1);
1625 if (reader->node == NULL)
1626 return(-1);
1627 if (reader->node->type != XML_ELEMENT_NODE)
1628 return(0);
1629
1630 if (reader->node->nsDef != NULL) {
1631 reader->curnode = (xmlNodePtr) reader->node->nsDef;
1632 return(1);
1633 }
1634 if (reader->node->properties != NULL) {
1635 reader->curnode = (xmlNodePtr) reader->node->properties;
1636 return(1);
1637 }
1638 return(0);
1639}
1640
1641/**
1642 * xmlTextReaderMoveToNextAttribute:
1643 * @reader: the xmlTextReaderPtr used
1644 *
1645 * Moves the position of the current instance to the next attribute
1646 * associated with the current node.
1647 *
1648 * Returns 1 in case of success, -1 in case of error, 0 if not found
1649 */
1650int
1651xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1652 if (reader == NULL)
1653 return(-1);
1654 if (reader->node == NULL)
1655 return(-1);
1656 if (reader->node->type != XML_ELEMENT_NODE)
1657 return(0);
1658 if (reader->curnode == NULL)
1659 return(xmlTextReaderMoveToFirstAttribute(reader));
1660
1661 if (reader->curnode->type == XML_NAMESPACE_DECL) {
1662 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1663 if (ns->next != NULL) {
1664 reader->curnode = (xmlNodePtr) ns->next;
1665 return(1);
1666 }
1667 if (reader->node->properties != NULL) {
1668 reader->curnode = (xmlNodePtr) reader->node->properties;
1669 return(1);
1670 }
1671 return(0);
1672 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1673 (reader->curnode->next != NULL)) {
1674 reader->curnode = reader->curnode->next;
1675 return(1);
1676 }
1677 return(0);
1678}
1679
1680/**
1681 * xmlTextReaderMoveToElement:
1682 * @reader: the xmlTextReaderPtr used
1683 *
1684 * Moves the position of the current instance to the node that
1685 * contains the current Attribute node.
1686 *
1687 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1688 */
1689int
1690xmlTextReaderMoveToElement(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 if (reader->curnode != NULL) {
1698 reader->curnode = NULL;
1699 return(1);
1700 }
1701 return(0);
1702}
1703
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001704/**
1705 * xmlTextReaderReadAttributeValue:
1706 * @reader: the xmlTextReaderPtr used
1707 *
1708 * Parses an attribute value into one or more Text and EntityReference nodes.
1709 *
1710 * Returns 1 in case of success, 0 if the reader was not positionned on an
1711 * ttribute node or all the attribute values have been read, or -1
1712 * in case of error.
1713 */
1714int
1715xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1716 if (reader == NULL)
1717 return(-1);
1718 if (reader->node == NULL)
1719 return(-1);
1720 if (reader->curnode == NULL)
1721 return(0);
1722 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1723 if (reader->curnode->children == NULL)
1724 return(0);
1725 reader->curnode = reader->curnode->children;
1726 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1727 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1728
1729 if (reader->faketext == NULL) {
1730 reader->faketext = xmlNewDocText(reader->node->doc,
1731 ns->href);
1732 } else {
1733 if (reader->faketext->content != NULL)
1734 xmlFree(reader->faketext->content);
1735 reader->faketext->content = xmlStrdup(ns->href);
1736 }
1737 reader->curnode = reader->faketext;
1738 } else {
1739 if (reader->curnode->next == NULL)
1740 return(0);
1741 reader->curnode = reader->curnode->next;
1742 }
1743 return(1);
1744}
1745
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001746/************************************************************************
1747 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001748 * Acces API to the current node *
1749 * *
1750 ************************************************************************/
1751/**
1752 * xmlTextReaderAttributeCount:
1753 * @reader: the xmlTextReaderPtr used
1754 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001755 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001756 *
1757 * Returns 0 i no attributes, -1 in case of error or the attribute count
1758 */
1759int
1760xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1761 int ret;
1762 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00001763 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001764 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001765
1766 if (reader == NULL)
1767 return(-1);
1768 if (reader->node == NULL)
1769 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001770
1771 if (reader->curnode != NULL)
1772 node = reader->curnode;
1773 else
1774 node = reader->node;
1775
1776 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001777 return(0);
1778 if ((reader->state == XML_TEXTREADER_END) ||
1779 (reader->state == XML_TEXTREADER_BACKTRACK))
1780 return(0);
1781 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001782 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001783 while (attr != NULL) {
1784 ret++;
1785 attr = attr->next;
1786 }
Daniel Veillard67df8092002-12-16 22:04:11 +00001787 ns = node->nsDef;
1788 while (ns != NULL) {
1789 ret++;
1790 ns = ns->next;
1791 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001792 return(ret);
1793}
1794
1795/**
1796 * xmlTextReaderNodeType:
1797 * @reader: the xmlTextReaderPtr used
1798 *
1799 * Get the node type of the current node
1800 * Reference:
1801 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1802 *
1803 * Returns the xmlNodeType of the current node or -1 in case of error
1804 */
1805int
1806xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001807 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001808 if (reader == NULL)
1809 return(-1);
1810 if (reader->node == NULL)
1811 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001812 if (reader->curnode != NULL)
1813 node = reader->curnode;
1814 else
1815 node = reader->node;
1816 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001817 case XML_ELEMENT_NODE:
1818 if ((reader->state == XML_TEXTREADER_END) ||
1819 (reader->state == XML_TEXTREADER_BACKTRACK))
1820 return(15);
1821 return(1);
Daniel Veillardecaba492002-12-30 10:55:29 +00001822 case XML_NAMESPACE_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001823 case XML_ATTRIBUTE_NODE:
1824 return(2);
1825 case XML_TEXT_NODE:
1826 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1827 case XML_CDATA_SECTION_NODE:
1828 return(4);
1829 case XML_ENTITY_REF_NODE:
1830 return(5);
1831 case XML_ENTITY_NODE:
1832 return(6);
1833 case XML_PI_NODE:
1834 return(7);
1835 case XML_COMMENT_NODE:
1836 return(8);
1837 case XML_DOCUMENT_NODE:
1838 case XML_HTML_DOCUMENT_NODE:
1839#ifdef LIBXML_DOCB_ENABLED
1840 case XML_DOCB_DOCUMENT_NODE:
1841#endif
1842 return(9);
1843 case XML_DOCUMENT_FRAG_NODE:
1844 return(11);
1845 case XML_NOTATION_NODE:
1846 return(12);
1847 case XML_DOCUMENT_TYPE_NODE:
1848 case XML_DTD_NODE:
1849 return(10);
1850
1851 case XML_ELEMENT_DECL:
1852 case XML_ATTRIBUTE_DECL:
1853 case XML_ENTITY_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001854 case XML_XINCLUDE_START:
1855 case XML_XINCLUDE_END:
1856 return(0);
1857 }
1858 return(-1);
1859}
1860
1861/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001862 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001863 * @reader: the xmlTextReaderPtr used
1864 *
1865 * Check if the current node is empty
1866 *
1867 * Returns 1 if empty, 0 if not and -1 in case of error
1868 */
1869int
1870xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1871 if ((reader == NULL) || (reader->node == NULL))
1872 return(-1);
Daniel Veillarddf512f42002-12-23 15:56:21 +00001873 if (reader->node->type != XML_ELEMENT_NODE)
1874 return(0);
Daniel Veillarde3c036e2003-01-01 15:11:05 +00001875 if (reader->curnode != NULL)
1876 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001877 if (reader->node->children != NULL)
1878 return(0);
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001879 if (reader->state == XML_TEXTREADER_END)
1880 return(0);
Daniel Veillard067bae52003-01-05 01:27:54 +00001881 return(reader->node->_private == (void *)xmlTextReaderIsEmpty);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001882}
1883
1884/**
1885 * xmlTextReaderLocalName:
1886 * @reader: the xmlTextReaderPtr used
1887 *
1888 * The local name of the node.
1889 *
1890 * Returns the local name or NULL if not available
1891 */
1892xmlChar *
1893xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001894 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001895 if ((reader == NULL) || (reader->node == NULL))
1896 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001897 if (reader->curnode != NULL)
1898 node = reader->curnode;
1899 else
1900 node = reader->node;
1901 if (node->type == XML_NAMESPACE_DECL) {
1902 xmlNsPtr ns = (xmlNsPtr) node;
1903 if (ns->prefix == NULL)
1904 return(xmlStrdup(BAD_CAST "xmlns"));
1905 else
1906 return(xmlStrdup(ns->prefix));
1907 }
1908 if ((node->type != XML_ELEMENT_NODE) &&
1909 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001910 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001911 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001912}
1913
1914/**
1915 * xmlTextReaderName:
1916 * @reader: the xmlTextReaderPtr used
1917 *
1918 * The qualified name of the node, equal to Prefix :LocalName.
1919 *
1920 * Returns the local name or NULL if not available
1921 */
1922xmlChar *
1923xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001924 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001925 xmlChar *ret;
1926
1927 if ((reader == NULL) || (reader->node == NULL))
1928 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001929 if (reader->curnode != NULL)
1930 node = reader->curnode;
1931 else
1932 node = reader->node;
1933 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001934 case XML_ELEMENT_NODE:
1935 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001936 if ((node->ns == NULL) ||
1937 (node->ns->prefix == NULL))
1938 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001939
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001940 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001941 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001942 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001943 return(ret);
1944 case XML_TEXT_NODE:
1945 return(xmlStrdup(BAD_CAST "#text"));
1946 case XML_CDATA_SECTION_NODE:
1947 return(xmlStrdup(BAD_CAST "#cdata-section"));
1948 case XML_ENTITY_NODE:
1949 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001950 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001951 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001952 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001953 case XML_COMMENT_NODE:
1954 return(xmlStrdup(BAD_CAST "#comment"));
1955 case XML_DOCUMENT_NODE:
1956 case XML_HTML_DOCUMENT_NODE:
1957#ifdef LIBXML_DOCB_ENABLED
1958 case XML_DOCB_DOCUMENT_NODE:
1959#endif
1960 return(xmlStrdup(BAD_CAST "#document"));
1961 case XML_DOCUMENT_FRAG_NODE:
1962 return(xmlStrdup(BAD_CAST "#document-fragment"));
1963 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001964 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001965 case XML_DOCUMENT_TYPE_NODE:
1966 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001967 return(xmlStrdup(node->name));
1968 case XML_NAMESPACE_DECL: {
1969 xmlNsPtr ns = (xmlNsPtr) node;
1970
1971 ret = xmlStrdup(BAD_CAST "xmlns");
1972 if (ns->prefix == NULL)
1973 return(ret);
1974 ret = xmlStrcat(ret, BAD_CAST ":");
1975 ret = xmlStrcat(ret, ns->prefix);
1976 return(ret);
1977 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001978
1979 case XML_ELEMENT_DECL:
1980 case XML_ATTRIBUTE_DECL:
1981 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001982 case XML_XINCLUDE_START:
1983 case XML_XINCLUDE_END:
1984 return(NULL);
1985 }
1986 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001987}
1988
1989/**
1990 * xmlTextReaderPrefix:
1991 * @reader: the xmlTextReaderPtr used
1992 *
1993 * A shorthand reference to the namespace associated with the node.
1994 *
1995 * Returns the prefix or NULL if not available
1996 */
1997xmlChar *
1998xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001999 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002000 if ((reader == NULL) || (reader->node == NULL))
2001 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002002 if (reader->curnode != NULL)
2003 node = reader->curnode;
2004 else
2005 node = reader->node;
2006 if (node->type == XML_NAMESPACE_DECL) {
2007 xmlNsPtr ns = (xmlNsPtr) node;
2008 if (ns->prefix == NULL)
2009 return(NULL);
2010 return(xmlStrdup(BAD_CAST "xmlns"));
2011 }
2012 if ((node->type != XML_ELEMENT_NODE) &&
2013 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002014 return(NULL);
Daniel Veillard952379b2003-03-17 15:37:12 +00002015 if ((node->ns != NULL) && (node->ns->prefix != NULL))
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002016 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002017 return(NULL);
2018}
2019
2020/**
2021 * xmlTextReaderNamespaceUri:
2022 * @reader: the xmlTextReaderPtr used
2023 *
2024 * The URI defining the namespace associated with the node.
2025 *
2026 * Returns the namespace URI or NULL if not available
2027 */
2028xmlChar *
2029xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002030 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002031 if ((reader == NULL) || (reader->node == NULL))
2032 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002033 if (reader->curnode != NULL)
2034 node = reader->curnode;
2035 else
2036 node = reader->node;
Daniel Veillardecaba492002-12-30 10:55:29 +00002037 if (node->type == XML_NAMESPACE_DECL)
2038 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002039 if ((node->type != XML_ELEMENT_NODE) &&
2040 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002041 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002042 if (node->ns != NULL)
2043 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002044 return(NULL);
2045}
2046
2047/**
2048 * xmlTextReaderBaseUri:
2049 * @reader: the xmlTextReaderPtr used
2050 *
2051 * The base URI of the node.
2052 *
2053 * Returns the base URI or NULL if not available
2054 */
2055xmlChar *
2056xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
2057 if ((reader == NULL) || (reader->node == NULL))
2058 return(NULL);
2059 return(xmlNodeGetBase(NULL, reader->node));
2060}
2061
2062/**
2063 * xmlTextReaderDepth:
2064 * @reader: the xmlTextReaderPtr used
2065 *
2066 * The depth of the node in the tree.
2067 *
2068 * Returns the depth or -1 in case of error
2069 */
2070int
2071xmlTextReaderDepth(xmlTextReaderPtr reader) {
2072 if (reader == NULL)
2073 return(-1);
2074 if (reader->node == NULL)
2075 return(0);
2076
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002077 if (reader->curnode != NULL) {
2078 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
2079 (reader->curnode->type == XML_NAMESPACE_DECL))
2080 return(reader->depth + 1);
2081 return(reader->depth + 2);
2082 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002083 return(reader->depth);
2084}
2085
2086/**
2087 * xmlTextReaderHasAttributes:
2088 * @reader: the xmlTextReaderPtr used
2089 *
2090 * Whether the node has attributes.
2091 *
2092 * Returns 1 if true, 0 if false, and -1 in case or error
2093 */
2094int
2095xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002096 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002097 if (reader == NULL)
2098 return(-1);
2099 if (reader->node == NULL)
2100 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002101 if (reader->curnode != NULL)
2102 node = reader->curnode;
2103 else
2104 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002105
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002106 if ((node->type == XML_ELEMENT_NODE) &&
2107 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002108 return(1);
2109 /* TODO: handle the xmlDecl */
2110 return(0);
2111}
2112
2113/**
2114 * xmlTextReaderHasValue:
2115 * @reader: the xmlTextReaderPtr used
2116 *
2117 * Whether the node can have a text value.
2118 *
2119 * Returns 1 if true, 0 if false, and -1 in case or error
2120 */
2121int
2122xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002123 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002124 if (reader == NULL)
2125 return(-1);
2126 if (reader->node == NULL)
2127 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002128 if (reader->curnode != NULL)
2129 node = reader->curnode;
2130 else
2131 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002132
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002133 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002134 case XML_ATTRIBUTE_NODE:
2135 case XML_TEXT_NODE:
2136 case XML_CDATA_SECTION_NODE:
2137 case XML_PI_NODE:
2138 case XML_COMMENT_NODE:
Daniel Veillard9e077102003-04-10 13:36:54 +00002139 case XML_NAMESPACE_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002140 return(1);
2141 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002142 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002143 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002144 return(0);
2145}
2146
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002147/**
2148 * xmlTextReaderValue:
2149 * @reader: the xmlTextReaderPtr used
2150 *
2151 * Provides the text value of the node if present
2152 *
2153 * Returns the string or NULL if not available. The retsult must be deallocated
2154 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002155 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002156xmlChar *
2157xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002158 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002159 if (reader == NULL)
2160 return(NULL);
2161 if (reader->node == NULL)
2162 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002163 if (reader->curnode != NULL)
2164 node = reader->curnode;
2165 else
2166 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002167
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002168 switch (node->type) {
2169 case XML_NAMESPACE_DECL:
2170 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002171 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002172 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002173
2174 if (attr->parent != NULL)
2175 return (xmlNodeListGetString
2176 (attr->parent->doc, attr->children, 1));
2177 else
2178 return (xmlNodeListGetString(NULL, attr->children, 1));
2179 break;
2180 }
2181 case XML_TEXT_NODE:
2182 case XML_CDATA_SECTION_NODE:
2183 case XML_PI_NODE:
2184 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002185 if (node->content != NULL)
2186 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002187 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002188 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002189 }
2190 return(NULL);
2191}
2192
2193/**
2194 * xmlTextReaderIsDefault:
2195 * @reader: the xmlTextReaderPtr used
2196 *
2197 * Whether an Attribute node was generated from the default value
2198 * defined in the DTD or schema.
2199 *
2200 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
2201 */
2202int
2203xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
2204 if (reader == NULL)
2205 return(-1);
2206 return(0);
2207}
2208
2209/**
2210 * xmlTextReaderQuoteChar:
2211 * @reader: the xmlTextReaderPtr used
2212 *
2213 * The quotation mark character used to enclose the value of an attribute.
2214 *
2215 * Returns " or ' and -1 in case of error
2216 */
2217int
2218xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
2219 if (reader == NULL)
2220 return(-1);
2221 /* TODO maybe lookup the attribute value for " first */
2222 return((int) '"');
2223}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002224
2225/**
2226 * xmlTextReaderXmlLang:
2227 * @reader: the xmlTextReaderPtr used
2228 *
2229 * The xml:lang scope within which the node resides.
2230 *
2231 * Returns the xml:lang value or NULL if none exists.
2232 */
2233xmlChar *
2234xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
2235 if (reader == NULL)
2236 return(NULL);
2237 if (reader->node == NULL)
2238 return(NULL);
2239 return(xmlNodeGetLang(reader->node));
2240}
2241
Daniel Veillard67df8092002-12-16 22:04:11 +00002242/**
2243 * xmlTextReaderNormalization:
2244 * @reader: the xmlTextReaderPtr used
2245 *
2246 * The value indicating whether to normalize white space and attribute values.
2247 * Since attribute value and end of line normalizations are a MUST in the XML
2248 * specification only the value true is accepted. The broken bahaviour of
2249 * accepting out of range character entities like &#0; is of course not
2250 * supported either.
2251 *
2252 * Returns 1 or -1 in case of error.
2253 */
2254int
2255xmlTextReaderNormalization(xmlTextReaderPtr reader) {
2256 if (reader == NULL)
2257 return(-1);
2258 return(1);
2259}
2260
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002261/************************************************************************
2262 * *
2263 * Extensions to the base APIs *
2264 * *
2265 ************************************************************************/
2266
2267/**
2268 * xmlTextReaderSetParserProp:
2269 * @reader: the xmlTextReaderPtr used
2270 * @prop: the xmlParserProperties to set
2271 * @value: usually 0 or 1 to (de)activate it
2272 *
2273 * Change the parser processing behaviour by changing some of its internal
2274 * properties. Note that some properties can only be changed before any
2275 * read has been done.
2276 *
2277 * Returns 0 if the call was successful, or -1 in case of error
2278 */
2279int
2280xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
2281 xmlParserProperties p = (xmlParserProperties) prop;
2282 xmlParserCtxtPtr ctxt;
2283
2284 if ((reader == NULL) || (reader->ctxt == NULL))
2285 return(-1);
2286 ctxt = reader->ctxt;
2287
2288 switch (p) {
2289 case XML_PARSER_LOADDTD:
2290 if (value != 0) {
2291 if (ctxt->loadsubset == 0) {
2292 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2293 return(-1);
2294 ctxt->loadsubset = XML_DETECT_IDS;
2295 }
2296 } else {
2297 ctxt->loadsubset = 0;
2298 }
2299 return(0);
2300 case XML_PARSER_DEFAULTATTRS:
2301 if (value != 0) {
2302 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
2303 } else {
2304 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2305 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
2306 }
2307 return(0);
2308 case XML_PARSER_VALIDATE:
2309 if (value != 0) {
2310 ctxt->validate = 1;
2311 } else {
2312 ctxt->validate = 0;
2313 }
2314 return(0);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002315 case XML_PARSER_SUBST_ENTITIES:
2316 if (value != 0) {
2317 ctxt->replaceEntities = 1;
2318 } else {
2319 ctxt->replaceEntities = 0;
2320 }
2321 return(0);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002322 }
2323 return(-1);
2324}
2325
2326/**
2327 * xmlTextReaderGetParserProp:
2328 * @reader: the xmlTextReaderPtr used
2329 * @prop: the xmlParserProperties to get
2330 *
2331 * Read the parser internal property.
2332 *
2333 * Returns the value, usually 0 or 1, or -1 in case of error.
2334 */
2335int
2336xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
2337 xmlParserProperties p = (xmlParserProperties) prop;
2338 xmlParserCtxtPtr ctxt;
2339
2340 if ((reader == NULL) || (reader->ctxt == NULL))
2341 return(-1);
2342 ctxt = reader->ctxt;
2343
2344 switch (p) {
2345 case XML_PARSER_LOADDTD:
2346 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
2347 return(1);
2348 return(0);
2349 case XML_PARSER_DEFAULTATTRS:
2350 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2351 return(1);
2352 return(0);
2353 case XML_PARSER_VALIDATE:
2354 return(ctxt->validate);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002355 case XML_PARSER_SUBST_ENTITIES:
2356 return(ctxt->replaceEntities);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002357 }
2358 return(-1);
2359}
2360
Daniel Veillarde18fc182002-12-28 22:56:33 +00002361/**
2362 * xmlTextReaderCurrentNode:
2363 * @reader: the xmlTextReaderPtr used
2364 *
2365 * Hacking interface allowing to get the xmlNodePtr correponding to the
2366 * current node being accessed by the xmlTextReader. This is dangerous
2367 * because the underlying node may be destroyed on the next Reads.
2368 *
2369 * Returns the xmlNodePtr or NULL in case of error.
2370 */
2371xmlNodePtr
2372xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
2373 if (reader == NULL)
2374 return(NULL);
2375
2376 if (reader->curnode != NULL)
2377 return(reader->curnode);
2378 return(reader->node);
2379}
2380
2381/**
2382 * xmlTextReaderCurrentDoc:
2383 * @reader: the xmlTextReaderPtr used
2384 *
2385 * Hacking interface allowing to get the xmlDocPtr correponding to the
2386 * current document being accessed by the xmlTextReader. This is dangerous
2387 * because the associated node may be destroyed on the next Reads.
2388 *
2389 * Returns the xmlDocPtr or NULL in case of error.
2390 */
2391xmlDocPtr
2392xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
2393 if ((reader == NULL) || (reader->ctxt == NULL))
2394 return(NULL);
2395
2396 return(reader->ctxt->myDoc);
2397}
2398
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002399/************************************************************************
2400 * *
Daniel Veillard26f70262003-01-16 22:45:08 +00002401 * Error Handling Extensions *
2402 * *
2403 ************************************************************************/
2404
2405/* helper to build a xmlMalloc'ed string from a format and va_list */
2406static char *
2407xmlTextReaderBuildMessage(const char *msg, va_list ap) {
2408 int size;
2409 int chars;
2410 char *larger;
2411 char *str;
2412
2413 str = (char *) xmlMalloc(150);
2414 if (str == NULL) {
2415 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
2416 return NULL;
2417 }
2418
2419 size = 150;
2420
2421 while (1) {
2422 chars = vsnprintf(str, size, msg, ap);
2423 if ((chars > -1) && (chars < size))
2424 break;
2425 if (chars > -1)
2426 size += chars + 1;
2427 else
2428 size += 100;
2429 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
2430 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
2431 xmlFree(str);
2432 return NULL;
2433 }
2434 str = larger;
2435 }
2436
2437 return str;
2438}
2439
Daniel Veillard417be3a2003-01-20 21:26:34 +00002440/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00002441 * xmlTextReaderLocatorLineNumber:
Daniel Veillard417be3a2003-01-20 21:26:34 +00002442 * @locator: the xmlTextReaderLocatorPtr used
2443 *
2444 * Obtain the line number for the given locator.
2445 *
2446 * Returns the line number or -1 in case of error.
2447 */
2448int
2449xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
2450 /* we know that locator is a xmlParserCtxtPtr */
2451 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
2452 int ret = -1;
2453
2454 if (ctx->node != NULL) {
2455 ret = xmlGetLineNo(ctx->node);
2456 }
2457 else {
2458 /* inspired from error.c */
2459 xmlParserInputPtr input;
2460 input = ctx->input;
2461 if ((input->filename == NULL) && (ctx->inputNr > 1))
2462 input = ctx->inputTab[ctx->inputNr - 2];
2463 if (input != NULL) {
2464 ret = input->line;
2465 }
2466 else {
2467 ret = -1;
2468 }
2469 }
2470
2471 return ret;
2472}
2473
2474/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00002475 * xmlTextReaderLocatorBaseURI:
Daniel Veillard417be3a2003-01-20 21:26:34 +00002476 * @locator: the xmlTextReaderLocatorPtr used
2477 *
2478 * Obtain the base URI for the given locator.
2479 *
2480 * Returns the base URI or NULL in case of error.
2481 */
2482xmlChar *
2483xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
2484 /* we know that locator is a xmlParserCtxtPtr */
2485 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
2486 xmlChar *ret = NULL;
2487
2488 if (ctx->node != NULL) {
2489 ret = xmlNodeGetBase(NULL,ctx->node);
2490 }
2491 else {
2492 /* inspired from error.c */
2493 xmlParserInputPtr input;
2494 input = ctx->input;
2495 if ((input->filename == NULL) && (ctx->inputNr > 1))
2496 input = ctx->inputTab[ctx->inputNr - 2];
2497 if (input != NULL) {
Daniel Veillard580ced82003-03-21 21:22:48 +00002498 ret = xmlStrdup(BAD_CAST input->filename);
Daniel Veillard417be3a2003-01-20 21:26:34 +00002499 }
2500 else {
2501 ret = NULL;
2502 }
2503 }
2504
2505 return ret;
2506}
2507
Daniel Veillard26f70262003-01-16 22:45:08 +00002508static void
2509xmlTextReaderGenericError(void *ctxt, int severity, char *str) {
2510 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
2511 xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private;
2512
2513 if (str != NULL) {
2514 reader->errorFunc(reader->errorFuncArg,
2515 str,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002516 severity,
2517 (xmlTextReaderLocatorPtr)ctx);
Daniel Veillard26f70262003-01-16 22:45:08 +00002518 xmlFree(str);
2519 }
2520}
2521
2522static void
2523xmlTextReaderError(void *ctxt, const char *msg, ...) {
2524 va_list ap;
2525
2526 va_start(ap,msg);
2527 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002528 XML_PARSER_SEVERITY_ERROR,
Daniel Veillard26f70262003-01-16 22:45:08 +00002529 xmlTextReaderBuildMessage(msg,ap));
2530 va_end(ap);
2531
2532}
2533
2534static void
2535xmlTextReaderWarning(void *ctxt, const char *msg, ...) {
2536 va_list ap;
2537
2538 va_start(ap,msg);
2539 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002540 XML_PARSER_SEVERITY_WARNING,
Daniel Veillard26f70262003-01-16 22:45:08 +00002541 xmlTextReaderBuildMessage(msg,ap));
2542 va_end(ap);
2543}
2544
2545static void
2546xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
2547 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00002548 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00002549
Daniel Veillard417be3a2003-01-20 21:26:34 +00002550 if ((len > 1) && (msg[len - 2] != ':')) {
2551 /*
2552 * some callbacks only report locator information:
2553 * skip them (mimicking behaviour in error.c)
2554 */
2555 va_start(ap,msg);
2556 xmlTextReaderGenericError(ctxt,
2557 XML_PARSER_SEVERITY_VALIDITY_ERROR,
2558 xmlTextReaderBuildMessage(msg,ap));
2559 va_end(ap);
2560 }
Daniel Veillard26f70262003-01-16 22:45:08 +00002561}
2562
2563static void
2564xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
2565 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00002566 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00002567
Daniel Veillard417be3a2003-01-20 21:26:34 +00002568 if ((len != 0) && (msg[len - 1] != ':')) {
2569 /*
2570 * some callbacks only report locator information:
2571 * skip them (mimicking behaviour in error.c)
2572 */
2573 va_start(ap,msg);
2574 xmlTextReaderGenericError(ctxt,
2575 XML_PARSER_SEVERITY_VALIDITY_WARNING,
2576 xmlTextReaderBuildMessage(msg,ap));
2577 va_end(ap);
2578 }
Daniel Veillard26f70262003-01-16 22:45:08 +00002579}
2580
2581/**
2582 * xmlTextReaderSetErrorHandler:
2583 * @reader: the xmlTextReaderPtr used
2584 * @f: the callback function to call on error and warnings
2585 * @arg: a user argument to pass to the callback function
2586 *
Daniel Veillard417be3a2003-01-20 21:26:34 +00002587 * Register a callback function that will be called on error and warnings.
2588 *
Daniel Veillard26f70262003-01-16 22:45:08 +00002589 * If @f is NULL, the default error and warning handlers are restored.
2590 */
2591void
2592xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
2593 xmlTextReaderErrorFunc f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002594 void *arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00002595 if (f != NULL) {
2596 reader->ctxt->sax->error = xmlTextReaderError;
2597 reader->ctxt->vctxt.error = xmlTextReaderValidityError;
2598 reader->ctxt->sax->warning = xmlTextReaderWarning;
2599 reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
2600 reader->errorFunc = f;
2601 reader->errorFuncArg = arg;
2602 }
2603 else {
2604 /* restore defaults */
2605 reader->ctxt->sax->error = xmlParserError;
2606 reader->ctxt->vctxt.error = xmlParserValidityError;
2607 reader->ctxt->sax->warning = xmlParserWarning;
2608 reader->ctxt->vctxt.warning = xmlParserValidityWarning;
2609 reader->errorFunc = NULL;
2610 reader->errorFuncArg = NULL;
2611 }
2612}
2613
Daniel Veillard417be3a2003-01-20 21:26:34 +00002614/**
Daniel Veillardf6bad792003-04-11 19:38:54 +00002615 * xmlTextReaderIsValid:
2616 * @reader: the xmlTextReaderPtr used
2617 *
2618 * Retrieve the validity status from the parser context
2619 *
2620 * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
2621 */
2622int
2623xmlTextReaderIsValid(xmlTextReaderPtr reader) {
2624 if ((reader == NULL) || (reader->ctxt == NULL)) return(-1);
2625 return(reader->ctxt->valid);
2626}
2627
2628/**
Daniel Veillard417be3a2003-01-20 21:26:34 +00002629 * xmlTextReaderGetErrorHandler:
2630 * @reader: the xmlTextReaderPtr used
2631 * @f: the callback function or NULL is no callback has been registered
2632 * @arg: a user argument
2633 *
2634 * Retrieve the error callback function and user argument.
2635 */
Daniel Veillard26f70262003-01-16 22:45:08 +00002636void
2637xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
2638 xmlTextReaderErrorFunc *f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002639 void **arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00002640 *f = reader->errorFunc;
2641 *arg = reader->errorFuncArg;
2642}
2643
2644/************************************************************************
2645 * *
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002646 * Utilities *
2647 * *
2648 ************************************************************************/
2649/**
2650 * xmlBase64Decode:
2651 * @in: the input buffer
2652 * @inlen: the size of the input (in), the size read from it (out)
2653 * @to: the output buffer
2654 * @tolen: the size of the output (in), the size written to (out)
2655 *
2656 * Base64 decoder, reads from @in and save in @to
Daniel Veillardd4310742003-02-18 21:12:46 +00002657 * TODO: tell jody when this is actually exported
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002658 *
2659 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
2660 * 2 if there wasn't enough space on the output or -1 in case of error.
2661 */
2662static int
2663xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
2664 unsigned char *to, unsigned long *tolen) {
2665 unsigned long incur; /* current index in in[] */
2666 unsigned long inblk; /* last block index in in[] */
2667 unsigned long outcur; /* current index in out[] */
2668 unsigned long inmax; /* size of in[] */
2669 unsigned long outmax; /* size of out[] */
2670 unsigned char cur; /* the current value read from in[] */
2671 unsigned char intmp[3], outtmp[4]; /* temporary buffers for the convert */
2672 int nbintmp; /* number of byte in intmp[] */
2673 int is_ignore; /* cur should be ignored */
2674 int is_end = 0; /* the end of the base64 was found */
2675 int retval = 1;
2676 int i;
2677
2678 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
2679 return(-1);
2680
2681 incur = 0;
2682 inblk = 0;
2683 outcur = 0;
2684 inmax = *inlen;
2685 outmax = *tolen;
2686 nbintmp = 0;
2687
2688 while (1) {
2689 if (incur >= inmax)
2690 break;
2691 cur = in[incur++];
2692 is_ignore = 0;
2693 if ((cur >= 'A') && (cur <= 'Z'))
2694 cur = cur - 'A';
2695 else if ((cur >= 'a') && (cur <= 'z'))
2696 cur = cur - 'a' + 26;
2697 else if ((cur >= '0') && (cur <= '9'))
2698 cur = cur - '0' + 52;
2699 else if (cur == '+')
2700 cur = 62;
2701 else if (cur == '/')
2702 cur = 63;
2703 else if (cur == '.')
2704 cur = 0;
2705 else if (cur == '=') /*no op , end of the base64 stream */
2706 is_end = 1;
2707 else {
2708 is_ignore = 1;
2709 if (nbintmp == 0)
2710 inblk = incur;
2711 }
2712
2713 if (!is_ignore) {
2714 int nbouttmp = 3;
2715 int is_break = 0;
2716
2717 if (is_end) {
2718 if (nbintmp == 0)
2719 break;
2720 if ((nbintmp == 1) || (nbintmp == 2))
2721 nbouttmp = 1;
2722 else
2723 nbouttmp = 2;
2724 nbintmp = 3;
2725 is_break = 1;
2726 }
2727 intmp[nbintmp++] = cur;
2728 /*
2729 * if intmp is full, push the 4byte sequence as a 3 byte
2730 * sequence out
2731 */
2732 if (nbintmp == 4) {
2733 nbintmp = 0;
2734 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
2735 outtmp[1] =
2736 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
2737 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
2738 if (outcur + 3 >= outmax) {
2739 retval = 2;
2740 break;
2741 }
2742
2743 for (i = 0; i < nbouttmp; i++)
2744 to[outcur++] = outtmp[i];
2745 inblk = incur;
2746 }
2747
2748 if (is_break) {
2749 retval = 0;
2750 break;
2751 }
2752 }
2753 }
2754
2755 *tolen = outcur;
2756 *inlen = inblk;
2757 return (retval);
2758}
2759
2760/*
2761 * Test routine for the xmlBase64Decode function
2762 */
2763#if 0
2764int main(int argc, char **argv) {
2765 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
2766 char output[100];
2767 char output2[100];
2768 char output3[100];
2769 unsigned long inlen = strlen(input);
2770 unsigned long outlen = 100;
2771 int ret;
2772 unsigned long cons, tmp, tmp2, prod;
2773
2774 /*
2775 * Direct
2776 */
2777 ret = xmlBase64Decode(input, &inlen, output, &outlen);
2778
2779 output[outlen] = 0;
2780 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
2781
2782 /*
2783 * output chunking
2784 */
2785 cons = 0;
2786 prod = 0;
2787 while (cons < inlen) {
2788 tmp = 5;
2789 tmp2 = inlen - cons;
2790
2791 printf("%ld %ld\n", cons, prod);
2792 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
2793 cons += tmp2;
2794 prod += tmp;
2795 printf("%ld %ld\n", cons, prod);
2796 }
2797 output2[outlen] = 0;
2798 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
2799
2800 /*
2801 * input chunking
2802 */
2803 cons = 0;
2804 prod = 0;
2805 while (cons < inlen) {
2806 tmp = 100 - prod;
2807 tmp2 = inlen - cons;
2808 if (tmp2 > 5)
2809 tmp2 = 5;
2810
2811 printf("%ld %ld\n", cons, prod);
2812 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
2813 cons += tmp2;
2814 prod += tmp;
2815 printf("%ld %ld\n", cons, prod);
2816 }
2817 output3[outlen] = 0;
2818 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
2819 return(0);
2820
2821}
2822#endif