xmlreader.c revision 409a8147c1b5784f6c860ec6de7d94fd59a130ce
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/*
14 * TODOs:
15 *   - provide an API to preserve part of the tree
16 *   - Streaming XInclude support
17 *   - validation against a provided DTD
18 *   - XML Schemas validation
19 *   - setting(s) for NoBlanks
20 *   - performances and tuning ...
21 */
22#define IN_LIBXML
23#include "libxml.h"
24
25#include <string.h> /* for memset() only ! */
26#include <stdarg.h>
27
28#ifdef HAVE_CTYPE_H
29#include <ctype.h>
30#endif
31#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
34
35#include <libxml/xmlmemory.h>
36#include <libxml/xmlIO.h>
37#include <libxml/xmlreader.h>
38#include <libxml/relaxng.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#define CHUNK_SIZE 512
60/************************************************************************
61 *									*
62 *	The parser: maps the Text Reader API on top of the existing	*
63 *		parsing routines building a tree			*
64 *									*
65 ************************************************************************/
66
67#define XML_TEXTREADER_INPUT	1
68#define XML_TEXTREADER_CTXT	2
69
70typedef enum {
71    XML_TEXTREADER_MODE_INITIAL = 0,
72    XML_TEXTREADER_MODE_INTERACTIVE = 1,
73    XML_TEXTREADER_MODE_ERROR = 2,
74    XML_TEXTREADER_MODE_EOF =3,
75    XML_TEXTREADER_MODE_CLOSED = 4,
76    XML_TEXTREADER_MODE_READING = 5
77} xmlTextReaderMode;
78
79typedef enum {
80    XML_TEXTREADER_NONE = -1,
81    XML_TEXTREADER_START= 0,
82    XML_TEXTREADER_ELEMENT= 1,
83    XML_TEXTREADER_END= 2,
84    XML_TEXTREADER_EMPTY= 3,
85    XML_TEXTREADER_BACKTRACK= 4,
86    XML_TEXTREADER_DONE= 5,
87    XML_TEXTREADER_ERROR= 6
88} xmlTextReaderState;
89
90typedef enum {
91    XML_TEXTREADER_NOT_VALIDATE = 0,
92    XML_TEXTREADER_VALIDATE_DTD = 1,
93    XML_TEXTREADER_VALIDATE_RNG = 2
94} xmlTextReaderValidate;
95
96struct _xmlTextReader {
97    int				mode;	/* the parsing mode */
98    xmlTextReaderValidate       validate;/* is there any validation */
99    int				allocs;	/* what structure were deallocated */
100    xmlTextReaderState		state;
101    xmlParserCtxtPtr		ctxt;	/* the parser context */
102    xmlSAXHandlerPtr		sax;	/* the parser SAX callbacks */
103    xmlParserInputBufferPtr	input;	/* the input */
104    startElementSAXFunc		startElement;/* initial SAX callbacks */
105    endElementSAXFunc		endElement;  /* idem */
106    charactersSAXFunc		characters;
107    cdataBlockSAXFunc		cdataBlock;
108    unsigned int 		base;	/* base of the segment in the input */
109    unsigned int 		cur;	/* current position in the input */
110    xmlNodePtr			node;	/* current node */
111    xmlNodePtr			curnode;/* current attribute node */
112    int				depth;  /* depth of the current node */
113    xmlNodePtr			faketext;/* fake xmlNs chld */
114
115    /* entity stack when traversing entities content */
116    xmlNodePtr         ent;          /* Current Entity Ref Node */
117    int                entNr;        /* Depth of the entities stack */
118    int                entMax;       /* Max depth of the entities stack */
119    xmlNodePtr        *entTab;       /* array of entities */
120
121    /* error handling */
122    xmlTextReaderErrorFunc errorFunc;    /* callback function */
123    void                  *errorFuncArg; /* callback function user argument */
124
125#ifdef LIBXML_SCHEMAS_ENABLED
126    /* Handling of RelaxNG validation */
127    xmlRelaxNGPtr          rngSchemas;   /* The Relax NG schemas */
128    xmlRelaxNGValidCtxtPtr rngValidCtxt; /* The Relax NG validation context */
129    int                  rngValidErrors; /* The number of errors detected */
130    xmlNodePtr             rngFullNode;  /* the node if RNG not progressive */
131#endif
132};
133
134static const char *xmlTextReaderIsEmpty = "This element is empty";
135
136#ifdef DEBUG_READER
137static void
138xmlTextReaderDebug(xmlTextReaderPtr reader) {
139    if ((reader == NULL) || (reader->ctxt == NULL)) {
140	fprintf(stderr, "xmlTextReader NULL\n");
141	return;
142    }
143    fprintf(stderr, "xmlTextReader: state %d depth %d ",
144	    reader->state, reader->depth);
145    if (reader->node == NULL) {
146	fprintf(stderr, "node = NULL\n");
147    } else {
148	fprintf(stderr, "node %s\n", reader->node->name);
149    }
150    fprintf(stderr, "  input: base %d, cur %d, depth %d: ",
151	    reader->base, reader->cur, reader->ctxt->nodeNr);
152    if (reader->input->buffer == NULL) {
153	fprintf(stderr, "buffer is NULL\n");
154    } else {
155#ifdef LIBXML_DEBUG_ENABLED
156	xmlDebugDumpString(stderr,
157		&reader->input->buffer->content[reader->cur]);
158#endif
159	fprintf(stderr, "\n");
160    }
161}
162#endif
163
164/**
165 * xmlTextReaderEntPush:
166 * @reader:  the xmlTextReaderPtr used
167 * @value:  the entity reference node
168 *
169 * Pushes a new entity reference node on top of the entities stack
170 *
171 * Returns 0 in case of error, the index in the stack otherwise
172 */
173static int
174xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
175{
176    if (reader->entMax <= 0) {
177	reader->entMax = 10;
178	reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
179		                                  sizeof(reader->entTab[0]));
180        if (reader->entTab == NULL) {
181            xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
182            return (0);
183        }
184    }
185    if (reader->entNr >= reader->entMax) {
186        reader->entMax *= 2;
187        reader->entTab =
188            (xmlNodePtr *) xmlRealloc(reader->entTab,
189                                      reader->entMax *
190                                      sizeof(reader->entTab[0]));
191        if (reader->entTab == NULL) {
192            xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
193            return (0);
194        }
195    }
196    reader->entTab[reader->entNr] = value;
197    reader->ent = value;
198    return (reader->entNr++);
199}
200
201/**
202 * xmlTextReaderEntPop:
203 * @reader:  the xmlTextReaderPtr used
204 *
205 * Pops the top element entity from the entities stack
206 *
207 * Returns the entity just removed
208 */
209static xmlNodePtr
210xmlTextReaderEntPop(xmlTextReaderPtr reader)
211{
212    xmlNodePtr ret;
213
214    if (reader->entNr <= 0)
215        return (0);
216    reader->entNr--;
217    if (reader->entNr > 0)
218        reader->ent = reader->entTab[reader->entNr - 1];
219    else
220        reader->ent = NULL;
221    ret = reader->entTab[reader->entNr];
222    reader->entTab[reader->entNr] = 0;
223    return (ret);
224}
225
226/**
227 * xmlTextReaderStartElement:
228 * @ctx: the user data (XML parser context)
229 * @fullname:  The element name, including namespace prefix
230 * @atts:  An array of name/value attributes pairs, NULL terminated
231 *
232 * called when an opening tag has been processed.
233 */
234static void
235xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
236	                  const xmlChar **atts) {
237    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
238    xmlParserCtxtPtr origctxt;
239    xmlTextReaderPtr reader = ctxt->_private;
240
241#ifdef DEBUG_CALLBACKS
242    printf("xmlTextReaderStartElement(%s)\n", fullname);
243#endif
244    if ((reader != NULL) && (reader->startElement != NULL)) {
245	/*
246	 * when processing an entity, the context may have been changed
247	 */
248	origctxt = reader->ctxt;
249	reader->startElement(ctx, fullname, atts);
250	if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
251	    (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
252	    (ctxt->input->cur[1] == '>'))
253	    ctxt->node->_private = (void *) xmlTextReaderIsEmpty;
254    }
255    if (reader != NULL)
256	reader->state = XML_TEXTREADER_ELEMENT;
257}
258
259/**
260 * xmlTextReaderEndElement:
261 * @ctx: the user data (XML parser context)
262 * @fullname:  The element name, including namespace prefix
263 *
264 * called when an ending tag has been processed.
265 */
266static void
267xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
268    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
269    xmlParserCtxtPtr origctxt;
270    xmlTextReaderPtr reader = ctxt->_private;
271
272#ifdef DEBUG_CALLBACKS
273    printf("xmlTextReaderEndElement(%s)\n", fullname);
274#endif
275    if ((reader != NULL) && (reader->endElement != NULL)) {
276	/*
277	 * when processing an entity, the context may have been changed
278	 */
279	origctxt = reader->ctxt;
280
281	reader->endElement(ctx, fullname);
282    }
283}
284
285/**
286 * xmlTextReaderCharacters:
287 * @ctx: the user data (XML parser context)
288 * @ch:  a xmlChar string
289 * @len: the number of xmlChar
290 *
291 * receiving some chars from the parser.
292 */
293static void
294xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
295{
296    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
297    xmlParserCtxtPtr origctxt;
298    xmlTextReaderPtr reader = ctxt->_private;
299
300#ifdef DEBUG_CALLBACKS
301    printf("xmlTextReaderCharacters()\n");
302#endif
303    if ((reader != NULL) && (reader->characters != NULL)) {
304	reader->characters(ctx, ch, len);
305	/*
306	 * when processing an entity, the context may have been changed
307	 */
308	origctxt = reader->ctxt;
309    }
310}
311
312/**
313 * xmlTextReaderCDataBlock:
314 * @ctx: the user data (XML parser context)
315 * @value:  The pcdata content
316 * @len:  the block length
317 *
318 * called when a pcdata block has been parsed
319 */
320static void
321xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
322{
323    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
324    xmlTextReaderPtr reader = ctxt->_private;
325
326#ifdef DEBUG_CALLBACKS
327    printf("xmlTextReaderCDataBlock()\n");
328#endif
329    if ((reader != NULL) && (reader->cdataBlock != NULL)) {
330	reader->cdataBlock(ctx, ch, len);
331    }
332}
333
334/**
335 * xmlTextReaderPushData:
336 * @reader:  the xmlTextReaderPtr used
337 *
338 * Push data down the progressive parser until a significant callback
339 * got raised.
340 *
341 * Returns -1 in case of failure, 0 otherwise
342 */
343static int
344xmlTextReaderPushData(xmlTextReaderPtr reader) {
345    xmlBufferPtr inbuf;
346    int val, s;
347    int oldstate;
348
349    if ((reader->input == NULL) || (reader->input->buffer == NULL))
350	return(-1);
351
352    oldstate = reader->state;
353    reader->state = XML_TEXTREADER_NONE;
354    inbuf = reader->input->buffer;
355
356    while (reader->state == XML_TEXTREADER_NONE) {
357	if (inbuf->use < reader->cur + CHUNK_SIZE) {
358	    /*
359	     * Refill the buffer unless we are at the end of the stream
360	     */
361	    if (reader->mode != XML_TEXTREADER_MODE_EOF) {
362		val = xmlParserInputBufferRead(reader->input, 4096);
363		if (val <= 0) {
364		    reader->mode = XML_TEXTREADER_MODE_EOF;
365		    reader->state = oldstate;
366		    if ((oldstate != XML_TEXTREADER_START) ||
367			(reader->ctxt->myDoc != NULL))
368			return(val);
369		}
370
371	    } else
372		break;
373	}
374	/*
375	 * parse by block of CHUNK_SIZE bytes, various tests show that
376	 * it's the best tradeoff at least on a 1.2GH Duron
377	 */
378	if (inbuf->use >= reader->cur + CHUNK_SIZE) {
379	    val = xmlParseChunk(reader->ctxt,
380		          (const char *) &inbuf->content[reader->cur],
381			  CHUNK_SIZE, 0);
382	    reader->cur += CHUNK_SIZE;
383	    if (val != 0)
384		return(-1);
385	} else {
386	    s = inbuf->use - reader->cur;
387	    val = xmlParseChunk(reader->ctxt,
388		          (const char *) &inbuf->content[reader->cur],
389			  s, 0);
390	    reader->cur += s;
391	    if (val != 0)
392		return(-1);
393	    break;
394	}
395    }
396
397    /*
398     * Discard the consumed input when needed and possible
399     */
400    if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
401	if (reader->cur >= 4096) {
402	    val = xmlBufferShrink(inbuf, reader->cur);
403	    if (val >= 0) {
404		reader->cur -= val;
405	    }
406	}
407    }
408
409    /*
410     * At the end of the stream signal that the work is done to the Push
411     * parser.
412     */
413    else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
414	if (reader->mode != XML_TEXTREADER_DONE) {
415	    s = inbuf->use - reader->cur;
416	    val = xmlParseChunk(reader->ctxt,
417		    (const char *) &inbuf->content[reader->cur],
418		    s, 1);
419	    reader->cur = inbuf->use;
420	    reader->mode = XML_TEXTREADER_DONE;
421	    if (val != 0) return(-1);
422	}
423    }
424    reader->state = oldstate;
425    return(0);
426}
427
428/**
429 * xmlTextReaderValidatePush:
430 * @reader:  the xmlTextReaderPtr used
431 *
432 * Push the current node for validation
433 */
434static void
435xmlTextReaderValidatePush(xmlTextReaderPtr reader) {
436#ifdef LIBXML_REGEXP_ENABLED
437    xmlNodePtr node = reader->node;
438
439    if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
440        (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
441	if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
442	    reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
443				    reader->ctxt->myDoc, node, node->name);
444	} else {
445	    /* TODO use the BuildQName interface */
446	    xmlChar *qname;
447
448	    qname = xmlStrdup(node->ns->prefix);
449	    qname = xmlStrcat(qname, BAD_CAST ":");
450	    qname = xmlStrcat(qname, node->name);
451	    reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
452				    reader->ctxt->myDoc, node, qname);
453	    if (qname != NULL)
454		xmlFree(qname);
455	}
456#ifdef LIBXML_SCHEMAS_ENABLED
457    } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
458               (reader->rngValidCtxt != NULL)) {
459	int ret;
460
461	if (reader->rngFullNode != NULL) return;
462	ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
463	                                    reader->ctxt->myDoc,
464					    node);
465	if (ret == 0) {
466	    /*
467	     * this element requires a full tree
468	     */
469	    node = xmlTextReaderExpand(reader);
470	    if (node == NULL) {
471printf("Expand failed !\n");
472	        ret = -1;
473	    } else {
474		ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt,
475						    reader->ctxt->myDoc,
476						    node);
477		reader->rngFullNode = node;
478	    }
479	}
480	if (ret != 1)
481	    reader->rngValidErrors++;
482#endif
483    }
484#endif /* LIBXML_REGEXP_ENABLED */
485}
486
487/**
488 * xmlTextReaderValidateCData:
489 * @reader:  the xmlTextReaderPtr used
490 * @data:  pointer to the CData
491 * @len:  lenght of the CData block in bytes.
492 *
493 * Push some CData for validation
494 */
495static void
496xmlTextReaderValidateCData(xmlTextReaderPtr reader,
497                           const xmlChar *data, int len) {
498#ifdef LIBXML_REGEXP_ENABLED
499    if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
500        (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
501	reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt,
502	                                            data, len);
503#ifdef LIBXML_SCHEMAS_ENABLED
504    } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
505               (reader->rngValidCtxt != NULL)) {
506	int ret;
507
508	if (reader->rngFullNode != NULL) return;
509	ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len);
510	if (ret != 1)
511	    reader->rngValidErrors++;
512#endif
513    }
514#endif /* LIBXML_REGEXP_ENABLED */
515}
516
517/**
518 * xmlTextReaderValidatePop:
519 * @reader:  the xmlTextReaderPtr used
520 *
521 * Pop the current node from validation
522 */
523static void
524xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
525#ifdef LIBXML_REGEXP_ENABLED
526    xmlNodePtr node = reader->node;
527
528    if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
529        (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
530	if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
531	    reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
532				    reader->ctxt->myDoc, node, node->name);
533	} else {
534	    /* TODO use the BuildQName interface */
535	    xmlChar *qname;
536
537	    qname = xmlStrdup(node->ns->prefix);
538	    qname = xmlStrcat(qname, BAD_CAST ":");
539	    qname = xmlStrcat(qname, node->name);
540	    reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
541				    reader->ctxt->myDoc, node, qname);
542	    if (qname != NULL)
543		xmlFree(qname);
544	}
545#ifdef LIBXML_SCHEMAS_ENABLED
546    } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
547               (reader->rngValidCtxt != NULL)) {
548	int ret;
549
550	if (reader->rngFullNode != NULL) {
551	    if (node == reader->rngFullNode)
552	        reader->rngFullNode = NULL;
553	    return;
554	}
555	ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
556	                                   reader->ctxt->myDoc,
557					   node);
558	if (ret != 1)
559	    reader->rngValidErrors++;
560#endif
561    }
562#endif /* LIBXML_REGEXP_ENABLED */
563}
564/**
565 * xmlTextReaderValidateEntity:
566 * @reader:  the xmlTextReaderPtr used
567 *
568 * Handle the validation when an entity reference is encountered and
569 * entity substitution is not activated. As a result the parser interface
570 * must walk through the entity and do the validation calls
571 */
572static void
573xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
574#ifdef LIBXML_REGEXP_ENABLED
575    xmlNodePtr oldnode = reader->node;
576    xmlNodePtr node = reader->node;
577    xmlParserCtxtPtr ctxt = reader->ctxt;
578
579    do {
580	if (node->type == XML_ENTITY_REF_NODE) {
581	    /*
582	     * Case where the underlying tree is not availble, lookup the entity
583	     * and walk it.
584	     */
585	    if ((node->children == NULL) && (ctxt->sax != NULL) &&
586		(ctxt->sax->getEntity != NULL)) {
587		node->children = (xmlNodePtr)
588		    ctxt->sax->getEntity(ctxt, node->name);
589	    }
590
591	    if ((node->children != NULL) &&
592		(node->children->type == XML_ENTITY_DECL) &&
593		(node->children->children != NULL)) {
594		xmlTextReaderEntPush(reader, node);
595		node = node->children->children;
596		continue;
597	    } else {
598		/*
599		 * The error has probably be raised already.
600		 */
601		if (node == oldnode)
602		    break;
603		node = node->next;
604	    }
605	} else if (node->type == XML_ELEMENT_NODE) {
606	    reader->node = node;
607	    xmlTextReaderValidatePush(reader);
608	} else if ((node->type == XML_TEXT_NODE) ||
609		   (node->type == XML_CDATA_SECTION_NODE)) {
610            xmlTextReaderValidateCData(reader, node->content,
611	                               xmlStrlen(node->content));
612	}
613
614	/*
615	 * go to next node
616	 */
617	if (node->children != NULL) {
618	    node = node->children;
619	    continue;
620	} else if (node->type == XML_ELEMENT_NODE) {
621	    xmlTextReaderValidatePop(reader);
622	}
623	if (node->next != NULL) {
624	    node = node->next;
625	    continue;
626	}
627	do {
628	    node = node->parent;
629	    if (node->type == XML_ELEMENT_NODE) {
630		reader->node = node;
631		xmlTextReaderValidatePop(reader);
632	    }
633	    if ((node->type == XML_ENTITY_DECL) &&
634		(reader->ent != NULL) && (reader->ent->children == node)) {
635		node = xmlTextReaderEntPop(reader);
636	    }
637	    if (node == oldnode)
638		break;
639	    if (node->next != NULL) {
640		node = node->next;
641		break;
642	    }
643	} while ((node != NULL) && (node != oldnode));
644    } while ((node != NULL) && (node != oldnode));
645    reader->node = oldnode;
646#endif /* LIBXML_REGEXP_ENABLED */
647}
648
649
650/**
651 * xmlTextReaderGetSuccessor:
652 * @cur:  the current node
653 *
654 * Get the successor of a node if available.
655 *
656 * Returns the successor node or NULL
657 */
658static xmlNodePtr
659xmlTextReaderGetSuccessor(xmlNodePtr cur) {
660    if (cur == NULL) return(NULL) ; /* ERROR */
661    if (cur->next != NULL) return(cur->next) ;
662    do {
663        cur = cur->parent;
664        if (cur == NULL) return(NULL);
665        if (cur->next != NULL) return(cur->next);
666    } while (cur != NULL);
667    return(cur);
668}
669
670/**
671 * xmlTextReaderDoExpand:
672 * @reader:  the xmlTextReaderPtr used
673 *
674 * Makes sure that the current node is fully read as well as all its
675 * descendant. It means the full DOM subtree must be available at the
676 * end of the call.
677 *
678 * Returns 1 if the node was expanded successfully, 0 if there is no more
679 *          nodes to read, or -1 in case of error
680 */
681static int
682xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
683    int val;
684
685    if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
686        return(-1);
687
688    do {
689        if (xmlTextReaderGetSuccessor(reader->node) != NULL)
690	    return(1);
691	if (reader->ctxt->nodeNr <= reader->depth)
692	    return(1);
693	if (reader->mode == XML_TEXTREADER_MODE_EOF)
694	    return(1);
695	val = xmlTextReaderPushData(reader);
696	if (val < 0)
697	    return(-1);
698    } while(reader->mode != XML_TEXTREADER_MODE_EOF);
699    return(1);
700}
701
702/**
703 * xmlTextReaderRead:
704 * @reader:  the xmlTextReaderPtr used
705 *
706 *  Moves the position of the current instance to the next node in
707 *  the stream, exposing its properties.
708 *
709 *  Returns 1 if the node was read successfully, 0 if there is no more
710 *          nodes to read, or -1 in case of error
711 */
712int
713xmlTextReaderRead(xmlTextReaderPtr reader) {
714    int val, olddepth = 0;
715    xmlTextReaderState oldstate = 0;
716    xmlNodePtr oldnode = NULL;
717
718    if ((reader == NULL) || (reader->ctxt == NULL))
719	return(-1);
720    if (reader->ctxt->wellFormed != 1)
721	return(-1);
722
723#ifdef DEBUG_READER
724    fprintf(stderr, "\nREAD ");
725    DUMP_READER
726#endif
727    reader->curnode = NULL;
728    if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
729	reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
730	/*
731	 * Initial state
732	 */
733	do {
734	    val = xmlTextReaderPushData(reader);
735	    if (val < 0)
736		return(-1);
737	} while ((reader->ctxt->node == NULL) &&
738		 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
739		  (reader->mode != XML_TEXTREADER_DONE)));
740	if (reader->ctxt->node == NULL) {
741	    if (reader->ctxt->myDoc != NULL) {
742		reader->node = reader->ctxt->myDoc->children;
743	    }
744	    if (reader->node == NULL)
745		return(-1);
746	    reader->state = XML_TEXTREADER_ELEMENT;
747	} else {
748	    if (reader->ctxt->myDoc != NULL) {
749		reader->node = reader->ctxt->myDoc->children;
750	    }
751	    if (reader->node == NULL)
752		reader->node = reader->ctxt->nodeTab[0];
753	    reader->state = XML_TEXTREADER_ELEMENT;
754	}
755	reader->depth = 0;
756	goto node_found;
757    }
758    oldstate = reader->state;
759    olddepth = reader->ctxt->nodeNr;
760    oldnode = reader->node;
761
762get_next_node:
763    /*
764     * If we are not backtracking on ancestors or examined nodes,
765     * that the parser didn't finished or that we arent at the end
766     * of stream, continue processing.
767     */
768    while ((reader->node->next == NULL) &&
769	   (reader->ctxt->nodeNr == olddepth) &&
770           ((oldstate == XML_TEXTREADER_BACKTRACK) ||
771            (reader->node->children == NULL) ||
772	    (reader->node->type == XML_ENTITY_REF_NODE) ||
773	    ((reader->node->children != NULL) &&
774	     (reader->node->children->type == XML_TEXT_NODE) &&
775	     (reader->node->children->next == NULL)) ||
776	    (reader->node->type == XML_DTD_NODE) ||
777	    (reader->node->type == XML_DOCUMENT_NODE) ||
778	    (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
779	   ((reader->ctxt->node == NULL) ||
780	    (reader->ctxt->node == reader->node) ||
781	    (reader->ctxt->node == reader->node->parent)) &&
782	   (reader->ctxt->instate != XML_PARSER_EOF)) {
783	val = xmlTextReaderPushData(reader);
784	if (val < 0)
785	    return(-1);
786	if (reader->node == NULL)
787	    goto node_end;
788    }
789    if (oldstate != XML_TEXTREADER_BACKTRACK) {
790	if ((reader->node->children != NULL) &&
791	    (reader->node->type != XML_ENTITY_REF_NODE) &&
792	    (reader->node->type != XML_DTD_NODE)) {
793	    reader->node = reader->node->children;
794	    reader->depth++;
795	    reader->state = XML_TEXTREADER_ELEMENT;
796	    goto node_found;
797	}
798    }
799    if (reader->node->next != NULL) {
800	if ((oldstate == XML_TEXTREADER_ELEMENT) &&
801            (reader->node->type == XML_ELEMENT_NODE) &&
802	    (reader->node->children == NULL) &&
803	    (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
804	    reader->state = XML_TEXTREADER_END;
805	    goto node_found;
806	}
807	if ((reader->validate) &&
808	    (reader->node->type == XML_ELEMENT_NODE))
809	    xmlTextReaderValidatePop(reader);
810	reader->node = reader->node->next;
811	reader->state = XML_TEXTREADER_ELEMENT;
812
813	/*
814	 * Cleanup of the old node
815	 */
816	if ((reader->node->prev != NULL) &&
817            (reader->node->prev->type != XML_DTD_NODE)) {
818	    xmlNodePtr tmp = reader->node->prev;
819	    xmlUnlinkNode(tmp);
820	    xmlFreeNode(tmp);
821	}
822
823	goto node_found;
824    }
825    if ((oldstate == XML_TEXTREADER_ELEMENT) &&
826	(reader->node->type == XML_ELEMENT_NODE) &&
827	(reader->node->children == NULL) &&
828	(reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
829	reader->state = XML_TEXTREADER_END;
830	goto node_found;
831    }
832    if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE))
833	xmlTextReaderValidatePop(reader);
834    reader->node = reader->node->parent;
835    if ((reader->node == NULL) ||
836	(reader->node->type == XML_DOCUMENT_NODE) ||
837#ifdef LIBXML_DOCB_ENABLED
838	(reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
839#endif
840	(reader->node->type == XML_HTML_DOCUMENT_NODE)) {
841	if (reader->mode != XML_TEXTREADER_DONE) {
842	    val = xmlParseChunk(reader->ctxt, "", 0, 1);
843	    reader->mode = XML_TEXTREADER_DONE;
844	}
845	reader->node = NULL;
846	reader->depth = -1;
847
848	/*
849	 * Cleanup of the old node
850	 */
851	if (oldnode->type != XML_DTD_NODE) {
852	    xmlUnlinkNode(oldnode);
853	    xmlFreeNode(oldnode);
854	}
855
856	goto node_end;
857    }
858    reader->depth--;
859    reader->state = XML_TEXTREADER_BACKTRACK;
860
861node_found:
862    DUMP_READER
863
864    /*
865     * If we are in the middle of a piece of CDATA make sure it's finished
866     */
867    if ((reader->node != NULL) &&
868        ((reader->node->type == XML_TEXT_NODE) ||
869	 (reader->node->type == XML_CDATA_SECTION_NODE))) {
870            xmlTextReaderExpand(reader);
871    }
872
873    /*
874     * Handle entities enter and exit when in entity replacement mode
875     */
876    if ((reader->node != NULL) &&
877	(reader->node->type == XML_ENTITY_REF_NODE) &&
878	(reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
879	/*
880	 * Case where the underlying tree is not availble, lookup the entity
881	 * and walk it.
882	 */
883	if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
884	    (reader->ctxt->sax->getEntity != NULL)) {
885	    reader->node->children = (xmlNodePtr)
886		reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
887	}
888
889	if ((reader->node->children != NULL) &&
890	    (reader->node->children->type == XML_ENTITY_DECL) &&
891	    (reader->node->children->children != NULL)) {
892	    xmlTextReaderEntPush(reader, reader->node);
893	    reader->node = reader->node->children->children;
894	}
895    } else if ((reader->node != NULL) &&
896	       (reader->node->type == XML_ENTITY_REF_NODE) &&
897	       (reader->ctxt != NULL) && (reader->validate)) {
898	xmlTextReaderValidateEntity(reader);
899    }
900    if ((reader->node != NULL) &&
901	(reader->node->type == XML_ENTITY_DECL) &&
902	(reader->ent != NULL) && (reader->ent->children == reader->node)) {
903	reader->node = xmlTextReaderEntPop(reader);
904	reader->depth++;
905        goto get_next_node;
906    }
907#ifdef LIBXML_REGEXP_ENABLED
908    if ((reader->validate) && (reader->node != NULL)) {
909	xmlNodePtr node = reader->node;
910
911	if ((node->type == XML_ELEMENT_NODE) &&
912            ((reader->state != XML_TEXTREADER_END) &&
913	     (reader->state != XML_TEXTREADER_BACKTRACK))) {
914	    xmlTextReaderValidatePush(reader);
915	} else if ((node->type == XML_TEXT_NODE) ||
916		   (node->type == XML_CDATA_SECTION_NODE)) {
917            xmlTextReaderValidateCData(reader, node->content,
918	                               xmlStrlen(node->content));
919	}
920    }
921#endif /* LIBXML_REGEXP_ENABLED */
922    return(1);
923node_end:
924    reader->mode = XML_TEXTREADER_DONE;
925    return(0);
926}
927
928/**
929 * xmlTextReaderReadState:
930 * @reader:  the xmlTextReaderPtr used
931 *
932 * Gets the read state of the reader.
933 *
934 * Returns the state value, or -1 in case of error
935 */
936int
937xmlTextReaderReadState(xmlTextReaderPtr reader) {
938    if (reader == NULL)
939	return(-1);
940    return(reader->mode);
941}
942
943/**
944 * xmlTextReaderExpand:
945 * @reader:  the xmlTextReaderPtr used
946 *
947 * Reads the contents of the current node and the full subtree. It then makes
948 * the subtree available until the next xmlTextReaderRead() call
949 *
950 * Returns a node pointer valid until the next xmlTextReaderRead() call
951 *         or NULL in case of error.
952 */
953xmlNodePtr
954xmlTextReaderExpand(xmlTextReaderPtr reader) {
955    if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
956        return(NULL);
957    if (xmlTextReaderDoExpand(reader) < 0)
958        return(NULL);
959    return(reader->node);
960}
961
962/**
963 * xmlTextReaderNext:
964 * @reader:  the xmlTextReaderPtr used
965 *
966 * Skip to the node following the current one in document order while
967 * avoiding the subtree if any.
968 *
969 * Returns 1 if the node was read successfully, 0 if there is no more
970 *          nodes to read, or -1 in case of error
971 */
972int
973xmlTextReaderNext(xmlTextReaderPtr reader) {
974    int ret;
975    xmlNodePtr cur;
976
977    if (reader == NULL)
978	return(-1);
979    cur = reader->node;
980    if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
981        return(xmlTextReaderRead(reader));
982    if (reader->state == XML_TEXTREADER_END)
983        return(xmlTextReaderRead(reader));
984    if (cur->_private == (void *)xmlTextReaderIsEmpty)
985        return(xmlTextReaderRead(reader));
986    do {
987        ret = xmlTextReaderRead(reader);
988	if (ret != 1)
989	    return(ret);
990    } while (reader->node != cur);
991    return(xmlTextReaderRead(reader));
992}
993
994/**
995 * xmlTextReaderReadInnerXml:
996 * @reader:  the xmlTextReaderPtr used
997 *
998 * Reads the contents of the current node, including child nodes and markup.
999 *
1000 * Returns a string containing the XML content, or NULL if the current node
1001 *         is neither an element nor attribute, or has no child nodes. The
1002 *         string must be deallocated by the caller.
1003 */
1004xmlChar *
1005xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
1006    TODO
1007    return(NULL);
1008}
1009
1010/**
1011 * xmlTextReaderReadOuterXml:
1012 * @reader:  the xmlTextReaderPtr used
1013 *
1014 * Reads the contents of the current node, including child nodes and markup.
1015 *
1016 * Returns a string containing the XML content, or NULL if the current node
1017 *         is neither an element nor attribute, or has no child nodes. The
1018 *         string must be deallocated by the caller.
1019 */
1020xmlChar *
1021xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
1022    TODO
1023    return(NULL);
1024}
1025
1026/**
1027 * xmlTextReaderReadString:
1028 * @reader:  the xmlTextReaderPtr used
1029 *
1030 * Reads the contents of an element or a text node as a string.
1031 *
1032 * Returns a string containing the contents of the Element or Text node,
1033 *         or NULL if the reader is positioned on any other type of node.
1034 *         The string must be deallocated by the caller.
1035 */
1036xmlChar *
1037xmlTextReaderReadString(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
1038    TODO
1039    return(NULL);
1040}
1041
1042/**
1043 * xmlTextReaderReadBase64:
1044 * @reader:  the xmlTextReaderPtr used
1045 * @array:  a byte array to store the content.
1046 * @offset:  the zero-based index into array where the method should
1047 *           begin to write.
1048 * @len:  the number of bytes to write.
1049 *
1050 * Reads and decodes the Base64 encoded contents of an element and
1051 * stores the result in a byte buffer.
1052 *
1053 * Returns the number of bytes written to array, or zero if the current
1054 *         instance is not positioned on an element or -1 in case of error.
1055 */
1056int
1057xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
1058	                int offset, int len) {
1059    if ((reader == NULL) || (reader->ctxt == NULL))
1060	return(-1);
1061    if (reader->ctxt->wellFormed != 1)
1062	return(-1);
1063
1064    if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1065	return(0);
1066    TODO
1067    return(0);
1068}
1069
1070/**
1071 * xmlTextReaderReadBinHex:
1072 * @reader:  the xmlTextReaderPtr used
1073 * @array:  a byte array to store the content.
1074 * @offset:  the zero-based index into array where the method should
1075 *           begin to write.
1076 * @len:  the number of bytes to write.
1077 *
1078 * Reads and decodes the BinHex encoded contents of an element and
1079 * stores the result in a byte buffer.
1080 *
1081 * Returns the number of bytes written to array, or zero if the current
1082 *         instance is not positioned on an element or -1 in case of error.
1083 */
1084int
1085xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
1086	                int offset, int len) {
1087    if ((reader == NULL) || (reader->ctxt == NULL))
1088	return(-1);
1089    if (reader->ctxt->wellFormed != 1)
1090	return(-1);
1091
1092    if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1093	return(0);
1094    TODO
1095    return(0);
1096}
1097
1098/************************************************************************
1099 *									*
1100 *			Constructor and destructors			*
1101 *									*
1102 ************************************************************************/
1103/**
1104 * xmlNewTextReader:
1105 * @input: the xmlParserInputBufferPtr used to read data
1106 * @URI: the URI information for the source if available
1107 *
1108 * Create an xmlTextReader structure fed with @input
1109 *
1110 * Returns the new xmlTextReaderPtr or NULL in case of error
1111 */
1112xmlTextReaderPtr
1113xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
1114    xmlTextReaderPtr ret;
1115    int val;
1116
1117    if (input == NULL)
1118	return(NULL);
1119    ret = xmlMalloc(sizeof(xmlTextReader));
1120    if (ret == NULL) {
1121        xmlGenericError(xmlGenericErrorContext,
1122		"xmlNewTextReader : malloc failed\n");
1123	return(NULL);
1124    }
1125    memset(ret, 0, sizeof(xmlTextReader));
1126    ret->entTab = NULL;
1127    ret->entMax = 0;
1128    ret->entNr = 0;
1129    ret->input = input;
1130    ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
1131    if (ret->sax == NULL) {
1132	xmlFree(ret);
1133        xmlGenericError(xmlGenericErrorContext,
1134		"xmlNewTextReader : malloc failed\n");
1135	return(NULL);
1136    }
1137    memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
1138    ret->startElement = ret->sax->startElement;
1139    ret->sax->startElement = xmlTextReaderStartElement;
1140    ret->endElement = ret->sax->endElement;
1141    ret->sax->endElement = xmlTextReaderEndElement;
1142    ret->characters = ret->sax->characters;
1143    ret->sax->characters = xmlTextReaderCharacters;
1144    ret->cdataBlock = ret->sax->cdataBlock;
1145    ret->sax->cdataBlock = xmlTextReaderCDataBlock;
1146
1147    ret->mode = XML_TEXTREADER_MODE_INITIAL;
1148    ret->node = NULL;
1149    ret->curnode = NULL;
1150    val = xmlParserInputBufferRead(input, 4);
1151    if (val >= 4) {
1152	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
1153			(const char *) ret->input->buffer->content, 4, URI);
1154	ret->base = 0;
1155	ret->cur = 4;
1156    } else {
1157	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
1158	ret->base = 0;
1159	ret->cur = 0;
1160    }
1161    if (ret->ctxt == NULL) {
1162        xmlGenericError(xmlGenericErrorContext,
1163		"xmlNewTextReader : malloc failed\n");
1164	xmlFree(ret->sax);
1165	xmlFree(ret);
1166	return(NULL);
1167    }
1168    ret->ctxt->_private = ret;
1169    ret->ctxt->linenumbers = 1;
1170    ret->allocs = XML_TEXTREADER_CTXT;
1171    return(ret);
1172}
1173
1174/**
1175 * xmlNewTextReaderFilename:
1176 * @URI: the URI of the resource to process
1177 *
1178 * Create an xmlTextReader structure fed with the resource at @URI
1179 *
1180 * Returns the new xmlTextReaderPtr or NULL in case of error
1181 */
1182xmlTextReaderPtr
1183xmlNewTextReaderFilename(const char *URI) {
1184    xmlParserInputBufferPtr input;
1185    xmlTextReaderPtr ret;
1186    char *directory = NULL;
1187
1188    input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
1189    if (input == NULL)
1190	return(NULL);
1191    ret = xmlNewTextReader(input, URI);
1192    if (ret == NULL) {
1193	xmlFreeParserInputBuffer(input);
1194	return(NULL);
1195    }
1196    ret->allocs |= XML_TEXTREADER_INPUT;
1197    if (ret->ctxt->directory == NULL)
1198        directory = xmlParserGetDirectory(URI);
1199    if ((ret->ctxt->directory == NULL) && (directory != NULL))
1200        ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
1201    if (directory != NULL)
1202	xmlFree(directory);
1203    return(ret);
1204}
1205
1206/**
1207 * xmlFreeTextReader:
1208 * @reader:  the xmlTextReaderPtr
1209 *
1210 * Deallocate all the resources associated to the reader
1211 */
1212void
1213xmlFreeTextReader(xmlTextReaderPtr reader) {
1214    if (reader == NULL)
1215	return;
1216#ifdef LIBXML_SCHEMAS_ENABLED
1217    if (reader->rngSchemas != NULL) {
1218	xmlRelaxNGFree(reader->rngSchemas);
1219	reader->rngSchemas = NULL;
1220    }
1221    if (reader->rngValidCtxt != NULL) {
1222	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
1223	reader->rngValidCtxt = NULL;
1224    }
1225#endif
1226    if (reader->ctxt != NULL) {
1227	if (reader->ctxt->myDoc != NULL) {
1228	    xmlFreeDoc(reader->ctxt->myDoc);
1229	    reader->ctxt->myDoc = NULL;
1230	}
1231	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
1232	    (reader->ctxt->vctxt.vstateMax > 0)){
1233	    xmlFree(reader->ctxt->vctxt.vstateTab);
1234	    reader->ctxt->vctxt.vstateTab = 0;
1235	    reader->ctxt->vctxt.vstateMax = 0;
1236	}
1237	if (reader->allocs & XML_TEXTREADER_CTXT)
1238	    xmlFreeParserCtxt(reader->ctxt);
1239    }
1240    if (reader->sax != NULL)
1241	xmlFree(reader->sax);
1242    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT))
1243	xmlFreeParserInputBuffer(reader->input);
1244    if (reader->faketext != NULL) {
1245	xmlFreeNode(reader->faketext);
1246    }
1247    if (reader->entTab != NULL)
1248	xmlFree(reader->entTab);
1249    xmlFree(reader);
1250}
1251
1252/************************************************************************
1253 *									*
1254 *			Methods for XmlTextReader			*
1255 *									*
1256 ************************************************************************/
1257/**
1258 * xmlTextReaderClose:
1259 * @reader:  the xmlTextReaderPtr used
1260 *
1261 * This method releases any resources allocated by the current instance
1262 * changes the state to Closed and close any underlying input.
1263 *
1264 * Returns 0 or -1 in case of error
1265 */
1266int
1267xmlTextReaderClose(xmlTextReaderPtr reader) {
1268    if (reader == NULL)
1269	return(-1);
1270    reader->node = NULL;
1271    reader->curnode = NULL;
1272    reader->mode = XML_TEXTREADER_MODE_CLOSED;
1273    if (reader->ctxt != NULL) {
1274	if (reader->ctxt->myDoc != NULL) {
1275	    xmlFreeDoc(reader->ctxt->myDoc);
1276	    reader->ctxt->myDoc = NULL;
1277	}
1278	if (reader->allocs & XML_TEXTREADER_CTXT) {
1279	    xmlFreeParserCtxt(reader->ctxt);
1280	    reader->allocs -= XML_TEXTREADER_CTXT;
1281	}
1282    }
1283    if (reader->sax != NULL) {
1284        xmlFree(reader->sax);
1285	reader->sax = NULL;
1286    }
1287    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT)) {
1288	xmlFreeParserInputBuffer(reader->input);
1289	reader->allocs -= XML_TEXTREADER_INPUT;
1290    }
1291    return(0);
1292}
1293
1294/**
1295 * xmlTextReaderGetAttributeNo:
1296 * @reader:  the xmlTextReaderPtr used
1297 * @no: the zero-based index of the attribute relative to the containing element
1298 *
1299 * Provides the value of the attribute with the specified index relative
1300 * to the containing element.
1301 *
1302 * Returns a string containing the value of the specified attribute, or NULL
1303 *    in case of error. The string must be deallocated by the caller.
1304 */
1305xmlChar *
1306xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
1307    xmlChar *ret;
1308    int i;
1309    xmlAttrPtr cur;
1310    xmlNsPtr ns;
1311
1312    if (reader == NULL)
1313	return(NULL);
1314    if (reader->node == NULL)
1315	return(NULL);
1316    if (reader->curnode != NULL)
1317	return(NULL);
1318    /* TODO: handle the xmlDecl */
1319    if (reader->node->type != XML_ELEMENT_NODE)
1320	return(NULL);
1321
1322    ns = reader->node->nsDef;
1323    for (i = 0;(i < no) && (ns != NULL);i++) {
1324	ns = ns->next;
1325    }
1326    if (ns != NULL)
1327	return(xmlStrdup(ns->href));
1328
1329    cur = reader->node->properties;
1330    if (cur == NULL)
1331	return(NULL);
1332    for (;i < no;i++) {
1333	cur = cur->next;
1334	if (cur == NULL)
1335	    return(NULL);
1336    }
1337    /* TODO walk the DTD if present */
1338
1339    ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
1340    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
1341    return(ret);
1342}
1343
1344/**
1345 * xmlTextReaderGetAttribute:
1346 * @reader:  the xmlTextReaderPtr used
1347 * @name: the qualified name of the attribute.
1348 *
1349 * Provides the value of the attribute with the specified qualified name.
1350 *
1351 * Returns a string containing the value of the specified attribute, or NULL
1352 *    in case of error. The string must be deallocated by the caller.
1353 */
1354xmlChar *
1355xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1356    xmlChar *prefix = NULL;
1357    xmlChar *localname;
1358    xmlNsPtr ns;
1359    xmlChar *ret = NULL;
1360
1361    if ((reader == NULL) || (name == NULL))
1362	return(NULL);
1363    if (reader->node == NULL)
1364	return(NULL);
1365    if (reader->curnode != NULL)
1366	return(NULL);
1367
1368    /* TODO: handle the xmlDecl */
1369    if (reader->node->type != XML_ELEMENT_NODE)
1370	return(NULL);
1371
1372    localname = xmlSplitQName2(name, &prefix);
1373    if (localname == NULL)
1374	return(xmlGetProp(reader->node, name));
1375
1376    ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1377    if (ns != NULL)
1378        ret = xmlGetNsProp(reader->node, localname, ns->href);
1379
1380    if (localname != NULL)
1381        xmlFree(localname);
1382    if (prefix != NULL)
1383        xmlFree(prefix);
1384    return(ret);
1385}
1386
1387
1388/**
1389 * xmlTextReaderGetAttributeNs:
1390 * @reader:  the xmlTextReaderPtr used
1391 * @localName: the local name of the attribute.
1392 * @namespaceURI: the namespace URI of the attribute.
1393 *
1394 * Provides the value of the specified attribute
1395 *
1396 * Returns a string containing the value of the specified attribute, or NULL
1397 *    in case of error. The string must be deallocated by the caller.
1398 */
1399xmlChar *
1400xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
1401			    const xmlChar *namespaceURI) {
1402    if ((reader == NULL) || (localName == NULL))
1403	return(NULL);
1404    if (reader->node == NULL)
1405	return(NULL);
1406    if (reader->curnode != NULL)
1407	return(NULL);
1408
1409    /* TODO: handle the xmlDecl */
1410    if (reader->node->type != XML_ELEMENT_NODE)
1411	return(NULL);
1412
1413    return(xmlGetNsProp(reader->node, localName, namespaceURI));
1414}
1415
1416/**
1417 * xmlTextReaderGetRemainder:
1418 * @reader:  the xmlTextReaderPtr used
1419 *
1420 * Method to get the remainder of the buffered XML. this method stops the
1421 * parser, set its state to End Of File and return the input stream with
1422 * what is left that the parser did not use.
1423 *
1424 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
1425 *    in case of error.
1426 */
1427xmlParserInputBufferPtr
1428xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
1429    xmlParserInputBufferPtr ret = NULL;
1430
1431    if (reader == NULL)
1432	return(NULL);
1433    if (reader->node == NULL)
1434	return(NULL);
1435
1436    reader->node = NULL;
1437    reader->curnode = NULL;
1438    reader->mode = XML_TEXTREADER_MODE_EOF;
1439    if (reader->ctxt != NULL) {
1440	if (reader->ctxt->myDoc != NULL) {
1441	    xmlFreeDoc(reader->ctxt->myDoc);
1442	    reader->ctxt->myDoc = NULL;
1443	}
1444	if (reader->allocs & XML_TEXTREADER_CTXT) {
1445	    xmlFreeParserCtxt(reader->ctxt);
1446	    reader->allocs -= XML_TEXTREADER_CTXT;
1447	}
1448    }
1449    if (reader->sax != NULL) {
1450        xmlFree(reader->sax);
1451	reader->sax = NULL;
1452    }
1453    if (reader->allocs & XML_TEXTREADER_INPUT) {
1454	ret = reader->input;
1455	reader->allocs -= XML_TEXTREADER_INPUT;
1456    } else {
1457	/*
1458	 * Hum, one may need to duplicate the data structure because
1459	 * without reference counting the input may be freed twice:
1460	 *   - by the layer which allocated it.
1461	 *   - by the layer to which would have been returned to.
1462	 */
1463	TODO
1464	return(NULL);
1465    }
1466    return(ret);
1467}
1468
1469/**
1470 * xmlTextReaderLookupNamespace:
1471 * @reader:  the xmlTextReaderPtr used
1472 * @prefix: the prefix whose namespace URI is to be resolved. To return
1473 *          the default namespace, specify NULL
1474 *
1475 * Resolves a namespace prefix in the scope of the current element.
1476 *
1477 * Returns a string containing the namespace URI to which the prefix maps
1478 *    or NULL in case of error. The string must be deallocated by the caller.
1479 */
1480xmlChar *
1481xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
1482    xmlNsPtr ns;
1483
1484    if (reader == NULL)
1485	return(NULL);
1486    if (reader->node == NULL)
1487	return(NULL);
1488
1489    ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1490    if (ns == NULL)
1491	return(NULL);
1492    return(xmlStrdup(ns->href));
1493}
1494
1495/**
1496 * xmlTextReaderMoveToAttributeNo:
1497 * @reader:  the xmlTextReaderPtr used
1498 * @no: the zero-based index of the attribute relative to the containing
1499 *      element.
1500 *
1501 * Moves the position of the current instance to the attribute with
1502 * the specified index relative to the containing element.
1503 *
1504 * Returns 1 in case of success, -1 in case of error, 0 if not found
1505 */
1506int
1507xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
1508    int i;
1509    xmlAttrPtr cur;
1510    xmlNsPtr ns;
1511
1512    if (reader == NULL)
1513	return(-1);
1514    if (reader->node == NULL)
1515	return(-1);
1516    /* TODO: handle the xmlDecl */
1517    if (reader->node->type != XML_ELEMENT_NODE)
1518	return(-1);
1519
1520    reader->curnode = NULL;
1521
1522    ns = reader->node->nsDef;
1523    for (i = 0;(i < no) && (ns != NULL);i++) {
1524	ns = ns->next;
1525    }
1526    if (ns != NULL) {
1527	reader->curnode = (xmlNodePtr) ns;
1528	return(1);
1529    }
1530
1531    cur = reader->node->properties;
1532    if (cur == NULL)
1533	return(0);
1534    for (;i < no;i++) {
1535	cur = cur->next;
1536	if (cur == NULL)
1537	    return(0);
1538    }
1539    /* TODO walk the DTD if present */
1540
1541    reader->curnode = (xmlNodePtr) cur;
1542    return(1);
1543}
1544
1545/**
1546 * xmlTextReaderMoveToAttribute:
1547 * @reader:  the xmlTextReaderPtr used
1548 * @name: the qualified name of the attribute.
1549 *
1550 * Moves the position of the current instance to the attribute with
1551 * the specified qualified name.
1552 *
1553 * Returns 1 in case of success, -1 in case of error, 0 if not found
1554 */
1555int
1556xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1557    xmlChar *prefix = NULL;
1558    xmlChar *localname;
1559    xmlNsPtr ns;
1560    xmlAttrPtr prop;
1561
1562    if ((reader == NULL) || (name == NULL))
1563	return(-1);
1564    if (reader->node == NULL)
1565	return(-1);
1566
1567    /* TODO: handle the xmlDecl */
1568    if (reader->node->type != XML_ELEMENT_NODE)
1569	return(0);
1570
1571    localname = xmlSplitQName2(name, &prefix);
1572    if (localname == NULL) {
1573	/*
1574	 * Namespace default decl
1575	 */
1576	if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1577	    ns = reader->node->nsDef;
1578	    while (ns != NULL) {
1579		if (ns->prefix == NULL) {
1580		    reader->curnode = (xmlNodePtr) ns;
1581		    return(1);
1582		}
1583		ns = ns->next;
1584	    }
1585	    return(0);
1586	}
1587
1588	prop = reader->node->properties;
1589	while (prop != NULL) {
1590	    /*
1591	     * One need to have
1592	     *   - same attribute names
1593	     *   - and the attribute carrying that namespace
1594	     */
1595	    if ((xmlStrEqual(prop->name, name)) &&
1596		((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
1597		reader->curnode = (xmlNodePtr) prop;
1598		return(1);
1599	    }
1600	    prop = prop->next;
1601	}
1602	return(0);
1603    }
1604
1605    /*
1606     * Namespace default decl
1607     */
1608    if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
1609	ns = reader->node->nsDef;
1610	while (ns != NULL) {
1611	    if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
1612		reader->curnode = (xmlNodePtr) ns;
1613		goto found;
1614	    }
1615	    ns = ns->next;
1616	}
1617	goto not_found;
1618    }
1619    prop = reader->node->properties;
1620    while (prop != NULL) {
1621	/*
1622	 * One need to have
1623	 *   - same attribute names
1624	 *   - and the attribute carrying that namespace
1625	 */
1626	if ((xmlStrEqual(prop->name, localname)) &&
1627	    (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
1628	    reader->curnode = (xmlNodePtr) prop;
1629	    goto found;
1630	}
1631	prop = prop->next;
1632    }
1633not_found:
1634    if (localname != NULL)
1635        xmlFree(localname);
1636    if (prefix != NULL)
1637        xmlFree(prefix);
1638    return(0);
1639
1640found:
1641    if (localname != NULL)
1642        xmlFree(localname);
1643    if (prefix != NULL)
1644        xmlFree(prefix);
1645    return(1);
1646}
1647
1648/**
1649 * xmlTextReaderMoveToAttributeNs:
1650 * @reader:  the xmlTextReaderPtr used
1651 * @localName:  the local name of the attribute.
1652 * @namespaceURI:  the namespace URI of the attribute.
1653 *
1654 * Moves the position of the current instance to the attribute with the
1655 * specified local name and namespace URI.
1656 *
1657 * Returns 1 in case of success, -1 in case of error, 0 if not found
1658 */
1659int
1660xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1661	const xmlChar *localName, const xmlChar *namespaceURI) {
1662    xmlAttrPtr prop;
1663    xmlNodePtr node;
1664
1665    if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1666	return(-1);
1667    if (reader->node == NULL)
1668	return(-1);
1669    if (reader->node->type != XML_ELEMENT_NODE)
1670	return(0);
1671    node = reader->node;
1672
1673    /*
1674     * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1675     * namespace name associated to "xmlns"
1676     */
1677    prop = node->properties;
1678    while (prop != NULL) {
1679	/*
1680	 * One need to have
1681	 *   - same attribute names
1682	 *   - and the attribute carrying that namespace
1683	 */
1684        if (xmlStrEqual(prop->name, localName) &&
1685	    ((prop->ns != NULL) &&
1686	     (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1687	    reader->curnode = (xmlNodePtr) prop;
1688	    return(1);
1689        }
1690	prop = prop->next;
1691    }
1692    return(0);
1693}
1694
1695/**
1696 * xmlTextReaderMoveToFirstAttribute:
1697 * @reader:  the xmlTextReaderPtr used
1698 *
1699 * Moves the position of the current instance to the first attribute
1700 * associated with the current node.
1701 *
1702 * Returns 1 in case of success, -1 in case of error, 0 if not found
1703 */
1704int
1705xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1706    if (reader == NULL)
1707	return(-1);
1708    if (reader->node == NULL)
1709	return(-1);
1710    if (reader->node->type != XML_ELEMENT_NODE)
1711	return(0);
1712
1713    if (reader->node->nsDef != NULL) {
1714	reader->curnode = (xmlNodePtr) reader->node->nsDef;
1715	return(1);
1716    }
1717    if (reader->node->properties != NULL) {
1718	reader->curnode = (xmlNodePtr) reader->node->properties;
1719	return(1);
1720    }
1721    return(0);
1722}
1723
1724/**
1725 * xmlTextReaderMoveToNextAttribute:
1726 * @reader:  the xmlTextReaderPtr used
1727 *
1728 * Moves the position of the current instance to the next attribute
1729 * associated with the current node.
1730 *
1731 * Returns 1 in case of success, -1 in case of error, 0 if not found
1732 */
1733int
1734xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1735    if (reader == NULL)
1736	return(-1);
1737    if (reader->node == NULL)
1738	return(-1);
1739    if (reader->node->type != XML_ELEMENT_NODE)
1740	return(0);
1741    if (reader->curnode == NULL)
1742	return(xmlTextReaderMoveToFirstAttribute(reader));
1743
1744    if (reader->curnode->type == XML_NAMESPACE_DECL) {
1745	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1746	if (ns->next != NULL) {
1747	    reader->curnode = (xmlNodePtr) ns->next;
1748	    return(1);
1749	}
1750	if (reader->node->properties != NULL) {
1751	    reader->curnode = (xmlNodePtr) reader->node->properties;
1752	    return(1);
1753	}
1754	return(0);
1755    } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1756	       (reader->curnode->next != NULL)) {
1757	reader->curnode = reader->curnode->next;
1758	return(1);
1759    }
1760    return(0);
1761}
1762
1763/**
1764 * xmlTextReaderMoveToElement:
1765 * @reader:  the xmlTextReaderPtr used
1766 *
1767 * Moves the position of the current instance to the node that
1768 * contains the current Attribute  node.
1769 *
1770 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1771 */
1772int
1773xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
1774    if (reader == NULL)
1775	return(-1);
1776    if (reader->node == NULL)
1777	return(-1);
1778    if (reader->node->type != XML_ELEMENT_NODE)
1779	return(0);
1780    if (reader->curnode != NULL) {
1781	reader->curnode = NULL;
1782	return(1);
1783    }
1784    return(0);
1785}
1786
1787/**
1788 * xmlTextReaderReadAttributeValue:
1789 * @reader:  the xmlTextReaderPtr used
1790 *
1791 * Parses an attribute value into one or more Text and EntityReference nodes.
1792 *
1793 * Returns 1 in case of success, 0 if the reader was not positionned on an
1794 *         ttribute node or all the attribute values have been read, or -1
1795 *         in case of error.
1796 */
1797int
1798xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1799    if (reader == NULL)
1800	return(-1);
1801    if (reader->node == NULL)
1802	return(-1);
1803    if (reader->curnode == NULL)
1804	return(0);
1805    if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1806	if (reader->curnode->children == NULL)
1807	    return(0);
1808	reader->curnode = reader->curnode->children;
1809    } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1810	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1811
1812	if (reader->faketext == NULL) {
1813	    reader->faketext = xmlNewDocText(reader->node->doc,
1814		                             ns->href);
1815	} else {
1816            if (reader->faketext->content != NULL)
1817		xmlFree(reader->faketext->content);
1818	    reader->faketext->content = xmlStrdup(ns->href);
1819	}
1820	reader->curnode = reader->faketext;
1821    } else {
1822	if (reader->curnode->next == NULL)
1823	    return(0);
1824	reader->curnode = reader->curnode->next;
1825    }
1826    return(1);
1827}
1828
1829/************************************************************************
1830 *									*
1831 *			Acces API to the current node			*
1832 *									*
1833 ************************************************************************/
1834/**
1835 * xmlTextReaderAttributeCount:
1836 * @reader:  the xmlTextReaderPtr used
1837 *
1838 * Provides the number of attributes of the current node
1839 *
1840 * Returns 0 i no attributes, -1 in case of error or the attribute count
1841 */
1842int
1843xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1844    int ret;
1845    xmlAttrPtr attr;
1846    xmlNsPtr ns;
1847    xmlNodePtr node;
1848
1849    if (reader == NULL)
1850	return(-1);
1851    if (reader->node == NULL)
1852	return(0);
1853
1854    if (reader->curnode != NULL)
1855	node = reader->curnode;
1856    else
1857	node = reader->node;
1858
1859    if (node->type != XML_ELEMENT_NODE)
1860	return(0);
1861    if ((reader->state == XML_TEXTREADER_END) ||
1862	(reader->state == XML_TEXTREADER_BACKTRACK))
1863	return(0);
1864    ret = 0;
1865    attr = node->properties;
1866    while (attr != NULL) {
1867	ret++;
1868	attr = attr->next;
1869    }
1870    ns = node->nsDef;
1871    while (ns != NULL) {
1872	ret++;
1873	ns = ns->next;
1874    }
1875    return(ret);
1876}
1877
1878/**
1879 * xmlTextReaderNodeType:
1880 * @reader:  the xmlTextReaderPtr used
1881 *
1882 * Get the node type of the current node
1883 * Reference:
1884 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1885 *
1886 * Returns the xmlNodeType of the current node or -1 in case of error
1887 */
1888int
1889xmlTextReaderNodeType(xmlTextReaderPtr reader) {
1890    xmlNodePtr node;
1891    if (reader == NULL)
1892	return(-1);
1893    if (reader->node == NULL)
1894	return(0);
1895    if (reader->curnode != NULL)
1896	node = reader->curnode;
1897    else
1898	node = reader->node;
1899    switch (node->type) {
1900        case XML_ELEMENT_NODE:
1901	    if ((reader->state == XML_TEXTREADER_END) ||
1902		(reader->state == XML_TEXTREADER_BACKTRACK))
1903		return(15);
1904	    return(1);
1905        case XML_NAMESPACE_DECL:
1906        case XML_ATTRIBUTE_NODE:
1907	    return(2);
1908        case XML_TEXT_NODE:
1909	    return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1910        case XML_CDATA_SECTION_NODE:
1911	    return(4);
1912        case XML_ENTITY_REF_NODE:
1913	    return(5);
1914        case XML_ENTITY_NODE:
1915	    return(6);
1916        case XML_PI_NODE:
1917	    return(7);
1918        case XML_COMMENT_NODE:
1919	    return(8);
1920        case XML_DOCUMENT_NODE:
1921        case XML_HTML_DOCUMENT_NODE:
1922#ifdef LIBXML_DOCB_ENABLED
1923        case XML_DOCB_DOCUMENT_NODE:
1924#endif
1925	    return(9);
1926        case XML_DOCUMENT_FRAG_NODE:
1927	    return(11);
1928        case XML_NOTATION_NODE:
1929	    return(12);
1930        case XML_DOCUMENT_TYPE_NODE:
1931        case XML_DTD_NODE:
1932	    return(10);
1933
1934        case XML_ELEMENT_DECL:
1935        case XML_ATTRIBUTE_DECL:
1936        case XML_ENTITY_DECL:
1937        case XML_XINCLUDE_START:
1938        case XML_XINCLUDE_END:
1939	    return(0);
1940    }
1941    return(-1);
1942}
1943
1944/**
1945 * xmlTextReaderIsEmptyElement:
1946 * @reader:  the xmlTextReaderPtr used
1947 *
1948 * Check if the current node is empty
1949 *
1950 * Returns 1 if empty, 0 if not and -1 in case of error
1951 */
1952int
1953xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1954    if ((reader == NULL) || (reader->node == NULL))
1955	return(-1);
1956    if (reader->node->type != XML_ELEMENT_NODE)
1957	return(0);
1958    if (reader->curnode != NULL)
1959	return(0);
1960    if (reader->node->children != NULL)
1961	return(0);
1962    if (reader->state == XML_TEXTREADER_END)
1963	return(0);
1964    return(reader->node->_private == (void *)xmlTextReaderIsEmpty);
1965}
1966
1967/**
1968 * xmlTextReaderLocalName:
1969 * @reader:  the xmlTextReaderPtr used
1970 *
1971 * The local name of the node.
1972 *
1973 * Returns the local name or NULL if not available
1974 */
1975xmlChar *
1976xmlTextReaderLocalName(xmlTextReaderPtr reader) {
1977    xmlNodePtr node;
1978    if ((reader == NULL) || (reader->node == NULL))
1979	return(NULL);
1980    if (reader->curnode != NULL)
1981	node = reader->curnode;
1982    else
1983	node = reader->node;
1984    if (node->type == XML_NAMESPACE_DECL) {
1985	xmlNsPtr ns = (xmlNsPtr) node;
1986	if (ns->prefix == NULL)
1987	    return(xmlStrdup(BAD_CAST "xmlns"));
1988	else
1989	    return(xmlStrdup(ns->prefix));
1990    }
1991    if ((node->type != XML_ELEMENT_NODE) &&
1992	(node->type != XML_ATTRIBUTE_NODE))
1993	return(xmlTextReaderName(reader));
1994    return(xmlStrdup(node->name));
1995}
1996
1997/**
1998 * xmlTextReaderName:
1999 * @reader:  the xmlTextReaderPtr used
2000 *
2001 * The qualified name of the node, equal to Prefix :LocalName.
2002 *
2003 * Returns the local name or NULL if not available
2004 */
2005xmlChar *
2006xmlTextReaderName(xmlTextReaderPtr reader) {
2007    xmlNodePtr node;
2008    xmlChar *ret;
2009
2010    if ((reader == NULL) || (reader->node == NULL))
2011	return(NULL);
2012    if (reader->curnode != NULL)
2013	node = reader->curnode;
2014    else
2015	node = reader->node;
2016    switch (node->type) {
2017        case XML_ELEMENT_NODE:
2018        case XML_ATTRIBUTE_NODE:
2019	    if ((node->ns == NULL) ||
2020		(node->ns->prefix == NULL))
2021		return(xmlStrdup(node->name));
2022
2023	    ret = xmlStrdup(node->ns->prefix);
2024	    ret = xmlStrcat(ret, BAD_CAST ":");
2025	    ret = xmlStrcat(ret, node->name);
2026	    return(ret);
2027        case XML_TEXT_NODE:
2028	    return(xmlStrdup(BAD_CAST "#text"));
2029        case XML_CDATA_SECTION_NODE:
2030	    return(xmlStrdup(BAD_CAST "#cdata-section"));
2031        case XML_ENTITY_NODE:
2032        case XML_ENTITY_REF_NODE:
2033	    return(xmlStrdup(node->name));
2034        case XML_PI_NODE:
2035	    return(xmlStrdup(node->name));
2036        case XML_COMMENT_NODE:
2037	    return(xmlStrdup(BAD_CAST "#comment"));
2038        case XML_DOCUMENT_NODE:
2039        case XML_HTML_DOCUMENT_NODE:
2040#ifdef LIBXML_DOCB_ENABLED
2041        case XML_DOCB_DOCUMENT_NODE:
2042#endif
2043	    return(xmlStrdup(BAD_CAST "#document"));
2044        case XML_DOCUMENT_FRAG_NODE:
2045	    return(xmlStrdup(BAD_CAST "#document-fragment"));
2046        case XML_NOTATION_NODE:
2047	    return(xmlStrdup(node->name));
2048        case XML_DOCUMENT_TYPE_NODE:
2049        case XML_DTD_NODE:
2050	    return(xmlStrdup(node->name));
2051        case XML_NAMESPACE_DECL: {
2052	    xmlNsPtr ns = (xmlNsPtr) node;
2053
2054	    ret = xmlStrdup(BAD_CAST "xmlns");
2055	    if (ns->prefix == NULL)
2056		return(ret);
2057	    ret = xmlStrcat(ret, BAD_CAST ":");
2058	    ret = xmlStrcat(ret, ns->prefix);
2059	    return(ret);
2060	}
2061
2062        case XML_ELEMENT_DECL:
2063        case XML_ATTRIBUTE_DECL:
2064        case XML_ENTITY_DECL:
2065        case XML_XINCLUDE_START:
2066        case XML_XINCLUDE_END:
2067	    return(NULL);
2068    }
2069    return(NULL);
2070}
2071
2072/**
2073 * xmlTextReaderPrefix:
2074 * @reader:  the xmlTextReaderPtr used
2075 *
2076 * A shorthand reference to the namespace associated with the node.
2077 *
2078 * Returns the prefix or NULL if not available
2079 */
2080xmlChar *
2081xmlTextReaderPrefix(xmlTextReaderPtr reader) {
2082    xmlNodePtr node;
2083    if ((reader == NULL) || (reader->node == NULL))
2084	return(NULL);
2085    if (reader->curnode != NULL)
2086	node = reader->curnode;
2087    else
2088	node = reader->node;
2089    if (node->type == XML_NAMESPACE_DECL) {
2090	xmlNsPtr ns = (xmlNsPtr) node;
2091	if (ns->prefix == NULL)
2092	    return(NULL);
2093	return(xmlStrdup(BAD_CAST "xmlns"));
2094    }
2095    if ((node->type != XML_ELEMENT_NODE) &&
2096	(node->type != XML_ATTRIBUTE_NODE))
2097	return(NULL);
2098    if ((node->ns != NULL) && (node->ns->prefix != NULL))
2099	return(xmlStrdup(node->ns->prefix));
2100    return(NULL);
2101}
2102
2103/**
2104 * xmlTextReaderNamespaceUri:
2105 * @reader:  the xmlTextReaderPtr used
2106 *
2107 * The URI defining the namespace associated with the node.
2108 *
2109 * Returns the namespace URI or NULL if not available
2110 */
2111xmlChar *
2112xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
2113    xmlNodePtr node;
2114    if ((reader == NULL) || (reader->node == NULL))
2115	return(NULL);
2116    if (reader->curnode != NULL)
2117	node = reader->curnode;
2118    else
2119	node = reader->node;
2120    if (node->type == XML_NAMESPACE_DECL)
2121	return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
2122    if ((node->type != XML_ELEMENT_NODE) &&
2123	(node->type != XML_ATTRIBUTE_NODE))
2124	return(NULL);
2125    if (node->ns != NULL)
2126	return(xmlStrdup(node->ns->href));
2127    return(NULL);
2128}
2129
2130/**
2131 * xmlTextReaderBaseUri:
2132 * @reader:  the xmlTextReaderPtr used
2133 *
2134 * The base URI of the node.
2135 *
2136 * Returns the base URI or NULL if not available
2137 */
2138xmlChar *
2139xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
2140    if ((reader == NULL) || (reader->node == NULL))
2141	return(NULL);
2142    return(xmlNodeGetBase(NULL, reader->node));
2143}
2144
2145/**
2146 * xmlTextReaderDepth:
2147 * @reader:  the xmlTextReaderPtr used
2148 *
2149 * The depth of the node in the tree.
2150 *
2151 * Returns the depth or -1 in case of error
2152 */
2153int
2154xmlTextReaderDepth(xmlTextReaderPtr reader) {
2155    if (reader == NULL)
2156	return(-1);
2157    if (reader->node == NULL)
2158	return(0);
2159
2160    if (reader->curnode != NULL) {
2161	if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
2162	    (reader->curnode->type == XML_NAMESPACE_DECL))
2163	    return(reader->depth + 1);
2164	return(reader->depth + 2);
2165    }
2166    return(reader->depth);
2167}
2168
2169/**
2170 * xmlTextReaderHasAttributes:
2171 * @reader:  the xmlTextReaderPtr used
2172 *
2173 * Whether the node has attributes.
2174 *
2175 * Returns 1 if true, 0 if false, and -1 in case or error
2176 */
2177int
2178xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
2179    xmlNodePtr node;
2180    if (reader == NULL)
2181	return(-1);
2182    if (reader->node == NULL)
2183	return(0);
2184    if (reader->curnode != NULL)
2185	node = reader->curnode;
2186    else
2187	node = reader->node;
2188
2189    if ((node->type == XML_ELEMENT_NODE) &&
2190	(node->properties != NULL))
2191	return(1);
2192    /* TODO: handle the xmlDecl */
2193    return(0);
2194}
2195
2196/**
2197 * xmlTextReaderHasValue:
2198 * @reader:  the xmlTextReaderPtr used
2199 *
2200 * Whether the node can have a text value.
2201 *
2202 * Returns 1 if true, 0 if false, and -1 in case or error
2203 */
2204int
2205xmlTextReaderHasValue(xmlTextReaderPtr reader) {
2206    xmlNodePtr node;
2207    if (reader == NULL)
2208	return(-1);
2209    if (reader->node == NULL)
2210	return(0);
2211    if (reader->curnode != NULL)
2212	node = reader->curnode;
2213    else
2214	node = reader->node;
2215
2216    switch (node->type) {
2217        case XML_ATTRIBUTE_NODE:
2218        case XML_TEXT_NODE:
2219        case XML_CDATA_SECTION_NODE:
2220        case XML_PI_NODE:
2221        case XML_COMMENT_NODE:
2222        case XML_NAMESPACE_DECL:
2223	    return(1);
2224	default:
2225	    break;
2226    }
2227    return(0);
2228}
2229
2230/**
2231 * xmlTextReaderValue:
2232 * @reader:  the xmlTextReaderPtr used
2233 *
2234 * Provides the text value of the node if present
2235 *
2236 * Returns the string or NULL if not available. The retsult must be deallocated
2237 *     with xmlFree()
2238 */
2239xmlChar *
2240xmlTextReaderValue(xmlTextReaderPtr reader) {
2241    xmlNodePtr node;
2242    if (reader == NULL)
2243	return(NULL);
2244    if (reader->node == NULL)
2245	return(NULL);
2246    if (reader->curnode != NULL)
2247	node = reader->curnode;
2248    else
2249	node = reader->node;
2250
2251    switch (node->type) {
2252        case XML_NAMESPACE_DECL:
2253	    return(xmlStrdup(((xmlNsPtr) node)->href));
2254        case XML_ATTRIBUTE_NODE:{
2255	    xmlAttrPtr attr = (xmlAttrPtr) node;
2256
2257	    if (attr->parent != NULL)
2258		return (xmlNodeListGetString
2259			(attr->parent->doc, attr->children, 1));
2260	    else
2261		return (xmlNodeListGetString(NULL, attr->children, 1));
2262	    break;
2263	}
2264        case XML_TEXT_NODE:
2265        case XML_CDATA_SECTION_NODE:
2266        case XML_PI_NODE:
2267        case XML_COMMENT_NODE:
2268            if (node->content != NULL)
2269                return (xmlStrdup(node->content));
2270	default:
2271	    break;
2272    }
2273    return(NULL);
2274}
2275
2276/**
2277 * xmlTextReaderIsDefault:
2278 * @reader:  the xmlTextReaderPtr used
2279 *
2280 * Whether an Attribute  node was generated from the default value
2281 * defined in the DTD or schema.
2282 *
2283 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
2284 */
2285int
2286xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
2287    if (reader == NULL)
2288	return(-1);
2289    return(0);
2290}
2291
2292/**
2293 * xmlTextReaderQuoteChar:
2294 * @reader:  the xmlTextReaderPtr used
2295 *
2296 * The quotation mark character used to enclose the value of an attribute.
2297 *
2298 * Returns " or ' and -1 in case of error
2299 */
2300int
2301xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
2302    if (reader == NULL)
2303	return(-1);
2304    /* TODO maybe lookup the attribute value for " first */
2305    return((int) '"');
2306}
2307
2308/**
2309 * xmlTextReaderXmlLang:
2310 * @reader:  the xmlTextReaderPtr used
2311 *
2312 * The xml:lang scope within which the node resides.
2313 *
2314 * Returns the xml:lang value or NULL if none exists.
2315 */
2316xmlChar *
2317xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
2318    if (reader == NULL)
2319	return(NULL);
2320    if (reader->node == NULL)
2321	return(NULL);
2322    return(xmlNodeGetLang(reader->node));
2323}
2324
2325/**
2326 * xmlTextReaderNormalization:
2327 * @reader:  the xmlTextReaderPtr used
2328 *
2329 * The value indicating whether to normalize white space and attribute values.
2330 * Since attribute value and end of line normalizations are a MUST in the XML
2331 * specification only the value true is accepted. The broken bahaviour of
2332 * accepting out of range character entities like &#0; is of course not
2333 * supported either.
2334 *
2335 * Returns 1 or -1 in case of error.
2336 */
2337int
2338xmlTextReaderNormalization(xmlTextReaderPtr reader) {
2339    if (reader == NULL)
2340	return(-1);
2341    return(1);
2342}
2343
2344/************************************************************************
2345 *									*
2346 *			Extensions to the base APIs			*
2347 *									*
2348 ************************************************************************/
2349
2350/**
2351 * xmlTextReaderSetParserProp:
2352 * @reader:  the xmlTextReaderPtr used
2353 * @prop:  the xmlParserProperties to set
2354 * @value:  usually 0 or 1 to (de)activate it
2355 *
2356 * Change the parser processing behaviour by changing some of its internal
2357 * properties. Note that some properties can only be changed before any
2358 * read has been done.
2359 *
2360 * Returns 0 if the call was successful, or -1 in case of error
2361 */
2362int
2363xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
2364    xmlParserProperties p = (xmlParserProperties) prop;
2365    xmlParserCtxtPtr ctxt;
2366
2367    if ((reader == NULL) || (reader->ctxt == NULL))
2368	return(-1);
2369    ctxt = reader->ctxt;
2370
2371    switch (p) {
2372        case XML_PARSER_LOADDTD:
2373	    if (value != 0) {
2374		if (ctxt->loadsubset == 0) {
2375		    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2376			return(-1);
2377		    ctxt->loadsubset = XML_DETECT_IDS;
2378		}
2379	    } else {
2380		ctxt->loadsubset = 0;
2381	    }
2382	    return(0);
2383        case XML_PARSER_DEFAULTATTRS:
2384	    if (value != 0) {
2385		ctxt->loadsubset |= XML_COMPLETE_ATTRS;
2386	    } else {
2387		if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2388		    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
2389	    }
2390	    return(0);
2391        case XML_PARSER_VALIDATE:
2392	    if (value != 0) {
2393		ctxt->validate = 1;
2394		reader->validate = XML_TEXTREADER_VALIDATE_DTD;
2395	    } else {
2396		ctxt->validate = 0;
2397	    }
2398	    return(0);
2399        case XML_PARSER_SUBST_ENTITIES:
2400	    if (value != 0) {
2401		ctxt->replaceEntities = 1;
2402	    } else {
2403		ctxt->replaceEntities = 0;
2404	    }
2405	    return(0);
2406    }
2407    return(-1);
2408}
2409
2410/**
2411 * xmlTextReaderGetParserProp:
2412 * @reader:  the xmlTextReaderPtr used
2413 * @prop:  the xmlParserProperties to get
2414 *
2415 * Read the parser internal property.
2416 *
2417 * Returns the value, usually 0 or 1, or -1 in case of error.
2418 */
2419int
2420xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
2421    xmlParserProperties p = (xmlParserProperties) prop;
2422    xmlParserCtxtPtr ctxt;
2423
2424    if ((reader == NULL) || (reader->ctxt == NULL))
2425	return(-1);
2426    ctxt = reader->ctxt;
2427
2428    switch (p) {
2429        case XML_PARSER_LOADDTD:
2430	    if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
2431		return(1);
2432	    return(0);
2433        case XML_PARSER_DEFAULTATTRS:
2434	    if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2435		return(1);
2436	    return(0);
2437        case XML_PARSER_VALIDATE:
2438	    return(reader->validate);
2439	case XML_PARSER_SUBST_ENTITIES:
2440	    return(ctxt->replaceEntities);
2441    }
2442    return(-1);
2443}
2444
2445/**
2446 * xmlTextReaderCurrentNode:
2447 * @reader:  the xmlTextReaderPtr used
2448 *
2449 * Hacking interface allowing to get the xmlNodePtr correponding to the
2450 * current node being accessed by the xmlTextReader. This is dangerous
2451 * because the underlying node may be destroyed on the next Reads.
2452 *
2453 * Returns the xmlNodePtr or NULL in case of error.
2454 */
2455xmlNodePtr
2456xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
2457    if (reader == NULL)
2458	return(NULL);
2459
2460    if (reader->curnode != NULL)
2461	return(reader->curnode);
2462    return(reader->node);
2463}
2464
2465/**
2466 * xmlTextReaderCurrentDoc:
2467 * @reader:  the xmlTextReaderPtr used
2468 *
2469 * Hacking interface allowing to get the xmlDocPtr correponding to the
2470 * current document being accessed by the xmlTextReader. This is dangerous
2471 * because the associated node may be destroyed on the next Reads.
2472 *
2473 * Returns the xmlDocPtr or NULL in case of error.
2474 */
2475xmlDocPtr
2476xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
2477    if ((reader == NULL) || (reader->ctxt == NULL))
2478	return(NULL);
2479
2480    return(reader->ctxt->myDoc);
2481}
2482
2483#ifdef LIBXML_SCHEMAS_ENABLED
2484/**
2485 * xmlTextReaderRelaxNGSetSchema:
2486 * @reader:  the xmlTextReaderPtr used
2487 * @schema:  a precompiled RelaxNG schema
2488 *
2489 * Use RelaxNG to validate the document as it is processed.
2490 * Activation is only possible before the first Read().
2491 * if @schema is NULL, then RelaxNG validation is desactivated.
2492 @ The @schema should not be freed until the reader is deallocated
2493 * or its use has been deactivated.
2494 *
2495 * Returns 0 in case the RelaxNG validation could be (des)activated and
2496 *         -1 in case of error.
2497 */
2498int
2499xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
2500    if (schema == NULL) {
2501        if (reader->rngSchemas != NULL) {
2502	    xmlRelaxNGFree(reader->rngSchemas);
2503	    reader->rngSchemas = NULL;
2504	}
2505        if (reader->rngValidCtxt != NULL) {
2506	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2507	    reader->rngValidCtxt = NULL;
2508        }
2509	return(0);
2510    }
2511    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2512	return(-1);
2513    if (reader->rngSchemas != NULL) {
2514	xmlRelaxNGFree(reader->rngSchemas);
2515	reader->rngSchemas = NULL;
2516    }
2517    if (reader->rngValidCtxt != NULL) {
2518	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2519	reader->rngValidCtxt = NULL;
2520    }
2521    reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
2522    if (reader->rngValidCtxt == NULL)
2523        return(-1);
2524    if (reader->errorFunc != NULL) {
2525	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
2526			 (xmlRelaxNGValidityErrorFunc)reader->errorFunc,
2527			 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
2528			 reader->errorFuncArg);
2529    }
2530    reader->rngValidErrors = 0;
2531    reader->rngFullNode = NULL;
2532    reader->validate = XML_TEXTREADER_VALIDATE_RNG;
2533    return(0);
2534}
2535
2536/**
2537 * xmlTextReaderRelaxNGValidate:
2538 * @reader:  the xmlTextReaderPtr used
2539 * @rng:  the path to a RelaxNG schema or NULL
2540 *
2541 * Use RelaxNG to validate the document as it is processed.
2542 * Activation is only possible before the first Read().
2543 * if @rng is NULL, then RelaxNG validation is desactivated.
2544 *
2545 * Returns 0 in case the RelaxNG validation could be (des)activated and
2546 *         -1 in case of error.
2547 */
2548int
2549xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
2550    xmlRelaxNGParserCtxtPtr ctxt;
2551
2552    if (reader == NULL)
2553        return(-1);
2554
2555    if (rng == NULL) {
2556        if (reader->rngSchemas != NULL) {
2557	    xmlRelaxNGFree(reader->rngSchemas);
2558	    reader->rngSchemas = NULL;
2559	}
2560        if (reader->rngValidCtxt != NULL) {
2561	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2562	    reader->rngValidCtxt = NULL;
2563        }
2564	return(0);
2565    }
2566    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2567	return(-1);
2568    if (reader->rngSchemas != NULL) {
2569	xmlRelaxNGFree(reader->rngSchemas);
2570	reader->rngSchemas = NULL;
2571    }
2572    if (reader->rngValidCtxt != NULL) {
2573	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2574	reader->rngValidCtxt = NULL;
2575    }
2576    ctxt = xmlRelaxNGNewParserCtxt(rng);
2577    if (reader->errorFunc != NULL) {
2578	xmlRelaxNGSetParserErrors(ctxt,
2579			 (xmlRelaxNGValidityErrorFunc) reader->errorFunc,
2580			 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
2581			 reader->errorFuncArg);
2582    }
2583    reader->rngSchemas = xmlRelaxNGParse(ctxt);
2584    xmlRelaxNGFreeParserCtxt(ctxt);
2585    if (reader->rngSchemas == NULL)
2586        return(-1);
2587    reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
2588    if (reader->rngValidCtxt == NULL)
2589        return(-1);
2590    if (reader->errorFunc != NULL) {
2591	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
2592			 (xmlRelaxNGValidityErrorFunc)reader->errorFunc,
2593			 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
2594			 reader->errorFuncArg);
2595    }
2596    reader->rngValidErrors = 0;
2597    reader->rngFullNode = NULL;
2598    reader->validate = XML_TEXTREADER_VALIDATE_RNG;
2599    return(0);
2600}
2601#endif
2602
2603/************************************************************************
2604 *									*
2605 *			Error Handling Extensions                       *
2606 *									*
2607 ************************************************************************/
2608
2609/* helper to build a xmlMalloc'ed string from a format and va_list */
2610static char *
2611xmlTextReaderBuildMessage(const char *msg, va_list ap) {
2612    int size;
2613    int chars;
2614    char *larger;
2615    char *str;
2616
2617    str = (char *) xmlMallocAtomic(150);
2618    if (str == NULL) {
2619	xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
2620        return NULL;
2621    }
2622
2623    size = 150;
2624
2625    while (1) {
2626        chars = vsnprintf(str, size, msg, ap);
2627        if ((chars > -1) && (chars < size))
2628            break;
2629        if (chars > -1)
2630            size += chars + 1;
2631        else
2632            size += 100;
2633        if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
2634	    xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
2635            xmlFree(str);
2636            return NULL;
2637        }
2638        str = larger;
2639    }
2640
2641    return str;
2642}
2643
2644/**
2645 * xmlTextReaderLocatorLineNumber:
2646 * @locator: the xmlTextReaderLocatorPtr used
2647 *
2648 * Obtain the line number for the given locator.
2649 *
2650 * Returns the line number or -1 in case of error.
2651 */
2652int
2653xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
2654    /* we know that locator is a xmlParserCtxtPtr */
2655    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
2656    int ret = -1;
2657
2658    if (ctx->node != NULL) {
2659	ret = xmlGetLineNo(ctx->node);
2660    }
2661    else {
2662	/* inspired from error.c */
2663	xmlParserInputPtr input;
2664	input = ctx->input;
2665	if ((input->filename == NULL) && (ctx->inputNr > 1))
2666	    input = ctx->inputTab[ctx->inputNr - 2];
2667	if (input != NULL) {
2668	    ret = input->line;
2669	}
2670	else {
2671	    ret = -1;
2672	}
2673    }
2674
2675    return ret;
2676}
2677
2678/**
2679 * xmlTextReaderLocatorBaseURI:
2680 * @locator: the xmlTextReaderLocatorPtr used
2681 *
2682 * Obtain the base URI for the given locator.
2683 *
2684 * Returns the base URI or NULL in case of error.
2685 */
2686xmlChar *
2687xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
2688    /* we know that locator is a xmlParserCtxtPtr */
2689    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
2690    xmlChar *ret = NULL;
2691
2692    if (ctx->node != NULL) {
2693	ret = xmlNodeGetBase(NULL,ctx->node);
2694    }
2695    else {
2696	/* inspired from error.c */
2697	xmlParserInputPtr input;
2698	input = ctx->input;
2699	if ((input->filename == NULL) && (ctx->inputNr > 1))
2700	    input = ctx->inputTab[ctx->inputNr - 2];
2701	if (input != NULL) {
2702	    ret = xmlStrdup(BAD_CAST input->filename);
2703	}
2704	else {
2705	    ret = NULL;
2706	}
2707    }
2708
2709    return ret;
2710}
2711
2712static void
2713xmlTextReaderGenericError(void *ctxt, int severity, char *str) {
2714    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
2715    xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private;
2716
2717    if (str != NULL) {
2718	reader->errorFunc(reader->errorFuncArg,
2719			  str,
2720			  severity,
2721			  (xmlTextReaderLocatorPtr)ctx);
2722	xmlFree(str);
2723    }
2724}
2725
2726static void
2727xmlTextReaderError(void *ctxt, const char *msg, ...) {
2728    va_list ap;
2729
2730    va_start(ap,msg);
2731    xmlTextReaderGenericError(ctxt,
2732                              XML_PARSER_SEVERITY_ERROR,
2733	                      xmlTextReaderBuildMessage(msg,ap));
2734    va_end(ap);
2735
2736}
2737
2738static void
2739xmlTextReaderWarning(void *ctxt, const char *msg, ...) {
2740    va_list ap;
2741
2742    va_start(ap,msg);
2743    xmlTextReaderGenericError(ctxt,
2744                              XML_PARSER_SEVERITY_WARNING,
2745	                      xmlTextReaderBuildMessage(msg,ap));
2746    va_end(ap);
2747}
2748
2749static void
2750xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
2751    va_list ap;
2752    int len = xmlStrlen((const xmlChar *) msg);
2753
2754    if ((len > 1) && (msg[len - 2] != ':')) {
2755	/*
2756	 * some callbacks only report locator information:
2757	 * skip them (mimicking behaviour in error.c)
2758	 */
2759	va_start(ap,msg);
2760	xmlTextReaderGenericError(ctxt,
2761				  XML_PARSER_SEVERITY_VALIDITY_ERROR,
2762				  xmlTextReaderBuildMessage(msg,ap));
2763	va_end(ap);
2764    }
2765}
2766
2767static void
2768xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
2769    va_list ap;
2770    int len = xmlStrlen((const xmlChar *) msg);
2771
2772    if ((len != 0) && (msg[len - 1] != ':')) {
2773	/*
2774	 * some callbacks only report locator information:
2775	 * skip them (mimicking behaviour in error.c)
2776	 */
2777	va_start(ap,msg);
2778	xmlTextReaderGenericError(ctxt,
2779				  XML_PARSER_SEVERITY_VALIDITY_WARNING,
2780				  xmlTextReaderBuildMessage(msg,ap));
2781	va_end(ap);
2782    }
2783}
2784
2785/**
2786 * xmlTextReaderSetErrorHandler:
2787 * @reader:  the xmlTextReaderPtr used
2788 * @f:	the callback function to call on error and warnings
2789 * @arg:    a user argument to pass to the callback function
2790 *
2791 * Register a callback function that will be called on error and warnings.
2792 *
2793 * If @f is NULL, the default error and warning handlers are restored.
2794 */
2795void
2796xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
2797			     xmlTextReaderErrorFunc f,
2798			     void *arg) {
2799    if (f != NULL) {
2800	reader->ctxt->sax->error = xmlTextReaderError;
2801	reader->ctxt->vctxt.error = xmlTextReaderValidityError;
2802	reader->ctxt->sax->warning = xmlTextReaderWarning;
2803	reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
2804	reader->errorFunc = f;
2805	reader->errorFuncArg = arg;
2806    }
2807    else {
2808	/* restore defaults */
2809	reader->ctxt->sax->error = xmlParserError;
2810	reader->ctxt->vctxt.error = xmlParserValidityError;
2811	reader->ctxt->sax->warning = xmlParserWarning;
2812	reader->ctxt->vctxt.warning = xmlParserValidityWarning;
2813	reader->errorFunc = NULL;
2814	reader->errorFuncArg = NULL;
2815    }
2816}
2817
2818/**
2819 * xmlTextReaderIsValid:
2820 * @reader:  the xmlTextReaderPtr used
2821 *
2822 * Retrieve the validity status from the parser context
2823 *
2824 * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
2825 */
2826int
2827xmlTextReaderIsValid(xmlTextReaderPtr reader) {
2828    if (reader == NULL) return(-1);
2829#ifdef LIBXML_SCHEMAS_ENABLED
2830    if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
2831        return(reader->rngValidErrors == 0);
2832#endif
2833    if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
2834        (reader->ctxt != NULL))
2835	return(reader->ctxt->valid);
2836    return(0);
2837}
2838
2839/**
2840 * xmlTextReaderGetErrorHandler:
2841 * @reader:  the xmlTextReaderPtr used
2842 * @f:	the callback function or NULL is no callback has been registered
2843 * @arg:    a user argument
2844 *
2845 * Retrieve the error callback function and user argument.
2846 */
2847void
2848xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
2849			     xmlTextReaderErrorFunc *f,
2850			     void **arg) {
2851    *f = reader->errorFunc;
2852    *arg = reader->errorFuncArg;
2853}
2854
2855/************************************************************************
2856 *									*
2857 *			Utilities					*
2858 *									*
2859 ************************************************************************/
2860/**
2861 * xmlBase64Decode:
2862 * @in:  the input buffer
2863 * @inlen:  the size of the input (in), the size read from it (out)
2864 * @to:  the output buffer
2865 * @tolen:  the size of the output (in), the size written to (out)
2866 *
2867 * Base64 decoder, reads from @in and save in @to
2868 * TODO: tell jody when this is actually exported
2869 *
2870 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
2871 *         2 if there wasn't enough space on the output or -1 in case of error.
2872 */
2873static int
2874xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
2875	        unsigned char *to, unsigned long *tolen) {
2876    unsigned long incur;		/* current index in in[] */
2877    unsigned long inblk;		/* last block index in in[] */
2878    unsigned long outcur;		/* current index in out[] */
2879    unsigned long inmax;		/* size of in[] */
2880    unsigned long outmax;		/* size of out[] */
2881    unsigned char cur;			/* the current value read from in[] */
2882    unsigned char intmp[3], outtmp[4];	/* temporary buffers for the convert */
2883    int nbintmp;			/* number of byte in intmp[] */
2884    int is_ignore;			/* cur should be ignored */
2885    int is_end = 0;			/* the end of the base64 was found */
2886    int retval = 1;
2887    int i;
2888
2889    if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
2890	return(-1);
2891
2892    incur = 0;
2893    inblk = 0;
2894    outcur = 0;
2895    inmax = *inlen;
2896    outmax = *tolen;
2897    nbintmp = 0;
2898
2899    while (1) {
2900        if (incur >= inmax)
2901            break;
2902        cur = in[incur++];
2903        is_ignore = 0;
2904        if ((cur >= 'A') && (cur <= 'Z'))
2905            cur = cur - 'A';
2906        else if ((cur >= 'a') && (cur <= 'z'))
2907            cur = cur - 'a' + 26;
2908        else if ((cur >= '0') && (cur <= '9'))
2909            cur = cur - '0' + 52;
2910        else if (cur == '+')
2911            cur = 62;
2912        else if (cur == '/')
2913            cur = 63;
2914        else if (cur == '.')
2915            cur = 0;
2916        else if (cur == '=') /*no op , end of the base64 stream */
2917            is_end = 1;
2918        else {
2919            is_ignore = 1;
2920	    if (nbintmp == 0)
2921		inblk = incur;
2922	}
2923
2924        if (!is_ignore) {
2925            int nbouttmp = 3;
2926            int is_break = 0;
2927
2928            if (is_end) {
2929                if (nbintmp == 0)
2930                    break;
2931                if ((nbintmp == 1) || (nbintmp == 2))
2932                    nbouttmp = 1;
2933                else
2934                    nbouttmp = 2;
2935                nbintmp = 3;
2936                is_break = 1;
2937            }
2938            intmp[nbintmp++] = cur;
2939	    /*
2940	     * if intmp is full, push the 4byte sequence as a 3 byte
2941	     * sequence out
2942	     */
2943            if (nbintmp == 4) {
2944                nbintmp = 0;
2945                outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
2946                outtmp[1] =
2947                    ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
2948                outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
2949		if (outcur + 3 >= outmax) {
2950		    retval = 2;
2951		    break;
2952		}
2953
2954                for (i = 0; i < nbouttmp; i++)
2955		    to[outcur++] = outtmp[i];
2956		inblk = incur;
2957            }
2958
2959            if (is_break) {
2960		retval = 0;
2961                break;
2962	    }
2963        }
2964    }
2965
2966    *tolen = outcur;
2967    *inlen = inblk;
2968    return (retval);
2969}
2970
2971/*
2972 * Test routine for the xmlBase64Decode function
2973 */
2974#if 0
2975int main(int argc, char **argv) {
2976    char *input = "  VW4 gcGV0        \n      aXQgdGVzdCAuCg== ";
2977    char output[100];
2978    char output2[100];
2979    char output3[100];
2980    unsigned long inlen = strlen(input);
2981    unsigned long outlen = 100;
2982    int ret;
2983    unsigned long cons, tmp, tmp2, prod;
2984
2985    /*
2986     * Direct
2987     */
2988    ret = xmlBase64Decode(input, &inlen, output, &outlen);
2989
2990    output[outlen] = 0;
2991    printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
2992
2993    /*
2994     * output chunking
2995     */
2996    cons = 0;
2997    prod = 0;
2998    while (cons < inlen) {
2999	tmp = 5;
3000	tmp2 = inlen - cons;
3001
3002	printf("%ld %ld\n", cons, prod);
3003	ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
3004	cons += tmp2;
3005	prod += tmp;
3006	printf("%ld %ld\n", cons, prod);
3007    }
3008    output2[outlen] = 0;
3009    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
3010
3011    /*
3012     * input chunking
3013     */
3014    cons = 0;
3015    prod = 0;
3016    while (cons < inlen) {
3017	tmp = 100 - prod;
3018	tmp2 = inlen - cons;
3019	if (tmp2 > 5)
3020	    tmp2 = 5;
3021
3022	printf("%ld %ld\n", cons, prod);
3023	ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
3024	cons += tmp2;
3025	prod += tmp;
3026	printf("%ld %ld\n", cons, prod);
3027    }
3028    output3[outlen] = 0;
3029    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
3030    return(0);
3031
3032}
3033#endif
3034