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