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