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