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  *   - XML Schemas validation
16  */
17 #define IN_LIBXML
18 #include "libxml.h"
19 
20 #ifdef LIBXML_READER_ENABLED
21 #include <string.h> /* for memset() only ! */
22 #include <stdarg.h>
23 
24 #ifdef HAVE_CTYPE_H
25 #include <ctype.h>
26 #endif
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30 
31 #include <libxml/xmlmemory.h>
32 #include <libxml/xmlIO.h>
33 #include <libxml/xmlreader.h>
34 #include <libxml/parserInternals.h>
35 #ifdef LIBXML_SCHEMAS_ENABLED
36 #include <libxml/relaxng.h>
37 #include <libxml/xmlschemas.h>
38 #endif
39 #include <libxml/uri.h>
40 #ifdef LIBXML_XINCLUDE_ENABLED
41 #include <libxml/xinclude.h>
42 #endif
43 #ifdef LIBXML_PATTERN_ENABLED
44 #include <libxml/pattern.h>
45 #endif
46 
47 #define MAX_ERR_MSG_SIZE 64000
48 
49 /*
50  * The following VA_COPY was coded following an example in
51  * the Samba project.  It may not be sufficient for some
52  * esoteric implementations of va_list (i.e. it may need
53  * something involving a memcpy) but (hopefully) will be
54  * sufficient for libxml2.
55  */
56 #ifndef VA_COPY
57   #ifdef HAVE_VA_COPY
58     #define VA_COPY(dest, src) va_copy(dest, src)
59   #else
60     #ifdef HAVE___VA_COPY
61       #define VA_COPY(dest,src) __va_copy(dest, src)
62     #else
63       #define VA_COPY(dest,src) (dest) = (src)
64     #endif
65   #endif
66 #endif
67 
68 /* #define DEBUG_CALLBACKS */
69 /* #define DEBUG_READER */
70 
71 /**
72  * TODO:
73  *
74  * macro to flag unimplemented blocks
75  */
76 #define TODO								\
77     xmlGenericError(xmlGenericErrorContext,				\
78 	    "Unimplemented block at %s:%d\n",				\
79             __FILE__, __LINE__);
80 
81 #ifdef DEBUG_READER
82 #define DUMP_READER xmlTextReaderDebug(reader);
83 #else
84 #define DUMP_READER
85 #endif
86 
87 #define CHUNK_SIZE 512
88 /************************************************************************
89  *									*
90  *	The parser: maps the Text Reader API on top of the existing	*
91  *		parsing routines building a tree			*
92  *									*
93  ************************************************************************/
94 
95 #define XML_TEXTREADER_INPUT	1
96 #define XML_TEXTREADER_CTXT	2
97 
98 typedef enum {
99     XML_TEXTREADER_NONE = -1,
100     XML_TEXTREADER_START= 0,
101     XML_TEXTREADER_ELEMENT= 1,
102     XML_TEXTREADER_END= 2,
103     XML_TEXTREADER_EMPTY= 3,
104     XML_TEXTREADER_BACKTRACK= 4,
105     XML_TEXTREADER_DONE= 5,
106     XML_TEXTREADER_ERROR= 6
107 } xmlTextReaderState;
108 
109 typedef enum {
110     XML_TEXTREADER_NOT_VALIDATE = 0,
111     XML_TEXTREADER_VALIDATE_DTD = 1,
112     XML_TEXTREADER_VALIDATE_RNG = 2,
113     XML_TEXTREADER_VALIDATE_XSD = 4
114 } xmlTextReaderValidate;
115 
116 struct _xmlTextReader {
117     int				mode;	/* the parsing mode */
118     xmlDocPtr			doc;    /* when walking an existing doc */
119     xmlTextReaderValidate       validate;/* is there any validation */
120     int				allocs;	/* what structure were deallocated */
121     xmlTextReaderState		state;
122     xmlParserCtxtPtr		ctxt;	/* the parser context */
123     xmlSAXHandlerPtr		sax;	/* the parser SAX callbacks */
124     xmlParserInputBufferPtr	input;	/* the input */
125     startElementSAXFunc		startElement;/* initial SAX callbacks */
126     endElementSAXFunc		endElement;  /* idem */
127     startElementNsSAX2Func	startElementNs;/* idem */
128     endElementNsSAX2Func	endElementNs;  /* idem */
129     charactersSAXFunc		characters;
130     cdataBlockSAXFunc		cdataBlock;
131     unsigned int		base;	/* base of the segment in the input */
132     unsigned int		cur;	/* current position in the input */
133     xmlNodePtr			node;	/* current node */
134     xmlNodePtr			curnode;/* current attribute node */
135     int				depth;  /* depth of the current node */
136     xmlNodePtr			faketext;/* fake xmlNs chld */
137     int				preserve;/* preserve the resulting document */
138     xmlBufferPtr		buffer; /* used to return const xmlChar * */
139     xmlDictPtr			dict;	/* the context dictionnary */
140 
141     /* entity stack when traversing entities content */
142     xmlNodePtr         ent;          /* Current Entity Ref Node */
143     int                entNr;        /* Depth of the entities stack */
144     int                entMax;       /* Max depth of the entities stack */
145     xmlNodePtr        *entTab;       /* array of entities */
146 
147     /* error handling */
148     xmlTextReaderErrorFunc errorFunc;    /* callback function */
149     void                  *errorFuncArg; /* callback function user argument */
150 
151 #ifdef LIBXML_SCHEMAS_ENABLED
152     /* Handling of RelaxNG validation */
153     xmlRelaxNGPtr          rngSchemas;	/* The Relax NG schemas */
154     xmlRelaxNGValidCtxtPtr rngValidCtxt;/* The Relax NG validation context */
155     int                    rngValidErrors;/* The number of errors detected */
156     xmlNodePtr             rngFullNode;	/* the node if RNG not progressive */
157     /* Handling of Schemas validation */
158     xmlSchemaPtr          xsdSchemas;	/* The Schemas schemas */
159     xmlSchemaValidCtxtPtr xsdValidCtxt;/* The Schemas validation context */
160     int                   xsdPreserveCtxt; /* 1 if the context was provided by the user */
161     int                   xsdValidErrors;/* The number of errors detected */
162     xmlSchemaSAXPlugPtr   xsdPlug;	/* the schemas plug in SAX pipeline */
163 #endif
164 #ifdef LIBXML_XINCLUDE_ENABLED
165     /* Handling of XInclude processing */
166     int                xinclude;	/* is xinclude asked for */
167     const xmlChar *    xinclude_name;	/* the xinclude name from dict */
168     xmlXIncludeCtxtPtr xincctxt;	/* the xinclude context */
169     int                in_xinclude;	/* counts for xinclude */
170 #endif
171 #ifdef LIBXML_PATTERN_ENABLED
172     int                patternNr;       /* number of preserve patterns */
173     int                patternMax;      /* max preserve patterns */
174     xmlPatternPtr     *patternTab;      /* array of preserve patterns */
175 #endif
176     int                preserves;	/* level of preserves */
177     int                parserFlags;	/* the set of options set */
178     /* Structured error handling */
179     xmlStructuredErrorFunc sErrorFunc;  /* callback function */
180 };
181 
182 #define NODE_IS_EMPTY		0x1
183 #define NODE_IS_PRESERVED	0x2
184 #define NODE_IS_SPRESERVED	0x4
185 
186 /**
187  * CONSTSTR:
188  *
189  * Macro used to return an interned string
190  */
191 #define CONSTSTR(str) xmlDictLookup(reader->dict, (str), -1)
192 #define CONSTQSTR(p, str) xmlDictQLookup(reader->dict, (p), (str))
193 
194 static int xmlTextReaderReadTree(xmlTextReaderPtr reader);
195 static int xmlTextReaderNextTree(xmlTextReaderPtr reader);
196 
197 /************************************************************************
198  *									*
199  *	Our own version of the freeing routines as we recycle nodes	*
200  *									*
201  ************************************************************************/
202 /**
203  * DICT_FREE:
204  * @str:  a string
205  *
206  * Free a string if it is not owned by the "dict" dictionnary in the
207  * current scope
208  */
209 #define DICT_FREE(str)						\
210 	if ((str) && ((!dict) ||				\
211 	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
212 	    xmlFree((char *)(str));
213 
214 static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur);
215 static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur);
216 
217 /**
218  * xmlFreeID:
219  * @not:  A id
220  *
221  * Deallocate the memory used by an id definition
222  */
223 static void
xmlFreeID(xmlIDPtr id)224 xmlFreeID(xmlIDPtr id) {
225     xmlDictPtr dict = NULL;
226 
227     if (id == NULL) return;
228 
229     if (id->doc != NULL)
230         dict = id->doc->dict;
231 
232     if (id->value != NULL)
233 	DICT_FREE(id->value)
234     xmlFree(id);
235 }
236 
237 /**
238  * xmlTextReaderRemoveID:
239  * @doc:  the document
240  * @attr:  the attribute
241  *
242  * Remove the given attribute from the ID table maintained internally.
243  *
244  * Returns -1 if the lookup failed and 0 otherwise
245  */
246 static int
xmlTextReaderRemoveID(xmlDocPtr doc,xmlAttrPtr attr)247 xmlTextReaderRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
248     xmlIDTablePtr table;
249     xmlIDPtr id;
250     xmlChar *ID;
251 
252     if (doc == NULL) return(-1);
253     if (attr == NULL) return(-1);
254     table = (xmlIDTablePtr) doc->ids;
255     if (table == NULL)
256         return(-1);
257 
258     ID = xmlNodeListGetString(doc, attr->children, 1);
259     if (ID == NULL)
260 	return(-1);
261     id = xmlHashLookup(table, ID);
262     xmlFree(ID);
263     if (id == NULL || id->attr != attr) {
264 	return(-1);
265     }
266     id->name = attr->name;
267     id->attr = NULL;
268     return(0);
269 }
270 
271 /**
272  * xmlTextReaderFreeProp:
273  * @reader:  the xmlTextReaderPtr used
274  * @cur:  the node
275  *
276  * Free a node.
277  */
278 static void
xmlTextReaderFreeProp(xmlTextReaderPtr reader,xmlAttrPtr cur)279 xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
280     xmlDictPtr dict;
281 
282     dict = reader->ctxt->dict;
283     if (cur == NULL) return;
284 
285     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
286 	xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);
287 
288     /* Check for ID removal -> leading to invalid references ! */
289     if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
290 	((cur->parent->doc->intSubset != NULL) ||
291 	 (cur->parent->doc->extSubset != NULL))) {
292         if (xmlIsID(cur->parent->doc, cur->parent, cur))
293 	    xmlTextReaderRemoveID(cur->parent->doc, cur);
294     }
295     if (cur->children != NULL)
296         xmlTextReaderFreeNodeList(reader, cur->children);
297 
298     DICT_FREE(cur->name);
299     if ((reader != NULL) && (reader->ctxt != NULL) &&
300         (reader->ctxt->freeAttrsNr < 100)) {
301         cur->next = reader->ctxt->freeAttrs;
302 	reader->ctxt->freeAttrs = cur;
303 	reader->ctxt->freeAttrsNr++;
304     } else {
305 	xmlFree(cur);
306     }
307 }
308 
309 /**
310  * xmlTextReaderFreePropList:
311  * @reader:  the xmlTextReaderPtr used
312  * @cur:  the first property in the list
313  *
314  * Free a property and all its siblings, all the children are freed too.
315  */
316 static void
xmlTextReaderFreePropList(xmlTextReaderPtr reader,xmlAttrPtr cur)317 xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) {
318     xmlAttrPtr next;
319     if (cur == NULL) return;
320     while (cur != NULL) {
321         next = cur->next;
322         xmlTextReaderFreeProp(reader, cur);
323 	cur = next;
324     }
325 }
326 
327 /**
328  * xmlTextReaderFreeNodeList:
329  * @reader:  the xmlTextReaderPtr used
330  * @cur:  the first node in the list
331  *
332  * Free a node and all its siblings, this is a recursive behaviour, all
333  * the children are freed too.
334  */
335 static void
xmlTextReaderFreeNodeList(xmlTextReaderPtr reader,xmlNodePtr cur)336 xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
337     xmlNodePtr next;
338     xmlDictPtr dict;
339 
340     dict = reader->ctxt->dict;
341     if (cur == NULL) return;
342     if (cur->type == XML_NAMESPACE_DECL) {
343 	xmlFreeNsList((xmlNsPtr) cur);
344 	return;
345     }
346     if ((cur->type == XML_DOCUMENT_NODE) ||
347 	(cur->type == XML_HTML_DOCUMENT_NODE)) {
348 	xmlFreeDoc((xmlDocPtr) cur);
349 	return;
350     }
351     while (cur != NULL) {
352         next = cur->next;
353 	/* unroll to speed up freeing the document */
354 	if (cur->type != XML_DTD_NODE) {
355 
356 	    if ((cur->children != NULL) &&
357 		(cur->type != XML_ENTITY_REF_NODE)) {
358 		if (cur->children->parent == cur)
359 		    xmlTextReaderFreeNodeList(reader, cur->children);
360 		cur->children = NULL;
361 	    }
362 
363 	    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
364 		xmlDeregisterNodeDefaultValue(cur);
365 
366 	    if (((cur->type == XML_ELEMENT_NODE) ||
367 		 (cur->type == XML_XINCLUDE_START) ||
368 		 (cur->type == XML_XINCLUDE_END)) &&
369 		(cur->properties != NULL))
370 		xmlTextReaderFreePropList(reader, cur->properties);
371 	    if ((cur->content != (xmlChar *) &(cur->properties)) &&
372 	        (cur->type != XML_ELEMENT_NODE) &&
373 		(cur->type != XML_XINCLUDE_START) &&
374 		(cur->type != XML_XINCLUDE_END) &&
375 		(cur->type != XML_ENTITY_REF_NODE)) {
376 		DICT_FREE(cur->content);
377 	    }
378 	    if (((cur->type == XML_ELEMENT_NODE) ||
379 	         (cur->type == XML_XINCLUDE_START) ||
380 		 (cur->type == XML_XINCLUDE_END)) &&
381 		(cur->nsDef != NULL))
382 		xmlFreeNsList(cur->nsDef);
383 
384 	    /*
385 	     * we don't free element names here they are interned now
386 	     */
387 	    if ((cur->type != XML_TEXT_NODE) &&
388 		(cur->type != XML_COMMENT_NODE))
389 		DICT_FREE(cur->name);
390 	    if (((cur->type == XML_ELEMENT_NODE) ||
391 		 (cur->type == XML_TEXT_NODE)) &&
392 	        (reader != NULL) && (reader->ctxt != NULL) &&
393 		(reader->ctxt->freeElemsNr < 100)) {
394 	        cur->next = reader->ctxt->freeElems;
395 		reader->ctxt->freeElems = cur;
396 		reader->ctxt->freeElemsNr++;
397 	    } else {
398 		xmlFree(cur);
399 	    }
400 	}
401 	cur = next;
402     }
403 }
404 
405 /**
406  * xmlTextReaderFreeNode:
407  * @reader:  the xmlTextReaderPtr used
408  * @cur:  the node
409  *
410  * Free a node, this is a recursive behaviour, all the children are freed too.
411  * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
412  */
413 static void
xmlTextReaderFreeNode(xmlTextReaderPtr reader,xmlNodePtr cur)414 xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) {
415     xmlDictPtr dict;
416 
417     dict = reader->ctxt->dict;
418     if (cur->type == XML_DTD_NODE) {
419 	xmlFreeDtd((xmlDtdPtr) cur);
420 	return;
421     }
422     if (cur->type == XML_NAMESPACE_DECL) {
423 	xmlFreeNs((xmlNsPtr) cur);
424         return;
425     }
426     if (cur->type == XML_ATTRIBUTE_NODE) {
427 	xmlTextReaderFreeProp(reader, (xmlAttrPtr) cur);
428 	return;
429     }
430 
431     if ((cur->children != NULL) &&
432 	(cur->type != XML_ENTITY_REF_NODE)) {
433 	if (cur->children->parent == cur)
434 	    xmlTextReaderFreeNodeList(reader, cur->children);
435 	cur->children = NULL;
436     }
437 
438     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
439 	xmlDeregisterNodeDefaultValue(cur);
440 
441     if (((cur->type == XML_ELEMENT_NODE) ||
442 	 (cur->type == XML_XINCLUDE_START) ||
443 	 (cur->type == XML_XINCLUDE_END)) &&
444 	(cur->properties != NULL))
445 	xmlTextReaderFreePropList(reader, cur->properties);
446     if ((cur->content != (xmlChar *) &(cur->properties)) &&
447         (cur->type != XML_ELEMENT_NODE) &&
448 	(cur->type != XML_XINCLUDE_START) &&
449 	(cur->type != XML_XINCLUDE_END) &&
450 	(cur->type != XML_ENTITY_REF_NODE)) {
451 	DICT_FREE(cur->content);
452     }
453     if (((cur->type == XML_ELEMENT_NODE) ||
454 	 (cur->type == XML_XINCLUDE_START) ||
455 	 (cur->type == XML_XINCLUDE_END)) &&
456 	(cur->nsDef != NULL))
457 	xmlFreeNsList(cur->nsDef);
458 
459     /*
460      * we don't free names here they are interned now
461      */
462     if ((cur->type != XML_TEXT_NODE) &&
463         (cur->type != XML_COMMENT_NODE))
464 	DICT_FREE(cur->name);
465 
466     if (((cur->type == XML_ELEMENT_NODE) ||
467 	 (cur->type == XML_TEXT_NODE)) &&
468 	(reader != NULL) && (reader->ctxt != NULL) &&
469 	(reader->ctxt->freeElemsNr < 100)) {
470 	cur->next = reader->ctxt->freeElems;
471 	reader->ctxt->freeElems = cur;
472 	reader->ctxt->freeElemsNr++;
473     } else {
474 	xmlFree(cur);
475     }
476 }
477 
478 /**
479  * xmlTextReaderFreeIDTable:
480  * @table:  An id table
481  *
482  * Deallocate the memory used by an ID hash table.
483  */
484 static void
xmlTextReaderFreeIDTable(xmlIDTablePtr table)485 xmlTextReaderFreeIDTable(xmlIDTablePtr table) {
486     xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
487 }
488 
489 /**
490  * xmlTextReaderFreeDoc:
491  * @reader:  the xmlTextReaderPtr used
492  * @cur:  pointer to the document
493  *
494  * Free up all the structures used by a document, tree included.
495  */
496 static void
xmlTextReaderFreeDoc(xmlTextReaderPtr reader,xmlDocPtr cur)497 xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) {
498     xmlDtdPtr extSubset, intSubset;
499 
500     if (cur == NULL) return;
501 
502     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
503 	xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);
504 
505     /*
506      * Do this before freeing the children list to avoid ID lookups
507      */
508     if (cur->ids != NULL) xmlTextReaderFreeIDTable((xmlIDTablePtr) cur->ids);
509     cur->ids = NULL;
510     if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
511     cur->refs = NULL;
512     extSubset = cur->extSubset;
513     intSubset = cur->intSubset;
514     if (intSubset == extSubset)
515 	extSubset = NULL;
516     if (extSubset != NULL) {
517 	xmlUnlinkNode((xmlNodePtr) cur->extSubset);
518 	cur->extSubset = NULL;
519 	xmlFreeDtd(extSubset);
520     }
521     if (intSubset != NULL) {
522 	xmlUnlinkNode((xmlNodePtr) cur->intSubset);
523 	cur->intSubset = NULL;
524 	xmlFreeDtd(intSubset);
525     }
526 
527     if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children);
528 
529     if (cur->version != NULL) xmlFree((char *) cur->version);
530     if (cur->name != NULL) xmlFree((char *) cur->name);
531     if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
532     if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
533     if (cur->URL != NULL) xmlFree((char *) cur->URL);
534     if (cur->dict != NULL) xmlDictFree(cur->dict);
535 
536     xmlFree(cur);
537 }
538 
539 /************************************************************************
540  *									*
541  *			The reader core parser				*
542  *									*
543  ************************************************************************/
544 #ifdef DEBUG_READER
545 static void
xmlTextReaderDebug(xmlTextReaderPtr reader)546 xmlTextReaderDebug(xmlTextReaderPtr reader) {
547     if ((reader == NULL) || (reader->ctxt == NULL)) {
548 	fprintf(stderr, "xmlTextReader NULL\n");
549 	return;
550     }
551     fprintf(stderr, "xmlTextReader: state %d depth %d ",
552 	    reader->state, reader->depth);
553     if (reader->node == NULL) {
554 	fprintf(stderr, "node = NULL\n");
555     } else {
556 	fprintf(stderr, "node %s\n", reader->node->name);
557     }
558     fprintf(stderr, "  input: base %d, cur %d, depth %d: ",
559 	    reader->base, reader->cur, reader->ctxt->nodeNr);
560     if (reader->input->buffer == NULL) {
561 	fprintf(stderr, "buffer is NULL\n");
562     } else {
563 #ifdef LIBXML_DEBUG_ENABLED
564 	xmlDebugDumpString(stderr,
565 		&reader->input->buffer->content[reader->cur]);
566 #endif
567 	fprintf(stderr, "\n");
568     }
569 }
570 #endif
571 
572 /**
573  * xmlTextReaderEntPush:
574  * @reader:  the xmlTextReaderPtr used
575  * @value:  the entity reference node
576  *
577  * Pushes a new entity reference node on top of the entities stack
578  *
579  * Returns 0 in case of error, the index in the stack otherwise
580  */
581 static int
xmlTextReaderEntPush(xmlTextReaderPtr reader,xmlNodePtr value)582 xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
583 {
584     if (reader->entMax <= 0) {
585 	reader->entMax = 10;
586 	reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
587 		                                  sizeof(reader->entTab[0]));
588         if (reader->entTab == NULL) {
589             xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
590             return (0);
591         }
592     }
593     if (reader->entNr >= reader->entMax) {
594         reader->entMax *= 2;
595         reader->entTab =
596             (xmlNodePtr *) xmlRealloc(reader->entTab,
597                                       reader->entMax *
598                                       sizeof(reader->entTab[0]));
599         if (reader->entTab == NULL) {
600             xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
601             return (0);
602         }
603     }
604     reader->entTab[reader->entNr] = value;
605     reader->ent = value;
606     return (reader->entNr++);
607 }
608 
609 /**
610  * xmlTextReaderEntPop:
611  * @reader:  the xmlTextReaderPtr used
612  *
613  * Pops the top element entity from the entities stack
614  *
615  * Returns the entity just removed
616  */
617 static xmlNodePtr
xmlTextReaderEntPop(xmlTextReaderPtr reader)618 xmlTextReaderEntPop(xmlTextReaderPtr reader)
619 {
620     xmlNodePtr ret;
621 
622     if (reader->entNr <= 0)
623         return (NULL);
624     reader->entNr--;
625     if (reader->entNr > 0)
626         reader->ent = reader->entTab[reader->entNr - 1];
627     else
628         reader->ent = NULL;
629     ret = reader->entTab[reader->entNr];
630     reader->entTab[reader->entNr] = NULL;
631     return (ret);
632 }
633 
634 /**
635  * xmlTextReaderStartElement:
636  * @ctx: the user data (XML parser context)
637  * @fullname:  The element name, including namespace prefix
638  * @atts:  An array of name/value attributes pairs, NULL terminated
639  *
640  * called when an opening tag has been processed.
641  */
642 static void
xmlTextReaderStartElement(void * ctx,const xmlChar * fullname,const xmlChar ** atts)643 xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
644 	                  const xmlChar **atts) {
645     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
646     xmlTextReaderPtr reader = ctxt->_private;
647 
648 #ifdef DEBUG_CALLBACKS
649     printf("xmlTextReaderStartElement(%s)\n", fullname);
650 #endif
651     if ((reader != NULL) && (reader->startElement != NULL)) {
652 	reader->startElement(ctx, fullname, atts);
653 	if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
654 	    (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
655 	    (ctxt->input->cur[1] == '>'))
656 	    ctxt->node->extra = NODE_IS_EMPTY;
657     }
658     if (reader != NULL)
659 	reader->state = XML_TEXTREADER_ELEMENT;
660 }
661 
662 /**
663  * xmlTextReaderEndElement:
664  * @ctx: the user data (XML parser context)
665  * @fullname:  The element name, including namespace prefix
666  *
667  * called when an ending tag has been processed.
668  */
669 static void
xmlTextReaderEndElement(void * ctx,const xmlChar * fullname)670 xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
671     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
672     xmlTextReaderPtr reader = ctxt->_private;
673 
674 #ifdef DEBUG_CALLBACKS
675     printf("xmlTextReaderEndElement(%s)\n", fullname);
676 #endif
677     if ((reader != NULL) && (reader->endElement != NULL)) {
678 	reader->endElement(ctx, fullname);
679     }
680 }
681 
682 /**
683  * xmlTextReaderStartElementNs:
684  * @ctx: the user data (XML parser context)
685  * @localname:  the local name of the element
686  * @prefix:  the element namespace prefix if available
687  * @URI:  the element namespace name if available
688  * @nb_namespaces:  number of namespace definitions on that node
689  * @namespaces:  pointer to the array of prefix/URI pairs namespace definitions
690  * @nb_attributes:  the number of attributes on that node
691  * nb_defaulted:  the number of defaulted attributes.
692  * @attributes:  pointer to the array of (localname/prefix/URI/value/end)
693  *               attribute values.
694  *
695  * called when an opening tag has been processed.
696  */
697 static void
xmlTextReaderStartElementNs(void * ctx,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI,int nb_namespaces,const xmlChar ** namespaces,int nb_attributes,int nb_defaulted,const xmlChar ** attributes)698 xmlTextReaderStartElementNs(void *ctx,
699                       const xmlChar *localname,
700 		      const xmlChar *prefix,
701 		      const xmlChar *URI,
702 		      int nb_namespaces,
703 		      const xmlChar **namespaces,
704 		      int nb_attributes,
705 		      int nb_defaulted,
706 		      const xmlChar **attributes)
707 {
708     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
709     xmlTextReaderPtr reader = ctxt->_private;
710 
711 #ifdef DEBUG_CALLBACKS
712     printf("xmlTextReaderStartElementNs(%s)\n", localname);
713 #endif
714     if ((reader != NULL) && (reader->startElementNs != NULL)) {
715 	reader->startElementNs(ctx, localname, prefix, URI, nb_namespaces,
716 	                       namespaces, nb_attributes, nb_defaulted,
717 			       attributes);
718 	if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
719 	    (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
720 	    (ctxt->input->cur[1] == '>'))
721 	    ctxt->node->extra = NODE_IS_EMPTY;
722     }
723     if (reader != NULL)
724 	reader->state = XML_TEXTREADER_ELEMENT;
725 }
726 
727 /**
728  * xmlTextReaderEndElementNs:
729  * @ctx: the user data (XML parser context)
730  * @localname:  the local name of the element
731  * @prefix:  the element namespace prefix if available
732  * @URI:  the element namespace name if available
733  *
734  * called when an ending tag has been processed.
735  */
736 static void
xmlTextReaderEndElementNs(void * ctx,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI)737 xmlTextReaderEndElementNs(void *ctx,
738                           const xmlChar * localname,
739                           const xmlChar * prefix,
740 		          const xmlChar * URI)
741 {
742     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
743     xmlTextReaderPtr reader = ctxt->_private;
744 
745 #ifdef DEBUG_CALLBACKS
746     printf("xmlTextReaderEndElementNs(%s)\n", localname);
747 #endif
748     if ((reader != NULL) && (reader->endElementNs != NULL)) {
749 	reader->endElementNs(ctx, localname, prefix, URI);
750     }
751 }
752 
753 
754 /**
755  * xmlTextReaderCharacters:
756  * @ctx: the user data (XML parser context)
757  * @ch:  a xmlChar string
758  * @len: the number of xmlChar
759  *
760  * receiving some chars from the parser.
761  */
762 static void
xmlTextReaderCharacters(void * ctx,const xmlChar * ch,int len)763 xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
764 {
765     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
766     xmlTextReaderPtr reader = ctxt->_private;
767 
768 #ifdef DEBUG_CALLBACKS
769     printf("xmlTextReaderCharacters()\n");
770 #endif
771     if ((reader != NULL) && (reader->characters != NULL)) {
772 	reader->characters(ctx, ch, len);
773     }
774 }
775 
776 /**
777  * xmlTextReaderCDataBlock:
778  * @ctx: the user data (XML parser context)
779  * @value:  The pcdata content
780  * @len:  the block length
781  *
782  * called when a pcdata block has been parsed
783  */
784 static void
xmlTextReaderCDataBlock(void * ctx,const xmlChar * ch,int len)785 xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
786 {
787     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
788     xmlTextReaderPtr reader = ctxt->_private;
789 
790 #ifdef DEBUG_CALLBACKS
791     printf("xmlTextReaderCDataBlock()\n");
792 #endif
793     if ((reader != NULL) && (reader->cdataBlock != NULL)) {
794 	reader->cdataBlock(ctx, ch, len);
795     }
796 }
797 
798 /**
799  * xmlTextReaderPushData:
800  * @reader:  the xmlTextReaderPtr used
801  *
802  * Push data down the progressive parser until a significant callback
803  * got raised.
804  *
805  * Returns -1 in case of failure, 0 otherwise
806  */
807 static int
xmlTextReaderPushData(xmlTextReaderPtr reader)808 xmlTextReaderPushData(xmlTextReaderPtr reader) {
809     xmlBufferPtr inbuf;
810     int val, s;
811     xmlTextReaderState oldstate;
812 
813     if ((reader->input == NULL) || (reader->input->buffer == NULL))
814 	return(-1);
815 
816     oldstate = reader->state;
817     reader->state = XML_TEXTREADER_NONE;
818     inbuf = reader->input->buffer;
819 
820     while (reader->state == XML_TEXTREADER_NONE) {
821 	if (inbuf->use < reader->cur + CHUNK_SIZE) {
822 	    /*
823 	     * Refill the buffer unless we are at the end of the stream
824 	     */
825 	    if (reader->mode != XML_TEXTREADER_MODE_EOF) {
826 		val = xmlParserInputBufferRead(reader->input, 4096);
827 		if ((val == 0) &&
828 		    (inbuf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) {
829 		    if (inbuf->use == reader->cur) {
830 			reader->mode = XML_TEXTREADER_MODE_EOF;
831 			reader->state = oldstate;
832 		    }
833 		} else if (val < 0) {
834 		    reader->mode = XML_TEXTREADER_MODE_EOF;
835 		    reader->state = oldstate;
836 		    if ((oldstate != XML_TEXTREADER_START) ||
837 			(reader->ctxt->myDoc != NULL))
838 			return(val);
839 		} else if (val == 0) {
840 		    /* mark the end of the stream and process the remains */
841 		    reader->mode = XML_TEXTREADER_MODE_EOF;
842 		    break;
843 		}
844 
845 	    } else
846 		break;
847 	}
848 	/*
849 	 * parse by block of CHUNK_SIZE bytes, various tests show that
850 	 * it's the best tradeoff at least on a 1.2GH Duron
851 	 */
852 	if (inbuf->use >= reader->cur + CHUNK_SIZE) {
853 	    val = xmlParseChunk(reader->ctxt,
854 		          (const char *) &inbuf->content[reader->cur],
855 			  CHUNK_SIZE, 0);
856 	    reader->cur += CHUNK_SIZE;
857 	    if ((val != 0) || (reader->ctxt->wellFormed == 0))
858 		return(-1);
859 	} else {
860 	    s = inbuf->use - reader->cur;
861 	    val = xmlParseChunk(reader->ctxt,
862 		          (const char *) &inbuf->content[reader->cur],
863 			  s, 0);
864 	    reader->cur += s;
865 	    if ((val != 0) || (reader->ctxt->wellFormed == 0))
866 		return(-1);
867 	    break;
868 	}
869     }
870 
871     /*
872      * Discard the consumed input when needed and possible
873      */
874     if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
875         if (inbuf->alloc != XML_BUFFER_ALLOC_IMMUTABLE) {
876 	    if ((reader->cur >= 4096) &&
877 		(inbuf->use - reader->cur <= CHUNK_SIZE)) {
878 		val = xmlBufferShrink(inbuf, reader->cur);
879 		if (val >= 0) {
880 		    reader->cur -= val;
881 		}
882 	    }
883 	}
884     }
885 
886     /*
887      * At the end of the stream signal that the work is done to the Push
888      * parser.
889      */
890     else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
891 	if (reader->state != XML_TEXTREADER_DONE) {
892 	    s = inbuf->use - reader->cur;
893 	    val = xmlParseChunk(reader->ctxt,
894 		    (const char *) &inbuf->content[reader->cur],
895 		    s, 1);
896 	    reader->cur = inbuf->use;
897 	    reader->state  = XML_TEXTREADER_DONE;
898 	    if ((val != 0) || (reader->ctxt->wellFormed == 0))
899 	        return(-1);
900 	}
901     }
902     reader->state = oldstate;
903     return(0);
904 }
905 
906 #ifdef LIBXML_REGEXP_ENABLED
907 /**
908  * xmlTextReaderValidatePush:
909  * @reader:  the xmlTextReaderPtr used
910  *
911  * Push the current node for validation
912  */
913 static void
xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)914 xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
915     xmlNodePtr node = reader->node;
916 
917 #ifdef LIBXML_VALID_ENABLED
918     if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
919         (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
920 	if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
921 	    reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
922 				    reader->ctxt->myDoc, node, node->name);
923 	} else {
924 	    /* TODO use the BuildQName interface */
925 	    xmlChar *qname;
926 
927 	    qname = xmlStrdup(node->ns->prefix);
928 	    qname = xmlStrcat(qname, BAD_CAST ":");
929 	    qname = xmlStrcat(qname, node->name);
930 	    reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
931 				    reader->ctxt->myDoc, node, qname);
932 	    if (qname != NULL)
933 		xmlFree(qname);
934 	}
935     }
936 #endif /* LIBXML_VALID_ENABLED */
937 #ifdef LIBXML_SCHEMAS_ENABLED
938     if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
939                (reader->rngValidCtxt != NULL)) {
940 	int ret;
941 
942 	if (reader->rngFullNode != NULL) return;
943 	ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
944 	                                    reader->ctxt->myDoc,
945 					    node);
946 	if (ret == 0) {
947 	    /*
948 	     * this element requires a full tree
949 	     */
950 	    node = xmlTextReaderExpand(reader);
951 	    if (node == NULL) {
952 printf("Expand failed !\n");
953 	        ret = -1;
954 	    } else {
955 		ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt,
956 						    reader->ctxt->myDoc,
957 						    node);
958 		reader->rngFullNode = node;
959 	    }
960 	}
961 	if (ret != 1)
962 	    reader->rngValidErrors++;
963     }
964 #endif
965 }
966 
967 /**
968  * xmlTextReaderValidateCData:
969  * @reader:  the xmlTextReaderPtr used
970  * @data:  pointer to the CData
971  * @len:  lenght of the CData block in bytes.
972  *
973  * Push some CData for validation
974  */
975 static void
xmlTextReaderValidateCData(xmlTextReaderPtr reader,const xmlChar * data,int len)976 xmlTextReaderValidateCData(xmlTextReaderPtr reader,
977                            const xmlChar *data, int len) {
978 #ifdef LIBXML_VALID_ENABLED
979     if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
980         (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
981 	reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt,
982 	                                            data, len);
983     }
984 #endif /* LIBXML_VALID_ENABLED */
985 #ifdef LIBXML_SCHEMAS_ENABLED
986     if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
987                (reader->rngValidCtxt != NULL)) {
988 	int ret;
989 
990 	if (reader->rngFullNode != NULL) return;
991 	ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len);
992 	if (ret != 1)
993 	    reader->rngValidErrors++;
994     }
995 #endif
996 }
997 
998 /**
999  * xmlTextReaderValidatePop:
1000  * @reader:  the xmlTextReaderPtr used
1001  *
1002  * Pop the current node from validation
1003  */
1004 static void
xmlTextReaderValidatePop(xmlTextReaderPtr reader)1005 xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
1006     xmlNodePtr node = reader->node;
1007 
1008 #ifdef LIBXML_VALID_ENABLED
1009     if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
1010         (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
1011 	if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
1012 	    reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
1013 				    reader->ctxt->myDoc, node, node->name);
1014 	} else {
1015 	    /* TODO use the BuildQName interface */
1016 	    xmlChar *qname;
1017 
1018 	    qname = xmlStrdup(node->ns->prefix);
1019 	    qname = xmlStrcat(qname, BAD_CAST ":");
1020 	    qname = xmlStrcat(qname, node->name);
1021 	    reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
1022 				    reader->ctxt->myDoc, node, qname);
1023 	    if (qname != NULL)
1024 		xmlFree(qname);
1025 	}
1026     }
1027 #endif /* LIBXML_VALID_ENABLED */
1028 #ifdef LIBXML_SCHEMAS_ENABLED
1029     if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
1030                (reader->rngValidCtxt != NULL)) {
1031 	int ret;
1032 
1033 	if (reader->rngFullNode != NULL) {
1034 	    if (node == reader->rngFullNode)
1035 	        reader->rngFullNode = NULL;
1036 	    return;
1037 	}
1038 	ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
1039 	                                   reader->ctxt->myDoc,
1040 					   node);
1041 	if (ret != 1)
1042 	    reader->rngValidErrors++;
1043     }
1044 #endif
1045 }
1046 
1047 /**
1048  * xmlTextReaderValidateEntity:
1049  * @reader:  the xmlTextReaderPtr used
1050  *
1051  * Handle the validation when an entity reference is encountered and
1052  * entity substitution is not activated. As a result the parser interface
1053  * must walk through the entity and do the validation calls
1054  */
1055 static void
xmlTextReaderValidateEntity(xmlTextReaderPtr reader)1056 xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
1057     xmlNodePtr oldnode = reader->node;
1058     xmlNodePtr node = reader->node;
1059     xmlParserCtxtPtr ctxt = reader->ctxt;
1060 
1061     do {
1062 	if (node->type == XML_ENTITY_REF_NODE) {
1063 	    /*
1064 	     * Case where the underlying tree is not availble, lookup the entity
1065 	     * and walk it.
1066 	     */
1067 	    if ((node->children == NULL) && (ctxt->sax != NULL) &&
1068 		(ctxt->sax->getEntity != NULL)) {
1069 		node->children = (xmlNodePtr)
1070 		    ctxt->sax->getEntity(ctxt, node->name);
1071 	    }
1072 
1073 	    if ((node->children != NULL) &&
1074 		(node->children->type == XML_ENTITY_DECL) &&
1075 		(node->children->children != NULL)) {
1076 		xmlTextReaderEntPush(reader, node);
1077 		node = node->children->children;
1078 		continue;
1079 	    } else {
1080 		/*
1081 		 * The error has probably be raised already.
1082 		 */
1083 		if (node == oldnode)
1084 		    break;
1085 		node = node->next;
1086 	    }
1087 #ifdef LIBXML_REGEXP_ENABLED
1088 	} else if (node->type == XML_ELEMENT_NODE) {
1089 	    reader->node = node;
1090 	    xmlTextReaderValidatePush(reader);
1091 	} else if ((node->type == XML_TEXT_NODE) ||
1092 		   (node->type == XML_CDATA_SECTION_NODE)) {
1093             xmlTextReaderValidateCData(reader, node->content,
1094 	                               xmlStrlen(node->content));
1095 #endif
1096 	}
1097 
1098 	/*
1099 	 * go to next node
1100 	 */
1101 	if (node->children != NULL) {
1102 	    node = node->children;
1103 	    continue;
1104 	} else if (node->type == XML_ELEMENT_NODE) {
1105 	    xmlTextReaderValidatePop(reader);
1106 	}
1107 	if (node->next != NULL) {
1108 	    node = node->next;
1109 	    continue;
1110 	}
1111 	do {
1112 	    node = node->parent;
1113 	    if (node->type == XML_ELEMENT_NODE) {
1114 	        xmlNodePtr tmp;
1115 		if (reader->entNr == 0) {
1116 		    while ((tmp = node->last) != NULL) {
1117 			if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
1118 			    xmlUnlinkNode(tmp);
1119 			    xmlTextReaderFreeNode(reader, tmp);
1120 			} else
1121 			    break;
1122 		    }
1123 		}
1124 		reader->node = node;
1125 		xmlTextReaderValidatePop(reader);
1126 	    }
1127 	    if ((node->type == XML_ENTITY_DECL) &&
1128 		(reader->ent != NULL) && (reader->ent->children == node)) {
1129 		node = xmlTextReaderEntPop(reader);
1130 	    }
1131 	    if (node == oldnode)
1132 		break;
1133 	    if (node->next != NULL) {
1134 		node = node->next;
1135 		break;
1136 	    }
1137 	} while ((node != NULL) && (node != oldnode));
1138     } while ((node != NULL) && (node != oldnode));
1139     reader->node = oldnode;
1140 }
1141 #endif /* LIBXML_REGEXP_ENABLED */
1142 
1143 
1144 /**
1145  * xmlTextReaderGetSuccessor:
1146  * @cur:  the current node
1147  *
1148  * Get the successor of a node if available.
1149  *
1150  * Returns the successor node or NULL
1151  */
1152 static xmlNodePtr
xmlTextReaderGetSuccessor(xmlNodePtr cur)1153 xmlTextReaderGetSuccessor(xmlNodePtr cur) {
1154     if (cur == NULL) return(NULL) ; /* ERROR */
1155     if (cur->next != NULL) return(cur->next) ;
1156     do {
1157         cur = cur->parent;
1158         if (cur == NULL) break;
1159         if (cur->next != NULL) return(cur->next);
1160     } while (cur != NULL);
1161     return(cur);
1162 }
1163 
1164 /**
1165  * xmlTextReaderDoExpand:
1166  * @reader:  the xmlTextReaderPtr used
1167  *
1168  * Makes sure that the current node is fully read as well as all its
1169  * descendant. It means the full DOM subtree must be available at the
1170  * end of the call.
1171  *
1172  * Returns 1 if the node was expanded successfully, 0 if there is no more
1173  *          nodes to read, or -1 in case of error
1174  */
1175 static int
xmlTextReaderDoExpand(xmlTextReaderPtr reader)1176 xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
1177     int val;
1178 
1179     if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
1180         return(-1);
1181     do {
1182 	if (reader->ctxt->instate == XML_PARSER_EOF) return(1);
1183 
1184         if (xmlTextReaderGetSuccessor(reader->node) != NULL)
1185 	    return(1);
1186 	if (reader->ctxt->nodeNr < reader->depth)
1187 	    return(1);
1188 	if (reader->mode == XML_TEXTREADER_MODE_EOF)
1189 	    return(1);
1190 	val = xmlTextReaderPushData(reader);
1191 	if (val < 0){
1192 	    reader->mode = XML_TEXTREADER_MODE_ERROR;
1193 	    return(-1);
1194 	}
1195     } while(reader->mode != XML_TEXTREADER_MODE_EOF);
1196     return(1);
1197 }
1198 
1199 /**
1200  * xmlTextReaderCollectSiblings:
1201  * @node:    the first child
1202  *
1203  *  Traverse depth-first through all sibling nodes and their children
1204  *  nodes and concatenate their content. This is an auxiliary function
1205  *  to xmlTextReaderReadString.
1206  *
1207  *  Returns a string containing the content, or NULL in case of error.
1208  */
1209 static xmlChar *
xmlTextReaderCollectSiblings(xmlNodePtr node)1210 xmlTextReaderCollectSiblings(xmlNodePtr node)
1211 {
1212     xmlBufferPtr buffer;
1213     xmlChar *ret;
1214 
1215     buffer = xmlBufferCreate();
1216     if (buffer == NULL)
1217        return NULL;
1218 
1219     for ( ; node != NULL; node = node->next) {
1220        switch (node->type) {
1221        case XML_TEXT_NODE:
1222        case XML_CDATA_SECTION_NODE:
1223            xmlBufferCat(buffer, node->content);
1224            break;
1225        case XML_ELEMENT_NODE: {
1226            xmlChar *tmp;
1227 
1228 	   tmp = xmlTextReaderCollectSiblings(node->children);
1229            xmlBufferCat(buffer, tmp);
1230 	   xmlFree(tmp);
1231 	   break;
1232        }
1233        default:
1234            break;
1235        }
1236     }
1237     ret = buffer->content;
1238     buffer->content = NULL;
1239     xmlBufferFree(buffer);
1240     return(ret);
1241 }
1242 
1243 /**
1244  * xmlTextReaderRead:
1245  * @reader:  the xmlTextReaderPtr used
1246  *
1247  *  Moves the position of the current instance to the next node in
1248  *  the stream, exposing its properties.
1249  *
1250  *  Returns 1 if the node was read successfully, 0 if there is no more
1251  *          nodes to read, or -1 in case of error
1252  */
1253 int
xmlTextReaderRead(xmlTextReaderPtr reader)1254 xmlTextReaderRead(xmlTextReaderPtr reader) {
1255     int val, olddepth = 0;
1256     xmlTextReaderState oldstate = XML_TEXTREADER_START;
1257     xmlNodePtr oldnode = NULL;
1258 
1259 
1260     if (reader == NULL)
1261 	return(-1);
1262     reader->curnode = NULL;
1263     if (reader->doc != NULL)
1264         return(xmlTextReaderReadTree(reader));
1265     if (reader->ctxt == NULL)
1266 	return(-1);
1267     if (reader->ctxt->wellFormed != 1)
1268 	return(-1);
1269 
1270 #ifdef DEBUG_READER
1271     fprintf(stderr, "\nREAD ");
1272     DUMP_READER
1273 #endif
1274     if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
1275 	reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
1276 	/*
1277 	 * Initial state
1278 	 */
1279 	do {
1280 	    val = xmlTextReaderPushData(reader);
1281 		if (val < 0){
1282 			reader->mode = XML_TEXTREADER_MODE_ERROR;
1283 			reader->state = XML_TEXTREADER_ERROR;
1284 		return(-1);
1285 		}
1286 	} while ((reader->ctxt->node == NULL) &&
1287 		 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
1288 		  (reader->state != XML_TEXTREADER_DONE)));
1289 	if (reader->ctxt->node == NULL) {
1290 	    if (reader->ctxt->myDoc != NULL) {
1291 		reader->node = reader->ctxt->myDoc->children;
1292 	    }
1293 	    if (reader->node == NULL){
1294 			reader->mode = XML_TEXTREADER_MODE_ERROR;
1295 			reader->state = XML_TEXTREADER_ERROR;
1296 		return(-1);
1297 		}
1298 	    reader->state = XML_TEXTREADER_ELEMENT;
1299 	} else {
1300 	    if (reader->ctxt->myDoc != NULL) {
1301 		reader->node = reader->ctxt->myDoc->children;
1302 	    }
1303 	    if (reader->node == NULL)
1304 		reader->node = reader->ctxt->nodeTab[0];
1305 	    reader->state = XML_TEXTREADER_ELEMENT;
1306 	}
1307 	reader->depth = 0;
1308 	reader->ctxt->parseMode = XML_PARSE_READER;
1309 	goto node_found;
1310     }
1311     oldstate = reader->state;
1312     olddepth = reader->ctxt->nodeNr;
1313     oldnode = reader->node;
1314 
1315 get_next_node:
1316     if (reader->node == NULL) {
1317 	if (reader->mode == XML_TEXTREADER_MODE_EOF)
1318 	    return(0);
1319 	else
1320 	    return(-1);
1321     }
1322 
1323     /*
1324      * If we are not backtracking on ancestors or examined nodes,
1325      * that the parser didn't finished or that we arent at the end
1326      * of stream, continue processing.
1327      */
1328     while ((reader->node != NULL) && (reader->node->next == NULL) &&
1329 	   (reader->ctxt->nodeNr == olddepth) &&
1330            ((oldstate == XML_TEXTREADER_BACKTRACK) ||
1331             (reader->node->children == NULL) ||
1332 	    (reader->node->type == XML_ENTITY_REF_NODE) ||
1333 	    ((reader->node->children != NULL) &&
1334 	     (reader->node->children->type == XML_TEXT_NODE) &&
1335 	     (reader->node->children->next == NULL)) ||
1336 	    (reader->node->type == XML_DTD_NODE) ||
1337 	    (reader->node->type == XML_DOCUMENT_NODE) ||
1338 	    (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
1339 	   ((reader->ctxt->node == NULL) ||
1340 	    (reader->ctxt->node == reader->node) ||
1341 	    (reader->ctxt->node == reader->node->parent)) &&
1342 	   (reader->ctxt->instate != XML_PARSER_EOF)) {
1343 	val = xmlTextReaderPushData(reader);
1344 	if (val < 0){
1345 		reader->mode = XML_TEXTREADER_MODE_ERROR;
1346 		reader->state = XML_TEXTREADER_ERROR;
1347 	    return(-1);
1348 	}
1349 	if (reader->node == NULL)
1350 	    goto node_end;
1351     }
1352     if (oldstate != XML_TEXTREADER_BACKTRACK) {
1353 	if ((reader->node->children != NULL) &&
1354 	    (reader->node->type != XML_ENTITY_REF_NODE) &&
1355 	    (reader->node->type != XML_XINCLUDE_START) &&
1356 	    (reader->node->type != XML_DTD_NODE)) {
1357 	    reader->node = reader->node->children;
1358 	    reader->depth++;
1359 	    reader->state = XML_TEXTREADER_ELEMENT;
1360 	    goto node_found;
1361 	}
1362     }
1363     if (reader->node->next != NULL) {
1364 	if ((oldstate == XML_TEXTREADER_ELEMENT) &&
1365             (reader->node->type == XML_ELEMENT_NODE) &&
1366 	    (reader->node->children == NULL) &&
1367 	    ((reader->node->extra & NODE_IS_EMPTY) == 0)
1368 #ifdef LIBXML_XINCLUDE_ENABLED
1369 	    && (reader->in_xinclude <= 0)
1370 #endif
1371 	    ) {
1372 	    reader->state = XML_TEXTREADER_END;
1373 	    goto node_found;
1374 	}
1375 #ifdef LIBXML_REGEXP_ENABLED
1376 	if ((reader->validate) &&
1377 	    (reader->node->type == XML_ELEMENT_NODE))
1378 	    xmlTextReaderValidatePop(reader);
1379 #endif /* LIBXML_REGEXP_ENABLED */
1380         if ((reader->preserves > 0) &&
1381 	    (reader->node->extra & NODE_IS_SPRESERVED))
1382 	    reader->preserves--;
1383 	reader->node = reader->node->next;
1384 	reader->state = XML_TEXTREADER_ELEMENT;
1385 
1386 	/*
1387 	 * Cleanup of the old node
1388 	 */
1389 	if ((reader->preserves == 0) &&
1390 #ifdef LIBXML_XINCLUDE_ENABLED
1391 	    (reader->in_xinclude == 0) &&
1392 #endif
1393 	    (reader->entNr == 0) &&
1394 	    (reader->node->prev != NULL) &&
1395             (reader->node->prev->type != XML_DTD_NODE) &&
1396 	    (reader->entNr == 0)) {
1397 	    xmlNodePtr tmp = reader->node->prev;
1398 	    if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
1399 		xmlUnlinkNode(tmp);
1400 		xmlTextReaderFreeNode(reader, tmp);
1401 	    }
1402 	}
1403 
1404 	goto node_found;
1405     }
1406     if ((oldstate == XML_TEXTREADER_ELEMENT) &&
1407 	(reader->node->type == XML_ELEMENT_NODE) &&
1408 	(reader->node->children == NULL) &&
1409 	((reader->node->extra & NODE_IS_EMPTY) == 0)) {;
1410 	reader->state = XML_TEXTREADER_END;
1411 	goto node_found;
1412     }
1413 #ifdef LIBXML_REGEXP_ENABLED
1414     if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE))
1415 	xmlTextReaderValidatePop(reader);
1416 #endif /* LIBXML_REGEXP_ENABLED */
1417     if ((reader->preserves > 0) &&
1418 	(reader->node->extra & NODE_IS_SPRESERVED))
1419 	reader->preserves--;
1420     reader->node = reader->node->parent;
1421     if ((reader->node == NULL) ||
1422 	(reader->node->type == XML_DOCUMENT_NODE) ||
1423 #ifdef LIBXML_DOCB_ENABLED
1424 	(reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
1425 #endif
1426 	(reader->node->type == XML_HTML_DOCUMENT_NODE)) {
1427 	if (reader->mode != XML_TEXTREADER_MODE_EOF) {
1428 	    val = xmlParseChunk(reader->ctxt, "", 0, 1);
1429 	    reader->state = XML_TEXTREADER_DONE;
1430 	    if (val != 0)
1431 	        return(-1);
1432 	}
1433 	reader->node = NULL;
1434 	reader->depth = -1;
1435 
1436 	/*
1437 	 * Cleanup of the old node
1438 	 */
1439 	if ((oldnode != NULL) && (reader->preserves == 0) &&
1440 #ifdef LIBXML_XINCLUDE_ENABLED
1441 	    (reader->in_xinclude == 0) &&
1442 #endif
1443 	    (reader->entNr == 0) &&
1444 	    (oldnode->type != XML_DTD_NODE) &&
1445 	    ((oldnode->extra & NODE_IS_PRESERVED) == 0) &&
1446 	    (reader->entNr == 0)) {
1447 	    xmlUnlinkNode(oldnode);
1448 	    xmlTextReaderFreeNode(reader, oldnode);
1449 	}
1450 
1451 	goto node_end;
1452     }
1453     if ((reader->preserves == 0) &&
1454 #ifdef LIBXML_XINCLUDE_ENABLED
1455         (reader->in_xinclude == 0) &&
1456 #endif
1457 	(reader->entNr == 0) &&
1458         (reader->node->last != NULL) &&
1459         ((reader->node->last->extra & NODE_IS_PRESERVED) == 0)) {
1460 	xmlNodePtr tmp = reader->node->last;
1461 	xmlUnlinkNode(tmp);
1462 	xmlTextReaderFreeNode(reader, tmp);
1463     }
1464     reader->depth--;
1465     reader->state = XML_TEXTREADER_BACKTRACK;
1466 
1467 node_found:
1468     DUMP_READER
1469 
1470     /*
1471      * If we are in the middle of a piece of CDATA make sure it's finished
1472      */
1473     if ((reader->node != NULL) &&
1474         (reader->node->next == NULL) &&
1475         ((reader->node->type == XML_TEXT_NODE) ||
1476 	 (reader->node->type == XML_CDATA_SECTION_NODE))) {
1477             if (xmlTextReaderExpand(reader) == NULL)
1478 	        return -1;
1479     }
1480 
1481 #ifdef LIBXML_XINCLUDE_ENABLED
1482     /*
1483      * Handle XInclude if asked for
1484      */
1485     if ((reader->xinclude) && (reader->node != NULL) &&
1486 	(reader->node->type == XML_ELEMENT_NODE) &&
1487 	(reader->node->ns != NULL) &&
1488 	((xmlStrEqual(reader->node->ns->href, XINCLUDE_NS)) ||
1489 	 (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) {
1490 	if (reader->xincctxt == NULL) {
1491 	    reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc);
1492 	    xmlXIncludeSetFlags(reader->xincctxt,
1493 	                        reader->parserFlags & (~XML_PARSE_NOXINCNODE));
1494 	}
1495 	/*
1496 	 * expand that node and process it
1497 	 */
1498 	if (xmlTextReaderExpand(reader) == NULL)
1499 	    return -1;
1500 	xmlXIncludeProcessNode(reader->xincctxt, reader->node);
1501     }
1502     if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) {
1503         reader->in_xinclude++;
1504 	goto get_next_node;
1505     }
1506     if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_END)) {
1507         reader->in_xinclude--;
1508 	goto get_next_node;
1509     }
1510 #endif
1511     /*
1512      * Handle entities enter and exit when in entity replacement mode
1513      */
1514     if ((reader->node != NULL) &&
1515 	(reader->node->type == XML_ENTITY_REF_NODE) &&
1516 	(reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
1517 	/*
1518 	 * Case where the underlying tree is not availble, lookup the entity
1519 	 * and walk it.
1520 	 */
1521 	if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
1522 	    (reader->ctxt->sax->getEntity != NULL)) {
1523 	    reader->node->children = (xmlNodePtr)
1524 		reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
1525 	}
1526 
1527 	if ((reader->node->children != NULL) &&
1528 	    (reader->node->children->type == XML_ENTITY_DECL) &&
1529 	    (reader->node->children->children != NULL)) {
1530 	    xmlTextReaderEntPush(reader, reader->node);
1531 	    reader->node = reader->node->children->children;
1532 	}
1533 #ifdef LIBXML_REGEXP_ENABLED
1534     } else if ((reader->node != NULL) &&
1535 	       (reader->node->type == XML_ENTITY_REF_NODE) &&
1536 	       (reader->ctxt != NULL) && (reader->validate)) {
1537 	xmlTextReaderValidateEntity(reader);
1538 #endif /* LIBXML_REGEXP_ENABLED */
1539     }
1540     if ((reader->node != NULL) &&
1541 	(reader->node->type == XML_ENTITY_DECL) &&
1542 	(reader->ent != NULL) && (reader->ent->children == reader->node)) {
1543 	reader->node = xmlTextReaderEntPop(reader);
1544 	reader->depth++;
1545         goto get_next_node;
1546     }
1547 #ifdef LIBXML_REGEXP_ENABLED
1548     if ((reader->validate) && (reader->node != NULL)) {
1549 	xmlNodePtr node = reader->node;
1550 
1551 	if ((node->type == XML_ELEMENT_NODE) &&
1552             ((reader->state != XML_TEXTREADER_END) &&
1553 	     (reader->state != XML_TEXTREADER_BACKTRACK))) {
1554 	    xmlTextReaderValidatePush(reader);
1555 	} else if ((node->type == XML_TEXT_NODE) ||
1556 		   (node->type == XML_CDATA_SECTION_NODE)) {
1557             xmlTextReaderValidateCData(reader, node->content,
1558 	                               xmlStrlen(node->content));
1559 	}
1560     }
1561 #endif /* LIBXML_REGEXP_ENABLED */
1562 #ifdef LIBXML_PATTERN_ENABLED
1563     if ((reader->patternNr > 0) && (reader->state != XML_TEXTREADER_END) &&
1564         (reader->state != XML_TEXTREADER_BACKTRACK)) {
1565         int i;
1566 	for (i = 0;i < reader->patternNr;i++) {
1567 	     if (xmlPatternMatch(reader->patternTab[i], reader->node) == 1) {
1568 	         xmlTextReaderPreserve(reader);
1569 		 break;
1570              }
1571 	}
1572     }
1573 #endif /* LIBXML_PATTERN_ENABLED */
1574 #ifdef LIBXML_SCHEMAS_ENABLED
1575     if ((reader->validate == XML_TEXTREADER_VALIDATE_XSD) &&
1576         (reader->xsdValidErrors == 0) &&
1577 	(reader->xsdValidCtxt != NULL)) {
1578 	reader->xsdValidErrors = !xmlSchemaIsValid(reader->xsdValidCtxt);
1579     }
1580 #endif /* LIBXML_PATTERN_ENABLED */
1581     return(1);
1582 node_end:
1583     reader->state = XML_TEXTREADER_DONE;
1584     return(0);
1585 }
1586 
1587 /**
1588  * xmlTextReaderReadState:
1589  * @reader:  the xmlTextReaderPtr used
1590  *
1591  * Gets the read state of the reader.
1592  *
1593  * Returns the state value, or -1 in case of error
1594  */
1595 int
xmlTextReaderReadState(xmlTextReaderPtr reader)1596 xmlTextReaderReadState(xmlTextReaderPtr reader) {
1597     if (reader == NULL)
1598 	return(-1);
1599     return(reader->mode);
1600 }
1601 
1602 /**
1603  * xmlTextReaderExpand:
1604  * @reader:  the xmlTextReaderPtr used
1605  *
1606  * Reads the contents of the current node and the full subtree. It then makes
1607  * the subtree available until the next xmlTextReaderRead() call
1608  *
1609  * Returns a node pointer valid until the next xmlTextReaderRead() call
1610  *         or NULL in case of error.
1611  */
1612 xmlNodePtr
xmlTextReaderExpand(xmlTextReaderPtr reader)1613 xmlTextReaderExpand(xmlTextReaderPtr reader) {
1614     if ((reader == NULL) || (reader->node == NULL))
1615         return(NULL);
1616     if (reader->doc != NULL)
1617         return(reader->node);
1618     if (reader->ctxt == NULL)
1619         return(NULL);
1620     if (xmlTextReaderDoExpand(reader) < 0)
1621         return(NULL);
1622     return(reader->node);
1623 }
1624 
1625 /**
1626  * xmlTextReaderNext:
1627  * @reader:  the xmlTextReaderPtr used
1628  *
1629  * Skip to the node following the current one in document order while
1630  * avoiding the subtree if any.
1631  *
1632  * Returns 1 if the node was read successfully, 0 if there is no more
1633  *          nodes to read, or -1 in case of error
1634  */
1635 int
xmlTextReaderNext(xmlTextReaderPtr reader)1636 xmlTextReaderNext(xmlTextReaderPtr reader) {
1637     int ret;
1638     xmlNodePtr cur;
1639 
1640     if (reader == NULL)
1641 	return(-1);
1642     if (reader->doc != NULL)
1643         return(xmlTextReaderNextTree(reader));
1644     cur = reader->node;
1645     if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
1646         return(xmlTextReaderRead(reader));
1647     if (reader->state == XML_TEXTREADER_END || reader->state == XML_TEXTREADER_BACKTRACK)
1648         return(xmlTextReaderRead(reader));
1649     if (cur->extra & NODE_IS_EMPTY)
1650         return(xmlTextReaderRead(reader));
1651     do {
1652         ret = xmlTextReaderRead(reader);
1653 	if (ret != 1)
1654 	    return(ret);
1655     } while (reader->node != cur);
1656     return(xmlTextReaderRead(reader));
1657 }
1658 
1659 #ifdef LIBXML_WRITER_ENABLED
1660 /**
1661  * xmlTextReaderReadInnerXml:
1662  * @reader:  the xmlTextReaderPtr used
1663  *
1664  * Reads the contents of the current node, including child nodes and markup.
1665  *
1666  * Returns a string containing the XML content, or NULL if the current node
1667  *         is neither an element nor attribute, or has no child nodes. The
1668  *         string must be deallocated by the caller.
1669  */
1670 xmlChar *
xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)1671 xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
1672 {
1673     xmlChar *resbuf;
1674     xmlNodePtr node, cur_node;
1675     xmlBufferPtr buff, buff2;
1676     xmlDocPtr doc;
1677 
1678     if (xmlTextReaderExpand(reader) == NULL) {
1679         return NULL;
1680     }
1681     doc = reader->doc;
1682     buff = xmlBufferCreate();
1683     for (cur_node = reader->node->children; cur_node != NULL;
1684          cur_node = cur_node->next) {
1685         node = xmlDocCopyNode(cur_node, doc, 1);
1686         buff2 = xmlBufferCreate();
1687         if (xmlNodeDump(buff2, doc, node, 0, 0) == -1) {
1688             xmlFreeNode(node);
1689             xmlBufferFree(buff2);
1690             xmlBufferFree(buff);
1691             return NULL;
1692         }
1693         xmlBufferCat(buff, buff2->content);
1694         xmlFreeNode(node);
1695         xmlBufferFree(buff2);
1696     }
1697     resbuf = buff->content;
1698     buff->content = NULL;
1699 
1700     xmlBufferFree(buff);
1701     return resbuf;
1702 }
1703 #endif
1704 
1705 #ifdef LIBXML_WRITER_ENABLED
1706 /**
1707  * xmlTextReaderReadOuterXml:
1708  * @reader:  the xmlTextReaderPtr used
1709  *
1710  * Reads the contents of the current node, including child nodes and markup.
1711  *
1712  * Returns a string containing the XML content, or NULL if the current node
1713  *         is neither an element nor attribute, or has no child nodes. The
1714  *         string must be deallocated by the caller.
1715  */
1716 xmlChar *
xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)1717 xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
1718 {
1719     xmlChar *resbuf;
1720     xmlNodePtr node;
1721     xmlBufferPtr buff;
1722     xmlDocPtr doc;
1723 
1724     node = reader->node;
1725     doc = reader->doc;
1726     if (xmlTextReaderExpand(reader) == NULL) {
1727         return NULL;
1728     }
1729     node = xmlDocCopyNode(node, doc, 1);
1730     buff = xmlBufferCreate();
1731     if (xmlNodeDump(buff, doc, node, 0, 0) == -1) {
1732         xmlFreeNode(node);
1733         xmlBufferFree(buff);
1734         return NULL;
1735     }
1736 
1737     resbuf = buff->content;
1738     buff->content = NULL;
1739 
1740     xmlFreeNode(node);
1741     xmlBufferFree(buff);
1742     return resbuf;
1743 }
1744 #endif
1745 
1746 /**
1747  * xmlTextReaderReadString:
1748  * @reader:  the xmlTextReaderPtr used
1749  *
1750  * Reads the contents of an element or a text node as a string.
1751  *
1752  * Returns a string containing the contents of the Element or Text node,
1753  *         or NULL if the reader is positioned on any other type of node.
1754  *         The string must be deallocated by the caller.
1755  */
1756 xmlChar *
xmlTextReaderReadString(xmlTextReaderPtr reader)1757 xmlTextReaderReadString(xmlTextReaderPtr reader)
1758 {
1759     xmlNodePtr node;
1760 
1761     if ((reader == NULL) || (reader->node == NULL))
1762        return(NULL);
1763 
1764     node = (reader->curnode != NULL) ? reader->curnode : reader->node;
1765     switch (node->type) {
1766     case XML_TEXT_NODE:
1767        if (node->content != NULL)
1768            return(xmlStrdup(node->content));
1769        break;
1770     case XML_ELEMENT_NODE:
1771 	if (xmlTextReaderDoExpand(reader) != -1) {
1772 	    return xmlTextReaderCollectSiblings(node->children);
1773 	}
1774     case XML_ATTRIBUTE_NODE:
1775 	TODO
1776 	break;
1777     default:
1778        break;
1779     }
1780     return(NULL);
1781 }
1782 
1783 #if 0
1784 /**
1785  * xmlTextReaderReadBase64:
1786  * @reader:  the xmlTextReaderPtr used
1787  * @array:  a byte array to store the content.
1788  * @offset:  the zero-based index into array where the method should
1789  *           begin to write.
1790  * @len:  the number of bytes to write.
1791  *
1792  * Reads and decodes the Base64 encoded contents of an element and
1793  * stores the result in a byte buffer.
1794  *
1795  * Returns the number of bytes written to array, or zero if the current
1796  *         instance is not positioned on an element or -1 in case of error.
1797  */
1798 int
1799 xmlTextReaderReadBase64(xmlTextReaderPtr reader,
1800                         unsigned char *array ATTRIBUTE_UNUSED,
1801 	                int offset ATTRIBUTE_UNUSED,
1802 			int len ATTRIBUTE_UNUSED) {
1803     if ((reader == NULL) || (reader->ctxt == NULL))
1804 	return(-1);
1805     if (reader->ctxt->wellFormed != 1)
1806 	return(-1);
1807 
1808     if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1809 	return(0);
1810     TODO
1811     return(0);
1812 }
1813 
1814 /**
1815  * xmlTextReaderReadBinHex:
1816  * @reader:  the xmlTextReaderPtr used
1817  * @array:  a byte array to store the content.
1818  * @offset:  the zero-based index into array where the method should
1819  *           begin to write.
1820  * @len:  the number of bytes to write.
1821  *
1822  * Reads and decodes the BinHex encoded contents of an element and
1823  * stores the result in a byte buffer.
1824  *
1825  * Returns the number of bytes written to array, or zero if the current
1826  *         instance is not positioned on an element or -1 in case of error.
1827  */
1828 int
1829 xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
1830                         unsigned char *array ATTRIBUTE_UNUSED,
1831 	                int offset ATTRIBUTE_UNUSED,
1832 			int len ATTRIBUTE_UNUSED) {
1833     if ((reader == NULL) || (reader->ctxt == NULL))
1834 	return(-1);
1835     if (reader->ctxt->wellFormed != 1)
1836 	return(-1);
1837 
1838     if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1839 	return(0);
1840     TODO
1841     return(0);
1842 }
1843 #endif
1844 
1845 /************************************************************************
1846  *									*
1847  *			Operating on a preparsed tree			*
1848  *									*
1849  ************************************************************************/
1850 static int
xmlTextReaderNextTree(xmlTextReaderPtr reader)1851 xmlTextReaderNextTree(xmlTextReaderPtr reader)
1852 {
1853     if (reader == NULL)
1854         return(-1);
1855 
1856     if (reader->state == XML_TEXTREADER_END)
1857         return(0);
1858 
1859     if (reader->node == NULL) {
1860         if (reader->doc->children == NULL) {
1861             reader->state = XML_TEXTREADER_END;
1862             return(0);
1863         }
1864 
1865         reader->node = reader->doc->children;
1866         reader->state = XML_TEXTREADER_START;
1867         return(1);
1868     }
1869 
1870     if (reader->state != XML_TEXTREADER_BACKTRACK) {
1871 	/* Here removed traversal to child, because we want to skip the subtree,
1872 	replace with traversal to sibling to skip subtree */
1873         if (reader->node->next != 0) {
1874 	    /* Move to sibling if present,skipping sub-tree */
1875             reader->node = reader->node->next;
1876             reader->state = XML_TEXTREADER_START;
1877             return(1);
1878         }
1879 
1880 	/* if reader->node->next is NULL mean no subtree for current node,
1881 	so need to move to sibling of parent node if present */
1882         if ((reader->node->type == XML_ELEMENT_NODE) ||
1883             (reader->node->type == XML_ATTRIBUTE_NODE)) {
1884             reader->state = XML_TEXTREADER_BACKTRACK;
1885 	    /* This will move to parent if present */
1886             xmlTextReaderRead(reader);
1887         }
1888     }
1889 
1890     if (reader->node->next != 0) {
1891         reader->node = reader->node->next;
1892         reader->state = XML_TEXTREADER_START;
1893         return(1);
1894     }
1895 
1896     if (reader->node->parent != 0) {
1897         if (reader->node->parent->type == XML_DOCUMENT_NODE) {
1898             reader->state = XML_TEXTREADER_END;
1899             return(0);
1900         }
1901 
1902         reader->node = reader->node->parent;
1903         reader->depth--;
1904         reader->state = XML_TEXTREADER_BACKTRACK;
1905 	/* Repeat process to move to sibling of parent node if present */
1906         xmlTextReaderNextTree(reader);
1907     }
1908 
1909     reader->state = XML_TEXTREADER_END;
1910 
1911     return(1);
1912 }
1913 
1914 /**
1915  * xmlTextReaderReadTree:
1916  * @reader:  the xmlTextReaderPtr used
1917  *
1918  *  Moves the position of the current instance to the next node in
1919  *  the stream, exposing its properties.
1920  *
1921  *  Returns 1 if the node was read successfully, 0 if there is no more
1922  *          nodes to read, or -1 in case of error
1923  */
1924 static int
xmlTextReaderReadTree(xmlTextReaderPtr reader)1925 xmlTextReaderReadTree(xmlTextReaderPtr reader) {
1926     if (reader->state == XML_TEXTREADER_END)
1927         return(0);
1928 
1929 next_node:
1930     if (reader->node == NULL) {
1931         if (reader->doc->children == NULL) {
1932             reader->state = XML_TEXTREADER_END;
1933             return(0);
1934         }
1935 
1936         reader->node = reader->doc->children;
1937         reader->state = XML_TEXTREADER_START;
1938         goto found_node;
1939     }
1940 
1941     if ((reader->state != XML_TEXTREADER_BACKTRACK) &&
1942         (reader->node->type != XML_DTD_NODE) &&
1943         (reader->node->type != XML_XINCLUDE_START) &&
1944 	(reader->node->type != XML_ENTITY_REF_NODE)) {
1945         if (reader->node->children != NULL) {
1946             reader->node = reader->node->children;
1947             reader->depth++;
1948             reader->state = XML_TEXTREADER_START;
1949             goto found_node;
1950         }
1951 
1952         if (reader->node->type == XML_ATTRIBUTE_NODE) {
1953             reader->state = XML_TEXTREADER_BACKTRACK;
1954             goto found_node;
1955         }
1956     }
1957 
1958     if (reader->node->next != NULL) {
1959         reader->node = reader->node->next;
1960         reader->state = XML_TEXTREADER_START;
1961         goto found_node;
1962     }
1963 
1964     if (reader->node->parent != NULL) {
1965         if ((reader->node->parent->type == XML_DOCUMENT_NODE) ||
1966 	    (reader->node->parent->type == XML_HTML_DOCUMENT_NODE)) {
1967             reader->state = XML_TEXTREADER_END;
1968             return(0);
1969         }
1970 
1971         reader->node = reader->node->parent;
1972         reader->depth--;
1973         reader->state = XML_TEXTREADER_BACKTRACK;
1974         goto found_node;
1975     }
1976 
1977     reader->state = XML_TEXTREADER_END;
1978 
1979 found_node:
1980     if ((reader->node->type == XML_XINCLUDE_START) ||
1981         (reader->node->type == XML_XINCLUDE_END))
1982 	goto next_node;
1983 
1984     return(1);
1985 }
1986 
1987 /**
1988  * xmlTextReaderNextSibling:
1989  * @reader:  the xmlTextReaderPtr used
1990  *
1991  * Skip to the node following the current one in document order while
1992  * avoiding the subtree if any.
1993  * Currently implemented only for Readers built on a document
1994  *
1995  * Returns 1 if the node was read successfully, 0 if there is no more
1996  *          nodes to read, or -1 in case of error
1997  */
1998 int
xmlTextReaderNextSibling(xmlTextReaderPtr reader)1999 xmlTextReaderNextSibling(xmlTextReaderPtr reader) {
2000     if (reader == NULL)
2001         return(-1);
2002     if (reader->doc == NULL) {
2003         /* TODO */
2004 	return(-1);
2005     }
2006 
2007     if (reader->state == XML_TEXTREADER_END)
2008         return(0);
2009 
2010     if (reader->node == NULL)
2011         return(xmlTextReaderNextTree(reader));
2012 
2013     if (reader->node->next != NULL) {
2014         reader->node = reader->node->next;
2015         reader->state = XML_TEXTREADER_START;
2016         return(1);
2017     }
2018 
2019     return(0);
2020 }
2021 
2022 /************************************************************************
2023  *									*
2024  *			Constructor and destructors			*
2025  *									*
2026  ************************************************************************/
2027 /**
2028  * xmlNewTextReader:
2029  * @input: the xmlParserInputBufferPtr used to read data
2030  * @URI: the URI information for the source if available
2031  *
2032  * Create an xmlTextReader structure fed with @input
2033  *
2034  * Returns the new xmlTextReaderPtr or NULL in case of error
2035  */
2036 xmlTextReaderPtr
xmlNewTextReader(xmlParserInputBufferPtr input,const char * URI)2037 xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
2038     xmlTextReaderPtr ret;
2039 
2040     if (input == NULL)
2041 	return(NULL);
2042     ret = xmlMalloc(sizeof(xmlTextReader));
2043     if (ret == NULL) {
2044         xmlGenericError(xmlGenericErrorContext,
2045 		"xmlNewTextReader : malloc failed\n");
2046 	return(NULL);
2047     }
2048     memset(ret, 0, sizeof(xmlTextReader));
2049     ret->doc = NULL;
2050     ret->entTab = NULL;
2051     ret->entMax = 0;
2052     ret->entNr = 0;
2053     ret->input = input;
2054     ret->buffer = xmlBufferCreateSize(100);
2055     if (ret->buffer == NULL) {
2056         xmlFree(ret);
2057         xmlGenericError(xmlGenericErrorContext,
2058 		"xmlNewTextReader : malloc failed\n");
2059 	return(NULL);
2060     }
2061     ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
2062     if (ret->sax == NULL) {
2063 	xmlBufferFree(ret->buffer);
2064 	xmlFree(ret);
2065         xmlGenericError(xmlGenericErrorContext,
2066 		"xmlNewTextReader : malloc failed\n");
2067 	return(NULL);
2068     }
2069     xmlSAXVersion(ret->sax, 2);
2070     ret->startElement = ret->sax->startElement;
2071     ret->sax->startElement = xmlTextReaderStartElement;
2072     ret->endElement = ret->sax->endElement;
2073     ret->sax->endElement = xmlTextReaderEndElement;
2074 #ifdef LIBXML_SAX1_ENABLED
2075     if (ret->sax->initialized == XML_SAX2_MAGIC) {
2076 #endif /* LIBXML_SAX1_ENABLED */
2077 	ret->startElementNs = ret->sax->startElementNs;
2078 	ret->sax->startElementNs = xmlTextReaderStartElementNs;
2079 	ret->endElementNs = ret->sax->endElementNs;
2080 	ret->sax->endElementNs = xmlTextReaderEndElementNs;
2081 #ifdef LIBXML_SAX1_ENABLED
2082     } else {
2083 	ret->startElementNs = NULL;
2084 	ret->endElementNs = NULL;
2085     }
2086 #endif /* LIBXML_SAX1_ENABLED */
2087     ret->characters = ret->sax->characters;
2088     ret->sax->characters = xmlTextReaderCharacters;
2089     ret->sax->ignorableWhitespace = xmlTextReaderCharacters;
2090     ret->cdataBlock = ret->sax->cdataBlock;
2091     ret->sax->cdataBlock = xmlTextReaderCDataBlock;
2092 
2093     ret->mode = XML_TEXTREADER_MODE_INITIAL;
2094     ret->node = NULL;
2095     ret->curnode = NULL;
2096     if (ret->input->buffer->use < 4) {
2097 	xmlParserInputBufferRead(input, 4);
2098     }
2099     if (ret->input->buffer->use >= 4) {
2100 	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
2101 			(const char *) ret->input->buffer->content, 4, URI);
2102 	ret->base = 0;
2103 	ret->cur = 4;
2104     } else {
2105 	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
2106 	ret->base = 0;
2107 	ret->cur = 0;
2108     }
2109 
2110     if (ret->ctxt == NULL) {
2111         xmlGenericError(xmlGenericErrorContext,
2112 		"xmlNewTextReader : malloc failed\n");
2113 	xmlBufferFree(ret->buffer);
2114 	xmlFree(ret->sax);
2115 	xmlFree(ret);
2116 	return(NULL);
2117     }
2118     ret->ctxt->parseMode = XML_PARSE_READER;
2119     ret->ctxt->_private = ret;
2120     ret->ctxt->linenumbers = 1;
2121     ret->ctxt->dictNames = 1;
2122     ret->allocs = XML_TEXTREADER_CTXT;
2123     /*
2124      * use the parser dictionnary to allocate all elements and attributes names
2125      */
2126     ret->ctxt->docdict = 1;
2127     ret->dict = ret->ctxt->dict;
2128 #ifdef LIBXML_XINCLUDE_ENABLED
2129     ret->xinclude = 0;
2130 #endif
2131 #ifdef LIBXML_PATTERN_ENABLED
2132     ret->patternMax = 0;
2133     ret->patternTab = NULL;
2134 #endif
2135     return(ret);
2136 }
2137 
2138 /**
2139  * xmlNewTextReaderFilename:
2140  * @URI: the URI of the resource to process
2141  *
2142  * Create an xmlTextReader structure fed with the resource at @URI
2143  *
2144  * Returns the new xmlTextReaderPtr or NULL in case of error
2145  */
2146 xmlTextReaderPtr
xmlNewTextReaderFilename(const char * URI)2147 xmlNewTextReaderFilename(const char *URI) {
2148     xmlParserInputBufferPtr input;
2149     xmlTextReaderPtr ret;
2150     char *directory = NULL;
2151 
2152     input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
2153     if (input == NULL)
2154 	return(NULL);
2155     ret = xmlNewTextReader(input, URI);
2156     if (ret == NULL) {
2157 	xmlFreeParserInputBuffer(input);
2158 	return(NULL);
2159     }
2160     ret->allocs |= XML_TEXTREADER_INPUT;
2161     if (ret->ctxt->directory == NULL)
2162         directory = xmlParserGetDirectory(URI);
2163     if ((ret->ctxt->directory == NULL) && (directory != NULL))
2164         ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
2165     if (directory != NULL)
2166 	xmlFree(directory);
2167     return(ret);
2168 }
2169 
2170 /**
2171  * xmlFreeTextReader:
2172  * @reader:  the xmlTextReaderPtr
2173  *
2174  * Deallocate all the resources associated to the reader
2175  */
2176 void
xmlFreeTextReader(xmlTextReaderPtr reader)2177 xmlFreeTextReader(xmlTextReaderPtr reader) {
2178     if (reader == NULL)
2179 	return;
2180 #ifdef LIBXML_SCHEMAS_ENABLED
2181     if (reader->rngSchemas != NULL) {
2182 	xmlRelaxNGFree(reader->rngSchemas);
2183 	reader->rngSchemas = NULL;
2184     }
2185     if (reader->rngValidCtxt != NULL) {
2186 	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2187 	reader->rngValidCtxt = NULL;
2188     }
2189     if (reader->xsdPlug != NULL) {
2190 	xmlSchemaSAXUnplug(reader->xsdPlug);
2191 	reader->xsdPlug = NULL;
2192     }
2193     if (reader->xsdValidCtxt != NULL) {
2194 	if (! reader->xsdPreserveCtxt)
2195 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
2196 	reader->xsdValidCtxt = NULL;
2197     }
2198     if (reader->xsdSchemas != NULL) {
2199 	xmlSchemaFree(reader->xsdSchemas);
2200 	reader->xsdSchemas = NULL;
2201     }
2202 #endif
2203 #ifdef LIBXML_XINCLUDE_ENABLED
2204     if (reader->xincctxt != NULL)
2205 	xmlXIncludeFreeContext(reader->xincctxt);
2206 #endif
2207 #ifdef LIBXML_PATTERN_ENABLED
2208     if (reader->patternTab != NULL) {
2209         int i;
2210 	for (i = 0;i < reader->patternNr;i++) {
2211 	    if (reader->patternTab[i] != NULL)
2212 	        xmlFreePattern(reader->patternTab[i]);
2213 	}
2214 	xmlFree(reader->patternTab);
2215     }
2216 #endif
2217     if (reader->faketext != NULL) {
2218 	xmlFreeNode(reader->faketext);
2219     }
2220     if (reader->ctxt != NULL) {
2221         if (reader->dict == reader->ctxt->dict)
2222 	    reader->dict = NULL;
2223 	if (reader->ctxt->myDoc != NULL) {
2224 	    if (reader->preserve == 0)
2225 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2226 	    reader->ctxt->myDoc = NULL;
2227 	}
2228 	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
2229 	    (reader->ctxt->vctxt.vstateMax > 0)){
2230 	    xmlFree(reader->ctxt->vctxt.vstateTab);
2231 	    reader->ctxt->vctxt.vstateTab = NULL;
2232 	    reader->ctxt->vctxt.vstateMax = 0;
2233 	}
2234 	if (reader->allocs & XML_TEXTREADER_CTXT)
2235 	    xmlFreeParserCtxt(reader->ctxt);
2236     }
2237     if (reader->sax != NULL)
2238 	xmlFree(reader->sax);
2239     if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT))
2240 	xmlFreeParserInputBuffer(reader->input);
2241     if (reader->buffer != NULL)
2242         xmlBufferFree(reader->buffer);
2243     if (reader->entTab != NULL)
2244 	xmlFree(reader->entTab);
2245     if (reader->dict != NULL)
2246         xmlDictFree(reader->dict);
2247     xmlFree(reader);
2248 }
2249 
2250 /************************************************************************
2251  *									*
2252  *			Methods for XmlTextReader			*
2253  *									*
2254  ************************************************************************/
2255 /**
2256  * xmlTextReaderClose:
2257  * @reader:  the xmlTextReaderPtr used
2258  *
2259  * This method releases any resources allocated by the current instance
2260  * changes the state to Closed and close any underlying input.
2261  *
2262  * Returns 0 or -1 in case of error
2263  */
2264 int
xmlTextReaderClose(xmlTextReaderPtr reader)2265 xmlTextReaderClose(xmlTextReaderPtr reader) {
2266     if (reader == NULL)
2267 	return(-1);
2268     reader->node = NULL;
2269     reader->curnode = NULL;
2270     reader->mode = XML_TEXTREADER_MODE_CLOSED;
2271     if (reader->ctxt != NULL) {
2272 	xmlStopParser(reader->ctxt);
2273 	if (reader->ctxt->myDoc != NULL) {
2274 	    if (reader->preserve == 0)
2275 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2276 	    reader->ctxt->myDoc = NULL;
2277 	}
2278     }
2279     if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT)) {
2280 	xmlFreeParserInputBuffer(reader->input);
2281 	reader->allocs -= XML_TEXTREADER_INPUT;
2282     }
2283     return(0);
2284 }
2285 
2286 /**
2287  * xmlTextReaderGetAttributeNo:
2288  * @reader:  the xmlTextReaderPtr used
2289  * @no: the zero-based index of the attribute relative to the containing element
2290  *
2291  * Provides the value of the attribute with the specified index relative
2292  * to the containing element.
2293  *
2294  * Returns a string containing the value of the specified attribute, or NULL
2295  *    in case of error. The string must be deallocated by the caller.
2296  */
2297 xmlChar *
xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader,int no)2298 xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
2299     xmlChar *ret;
2300     int i;
2301     xmlAttrPtr cur;
2302     xmlNsPtr ns;
2303 
2304     if (reader == NULL)
2305 	return(NULL);
2306     if (reader->node == NULL)
2307 	return(NULL);
2308     if (reader->curnode != NULL)
2309 	return(NULL);
2310     /* TODO: handle the xmlDecl */
2311     if (reader->node->type != XML_ELEMENT_NODE)
2312 	return(NULL);
2313 
2314     ns = reader->node->nsDef;
2315     for (i = 0;(i < no) && (ns != NULL);i++) {
2316 	ns = ns->next;
2317     }
2318     if (ns != NULL)
2319 	return(xmlStrdup(ns->href));
2320 
2321     cur = reader->node->properties;
2322     if (cur == NULL)
2323 	return(NULL);
2324     for (;i < no;i++) {
2325 	cur = cur->next;
2326 	if (cur == NULL)
2327 	    return(NULL);
2328     }
2329     /* TODO walk the DTD if present */
2330 
2331     ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
2332     if (ret == NULL) return(xmlStrdup((xmlChar *)""));
2333     return(ret);
2334 }
2335 
2336 /**
2337  * xmlTextReaderGetAttribute:
2338  * @reader:  the xmlTextReaderPtr used
2339  * @name: the qualified name of the attribute.
2340  *
2341  * Provides the value of the attribute with the specified qualified name.
2342  *
2343  * Returns a string containing the value of the specified attribute, or NULL
2344  *    in case of error. The string must be deallocated by the caller.
2345  */
2346 xmlChar *
xmlTextReaderGetAttribute(xmlTextReaderPtr reader,const xmlChar * name)2347 xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
2348     xmlChar *prefix = NULL;
2349     xmlChar *localname;
2350     xmlNsPtr ns;
2351     xmlChar *ret = NULL;
2352 
2353     if ((reader == NULL) || (name == NULL))
2354 	return(NULL);
2355     if (reader->node == NULL)
2356 	return(NULL);
2357     if (reader->curnode != NULL)
2358 	return(NULL);
2359 
2360     /* TODO: handle the xmlDecl */
2361     if (reader->node->type != XML_ELEMENT_NODE)
2362 	return(NULL);
2363 
2364     localname = xmlSplitQName2(name, &prefix);
2365     if (localname == NULL) {
2366 		/*
2367 		 * Namespace default decl
2368 		 */
2369 		if (xmlStrEqual(name, BAD_CAST "xmlns")) {
2370 			ns = reader->node->nsDef;
2371 			while (ns != NULL) {
2372 				if (ns->prefix == NULL) {
2373 					return(xmlStrdup(ns->href));
2374 				}
2375 				ns = ns->next;
2376 			}
2377 			return NULL;
2378 		}
2379 		return(xmlGetNoNsProp(reader->node, name));
2380 	}
2381 
2382     /*
2383      * Namespace default decl
2384      */
2385     if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
2386 		ns = reader->node->nsDef;
2387 		while (ns != NULL) {
2388 			if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
2389 				ret = xmlStrdup(ns->href);
2390 				break;
2391 			}
2392 			ns = ns->next;
2393 		}
2394     } else {
2395 		ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
2396 		if (ns != NULL)
2397 			ret = xmlGetNsProp(reader->node, localname, ns->href);
2398 	}
2399 
2400     xmlFree(localname);
2401     if (prefix != NULL)
2402         xmlFree(prefix);
2403     return(ret);
2404 }
2405 
2406 
2407 /**
2408  * xmlTextReaderGetAttributeNs:
2409  * @reader:  the xmlTextReaderPtr used
2410  * @localName: the local name of the attribute.
2411  * @namespaceURI: the namespace URI of the attribute.
2412  *
2413  * Provides the value of the specified attribute
2414  *
2415  * Returns a string containing the value of the specified attribute, or NULL
2416  *    in case of error. The string must be deallocated by the caller.
2417  */
2418 xmlChar *
xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader,const xmlChar * localName,const xmlChar * namespaceURI)2419 xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
2420 			    const xmlChar *namespaceURI) {
2421     xmlChar *prefix = NULL;
2422     xmlNsPtr ns;
2423 
2424     if ((reader == NULL) || (localName == NULL))
2425 	return(NULL);
2426     if (reader->node == NULL)
2427 	return(NULL);
2428     if (reader->curnode != NULL)
2429 	return(NULL);
2430 
2431     /* TODO: handle the xmlDecl */
2432     if (reader->node->type != XML_ELEMENT_NODE)
2433 	return(NULL);
2434 
2435     if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
2436 		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
2437 			prefix = BAD_CAST localName;
2438 		}
2439 		ns = reader->node->nsDef;
2440 		while (ns != NULL) {
2441 			if ((prefix == NULL && ns->prefix == NULL) ||
2442 				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
2443 				return xmlStrdup(ns->href);
2444 			}
2445 			ns = ns->next;
2446 		}
2447 		return NULL;
2448     }
2449 
2450     return(xmlGetNsProp(reader->node, localName, namespaceURI));
2451 }
2452 
2453 /**
2454  * xmlTextReaderGetRemainder:
2455  * @reader:  the xmlTextReaderPtr used
2456  *
2457  * Method to get the remainder of the buffered XML. this method stops the
2458  * parser, set its state to End Of File and return the input stream with
2459  * what is left that the parser did not use.
2460  *
2461  * The implementation is not good, the parser certainly procgressed past
2462  * what's left in reader->input, and there is an allocation problem. Best
2463  * would be to rewrite it differently.
2464  *
2465  * Returns the xmlParserInputBufferPtr attached to the XML or NULL
2466  *    in case of error.
2467  */
2468 xmlParserInputBufferPtr
xmlTextReaderGetRemainder(xmlTextReaderPtr reader)2469 xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
2470     xmlParserInputBufferPtr ret = NULL;
2471 
2472     if (reader == NULL)
2473 	return(NULL);
2474     if (reader->node == NULL)
2475 	return(NULL);
2476 
2477     reader->node = NULL;
2478     reader->curnode = NULL;
2479     reader->mode = XML_TEXTREADER_MODE_EOF;
2480     if (reader->ctxt != NULL) {
2481 	xmlStopParser(reader->ctxt);
2482 	if (reader->ctxt->myDoc != NULL) {
2483 	    if (reader->preserve == 0)
2484 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2485 	    reader->ctxt->myDoc = NULL;
2486 	}
2487     }
2488     if (reader->allocs & XML_TEXTREADER_INPUT) {
2489 	ret = reader->input;
2490 	reader->input = NULL;
2491 	reader->allocs -= XML_TEXTREADER_INPUT;
2492     } else {
2493 	/*
2494 	 * Hum, one may need to duplicate the data structure because
2495 	 * without reference counting the input may be freed twice:
2496 	 *   - by the layer which allocated it.
2497 	 *   - by the layer to which would have been returned to.
2498 	 */
2499 	TODO
2500 	return(NULL);
2501     }
2502     return(ret);
2503 }
2504 
2505 /**
2506  * xmlTextReaderLookupNamespace:
2507  * @reader:  the xmlTextReaderPtr used
2508  * @prefix: the prefix whose namespace URI is to be resolved. To return
2509  *          the default namespace, specify NULL
2510  *
2511  * Resolves a namespace prefix in the scope of the current element.
2512  *
2513  * Returns a string containing the namespace URI to which the prefix maps
2514  *    or NULL in case of error. The string must be deallocated by the caller.
2515  */
2516 xmlChar *
xmlTextReaderLookupNamespace(xmlTextReaderPtr reader,const xmlChar * prefix)2517 xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
2518     xmlNsPtr ns;
2519 
2520     if (reader == NULL)
2521 	return(NULL);
2522     if (reader->node == NULL)
2523 	return(NULL);
2524 
2525     ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
2526     if (ns == NULL)
2527 	return(NULL);
2528     return(xmlStrdup(ns->href));
2529 }
2530 
2531 /**
2532  * xmlTextReaderMoveToAttributeNo:
2533  * @reader:  the xmlTextReaderPtr used
2534  * @no: the zero-based index of the attribute relative to the containing
2535  *      element.
2536  *
2537  * Moves the position of the current instance to the attribute with
2538  * the specified index relative to the containing element.
2539  *
2540  * Returns 1 in case of success, -1 in case of error, 0 if not found
2541  */
2542 int
xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader,int no)2543 xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
2544     int i;
2545     xmlAttrPtr cur;
2546     xmlNsPtr ns;
2547 
2548     if (reader == NULL)
2549 	return(-1);
2550     if (reader->node == NULL)
2551 	return(-1);
2552     /* TODO: handle the xmlDecl */
2553     if (reader->node->type != XML_ELEMENT_NODE)
2554 	return(-1);
2555 
2556     reader->curnode = NULL;
2557 
2558     ns = reader->node->nsDef;
2559     for (i = 0;(i < no) && (ns != NULL);i++) {
2560 	ns = ns->next;
2561     }
2562     if (ns != NULL) {
2563 	reader->curnode = (xmlNodePtr) ns;
2564 	return(1);
2565     }
2566 
2567     cur = reader->node->properties;
2568     if (cur == NULL)
2569 	return(0);
2570     for (;i < no;i++) {
2571 	cur = cur->next;
2572 	if (cur == NULL)
2573 	    return(0);
2574     }
2575     /* TODO walk the DTD if present */
2576 
2577     reader->curnode = (xmlNodePtr) cur;
2578     return(1);
2579 }
2580 
2581 /**
2582  * xmlTextReaderMoveToAttribute:
2583  * @reader:  the xmlTextReaderPtr used
2584  * @name: the qualified name of the attribute.
2585  *
2586  * Moves the position of the current instance to the attribute with
2587  * the specified qualified name.
2588  *
2589  * Returns 1 in case of success, -1 in case of error, 0 if not found
2590  */
2591 int
xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader,const xmlChar * name)2592 xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
2593     xmlChar *prefix = NULL;
2594     xmlChar *localname;
2595     xmlNsPtr ns;
2596     xmlAttrPtr prop;
2597 
2598     if ((reader == NULL) || (name == NULL))
2599 	return(-1);
2600     if (reader->node == NULL)
2601 	return(-1);
2602 
2603     /* TODO: handle the xmlDecl */
2604     if (reader->node->type != XML_ELEMENT_NODE)
2605 	return(0);
2606 
2607     localname = xmlSplitQName2(name, &prefix);
2608     if (localname == NULL) {
2609 	/*
2610 	 * Namespace default decl
2611 	 */
2612 	if (xmlStrEqual(name, BAD_CAST "xmlns")) {
2613 	    ns = reader->node->nsDef;
2614 	    while (ns != NULL) {
2615 		if (ns->prefix == NULL) {
2616 		    reader->curnode = (xmlNodePtr) ns;
2617 		    return(1);
2618 		}
2619 		ns = ns->next;
2620 	    }
2621 	    return(0);
2622 	}
2623 
2624 	prop = reader->node->properties;
2625 	while (prop != NULL) {
2626 	    /*
2627 	     * One need to have
2628 	     *   - same attribute names
2629 	     *   - and the attribute carrying that namespace
2630 	     */
2631 	    if ((xmlStrEqual(prop->name, name)) &&
2632 		((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
2633 		reader->curnode = (xmlNodePtr) prop;
2634 		return(1);
2635 	    }
2636 	    prop = prop->next;
2637 	}
2638 	return(0);
2639     }
2640 
2641     /*
2642      * Namespace default decl
2643      */
2644     if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
2645 	ns = reader->node->nsDef;
2646 	while (ns != NULL) {
2647 	    if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
2648 		reader->curnode = (xmlNodePtr) ns;
2649 		goto found;
2650 	    }
2651 	    ns = ns->next;
2652 	}
2653 	goto not_found;
2654     }
2655     prop = reader->node->properties;
2656     while (prop != NULL) {
2657 	/*
2658 	 * One need to have
2659 	 *   - same attribute names
2660 	 *   - and the attribute carrying that namespace
2661 	 */
2662 	if ((xmlStrEqual(prop->name, localname)) &&
2663 	    (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
2664 	    reader->curnode = (xmlNodePtr) prop;
2665 	    goto found;
2666 	}
2667 	prop = prop->next;
2668     }
2669 not_found:
2670     if (localname != NULL)
2671         xmlFree(localname);
2672     if (prefix != NULL)
2673         xmlFree(prefix);
2674     return(0);
2675 
2676 found:
2677     if (localname != NULL)
2678         xmlFree(localname);
2679     if (prefix != NULL)
2680         xmlFree(prefix);
2681     return(1);
2682 }
2683 
2684 /**
2685  * xmlTextReaderMoveToAttributeNs:
2686  * @reader:  the xmlTextReaderPtr used
2687  * @localName:  the local name of the attribute.
2688  * @namespaceURI:  the namespace URI of the attribute.
2689  *
2690  * Moves the position of the current instance to the attribute with the
2691  * specified local name and namespace URI.
2692  *
2693  * Returns 1 in case of success, -1 in case of error, 0 if not found
2694  */
2695 int
xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,const xmlChar * localName,const xmlChar * namespaceURI)2696 xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
2697 	const xmlChar *localName, const xmlChar *namespaceURI) {
2698     xmlAttrPtr prop;
2699     xmlNodePtr node;
2700     xmlNsPtr ns;
2701     xmlChar *prefix = NULL;
2702 
2703     if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
2704 	return(-1);
2705     if (reader->node == NULL)
2706 	return(-1);
2707     if (reader->node->type != XML_ELEMENT_NODE)
2708 	return(0);
2709     node = reader->node;
2710 
2711     if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
2712 		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
2713 			prefix = BAD_CAST localName;
2714 		}
2715 		ns = reader->node->nsDef;
2716 		while (ns != NULL) {
2717 			if ((prefix == NULL && ns->prefix == NULL) ||
2718 				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
2719 				reader->curnode = (xmlNodePtr) ns;
2720 				return(1);
2721 			}
2722 			ns = ns->next;
2723 		}
2724 		return(0);
2725     }
2726 
2727     prop = node->properties;
2728     while (prop != NULL) {
2729 	/*
2730 	 * One need to have
2731 	 *   - same attribute names
2732 	 *   - and the attribute carrying that namespace
2733 	 */
2734         if (xmlStrEqual(prop->name, localName) &&
2735 	    ((prop->ns != NULL) &&
2736 	     (xmlStrEqual(prop->ns->href, namespaceURI)))) {
2737 	    reader->curnode = (xmlNodePtr) prop;
2738 	    return(1);
2739         }
2740 	prop = prop->next;
2741     }
2742     return(0);
2743 }
2744 
2745 /**
2746  * xmlTextReaderMoveToFirstAttribute:
2747  * @reader:  the xmlTextReaderPtr used
2748  *
2749  * Moves the position of the current instance to the first attribute
2750  * associated with the current node.
2751  *
2752  * Returns 1 in case of success, -1 in case of error, 0 if not found
2753  */
2754 int
xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader)2755 xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
2756     if (reader == NULL)
2757 	return(-1);
2758     if (reader->node == NULL)
2759 	return(-1);
2760     if (reader->node->type != XML_ELEMENT_NODE)
2761 	return(0);
2762 
2763     if (reader->node->nsDef != NULL) {
2764 	reader->curnode = (xmlNodePtr) reader->node->nsDef;
2765 	return(1);
2766     }
2767     if (reader->node->properties != NULL) {
2768 	reader->curnode = (xmlNodePtr) reader->node->properties;
2769 	return(1);
2770     }
2771     return(0);
2772 }
2773 
2774 /**
2775  * xmlTextReaderMoveToNextAttribute:
2776  * @reader:  the xmlTextReaderPtr used
2777  *
2778  * Moves the position of the current instance to the next attribute
2779  * associated with the current node.
2780  *
2781  * Returns 1 in case of success, -1 in case of error, 0 if not found
2782  */
2783 int
xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader)2784 xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
2785     if (reader == NULL)
2786 	return(-1);
2787     if (reader->node == NULL)
2788 	return(-1);
2789     if (reader->node->type != XML_ELEMENT_NODE)
2790 	return(0);
2791     if (reader->curnode == NULL)
2792 	return(xmlTextReaderMoveToFirstAttribute(reader));
2793 
2794     if (reader->curnode->type == XML_NAMESPACE_DECL) {
2795 	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2796 	if (ns->next != NULL) {
2797 	    reader->curnode = (xmlNodePtr) ns->next;
2798 	    return(1);
2799 	}
2800 	if (reader->node->properties != NULL) {
2801 	    reader->curnode = (xmlNodePtr) reader->node->properties;
2802 	    return(1);
2803 	}
2804 	return(0);
2805     } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
2806 	       (reader->curnode->next != NULL)) {
2807 	reader->curnode = reader->curnode->next;
2808 	return(1);
2809     }
2810     return(0);
2811 }
2812 
2813 /**
2814  * xmlTextReaderMoveToElement:
2815  * @reader:  the xmlTextReaderPtr used
2816  *
2817  * Moves the position of the current instance to the node that
2818  * contains the current Attribute  node.
2819  *
2820  * Returns 1 in case of success, -1 in case of error, 0 if not moved
2821  */
2822 int
xmlTextReaderMoveToElement(xmlTextReaderPtr reader)2823 xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
2824     if (reader == NULL)
2825 	return(-1);
2826     if (reader->node == NULL)
2827 	return(-1);
2828     if (reader->node->type != XML_ELEMENT_NODE)
2829 	return(0);
2830     if (reader->curnode != NULL) {
2831 	reader->curnode = NULL;
2832 	return(1);
2833     }
2834     return(0);
2835 }
2836 
2837 /**
2838  * xmlTextReaderReadAttributeValue:
2839  * @reader:  the xmlTextReaderPtr used
2840  *
2841  * Parses an attribute value into one or more Text and EntityReference nodes.
2842  *
2843  * Returns 1 in case of success, 0 if the reader was not positionned on an
2844  *         ttribute node or all the attribute values have been read, or -1
2845  *         in case of error.
2846  */
2847 int
xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader)2848 xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
2849     if (reader == NULL)
2850 	return(-1);
2851     if (reader->node == NULL)
2852 	return(-1);
2853     if (reader->curnode == NULL)
2854 	return(0);
2855     if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
2856 	if (reader->curnode->children == NULL)
2857 	    return(0);
2858 	reader->curnode = reader->curnode->children;
2859     } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
2860 	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2861 
2862 	if (reader->faketext == NULL) {
2863 	    reader->faketext = xmlNewDocText(reader->node->doc,
2864 		                             ns->href);
2865 	} else {
2866             if ((reader->faketext->content != NULL) &&
2867 	        (reader->faketext->content !=
2868 		 (xmlChar *) &(reader->faketext->properties)))
2869 		xmlFree(reader->faketext->content);
2870 	    reader->faketext->content = xmlStrdup(ns->href);
2871 	}
2872 	reader->curnode = reader->faketext;
2873     } else {
2874 	if (reader->curnode->next == NULL)
2875 	    return(0);
2876 	reader->curnode = reader->curnode->next;
2877     }
2878     return(1);
2879 }
2880 
2881 /**
2882  * xmlTextReaderConstEncoding:
2883  * @reader:  the xmlTextReaderPtr used
2884  *
2885  * Determine the encoding of the document being read.
2886  *
2887  * Returns a string containing the encoding of the document or NULL in
2888  * case of error.  The string is deallocated with the reader.
2889  */
2890 const xmlChar *
xmlTextReaderConstEncoding(xmlTextReaderPtr reader)2891 xmlTextReaderConstEncoding(xmlTextReaderPtr reader) {
2892     xmlDocPtr doc = NULL;
2893     if (reader == NULL)
2894 	return(NULL);
2895     if (reader->doc != NULL)
2896         doc = reader->doc;
2897     else if (reader->ctxt != NULL)
2898 	doc = reader->ctxt->myDoc;
2899     if (doc == NULL)
2900 	return(NULL);
2901 
2902     if (doc->encoding == NULL)
2903 	return(NULL);
2904     else
2905       return(CONSTSTR(doc->encoding));
2906 }
2907 
2908 
2909 /************************************************************************
2910  *									*
2911  *			Acces API to the current node			*
2912  *									*
2913  ************************************************************************/
2914 /**
2915  * xmlTextReaderAttributeCount:
2916  * @reader:  the xmlTextReaderPtr used
2917  *
2918  * Provides the number of attributes of the current node
2919  *
2920  * Returns 0 i no attributes, -1 in case of error or the attribute count
2921  */
2922 int
xmlTextReaderAttributeCount(xmlTextReaderPtr reader)2923 xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
2924     int ret;
2925     xmlAttrPtr attr;
2926     xmlNsPtr ns;
2927     xmlNodePtr node;
2928 
2929     if (reader == NULL)
2930 	return(-1);
2931     if (reader->node == NULL)
2932 	return(0);
2933 
2934     if (reader->curnode != NULL)
2935 	node = reader->curnode;
2936     else
2937 	node = reader->node;
2938 
2939     if (node->type != XML_ELEMENT_NODE)
2940 	return(0);
2941     if ((reader->state == XML_TEXTREADER_END) ||
2942 	(reader->state == XML_TEXTREADER_BACKTRACK))
2943 	return(0);
2944     ret = 0;
2945     attr = node->properties;
2946     while (attr != NULL) {
2947 	ret++;
2948 	attr = attr->next;
2949     }
2950     ns = node->nsDef;
2951     while (ns != NULL) {
2952 	ret++;
2953 	ns = ns->next;
2954     }
2955     return(ret);
2956 }
2957 
2958 /**
2959  * xmlTextReaderNodeType:
2960  * @reader:  the xmlTextReaderPtr used
2961  *
2962  * Get the node type of the current node
2963  * Reference:
2964  * http://www.gnu.org/software/dotgnu/pnetlib-doc/System/Xml/XmlNodeType.html
2965  *
2966  * Returns the xmlNodeType of the current node or -1 in case of error
2967  */
2968 int
xmlTextReaderNodeType(xmlTextReaderPtr reader)2969 xmlTextReaderNodeType(xmlTextReaderPtr reader) {
2970     xmlNodePtr node;
2971 
2972     if (reader == NULL)
2973 	return(-1);
2974     if (reader->node == NULL)
2975 	return(XML_READER_TYPE_NONE);
2976     if (reader->curnode != NULL)
2977 	node = reader->curnode;
2978     else
2979 	node = reader->node;
2980     switch (node->type) {
2981         case XML_ELEMENT_NODE:
2982 	    if ((reader->state == XML_TEXTREADER_END) ||
2983 		(reader->state == XML_TEXTREADER_BACKTRACK))
2984 		return(XML_READER_TYPE_END_ELEMENT);
2985 	    return(XML_READER_TYPE_ELEMENT);
2986         case XML_NAMESPACE_DECL:
2987         case XML_ATTRIBUTE_NODE:
2988 	    return(XML_READER_TYPE_ATTRIBUTE);
2989         case XML_TEXT_NODE:
2990 	    if (xmlIsBlankNode(reader->node)) {
2991 		if (xmlNodeGetSpacePreserve(reader->node))
2992 		    return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
2993 		else
2994 		    return(XML_READER_TYPE_WHITESPACE);
2995 	    } else {
2996 		return(XML_READER_TYPE_TEXT);
2997 	    }
2998         case XML_CDATA_SECTION_NODE:
2999 	    return(XML_READER_TYPE_CDATA);
3000         case XML_ENTITY_REF_NODE:
3001 	    return(XML_READER_TYPE_ENTITY_REFERENCE);
3002         case XML_ENTITY_NODE:
3003 	    return(XML_READER_TYPE_ENTITY);
3004         case XML_PI_NODE:
3005 	    return(XML_READER_TYPE_PROCESSING_INSTRUCTION);
3006         case XML_COMMENT_NODE:
3007 	    return(XML_READER_TYPE_COMMENT);
3008         case XML_DOCUMENT_NODE:
3009         case XML_HTML_DOCUMENT_NODE:
3010 #ifdef LIBXML_DOCB_ENABLED
3011         case XML_DOCB_DOCUMENT_NODE:
3012 #endif
3013 	    return(XML_READER_TYPE_DOCUMENT);
3014         case XML_DOCUMENT_FRAG_NODE:
3015 	    return(XML_READER_TYPE_DOCUMENT_FRAGMENT);
3016         case XML_NOTATION_NODE:
3017 	    return(XML_READER_TYPE_NOTATION);
3018         case XML_DOCUMENT_TYPE_NODE:
3019         case XML_DTD_NODE:
3020 	    return(XML_READER_TYPE_DOCUMENT_TYPE);
3021 
3022         case XML_ELEMENT_DECL:
3023         case XML_ATTRIBUTE_DECL:
3024         case XML_ENTITY_DECL:
3025         case XML_XINCLUDE_START:
3026         case XML_XINCLUDE_END:
3027 	    return(XML_READER_TYPE_NONE);
3028     }
3029     return(-1);
3030 }
3031 
3032 /**
3033  * xmlTextReaderIsEmptyElement:
3034  * @reader:  the xmlTextReaderPtr used
3035  *
3036  * Check if the current node is empty
3037  *
3038  * Returns 1 if empty, 0 if not and -1 in case of error
3039  */
3040 int
xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader)3041 xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
3042     if ((reader == NULL) || (reader->node == NULL))
3043 	return(-1);
3044     if (reader->node->type != XML_ELEMENT_NODE)
3045 	return(0);
3046     if (reader->curnode != NULL)
3047 	return(0);
3048     if (reader->node->children != NULL)
3049 	return(0);
3050     if (reader->state == XML_TEXTREADER_END)
3051 	return(0);
3052     if (reader->doc != NULL)
3053         return(1);
3054 #ifdef LIBXML_XINCLUDE_ENABLED
3055     if (reader->in_xinclude > 0)
3056         return(1);
3057 #endif
3058     return((reader->node->extra & NODE_IS_EMPTY) != 0);
3059 }
3060 
3061 /**
3062  * xmlTextReaderLocalName:
3063  * @reader:  the xmlTextReaderPtr used
3064  *
3065  * The local name of the node.
3066  *
3067  * Returns the local name or NULL if not available,
3068  *   if non NULL it need to be freed by the caller.
3069  */
3070 xmlChar *
xmlTextReaderLocalName(xmlTextReaderPtr reader)3071 xmlTextReaderLocalName(xmlTextReaderPtr reader) {
3072     xmlNodePtr node;
3073     if ((reader == NULL) || (reader->node == NULL))
3074 	return(NULL);
3075     if (reader->curnode != NULL)
3076 	node = reader->curnode;
3077     else
3078 	node = reader->node;
3079     if (node->type == XML_NAMESPACE_DECL) {
3080 	xmlNsPtr ns = (xmlNsPtr) node;
3081 	if (ns->prefix == NULL)
3082 	    return(xmlStrdup(BAD_CAST "xmlns"));
3083 	else
3084 	    return(xmlStrdup(ns->prefix));
3085     }
3086     if ((node->type != XML_ELEMENT_NODE) &&
3087 	(node->type != XML_ATTRIBUTE_NODE))
3088 	return(xmlTextReaderName(reader));
3089     return(xmlStrdup(node->name));
3090 }
3091 
3092 /**
3093  * xmlTextReaderConstLocalName:
3094  * @reader:  the xmlTextReaderPtr used
3095  *
3096  * The local name of the node.
3097  *
3098  * Returns the local name or NULL if not available, the
3099  *         string will be deallocated with the reader.
3100  */
3101 const xmlChar *
xmlTextReaderConstLocalName(xmlTextReaderPtr reader)3102 xmlTextReaderConstLocalName(xmlTextReaderPtr reader) {
3103     xmlNodePtr node;
3104     if ((reader == NULL) || (reader->node == NULL))
3105 	return(NULL);
3106     if (reader->curnode != NULL)
3107 	node = reader->curnode;
3108     else
3109 	node = reader->node;
3110     if (node->type == XML_NAMESPACE_DECL) {
3111 	xmlNsPtr ns = (xmlNsPtr) node;
3112 	if (ns->prefix == NULL)
3113 	    return(CONSTSTR(BAD_CAST "xmlns"));
3114 	else
3115 	    return(ns->prefix);
3116     }
3117     if ((node->type != XML_ELEMENT_NODE) &&
3118 	(node->type != XML_ATTRIBUTE_NODE))
3119 	return(xmlTextReaderConstName(reader));
3120     return(node->name);
3121 }
3122 
3123 /**
3124  * xmlTextReaderName:
3125  * @reader:  the xmlTextReaderPtr used
3126  *
3127  * The qualified name of the node, equal to Prefix :LocalName.
3128  *
3129  * Returns the local name or NULL if not available,
3130  *   if non NULL it need to be freed by the caller.
3131  */
3132 xmlChar *
xmlTextReaderName(xmlTextReaderPtr reader)3133 xmlTextReaderName(xmlTextReaderPtr reader) {
3134     xmlNodePtr node;
3135     xmlChar *ret;
3136 
3137     if ((reader == NULL) || (reader->node == NULL))
3138 	return(NULL);
3139     if (reader->curnode != NULL)
3140 	node = reader->curnode;
3141     else
3142 	node = reader->node;
3143     switch (node->type) {
3144         case XML_ELEMENT_NODE:
3145         case XML_ATTRIBUTE_NODE:
3146 	    if ((node->ns == NULL) ||
3147 		(node->ns->prefix == NULL))
3148 		return(xmlStrdup(node->name));
3149 
3150 	    ret = xmlStrdup(node->ns->prefix);
3151 	    ret = xmlStrcat(ret, BAD_CAST ":");
3152 	    ret = xmlStrcat(ret, node->name);
3153 	    return(ret);
3154         case XML_TEXT_NODE:
3155 	    return(xmlStrdup(BAD_CAST "#text"));
3156         case XML_CDATA_SECTION_NODE:
3157 	    return(xmlStrdup(BAD_CAST "#cdata-section"));
3158         case XML_ENTITY_NODE:
3159         case XML_ENTITY_REF_NODE:
3160 	    return(xmlStrdup(node->name));
3161         case XML_PI_NODE:
3162 	    return(xmlStrdup(node->name));
3163         case XML_COMMENT_NODE:
3164 	    return(xmlStrdup(BAD_CAST "#comment"));
3165         case XML_DOCUMENT_NODE:
3166         case XML_HTML_DOCUMENT_NODE:
3167 #ifdef LIBXML_DOCB_ENABLED
3168         case XML_DOCB_DOCUMENT_NODE:
3169 #endif
3170 	    return(xmlStrdup(BAD_CAST "#document"));
3171         case XML_DOCUMENT_FRAG_NODE:
3172 	    return(xmlStrdup(BAD_CAST "#document-fragment"));
3173         case XML_NOTATION_NODE:
3174 	    return(xmlStrdup(node->name));
3175         case XML_DOCUMENT_TYPE_NODE:
3176         case XML_DTD_NODE:
3177 	    return(xmlStrdup(node->name));
3178         case XML_NAMESPACE_DECL: {
3179 	    xmlNsPtr ns = (xmlNsPtr) node;
3180 
3181 	    ret = xmlStrdup(BAD_CAST "xmlns");
3182 	    if (ns->prefix == NULL)
3183 		return(ret);
3184 	    ret = xmlStrcat(ret, BAD_CAST ":");
3185 	    ret = xmlStrcat(ret, ns->prefix);
3186 	    return(ret);
3187 	}
3188 
3189         case XML_ELEMENT_DECL:
3190         case XML_ATTRIBUTE_DECL:
3191         case XML_ENTITY_DECL:
3192         case XML_XINCLUDE_START:
3193         case XML_XINCLUDE_END:
3194 	    return(NULL);
3195     }
3196     return(NULL);
3197 }
3198 
3199 /**
3200  * xmlTextReaderConstName:
3201  * @reader:  the xmlTextReaderPtr used
3202  *
3203  * The qualified name of the node, equal to Prefix :LocalName.
3204  *
3205  * Returns the local name or NULL if not available, the string is
3206  *         deallocated with the reader.
3207  */
3208 const xmlChar *
xmlTextReaderConstName(xmlTextReaderPtr reader)3209 xmlTextReaderConstName(xmlTextReaderPtr reader) {
3210     xmlNodePtr node;
3211 
3212     if ((reader == NULL) || (reader->node == NULL))
3213 	return(NULL);
3214     if (reader->curnode != NULL)
3215 	node = reader->curnode;
3216     else
3217 	node = reader->node;
3218     switch (node->type) {
3219         case XML_ELEMENT_NODE:
3220         case XML_ATTRIBUTE_NODE:
3221 	    if ((node->ns == NULL) ||
3222 		(node->ns->prefix == NULL))
3223 		return(node->name);
3224 	    return(CONSTQSTR(node->ns->prefix, node->name));
3225         case XML_TEXT_NODE:
3226 	    return(CONSTSTR(BAD_CAST "#text"));
3227         case XML_CDATA_SECTION_NODE:
3228 	    return(CONSTSTR(BAD_CAST "#cdata-section"));
3229         case XML_ENTITY_NODE:
3230         case XML_ENTITY_REF_NODE:
3231 	    return(CONSTSTR(node->name));
3232         case XML_PI_NODE:
3233 	    return(CONSTSTR(node->name));
3234         case XML_COMMENT_NODE:
3235 	    return(CONSTSTR(BAD_CAST "#comment"));
3236         case XML_DOCUMENT_NODE:
3237         case XML_HTML_DOCUMENT_NODE:
3238 #ifdef LIBXML_DOCB_ENABLED
3239         case XML_DOCB_DOCUMENT_NODE:
3240 #endif
3241 	    return(CONSTSTR(BAD_CAST "#document"));
3242         case XML_DOCUMENT_FRAG_NODE:
3243 	    return(CONSTSTR(BAD_CAST "#document-fragment"));
3244         case XML_NOTATION_NODE:
3245 	    return(CONSTSTR(node->name));
3246         case XML_DOCUMENT_TYPE_NODE:
3247         case XML_DTD_NODE:
3248 	    return(CONSTSTR(node->name));
3249         case XML_NAMESPACE_DECL: {
3250 	    xmlNsPtr ns = (xmlNsPtr) node;
3251 
3252 	    if (ns->prefix == NULL)
3253 		return(CONSTSTR(BAD_CAST "xmlns"));
3254 	    return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix));
3255 	}
3256 
3257         case XML_ELEMENT_DECL:
3258         case XML_ATTRIBUTE_DECL:
3259         case XML_ENTITY_DECL:
3260         case XML_XINCLUDE_START:
3261         case XML_XINCLUDE_END:
3262 	    return(NULL);
3263     }
3264     return(NULL);
3265 }
3266 
3267 /**
3268  * xmlTextReaderPrefix:
3269  * @reader:  the xmlTextReaderPtr used
3270  *
3271  * A shorthand reference to the namespace associated with the node.
3272  *
3273  * Returns the prefix or NULL if not available,
3274  *    if non NULL it need to be freed by the caller.
3275  */
3276 xmlChar *
xmlTextReaderPrefix(xmlTextReaderPtr reader)3277 xmlTextReaderPrefix(xmlTextReaderPtr reader) {
3278     xmlNodePtr node;
3279     if ((reader == NULL) || (reader->node == NULL))
3280 	return(NULL);
3281     if (reader->curnode != NULL)
3282 	node = reader->curnode;
3283     else
3284 	node = reader->node;
3285     if (node->type == XML_NAMESPACE_DECL) {
3286 	xmlNsPtr ns = (xmlNsPtr) node;
3287 	if (ns->prefix == NULL)
3288 	    return(NULL);
3289 	return(xmlStrdup(BAD_CAST "xmlns"));
3290     }
3291     if ((node->type != XML_ELEMENT_NODE) &&
3292 	(node->type != XML_ATTRIBUTE_NODE))
3293 	return(NULL);
3294     if ((node->ns != NULL) && (node->ns->prefix != NULL))
3295 	return(xmlStrdup(node->ns->prefix));
3296     return(NULL);
3297 }
3298 
3299 /**
3300  * xmlTextReaderConstPrefix:
3301  * @reader:  the xmlTextReaderPtr used
3302  *
3303  * A shorthand reference to the namespace associated with the node.
3304  *
3305  * Returns the prefix or NULL if not available, the string is deallocated
3306  *         with the reader.
3307  */
3308 const xmlChar *
xmlTextReaderConstPrefix(xmlTextReaderPtr reader)3309 xmlTextReaderConstPrefix(xmlTextReaderPtr reader) {
3310     xmlNodePtr node;
3311     if ((reader == NULL) || (reader->node == NULL))
3312 	return(NULL);
3313     if (reader->curnode != NULL)
3314 	node = reader->curnode;
3315     else
3316 	node = reader->node;
3317     if (node->type == XML_NAMESPACE_DECL) {
3318 	xmlNsPtr ns = (xmlNsPtr) node;
3319 	if (ns->prefix == NULL)
3320 	    return(NULL);
3321 	return(CONSTSTR(BAD_CAST "xmlns"));
3322     }
3323     if ((node->type != XML_ELEMENT_NODE) &&
3324 	(node->type != XML_ATTRIBUTE_NODE))
3325 	return(NULL);
3326     if ((node->ns != NULL) && (node->ns->prefix != NULL))
3327 	return(CONSTSTR(node->ns->prefix));
3328     return(NULL);
3329 }
3330 
3331 /**
3332  * xmlTextReaderNamespaceUri:
3333  * @reader:  the xmlTextReaderPtr used
3334  *
3335  * The URI defining the namespace associated with the node.
3336  *
3337  * Returns the namespace URI or NULL if not available,
3338  *    if non NULL it need to be freed by the caller.
3339  */
3340 xmlChar *
xmlTextReaderNamespaceUri(xmlTextReaderPtr reader)3341 xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
3342     xmlNodePtr node;
3343     if ((reader == NULL) || (reader->node == NULL))
3344 	return(NULL);
3345     if (reader->curnode != NULL)
3346 	node = reader->curnode;
3347     else
3348 	node = reader->node;
3349     if (node->type == XML_NAMESPACE_DECL)
3350 	return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
3351     if ((node->type != XML_ELEMENT_NODE) &&
3352 	(node->type != XML_ATTRIBUTE_NODE))
3353 	return(NULL);
3354     if (node->ns != NULL)
3355 	return(xmlStrdup(node->ns->href));
3356     return(NULL);
3357 }
3358 
3359 /**
3360  * xmlTextReaderConstNamespaceUri:
3361  * @reader:  the xmlTextReaderPtr used
3362  *
3363  * The URI defining the namespace associated with the node.
3364  *
3365  * Returns the namespace URI or NULL if not available, the string
3366  *         will be deallocated with the reader
3367  */
3368 const xmlChar *
xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader)3369 xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) {
3370     xmlNodePtr node;
3371     if ((reader == NULL) || (reader->node == NULL))
3372 	return(NULL);
3373     if (reader->curnode != NULL)
3374 	node = reader->curnode;
3375     else
3376 	node = reader->node;
3377     if (node->type == XML_NAMESPACE_DECL)
3378 	return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/"));
3379     if ((node->type != XML_ELEMENT_NODE) &&
3380 	(node->type != XML_ATTRIBUTE_NODE))
3381 	return(NULL);
3382     if (node->ns != NULL)
3383 	return(CONSTSTR(node->ns->href));
3384     return(NULL);
3385 }
3386 
3387 /**
3388  * xmlTextReaderBaseUri:
3389  * @reader:  the xmlTextReaderPtr used
3390  *
3391  * The base URI of the node.
3392  *
3393  * Returns the base URI or NULL if not available,
3394  *    if non NULL it need to be freed by the caller.
3395  */
3396 xmlChar *
xmlTextReaderBaseUri(xmlTextReaderPtr reader)3397 xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
3398     if ((reader == NULL) || (reader->node == NULL))
3399 	return(NULL);
3400     return(xmlNodeGetBase(NULL, reader->node));
3401 }
3402 
3403 /**
3404  * xmlTextReaderConstBaseUri:
3405  * @reader:  the xmlTextReaderPtr used
3406  *
3407  * The base URI of the node.
3408  *
3409  * Returns the base URI or NULL if not available, the string
3410  *         will be deallocated with the reader
3411  */
3412 const xmlChar *
xmlTextReaderConstBaseUri(xmlTextReaderPtr reader)3413 xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) {
3414     xmlChar *tmp;
3415     const xmlChar *ret;
3416 
3417     if ((reader == NULL) || (reader->node == NULL))
3418 	return(NULL);
3419     tmp = xmlNodeGetBase(NULL, reader->node);
3420     if (tmp == NULL)
3421         return(NULL);
3422     ret = CONSTSTR(tmp);
3423     xmlFree(tmp);
3424     return(ret);
3425 }
3426 
3427 /**
3428  * xmlTextReaderDepth:
3429  * @reader:  the xmlTextReaderPtr used
3430  *
3431  * The depth of the node in the tree.
3432  *
3433  * Returns the depth or -1 in case of error
3434  */
3435 int
xmlTextReaderDepth(xmlTextReaderPtr reader)3436 xmlTextReaderDepth(xmlTextReaderPtr reader) {
3437     if (reader == NULL)
3438 	return(-1);
3439     if (reader->node == NULL)
3440 	return(0);
3441 
3442     if (reader->curnode != NULL) {
3443 	if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
3444 	    (reader->curnode->type == XML_NAMESPACE_DECL))
3445 	    return(reader->depth + 1);
3446 	return(reader->depth + 2);
3447     }
3448     return(reader->depth);
3449 }
3450 
3451 /**
3452  * xmlTextReaderHasAttributes:
3453  * @reader:  the xmlTextReaderPtr used
3454  *
3455  * Whether the node has attributes.
3456  *
3457  * Returns 1 if true, 0 if false, and -1 in case or error
3458  */
3459 int
xmlTextReaderHasAttributes(xmlTextReaderPtr reader)3460 xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
3461     xmlNodePtr node;
3462     if (reader == NULL)
3463 	return(-1);
3464     if (reader->node == NULL)
3465 	return(0);
3466     if (reader->curnode != NULL)
3467 	node = reader->curnode;
3468     else
3469 	node = reader->node;
3470 
3471     if ((node->type == XML_ELEMENT_NODE) &&
3472 	((node->properties != NULL) || (node->nsDef != NULL)))
3473 	return(1);
3474     /* TODO: handle the xmlDecl */
3475     return(0);
3476 }
3477 
3478 /**
3479  * xmlTextReaderHasValue:
3480  * @reader:  the xmlTextReaderPtr used
3481  *
3482  * Whether the node can have a text value.
3483  *
3484  * Returns 1 if true, 0 if false, and -1 in case or error
3485  */
3486 int
xmlTextReaderHasValue(xmlTextReaderPtr reader)3487 xmlTextReaderHasValue(xmlTextReaderPtr reader) {
3488     xmlNodePtr node;
3489     if (reader == NULL)
3490 	return(-1);
3491     if (reader->node == NULL)
3492 	return(0);
3493     if (reader->curnode != NULL)
3494 	node = reader->curnode;
3495     else
3496 	node = reader->node;
3497 
3498     switch (node->type) {
3499         case XML_ATTRIBUTE_NODE:
3500         case XML_TEXT_NODE:
3501         case XML_CDATA_SECTION_NODE:
3502         case XML_PI_NODE:
3503         case XML_COMMENT_NODE:
3504         case XML_NAMESPACE_DECL:
3505 	    return(1);
3506 	default:
3507 	    break;
3508     }
3509     return(0);
3510 }
3511 
3512 /**
3513  * xmlTextReaderValue:
3514  * @reader:  the xmlTextReaderPtr used
3515  *
3516  * Provides the text value of the node if present
3517  *
3518  * Returns the string or NULL if not available. The result must be deallocated
3519  *     with xmlFree()
3520  */
3521 xmlChar *
xmlTextReaderValue(xmlTextReaderPtr reader)3522 xmlTextReaderValue(xmlTextReaderPtr reader) {
3523     xmlNodePtr node;
3524     if (reader == NULL)
3525 	return(NULL);
3526     if (reader->node == NULL)
3527 	return(NULL);
3528     if (reader->curnode != NULL)
3529 	node = reader->curnode;
3530     else
3531 	node = reader->node;
3532 
3533     switch (node->type) {
3534         case XML_NAMESPACE_DECL:
3535 	    return(xmlStrdup(((xmlNsPtr) node)->href));
3536         case XML_ATTRIBUTE_NODE:{
3537 	    xmlAttrPtr attr = (xmlAttrPtr) node;
3538 
3539 	    if (attr->parent != NULL)
3540 		return (xmlNodeListGetString
3541 			(attr->parent->doc, attr->children, 1));
3542 	    else
3543 		return (xmlNodeListGetString(NULL, attr->children, 1));
3544 	    break;
3545 	}
3546         case XML_TEXT_NODE:
3547         case XML_CDATA_SECTION_NODE:
3548         case XML_PI_NODE:
3549         case XML_COMMENT_NODE:
3550             if (node->content != NULL)
3551                 return (xmlStrdup(node->content));
3552 	default:
3553 	    break;
3554     }
3555     return(NULL);
3556 }
3557 
3558 /**
3559  * xmlTextReaderConstValue:
3560  * @reader:  the xmlTextReaderPtr used
3561  *
3562  * Provides the text value of the node if present
3563  *
3564  * Returns the string or NULL if not available. The result will be
3565  *     deallocated on the next Read() operation.
3566  */
3567 const xmlChar *
xmlTextReaderConstValue(xmlTextReaderPtr reader)3568 xmlTextReaderConstValue(xmlTextReaderPtr reader) {
3569     xmlNodePtr node;
3570     if (reader == NULL)
3571 	return(NULL);
3572     if (reader->node == NULL)
3573 	return(NULL);
3574     if (reader->curnode != NULL)
3575 	node = reader->curnode;
3576     else
3577 	node = reader->node;
3578 
3579     switch (node->type) {
3580         case XML_NAMESPACE_DECL:
3581 	    return(((xmlNsPtr) node)->href);
3582         case XML_ATTRIBUTE_NODE:{
3583 	    xmlAttrPtr attr = (xmlAttrPtr) node;
3584 
3585 	    if ((attr->children != NULL) &&
3586 	        (attr->children->type == XML_TEXT_NODE) &&
3587 		(attr->children->next == NULL))
3588 		return(attr->children->content);
3589 	    else {
3590 		if (reader->buffer == NULL)
3591 		    reader->buffer = xmlBufferCreateSize(100);
3592 		if (reader->buffer == NULL) {
3593 		    xmlGenericError(xmlGenericErrorContext,
3594 				    "xmlTextReaderSetup : malloc failed\n");
3595 		    return (NULL);
3596 		}
3597 	        reader->buffer->use = 0;
3598 	        xmlNodeBufGetContent(reader->buffer, node);
3599 		return(reader->buffer->content);
3600 	    }
3601 	    break;
3602 	}
3603         case XML_TEXT_NODE:
3604         case XML_CDATA_SECTION_NODE:
3605         case XML_PI_NODE:
3606         case XML_COMMENT_NODE:
3607 	    return(node->content);
3608 	default:
3609 	    break;
3610     }
3611     return(NULL);
3612 }
3613 
3614 /**
3615  * xmlTextReaderIsDefault:
3616  * @reader:  the xmlTextReaderPtr used
3617  *
3618  * Whether an Attribute  node was generated from the default value
3619  * defined in the DTD or schema.
3620  *
3621  * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
3622  */
3623 int
xmlTextReaderIsDefault(xmlTextReaderPtr reader)3624 xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
3625     if (reader == NULL)
3626 	return(-1);
3627     return(0);
3628 }
3629 
3630 /**
3631  * xmlTextReaderQuoteChar:
3632  * @reader:  the xmlTextReaderPtr used
3633  *
3634  * The quotation mark character used to enclose the value of an attribute.
3635  *
3636  * Returns " or ' and -1 in case of error
3637  */
3638 int
xmlTextReaderQuoteChar(xmlTextReaderPtr reader)3639 xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
3640     if (reader == NULL)
3641 	return(-1);
3642     /* TODO maybe lookup the attribute value for " first */
3643     return((int) '"');
3644 }
3645 
3646 /**
3647  * xmlTextReaderXmlLang:
3648  * @reader:  the xmlTextReaderPtr used
3649  *
3650  * The xml:lang scope within which the node resides.
3651  *
3652  * Returns the xml:lang value or NULL if none exists.,
3653  *    if non NULL it need to be freed by the caller.
3654  */
3655 xmlChar *
xmlTextReaderXmlLang(xmlTextReaderPtr reader)3656 xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
3657     if (reader == NULL)
3658 	return(NULL);
3659     if (reader->node == NULL)
3660 	return(NULL);
3661     return(xmlNodeGetLang(reader->node));
3662 }
3663 
3664 /**
3665  * xmlTextReaderConstXmlLang:
3666  * @reader:  the xmlTextReaderPtr used
3667  *
3668  * The xml:lang scope within which the node resides.
3669  *
3670  * Returns the xml:lang value or NULL if none exists.
3671  */
3672 const xmlChar *
xmlTextReaderConstXmlLang(xmlTextReaderPtr reader)3673 xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) {
3674     xmlChar *tmp;
3675     const xmlChar *ret;
3676 
3677     if (reader == NULL)
3678 	return(NULL);
3679     if (reader->node == NULL)
3680 	return(NULL);
3681     tmp = xmlNodeGetLang(reader->node);
3682     if (tmp == NULL)
3683         return(NULL);
3684     ret = CONSTSTR(tmp);
3685     xmlFree(tmp);
3686     return(ret);
3687 }
3688 
3689 /**
3690  * xmlTextReaderConstString:
3691  * @reader:  the xmlTextReaderPtr used
3692  * @str:  the string to intern.
3693  *
3694  * Get an interned string from the reader, allows for example to
3695  * speedup string name comparisons
3696  *
3697  * Returns an interned copy of the string or NULL in case of error. The
3698  *         string will be deallocated with the reader.
3699  */
3700 const xmlChar *
xmlTextReaderConstString(xmlTextReaderPtr reader,const xmlChar * str)3701 xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) {
3702     if (reader == NULL)
3703 	return(NULL);
3704     return(CONSTSTR(str));
3705 }
3706 
3707 /**
3708  * xmlTextReaderNormalization:
3709  * @reader:  the xmlTextReaderPtr used
3710  *
3711  * The value indicating whether to normalize white space and attribute values.
3712  * Since attribute value and end of line normalizations are a MUST in the XML
3713  * specification only the value true is accepted. The broken bahaviour of
3714  * accepting out of range character entities like &#0; is of course not
3715  * supported either.
3716  *
3717  * Returns 1 or -1 in case of error.
3718  */
3719 int
xmlTextReaderNormalization(xmlTextReaderPtr reader)3720 xmlTextReaderNormalization(xmlTextReaderPtr reader) {
3721     if (reader == NULL)
3722 	return(-1);
3723     return(1);
3724 }
3725 
3726 /************************************************************************
3727  *									*
3728  *			Extensions to the base APIs			*
3729  *									*
3730  ************************************************************************/
3731 
3732 /**
3733  * xmlTextReaderSetParserProp:
3734  * @reader:  the xmlTextReaderPtr used
3735  * @prop:  the xmlParserProperties to set
3736  * @value:  usually 0 or 1 to (de)activate it
3737  *
3738  * Change the parser processing behaviour by changing some of its internal
3739  * properties. Note that some properties can only be changed before any
3740  * read has been done.
3741  *
3742  * Returns 0 if the call was successful, or -1 in case of error
3743  */
3744 int
xmlTextReaderSetParserProp(xmlTextReaderPtr reader,int prop,int value)3745 xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
3746     xmlParserProperties p = (xmlParserProperties) prop;
3747     xmlParserCtxtPtr ctxt;
3748 
3749     if ((reader == NULL) || (reader->ctxt == NULL))
3750 	return(-1);
3751     ctxt = reader->ctxt;
3752 
3753     switch (p) {
3754         case XML_PARSER_LOADDTD:
3755 	    if (value != 0) {
3756 		if (ctxt->loadsubset == 0) {
3757 		    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
3758 			return(-1);
3759 		    ctxt->loadsubset = XML_DETECT_IDS;
3760 		}
3761 	    } else {
3762 		ctxt->loadsubset = 0;
3763 	    }
3764 	    return(0);
3765         case XML_PARSER_DEFAULTATTRS:
3766 	    if (value != 0) {
3767 		ctxt->loadsubset |= XML_COMPLETE_ATTRS;
3768 	    } else {
3769 		if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3770 		    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
3771 	    }
3772 	    return(0);
3773         case XML_PARSER_VALIDATE:
3774 	    if (value != 0) {
3775 		ctxt->validate = 1;
3776 		reader->validate = XML_TEXTREADER_VALIDATE_DTD;
3777 	    } else {
3778 		ctxt->validate = 0;
3779 	    }
3780 	    return(0);
3781         case XML_PARSER_SUBST_ENTITIES:
3782 	    if (value != 0) {
3783 		ctxt->replaceEntities = 1;
3784 	    } else {
3785 		ctxt->replaceEntities = 0;
3786 	    }
3787 	    return(0);
3788     }
3789     return(-1);
3790 }
3791 
3792 /**
3793  * xmlTextReaderGetParserProp:
3794  * @reader:  the xmlTextReaderPtr used
3795  * @prop:  the xmlParserProperties to get
3796  *
3797  * Read the parser internal property.
3798  *
3799  * Returns the value, usually 0 or 1, or -1 in case of error.
3800  */
3801 int
xmlTextReaderGetParserProp(xmlTextReaderPtr reader,int prop)3802 xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
3803     xmlParserProperties p = (xmlParserProperties) prop;
3804     xmlParserCtxtPtr ctxt;
3805 
3806     if ((reader == NULL) || (reader->ctxt == NULL))
3807 	return(-1);
3808     ctxt = reader->ctxt;
3809 
3810     switch (p) {
3811         case XML_PARSER_LOADDTD:
3812 	    if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
3813 		return(1);
3814 	    return(0);
3815         case XML_PARSER_DEFAULTATTRS:
3816 	    if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3817 		return(1);
3818 	    return(0);
3819         case XML_PARSER_VALIDATE:
3820 	    return(reader->validate);
3821 	case XML_PARSER_SUBST_ENTITIES:
3822 	    return(ctxt->replaceEntities);
3823     }
3824     return(-1);
3825 }
3826 
3827 
3828 /**
3829  * xmlTextReaderGetParserLineNumber:
3830  * @reader: the user data (XML reader context)
3831  *
3832  * Provide the line number of the current parsing point.
3833  *
3834  * Returns an int or 0 if not available
3835  */
3836 int
xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader)3837 xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader)
3838 {
3839     if ((reader == NULL) || (reader->ctxt == NULL) ||
3840         (reader->ctxt->input == NULL)) {
3841         return (0);
3842     }
3843     return (reader->ctxt->input->line);
3844 }
3845 
3846 /**
3847  * xmlTextReaderGetParserColumnNumber:
3848  * @reader: the user data (XML reader context)
3849  *
3850  * Provide the column number of the current parsing point.
3851  *
3852  * Returns an int or 0 if not available
3853  */
3854 int
xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader)3855 xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader)
3856 {
3857     if ((reader == NULL) || (reader->ctxt == NULL) ||
3858         (reader->ctxt->input == NULL)) {
3859         return (0);
3860     }
3861     return (reader->ctxt->input->col);
3862 }
3863 
3864 /**
3865  * xmlTextReaderCurrentNode:
3866  * @reader:  the xmlTextReaderPtr used
3867  *
3868  * Hacking interface allowing to get the xmlNodePtr correponding to the
3869  * current node being accessed by the xmlTextReader. This is dangerous
3870  * because the underlying node may be destroyed on the next Reads.
3871  *
3872  * Returns the xmlNodePtr or NULL in case of error.
3873  */
3874 xmlNodePtr
xmlTextReaderCurrentNode(xmlTextReaderPtr reader)3875 xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
3876     if (reader == NULL)
3877 	return(NULL);
3878 
3879     if (reader->curnode != NULL)
3880 	return(reader->curnode);
3881     return(reader->node);
3882 }
3883 
3884 /**
3885  * xmlTextReaderPreserve:
3886  * @reader:  the xmlTextReaderPtr used
3887  *
3888  * This tells the XML Reader to preserve the current node.
3889  * The caller must also use xmlTextReaderCurrentDoc() to
3890  * keep an handle on the resulting document once parsing has finished
3891  *
3892  * Returns the xmlNodePtr or NULL in case of error.
3893  */
3894 xmlNodePtr
xmlTextReaderPreserve(xmlTextReaderPtr reader)3895 xmlTextReaderPreserve(xmlTextReaderPtr reader) {
3896     xmlNodePtr cur, parent;
3897 
3898     if (reader == NULL)
3899 	return(NULL);
3900 
3901     if (reader->curnode != NULL)
3902         cur = reader->curnode;
3903     else
3904         cur = reader->node;
3905     if (cur == NULL)
3906         return(NULL);
3907 
3908     if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) {
3909 	cur->extra |= NODE_IS_PRESERVED;
3910 	cur->extra |= NODE_IS_SPRESERVED;
3911     }
3912     reader->preserves++;
3913 
3914     parent = cur->parent;;
3915     while (parent != NULL) {
3916         if (parent->type == XML_ELEMENT_NODE)
3917 	    parent->extra |= NODE_IS_PRESERVED;
3918 	parent = parent->parent;
3919     }
3920     return(cur);
3921 }
3922 
3923 #ifdef LIBXML_PATTERN_ENABLED
3924 /**
3925  * xmlTextReaderPreservePattern:
3926  * @reader:  the xmlTextReaderPtr used
3927  * @pattern:  an XPath subset pattern
3928  * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
3929  *
3930  * This tells the XML Reader to preserve all nodes matched by the
3931  * pattern. The caller must also use xmlTextReaderCurrentDoc() to
3932  * keep an handle on the resulting document once parsing has finished
3933  *
3934  * Returns a positive number in case of success and -1 in case of error
3935  */
3936 int
xmlTextReaderPreservePattern(xmlTextReaderPtr reader,const xmlChar * pattern,const xmlChar ** namespaces)3937 xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern,
3938                              const xmlChar **namespaces)
3939 {
3940     xmlPatternPtr comp;
3941 
3942     if ((reader == NULL) || (pattern == NULL))
3943 	return(-1);
3944 
3945     comp = xmlPatterncompile(pattern, reader->dict, 0, namespaces);
3946     if (comp == NULL)
3947         return(-1);
3948 
3949     if (reader->patternMax <= 0) {
3950 	reader->patternMax = 4;
3951 	reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax *
3952 					      sizeof(reader->patternTab[0]));
3953         if (reader->patternTab == NULL) {
3954             xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
3955             return (-1);
3956         }
3957     }
3958     if (reader->patternNr >= reader->patternMax) {
3959         xmlPatternPtr *tmp;
3960         reader->patternMax *= 2;
3961 	tmp = (xmlPatternPtr *) xmlRealloc(reader->patternTab,
3962                                       reader->patternMax *
3963                                       sizeof(reader->patternTab[0]));
3964         if (tmp == NULL) {
3965             xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
3966 	    reader->patternMax /= 2;
3967             return (-1);
3968         }
3969 	reader->patternTab = tmp;
3970     }
3971     reader->patternTab[reader->patternNr] = comp;
3972     return(reader->patternNr++);
3973 }
3974 #endif
3975 
3976 /**
3977  * xmlTextReaderCurrentDoc:
3978  * @reader:  the xmlTextReaderPtr used
3979  *
3980  * Hacking interface allowing to get the xmlDocPtr correponding to the
3981  * current document being accessed by the xmlTextReader.
3982  * NOTE: as a result of this call, the reader will not destroy the
3983  *       associated XML document and calling xmlFreeDoc() on the result
3984  *       is needed once the reader parsing has finished.
3985  *
3986  * Returns the xmlDocPtr or NULL in case of error.
3987  */
3988 xmlDocPtr
xmlTextReaderCurrentDoc(xmlTextReaderPtr reader)3989 xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
3990     if (reader == NULL)
3991 	return(NULL);
3992     if (reader->doc != NULL)
3993         return(reader->doc);
3994     if ((reader->ctxt == NULL) || (reader->ctxt->myDoc == NULL))
3995 	return(NULL);
3996 
3997     reader->preserve = 1;
3998     return(reader->ctxt->myDoc);
3999 }
4000 
4001 #ifdef LIBXML_SCHEMAS_ENABLED
4002 static char *xmlTextReaderBuildMessage(const char *msg, va_list ap);
4003 
4004 static void XMLCDECL
4005 xmlTextReaderValidityError(void *ctxt, const char *msg, ...);
4006 
4007 static void XMLCDECL
4008 xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...);
4009 
4010 static void XMLCDECL
xmlTextReaderValidityErrorRelay(void * ctx,const char * msg,...)4011 xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...)
4012 {
4013     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
4014 
4015     char *str;
4016 
4017     va_list ap;
4018 
4019     va_start(ap, msg);
4020     str = xmlTextReaderBuildMessage(msg, ap);
4021     if (!reader->errorFunc) {
4022         xmlTextReaderValidityError(ctx, "%s", str);
4023     } else {
4024         reader->errorFunc(reader->errorFuncArg, str,
4025                           XML_PARSER_SEVERITY_VALIDITY_ERROR,
4026                           NULL /* locator */ );
4027     }
4028     if (str != NULL)
4029         xmlFree(str);
4030     va_end(ap);
4031 }
4032 
4033 static void XMLCDECL
xmlTextReaderValidityWarningRelay(void * ctx,const char * msg,...)4034 xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...)
4035 {
4036     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
4037 
4038     char *str;
4039 
4040     va_list ap;
4041 
4042     va_start(ap, msg);
4043     str = xmlTextReaderBuildMessage(msg, ap);
4044     if (!reader->errorFunc) {
4045         xmlTextReaderValidityWarning(ctx, "%s", str);
4046     } else {
4047         reader->errorFunc(reader->errorFuncArg, str,
4048                           XML_PARSER_SEVERITY_VALIDITY_WARNING,
4049                           NULL /* locator */ );
4050     }
4051     if (str != NULL)
4052         xmlFree(str);
4053     va_end(ap);
4054 }
4055 
4056 static void
4057   xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error);
4058 
4059 static void
xmlTextReaderValidityStructuredRelay(void * userData,xmlErrorPtr error)4060 xmlTextReaderValidityStructuredRelay(void *userData, xmlErrorPtr error)
4061 {
4062     xmlTextReaderPtr reader = (xmlTextReaderPtr) userData;
4063 
4064     if (reader->sErrorFunc) {
4065         reader->sErrorFunc(reader->errorFuncArg, error);
4066     } else {
4067         xmlTextReaderStructuredError(reader, error);
4068     }
4069 }
4070 /**
4071  * xmlTextReaderRelaxNGSetSchema:
4072  * @reader:  the xmlTextReaderPtr used
4073  * @schema:  a precompiled RelaxNG schema
4074  *
4075  * Use RelaxNG to validate the document as it is processed.
4076  * Activation is only possible before the first Read().
4077  * if @schema is NULL, then RelaxNG validation is desactivated.
4078  @ The @schema should not be freed until the reader is deallocated
4079  * or its use has been deactivated.
4080  *
4081  * Returns 0 in case the RelaxNG validation could be (des)activated and
4082  *         -1 in case of error.
4083  */
4084 int
xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader,xmlRelaxNGPtr schema)4085 xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
4086     if (reader == NULL)
4087         return(-1);
4088     if (schema == NULL) {
4089         if (reader->rngSchemas != NULL) {
4090 	    xmlRelaxNGFree(reader->rngSchemas);
4091 	    reader->rngSchemas = NULL;
4092 	}
4093         if (reader->rngValidCtxt != NULL) {
4094 	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4095 	    reader->rngValidCtxt = NULL;
4096         }
4097 	return(0);
4098     }
4099     if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4100 	return(-1);
4101     if (reader->rngSchemas != NULL) {
4102 	xmlRelaxNGFree(reader->rngSchemas);
4103 	reader->rngSchemas = NULL;
4104     }
4105     if (reader->rngValidCtxt != NULL) {
4106 	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4107 	reader->rngValidCtxt = NULL;
4108     }
4109     reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
4110     if (reader->rngValidCtxt == NULL)
4111         return(-1);
4112     if (reader->errorFunc != NULL) {
4113 	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4114 			xmlTextReaderValidityErrorRelay,
4115 			xmlTextReaderValidityWarningRelay,
4116 			reader);
4117     }
4118 	if (reader->sErrorFunc != NULL) {
4119 		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4120 			xmlTextReaderValidityStructuredRelay,
4121 			reader);
4122     }
4123     reader->rngValidErrors = 0;
4124     reader->rngFullNode = NULL;
4125     reader->validate = XML_TEXTREADER_VALIDATE_RNG;
4126     return(0);
4127 }
4128 
4129 /**
4130  * xmlTextReaderSetSchema:
4131  * @reader:  the xmlTextReaderPtr used
4132  * @schema:  a precompiled Schema schema
4133  *
4134  * Use XSD Schema to validate the document as it is processed.
4135  * Activation is only possible before the first Read().
4136  * if @schema is NULL, then Schema validation is desactivated.
4137  @ The @schema should not be freed until the reader is deallocated
4138  * or its use has been deactivated.
4139  *
4140  * Returns 0 in case the Schema validation could be (des)activated and
4141  *         -1 in case of error.
4142  */
4143 int
xmlTextReaderSetSchema(xmlTextReaderPtr reader,xmlSchemaPtr schema)4144 xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) {
4145     if (reader == NULL)
4146         return(-1);
4147     if (schema == NULL) {
4148 	if (reader->xsdPlug != NULL) {
4149 	    xmlSchemaSAXUnplug(reader->xsdPlug);
4150 	    reader->xsdPlug = NULL;
4151 	}
4152         if (reader->xsdValidCtxt != NULL) {
4153 	    if (! reader->xsdPreserveCtxt)
4154 		xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4155 	    reader->xsdValidCtxt = NULL;
4156         }
4157 	reader->xsdPreserveCtxt = 0;
4158         if (reader->xsdSchemas != NULL) {
4159 	    xmlSchemaFree(reader->xsdSchemas);
4160 	    reader->xsdSchemas = NULL;
4161 	}
4162 	return(0);
4163     }
4164     if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4165 	return(-1);
4166     if (reader->xsdPlug != NULL) {
4167 	xmlSchemaSAXUnplug(reader->xsdPlug);
4168 	reader->xsdPlug = NULL;
4169     }
4170     if (reader->xsdValidCtxt != NULL) {
4171 	if (! reader->xsdPreserveCtxt)
4172 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4173 	reader->xsdValidCtxt = NULL;
4174     }
4175     reader->xsdPreserveCtxt = 0;
4176     if (reader->xsdSchemas != NULL) {
4177 	xmlSchemaFree(reader->xsdSchemas);
4178 	reader->xsdSchemas = NULL;
4179     }
4180     reader->xsdValidCtxt = xmlSchemaNewValidCtxt(schema);
4181     if (reader->xsdValidCtxt == NULL) {
4182 	xmlSchemaFree(reader->xsdSchemas);
4183 	reader->xsdSchemas = NULL;
4184         return(-1);
4185     }
4186     reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4187                                        &(reader->ctxt->sax),
4188 				       &(reader->ctxt->userData));
4189     if (reader->xsdPlug == NULL) {
4190 	xmlSchemaFree(reader->xsdSchemas);
4191 	reader->xsdSchemas = NULL;
4192 	xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4193 	reader->xsdValidCtxt = NULL;
4194 	return(-1);
4195     }
4196     if (reader->errorFunc != NULL) {
4197 	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4198 			xmlTextReaderValidityErrorRelay,
4199 			xmlTextReaderValidityWarningRelay,
4200 			reader);
4201     }
4202 	if (reader->sErrorFunc != NULL) {
4203 		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4204 			xmlTextReaderValidityStructuredRelay,
4205 			reader);
4206     }
4207     reader->xsdValidErrors = 0;
4208     reader->validate = XML_TEXTREADER_VALIDATE_XSD;
4209     return(0);
4210 }
4211 
4212 /**
4213  * xmlTextReaderRelaxNGValidate:
4214  * @reader:  the xmlTextReaderPtr used
4215  * @rng:  the path to a RelaxNG schema or NULL
4216  *
4217  * Use RelaxNG to validate the document as it is processed.
4218  * Activation is only possible before the first Read().
4219  * if @rng is NULL, then RelaxNG validation is deactivated.
4220  *
4221  * Returns 0 in case the RelaxNG validation could be (de)activated and
4222  *         -1 in case of error.
4223  */
4224 int
xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader,const char * rng)4225 xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
4226     xmlRelaxNGParserCtxtPtr ctxt;
4227 
4228     if (reader == NULL)
4229         return(-1);
4230 
4231     if (rng == NULL) {
4232         if (reader->rngValidCtxt != NULL) {
4233 	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4234 	    reader->rngValidCtxt = NULL;
4235         }
4236         if (reader->rngSchemas != NULL) {
4237 	    xmlRelaxNGFree(reader->rngSchemas);
4238 	    reader->rngSchemas = NULL;
4239 	}
4240 	return(0);
4241     }
4242     if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4243 	return(-1);
4244     if (reader->rngSchemas != NULL) {
4245 	xmlRelaxNGFree(reader->rngSchemas);
4246 	reader->rngSchemas = NULL;
4247     }
4248     if (reader->rngValidCtxt != NULL) {
4249 	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4250 	reader->rngValidCtxt = NULL;
4251     }
4252     ctxt = xmlRelaxNGNewParserCtxt(rng);
4253     if (reader->errorFunc != NULL) {
4254 	xmlRelaxNGSetParserErrors(ctxt,
4255 			 xmlTextReaderValidityErrorRelay,
4256 			 xmlTextReaderValidityWarningRelay,
4257 			 reader);
4258     }
4259     if (reader->sErrorFunc != NULL) {
4260 	xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4261 			xmlTextReaderValidityStructuredRelay,
4262 			reader);
4263     }
4264     reader->rngSchemas = xmlRelaxNGParse(ctxt);
4265     xmlRelaxNGFreeParserCtxt(ctxt);
4266     if (reader->rngSchemas == NULL)
4267         return(-1);
4268     reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
4269     if (reader->rngValidCtxt == NULL) {
4270 	xmlRelaxNGFree(reader->rngSchemas);
4271 	reader->rngSchemas = NULL;
4272         return(-1);
4273     }
4274     if (reader->errorFunc != NULL) {
4275 	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4276 			 xmlTextReaderValidityErrorRelay,
4277 			 xmlTextReaderValidityWarningRelay,
4278 			 reader);
4279     }
4280 	if (reader->sErrorFunc != NULL) {
4281 		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4282 			xmlTextReaderValidityStructuredRelay,
4283 			reader);
4284     }
4285     reader->rngValidErrors = 0;
4286     reader->rngFullNode = NULL;
4287     reader->validate = XML_TEXTREADER_VALIDATE_RNG;
4288     return(0);
4289 }
4290 
4291 /**
4292  * xmlTextReaderSchemaValidateInternal:
4293  * @reader:  the xmlTextReaderPtr used
4294  * @xsd:  the path to a W3C XSD schema or NULL
4295  * @ctxt: the XML Schema validation context or NULL
4296  * @options: options (not used yet)
4297  *
4298  * Validate the document as it is processed using XML Schema.
4299  * Activation is only possible before the first Read().
4300  * If both @xsd and @ctxt are NULL then XML Schema validation is deactivated.
4301  *
4302  * Returns 0 in case the schemas validation could be (de)activated and
4303  *         -1 in case of error.
4304  */
4305 static int
xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader,const char * xsd,xmlSchemaValidCtxtPtr ctxt,int options ATTRIBUTE_UNUSED)4306 xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader,
4307 				    const char *xsd,
4308 				    xmlSchemaValidCtxtPtr ctxt,
4309 				    int options ATTRIBUTE_UNUSED)
4310 {
4311     if (reader == NULL)
4312         return(-1);
4313 
4314     if ((xsd != NULL) && (ctxt != NULL))
4315 	return(-1);
4316 
4317     if (((xsd != NULL) || (ctxt != NULL)) &&
4318 	((reader->mode != XML_TEXTREADER_MODE_INITIAL) ||
4319         (reader->ctxt == NULL)))
4320 	return(-1);
4321 
4322     /* Cleanup previous validation stuff. */
4323     if (reader->xsdPlug != NULL) {
4324 	xmlSchemaSAXUnplug(reader->xsdPlug);
4325 	reader->xsdPlug = NULL;
4326     }
4327     if (reader->xsdValidCtxt != NULL) {
4328 	if (! reader->xsdPreserveCtxt)
4329 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4330 	reader->xsdValidCtxt = NULL;
4331     }
4332     reader->xsdPreserveCtxt = 0;
4333     if (reader->xsdSchemas != NULL) {
4334 	xmlSchemaFree(reader->xsdSchemas);
4335 	reader->xsdSchemas = NULL;
4336     }
4337 
4338     if ((xsd == NULL) && (ctxt == NULL)) {
4339 	/* We just want to deactivate the validation, so get out. */
4340 	return(0);
4341     }
4342 
4343     if (xsd != NULL) {
4344 	xmlSchemaParserCtxtPtr pctxt;
4345 	/* Parse the schema and create validation environment. */
4346 	pctxt = xmlSchemaNewParserCtxt(xsd);
4347 	if (reader->errorFunc != NULL) {
4348 	    xmlSchemaSetParserErrors(pctxt,
4349 		xmlTextReaderValidityErrorRelay,
4350 		xmlTextReaderValidityWarningRelay,
4351 		reader);
4352 	}
4353 	reader->xsdSchemas = xmlSchemaParse(pctxt);
4354 	xmlSchemaFreeParserCtxt(pctxt);
4355 	if (reader->xsdSchemas == NULL)
4356 	    return(-1);
4357 	reader->xsdValidCtxt = xmlSchemaNewValidCtxt(reader->xsdSchemas);
4358 	if (reader->xsdValidCtxt == NULL) {
4359 	    xmlSchemaFree(reader->xsdSchemas);
4360 	    reader->xsdSchemas = NULL;
4361 	    return(-1);
4362 	}
4363 	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4364 	    &(reader->ctxt->sax),
4365 	    &(reader->ctxt->userData));
4366 	if (reader->xsdPlug == NULL) {
4367 	    xmlSchemaFree(reader->xsdSchemas);
4368 	    reader->xsdSchemas = NULL;
4369 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4370 	    reader->xsdValidCtxt = NULL;
4371 	    return(-1);
4372 	}
4373     } else {
4374 	/* Use the given validation context. */
4375 	reader->xsdValidCtxt = ctxt;
4376 	reader->xsdPreserveCtxt = 1;
4377 	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4378 	    &(reader->ctxt->sax),
4379 	    &(reader->ctxt->userData));
4380 	if (reader->xsdPlug == NULL) {
4381 	    reader->xsdValidCtxt = NULL;
4382 	    reader->xsdPreserveCtxt = 0;
4383 	    return(-1);
4384 	}
4385     }
4386     /*
4387     * Redirect the validation context's error channels to use
4388     * the reader channels.
4389     * TODO: In case the user provides the validation context we
4390     *   could make this redirection optional.
4391     */
4392     if (reader->errorFunc != NULL) {
4393 	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4394 			 xmlTextReaderValidityErrorRelay,
4395 			 xmlTextReaderValidityWarningRelay,
4396 			 reader);
4397     }
4398 	if (reader->sErrorFunc != NULL) {
4399 		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4400 			xmlTextReaderValidityStructuredRelay,
4401 			reader);
4402     }
4403     reader->xsdValidErrors = 0;
4404     reader->validate = XML_TEXTREADER_VALIDATE_XSD;
4405     return(0);
4406 }
4407 
4408 /**
4409  * xmlTextReaderSchemaValidateCtxt:
4410  * @reader:  the xmlTextReaderPtr used
4411  * @ctxt: the XML Schema validation context or NULL
4412  * @options: options (not used yet)
4413  *
4414  * Use W3C XSD schema context to validate the document as it is processed.
4415  * Activation is only possible before the first Read().
4416  * If @ctxt is NULL, then XML Schema validation is deactivated.
4417  *
4418  * Returns 0 in case the schemas validation could be (de)activated and
4419  *         -1 in case of error.
4420  */
4421 int
xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader,xmlSchemaValidCtxtPtr ctxt,int options)4422 xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader,
4423 				    xmlSchemaValidCtxtPtr ctxt,
4424 				    int options)
4425 {
4426     return(xmlTextReaderSchemaValidateInternal(reader, NULL, ctxt, options));
4427 }
4428 
4429 /**
4430  * xmlTextReaderSchemaValidate:
4431  * @reader:  the xmlTextReaderPtr used
4432  * @xsd:  the path to a W3C XSD schema or NULL
4433  *
4434  * Use W3C XSD schema to validate the document as it is processed.
4435  * Activation is only possible before the first Read().
4436  * If @xsd is NULL, then XML Schema validation is deactivated.
4437  *
4438  * Returns 0 in case the schemas validation could be (de)activated and
4439  *         -1 in case of error.
4440  */
4441 int
xmlTextReaderSchemaValidate(xmlTextReaderPtr reader,const char * xsd)4442 xmlTextReaderSchemaValidate(xmlTextReaderPtr reader, const char *xsd)
4443 {
4444     return(xmlTextReaderSchemaValidateInternal(reader, xsd, NULL, 0));
4445 }
4446 #endif
4447 
4448 /**
4449  * xmlTextReaderIsNamespaceDecl:
4450  * @reader: the xmlTextReaderPtr used
4451  *
4452  * Determine whether the current node is a namespace declaration
4453  * rather than a regular attribute.
4454  *
4455  * Returns 1 if the current node is a namespace declaration, 0 if it
4456  * is a regular attribute or other type of node, or -1 in case of
4457  * error.
4458  */
4459 int
xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader)4460 xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader) {
4461     xmlNodePtr node;
4462     if (reader == NULL)
4463 	return(-1);
4464     if (reader->node == NULL)
4465 	return(-1);
4466     if (reader->curnode != NULL)
4467 	node = reader->curnode;
4468     else
4469 	node = reader->node;
4470 
4471     if (XML_NAMESPACE_DECL == node->type)
4472 	return(1);
4473     else
4474 	return(0);
4475 }
4476 
4477 /**
4478  * xmlTextReaderConstXmlVersion:
4479  * @reader:  the xmlTextReaderPtr used
4480  *
4481  * Determine the XML version of the document being read.
4482  *
4483  * Returns a string containing the XML version of the document or NULL
4484  * in case of error.  The string is deallocated with the reader.
4485  */
4486 const xmlChar *
xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader)4487 xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) {
4488     xmlDocPtr doc = NULL;
4489     if (reader == NULL)
4490 	return(NULL);
4491     if (reader->doc != NULL)
4492         doc = reader->doc;
4493     else if (reader->ctxt != NULL)
4494 	doc = reader->ctxt->myDoc;
4495     if (doc == NULL)
4496 	return(NULL);
4497 
4498     if (doc->version == NULL)
4499 	return(NULL);
4500     else
4501       return(CONSTSTR(doc->version));
4502 }
4503 
4504 /**
4505  * xmlTextReaderStandalone:
4506  * @reader:  the xmlTextReaderPtr used
4507  *
4508  * Determine the standalone status of the document being read.
4509  *
4510  * Returns 1 if the document was declared to be standalone, 0 if it
4511  * was declared to be not standalone, or -1 if the document did not
4512  * specify its standalone status or in case of error.
4513  */
4514 int
xmlTextReaderStandalone(xmlTextReaderPtr reader)4515 xmlTextReaderStandalone(xmlTextReaderPtr reader) {
4516     xmlDocPtr doc = NULL;
4517     if (reader == NULL)
4518 	return(-1);
4519     if (reader->doc != NULL)
4520         doc = reader->doc;
4521     else if (reader->ctxt != NULL)
4522 	doc = reader->ctxt->myDoc;
4523     if (doc == NULL)
4524 	return(-1);
4525 
4526     return(doc->standalone);
4527 }
4528 
4529 /************************************************************************
4530  *									*
4531  *			Error Handling Extensions                       *
4532  *									*
4533  ************************************************************************/
4534 
4535 /* helper to build a xmlMalloc'ed string from a format and va_list */
4536 static char *
xmlTextReaderBuildMessage(const char * msg,va_list ap)4537 xmlTextReaderBuildMessage(const char *msg, va_list ap) {
4538     int size = 0;
4539     int chars;
4540     char *larger;
4541     char *str = NULL;
4542     va_list aq;
4543 
4544     while (1) {
4545         VA_COPY(aq, ap);
4546         chars = vsnprintf(str, size, msg, aq);
4547         va_end(aq);
4548         if (chars < 0) {
4549 	    xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n");
4550 	    if (str)
4551 		xmlFree(str);
4552 	    return NULL;
4553 	}
4554 	if ((chars < size) || (size == MAX_ERR_MSG_SIZE))
4555             break;
4556         if (chars < MAX_ERR_MSG_SIZE)
4557 	size = chars + 1;
4558 	else
4559 		size = MAX_ERR_MSG_SIZE;
4560         if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
4561 	    xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
4562 	    if (str)
4563                 xmlFree(str);
4564             return NULL;
4565         }
4566         str = larger;
4567     }
4568 
4569     return str;
4570 }
4571 
4572 /**
4573  * xmlTextReaderLocatorLineNumber:
4574  * @locator: the xmlTextReaderLocatorPtr used
4575  *
4576  * Obtain the line number for the given locator.
4577  *
4578  * Returns the line number or -1 in case of error.
4579  */
4580 int
xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator)4581 xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
4582     /* we know that locator is a xmlParserCtxtPtr */
4583     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
4584     int ret = -1;
4585 
4586     if (locator == NULL)
4587         return(-1);
4588     if (ctx->node != NULL) {
4589 	ret = xmlGetLineNo(ctx->node);
4590     }
4591     else {
4592 	/* inspired from error.c */
4593 	xmlParserInputPtr input;
4594 	input = ctx->input;
4595 	if ((input->filename == NULL) && (ctx->inputNr > 1))
4596 	    input = ctx->inputTab[ctx->inputNr - 2];
4597 	if (input != NULL) {
4598 	    ret = input->line;
4599 	}
4600 	else {
4601 	    ret = -1;
4602 	}
4603     }
4604 
4605     return ret;
4606 }
4607 
4608 /**
4609  * xmlTextReaderLocatorBaseURI:
4610  * @locator: the xmlTextReaderLocatorPtr used
4611  *
4612  * Obtain the base URI for the given locator.
4613  *
4614  * Returns the base URI or NULL in case of error,
4615  *    if non NULL it need to be freed by the caller.
4616  */
4617 xmlChar *
xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator)4618 xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
4619     /* we know that locator is a xmlParserCtxtPtr */
4620     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
4621     xmlChar *ret = NULL;
4622 
4623     if (locator == NULL)
4624         return(NULL);
4625     if (ctx->node != NULL) {
4626 	ret = xmlNodeGetBase(NULL,ctx->node);
4627     }
4628     else {
4629 	/* inspired from error.c */
4630 	xmlParserInputPtr input;
4631 	input = ctx->input;
4632 	if ((input->filename == NULL) && (ctx->inputNr > 1))
4633 	    input = ctx->inputTab[ctx->inputNr - 2];
4634 	if (input != NULL) {
4635 	    ret = xmlStrdup(BAD_CAST input->filename);
4636 	}
4637 	else {
4638 	    ret = NULL;
4639 	}
4640     }
4641 
4642     return ret;
4643 }
4644 
4645 static void
xmlTextReaderGenericError(void * ctxt,xmlParserSeverities severity,char * str)4646 xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity,
4647                           char *str)
4648 {
4649     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
4650 
4651     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
4652 
4653     if (str != NULL) {
4654         if (reader->errorFunc)
4655             reader->errorFunc(reader->errorFuncArg, str, severity,
4656                               (xmlTextReaderLocatorPtr) ctx);
4657         xmlFree(str);
4658     }
4659 }
4660 
4661 static void
xmlTextReaderStructuredError(void * ctxt,xmlErrorPtr error)4662 xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error)
4663 {
4664     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
4665 
4666     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
4667 
4668     if (error && reader->sErrorFunc) {
4669         reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error);
4670     }
4671 }
4672 
4673 static void XMLCDECL
xmlTextReaderError(void * ctxt,const char * msg,...)4674 xmlTextReaderError(void *ctxt, const char *msg, ...)
4675 {
4676     va_list ap;
4677 
4678     va_start(ap, msg);
4679     xmlTextReaderGenericError(ctxt,
4680                               XML_PARSER_SEVERITY_ERROR,
4681                               xmlTextReaderBuildMessage(msg, ap));
4682     va_end(ap);
4683 
4684 }
4685 
4686 static void XMLCDECL
xmlTextReaderWarning(void * ctxt,const char * msg,...)4687 xmlTextReaderWarning(void *ctxt, const char *msg, ...)
4688 {
4689     va_list ap;
4690 
4691     va_start(ap, msg);
4692     xmlTextReaderGenericError(ctxt,
4693                               XML_PARSER_SEVERITY_WARNING,
4694                               xmlTextReaderBuildMessage(msg, ap));
4695     va_end(ap);
4696 }
4697 
4698 static void XMLCDECL
xmlTextReaderValidityError(void * ctxt,const char * msg,...)4699 xmlTextReaderValidityError(void *ctxt, const char *msg, ...)
4700 {
4701     va_list ap;
4702 
4703     int len = xmlStrlen((const xmlChar *) msg);
4704 
4705     if ((len > 1) && (msg[len - 2] != ':')) {
4706         /*
4707          * some callbacks only report locator information:
4708          * skip them (mimicking behaviour in error.c)
4709          */
4710         va_start(ap, msg);
4711         xmlTextReaderGenericError(ctxt,
4712                                   XML_PARSER_SEVERITY_VALIDITY_ERROR,
4713                                   xmlTextReaderBuildMessage(msg, ap));
4714         va_end(ap);
4715     }
4716 }
4717 
4718 static void XMLCDECL
xmlTextReaderValidityWarning(void * ctxt,const char * msg,...)4719 xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...)
4720 {
4721     va_list ap;
4722 
4723     int len = xmlStrlen((const xmlChar *) msg);
4724 
4725     if ((len != 0) && (msg[len - 1] != ':')) {
4726         /*
4727          * some callbacks only report locator information:
4728          * skip them (mimicking behaviour in error.c)
4729          */
4730         va_start(ap, msg);
4731         xmlTextReaderGenericError(ctxt,
4732                                   XML_PARSER_SEVERITY_VALIDITY_WARNING,
4733                                   xmlTextReaderBuildMessage(msg, ap));
4734         va_end(ap);
4735     }
4736 }
4737 
4738 /**
4739  * xmlTextReaderSetErrorHandler:
4740  * @reader:  the xmlTextReaderPtr used
4741  * @f:	the callback function to call on error and warnings
4742  * @arg:    a user argument to pass to the callback function
4743  *
4744  * Register a callback function that will be called on error and warnings.
4745  *
4746  * If @f is NULL, the default error and warning handlers are restored.
4747  */
4748 void
xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,xmlTextReaderErrorFunc f,void * arg)4749 xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
4750                              xmlTextReaderErrorFunc f, void *arg)
4751 {
4752     if (f != NULL) {
4753         reader->ctxt->sax->error = xmlTextReaderError;
4754         reader->ctxt->sax->serror = NULL;
4755         reader->ctxt->vctxt.error = xmlTextReaderValidityError;
4756         reader->ctxt->sax->warning = xmlTextReaderWarning;
4757         reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
4758         reader->errorFunc = f;
4759         reader->sErrorFunc = NULL;
4760         reader->errorFuncArg = arg;
4761 #ifdef LIBXML_SCHEMAS_ENABLED
4762         if (reader->rngValidCtxt) {
4763             xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4764                                      xmlTextReaderValidityErrorRelay,
4765                                      xmlTextReaderValidityWarningRelay,
4766                                      reader);
4767             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
4768                                                reader);
4769         }
4770         if (reader->xsdValidCtxt) {
4771             xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4772                                     xmlTextReaderValidityErrorRelay,
4773                                     xmlTextReaderValidityWarningRelay,
4774                                     reader);
4775             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
4776                                               reader);
4777         }
4778 #endif
4779     } else {
4780         /* restore defaults */
4781         reader->ctxt->sax->error = xmlParserError;
4782         reader->ctxt->vctxt.error = xmlParserValidityError;
4783         reader->ctxt->sax->warning = xmlParserWarning;
4784         reader->ctxt->vctxt.warning = xmlParserValidityWarning;
4785         reader->errorFunc = NULL;
4786         reader->sErrorFunc = NULL;
4787         reader->errorFuncArg = NULL;
4788 #ifdef LIBXML_SCHEMAS_ENABLED
4789         if (reader->rngValidCtxt) {
4790             xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
4791                                      reader);
4792             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
4793                                                reader);
4794         }
4795         if (reader->xsdValidCtxt) {
4796             xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
4797                                     reader);
4798             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
4799                                               reader);
4800         }
4801 #endif
4802     }
4803 }
4804 
4805 /**
4806 * xmlTextReaderSetStructuredErrorHandler:
4807  * @reader:  the xmlTextReaderPtr used
4808  * @f:	the callback function to call on error and warnings
4809  * @arg:    a user argument to pass to the callback function
4810  *
4811  * Register a callback function that will be called on error and warnings.
4812  *
4813  * If @f is NULL, the default error and warning handlers are restored.
4814  */
4815 void
xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader,xmlStructuredErrorFunc f,void * arg)4816 xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader,
4817                                        xmlStructuredErrorFunc f, void *arg)
4818 {
4819     if (f != NULL) {
4820         reader->ctxt->sax->error = NULL;
4821         reader->ctxt->sax->serror = xmlTextReaderStructuredError;
4822         reader->ctxt->vctxt.error = xmlTextReaderValidityError;
4823         reader->ctxt->sax->warning = xmlTextReaderWarning;
4824         reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
4825         reader->sErrorFunc = f;
4826         reader->errorFunc = NULL;
4827         reader->errorFuncArg = arg;
4828 #ifdef LIBXML_SCHEMAS_ENABLED
4829         if (reader->rngValidCtxt) {
4830             xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
4831                                      reader);
4832             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4833                                         xmlTextReaderValidityStructuredRelay,
4834                                                reader);
4835         }
4836         if (reader->xsdValidCtxt) {
4837             xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
4838                                     reader);
4839             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4840                                        xmlTextReaderValidityStructuredRelay,
4841                                               reader);
4842         }
4843 #endif
4844     } else {
4845         /* restore defaults */
4846         reader->ctxt->sax->error = xmlParserError;
4847         reader->ctxt->sax->serror = NULL;
4848         reader->ctxt->vctxt.error = xmlParserValidityError;
4849         reader->ctxt->sax->warning = xmlParserWarning;
4850         reader->ctxt->vctxt.warning = xmlParserValidityWarning;
4851         reader->errorFunc = NULL;
4852         reader->sErrorFunc = NULL;
4853         reader->errorFuncArg = NULL;
4854 #ifdef LIBXML_SCHEMAS_ENABLED
4855         if (reader->rngValidCtxt) {
4856             xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
4857                                      reader);
4858             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
4859                                                reader);
4860         }
4861         if (reader->xsdValidCtxt) {
4862             xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
4863                                     reader);
4864             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
4865                                               reader);
4866         }
4867 #endif
4868     }
4869 }
4870 
4871 /**
4872  * xmlTextReaderIsValid:
4873  * @reader:  the xmlTextReaderPtr used
4874  *
4875  * Retrieve the validity status from the parser context
4876  *
4877  * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
4878  */
4879 int
xmlTextReaderIsValid(xmlTextReaderPtr reader)4880 xmlTextReaderIsValid(xmlTextReaderPtr reader)
4881 {
4882     if (reader == NULL)
4883         return (-1);
4884 #ifdef LIBXML_SCHEMAS_ENABLED
4885     if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
4886         return (reader->rngValidErrors == 0);
4887     if (reader->validate == XML_TEXTREADER_VALIDATE_XSD)
4888         return (reader->xsdValidErrors == 0);
4889 #endif
4890     if ((reader->ctxt != NULL) && (reader->ctxt->validate == 1))
4891         return (reader->ctxt->valid);
4892     return (0);
4893 }
4894 
4895 /**
4896  * xmlTextReaderGetErrorHandler:
4897  * @reader:  the xmlTextReaderPtr used
4898  * @f:	the callback function or NULL is no callback has been registered
4899  * @arg:    a user argument
4900  *
4901  * Retrieve the error callback function and user argument.
4902  */
4903 void
xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,xmlTextReaderErrorFunc * f,void ** arg)4904 xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
4905                              xmlTextReaderErrorFunc * f, void **arg)
4906 {
4907     if (f != NULL)
4908         *f = reader->errorFunc;
4909     if (arg != NULL)
4910         *arg = reader->errorFuncArg;
4911 }
4912 /************************************************************************
4913  *									*
4914  *	New set (2.6.0) of simpler and more flexible APIs		*
4915  *									*
4916  ************************************************************************/
4917 
4918 /**
4919  * xmlTextReaderSetup:
4920  * @reader:  an XML reader
4921  * @input: xmlParserInputBufferPtr used to feed the reader, will
4922  *         be destroyed with it.
4923  * @URL:  the base URL to use for the document
4924  * @encoding:  the document encoding, or NULL
4925  * @options:  a combination of xmlParserOption
4926  *
4927  * Setup an XML reader with new options
4928  *
4929  * Returns 0 in case of success and -1 in case of error.
4930  */
4931 int
xmlTextReaderSetup(xmlTextReaderPtr reader,xmlParserInputBufferPtr input,const char * URL,const char * encoding,int options)4932 xmlTextReaderSetup(xmlTextReaderPtr reader,
4933                    xmlParserInputBufferPtr input, const char *URL,
4934                    const char *encoding, int options)
4935 {
4936     if (reader == NULL) {
4937         if (input != NULL)
4938 	    xmlFreeParserInputBuffer(input);
4939         return (-1);
4940     }
4941 
4942     /*
4943      * we force the generation of compact text nodes on the reader
4944      * since usr applications should never modify the tree
4945      */
4946     options |= XML_PARSE_COMPACT;
4947 
4948     reader->doc = NULL;
4949     reader->entNr = 0;
4950     reader->parserFlags = options;
4951     reader->validate = XML_TEXTREADER_NOT_VALIDATE;
4952     if ((input != NULL) && (reader->input != NULL) &&
4953         (reader->allocs & XML_TEXTREADER_INPUT)) {
4954 	xmlFreeParserInputBuffer(reader->input);
4955 	reader->input = NULL;
4956 	reader->allocs -= XML_TEXTREADER_INPUT;
4957     }
4958     if (input != NULL) {
4959 	reader->input = input;
4960 	reader->allocs |= XML_TEXTREADER_INPUT;
4961     }
4962     if (reader->buffer == NULL)
4963         reader->buffer = xmlBufferCreateSize(100);
4964     if (reader->buffer == NULL) {
4965         xmlGenericError(xmlGenericErrorContext,
4966                         "xmlTextReaderSetup : malloc failed\n");
4967         return (-1);
4968     }
4969     if (reader->sax == NULL)
4970 	reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
4971     if (reader->sax == NULL) {
4972         xmlGenericError(xmlGenericErrorContext,
4973                         "xmlTextReaderSetup : malloc failed\n");
4974         return (-1);
4975     }
4976     xmlSAXVersion(reader->sax, 2);
4977     reader->startElement = reader->sax->startElement;
4978     reader->sax->startElement = xmlTextReaderStartElement;
4979     reader->endElement = reader->sax->endElement;
4980     reader->sax->endElement = xmlTextReaderEndElement;
4981 #ifdef LIBXML_SAX1_ENABLED
4982     if (reader->sax->initialized == XML_SAX2_MAGIC) {
4983 #endif /* LIBXML_SAX1_ENABLED */
4984         reader->startElementNs = reader->sax->startElementNs;
4985         reader->sax->startElementNs = xmlTextReaderStartElementNs;
4986         reader->endElementNs = reader->sax->endElementNs;
4987         reader->sax->endElementNs = xmlTextReaderEndElementNs;
4988 #ifdef LIBXML_SAX1_ENABLED
4989     } else {
4990         reader->startElementNs = NULL;
4991         reader->endElementNs = NULL;
4992     }
4993 #endif /* LIBXML_SAX1_ENABLED */
4994     reader->characters = reader->sax->characters;
4995     reader->sax->characters = xmlTextReaderCharacters;
4996     reader->sax->ignorableWhitespace = xmlTextReaderCharacters;
4997     reader->cdataBlock = reader->sax->cdataBlock;
4998     reader->sax->cdataBlock = xmlTextReaderCDataBlock;
4999 
5000     reader->mode = XML_TEXTREADER_MODE_INITIAL;
5001     reader->node = NULL;
5002     reader->curnode = NULL;
5003     if (input != NULL) {
5004         if (reader->input->buffer->use < 4) {
5005             xmlParserInputBufferRead(input, 4);
5006         }
5007         if (reader->ctxt == NULL) {
5008             if (reader->input->buffer->use >= 4) {
5009                 reader->ctxt = xmlCreatePushParserCtxt(reader->sax, NULL,
5010 		       (const char *) reader->input->buffer->content, 4, URL);
5011                 reader->base = 0;
5012                 reader->cur = 4;
5013             } else {
5014                 reader->ctxt =
5015                     xmlCreatePushParserCtxt(reader->sax, NULL, NULL, 0, URL);
5016                 reader->base = 0;
5017                 reader->cur = 0;
5018             }
5019         } else {
5020 	    xmlParserInputPtr inputStream;
5021 	    xmlParserInputBufferPtr buf;
5022 	    xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
5023 
5024 	    xmlCtxtReset(reader->ctxt);
5025 	    buf = xmlAllocParserInputBuffer(enc);
5026 	    if (buf == NULL) return(-1);
5027 	    inputStream = xmlNewInputStream(reader->ctxt);
5028 	    if (inputStream == NULL) {
5029 		xmlFreeParserInputBuffer(buf);
5030 		return(-1);
5031 	    }
5032 
5033 	    if (URL == NULL)
5034 		inputStream->filename = NULL;
5035 	    else
5036 		inputStream->filename = (char *)
5037 		    xmlCanonicPath((const xmlChar *) URL);
5038 	    inputStream->buf = buf;
5039 	    inputStream->base = inputStream->buf->buffer->content;
5040 	    inputStream->cur = inputStream->buf->buffer->content;
5041 	    inputStream->end =
5042             &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
5043 
5044 	    inputPush(reader->ctxt, inputStream);
5045 	    reader->cur = 0;
5046 	}
5047         if (reader->ctxt == NULL) {
5048             xmlGenericError(xmlGenericErrorContext,
5049                             "xmlTextReaderSetup : malloc failed\n");
5050             return (-1);
5051         }
5052     }
5053     if (reader->dict != NULL) {
5054         if (reader->ctxt->dict != NULL) {
5055 	    if (reader->dict != reader->ctxt->dict) {
5056 		xmlDictFree(reader->dict);
5057 		reader->dict = reader->ctxt->dict;
5058 	    }
5059 	} else {
5060 	    reader->ctxt->dict = reader->dict;
5061 	}
5062     } else {
5063 	if (reader->ctxt->dict == NULL)
5064 	    reader->ctxt->dict = xmlDictCreate();
5065         reader->dict = reader->ctxt->dict;
5066     }
5067     reader->ctxt->_private = reader;
5068     reader->ctxt->linenumbers = 1;
5069     reader->ctxt->dictNames = 1;
5070     /*
5071      * use the parser dictionnary to allocate all elements and attributes names
5072      */
5073     reader->ctxt->docdict = 1;
5074     reader->ctxt->parseMode = XML_PARSE_READER;
5075 
5076 #ifdef LIBXML_XINCLUDE_ENABLED
5077     if (reader->xincctxt != NULL) {
5078 	xmlXIncludeFreeContext(reader->xincctxt);
5079 	reader->xincctxt = NULL;
5080     }
5081     if (options & XML_PARSE_XINCLUDE) {
5082         reader->xinclude = 1;
5083 	reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1);
5084 	options -= XML_PARSE_XINCLUDE;
5085     } else
5086         reader->xinclude = 0;
5087     reader->in_xinclude = 0;
5088 #endif
5089 #ifdef LIBXML_PATTERN_ENABLED
5090     if (reader->patternTab == NULL) {
5091         reader->patternNr = 0;
5092 	reader->patternMax = 0;
5093     }
5094     while (reader->patternNr > 0) {
5095         reader->patternNr--;
5096 	if (reader->patternTab[reader->patternNr] != NULL) {
5097 	    xmlFreePattern(reader->patternTab[reader->patternNr]);
5098             reader->patternTab[reader->patternNr] = NULL;
5099 	}
5100     }
5101 #endif
5102 
5103     if (options & XML_PARSE_DTDVALID)
5104         reader->validate = XML_TEXTREADER_VALIDATE_DTD;
5105 
5106     xmlCtxtUseOptions(reader->ctxt, options);
5107     if (encoding != NULL) {
5108         xmlCharEncodingHandlerPtr hdlr;
5109 
5110         hdlr = xmlFindCharEncodingHandler(encoding);
5111         if (hdlr != NULL)
5112             xmlSwitchToEncoding(reader->ctxt, hdlr);
5113     }
5114     if ((URL != NULL) && (reader->ctxt->input != NULL) &&
5115         (reader->ctxt->input->filename == NULL))
5116         reader->ctxt->input->filename = (char *)
5117             xmlStrdup((const xmlChar *) URL);
5118 
5119     reader->doc = NULL;
5120 
5121     return (0);
5122 }
5123 
5124 /**
5125  * xmlTextReaderByteConsumed:
5126  * @reader: an XML reader
5127  *
5128  * This function provides the current index of the parser used
5129  * by the reader, relative to the start of the current entity.
5130  * This function actually just wraps a call to xmlBytesConsumed()
5131  * for the parser context associated with the reader.
5132  * See xmlBytesConsumed() for more information.
5133  *
5134  * Returns the index in bytes from the beginning of the entity or -1
5135  *         in case the index could not be computed.
5136  */
5137 long
xmlTextReaderByteConsumed(xmlTextReaderPtr reader)5138 xmlTextReaderByteConsumed(xmlTextReaderPtr reader) {
5139     if ((reader == NULL) || (reader->ctxt == NULL))
5140         return(-1);
5141     return(xmlByteConsumed(reader->ctxt));
5142 }
5143 
5144 
5145 /**
5146  * xmlReaderWalker:
5147  * @doc:  a preparsed document
5148  *
5149  * Create an xmltextReader for a preparsed document.
5150  *
5151  * Returns the new reader or NULL in case of error.
5152  */
5153 xmlTextReaderPtr
xmlReaderWalker(xmlDocPtr doc)5154 xmlReaderWalker(xmlDocPtr doc)
5155 {
5156     xmlTextReaderPtr ret;
5157 
5158     if (doc == NULL)
5159         return(NULL);
5160 
5161     ret = xmlMalloc(sizeof(xmlTextReader));
5162     if (ret == NULL) {
5163         xmlGenericError(xmlGenericErrorContext,
5164 		"xmlNewTextReader : malloc failed\n");
5165 	return(NULL);
5166     }
5167     memset(ret, 0, sizeof(xmlTextReader));
5168     ret->entNr = 0;
5169     ret->input = NULL;
5170     ret->mode = XML_TEXTREADER_MODE_INITIAL;
5171     ret->node = NULL;
5172     ret->curnode = NULL;
5173     ret->base = 0;
5174     ret->cur = 0;
5175     ret->allocs = XML_TEXTREADER_CTXT;
5176     ret->doc = doc;
5177     ret->state = XML_TEXTREADER_START;
5178     ret->dict = xmlDictCreate();
5179     return(ret);
5180 }
5181 
5182 /**
5183  * xmlReaderForDoc:
5184  * @cur:  a pointer to a zero terminated string
5185  * @URL:  the base URL to use for the document
5186  * @encoding:  the document encoding, or NULL
5187  * @options:  a combination of xmlParserOption
5188  *
5189  * Create an xmltextReader for an XML in-memory document.
5190  * The parsing flags @options are a combination of xmlParserOption.
5191  *
5192  * Returns the new reader or NULL in case of error.
5193  */
5194 xmlTextReaderPtr
xmlReaderForDoc(const xmlChar * cur,const char * URL,const char * encoding,int options)5195 xmlReaderForDoc(const xmlChar * cur, const char *URL, const char *encoding,
5196                 int options)
5197 {
5198     int len;
5199 
5200     if (cur == NULL)
5201         return (NULL);
5202     len = xmlStrlen(cur);
5203 
5204     return (xmlReaderForMemory
5205             ((const char *) cur, len, URL, encoding, options));
5206 }
5207 
5208 /**
5209  * xmlReaderForFile:
5210  * @filename:  a file or URL
5211  * @encoding:  the document encoding, or NULL
5212  * @options:  a combination of xmlParserOption
5213  *
5214  * parse an XML file from the filesystem or the network.
5215  * The parsing flags @options are a combination of xmlParserOption.
5216  *
5217  * Returns the new reader or NULL in case of error.
5218  */
5219 xmlTextReaderPtr
xmlReaderForFile(const char * filename,const char * encoding,int options)5220 xmlReaderForFile(const char *filename, const char *encoding, int options)
5221 {
5222     xmlTextReaderPtr reader;
5223 
5224     reader = xmlNewTextReaderFilename(filename);
5225     if (reader == NULL)
5226         return (NULL);
5227     xmlTextReaderSetup(reader, NULL, NULL, encoding, options);
5228     return (reader);
5229 }
5230 
5231 /**
5232  * xmlReaderForMemory:
5233  * @buffer:  a pointer to a char array
5234  * @size:  the size of the array
5235  * @URL:  the base URL to use for the document
5236  * @encoding:  the document encoding, or NULL
5237  * @options:  a combination of xmlParserOption
5238  *
5239  * Create an xmltextReader for an XML in-memory document.
5240  * The parsing flags @options are a combination of xmlParserOption.
5241  *
5242  * Returns the new reader or NULL in case of error.
5243  */
5244 xmlTextReaderPtr
xmlReaderForMemory(const char * buffer,int size,const char * URL,const char * encoding,int options)5245 xmlReaderForMemory(const char *buffer, int size, const char *URL,
5246                    const char *encoding, int options)
5247 {
5248     xmlTextReaderPtr reader;
5249     xmlParserInputBufferPtr buf;
5250 
5251     buf = xmlParserInputBufferCreateStatic(buffer, size,
5252                                       XML_CHAR_ENCODING_NONE);
5253     if (buf == NULL) {
5254         return (NULL);
5255     }
5256     reader = xmlNewTextReader(buf, URL);
5257     if (reader == NULL) {
5258         xmlFreeParserInputBuffer(buf);
5259         return (NULL);
5260     }
5261     reader->allocs |= XML_TEXTREADER_INPUT;
5262     xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5263     return (reader);
5264 }
5265 
5266 /**
5267  * xmlReaderForFd:
5268  * @fd:  an open file descriptor
5269  * @URL:  the base URL to use for the document
5270  * @encoding:  the document encoding, or NULL
5271  * @options:  a combination of xmlParserOption
5272  *
5273  * Create an xmltextReader for an XML from a file descriptor.
5274  * The parsing flags @options are a combination of xmlParserOption.
5275  * NOTE that the file descriptor will not be closed when the
5276  *      reader is closed or reset.
5277  *
5278  * Returns the new reader or NULL in case of error.
5279  */
5280 xmlTextReaderPtr
xmlReaderForFd(int fd,const char * URL,const char * encoding,int options)5281 xmlReaderForFd(int fd, const char *URL, const char *encoding, int options)
5282 {
5283     xmlTextReaderPtr reader;
5284     xmlParserInputBufferPtr input;
5285 
5286     if (fd < 0)
5287         return (NULL);
5288 
5289     input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
5290     if (input == NULL)
5291         return (NULL);
5292     input->closecallback = NULL;
5293     reader = xmlNewTextReader(input, URL);
5294     if (reader == NULL) {
5295         xmlFreeParserInputBuffer(input);
5296         return (NULL);
5297     }
5298     reader->allocs |= XML_TEXTREADER_INPUT;
5299     xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5300     return (reader);
5301 }
5302 
5303 /**
5304  * xmlReaderForIO:
5305  * @ioread:  an I/O read function
5306  * @ioclose:  an I/O close function
5307  * @ioctx:  an I/O handler
5308  * @URL:  the base URL to use for the document
5309  * @encoding:  the document encoding, or NULL
5310  * @options:  a combination of xmlParserOption
5311  *
5312  * Create an xmltextReader for an XML document from I/O functions and source.
5313  * The parsing flags @options are a combination of xmlParserOption.
5314  *
5315  * Returns the new reader or NULL in case of error.
5316  */
5317 xmlTextReaderPtr
xmlReaderForIO(xmlInputReadCallback ioread,xmlInputCloseCallback ioclose,void * ioctx,const char * URL,const char * encoding,int options)5318 xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
5319                void *ioctx, const char *URL, const char *encoding,
5320                int options)
5321 {
5322     xmlTextReaderPtr reader;
5323     xmlParserInputBufferPtr input;
5324 
5325     if (ioread == NULL)
5326         return (NULL);
5327 
5328     input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
5329                                          XML_CHAR_ENCODING_NONE);
5330     if (input == NULL)
5331         return (NULL);
5332     reader = xmlNewTextReader(input, URL);
5333     if (reader == NULL) {
5334         xmlFreeParserInputBuffer(input);
5335         return (NULL);
5336     }
5337     reader->allocs |= XML_TEXTREADER_INPUT;
5338     xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5339     return (reader);
5340 }
5341 
5342 /**
5343  * xmlReaderNewWalker:
5344  * @reader:  an XML reader
5345  * @doc:  a preparsed document
5346  *
5347  * Setup an xmltextReader to parse a preparsed XML document.
5348  * This reuses the existing @reader xmlTextReader.
5349  *
5350  * Returns 0 in case of success and -1 in case of error
5351  */
5352 int
xmlReaderNewWalker(xmlTextReaderPtr reader,xmlDocPtr doc)5353 xmlReaderNewWalker(xmlTextReaderPtr reader, xmlDocPtr doc)
5354 {
5355     if (doc == NULL)
5356         return (-1);
5357     if (reader == NULL)
5358         return (-1);
5359 
5360     if (reader->input != NULL) {
5361         xmlFreeParserInputBuffer(reader->input);
5362     }
5363     if (reader->ctxt != NULL) {
5364 	xmlCtxtReset(reader->ctxt);
5365     }
5366 
5367     reader->entNr = 0;
5368     reader->input = NULL;
5369     reader->mode = XML_TEXTREADER_MODE_INITIAL;
5370     reader->node = NULL;
5371     reader->curnode = NULL;
5372     reader->base = 0;
5373     reader->cur = 0;
5374     reader->allocs = XML_TEXTREADER_CTXT;
5375     reader->doc = doc;
5376     reader->state = XML_TEXTREADER_START;
5377     if (reader->dict == NULL) {
5378         if ((reader->ctxt != NULL) && (reader->ctxt->dict != NULL))
5379 	    reader->dict = reader->ctxt->dict;
5380 	else
5381 	    reader->dict = xmlDictCreate();
5382     }
5383     return(0);
5384 }
5385 
5386 /**
5387  * xmlReaderNewDoc:
5388  * @reader:  an XML reader
5389  * @cur:  a pointer to a zero terminated string
5390  * @URL:  the base URL to use for the document
5391  * @encoding:  the document encoding, or NULL
5392  * @options:  a combination of xmlParserOption
5393  *
5394  * Setup an xmltextReader to parse an XML in-memory document.
5395  * The parsing flags @options are a combination of xmlParserOption.
5396  * This reuses the existing @reader xmlTextReader.
5397  *
5398  * Returns 0 in case of success and -1 in case of error
5399  */
5400 int
xmlReaderNewDoc(xmlTextReaderPtr reader,const xmlChar * cur,const char * URL,const char * encoding,int options)5401 xmlReaderNewDoc(xmlTextReaderPtr reader, const xmlChar * cur,
5402                 const char *URL, const char *encoding, int options)
5403 {
5404 
5405     int len;
5406 
5407     if (cur == NULL)
5408         return (-1);
5409     if (reader == NULL)
5410         return (-1);
5411 
5412     len = xmlStrlen(cur);
5413     return (xmlReaderNewMemory(reader, (const char *)cur, len,
5414                                URL, encoding, options));
5415 }
5416 
5417 /**
5418  * xmlReaderNewFile:
5419  * @reader:  an XML reader
5420  * @filename:  a file or URL
5421  * @encoding:  the document encoding, or NULL
5422  * @options:  a combination of xmlParserOption
5423  *
5424  * parse an XML file from the filesystem or the network.
5425  * The parsing flags @options are a combination of xmlParserOption.
5426  * This reuses the existing @reader xmlTextReader.
5427  *
5428  * Returns 0 in case of success and -1 in case of error
5429  */
5430 int
xmlReaderNewFile(xmlTextReaderPtr reader,const char * filename,const char * encoding,int options)5431 xmlReaderNewFile(xmlTextReaderPtr reader, const char *filename,
5432                  const char *encoding, int options)
5433 {
5434     xmlParserInputBufferPtr input;
5435 
5436     if (filename == NULL)
5437         return (-1);
5438     if (reader == NULL)
5439         return (-1);
5440 
5441     input =
5442         xmlParserInputBufferCreateFilename(filename,
5443                                            XML_CHAR_ENCODING_NONE);
5444     if (input == NULL)
5445         return (-1);
5446     return (xmlTextReaderSetup(reader, input, filename, encoding, options));
5447 }
5448 
5449 /**
5450  * xmlReaderNewMemory:
5451  * @reader:  an XML reader
5452  * @buffer:  a pointer to a char array
5453  * @size:  the size of the array
5454  * @URL:  the base URL to use for the document
5455  * @encoding:  the document encoding, or NULL
5456  * @options:  a combination of xmlParserOption
5457  *
5458  * Setup an xmltextReader to parse an XML in-memory document.
5459  * The parsing flags @options are a combination of xmlParserOption.
5460  * This reuses the existing @reader xmlTextReader.
5461  *
5462  * Returns 0 in case of success and -1 in case of error
5463  */
5464 int
xmlReaderNewMemory(xmlTextReaderPtr reader,const char * buffer,int size,const char * URL,const char * encoding,int options)5465 xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size,
5466                    const char *URL, const char *encoding, int options)
5467 {
5468     xmlParserInputBufferPtr input;
5469 
5470     if (reader == NULL)
5471         return (-1);
5472     if (buffer == NULL)
5473         return (-1);
5474 
5475     input = xmlParserInputBufferCreateStatic(buffer, size,
5476                                       XML_CHAR_ENCODING_NONE);
5477     if (input == NULL) {
5478         return (-1);
5479     }
5480     return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5481 }
5482 
5483 /**
5484  * xmlReaderNewFd:
5485  * @reader:  an XML reader
5486  * @fd:  an open file descriptor
5487  * @URL:  the base URL to use for the document
5488  * @encoding:  the document encoding, or NULL
5489  * @options:  a combination of xmlParserOption
5490  *
5491  * Setup an xmltextReader to parse an XML from a file descriptor.
5492  * NOTE that the file descriptor will not be closed when the
5493  *      reader is closed or reset.
5494  * The parsing flags @options are a combination of xmlParserOption.
5495  * This reuses the existing @reader xmlTextReader.
5496  *
5497  * Returns 0 in case of success and -1 in case of error
5498  */
5499 int
xmlReaderNewFd(xmlTextReaderPtr reader,int fd,const char * URL,const char * encoding,int options)5500 xmlReaderNewFd(xmlTextReaderPtr reader, int fd,
5501                const char *URL, const char *encoding, int options)
5502 {
5503     xmlParserInputBufferPtr input;
5504 
5505     if (fd < 0)
5506         return (-1);
5507     if (reader == NULL)
5508         return (-1);
5509 
5510     input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
5511     if (input == NULL)
5512         return (-1);
5513     input->closecallback = NULL;
5514     return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5515 }
5516 
5517 /**
5518  * xmlReaderNewIO:
5519  * @reader:  an XML reader
5520  * @ioread:  an I/O read function
5521  * @ioclose:  an I/O close function
5522  * @ioctx:  an I/O handler
5523  * @URL:  the base URL to use for the document
5524  * @encoding:  the document encoding, or NULL
5525  * @options:  a combination of xmlParserOption
5526  *
5527  * Setup an xmltextReader to parse an XML document from I/O functions
5528  * and source.
5529  * The parsing flags @options are a combination of xmlParserOption.
5530  * This reuses the existing @reader xmlTextReader.
5531  *
5532  * Returns 0 in case of success and -1 in case of error
5533  */
5534 int
xmlReaderNewIO(xmlTextReaderPtr reader,xmlInputReadCallback ioread,xmlInputCloseCallback ioclose,void * ioctx,const char * URL,const char * encoding,int options)5535 xmlReaderNewIO(xmlTextReaderPtr reader, xmlInputReadCallback ioread,
5536                xmlInputCloseCallback ioclose, void *ioctx,
5537                const char *URL, const char *encoding, int options)
5538 {
5539     xmlParserInputBufferPtr input;
5540 
5541     if (ioread == NULL)
5542         return (-1);
5543     if (reader == NULL)
5544         return (-1);
5545 
5546     input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
5547                                          XML_CHAR_ENCODING_NONE);
5548     if (input == NULL)
5549         return (-1);
5550     return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5551 }
5552 /************************************************************************
5553  *									*
5554  *			Utilities					*
5555  *									*
5556  ************************************************************************/
5557 #ifdef NOT_USED_YET
5558 
5559 /**
5560  * xmlBase64Decode:
5561  * @in:  the input buffer
5562  * @inlen:  the size of the input (in), the size read from it (out)
5563  * @to:  the output buffer
5564  * @tolen:  the size of the output (in), the size written to (out)
5565  *
5566  * Base64 decoder, reads from @in and save in @to
5567  * TODO: tell jody when this is actually exported
5568  *
5569  * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
5570  *         2 if there wasn't enough space on the output or -1 in case of error.
5571  */
5572 static int
xmlBase64Decode(const unsigned char * in,unsigned long * inlen,unsigned char * to,unsigned long * tolen)5573 xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
5574                 unsigned char *to, unsigned long *tolen)
5575 {
5576     unsigned long incur;        /* current index in in[] */
5577 
5578     unsigned long inblk;        /* last block index in in[] */
5579 
5580     unsigned long outcur;       /* current index in out[] */
5581 
5582     unsigned long inmax;        /* size of in[] */
5583 
5584     unsigned long outmax;       /* size of out[] */
5585 
5586     unsigned char cur;          /* the current value read from in[] */
5587 
5588     unsigned char intmp[4], outtmp[4];  /* temporary buffers for the convert */
5589 
5590     int nbintmp;                /* number of byte in intmp[] */
5591 
5592     int is_ignore;              /* cur should be ignored */
5593 
5594     int is_end = 0;             /* the end of the base64 was found */
5595 
5596     int retval = 1;
5597 
5598     int i;
5599 
5600     if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
5601         return (-1);
5602 
5603     incur = 0;
5604     inblk = 0;
5605     outcur = 0;
5606     inmax = *inlen;
5607     outmax = *tolen;
5608     nbintmp = 0;
5609 
5610     while (1) {
5611         if (incur >= inmax)
5612             break;
5613         cur = in[incur++];
5614         is_ignore = 0;
5615         if ((cur >= 'A') && (cur <= 'Z'))
5616             cur = cur - 'A';
5617         else if ((cur >= 'a') && (cur <= 'z'))
5618             cur = cur - 'a' + 26;
5619         else if ((cur >= '0') && (cur <= '9'))
5620             cur = cur - '0' + 52;
5621         else if (cur == '+')
5622             cur = 62;
5623         else if (cur == '/')
5624             cur = 63;
5625         else if (cur == '.')
5626             cur = 0;
5627         else if (cur == '=')    /*no op , end of the base64 stream */
5628             is_end = 1;
5629         else {
5630             is_ignore = 1;
5631             if (nbintmp == 0)
5632                 inblk = incur;
5633         }
5634 
5635         if (!is_ignore) {
5636             int nbouttmp = 3;
5637 
5638             int is_break = 0;
5639 
5640             if (is_end) {
5641                 if (nbintmp == 0)
5642                     break;
5643                 if ((nbintmp == 1) || (nbintmp == 2))
5644                     nbouttmp = 1;
5645                 else
5646                     nbouttmp = 2;
5647                 nbintmp = 3;
5648                 is_break = 1;
5649             }
5650             intmp[nbintmp++] = cur;
5651             /*
5652              * if intmp is full, push the 4byte sequence as a 3 byte
5653              * sequence out
5654              */
5655             if (nbintmp == 4) {
5656                 nbintmp = 0;
5657                 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
5658                 outtmp[1] =
5659                     ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
5660                 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
5661                 if (outcur + 3 >= outmax) {
5662                     retval = 2;
5663                     break;
5664                 }
5665 
5666                 for (i = 0; i < nbouttmp; i++)
5667                     to[outcur++] = outtmp[i];
5668                 inblk = incur;
5669             }
5670 
5671             if (is_break) {
5672                 retval = 0;
5673                 break;
5674             }
5675         }
5676     }
5677 
5678     *tolen = outcur;
5679     *inlen = inblk;
5680     return (retval);
5681 }
5682 
5683 /*
5684  * Test routine for the xmlBase64Decode function
5685  */
5686 #if 0
5687 int
5688 main(int argc, char **argv)
5689 {
5690     char *input = "  VW4 gcGV0        \n      aXQgdGVzdCAuCg== ";
5691 
5692     char output[100];
5693 
5694     char output2[100];
5695 
5696     char output3[100];
5697 
5698     unsigned long inlen = strlen(input);
5699 
5700     unsigned long outlen = 100;
5701 
5702     int ret;
5703 
5704     unsigned long cons, tmp, tmp2, prod;
5705 
5706     /*
5707      * Direct
5708      */
5709     ret = xmlBase64Decode(input, &inlen, output, &outlen);
5710 
5711     output[outlen] = 0;
5712     printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen,
5713            outlen, output)indent: Standard input:179: Error:Unmatched #endif
5714 ;
5715 
5716     /*
5717      * output chunking
5718      */
5719     cons = 0;
5720     prod = 0;
5721     while (cons < inlen) {
5722         tmp = 5;
5723         tmp2 = inlen - cons;
5724 
5725         printf("%ld %ld\n", cons, prod);
5726         ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
5727         cons += tmp2;
5728         prod += tmp;
5729         printf("%ld %ld\n", cons, prod);
5730     }
5731     output2[outlen] = 0;
5732     printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
5733            prod, output2);
5734 
5735     /*
5736      * input chunking
5737      */
5738     cons = 0;
5739     prod = 0;
5740     while (cons < inlen) {
5741         tmp = 100 - prod;
5742         tmp2 = inlen - cons;
5743         if (tmp2 > 5)
5744             tmp2 = 5;
5745 
5746         printf("%ld %ld\n", cons, prod);
5747         ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
5748         cons += tmp2;
5749         prod += tmp;
5750         printf("%ld %ld\n", cons, prod);
5751     }
5752     output3[outlen] = 0;
5753     printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
5754            prod, output3);
5755     return (0);
5756 
5757 }
5758 #endif
5759 #endif /* NOT_USED_YET */
5760 #define bottom_xmlreader
5761 #include "elfgcchack.h"
5762 #endif /* LIBXML_READER_ENABLED */
5763