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