xmlreader.c revision ecaba49a7287212fb288403c123f8dbaf7ca6cfd
1/*
2 * xmlreader.c: implements the xmlTextReader streaming node API
3 *
4 * NOTE:
5 *   XmlTextReader.Normalization Property won't be supported, since
6 *     it makes the parser non compliant to the XML recommendation
7 *
8 * See Copyright for the status of this software.
9 *
10 * daniel@veillard.com
11 */
12
13#define IN_LIBXML
14#include "libxml.h"
15
16#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24
25#include <libxml/xmlmemory.h>
26#include <libxml/xmlIO.h>
27#include <libxml/xmlreader.h>
28
29/* #define DEBUG_CALLBACKS */
30/* #define DEBUG_READER */
31
32/**
33 * TODO:
34 *
35 * macro to flag unimplemented blocks
36 */
37#define TODO 								\
38    xmlGenericError(xmlGenericErrorContext,				\
39	    "Unimplemented block at %s:%d\n",				\
40            __FILE__, __LINE__);
41
42#ifdef DEBUG_READER
43#define DUMP_READER xmlTextReaderDebug(reader);
44#else
45#define DUMP_READER
46#endif
47
48/************************************************************************
49 *									*
50 *	The parser: maps the Text Reader API on top of the existing	*
51 *		parsing routines building a tree			*
52 *									*
53 ************************************************************************/
54
55#define XML_TEXTREADER_INPUT	1
56#define XML_TEXTREADER_CTXT	2
57
58typedef enum {
59    XML_TEXTREADER_MODE_INITIAL = 0,
60    XML_TEXTREADER_MODE_INTERACTIVE = 1,
61    XML_TEXTREADER_MODE_ERROR = 2,
62    XML_TEXTREADER_MODE_EOF =3,
63    XML_TEXTREADER_MODE_CLOSED = 4,
64    XML_TEXTREADER_MODE_READING = 5
65} xmlTextReaderMode;
66
67typedef enum {
68    XML_TEXTREADER_NONE = -1,
69    XML_TEXTREADER_START= 0,
70    XML_TEXTREADER_ELEMENT= 1,
71    XML_TEXTREADER_END= 2,
72    XML_TEXTREADER_EMPTY= 3,
73    XML_TEXTREADER_BACKTRACK= 4,
74    XML_TEXTREADER_DONE= 5
75} xmlTextReaderState;
76
77struct _xmlTextReader {
78    int				mode;	/* the parsing mode */
79    int				allocs;	/* what structure were deallocated */
80    xmlTextReaderState		state;
81    xmlParserCtxtPtr		ctxt;	/* the parser context */
82    xmlSAXHandlerPtr		sax;	/* the parser SAX callbacks */
83    xmlParserInputBufferPtr	input;	/* the input */
84    startElementSAXFunc		startElement;/* initial SAX callbacks */
85    endElementSAXFunc		endElement;  /* idem */
86    charactersSAXFunc		characters;
87    cdataBlockSAXFunc		cdataBlock;
88    unsigned int 		base;	/* base of the segment in the input */
89    unsigned int 		cur;	/* current position in the input */
90    xmlNodePtr			node;	/* current node */
91    xmlNodePtr			curnode;/* current attribute node */
92    int				depth;  /* depth of the current node */
93    xmlNodePtr			faketext;/* fake xmlNs chld */
94    int				wasempty;/* was the last node empty */
95};
96
97#ifdef DEBUG_READER
98static void
99xmlTextReaderDebug(xmlTextReaderPtr reader) {
100    if ((reader == NULL) || (reader->ctxt == NULL)) {
101	fprintf(stderr, "xmlTextReader NULL\n");
102	return;
103    }
104    fprintf(stderr, "xmlTextReader: state %d depth %d ",
105	    reader->state, reader->depth);
106    if (reader->node == NULL) {
107	fprintf(stderr, "node = NULL\n");
108    } else {
109	fprintf(stderr, "node %s\n", reader->node->name);
110    }
111    fprintf(stderr, "  input: base %d, cur %d, depth %d: ",
112	    reader->base, reader->cur, reader->ctxt->nodeNr);
113    if (reader->input->buffer == NULL) {
114	fprintf(stderr, "buffer is NULL\n");
115    } else {
116#ifdef LIBXML_DEBUG_ENABLED
117	xmlDebugDumpString(stderr,
118		&reader->input->buffer->content[reader->cur]);
119#endif
120	fprintf(stderr, "\n");
121    }
122}
123#endif
124
125/**
126 * xmlTextReaderStartElement:
127 * @ctx: the user data (XML parser context)
128 * @fullname:  The element name, including namespace prefix
129 * @atts:  An array of name/value attributes pairs, NULL terminated
130 *
131 * called when an opening tag has been processed.
132 */
133static void
134xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
135	                  const xmlChar **atts) {
136    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
137    xmlTextReaderPtr reader = ctxt->_private;
138
139#ifdef DEBUG_CALLBACKS
140    printf("xmlTextReaderStartElement(%s)\n", fullname);
141#endif
142    if ((reader != NULL) && (reader->startElement != NULL)) {
143	reader->startElement(ctx, fullname, atts);
144	if (ctxt->validate) {
145	    ctxt->valid &= xmlValidatePushElement(&ctxt->vctxt, ctxt->myDoc,
146		                                  ctxt->node, fullname);
147	}
148    }
149    reader->state = XML_TEXTREADER_ELEMENT;
150}
151
152/**
153 * xmlTextReaderEndElement:
154 * @ctx: the user data (XML parser context)
155 * @fullname:  The element name, including namespace prefix
156 *
157 * called when an ending tag has been processed.
158 */
159static void
160xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
161    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
162    xmlTextReaderPtr reader = ctxt->_private;
163
164#ifdef DEBUG_CALLBACKS
165    printf("xmlTextReaderEndElement(%s)\n", fullname);
166#endif
167    if ((reader != NULL) && (reader->endElement != NULL)) {
168	xmlNodePtr node = ctxt->node;
169
170	reader->endElement(ctx, fullname);
171
172	if (ctxt->validate) {
173	    ctxt->valid &= xmlValidatePopElement(&ctxt->vctxt, ctxt->myDoc,
174		                                 node, fullname);
175	}
176    }
177    if (reader->state == XML_TEXTREADER_ELEMENT)
178	reader->wasempty = 1;
179    else
180	reader->wasempty = 0;
181}
182
183/**
184 * xmlTextReaderCharacters:
185 * @ctx: the user data (XML parser context)
186 * @ch:  a xmlChar string
187 * @len: the number of xmlChar
188 *
189 * receiving some chars from the parser.
190 */
191static void
192xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
193{
194    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
195    xmlTextReaderPtr reader = ctxt->_private;
196
197#ifdef DEBUG_CALLBACKS
198    printf("xmlTextReaderCharacters()\n");
199#endif
200    if ((reader != NULL) && (reader->characters != NULL)) {
201	reader->characters(ctx, ch, len);
202
203	if (ctxt->validate) {
204	    ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt, ch, len);
205	}
206    }
207}
208
209/**
210 * xmlTextReaderCDataBlock:
211 * @ctx: the user data (XML parser context)
212 * @value:  The pcdata content
213 * @len:  the block length
214 *
215 * called when a pcdata block has been parsed
216 */
217static void
218xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
219{
220    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
221    xmlTextReaderPtr reader = ctxt->_private;
222
223#ifdef DEBUG_CALLBACKS
224    printf("xmlTextReaderCDataBlock()\n");
225#endif
226    if ((reader != NULL) && (reader->cdataBlock != NULL)) {
227	reader->cdataBlock(ctx, ch, len);
228
229	if (ctxt->validate) {
230	    ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt, ch, len);
231	}
232    }
233}
234
235/**
236 * xmlTextReaderPushData:
237 * @reader:  the xmlTextReaderPtr used
238 *
239 * Push data down the progressive parser until a significant callback
240 * got raised.
241 *
242 * Returns -1 in case of failure, 0 otherwise
243 */
244static int
245xmlTextReaderPushData(xmlTextReaderPtr reader) {
246    unsigned int cur = reader->cur;
247    xmlBufferPtr inbuf;
248    int val;
249    int oldstate;
250
251    if ((reader->input == NULL) || (reader->input->buffer == NULL))
252	return(-1);
253
254    oldstate = reader->state;
255    reader->state = XML_TEXTREADER_NONE;
256    inbuf = reader->input->buffer;
257    while (reader->state == XML_TEXTREADER_NONE) {
258	if (cur >= inbuf->use) {
259	    /*
260	     * Refill the buffer unless we are at the end of the stream
261	     */
262	    if (reader->mode != XML_TEXTREADER_MODE_EOF) {
263		val = xmlParserInputBufferRead(reader->input, 4096);
264		if (val <= 0) {
265		    reader->mode = XML_TEXTREADER_MODE_EOF;
266		    reader->state = oldstate;
267		    return(val);
268		}
269	    } else
270		break;
271	}
272	if ((inbuf->content[cur] == '>') || (inbuf->content[cur] == '&')) {
273	    cur = cur + 1;
274	    val = xmlParseChunk(reader->ctxt,
275		          (const char *) &inbuf->content[reader->cur],
276			  cur - reader->cur, 0);
277	    if (val != 0)
278		return(-1);
279	    reader->cur = cur;
280	    break;
281	} else {
282	    cur = cur + 1;
283
284	    /*
285	     * One may have to force a flush at some point when parsing really
286	     * large CDATA sections
287	     */
288	    if ((cur - reader->cur > 4096) && (reader->base == 0) &&
289		(reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) {
290		cur = cur + 1;
291		val = xmlParseChunk(reader->ctxt,
292			      (const char *) &inbuf->content[reader->cur],
293			      cur - reader->cur, 0);
294		if (val != 0)
295		    return(-1);
296		reader->cur = cur;
297	    }
298	}
299    }
300    /*
301     * Discard the consumed input when needed and possible
302     */
303    if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
304	if ((reader->cur >= 4096) && (reader->base == 0)) {
305	    val = xmlBufferShrink(inbuf, cur);
306	    if (val >= 0) {
307		reader->cur -= val;
308	    }
309	}
310    }
311
312    /*
313     * At the end of the stream signal that the work is done to the Push
314     * parser.
315     */
316    if (reader->mode == XML_TEXTREADER_MODE_EOF) {
317	if (reader->mode != XML_TEXTREADER_DONE) {
318	    val = xmlParseChunk(reader->ctxt,
319		    (const char *) &inbuf->content[reader->cur], 0, 1);
320	    reader->mode = XML_TEXTREADER_DONE;
321	}
322    }
323    reader->state = oldstate;
324    return(0);
325}
326
327/**
328 * xmlTextReaderRead:
329 * @reader:  the xmlTextReaderPtr used
330 *
331 *  Moves the position of the current instance to the next node in
332 *  the stream, exposing its properties.
333 *
334 *  Returns 1 if the node was read successfully, 0 if there is no more
335 *          nodes to read, or -1 in case of error
336 */
337int
338xmlTextReaderRead(xmlTextReaderPtr reader) {
339    int val, olddepth, wasempty;
340    xmlTextReaderState oldstate;
341    xmlNodePtr oldnode;
342
343    if ((reader == NULL) || (reader->ctxt == NULL))
344	return(-1);
345    if (reader->ctxt->wellFormed != 1)
346	return(-1);
347
348#ifdef DEBUG_READER
349    fprintf(stderr, "\nREAD ");
350    DUMP_READER
351#endif
352    reader->curnode = NULL;
353    if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
354	reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
355	/*
356	 * Initial state
357	 */
358	do {
359	    val = xmlTextReaderPushData(reader);
360	    if (val < 0)
361		return(-1);
362	} while ((reader->ctxt->node == NULL) &&
363		 (reader->mode != XML_TEXTREADER_MODE_EOF));
364	if (reader->ctxt->node == NULL) {
365	    if (reader->ctxt->myDoc != NULL)
366		reader->node = reader->ctxt->myDoc->children;
367	    if (reader->node == NULL)
368		return(-1);
369	} else {
370	    reader->node = reader->ctxt->node;
371	}
372	reader->depth = 1;
373	return(1);
374    }
375    oldstate = reader->state;
376    olddepth = reader->ctxt->nodeNr;
377    oldnode = reader->node;
378    wasempty = ((reader->wasempty == 1) && (reader->ctxt->node != NULL) &&
379	        (reader->ctxt->node->last == reader->node));
380
381    /*
382     * If we are not backtracking on ancestors or examined nodes,
383     * that the parser didn't finished or that we arent at the end
384     * of stream, continue processing.
385     */
386    while (((oldstate == XML_TEXTREADER_BACKTRACK) ||
387            (reader->node->children == NULL) ||
388	    (reader->node->type == XML_ENTITY_REF_NODE) ||
389	    (reader->node->type == XML_DTD_NODE)) &&
390	   (reader->node->next == NULL) &&
391	   (reader->ctxt->nodeNr == olddepth) &&
392	   (reader->ctxt->instate != XML_PARSER_EOF)) {
393	val = xmlTextReaderPushData(reader);
394	if (val < 0)
395	    return(-1);
396	if (reader->node == NULL)
397	    return(0);
398    }
399    if (oldstate != XML_TEXTREADER_BACKTRACK) {
400	if ((reader->node->children != NULL) &&
401	    (reader->node->type != XML_ENTITY_REF_NODE) &&
402	    (reader->node->type != XML_DTD_NODE)) {
403	    reader->node = reader->node->children;
404	    reader->depth++;
405	    reader->state = XML_TEXTREADER_ELEMENT;
406	    DUMP_READER
407	    return(1);
408	}
409    }
410    if (reader->node->next != NULL) {
411	if ((oldstate == XML_TEXTREADER_ELEMENT) &&
412            (reader->node->type == XML_ELEMENT_NODE) &&
413	    (wasempty == 0)) {
414	    reader->state = XML_TEXTREADER_END;
415	    DUMP_READER
416	    return(1);
417	}
418	reader->node = reader->node->next;
419	reader->state = XML_TEXTREADER_ELEMENT;
420	DUMP_READER
421	/*
422	 * Cleanup of the old node
423	 */
424	if (oldnode->type != XML_DTD_NODE) {
425	    xmlUnlinkNode(oldnode);
426	    xmlFreeNode(oldnode);
427	}
428
429	return(1);
430    }
431    if ((oldstate == XML_TEXTREADER_ELEMENT) &&
432	(reader->node->type == XML_ELEMENT_NODE)) {
433	reader->state = XML_TEXTREADER_END;
434	DUMP_READER
435	return(1);
436    }
437    reader->node = reader->node->parent;
438    if ((reader->node == NULL) ||
439	(reader->node->type == XML_DOCUMENT_NODE) ||
440#ifdef LIBXML_DOCB_ENABLED
441	(reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
442#endif
443	(reader->node->type == XML_HTML_DOCUMENT_NODE)) {
444	if (reader->mode != XML_TEXTREADER_DONE) {
445	    val = xmlParseChunk(reader->ctxt, "", 0, 1);
446	    reader->mode = XML_TEXTREADER_DONE;
447	}
448	reader->node = NULL;
449	reader->depth = 0;
450
451	/*
452	 * Cleanup of the old node
453	 */
454	if (oldnode->type != XML_DTD_NODE) {
455	    xmlUnlinkNode(oldnode);
456	    xmlFreeNode(oldnode);
457	}
458
459	return(0);
460    }
461    reader->depth--;
462    reader->state = XML_TEXTREADER_BACKTRACK;
463    DUMP_READER
464    return(1);
465}
466
467/**
468 * xmlTextReaderReadState:
469 * @reader:  the xmlTextReaderPtr used
470 *
471 * Gets the read state of the reader.
472 *
473 * Returns the state value, or -1 in case of error
474 */
475int
476xmlTextReaderReadState(xmlTextReaderPtr reader) {
477    if (reader == NULL)
478	return(-1);
479    return(reader->mode);
480}
481
482/**
483 * xmlTextReaderReadInnerXml:
484 * @reader:  the xmlTextReaderPtr used
485 *
486 * Reads the contents of the current node, including child nodes and markup.
487 *
488 * Returns a string containing the XML content, or NULL if the current node
489 *         is neither an element nor attribute, or has no child nodes. The
490 *         string must be deallocated by the caller.
491 */
492xmlChar *
493xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) {
494    TODO
495    return(NULL);
496}
497
498/**
499 * xmlTextReaderReadOuterXml:
500 * @reader:  the xmlTextReaderPtr used
501 *
502 * Reads the contents of the current node, including child nodes and markup.
503 *
504 * Returns a string containing the XML content, or NULL if the current node
505 *         is neither an element nor attribute, or has no child nodes. The
506 *         string must be deallocated by the caller.
507 */
508xmlChar *
509xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) {
510    TODO
511    return(NULL);
512}
513
514/**
515 * xmlTextReaderReadString:
516 * @reader:  the xmlTextReaderPtr used
517 *
518 * Reads the contents of an element or a text node as a string.
519 *
520 * Returns a string containing the contents of the Element or Text node,
521 *         or NULL if the reader is positioned on any other type of node.
522 *         The string must be deallocated by the caller.
523 */
524xmlChar *
525xmlTextReaderReadString(xmlTextReaderPtr reader) {
526    TODO
527    return(NULL);
528}
529
530/**
531 * xmlTextReaderReadBase64:
532 * @reader:  the xmlTextReaderPtr used
533 * @array:  a byte array to store the content.
534 * @offset:  the zero-based index into array where the method should
535 *           begin to write.
536 * @len:  the number of bytes to write.
537 *
538 * Reads and decodes the Base64 encoded contents of an element and
539 * stores the result in a byte buffer.
540 *
541 * Returns the number of bytes written to array, or zero if the current
542 *         instance is not positioned on an element or -1 in case of error.
543 */
544int
545xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
546	                int offset, int len) {
547    if ((reader == NULL) || (reader->ctxt == NULL))
548	return(-1);
549    if (reader->ctxt->wellFormed != 1)
550	return(-1);
551
552    if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
553	return(0);
554    TODO
555    return(0);
556}
557
558/**
559 * xmlTextReaderReadBinHex:
560 * @reader:  the xmlTextReaderPtr used
561 * @array:  a byte array to store the content.
562 * @offset:  the zero-based index into array where the method should
563 *           begin to write.
564 * @len:  the number of bytes to write.
565 *
566 * Reads and decodes the BinHex encoded contents of an element and
567 * stores the result in a byte buffer.
568 *
569 * Returns the number of bytes written to array, or zero if the current
570 *         instance is not positioned on an element or -1 in case of error.
571 */
572int
573xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
574	                int offset, int len) {
575    if ((reader == NULL) || (reader->ctxt == NULL))
576	return(-1);
577    if (reader->ctxt->wellFormed != 1)
578	return(-1);
579
580    if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
581	return(0);
582    TODO
583    return(0);
584}
585
586/************************************************************************
587 *									*
588 *			Constructor and destructors			*
589 *									*
590 ************************************************************************/
591/**
592 * xmlNewTextReader:
593 * @input: the xmlParserInputBufferPtr used to read data
594 * @URI: the URI information for the source if available
595 *
596 * Create an xmlTextReader structure fed with @input
597 *
598 * Returns the new xmlTextReaderPtr or NULL in case of error
599 */
600xmlTextReaderPtr
601xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
602    xmlTextReaderPtr ret;
603    int val;
604
605    if (input == NULL)
606	return(NULL);
607    ret = xmlMalloc(sizeof(xmlTextReader));
608    if (ret == NULL) {
609        xmlGenericError(xmlGenericErrorContext,
610		"xmlNewTextReader : malloc failed\n");
611	return(NULL);
612    }
613    memset(ret, 0, sizeof(xmlTextReader));
614    ret->input = input;
615    ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
616    if (ret->sax == NULL) {
617	xmlFree(ret);
618        xmlGenericError(xmlGenericErrorContext,
619		"xmlNewTextReader : malloc failed\n");
620	return(NULL);
621    }
622    memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
623    ret->startElement = ret->sax->startElement;
624    ret->sax->startElement = xmlTextReaderStartElement;
625    ret->endElement = ret->sax->endElement;
626    ret->sax->endElement = xmlTextReaderEndElement;
627    ret->characters = ret->sax->characters;
628    ret->sax->characters = xmlTextReaderCharacters;
629    ret->cdataBlock = ret->sax->cdataBlock;
630    ret->sax->cdataBlock = xmlTextReaderCDataBlock;
631
632    ret->mode = XML_TEXTREADER_MODE_INITIAL;
633    ret->node = NULL;
634    ret->curnode = NULL;
635    val = xmlParserInputBufferRead(input, 4);
636    if (val >= 4) {
637	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
638			(const char *) ret->input->buffer->content, 4, URI);
639	ret->base = 0;
640	ret->cur = 4;
641    } else {
642	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
643	ret->base = 0;
644	ret->cur = 0;
645    }
646    ret->ctxt->_private = ret;
647    ret->ctxt->linenumbers = 1;
648    ret->allocs = XML_TEXTREADER_CTXT;
649    return(ret);
650
651}
652
653/**
654 * xmlNewTextReaderFilename:
655 * @URI: the URI of the resource to process
656 *
657 * Create an xmlTextReader structure fed with the resource at @URI
658 *
659 * Returns the new xmlTextReaderPtr or NULL in case of error
660 */
661xmlTextReaderPtr
662xmlNewTextReaderFilename(const char *URI) {
663    xmlParserInputBufferPtr input;
664    xmlTextReaderPtr ret;
665    char *directory = NULL;
666
667    input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
668    if (input == NULL)
669	return(NULL);
670    ret = xmlNewTextReader(input, URI);
671    if (ret == NULL) {
672	xmlFreeParserInputBuffer(input);
673	return(NULL);
674    }
675    ret->allocs |= XML_TEXTREADER_INPUT;
676    if (ret->ctxt->directory == NULL)
677        directory = xmlParserGetDirectory(URI);
678    if ((ret->ctxt->directory == NULL) && (directory != NULL))
679        ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
680    if (directory != NULL)
681	xmlFree(directory);
682    return(ret);
683}
684
685/**
686 * xmlFreeTextReader:
687 * @reader:  the xmlTextReaderPtr
688 *
689 * Deallocate all the resources associated to the reader
690 */
691void
692xmlFreeTextReader(xmlTextReaderPtr reader) {
693    if (reader == NULL)
694	return;
695    if (reader->ctxt != NULL) {
696	if (reader->ctxt->myDoc != NULL) {
697	    xmlFreeDoc(reader->ctxt->myDoc);
698	    reader->ctxt->myDoc = NULL;
699	}
700	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
701	    (reader->ctxt->vctxt.vstateMax > 0)){
702	    xmlFree(reader->ctxt->vctxt.vstateTab);
703	    reader->ctxt->vctxt.vstateTab = 0;
704	    reader->ctxt->vctxt.vstateMax = 0;
705	}
706	if (reader->allocs & XML_TEXTREADER_CTXT)
707	    xmlFreeParserCtxt(reader->ctxt);
708    }
709    if (reader->sax != NULL)
710	xmlFree(reader->sax);
711    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT))
712	xmlFreeParserInputBuffer(reader->input);
713    if (reader->faketext != NULL) {
714	xmlFreeNode(reader->faketext);
715    }
716    xmlFree(reader);
717}
718
719/************************************************************************
720 *									*
721 *			Methods for XmlTextReader			*
722 *									*
723 ************************************************************************/
724/**
725 * xmlTextReaderClose:
726 * @reader:  the xmlTextReaderPtr used
727 *
728 * This method releases any resources allocated by the current instance
729 * changes the state to Closed and close any underlying input.
730 *
731 * Returns 0 or -1 in case of error
732 */
733int
734xmlTextReaderClose(xmlTextReaderPtr reader) {
735    if (reader == NULL)
736	return(-1);
737    reader->node = NULL;
738    reader->curnode = NULL;
739    reader->mode = XML_TEXTREADER_MODE_CLOSED;
740    if (reader->ctxt != NULL) {
741	if (reader->ctxt->myDoc != NULL) {
742	    xmlFreeDoc(reader->ctxt->myDoc);
743	    reader->ctxt->myDoc = NULL;
744	}
745	if (reader->allocs & XML_TEXTREADER_CTXT) {
746	    xmlFreeParserCtxt(reader->ctxt);
747	    reader->allocs -= XML_TEXTREADER_CTXT;
748	}
749    }
750    if (reader->sax != NULL) {
751        xmlFree(reader->sax);
752	reader->sax = NULL;
753    }
754    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT)) {
755	xmlFreeParserInputBuffer(reader->input);
756	reader->allocs -= XML_TEXTREADER_INPUT;
757    }
758    return(0);
759}
760
761/**
762 * xmlTextReaderGetAttributeNo:
763 * @reader:  the xmlTextReaderPtr used
764 * @no: the zero-based index of the attribute relative to the containing element
765 *
766 * Provides the value of the attribute with the specified index relative
767 * to the containing element.
768 *
769 * Returns a string containing the value of the specified attribute, or NULL
770 *    in case of error. The string must be deallocated by the caller.
771 */
772xmlChar *
773xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
774    xmlChar *ret;
775    int i;
776    xmlAttrPtr cur;
777    xmlNsPtr ns;
778
779    if (reader == NULL)
780	return(NULL);
781    if (reader->node == NULL)
782	return(NULL);
783    if (reader->curnode != NULL)
784	return(NULL);
785    /* TODO: handle the xmlDecl */
786    if (reader->node->type != XML_ELEMENT_NODE)
787	return(NULL);
788
789    ns = reader->node->nsDef;
790    for (i = 0;(i < no) && (ns != NULL);i++) {
791	ns = ns->next;
792    }
793    if (ns != NULL)
794	return(xmlStrdup(ns->href));
795
796    cur = reader->node->properties;
797    if (cur == NULL)
798	return(NULL);
799    for (;i < no;i++) {
800	cur = cur->next;
801	if (cur == NULL)
802	    return(NULL);
803    }
804    /* TODO walk the DTD if present */
805
806    ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
807    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
808    return(ret);
809}
810
811/**
812 * xmlTextReaderGetAttribute:
813 * @reader:  the xmlTextReaderPtr used
814 * @name: the qualified name of the attribute.
815 *
816 * Provides the value of the attribute with the specified qualified name.
817 *
818 * Returns a string containing the value of the specified attribute, or NULL
819 *    in case of error. The string must be deallocated by the caller.
820 */
821xmlChar *
822xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
823    xmlChar *prefix = NULL;
824    xmlChar *localname;
825    xmlNsPtr ns;
826    xmlChar *ret = NULL;
827
828    if ((reader == NULL) || (name == NULL))
829	return(NULL);
830    if (reader->node == NULL)
831	return(NULL);
832    if (reader->curnode != NULL)
833	return(NULL);
834
835    /* TODO: handle the xmlDecl */
836    if (reader->node->type != XML_ELEMENT_NODE)
837	return(NULL);
838
839    localname = xmlSplitQName2(name, &prefix);
840    if (localname == NULL)
841	return(xmlGetProp(reader->node, name));
842
843    ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
844    if (ns != NULL)
845        ret = xmlGetNsProp(reader->node, localname, ns->href);
846
847    if (localname != NULL)
848        xmlFree(localname);
849    if (prefix != NULL)
850        xmlFree(prefix);
851    return(ret);
852}
853
854
855/**
856 * xmlTextReaderGetAttributeNs:
857 * @reader:  the xmlTextReaderPtr used
858 * @localName: the local name of the attribute.
859 * @namespaceURI: the namespace URI of the attribute.
860 *
861 * Provides the value of the specified attribute
862 *
863 * Returns a string containing the value of the specified attribute, or NULL
864 *    in case of error. The string must be deallocated by the caller.
865 */
866xmlChar *
867xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
868			    const xmlChar *namespaceURI) {
869    if ((reader == NULL) || (localName == NULL))
870	return(NULL);
871    if (reader->node == NULL)
872	return(NULL);
873    if (reader->curnode != NULL)
874	return(NULL);
875
876    /* TODO: handle the xmlDecl */
877    if (reader->node->type != XML_ELEMENT_NODE)
878	return(NULL);
879
880    return(xmlGetNsProp(reader->node, localName, namespaceURI));
881}
882
883/**
884 * xmlTextReaderGetRemainder:
885 * @reader:  the xmlTextReaderPtr used
886 *
887 * Method to get the remainder of the buffered XML. this method stops the
888 * parser, set its state to End Of File and return the input stream with
889 * what is left that the parser did not use.
890 *
891 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
892 *    in case of error.
893 */
894xmlParserInputBufferPtr
895xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
896    xmlParserInputBufferPtr ret = NULL;
897
898    if (reader == NULL)
899	return(NULL);
900    if (reader->node == NULL)
901	return(NULL);
902
903    reader->node = NULL;
904    reader->curnode = NULL;
905    reader->mode = XML_TEXTREADER_MODE_EOF;
906    if (reader->ctxt != NULL) {
907	if (reader->ctxt->myDoc != NULL) {
908	    xmlFreeDoc(reader->ctxt->myDoc);
909	    reader->ctxt->myDoc = NULL;
910	}
911	if (reader->allocs & XML_TEXTREADER_CTXT) {
912	    xmlFreeParserCtxt(reader->ctxt);
913	    reader->allocs -= XML_TEXTREADER_CTXT;
914	}
915    }
916    if (reader->sax != NULL) {
917        xmlFree(reader->sax);
918	reader->sax = NULL;
919    }
920    if (reader->allocs & XML_TEXTREADER_INPUT) {
921	ret = reader->input;
922	reader->allocs -= XML_TEXTREADER_INPUT;
923    } else {
924	/*
925	 * Hum, one may need to duplicate the data structure because
926	 * without reference counting the input may be freed twice:
927	 *   - by the layer which allocated it.
928	 *   - by the layer to which would have been returned to.
929	 */
930	TODO
931	return(NULL);
932    }
933    return(ret);
934}
935
936/**
937 * xmlTextReaderLookupNamespace:
938 * @reader:  the xmlTextReaderPtr used
939 * @prefix: the prefix whose namespace URI is to be resolved. To return
940 *          the default namespace, specify NULL
941 *
942 * Resolves a namespace prefix in the scope of the current element.
943 *
944 * Returns a string containing the namespace URI to which the prefix maps
945 *    or NULL in case of error. The string must be deallocated by the caller.
946 */
947xmlChar *
948xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
949    xmlNsPtr ns;
950
951    if (reader == NULL)
952	return(NULL);
953    if (reader->node == NULL)
954	return(NULL);
955
956    ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
957    if (ns == NULL)
958	return(NULL);
959    return(xmlStrdup(ns->href));
960}
961
962/**
963 * xmlTextReaderMoveToAttributeNo:
964 * @reader:  the xmlTextReaderPtr used
965 * @no: the zero-based index of the attribute relative to the containing
966 *      element.
967 *
968 * Moves the position of the current instance to the attribute with
969 * the specified index relative to the containing element.
970 *
971 * Returns 1 in case of success, -1 in case of error, 0 if not found
972 */
973int
974xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
975    int i;
976    xmlAttrPtr cur;
977    xmlNsPtr ns;
978
979    if (reader == NULL)
980	return(-1);
981    if (reader->node == NULL)
982	return(-1);
983    /* TODO: handle the xmlDecl */
984    if (reader->node->type != XML_ELEMENT_NODE)
985	return(-1);
986
987    reader->curnode = NULL;
988
989    ns = reader->node->nsDef;
990    for (i = 0;(i < no) && (ns != NULL);i++) {
991	ns = ns->next;
992    }
993    if (ns != NULL) {
994	reader->curnode = (xmlNodePtr) ns;
995	return(1);
996    }
997
998    cur = reader->node->properties;
999    if (cur == NULL)
1000	return(0);
1001    for (;i < no;i++) {
1002	cur = cur->next;
1003	if (cur == NULL)
1004	    return(0);
1005    }
1006    /* TODO walk the DTD if present */
1007
1008    reader->curnode = (xmlNodePtr) cur;
1009    return(1);
1010}
1011
1012/**
1013 * xmlTextReaderMoveToAttribute:
1014 * @reader:  the xmlTextReaderPtr used
1015 * @name: the qualified name of the attribute.
1016 *
1017 * Moves the position of the current instance to the attribute with
1018 * the specified qualified name.
1019 *
1020 * Returns 1 in case of success, -1 in case of error, 0 if not found
1021 */
1022int
1023xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1024    xmlChar *prefix = NULL;
1025    xmlChar *localname;
1026    xmlNsPtr ns;
1027    xmlAttrPtr prop;
1028
1029    if ((reader == NULL) || (name == NULL))
1030	return(-1);
1031    if (reader->node == NULL)
1032	return(-1);
1033
1034    /* TODO: handle the xmlDecl */
1035    if (reader->node->type != XML_ELEMENT_NODE)
1036	return(0);
1037
1038    localname = xmlSplitQName2(name, &prefix);
1039    if (localname == NULL) {
1040	/*
1041	 * Namespace default decl
1042	 */
1043	if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1044	    ns = reader->node->nsDef;
1045	    while (ns != NULL) {
1046		if (ns->prefix == NULL) {
1047		    reader->curnode = (xmlNodePtr) ns;
1048		    return(1);
1049		}
1050		ns = ns->next;
1051	    }
1052	    return(0);
1053	}
1054
1055	prop = reader->node->properties;
1056	while (prop != NULL) {
1057	    /*
1058	     * One need to have
1059	     *   - same attribute names
1060	     *   - and the attribute carrying that namespace
1061	     */
1062	    if ((xmlStrEqual(prop->name, name)) &&
1063		((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
1064		reader->curnode = (xmlNodePtr) prop;
1065		return(1);
1066	    }
1067	    prop = prop->next;
1068	}
1069	return(0);
1070    }
1071
1072    /*
1073     * Namespace default decl
1074     */
1075    if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
1076	ns = reader->node->nsDef;
1077	while (ns != NULL) {
1078	    if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
1079		reader->curnode = (xmlNodePtr) ns;
1080		goto found;
1081	    }
1082	    ns = ns->next;
1083	}
1084	goto not_found;
1085    }
1086    prop = reader->node->properties;
1087    while (prop != NULL) {
1088	/*
1089	 * One need to have
1090	 *   - same attribute names
1091	 *   - and the attribute carrying that namespace
1092	 */
1093	if ((xmlStrEqual(prop->name, localname)) &&
1094	    (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
1095	    reader->curnode = (xmlNodePtr) prop;
1096	    goto found;
1097	}
1098	prop = prop->next;
1099    }
1100not_found:
1101    if (localname != NULL)
1102        xmlFree(localname);
1103    if (prefix != NULL)
1104        xmlFree(prefix);
1105    return(0);
1106
1107found:
1108    if (localname != NULL)
1109        xmlFree(localname);
1110    if (prefix != NULL)
1111        xmlFree(prefix);
1112    return(1);
1113}
1114
1115/**
1116 * xmlTextReaderMoveToAttributeNs:
1117 * @reader:  the xmlTextReaderPtr used
1118 * @localName:  the local name of the attribute.
1119 * @namespaceURI:  the namespace URI of the attribute.
1120 *
1121 * Moves the position of the current instance to the attribute with the
1122 * specified local name and namespace URI.
1123 *
1124 * Returns 1 in case of success, -1 in case of error, 0 if not found
1125 */
1126int
1127xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1128	const xmlChar *localName, const xmlChar *namespaceURI) {
1129    xmlAttrPtr prop;
1130    xmlNodePtr node;
1131
1132    if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1133	return(-1);
1134    if (reader->node == NULL)
1135	return(-1);
1136    if (reader->node->type != XML_ELEMENT_NODE)
1137	return(0);
1138    node = reader->node;
1139
1140    /*
1141     * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1142     * namespace name associated to "xmlns"
1143     */
1144    prop = node->properties;
1145    while (prop != NULL) {
1146	/*
1147	 * One need to have
1148	 *   - same attribute names
1149	 *   - and the attribute carrying that namespace
1150	 */
1151        if (xmlStrEqual(prop->name, localName) &&
1152	    ((prop->ns != NULL) &&
1153	     (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1154	    reader->curnode = (xmlNodePtr) prop;
1155	    return(1);
1156        }
1157	prop = prop->next;
1158    }
1159    return(0);
1160}
1161
1162/**
1163 * xmlTextReaderMoveToFirstAttribute:
1164 * @reader:  the xmlTextReaderPtr used
1165 *
1166 * Moves the position of the current instance to the first attribute
1167 * associated with the current node.
1168 *
1169 * Returns 1 in case of success, -1 in case of error, 0 if not found
1170 */
1171int
1172xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1173    if (reader == NULL)
1174	return(-1);
1175    if (reader->node == NULL)
1176	return(-1);
1177    if (reader->node->type != XML_ELEMENT_NODE)
1178	return(0);
1179
1180    if (reader->node->nsDef != NULL) {
1181	reader->curnode = (xmlNodePtr) reader->node->nsDef;
1182	return(1);
1183    }
1184    if (reader->node->properties != NULL) {
1185	reader->curnode = (xmlNodePtr) reader->node->properties;
1186	return(1);
1187    }
1188    return(0);
1189}
1190
1191/**
1192 * xmlTextReaderMoveToNextAttribute:
1193 * @reader:  the xmlTextReaderPtr used
1194 *
1195 * Moves the position of the current instance to the next attribute
1196 * associated with the current node.
1197 *
1198 * Returns 1 in case of success, -1 in case of error, 0 if not found
1199 */
1200int
1201xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1202    if (reader == NULL)
1203	return(-1);
1204    if (reader->node == NULL)
1205	return(-1);
1206    if (reader->node->type != XML_ELEMENT_NODE)
1207	return(0);
1208    if (reader->curnode == NULL)
1209	return(xmlTextReaderMoveToFirstAttribute(reader));
1210
1211    if (reader->curnode->type == XML_NAMESPACE_DECL) {
1212	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1213	if (ns->next != NULL) {
1214	    reader->curnode = (xmlNodePtr) ns->next;
1215	    return(1);
1216	}
1217	if (reader->node->properties != NULL) {
1218	    reader->curnode = (xmlNodePtr) reader->node->properties;
1219	    return(1);
1220	}
1221	return(0);
1222    } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1223	       (reader->curnode->next != NULL)) {
1224	reader->curnode = reader->curnode->next;
1225	return(1);
1226    }
1227    return(0);
1228}
1229
1230/**
1231 * xmlTextReaderMoveToElement:
1232 * @reader:  the xmlTextReaderPtr used
1233 *
1234 * Moves the position of the current instance to the node that
1235 * contains the current Attribute  node.
1236 *
1237 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1238 */
1239int
1240xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
1241    if (reader == NULL)
1242	return(-1);
1243    if (reader->node == NULL)
1244	return(-1);
1245    if (reader->node->type != XML_ELEMENT_NODE)
1246	return(0);
1247    if (reader->curnode != NULL) {
1248	reader->curnode = NULL;
1249	return(1);
1250    }
1251    return(0);
1252}
1253
1254/**
1255 * xmlTextReaderReadAttributeValue:
1256 * @reader:  the xmlTextReaderPtr used
1257 *
1258 * Parses an attribute value into one or more Text and EntityReference nodes.
1259 *
1260 * Returns 1 in case of success, 0 if the reader was not positionned on an
1261 *         ttribute node or all the attribute values have been read, or -1
1262 *         in case of error.
1263 */
1264int
1265xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1266    if (reader == NULL)
1267	return(-1);
1268    if (reader->node == NULL)
1269	return(-1);
1270    if (reader->curnode == NULL)
1271	return(0);
1272    if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1273	if (reader->curnode->children == NULL)
1274	    return(0);
1275	reader->curnode = reader->curnode->children;
1276    } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1277	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1278
1279	if (reader->faketext == NULL) {
1280	    reader->faketext = xmlNewDocText(reader->node->doc,
1281		                             ns->href);
1282	} else {
1283            if (reader->faketext->content != NULL)
1284		xmlFree(reader->faketext->content);
1285	    reader->faketext->content = xmlStrdup(ns->href);
1286	}
1287	reader->curnode = reader->faketext;
1288    } else {
1289	if (reader->curnode->next == NULL)
1290	    return(0);
1291	reader->curnode = reader->curnode->next;
1292    }
1293    return(1);
1294}
1295
1296/************************************************************************
1297 *									*
1298 *			Acces API to the current node			*
1299 *									*
1300 ************************************************************************/
1301/**
1302 * xmlTextReaderAttributeCount:
1303 * @reader:  the xmlTextReaderPtr used
1304 *
1305 * Provides the number of attributes of the current node
1306 *
1307 * Returns 0 i no attributes, -1 in case of error or the attribute count
1308 */
1309int
1310xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1311    int ret;
1312    xmlAttrPtr attr;
1313    xmlNsPtr ns;
1314    xmlNodePtr node;
1315
1316    if (reader == NULL)
1317	return(-1);
1318    if (reader->node == NULL)
1319	return(0);
1320
1321    if (reader->curnode != NULL)
1322	node = reader->curnode;
1323    else
1324	node = reader->node;
1325
1326    if (node->type != XML_ELEMENT_NODE)
1327	return(0);
1328    if ((reader->state == XML_TEXTREADER_END) ||
1329	(reader->state == XML_TEXTREADER_BACKTRACK))
1330	return(0);
1331    ret = 0;
1332    attr = node->properties;
1333    while (attr != NULL) {
1334	ret++;
1335	attr = attr->next;
1336    }
1337    ns = node->nsDef;
1338    while (ns != NULL) {
1339	ret++;
1340	ns = ns->next;
1341    }
1342    return(ret);
1343}
1344
1345/**
1346 * xmlTextReaderNodeType:
1347 * @reader:  the xmlTextReaderPtr used
1348 *
1349 * Get the node type of the current node
1350 * Reference:
1351 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1352 *
1353 * Returns the xmlNodeType of the current node or -1 in case of error
1354 */
1355int
1356xmlTextReaderNodeType(xmlTextReaderPtr reader) {
1357    xmlNodePtr node;
1358    if (reader == NULL)
1359	return(-1);
1360    if (reader->node == NULL)
1361	return(0);
1362    if (reader->curnode != NULL)
1363	node = reader->curnode;
1364    else
1365	node = reader->node;
1366    switch (node->type) {
1367        case XML_ELEMENT_NODE:
1368	    if ((reader->state == XML_TEXTREADER_END) ||
1369		(reader->state == XML_TEXTREADER_BACKTRACK))
1370		return(15);
1371	    return(1);
1372        case XML_NAMESPACE_DECL:
1373        case XML_ATTRIBUTE_NODE:
1374	    return(2);
1375        case XML_TEXT_NODE:
1376	    return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1377        case XML_CDATA_SECTION_NODE:
1378	    return(4);
1379        case XML_ENTITY_REF_NODE:
1380	    return(5);
1381        case XML_ENTITY_NODE:
1382	    return(6);
1383        case XML_PI_NODE:
1384	    return(7);
1385        case XML_COMMENT_NODE:
1386	    return(8);
1387        case XML_DOCUMENT_NODE:
1388        case XML_HTML_DOCUMENT_NODE:
1389#ifdef LIBXML_DOCB_ENABLED
1390        case XML_DOCB_DOCUMENT_NODE:
1391#endif
1392	    return(9);
1393        case XML_DOCUMENT_FRAG_NODE:
1394	    return(11);
1395        case XML_NOTATION_NODE:
1396	    return(12);
1397        case XML_DOCUMENT_TYPE_NODE:
1398        case XML_DTD_NODE:
1399	    return(10);
1400
1401        case XML_ELEMENT_DECL:
1402        case XML_ATTRIBUTE_DECL:
1403        case XML_ENTITY_DECL:
1404        case XML_XINCLUDE_START:
1405        case XML_XINCLUDE_END:
1406	    return(0);
1407    }
1408    return(-1);
1409}
1410
1411/**
1412 * xmlTextReaderIsEmptyElement:
1413 * @reader:  the xmlTextReaderPtr used
1414 *
1415 * Check if the current node is empty
1416 *
1417 * Returns 1 if empty, 0 if not and -1 in case of error
1418 */
1419int
1420xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1421    if ((reader == NULL) || (reader->node == NULL))
1422	return(-1);
1423    if (reader->node->type != XML_ELEMENT_NODE)
1424	return(0);
1425    if (reader->node->children != NULL)
1426	return(0);
1427    if (reader->node != reader->ctxt->node)
1428	return(1);
1429    if ((reader->ctxt->node != NULL) &&
1430	(reader->node == reader->ctxt->node->last) &&
1431	(reader->wasempty == 1))
1432	return(1);
1433    return(0);
1434}
1435
1436/**
1437 * xmlTextReaderLocalName:
1438 * @reader:  the xmlTextReaderPtr used
1439 *
1440 * The local name of the node.
1441 *
1442 * Returns the local name or NULL if not available
1443 */
1444xmlChar *
1445xmlTextReaderLocalName(xmlTextReaderPtr reader) {
1446    xmlNodePtr node;
1447    if ((reader == NULL) || (reader->node == NULL))
1448	return(NULL);
1449    if (reader->curnode != NULL)
1450	node = reader->curnode;
1451    else
1452	node = reader->node;
1453    if (node->type == XML_NAMESPACE_DECL) {
1454	xmlNsPtr ns = (xmlNsPtr) node;
1455	if (ns->prefix == NULL)
1456	    return(xmlStrdup(BAD_CAST "xmlns"));
1457	else
1458	    return(xmlStrdup(ns->prefix));
1459    }
1460    if ((node->type != XML_ELEMENT_NODE) &&
1461	(node->type != XML_ATTRIBUTE_NODE))
1462	return(xmlTextReaderName(reader));
1463    return(xmlStrdup(node->name));
1464}
1465
1466/**
1467 * xmlTextReaderName:
1468 * @reader:  the xmlTextReaderPtr used
1469 *
1470 * The qualified name of the node, equal to Prefix :LocalName.
1471 *
1472 * Returns the local name or NULL if not available
1473 */
1474xmlChar *
1475xmlTextReaderName(xmlTextReaderPtr reader) {
1476    xmlNodePtr node;
1477    xmlChar *ret;
1478
1479    if ((reader == NULL) || (reader->node == NULL))
1480	return(NULL);
1481    if (reader->curnode != NULL)
1482	node = reader->curnode;
1483    else
1484	node = reader->node;
1485    switch (node->type) {
1486        case XML_ELEMENT_NODE:
1487        case XML_ATTRIBUTE_NODE:
1488	    if ((node->ns == NULL) ||
1489		(node->ns->prefix == NULL))
1490		return(xmlStrdup(node->name));
1491
1492	    ret = xmlStrdup(node->ns->prefix);
1493	    ret = xmlStrcat(ret, BAD_CAST ":");
1494	    ret = xmlStrcat(ret, node->name);
1495	    return(ret);
1496        case XML_TEXT_NODE:
1497	    return(xmlStrdup(BAD_CAST "#text"));
1498        case XML_CDATA_SECTION_NODE:
1499	    return(xmlStrdup(BAD_CAST "#cdata-section"));
1500        case XML_ENTITY_NODE:
1501        case XML_ENTITY_REF_NODE:
1502	    return(xmlStrdup(node->name));
1503        case XML_PI_NODE:
1504	    return(xmlStrdup(node->name));
1505        case XML_COMMENT_NODE:
1506	    return(xmlStrdup(BAD_CAST "#comment"));
1507        case XML_DOCUMENT_NODE:
1508        case XML_HTML_DOCUMENT_NODE:
1509#ifdef LIBXML_DOCB_ENABLED
1510        case XML_DOCB_DOCUMENT_NODE:
1511#endif
1512	    return(xmlStrdup(BAD_CAST "#document"));
1513        case XML_DOCUMENT_FRAG_NODE:
1514	    return(xmlStrdup(BAD_CAST "#document-fragment"));
1515        case XML_NOTATION_NODE:
1516	    return(xmlStrdup(node->name));
1517        case XML_DOCUMENT_TYPE_NODE:
1518        case XML_DTD_NODE:
1519	    return(xmlStrdup(node->name));
1520        case XML_NAMESPACE_DECL: {
1521	    xmlNsPtr ns = (xmlNsPtr) node;
1522
1523	    ret = xmlStrdup(BAD_CAST "xmlns");
1524	    if (ns->prefix == NULL)
1525		return(ret);
1526	    ret = xmlStrcat(ret, BAD_CAST ":");
1527	    ret = xmlStrcat(ret, ns->prefix);
1528	    return(ret);
1529	}
1530
1531        case XML_ELEMENT_DECL:
1532        case XML_ATTRIBUTE_DECL:
1533        case XML_ENTITY_DECL:
1534        case XML_XINCLUDE_START:
1535        case XML_XINCLUDE_END:
1536	    return(NULL);
1537    }
1538    return(NULL);
1539}
1540
1541/**
1542 * xmlTextReaderPrefix:
1543 * @reader:  the xmlTextReaderPtr used
1544 *
1545 * A shorthand reference to the namespace associated with the node.
1546 *
1547 * Returns the prefix or NULL if not available
1548 */
1549xmlChar *
1550xmlTextReaderPrefix(xmlTextReaderPtr reader) {
1551    xmlNodePtr node;
1552    if ((reader == NULL) || (reader->node == NULL))
1553	return(NULL);
1554    if (reader->curnode != NULL)
1555	node = reader->curnode;
1556    else
1557	node = reader->node;
1558    if (node->type == XML_NAMESPACE_DECL) {
1559	xmlNsPtr ns = (xmlNsPtr) node;
1560	if (ns->prefix == NULL)
1561	    return(NULL);
1562	return(xmlStrdup(BAD_CAST "xmlns"));
1563    }
1564    if ((node->type != XML_ELEMENT_NODE) &&
1565	(node->type != XML_ATTRIBUTE_NODE))
1566	return(NULL);
1567    if ((node->ns != NULL) || (node->ns->prefix != NULL))
1568	return(xmlStrdup(node->ns->prefix));
1569    return(NULL);
1570}
1571
1572/**
1573 * xmlTextReaderNamespaceUri:
1574 * @reader:  the xmlTextReaderPtr used
1575 *
1576 * The URI defining the namespace associated with the node.
1577 *
1578 * Returns the namespace URI or NULL if not available
1579 */
1580xmlChar *
1581xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
1582    xmlNodePtr node;
1583    if ((reader == NULL) || (reader->node == NULL))
1584	return(NULL);
1585    if (reader->curnode != NULL)
1586	node = reader->curnode;
1587    else
1588	node = reader->node;
1589    if (node->type == XML_NAMESPACE_DECL)
1590	return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
1591    if ((node->type != XML_ELEMENT_NODE) &&
1592	(node->type != XML_ATTRIBUTE_NODE))
1593	return(NULL);
1594    if (node->ns != NULL)
1595	return(xmlStrdup(node->ns->href));
1596    return(NULL);
1597}
1598
1599/**
1600 * xmlTextReaderBaseUri:
1601 * @reader:  the xmlTextReaderPtr used
1602 *
1603 * The base URI of the node.
1604 *
1605 * Returns the base URI or NULL if not available
1606 */
1607xmlChar *
1608xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
1609    if ((reader == NULL) || (reader->node == NULL))
1610	return(NULL);
1611    return(xmlNodeGetBase(NULL, reader->node));
1612}
1613
1614/**
1615 * xmlTextReaderDepth:
1616 * @reader:  the xmlTextReaderPtr used
1617 *
1618 * The depth of the node in the tree.
1619 *
1620 * Returns the depth or -1 in case of error
1621 */
1622int
1623xmlTextReaderDepth(xmlTextReaderPtr reader) {
1624    if (reader == NULL)
1625	return(-1);
1626    if (reader->node == NULL)
1627	return(0);
1628
1629    if (reader->curnode != NULL) {
1630	if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
1631	    (reader->curnode->type == XML_NAMESPACE_DECL))
1632	    return(reader->depth + 1);
1633	return(reader->depth + 2);
1634    }
1635    return(reader->depth);
1636}
1637
1638/**
1639 * xmlTextReaderHasAttributes:
1640 * @reader:  the xmlTextReaderPtr used
1641 *
1642 * Whether the node has attributes.
1643 *
1644 * Returns 1 if true, 0 if false, and -1 in case or error
1645 */
1646int
1647xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
1648    xmlNodePtr node;
1649    if (reader == NULL)
1650	return(-1);
1651    if (reader->node == NULL)
1652	return(0);
1653    if (reader->curnode != NULL)
1654	node = reader->curnode;
1655    else
1656	node = reader->node;
1657
1658    if ((node->type == XML_ELEMENT_NODE) &&
1659	(node->properties != NULL))
1660	return(1);
1661    /* TODO: handle the xmlDecl */
1662    return(0);
1663}
1664
1665/**
1666 * xmlTextReaderHasValue:
1667 * @reader:  the xmlTextReaderPtr used
1668 *
1669 * Whether the node can have a text value.
1670 *
1671 * Returns 1 if true, 0 if false, and -1 in case or error
1672 */
1673int
1674xmlTextReaderHasValue(xmlTextReaderPtr reader) {
1675    xmlNodePtr node;
1676    if (reader == NULL)
1677	return(-1);
1678    if (reader->node == NULL)
1679	return(0);
1680    if (reader->curnode != NULL)
1681	node = reader->curnode;
1682    else
1683	node = reader->node;
1684
1685    switch (node->type) {
1686        case XML_ATTRIBUTE_NODE:
1687        case XML_TEXT_NODE:
1688        case XML_CDATA_SECTION_NODE:
1689        case XML_PI_NODE:
1690        case XML_COMMENT_NODE:
1691	    return(1);
1692	default:
1693	    return(0);
1694    }
1695    return(0);
1696}
1697
1698/**
1699 * xmlTextReaderValue:
1700 * @reader:  the xmlTextReaderPtr used
1701 *
1702 * Provides the text value of the node if present
1703 *
1704 * Returns the string or NULL if not available. The retsult must be deallocated
1705 *     with xmlFree()
1706 */
1707xmlChar *
1708xmlTextReaderValue(xmlTextReaderPtr reader) {
1709    xmlNodePtr node;
1710    if (reader == NULL)
1711	return(NULL);
1712    if (reader->node == NULL)
1713	return(NULL);
1714    if (reader->curnode != NULL)
1715	node = reader->curnode;
1716    else
1717	node = reader->node;
1718
1719    switch (node->type) {
1720        case XML_NAMESPACE_DECL:
1721	    return(xmlStrdup(((xmlNsPtr) node)->href));
1722        case XML_ATTRIBUTE_NODE:{
1723	    xmlAttrPtr attr = (xmlAttrPtr) node;
1724
1725	    if (attr->parent != NULL)
1726		return (xmlNodeListGetString
1727			(attr->parent->doc, attr->children, 1));
1728	    else
1729		return (xmlNodeListGetString(NULL, attr->children, 1));
1730	    break;
1731	}
1732        case XML_TEXT_NODE:
1733        case XML_CDATA_SECTION_NODE:
1734        case XML_PI_NODE:
1735        case XML_COMMENT_NODE:
1736            if (node->content != NULL)
1737                return (xmlStrdup(node->content));
1738	default:
1739	    return(NULL);
1740    }
1741    return(NULL);
1742}
1743
1744/**
1745 * xmlTextReaderIsDefault:
1746 * @reader:  the xmlTextReaderPtr used
1747 *
1748 * Whether an Attribute  node was generated from the default value
1749 * defined in the DTD or schema.
1750 *
1751 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
1752 */
1753int
1754xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
1755    if (reader == NULL)
1756	return(-1);
1757    return(0);
1758}
1759
1760/**
1761 * xmlTextReaderQuoteChar:
1762 * @reader:  the xmlTextReaderPtr used
1763 *
1764 * The quotation mark character used to enclose the value of an attribute.
1765 *
1766 * Returns " or ' and -1 in case of error
1767 */
1768int
1769xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
1770    if (reader == NULL)
1771	return(-1);
1772    /* TODO maybe lookup the attribute value for " first */
1773    return((int) '"');
1774}
1775
1776/**
1777 * xmlTextReaderXmlLang:
1778 * @reader:  the xmlTextReaderPtr used
1779 *
1780 * The xml:lang scope within which the node resides.
1781 *
1782 * Returns the xml:lang value or NULL if none exists.
1783 */
1784xmlChar *
1785xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
1786    if (reader == NULL)
1787	return(NULL);
1788    if (reader->node == NULL)
1789	return(NULL);
1790    return(xmlNodeGetLang(reader->node));
1791}
1792
1793/**
1794 * xmlTextReaderNormalization:
1795 * @reader:  the xmlTextReaderPtr used
1796 *
1797 * The value indicating whether to normalize white space and attribute values.
1798 * Since attribute value and end of line normalizations are a MUST in the XML
1799 * specification only the value true is accepted. The broken bahaviour of
1800 * accepting out of range character entities like &#0; is of course not
1801 * supported either.
1802 *
1803 * Returns 1 or -1 in case of error.
1804 */
1805int
1806xmlTextReaderNormalization(xmlTextReaderPtr reader) {
1807    if (reader == NULL)
1808	return(-1);
1809    return(1);
1810}
1811
1812/************************************************************************
1813 *									*
1814 *			Extensions to the base APIs			*
1815 *									*
1816 ************************************************************************/
1817
1818/**
1819 * xmlTextReaderSetParserProp:
1820 * @reader:  the xmlTextReaderPtr used
1821 * @prop:  the xmlParserProperties to set
1822 * @value:  usually 0 or 1 to (de)activate it
1823 *
1824 * Change the parser processing behaviour by changing some of its internal
1825 * properties. Note that some properties can only be changed before any
1826 * read has been done.
1827 *
1828 * Returns 0 if the call was successful, or -1 in case of error
1829 */
1830int
1831xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
1832    xmlParserProperties p = (xmlParserProperties) prop;
1833    xmlParserCtxtPtr ctxt;
1834
1835    if ((reader == NULL) || (reader->ctxt == NULL))
1836	return(-1);
1837    ctxt = reader->ctxt;
1838
1839    switch (p) {
1840        case XML_PARSER_LOADDTD:
1841	    if (value != 0) {
1842		if (ctxt->loadsubset == 0) {
1843		    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
1844			return(-1);
1845		    ctxt->loadsubset = XML_DETECT_IDS;
1846		}
1847	    } else {
1848		ctxt->loadsubset = 0;
1849	    }
1850	    return(0);
1851        case XML_PARSER_DEFAULTATTRS:
1852	    if (value != 0) {
1853		ctxt->loadsubset |= XML_COMPLETE_ATTRS;
1854	    } else {
1855		if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1856		    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
1857	    }
1858	    return(0);
1859        case XML_PARSER_VALIDATE:
1860	    if (value != 0) {
1861		ctxt->validate = 1;
1862	    } else {
1863		ctxt->validate = 0;
1864	    }
1865	    return(0);
1866        case XML_PARSER_SUBST_ENTITIES:
1867	    if (value != 0) {
1868		ctxt->replaceEntities = 1;
1869	    } else {
1870		ctxt->replaceEntities = 0;
1871	    }
1872	    return(0);
1873    }
1874    return(-1);
1875}
1876
1877/**
1878 * xmlTextReaderGetParserProp:
1879 * @reader:  the xmlTextReaderPtr used
1880 * @prop:  the xmlParserProperties to get
1881 *
1882 * Read the parser internal property.
1883 *
1884 * Returns the value, usually 0 or 1, or -1 in case of error.
1885 */
1886int
1887xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
1888    xmlParserProperties p = (xmlParserProperties) prop;
1889    xmlParserCtxtPtr ctxt;
1890
1891    if ((reader == NULL) || (reader->ctxt == NULL))
1892	return(-1);
1893    ctxt = reader->ctxt;
1894
1895    switch (p) {
1896        case XML_PARSER_LOADDTD:
1897	    if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
1898		return(1);
1899	    return(0);
1900        case XML_PARSER_DEFAULTATTRS:
1901	    if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1902		return(1);
1903	    return(0);
1904        case XML_PARSER_VALIDATE:
1905	    return(ctxt->validate);
1906	case XML_PARSER_SUBST_ENTITIES:
1907	    return(ctxt->replaceEntities);
1908    }
1909    return(-1);
1910}
1911
1912/**
1913 * xmlTextReaderCurrentNode:
1914 * @reader:  the xmlTextReaderPtr used
1915 *
1916 * Hacking interface allowing to get the xmlNodePtr correponding to the
1917 * current node being accessed by the xmlTextReader. This is dangerous
1918 * because the underlying node may be destroyed on the next Reads.
1919 *
1920 * Returns the xmlNodePtr or NULL in case of error.
1921 */
1922xmlNodePtr
1923xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
1924    if (reader == NULL)
1925	return(NULL);
1926
1927    if (reader->curnode != NULL)
1928	return(reader->curnode);
1929    return(reader->node);
1930}
1931
1932/**
1933 * xmlTextReaderCurrentDoc:
1934 * @reader:  the xmlTextReaderPtr used
1935 *
1936 * Hacking interface allowing to get the xmlDocPtr correponding to the
1937 * current document being accessed by the xmlTextReader. This is dangerous
1938 * because the associated node may be destroyed on the next Reads.
1939 *
1940 * Returns the xmlDocPtr or NULL in case of error.
1941 */
1942xmlDocPtr
1943xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
1944    if ((reader == NULL) || (reader->ctxt == NULL))
1945	return(NULL);
1946
1947    return(reader->ctxt->myDoc);
1948}
1949
1950/************************************************************************
1951 *									*
1952 *			Utilities					*
1953 *									*
1954 ************************************************************************/
1955/**
1956 * xmlBase64Decode:
1957 * @in:  the input buffer
1958 * @inlen:  the size of the input (in), the size read from it (out)
1959 * @to:  the output buffer
1960 * @tolen:  the size of the output (in), the size written to (out)
1961 *
1962 * Base64 decoder, reads from @in and save in @to
1963 *
1964 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
1965 *         2 if there wasn't enough space on the output or -1 in case of error.
1966 */
1967static int
1968xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
1969	        unsigned char *to, unsigned long *tolen) {
1970    unsigned long incur;		/* current index in in[] */
1971    unsigned long inblk;		/* last block index in in[] */
1972    unsigned long outcur;		/* current index in out[] */
1973    unsigned long inmax;		/* size of in[] */
1974    unsigned long outmax;		/* size of out[] */
1975    unsigned char cur;			/* the current value read from in[] */
1976    unsigned char intmp[3], outtmp[4];	/* temporary buffers for the convert */
1977    int nbintmp;			/* number of byte in intmp[] */
1978    int is_ignore;			/* cur should be ignored */
1979    int is_end = 0;			/* the end of the base64 was found */
1980    int retval = 1;
1981    int i;
1982
1983    if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
1984	return(-1);
1985
1986    incur = 0;
1987    inblk = 0;
1988    outcur = 0;
1989    inmax = *inlen;
1990    outmax = *tolen;
1991    nbintmp = 0;
1992
1993    while (1) {
1994        if (incur >= inmax)
1995            break;
1996        cur = in[incur++];
1997        is_ignore = 0;
1998        if ((cur >= 'A') && (cur <= 'Z'))
1999            cur = cur - 'A';
2000        else if ((cur >= 'a') && (cur <= 'z'))
2001            cur = cur - 'a' + 26;
2002        else if ((cur >= '0') && (cur <= '9'))
2003            cur = cur - '0' + 52;
2004        else if (cur == '+')
2005            cur = 62;
2006        else if (cur == '/')
2007            cur = 63;
2008        else if (cur == '.')
2009            cur = 0;
2010        else if (cur == '=') /*no op , end of the base64 stream */
2011            is_end = 1;
2012        else {
2013            is_ignore = 1;
2014	    if (nbintmp == 0)
2015		inblk = incur;
2016	}
2017
2018        if (!is_ignore) {
2019            int nbouttmp = 3;
2020            int is_break = 0;
2021
2022            if (is_end) {
2023                if (nbintmp == 0)
2024                    break;
2025                if ((nbintmp == 1) || (nbintmp == 2))
2026                    nbouttmp = 1;
2027                else
2028                    nbouttmp = 2;
2029                nbintmp = 3;
2030                is_break = 1;
2031            }
2032            intmp[nbintmp++] = cur;
2033	    /*
2034	     * if intmp is full, push the 4byte sequence as a 3 byte
2035	     * sequence out
2036	     */
2037            if (nbintmp == 4) {
2038                nbintmp = 0;
2039                outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
2040                outtmp[1] =
2041                    ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
2042                outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
2043		if (outcur + 3 >= outmax) {
2044		    retval = 2;
2045		    break;
2046		}
2047
2048                for (i = 0; i < nbouttmp; i++)
2049		    to[outcur++] = outtmp[i];
2050		inblk = incur;
2051            }
2052
2053            if (is_break) {
2054		retval = 0;
2055                break;
2056	    }
2057        }
2058    }
2059
2060    *tolen = outcur;
2061    *inlen = inblk;
2062    return (retval);
2063}
2064
2065/*
2066 * Test routine for the xmlBase64Decode function
2067 */
2068#if 0
2069int main(int argc, char **argv) {
2070    char *input = "  VW4 gcGV0        \n      aXQgdGVzdCAuCg== ";
2071    char output[100];
2072    char output2[100];
2073    char output3[100];
2074    unsigned long inlen = strlen(input);
2075    unsigned long outlen = 100;
2076    int ret;
2077    unsigned long cons, tmp, tmp2, prod;
2078
2079    /*
2080     * Direct
2081     */
2082    ret = xmlBase64Decode(input, &inlen, output, &outlen);
2083
2084    output[outlen] = 0;
2085    printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
2086
2087    /*
2088     * output chunking
2089     */
2090    cons = 0;
2091    prod = 0;
2092    while (cons < inlen) {
2093	tmp = 5;
2094	tmp2 = inlen - cons;
2095
2096	printf("%ld %ld\n", cons, prod);
2097	ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
2098	cons += tmp2;
2099	prod += tmp;
2100	printf("%ld %ld\n", cons, prod);
2101    }
2102    output2[outlen] = 0;
2103    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
2104
2105    /*
2106     * input chunking
2107     */
2108    cons = 0;
2109    prod = 0;
2110    while (cons < inlen) {
2111	tmp = 100 - prod;
2112	tmp2 = inlen - cons;
2113	if (tmp2 > 5)
2114	    tmp2 = 5;
2115
2116	printf("%ld %ld\n", cons, prod);
2117	ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
2118	cons += tmp2;
2119	prod += tmp;
2120	printf("%ld %ld\n", cons, prod);
2121    }
2122    output3[outlen] = 0;
2123    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
2124    return(0);
2125
2126}
2127#endif
2128