blob: 254fd54454417d064ec7191b05e59d7e40a576c1 [file] [log] [blame]
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001/*
2 * xmlreader.c: implements the xmlTextReader streaming node API
3 *
Daniel Veillard67df8092002-12-16 22:04:11 +00004 * NOTE:
5 * XmlTextReader.Normalization Property won't be supported, since
6 * it makes the parser non compliant to the XML recommendation
7 *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00008 * See Copyright for the status of this software.
9 *
10 * daniel@veillard.com
11 */
12
13#define IN_LIBXML
14#include "libxml.h"
15
16#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24
25#include <libxml/xmlmemory.h>
26#include <libxml/xmlIO.h>
27#include <libxml/xmlreader.h>
28
29/* #define DEBUG_CALLBACKS */
30/* #define DEBUG_READER */
31
32/**
33 * TODO:
34 *
35 * macro to flag unimplemented blocks
36 */
37#define TODO \
38 xmlGenericError(xmlGenericErrorContext, \
39 "Unimplemented block at %s:%d\n", \
40 __FILE__, __LINE__);
41
42#ifdef DEBUG_READER
43#define DUMP_READER xmlTextReaderDebug(reader);
44#else
45#define DUMP_READER
46#endif
47
48/************************************************************************
49 * *
50 * The parser: maps the Text Reader API on top of the existing *
51 * parsing routines building a tree *
52 * *
53 ************************************************************************/
54
55#define XML_TEXTREADER_INPUT 1
56#define XML_TEXTREADER_CTXT 2
57
58typedef enum {
Daniel Veillard67df8092002-12-16 22:04:11 +000059 XML_TEXTREADER_MODE_INITIAL = 0,
60 XML_TEXTREADER_MODE_INTERACTIVE = 1,
61 XML_TEXTREADER_MODE_ERROR = 2,
62 XML_TEXTREADER_MODE_EOF =3,
63 XML_TEXTREADER_MODE_CLOSED = 4,
64 XML_TEXTREADER_MODE_READING = 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000065} xmlTextReaderMode;
66
67typedef enum {
68 XML_TEXTREADER_NONE = -1,
69 XML_TEXTREADER_START= 0,
70 XML_TEXTREADER_ELEMENT= 1,
71 XML_TEXTREADER_END= 2,
72 XML_TEXTREADER_EMPTY= 3,
73 XML_TEXTREADER_BACKTRACK= 4
74} xmlTextReaderState;
75
76struct _xmlTextReader {
77 int mode; /* the parsing mode */
78 int allocs; /* what structure were deallocated */
79 xmlTextReaderState state;
80 xmlParserCtxtPtr ctxt; /* the parser context */
81 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
82 xmlParserInputBufferPtr input; /* the input */
83 startElementSAXFunc startElement;/* initial SAX callbacks */
84 endElementSAXFunc endElement; /* idem */
85 unsigned int base; /* base of the segment in the input */
86 unsigned int cur; /* current position in the input */
87 xmlNodePtr node; /* current node */
Daniel Veillardda46d2d2002-12-15 23:36:49 +000088 xmlNodePtr curnode;/* current attribute node */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000089 int depth; /* depth of the current node */
Daniel Veillardbeb70bd2002-12-18 14:53:54 +000090 xmlNodePtr faketext;/* fake xmlNs chld */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000091};
92
93#ifdef DEBUG_READER
94static void
95xmlTextReaderDebug(xmlTextReaderPtr reader) {
96 if ((reader == NULL) || (reader->ctxt == NULL)) {
97 fprintf(stderr, "xmlTextReader NULL\n");
98 return;
99 }
100 fprintf(stderr, "xmlTextReader: state %d depth %d ",
101 reader->state, reader->depth);
102 if (reader->node == NULL) {
103 fprintf(stderr, "node = NULL\n");
104 } else {
105 fprintf(stderr, "node %s\n", reader->node->name);
106 }
107 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
108 reader->base, reader->cur, reader->ctxt->nodeNr);
109 if (reader->input->buffer == NULL) {
110 fprintf(stderr, "buffer is NULL\n");
111 } else {
112#ifdef LIBXML_DEBUG_ENABLED
113 xmlDebugDumpString(stderr,
114 &reader->input->buffer->content[reader->cur]);
115#endif
116 fprintf(stderr, "\n");
117 }
118}
119#endif
120
121/**
122 * xmlTextReaderStartElement:
123 * @ctx: the user data (XML parser context)
124 * @fullname: The element name, including namespace prefix
125 * @atts: An array of name/value attributes pairs, NULL terminated
126 *
127 * called when an opening tag has been processed.
128 */
129static void
130xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
131 const xmlChar **atts) {
132 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
133 xmlTextReaderPtr reader = ctxt->_private;
134
135#ifdef DEBUG_CALLBACKS
136 printf("xmlTextReaderStartElement(%s)\n", fullname);
137#endif
138 if ((reader != NULL) && (reader->startElement != NULL))
139 reader->startElement(ctx, fullname, atts);
140 reader->state = XML_TEXTREADER_ELEMENT;
141}
142
143/**
144 * xmlTextReaderEndElement:
145 * @ctx: the user data (XML parser context)
146 * @fullname: The element name, including namespace prefix
147 *
148 * called when an ending tag has been processed.
149 */
150static void
151xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
152 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
153 xmlTextReaderPtr reader = ctxt->_private;
154
155#ifdef DEBUG_CALLBACKS
156 printf("xmlTextReaderEndElement(%s)\n", fullname);
157#endif
158 if ((reader != NULL) && (reader->endElement != NULL))
159 reader->endElement(ctx, fullname);
160 if (reader->state == XML_TEXTREADER_ELEMENT)
161 reader->state = XML_TEXTREADER_EMPTY;
162 else
163 reader->state = XML_TEXTREADER_END;
164}
165
166/**
167 * xmlTextReaderPushData:
168 * @reader: the xmlTextReaderPtr used
169 *
170 * Push data down the progressive parser until a significant callback
171 * got raised.
172 *
173 * Returns -1 in case of failure, 0 otherwise
174 */
175static int
176xmlTextReaderPushData(xmlTextReaderPtr reader) {
177 unsigned int cur = reader->cur;
178 xmlBufferPtr inbuf;
179 int val;
180
181 if ((reader->input == NULL) || (reader->input->buffer == NULL))
182 return(-1);
183
184 reader->state = XML_TEXTREADER_NONE;
185 inbuf = reader->input->buffer;
186 while (reader->state == XML_TEXTREADER_NONE) {
187 if (cur >= inbuf->use) {
188 /*
189 * Refill the buffer unless we are at the end of the stream
190 */
191 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
192 val = xmlParserInputBufferRead(reader->input, 4096);
193 if (val <= 0) {
194 reader->mode = XML_TEXTREADER_MODE_EOF;
195 return(val);
196 }
197 } else
198 break;
199 }
200 if ((inbuf->content[cur] == '>') || (inbuf->content[cur] == '&')) {
201 cur = cur + 1;
202 val = xmlParseChunk(reader->ctxt,
203 (const char *) &inbuf->content[reader->cur],
204 cur - reader->cur, 0);
205 if (val != 0)
206 return(-1);
207 reader->cur = cur;
208 break;
209 } else {
210 cur = cur + 1;
211
212 /*
213 * One may have to force a flush at some point when parsing really
214 * large CDATA sections
215 */
216 if ((cur - reader->cur > 4096) && (reader->base == 0) &&
Daniel Veillard67df8092002-12-16 22:04:11 +0000217 (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000218 cur = cur + 1;
219 val = xmlParseChunk(reader->ctxt,
220 (const char *) &inbuf->content[reader->cur],
221 cur - reader->cur, 0);
222 if (val != 0)
223 return(-1);
224 reader->cur = cur;
225 }
226 }
227 }
228 /*
229 * Discard the consumed input when needed and possible
230 */
Daniel Veillard67df8092002-12-16 22:04:11 +0000231 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000232 if ((reader->cur >= 4096) && (reader->base == 0)) {
233 val = xmlBufferShrink(inbuf, cur);
234 if (val >= 0) {
235 reader->cur -= val;
236 }
237 }
238 }
239
240 /*
241 * At the end of the stream signal that the work is done to the Push
242 * parser.
243 */
244 if ((reader->mode == XML_TEXTREADER_MODE_EOF) && (cur >= inbuf->use)) {
245 val = xmlParseChunk(reader->ctxt,
246 (const char *) &inbuf->content[reader->cur], 0, 1);
247 }
248 return(0);
249}
250
251/**
252 * xmlTextReaderRead:
253 * @reader: the xmlTextReaderPtr used
254 *
255 * Moves the position of the current instance to the next node in
256 * the stream, exposing its properties.
257 *
258 * Returns 1 if the node was read successfully, 0 if there is no more
259 * nodes to read, or -1 in case of error
260 */
261int
262xmlTextReaderRead(xmlTextReaderPtr reader) {
263 int val, olddepth;
264 xmlTextReaderState oldstate;
265 xmlNodePtr oldnode;
266
267 if ((reader == NULL) || (reader->ctxt == NULL))
268 return(-1);
269 if (reader->ctxt->wellFormed != 1)
270 return(-1);
271
272#ifdef DEBUG_READER
273 fprintf(stderr, "\nREAD ");
274 DUMP_READER
275#endif
Daniel Veillard67df8092002-12-16 22:04:11 +0000276 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
277 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000278 /*
279 * Initial state
280 */
281 do {
282 val = xmlTextReaderPushData(reader);
283 if (val < 0)
284 return(-1);
285 } while ((reader->ctxt->node == NULL) &&
286 (reader->mode != XML_TEXTREADER_MODE_EOF));
287 if (reader->ctxt->node == NULL) {
288 if (reader->ctxt->myDoc != NULL)
289 reader->node = reader->ctxt->myDoc->children;
290 if (reader->node == NULL)
291 return(-1);
292 } else {
293 reader->node = reader->ctxt->node;
294 }
295 reader->depth = 1;
296 return(1);
297 }
298 oldstate = reader->state;
299 olddepth = reader->ctxt->nodeNr;
300 oldnode = reader->node;
301 /*
302 * If we are not backtracking on ancestors or examined nodes,
303 * that the parser didn't finished or that we arent at the end
304 * of stream, continue processing.
305 */
306 if (oldstate != XML_TEXTREADER_BACKTRACK) {
307 while (((reader->node->children == NULL) ||
308 (reader->node->type == XML_ENTITY_REF_NODE) ||
309 (reader->node->type == XML_DTD_NODE)) &&
310 (reader->node->next == NULL) &&
311 (reader->ctxt->nodeNr == olddepth) &&
312 (reader->ctxt->instate != XML_PARSER_EOF)) {
313 val = xmlTextReaderPushData(reader);
314 if (val < 0)
315 return(-1);
316 if (reader->node == NULL)
317 return(0);
318 }
319 if ((reader->node->children != NULL) &&
320 (reader->node->type != XML_ENTITY_REF_NODE) &&
321 (reader->node->type != XML_DTD_NODE)) {
322 reader->node = reader->node->children;
323 reader->depth++;
324 if ((reader->state != XML_TEXTREADER_ELEMENT) &&
325 (reader->state != XML_TEXTREADER_EMPTY))
326 reader->state = XML_TEXTREADER_ELEMENT;
327 DUMP_READER
328 return(1);
329 }
330 }
331 if (reader->node->next != NULL) {
332 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
333 (reader->node->type == XML_ELEMENT_NODE)) {
334 reader->state = XML_TEXTREADER_END;
335 DUMP_READER
336 return(1);
337 }
338 reader->node = reader->node->next;
339 reader->state = XML_TEXTREADER_ELEMENT;
340 DUMP_READER
341 /*
342 * Cleanup of the old node
343 */
344 if (oldnode->type != XML_DTD_NODE) {
345 xmlUnlinkNode(oldnode);
346 xmlFreeNode(oldnode);
347 }
348
349 return(1);
350 }
351 reader->node = reader->node->parent;
352 if ((reader->node == NULL) ||
353 (reader->node->type == XML_DOCUMENT_NODE) ||
354#ifdef LIBXML_DOCB_ENABLED
355 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
356#endif
357 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
358 reader->node = NULL;
359 reader->depth = 0;
360
361 /*
362 * Cleanup of the old node
363 */
364 if (oldnode->type != XML_DTD_NODE) {
365 xmlUnlinkNode(oldnode);
366 xmlFreeNode(oldnode);
367 }
368
369 return(0);
370 }
371 reader->depth--;
372 reader->state = XML_TEXTREADER_BACKTRACK;
373 DUMP_READER
374 return(1);
375}
376
Daniel Veillard67df8092002-12-16 22:04:11 +0000377/**
378 * xmlTextReaderReadState:
379 * @reader: the xmlTextReaderPtr used
380 *
381 * Gets the read state of the reader.
382 *
383 * Returns the state value, or -1 in case of error
384 */
385int
386xmlTextReaderReadState(xmlTextReaderPtr reader) {
387 if (reader == NULL)
388 return(-1);
389 return(reader->mode);
390}
391
392/**
393 * xmlTextReaderReadInnerXml:
394 * @reader: the xmlTextReaderPtr used
395 *
396 * Reads the contents of the current node, including child nodes and markup.
397 *
398 * Returns a string containing the XML content, or NULL if the current node
399 * is neither an element nor attribute, or has no child nodes. The
400 * string must be deallocated by the caller.
401 */
402xmlChar *
403xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) {
404 TODO
405 return(NULL);
406}
407
408/**
409 * xmlTextReaderReadOuterXml:
410 * @reader: the xmlTextReaderPtr used
411 *
412 * Reads the contents of the current node, including child nodes and markup.
413 *
414 * Returns a string containing the XML content, or NULL if the current node
415 * is neither an element nor attribute, or has no child nodes. The
416 * string must be deallocated by the caller.
417 */
418xmlChar *
419xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) {
420 TODO
421 return(NULL);
422}
423
424/**
425 * xmlTextReaderReadString:
426 * @reader: the xmlTextReaderPtr used
427 *
428 * Reads the contents of an element or a text node as a string.
429 *
430 * Returns a string containing the contents of the Element or Text node,
431 * or NULL if the reader is positioned on any other type of node.
432 * The string must be deallocated by the caller.
433 */
434xmlChar *
435xmlTextReaderReadString(xmlTextReaderPtr reader) {
436 TODO
437 return(NULL);
438}
439
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000440/**
441 * xmlTextReaderReadBase64:
442 * @reader: the xmlTextReaderPtr used
443 * @array: a byte array to store the content.
444 * @offset: the zero-based index into array where the method should
445 * begin to write.
446 * @len: the number of bytes to write.
447 *
448 * Reads and decodes the Base64 encoded contents of an element and
449 * stores the result in a byte buffer.
450 *
451 * Returns the number of bytes written to array, or zero if the current
452 * instance is not positioned on an element or -1 in case of error.
453 */
454int
455xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
456 int offset, int len) {
457 if ((reader == NULL) || (reader->ctxt == NULL))
458 return(-1);
459 if (reader->ctxt->wellFormed != 1)
460 return(-1);
461
462 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
463 return(0);
464 TODO
465 return(0);
466}
467
468/**
469 * xmlTextReaderReadBinHex:
470 * @reader: the xmlTextReaderPtr used
471 * @array: a byte array to store the content.
472 * @offset: the zero-based index into array where the method should
473 * begin to write.
474 * @len: the number of bytes to write.
475 *
476 * Reads and decodes the BinHex encoded contents of an element and
477 * stores the result in a byte buffer.
478 *
479 * Returns the number of bytes written to array, or zero if the current
480 * instance is not positioned on an element or -1 in case of error.
481 */
482int
483xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
484 int offset, int len) {
485 if ((reader == NULL) || (reader->ctxt == NULL))
486 return(-1);
487 if (reader->ctxt->wellFormed != 1)
488 return(-1);
489
490 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
491 return(0);
492 TODO
493 return(0);
494}
495
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000496/************************************************************************
497 * *
498 * Constructor and destructors *
499 * *
500 ************************************************************************/
501/**
502 * xmlNewTextReader:
503 * @input: the xmlParserInputBufferPtr used to read data
504 *
505 * Create an xmlTextReader structure fed with @input
506 *
507 * Returns the new xmlTextReaderPtr or NULL in case of error
508 */
509xmlTextReaderPtr
510xmlNewTextReader(xmlParserInputBufferPtr input) {
511 xmlTextReaderPtr ret;
512 int val;
513
514 if (input == NULL)
515 return(NULL);
516 ret = xmlMalloc(sizeof(xmlTextReader));
517 if (ret == NULL) {
518 xmlGenericError(xmlGenericErrorContext,
519 "xmlNewTextReader : malloc failed\n");
520 return(NULL);
521 }
522 memset(ret, 0, sizeof(xmlTextReader));
523 ret->input = input;
524 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
525 if (ret->sax == NULL) {
526 xmlFree(ret);
527 xmlGenericError(xmlGenericErrorContext,
528 "xmlNewTextReader : malloc failed\n");
529 return(NULL);
530 }
531 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
532 ret->startElement = ret->sax->startElement;
533 ret->sax->startElement = xmlTextReaderStartElement;
534 ret->endElement = ret->sax->endElement;
535 ret->sax->endElement = xmlTextReaderEndElement;
536
Daniel Veillard67df8092002-12-16 22:04:11 +0000537 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000538 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000539 ret->curnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000540 val = xmlParserInputBufferRead(input, 4);
541 if (val >= 4) {
542 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
543 (const char *) ret->input->buffer->content, 4, NULL);
544 ret->base = 0;
545 ret->cur = 4;
546 } else {
547 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, NULL);
548 ret->base = 0;
549 ret->cur = 0;
550 }
551 ret->ctxt->_private = ret;
552 ret->allocs = XML_TEXTREADER_CTXT;
553 return(ret);
554
555}
556
557/**
558 * xmlNewTextReaderFilename:
559 * @URI: the URI of the resource to process
560 *
561 * Create an xmlTextReader structure fed with the resource at @URI
562 *
563 * Returns the new xmlTextReaderPtr or NULL in case of error
564 */
565xmlTextReaderPtr
566xmlNewTextReaderFilename(const char *URI) {
567 xmlParserInputBufferPtr input;
568 xmlTextReaderPtr ret;
569
570 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
571 if (input == NULL)
572 return(NULL);
573 ret = xmlNewTextReader(input);
574 if (ret == NULL) {
575 xmlFreeParserInputBuffer(input);
576 return(NULL);
577 }
578 ret->allocs |= XML_TEXTREADER_INPUT;
579 return(ret);
580}
581
582/**
583 * xmlFreeTextReader:
584 * @reader: the xmlTextReaderPtr
585 *
586 * Deallocate all the resources associated to the reader
587 */
588void
589xmlFreeTextReader(xmlTextReaderPtr reader) {
590 if (reader == NULL)
591 return;
592 if (reader->ctxt != NULL) {
593 if (reader->ctxt->myDoc != NULL) {
594 xmlFreeDoc(reader->ctxt->myDoc);
595 reader->ctxt->myDoc = NULL;
596 }
597 if (reader->allocs & XML_TEXTREADER_CTXT)
598 xmlFreeParserCtxt(reader->ctxt);
599 }
600 if (reader->sax != NULL)
601 xmlFree(reader->sax);
602 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
603 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000604 if (reader->faketext != NULL) {
605 xmlFreeNode(reader->faketext);
606 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000607 xmlFree(reader);
608}
609
610/************************************************************************
611 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000612 * Methods for XmlTextReader *
613 * *
614 ************************************************************************/
615/**
616 * xmlTextReaderClose:
617 * @reader: the xmlTextReaderPtr used
618 *
619 * This method releases any resources allocated by the current instance
620 * changes the state to Closed and close any underlying input.
621 *
622 * Returns 0 or -1 in case of error
623 */
624int
625xmlTextReaderClose(xmlTextReaderPtr reader) {
626 if (reader == NULL)
627 return(-1);
628 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000629 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000630 reader->mode = XML_TEXTREADER_MODE_CLOSED;
631 if (reader->ctxt != NULL) {
632 if (reader->ctxt->myDoc != NULL) {
633 xmlFreeDoc(reader->ctxt->myDoc);
634 reader->ctxt->myDoc = NULL;
635 }
636 if (reader->allocs & XML_TEXTREADER_CTXT) {
637 xmlFreeParserCtxt(reader->ctxt);
638 reader->allocs -= XML_TEXTREADER_CTXT;
639 }
640 }
641 if (reader->sax != NULL) {
642 xmlFree(reader->sax);
643 reader->sax = NULL;
644 }
645 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
646 xmlFreeParserInputBuffer(reader->input);
647 reader->allocs -= XML_TEXTREADER_INPUT;
648 }
649 return(0);
650}
651
652/**
653 * xmlTextReaderGetAttributeNo:
654 * @reader: the xmlTextReaderPtr used
655 * @no: the zero-based index of the attribute relative to the containing element
656 *
657 * Provides the value of the attribute with the specified index relative
658 * to the containing element.
659 *
660 * Returns a string containing the value of the specified attribute, or NULL
661 * in case of error. The string must be deallocated by the caller.
662 */
663xmlChar *
664xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
665 xmlChar *ret;
666 int i;
667 xmlAttrPtr cur;
668 xmlNsPtr ns;
669
670 if (reader == NULL)
671 return(NULL);
672 if (reader->node == NULL)
673 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000674 if (reader->curnode != NULL)
675 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000676 /* TODO: handle the xmlDecl */
677 if (reader->node->type != XML_ELEMENT_NODE)
678 return(NULL);
679
680 ns = reader->node->nsDef;
681 for (i = 0;(i < no) && (ns != NULL);i++) {
682 ns = ns->next;
683 }
684 if (ns != NULL)
685 return(xmlStrdup(ns->href));
686
687 cur = reader->node->properties;
688 if (cur == NULL)
689 return(NULL);
690 for (;i < no;i++) {
691 cur = cur->next;
692 if (cur == NULL)
693 return(NULL);
694 }
695 /* TODO walk the DTD if present */
696
697 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
698 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
699 return(ret);
700}
701
702/**
703 * xmlTextReaderGetAttribute:
704 * @reader: the xmlTextReaderPtr used
705 * @name: the qualified name of the attribute.
706 *
707 * Provides the value of the attribute with the specified qualified name.
708 *
709 * Returns a string containing the value of the specified attribute, or NULL
710 * in case of error. The string must be deallocated by the caller.
711 */
712xmlChar *
713xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
714 xmlChar *prefix = NULL;
715 xmlChar *localname;
716 xmlNsPtr ns;
717 xmlChar *ret = NULL;
718
719 if ((reader == NULL) || (name == NULL))
720 return(NULL);
721 if (reader->node == NULL)
722 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000723 if (reader->curnode != NULL)
724 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000725
726 /* TODO: handle the xmlDecl */
727 if (reader->node->type != XML_ELEMENT_NODE)
728 return(NULL);
729
730 localname = xmlSplitQName2(name, &prefix);
731 if (localname == NULL)
732 return(xmlGetProp(reader->node, name));
733
734 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
735 if (ns != NULL)
736 ret = xmlGetNsProp(reader->node, localname, ns->href);
737
738 if (localname != NULL)
739 xmlFree(localname);
740 if (prefix != NULL)
741 xmlFree(prefix);
742 return(ret);
743}
744
745
746/**
747 * xmlTextReaderGetAttributeNs:
748 * @reader: the xmlTextReaderPtr used
749 * @localName: the local name of the attribute.
750 * @namespaceURI: the namespace URI of the attribute.
751 *
752 * Provides the value of the specified attribute
753 *
754 * Returns a string containing the value of the specified attribute, or NULL
755 * in case of error. The string must be deallocated by the caller.
756 */
757xmlChar *
758xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
759 const xmlChar *namespaceURI) {
760 if ((reader == NULL) || (localName == NULL))
761 return(NULL);
762 if (reader->node == NULL)
763 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000764 if (reader->curnode != NULL)
765 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000766
767 /* TODO: handle the xmlDecl */
768 if (reader->node->type != XML_ELEMENT_NODE)
769 return(NULL);
770
771 return(xmlGetNsProp(reader->node, localName, namespaceURI));
772}
773
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000774/**
775 * xmlTextReaderGetRemainder:
776 * @reader: the xmlTextReaderPtr used
777 *
778 * Method to get the remainder of the buffered XML. this method stops the
779 * parser, set its state to End Of File and return the input stream with
780 * what is left that the parser did not use.
781 *
782 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
783 * in case of error.
784 */
785xmlParserInputBufferPtr
786xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
787 xmlParserInputBufferPtr ret = NULL;
788
789 if (reader == NULL)
790 return(NULL);
791 if (reader->node == NULL)
792 return(NULL);
793
794 reader->node = NULL;
795 reader->curnode = NULL;
796 reader->mode = XML_TEXTREADER_MODE_EOF;
797 if (reader->ctxt != NULL) {
798 if (reader->ctxt->myDoc != NULL) {
799 xmlFreeDoc(reader->ctxt->myDoc);
800 reader->ctxt->myDoc = NULL;
801 }
802 if (reader->allocs & XML_TEXTREADER_CTXT) {
803 xmlFreeParserCtxt(reader->ctxt);
804 reader->allocs -= XML_TEXTREADER_CTXT;
805 }
806 }
807 if (reader->sax != NULL) {
808 xmlFree(reader->sax);
809 reader->sax = NULL;
810 }
811 if (reader->allocs & XML_TEXTREADER_INPUT) {
812 ret = reader->input;
813 reader->allocs -= XML_TEXTREADER_INPUT;
814 } else {
815 /*
816 * Hum, one may need to duplicate the data structure because
817 * without reference counting the input may be freed twice:
818 * - by the layer which allocated it.
819 * - by the layer to which would have been returned to.
820 */
821 TODO
822 return(NULL);
823 }
824 return(ret);
825}
826
827/**
828 * xmlTextReaderLookupNamespace:
829 * @reader: the xmlTextReaderPtr used
830 * @prefix: the prefix whose namespace URI is to be resolved. To return
831 * the default namespace, specify NULL
832 *
833 * Resolves a namespace prefix in the scope of the current element.
834 *
835 * Returns a string containing the namespace URI to which the prefix maps
836 * or NULL in case of error. The string must be deallocated by the caller.
837 */
838xmlChar *
839xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
840 xmlNsPtr ns;
841
842 if (reader == NULL)
843 return(NULL);
844 if (reader->node == NULL)
845 return(NULL);
846
847 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
848 if (ns == NULL)
849 return(NULL);
850 return(xmlStrdup(ns->href));
851}
852
853/**
854 * xmlTextReaderMoveToAttributeNo:
855 * @reader: the xmlTextReaderPtr used
856 * @no: the zero-based index of the attribute relative to the containing
857 * element.
858 *
859 * Moves the position of the current instance to the attribute with
860 * the specified index relative to the containing element.
861 *
862 * Returns 1 in case of success, -1 in case of error, 0 if not found
863 */
864int
865xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
866 int i;
867 xmlAttrPtr cur;
868 xmlNsPtr ns;
869
870 if (reader == NULL)
871 return(-1);
872 if (reader->node == NULL)
873 return(-1);
874 /* TODO: handle the xmlDecl */
875 if (reader->node->type != XML_ELEMENT_NODE)
876 return(-1);
877
878 reader->curnode = NULL;
879
880 ns = reader->node->nsDef;
881 for (i = 0;(i < no) && (ns != NULL);i++) {
882 ns = ns->next;
883 }
884 if (ns != NULL) {
885 reader->curnode = (xmlNodePtr) ns;
886 return(1);
887 }
888
889 cur = reader->node->properties;
890 if (cur == NULL)
891 return(0);
892 for (;i < no;i++) {
893 cur = cur->next;
894 if (cur == NULL)
895 return(0);
896 }
897 /* TODO walk the DTD if present */
898
899 reader->curnode = (xmlNodePtr) cur;
900 return(1);
901}
902
903/**
904 * xmlTextReaderMoveToAttribute:
905 * @reader: the xmlTextReaderPtr used
906 * @name: the qualified name of the attribute.
907 *
908 * Moves the position of the current instance to the attribute with
909 * the specified qualified name.
910 *
911 * Returns 1 in case of success, -1 in case of error, 0 if not found
912 */
913int
914xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
915 xmlChar *prefix = NULL;
916 xmlChar *localname;
917 xmlNsPtr ns;
918 xmlAttrPtr prop;
919
920 if ((reader == NULL) || (name == NULL))
921 return(-1);
922 if (reader->node == NULL)
923 return(-1);
924
925 /* TODO: handle the xmlDecl */
926 if (reader->node->type != XML_ELEMENT_NODE)
927 return(0);
928
929 localname = xmlSplitQName2(name, &prefix);
930 if (localname == NULL) {
931 /*
932 * Namespace default decl
933 */
934 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
935 ns = reader->node->nsDef;
936 while (ns != NULL) {
937 if (ns->prefix == NULL) {
938 reader->curnode = (xmlNodePtr) ns;
939 return(1);
940 }
941 ns = ns->next;
942 }
943 return(0);
944 }
945
946 prop = reader->node->properties;
947 while (prop != NULL) {
948 /*
949 * One need to have
950 * - same attribute names
951 * - and the attribute carrying that namespace
952 */
953 if ((xmlStrEqual(prop->name, name)) &&
954 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
955 reader->curnode = (xmlNodePtr) prop;
956 return(1);
957 }
958 prop = prop->next;
959 }
960 return(0);
961 }
962
963 /*
964 * Namespace default decl
965 */
966 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
967 ns = reader->node->nsDef;
968 while (ns != NULL) {
969 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
970 reader->curnode = (xmlNodePtr) ns;
971 goto found;
972 }
973 ns = ns->next;
974 }
975 goto not_found;
976 }
977 prop = reader->node->properties;
978 while (prop != NULL) {
979 /*
980 * One need to have
981 * - same attribute names
982 * - and the attribute carrying that namespace
983 */
984 if ((xmlStrEqual(prop->name, localname)) &&
985 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
986 reader->curnode = (xmlNodePtr) prop;
987 goto found;
988 }
989 prop = prop->next;
990 }
991not_found:
992 if (localname != NULL)
993 xmlFree(localname);
994 if (prefix != NULL)
995 xmlFree(prefix);
996 return(0);
997
998found:
999 if (localname != NULL)
1000 xmlFree(localname);
1001 if (prefix != NULL)
1002 xmlFree(prefix);
1003 return(1);
1004}
1005
1006/**
1007 * xmlTextReaderMoveToAttributeNs:
1008 * @reader: the xmlTextReaderPtr used
1009 * @localName: the local name of the attribute.
1010 * @namespaceURI: the namespace URI of the attribute.
1011 *
1012 * Moves the position of the current instance to the attribute with the
1013 * specified local name and namespace URI.
1014 *
1015 * Returns 1 in case of success, -1 in case of error, 0 if not found
1016 */
1017int
1018xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1019 const xmlChar *localName, const xmlChar *namespaceURI) {
1020 xmlAttrPtr prop;
1021 xmlNodePtr node;
1022
1023 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1024 return(-1);
1025 if (reader->node == NULL)
1026 return(-1);
1027 if (reader->node->type != XML_ELEMENT_NODE)
1028 return(0);
1029 node = reader->node;
1030
1031 /*
1032 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1033 * namespace name associated to "xmlns"
1034 */
1035 prop = node->properties;
1036 while (prop != NULL) {
1037 /*
1038 * One need to have
1039 * - same attribute names
1040 * - and the attribute carrying that namespace
1041 */
1042 if (xmlStrEqual(prop->name, localName) &&
1043 ((prop->ns != NULL) &&
1044 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1045 reader->curnode = (xmlNodePtr) prop;
1046 return(1);
1047 }
1048 prop = prop->next;
1049 }
1050 return(0);
1051}
1052
1053/**
1054 * xmlTextReaderMoveToFirstAttribute:
1055 * @reader: the xmlTextReaderPtr used
1056 *
1057 * Moves the position of the current instance to the first attribute
1058 * associated with the current node.
1059 *
1060 * Returns 1 in case of success, -1 in case of error, 0 if not found
1061 */
1062int
1063xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1064 if (reader == NULL)
1065 return(-1);
1066 if (reader->node == NULL)
1067 return(-1);
1068 if (reader->node->type != XML_ELEMENT_NODE)
1069 return(0);
1070
1071 if (reader->node->nsDef != NULL) {
1072 reader->curnode = (xmlNodePtr) reader->node->nsDef;
1073 return(1);
1074 }
1075 if (reader->node->properties != NULL) {
1076 reader->curnode = (xmlNodePtr) reader->node->properties;
1077 return(1);
1078 }
1079 return(0);
1080}
1081
1082/**
1083 * xmlTextReaderMoveToNextAttribute:
1084 * @reader: the xmlTextReaderPtr used
1085 *
1086 * Moves the position of the current instance to the next attribute
1087 * associated with the current node.
1088 *
1089 * Returns 1 in case of success, -1 in case of error, 0 if not found
1090 */
1091int
1092xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1093 if (reader == NULL)
1094 return(-1);
1095 if (reader->node == NULL)
1096 return(-1);
1097 if (reader->node->type != XML_ELEMENT_NODE)
1098 return(0);
1099 if (reader->curnode == NULL)
1100 return(xmlTextReaderMoveToFirstAttribute(reader));
1101
1102 if (reader->curnode->type == XML_NAMESPACE_DECL) {
1103 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1104 if (ns->next != NULL) {
1105 reader->curnode = (xmlNodePtr) ns->next;
1106 return(1);
1107 }
1108 if (reader->node->properties != NULL) {
1109 reader->curnode = (xmlNodePtr) reader->node->properties;
1110 return(1);
1111 }
1112 return(0);
1113 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1114 (reader->curnode->next != NULL)) {
1115 reader->curnode = reader->curnode->next;
1116 return(1);
1117 }
1118 return(0);
1119}
1120
1121/**
1122 * xmlTextReaderMoveToElement:
1123 * @reader: the xmlTextReaderPtr used
1124 *
1125 * Moves the position of the current instance to the node that
1126 * contains the current Attribute node.
1127 *
1128 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1129 */
1130int
1131xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
1132 if (reader == NULL)
1133 return(-1);
1134 if (reader->node == NULL)
1135 return(-1);
1136 if (reader->node->type != XML_ELEMENT_NODE)
1137 return(0);
1138 if (reader->curnode != NULL) {
1139 reader->curnode = NULL;
1140 return(1);
1141 }
1142 return(0);
1143}
1144
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001145/**
1146 * xmlTextReaderReadAttributeValue:
1147 * @reader: the xmlTextReaderPtr used
1148 *
1149 * Parses an attribute value into one or more Text and EntityReference nodes.
1150 *
1151 * Returns 1 in case of success, 0 if the reader was not positionned on an
1152 * ttribute node or all the attribute values have been read, or -1
1153 * in case of error.
1154 */
1155int
1156xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1157 if (reader == NULL)
1158 return(-1);
1159 if (reader->node == NULL)
1160 return(-1);
1161 if (reader->curnode == NULL)
1162 return(0);
1163 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1164 if (reader->curnode->children == NULL)
1165 return(0);
1166 reader->curnode = reader->curnode->children;
1167 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1168 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1169
1170 if (reader->faketext == NULL) {
1171 reader->faketext = xmlNewDocText(reader->node->doc,
1172 ns->href);
1173 } else {
1174 if (reader->faketext->content != NULL)
1175 xmlFree(reader->faketext->content);
1176 reader->faketext->content = xmlStrdup(ns->href);
1177 }
1178 reader->curnode = reader->faketext;
1179 } else {
1180 if (reader->curnode->next == NULL)
1181 return(0);
1182 reader->curnode = reader->curnode->next;
1183 }
1184 return(1);
1185}
1186
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001187/************************************************************************
1188 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001189 * Acces API to the current node *
1190 * *
1191 ************************************************************************/
1192/**
1193 * xmlTextReaderAttributeCount:
1194 * @reader: the xmlTextReaderPtr used
1195 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001196 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001197 *
1198 * Returns 0 i no attributes, -1 in case of error or the attribute count
1199 */
1200int
1201xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1202 int ret;
1203 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00001204 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001205 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001206
1207 if (reader == NULL)
1208 return(-1);
1209 if (reader->node == NULL)
1210 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001211
1212 if (reader->curnode != NULL)
1213 node = reader->curnode;
1214 else
1215 node = reader->node;
1216
1217 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001218 return(0);
1219 if ((reader->state == XML_TEXTREADER_END) ||
1220 (reader->state == XML_TEXTREADER_BACKTRACK))
1221 return(0);
1222 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001223 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001224 while (attr != NULL) {
1225 ret++;
1226 attr = attr->next;
1227 }
Daniel Veillard67df8092002-12-16 22:04:11 +00001228 ns = node->nsDef;
1229 while (ns != NULL) {
1230 ret++;
1231 ns = ns->next;
1232 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001233 return(ret);
1234}
1235
1236/**
1237 * xmlTextReaderNodeType:
1238 * @reader: the xmlTextReaderPtr used
1239 *
1240 * Get the node type of the current node
1241 * Reference:
1242 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1243 *
1244 * Returns the xmlNodeType of the current node or -1 in case of error
1245 */
1246int
1247xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001248 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001249 if (reader == NULL)
1250 return(-1);
1251 if (reader->node == NULL)
1252 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001253 if (reader->curnode != NULL)
1254 node = reader->curnode;
1255 else
1256 node = reader->node;
1257 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001258 case XML_ELEMENT_NODE:
1259 if ((reader->state == XML_TEXTREADER_END) ||
1260 (reader->state == XML_TEXTREADER_BACKTRACK))
1261 return(15);
1262 return(1);
1263 case XML_ATTRIBUTE_NODE:
1264 return(2);
1265 case XML_TEXT_NODE:
1266 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1267 case XML_CDATA_SECTION_NODE:
1268 return(4);
1269 case XML_ENTITY_REF_NODE:
1270 return(5);
1271 case XML_ENTITY_NODE:
1272 return(6);
1273 case XML_PI_NODE:
1274 return(7);
1275 case XML_COMMENT_NODE:
1276 return(8);
1277 case XML_DOCUMENT_NODE:
1278 case XML_HTML_DOCUMENT_NODE:
1279#ifdef LIBXML_DOCB_ENABLED
1280 case XML_DOCB_DOCUMENT_NODE:
1281#endif
1282 return(9);
1283 case XML_DOCUMENT_FRAG_NODE:
1284 return(11);
1285 case XML_NOTATION_NODE:
1286 return(12);
1287 case XML_DOCUMENT_TYPE_NODE:
1288 case XML_DTD_NODE:
1289 return(10);
1290
1291 case XML_ELEMENT_DECL:
1292 case XML_ATTRIBUTE_DECL:
1293 case XML_ENTITY_DECL:
1294 case XML_NAMESPACE_DECL:
1295 case XML_XINCLUDE_START:
1296 case XML_XINCLUDE_END:
1297 return(0);
1298 }
1299 return(-1);
1300}
1301
1302/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001303 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001304 * @reader: the xmlTextReaderPtr used
1305 *
1306 * Check if the current node is empty
1307 *
1308 * Returns 1 if empty, 0 if not and -1 in case of error
1309 */
1310int
1311xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1312 if ((reader == NULL) || (reader->node == NULL))
1313 return(-1);
1314 if (reader->node->children != NULL)
1315 return(0);
1316 if ((reader->state == XML_TEXTREADER_EMPTY) ||
1317 (reader->state == XML_TEXTREADER_BACKTRACK))
1318 return(1);
1319 return(0);
1320}
1321
1322/**
1323 * xmlTextReaderLocalName:
1324 * @reader: the xmlTextReaderPtr used
1325 *
1326 * The local name of the node.
1327 *
1328 * Returns the local name or NULL if not available
1329 */
1330xmlChar *
1331xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001332 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001333 if ((reader == NULL) || (reader->node == NULL))
1334 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001335 if (reader->curnode != NULL)
1336 node = reader->curnode;
1337 else
1338 node = reader->node;
1339 if (node->type == XML_NAMESPACE_DECL) {
1340 xmlNsPtr ns = (xmlNsPtr) node;
1341 if (ns->prefix == NULL)
1342 return(xmlStrdup(BAD_CAST "xmlns"));
1343 else
1344 return(xmlStrdup(ns->prefix));
1345 }
1346 if ((node->type != XML_ELEMENT_NODE) &&
1347 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001348 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001349 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001350}
1351
1352/**
1353 * xmlTextReaderName:
1354 * @reader: the xmlTextReaderPtr used
1355 *
1356 * The qualified name of the node, equal to Prefix :LocalName.
1357 *
1358 * Returns the local name or NULL if not available
1359 */
1360xmlChar *
1361xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001362 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001363 xmlChar *ret;
1364
1365 if ((reader == NULL) || (reader->node == NULL))
1366 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001367 if (reader->curnode != NULL)
1368 node = reader->curnode;
1369 else
1370 node = reader->node;
1371 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001372 case XML_ELEMENT_NODE:
1373 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001374 if ((node->ns == NULL) ||
1375 (node->ns->prefix == NULL))
1376 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001377
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001378 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001379 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001380 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001381 return(ret);
1382 case XML_TEXT_NODE:
1383 return(xmlStrdup(BAD_CAST "#text"));
1384 case XML_CDATA_SECTION_NODE:
1385 return(xmlStrdup(BAD_CAST "#cdata-section"));
1386 case XML_ENTITY_NODE:
1387 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001388 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001389 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001390 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001391 case XML_COMMENT_NODE:
1392 return(xmlStrdup(BAD_CAST "#comment"));
1393 case XML_DOCUMENT_NODE:
1394 case XML_HTML_DOCUMENT_NODE:
1395#ifdef LIBXML_DOCB_ENABLED
1396 case XML_DOCB_DOCUMENT_NODE:
1397#endif
1398 return(xmlStrdup(BAD_CAST "#document"));
1399 case XML_DOCUMENT_FRAG_NODE:
1400 return(xmlStrdup(BAD_CAST "#document-fragment"));
1401 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001402 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001403 case XML_DOCUMENT_TYPE_NODE:
1404 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001405 return(xmlStrdup(node->name));
1406 case XML_NAMESPACE_DECL: {
1407 xmlNsPtr ns = (xmlNsPtr) node;
1408
1409 ret = xmlStrdup(BAD_CAST "xmlns");
1410 if (ns->prefix == NULL)
1411 return(ret);
1412 ret = xmlStrcat(ret, BAD_CAST ":");
1413 ret = xmlStrcat(ret, ns->prefix);
1414 return(ret);
1415 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001416
1417 case XML_ELEMENT_DECL:
1418 case XML_ATTRIBUTE_DECL:
1419 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001420 case XML_XINCLUDE_START:
1421 case XML_XINCLUDE_END:
1422 return(NULL);
1423 }
1424 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001425}
1426
1427/**
1428 * xmlTextReaderPrefix:
1429 * @reader: the xmlTextReaderPtr used
1430 *
1431 * A shorthand reference to the namespace associated with the node.
1432 *
1433 * Returns the prefix or NULL if not available
1434 */
1435xmlChar *
1436xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001437 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001438 if ((reader == NULL) || (reader->node == NULL))
1439 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001440 if (reader->curnode != NULL)
1441 node = reader->curnode;
1442 else
1443 node = reader->node;
1444 if (node->type == XML_NAMESPACE_DECL) {
1445 xmlNsPtr ns = (xmlNsPtr) node;
1446 if (ns->prefix == NULL)
1447 return(NULL);
1448 return(xmlStrdup(BAD_CAST "xmlns"));
1449 }
1450 if ((node->type != XML_ELEMENT_NODE) &&
1451 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001452 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001453 if ((node->ns != NULL) || (node->ns->prefix != NULL))
1454 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001455 return(NULL);
1456}
1457
1458/**
1459 * xmlTextReaderNamespaceUri:
1460 * @reader: the xmlTextReaderPtr used
1461 *
1462 * The URI defining the namespace associated with the node.
1463 *
1464 * Returns the namespace URI or NULL if not available
1465 */
1466xmlChar *
1467xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001468 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001469 if ((reader == NULL) || (reader->node == NULL))
1470 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001471 if (reader->curnode != NULL)
1472 node = reader->curnode;
1473 else
1474 node = reader->node;
1475 if (node->type == XML_NAMESPACE_DECL) {
1476 xmlNsPtr ns = (xmlNsPtr) node;
1477 return(xmlStrdup(ns->href));
1478 }
1479 if ((node->type != XML_ELEMENT_NODE) &&
1480 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001481 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001482 if (node->ns != NULL)
1483 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001484 return(NULL);
1485}
1486
1487/**
1488 * xmlTextReaderBaseUri:
1489 * @reader: the xmlTextReaderPtr used
1490 *
1491 * The base URI of the node.
1492 *
1493 * Returns the base URI or NULL if not available
1494 */
1495xmlChar *
1496xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
1497 if ((reader == NULL) || (reader->node == NULL))
1498 return(NULL);
1499 return(xmlNodeGetBase(NULL, reader->node));
1500}
1501
1502/**
1503 * xmlTextReaderDepth:
1504 * @reader: the xmlTextReaderPtr used
1505 *
1506 * The depth of the node in the tree.
1507 *
1508 * Returns the depth or -1 in case of error
1509 */
1510int
1511xmlTextReaderDepth(xmlTextReaderPtr reader) {
1512 if (reader == NULL)
1513 return(-1);
1514 if (reader->node == NULL)
1515 return(0);
1516
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001517 if (reader->curnode != NULL) {
1518 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
1519 (reader->curnode->type == XML_NAMESPACE_DECL))
1520 return(reader->depth + 1);
1521 return(reader->depth + 2);
1522 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001523 return(reader->depth);
1524}
1525
1526/**
1527 * xmlTextReaderHasAttributes:
1528 * @reader: the xmlTextReaderPtr used
1529 *
1530 * Whether the node has attributes.
1531 *
1532 * Returns 1 if true, 0 if false, and -1 in case or error
1533 */
1534int
1535xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001536 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001537 if (reader == NULL)
1538 return(-1);
1539 if (reader->node == NULL)
1540 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001541 if (reader->curnode != NULL)
1542 node = reader->curnode;
1543 else
1544 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001545
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001546 if ((node->type == XML_ELEMENT_NODE) &&
1547 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001548 return(1);
1549 /* TODO: handle the xmlDecl */
1550 return(0);
1551}
1552
1553/**
1554 * xmlTextReaderHasValue:
1555 * @reader: the xmlTextReaderPtr used
1556 *
1557 * Whether the node can have a text value.
1558 *
1559 * Returns 1 if true, 0 if false, and -1 in case or error
1560 */
1561int
1562xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001563 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001564 if (reader == NULL)
1565 return(-1);
1566 if (reader->node == NULL)
1567 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001568 if (reader->curnode != NULL)
1569 node = reader->curnode;
1570 else
1571 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001572
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001573 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001574 case XML_ATTRIBUTE_NODE:
1575 case XML_TEXT_NODE:
1576 case XML_CDATA_SECTION_NODE:
1577 case XML_PI_NODE:
1578 case XML_COMMENT_NODE:
1579 return(1);
1580 default:
1581 return(0);
1582 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001583 return(0);
1584}
1585
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001586/**
1587 * xmlTextReaderValue:
1588 * @reader: the xmlTextReaderPtr used
1589 *
1590 * Provides the text value of the node if present
1591 *
1592 * Returns the string or NULL if not available. The retsult must be deallocated
1593 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001594 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001595xmlChar *
1596xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001597 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001598 if (reader == NULL)
1599 return(NULL);
1600 if (reader->node == NULL)
1601 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001602 if (reader->curnode != NULL)
1603 node = reader->curnode;
1604 else
1605 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001606
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001607 switch (node->type) {
1608 case XML_NAMESPACE_DECL:
1609 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001610 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001611 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001612
1613 if (attr->parent != NULL)
1614 return (xmlNodeListGetString
1615 (attr->parent->doc, attr->children, 1));
1616 else
1617 return (xmlNodeListGetString(NULL, attr->children, 1));
1618 break;
1619 }
1620 case XML_TEXT_NODE:
1621 case XML_CDATA_SECTION_NODE:
1622 case XML_PI_NODE:
1623 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001624 if (node->content != NULL)
1625 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001626 default:
1627 return(NULL);
1628 }
1629 return(NULL);
1630}
1631
1632/**
1633 * xmlTextReaderIsDefault:
1634 * @reader: the xmlTextReaderPtr used
1635 *
1636 * Whether an Attribute node was generated from the default value
1637 * defined in the DTD or schema.
1638 *
1639 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
1640 */
1641int
1642xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
1643 if (reader == NULL)
1644 return(-1);
1645 return(0);
1646}
1647
1648/**
1649 * xmlTextReaderQuoteChar:
1650 * @reader: the xmlTextReaderPtr used
1651 *
1652 * The quotation mark character used to enclose the value of an attribute.
1653 *
1654 * Returns " or ' and -1 in case of error
1655 */
1656int
1657xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
1658 if (reader == NULL)
1659 return(-1);
1660 /* TODO maybe lookup the attribute value for " first */
1661 return((int) '"');
1662}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001663
1664/**
1665 * xmlTextReaderXmlLang:
1666 * @reader: the xmlTextReaderPtr used
1667 *
1668 * The xml:lang scope within which the node resides.
1669 *
1670 * Returns the xml:lang value or NULL if none exists.
1671 */
1672xmlChar *
1673xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
1674 if (reader == NULL)
1675 return(NULL);
1676 if (reader->node == NULL)
1677 return(NULL);
1678 return(xmlNodeGetLang(reader->node));
1679}
1680
Daniel Veillard67df8092002-12-16 22:04:11 +00001681/**
1682 * xmlTextReaderNormalization:
1683 * @reader: the xmlTextReaderPtr used
1684 *
1685 * The value indicating whether to normalize white space and attribute values.
1686 * Since attribute value and end of line normalizations are a MUST in the XML
1687 * specification only the value true is accepted. The broken bahaviour of
1688 * accepting out of range character entities like &#0; is of course not
1689 * supported either.
1690 *
1691 * Returns 1 or -1 in case of error.
1692 */
1693int
1694xmlTextReaderNormalization(xmlTextReaderPtr reader) {
1695 if (reader == NULL)
1696 return(-1);
1697 return(1);
1698}
1699
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001700/************************************************************************
1701 * *
1702 * Extensions to the base APIs *
1703 * *
1704 ************************************************************************/
1705
1706/**
1707 * xmlTextReaderSetParserProp:
1708 * @reader: the xmlTextReaderPtr used
1709 * @prop: the xmlParserProperties to set
1710 * @value: usually 0 or 1 to (de)activate it
1711 *
1712 * Change the parser processing behaviour by changing some of its internal
1713 * properties. Note that some properties can only be changed before any
1714 * read has been done.
1715 *
1716 * Returns 0 if the call was successful, or -1 in case of error
1717 */
1718int
1719xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
1720 xmlParserProperties p = (xmlParserProperties) prop;
1721 xmlParserCtxtPtr ctxt;
1722
1723 if ((reader == NULL) || (reader->ctxt == NULL))
1724 return(-1);
1725 ctxt = reader->ctxt;
1726
1727 switch (p) {
1728 case XML_PARSER_LOADDTD:
1729 if (value != 0) {
1730 if (ctxt->loadsubset == 0) {
1731 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
1732 return(-1);
1733 ctxt->loadsubset = XML_DETECT_IDS;
1734 }
1735 } else {
1736 ctxt->loadsubset = 0;
1737 }
1738 return(0);
1739 case XML_PARSER_DEFAULTATTRS:
1740 if (value != 0) {
1741 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
1742 } else {
1743 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1744 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
1745 }
1746 return(0);
1747 case XML_PARSER_VALIDATE:
1748 if (value != 0) {
1749 ctxt->validate = 1;
1750 } else {
1751 ctxt->validate = 0;
1752 }
1753 return(0);
1754 }
1755 return(-1);
1756}
1757
1758/**
1759 * xmlTextReaderGetParserProp:
1760 * @reader: the xmlTextReaderPtr used
1761 * @prop: the xmlParserProperties to get
1762 *
1763 * Read the parser internal property.
1764 *
1765 * Returns the value, usually 0 or 1, or -1 in case of error.
1766 */
1767int
1768xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
1769 xmlParserProperties p = (xmlParserProperties) prop;
1770 xmlParserCtxtPtr ctxt;
1771
1772 if ((reader == NULL) || (reader->ctxt == NULL))
1773 return(-1);
1774 ctxt = reader->ctxt;
1775
1776 switch (p) {
1777 case XML_PARSER_LOADDTD:
1778 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
1779 return(1);
1780 return(0);
1781 case XML_PARSER_DEFAULTATTRS:
1782 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1783 return(1);
1784 return(0);
1785 case XML_PARSER_VALIDATE:
1786 return(ctxt->validate);
1787 }
1788 return(-1);
1789}
1790
1791/************************************************************************
1792 * *
1793 * Utilities *
1794 * *
1795 ************************************************************************/
1796/**
1797 * xmlBase64Decode:
1798 * @in: the input buffer
1799 * @inlen: the size of the input (in), the size read from it (out)
1800 * @to: the output buffer
1801 * @tolen: the size of the output (in), the size written to (out)
1802 *
1803 * Base64 decoder, reads from @in and save in @to
1804 *
1805 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
1806 * 2 if there wasn't enough space on the output or -1 in case of error.
1807 */
1808static int
1809xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
1810 unsigned char *to, unsigned long *tolen) {
1811 unsigned long incur; /* current index in in[] */
1812 unsigned long inblk; /* last block index in in[] */
1813 unsigned long outcur; /* current index in out[] */
1814 unsigned long inmax; /* size of in[] */
1815 unsigned long outmax; /* size of out[] */
1816 unsigned char cur; /* the current value read from in[] */
1817 unsigned char intmp[3], outtmp[4]; /* temporary buffers for the convert */
1818 int nbintmp; /* number of byte in intmp[] */
1819 int is_ignore; /* cur should be ignored */
1820 int is_end = 0; /* the end of the base64 was found */
1821 int retval = 1;
1822 int i;
1823
1824 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
1825 return(-1);
1826
1827 incur = 0;
1828 inblk = 0;
1829 outcur = 0;
1830 inmax = *inlen;
1831 outmax = *tolen;
1832 nbintmp = 0;
1833
1834 while (1) {
1835 if (incur >= inmax)
1836 break;
1837 cur = in[incur++];
1838 is_ignore = 0;
1839 if ((cur >= 'A') && (cur <= 'Z'))
1840 cur = cur - 'A';
1841 else if ((cur >= 'a') && (cur <= 'z'))
1842 cur = cur - 'a' + 26;
1843 else if ((cur >= '0') && (cur <= '9'))
1844 cur = cur - '0' + 52;
1845 else if (cur == '+')
1846 cur = 62;
1847 else if (cur == '/')
1848 cur = 63;
1849 else if (cur == '.')
1850 cur = 0;
1851 else if (cur == '=') /*no op , end of the base64 stream */
1852 is_end = 1;
1853 else {
1854 is_ignore = 1;
1855 if (nbintmp == 0)
1856 inblk = incur;
1857 }
1858
1859 if (!is_ignore) {
1860 int nbouttmp = 3;
1861 int is_break = 0;
1862
1863 if (is_end) {
1864 if (nbintmp == 0)
1865 break;
1866 if ((nbintmp == 1) || (nbintmp == 2))
1867 nbouttmp = 1;
1868 else
1869 nbouttmp = 2;
1870 nbintmp = 3;
1871 is_break = 1;
1872 }
1873 intmp[nbintmp++] = cur;
1874 /*
1875 * if intmp is full, push the 4byte sequence as a 3 byte
1876 * sequence out
1877 */
1878 if (nbintmp == 4) {
1879 nbintmp = 0;
1880 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
1881 outtmp[1] =
1882 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
1883 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
1884 if (outcur + 3 >= outmax) {
1885 retval = 2;
1886 break;
1887 }
1888
1889 for (i = 0; i < nbouttmp; i++)
1890 to[outcur++] = outtmp[i];
1891 inblk = incur;
1892 }
1893
1894 if (is_break) {
1895 retval = 0;
1896 break;
1897 }
1898 }
1899 }
1900
1901 *tolen = outcur;
1902 *inlen = inblk;
1903 return (retval);
1904}
1905
1906/*
1907 * Test routine for the xmlBase64Decode function
1908 */
1909#if 0
1910int main(int argc, char **argv) {
1911 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
1912 char output[100];
1913 char output2[100];
1914 char output3[100];
1915 unsigned long inlen = strlen(input);
1916 unsigned long outlen = 100;
1917 int ret;
1918 unsigned long cons, tmp, tmp2, prod;
1919
1920 /*
1921 * Direct
1922 */
1923 ret = xmlBase64Decode(input, &inlen, output, &outlen);
1924
1925 output[outlen] = 0;
1926 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
1927
1928 /*
1929 * output chunking
1930 */
1931 cons = 0;
1932 prod = 0;
1933 while (cons < inlen) {
1934 tmp = 5;
1935 tmp2 = inlen - cons;
1936
1937 printf("%ld %ld\n", cons, prod);
1938 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
1939 cons += tmp2;
1940 prod += tmp;
1941 printf("%ld %ld\n", cons, prod);
1942 }
1943 output2[outlen] = 0;
1944 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
1945
1946 /*
1947 * input chunking
1948 */
1949 cons = 0;
1950 prod = 0;
1951 while (cons < inlen) {
1952 tmp = 100 - prod;
1953 tmp2 = inlen - cons;
1954 if (tmp2 > 5)
1955 tmp2 = 5;
1956
1957 printf("%ld %ld\n", cons, prod);
1958 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
1959 cons += tmp2;
1960 prod += tmp;
1961 printf("%ld %ld\n", cons, prod);
1962 }
1963 output3[outlen] = 0;
1964 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
1965 return(0);
1966
1967}
1968#endif