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