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