blob: 5649da9e7d5d4a62f335269f2032a496db0e1a7c [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,
Daniel Veillardea7751d2002-12-20 00:16:24 +000073 XML_TEXTREADER_BACKTRACK= 4,
74 XML_TEXTREADER_DONE= 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000075} xmlTextReaderState;
76
77struct _xmlTextReader {
78 int mode; /* the parsing mode */
79 int allocs; /* what structure were deallocated */
80 xmlTextReaderState state;
81 xmlParserCtxtPtr ctxt; /* the parser context */
82 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
83 xmlParserInputBufferPtr input; /* the input */
84 startElementSAXFunc startElement;/* initial SAX callbacks */
85 endElementSAXFunc endElement; /* idem */
Daniel Veillardea7751d2002-12-20 00:16:24 +000086 charactersSAXFunc characters;
87 cdataBlockSAXFunc cdataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +000088 unsigned int base; /* base of the segment in the input */
89 unsigned int cur; /* current position in the input */
90 xmlNodePtr node; /* current node */
Daniel Veillardda46d2d2002-12-15 23:36:49 +000091 xmlNodePtr curnode;/* current attribute node */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000092 int depth; /* depth of the current node */
Daniel Veillardbeb70bd2002-12-18 14:53:54 +000093 xmlNodePtr faketext;/* fake xmlNs chld */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000094};
95
96#ifdef DEBUG_READER
97static void
98xmlTextReaderDebug(xmlTextReaderPtr reader) {
99 if ((reader == NULL) || (reader->ctxt == NULL)) {
100 fprintf(stderr, "xmlTextReader NULL\n");
101 return;
102 }
103 fprintf(stderr, "xmlTextReader: state %d depth %d ",
104 reader->state, reader->depth);
105 if (reader->node == NULL) {
106 fprintf(stderr, "node = NULL\n");
107 } else {
108 fprintf(stderr, "node %s\n", reader->node->name);
109 }
110 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
111 reader->base, reader->cur, reader->ctxt->nodeNr);
112 if (reader->input->buffer == NULL) {
113 fprintf(stderr, "buffer is NULL\n");
114 } else {
115#ifdef LIBXML_DEBUG_ENABLED
116 xmlDebugDumpString(stderr,
117 &reader->input->buffer->content[reader->cur]);
118#endif
119 fprintf(stderr, "\n");
120 }
121}
122#endif
123
124/**
125 * xmlTextReaderStartElement:
126 * @ctx: the user data (XML parser context)
127 * @fullname: The element name, including namespace prefix
128 * @atts: An array of name/value attributes pairs, NULL terminated
129 *
130 * called when an opening tag has been processed.
131 */
132static void
133xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
134 const xmlChar **atts) {
135 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
136 xmlTextReaderPtr reader = ctxt->_private;
137
138#ifdef DEBUG_CALLBACKS
139 printf("xmlTextReaderStartElement(%s)\n", fullname);
140#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000141 if ((reader != NULL) && (reader->startElement != NULL)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000142 reader->startElement(ctx, fullname, atts);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000143 if (ctxt->validate) {
144 ctxt->valid &= xmlValidatePushElement(&ctxt->vctxt, ctxt->myDoc,
145 ctxt->node, fullname);
146 }
147 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000148 reader->state = XML_TEXTREADER_ELEMENT;
149}
150
151/**
152 * xmlTextReaderEndElement:
153 * @ctx: the user data (XML parser context)
154 * @fullname: The element name, including namespace prefix
155 *
156 * called when an ending tag has been processed.
157 */
158static void
159xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
160 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
161 xmlTextReaderPtr reader = ctxt->_private;
162
163#ifdef DEBUG_CALLBACKS
164 printf("xmlTextReaderEndElement(%s)\n", fullname);
165#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000166 if ((reader != NULL) && (reader->endElement != NULL)) {
167 xmlNodePtr node = ctxt->node;
168
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000169 reader->endElement(ctx, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000170
171 if (ctxt->validate) {
172 ctxt->valid &= xmlValidatePopElement(&ctxt->vctxt, ctxt->myDoc,
173 node, fullname);
174 }
175 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000176 if (reader->state == XML_TEXTREADER_ELEMENT)
177 reader->state = XML_TEXTREADER_EMPTY;
178 else
179 reader->state = XML_TEXTREADER_END;
180}
181
182/**
Daniel Veillardea7751d2002-12-20 00:16:24 +0000183 * xmlTextReaderCharacters:
184 * @ctx: the user data (XML parser context)
185 * @ch: a xmlChar string
186 * @len: the number of xmlChar
187 *
188 * receiving some chars from the parser.
189 */
190static void
191xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
192{
193 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
194 xmlTextReaderPtr reader = ctxt->_private;
195
196#ifdef DEBUG_CALLBACKS
197 printf("xmlTextReaderCharacters()\n");
198#endif
199 if ((reader != NULL) && (reader->characters != NULL)) {
200 reader->characters(ctx, ch, len);
201
202 if (ctxt->validate) {
203 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt, ch, len);
204 }
205 }
206}
207
208/**
209 * xmlTextReaderCDataBlock:
210 * @ctx: the user data (XML parser context)
211 * @value: The pcdata content
212 * @len: the block length
213 *
214 * called when a pcdata block has been parsed
215 */
216static void
217xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
218{
219 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
220 xmlTextReaderPtr reader = ctxt->_private;
221
222#ifdef DEBUG_CALLBACKS
223 printf("xmlTextReaderCDataBlock()\n");
224#endif
225 if ((reader != NULL) && (reader->cdataBlock != NULL)) {
226 reader->cdataBlock(ctx, ch, len);
227
228 if (ctxt->validate) {
229 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt, ch, len);
230 }
231 }
232}
233
234/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000235 * xmlTextReaderPushData:
236 * @reader: the xmlTextReaderPtr used
237 *
238 * Push data down the progressive parser until a significant callback
239 * got raised.
240 *
241 * Returns -1 in case of failure, 0 otherwise
242 */
243static int
244xmlTextReaderPushData(xmlTextReaderPtr reader) {
245 unsigned int cur = reader->cur;
246 xmlBufferPtr inbuf;
247 int val;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000248 int oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000249
250 if ((reader->input == NULL) || (reader->input->buffer == NULL))
251 return(-1);
252
Daniel Veillardea7751d2002-12-20 00:16:24 +0000253 oldstate = reader->state;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000254 reader->state = XML_TEXTREADER_NONE;
255 inbuf = reader->input->buffer;
256 while (reader->state == XML_TEXTREADER_NONE) {
257 if (cur >= inbuf->use) {
258 /*
259 * Refill the buffer unless we are at the end of the stream
260 */
261 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
262 val = xmlParserInputBufferRead(reader->input, 4096);
263 if (val <= 0) {
264 reader->mode = XML_TEXTREADER_MODE_EOF;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000265 reader->state = oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000266 return(val);
267 }
268 } else
269 break;
270 }
271 if ((inbuf->content[cur] == '>') || (inbuf->content[cur] == '&')) {
272 cur = cur + 1;
273 val = xmlParseChunk(reader->ctxt,
274 (const char *) &inbuf->content[reader->cur],
275 cur - reader->cur, 0);
276 if (val != 0)
277 return(-1);
278 reader->cur = cur;
279 break;
280 } else {
281 cur = cur + 1;
282
283 /*
284 * One may have to force a flush at some point when parsing really
285 * large CDATA sections
286 */
287 if ((cur - reader->cur > 4096) && (reader->base == 0) &&
Daniel Veillard67df8092002-12-16 22:04:11 +0000288 (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000289 cur = cur + 1;
290 val = xmlParseChunk(reader->ctxt,
291 (const char *) &inbuf->content[reader->cur],
292 cur - reader->cur, 0);
293 if (val != 0)
294 return(-1);
295 reader->cur = cur;
296 }
297 }
298 }
299 /*
300 * Discard the consumed input when needed and possible
301 */
Daniel Veillard67df8092002-12-16 22:04:11 +0000302 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000303 if ((reader->cur >= 4096) && (reader->base == 0)) {
304 val = xmlBufferShrink(inbuf, cur);
305 if (val >= 0) {
306 reader->cur -= val;
307 }
308 }
309 }
310
311 /*
312 * At the end of the stream signal that the work is done to the Push
313 * parser.
314 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000315 if (reader->mode == XML_TEXTREADER_MODE_EOF) {
316 if (reader->mode != XML_TEXTREADER_DONE) {
317 val = xmlParseChunk(reader->ctxt,
318 (const char *) &inbuf->content[reader->cur], 0, 1);
319 reader->mode = XML_TEXTREADER_DONE;
320 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000321 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000322 reader->state = oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000323 return(0);
324}
325
326/**
327 * xmlTextReaderRead:
328 * @reader: the xmlTextReaderPtr used
329 *
330 * Moves the position of the current instance to the next node in
331 * the stream, exposing its properties.
332 *
333 * Returns 1 if the node was read successfully, 0 if there is no more
334 * nodes to read, or -1 in case of error
335 */
336int
337xmlTextReaderRead(xmlTextReaderPtr reader) {
338 int val, olddepth;
339 xmlTextReaderState oldstate;
340 xmlNodePtr oldnode;
341
342 if ((reader == NULL) || (reader->ctxt == NULL))
343 return(-1);
344 if (reader->ctxt->wellFormed != 1)
345 return(-1);
346
347#ifdef DEBUG_READER
348 fprintf(stderr, "\nREAD ");
349 DUMP_READER
350#endif
Daniel Veillard67df8092002-12-16 22:04:11 +0000351 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
352 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000353 /*
354 * Initial state
355 */
356 do {
357 val = xmlTextReaderPushData(reader);
358 if (val < 0)
359 return(-1);
360 } while ((reader->ctxt->node == NULL) &&
361 (reader->mode != XML_TEXTREADER_MODE_EOF));
362 if (reader->ctxt->node == NULL) {
363 if (reader->ctxt->myDoc != NULL)
364 reader->node = reader->ctxt->myDoc->children;
365 if (reader->node == NULL)
366 return(-1);
367 } else {
368 reader->node = reader->ctxt->node;
369 }
370 reader->depth = 1;
371 return(1);
372 }
373 oldstate = reader->state;
374 olddepth = reader->ctxt->nodeNr;
375 oldnode = reader->node;
376 /*
377 * If we are not backtracking on ancestors or examined nodes,
378 * that the parser didn't finished or that we arent at the end
379 * of stream, continue processing.
380 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000381 while (((oldstate == XML_TEXTREADER_BACKTRACK) ||
382 (reader->node->children == NULL) ||
383 (reader->node->type == XML_ENTITY_REF_NODE) ||
384 (reader->node->type == XML_DTD_NODE)) &&
385 (reader->node->next == NULL) &&
386 (reader->ctxt->nodeNr == olddepth) &&
387 (reader->ctxt->instate != XML_PARSER_EOF)) {
388 val = xmlTextReaderPushData(reader);
389 if (val < 0)
390 return(-1);
391 if (reader->node == NULL)
392 return(0);
393 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000394 if (oldstate != XML_TEXTREADER_BACKTRACK) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000395 if ((reader->node->children != NULL) &&
396 (reader->node->type != XML_ENTITY_REF_NODE) &&
397 (reader->node->type != XML_DTD_NODE)) {
398 reader->node = reader->node->children;
399 reader->depth++;
400 if ((reader->state != XML_TEXTREADER_ELEMENT) &&
401 (reader->state != XML_TEXTREADER_EMPTY))
402 reader->state = XML_TEXTREADER_ELEMENT;
403 DUMP_READER
404 return(1);
405 }
406 }
407 if (reader->node->next != NULL) {
408 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
409 (reader->node->type == XML_ELEMENT_NODE)) {
410 reader->state = XML_TEXTREADER_END;
411 DUMP_READER
412 return(1);
413 }
414 reader->node = reader->node->next;
415 reader->state = XML_TEXTREADER_ELEMENT;
416 DUMP_READER
417 /*
418 * Cleanup of the old node
419 */
420 if (oldnode->type != XML_DTD_NODE) {
421 xmlUnlinkNode(oldnode);
422 xmlFreeNode(oldnode);
423 }
424
425 return(1);
426 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000427 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
428 (reader->node->type == XML_ELEMENT_NODE)) {
429 reader->state = XML_TEXTREADER_END;
430 DUMP_READER
431 return(1);
432 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000433 reader->node = reader->node->parent;
434 if ((reader->node == NULL) ||
435 (reader->node->type == XML_DOCUMENT_NODE) ||
436#ifdef LIBXML_DOCB_ENABLED
437 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
438#endif
439 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000440 if (reader->mode != XML_TEXTREADER_DONE) {
441 val = xmlParseChunk(reader->ctxt, "", 0, 1);
442 reader->mode = XML_TEXTREADER_DONE;
443 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000444 reader->node = NULL;
445 reader->depth = 0;
446
447 /*
448 * Cleanup of the old node
449 */
450 if (oldnode->type != XML_DTD_NODE) {
451 xmlUnlinkNode(oldnode);
452 xmlFreeNode(oldnode);
453 }
454
455 return(0);
456 }
457 reader->depth--;
458 reader->state = XML_TEXTREADER_BACKTRACK;
459 DUMP_READER
460 return(1);
461}
462
Daniel Veillard67df8092002-12-16 22:04:11 +0000463/**
464 * xmlTextReaderReadState:
465 * @reader: the xmlTextReaderPtr used
466 *
467 * Gets the read state of the reader.
468 *
469 * Returns the state value, or -1 in case of error
470 */
471int
472xmlTextReaderReadState(xmlTextReaderPtr reader) {
473 if (reader == NULL)
474 return(-1);
475 return(reader->mode);
476}
477
478/**
479 * xmlTextReaderReadInnerXml:
480 * @reader: the xmlTextReaderPtr used
481 *
482 * Reads the contents of the current node, including child nodes and markup.
483 *
484 * Returns a string containing the XML content, or NULL if the current node
485 * is neither an element nor attribute, or has no child nodes. The
486 * string must be deallocated by the caller.
487 */
488xmlChar *
489xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) {
490 TODO
491 return(NULL);
492}
493
494/**
495 * xmlTextReaderReadOuterXml:
496 * @reader: the xmlTextReaderPtr used
497 *
498 * Reads the contents of the current node, including child nodes and markup.
499 *
500 * Returns a string containing the XML content, or NULL if the current node
501 * is neither an element nor attribute, or has no child nodes. The
502 * string must be deallocated by the caller.
503 */
504xmlChar *
505xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) {
506 TODO
507 return(NULL);
508}
509
510/**
511 * xmlTextReaderReadString:
512 * @reader: the xmlTextReaderPtr used
513 *
514 * Reads the contents of an element or a text node as a string.
515 *
516 * Returns a string containing the contents of the Element or Text node,
517 * or NULL if the reader is positioned on any other type of node.
518 * The string must be deallocated by the caller.
519 */
520xmlChar *
521xmlTextReaderReadString(xmlTextReaderPtr reader) {
522 TODO
523 return(NULL);
524}
525
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000526/**
527 * xmlTextReaderReadBase64:
528 * @reader: the xmlTextReaderPtr used
529 * @array: a byte array to store the content.
530 * @offset: the zero-based index into array where the method should
531 * begin to write.
532 * @len: the number of bytes to write.
533 *
534 * Reads and decodes the Base64 encoded contents of an element and
535 * stores the result in a byte buffer.
536 *
537 * Returns the number of bytes written to array, or zero if the current
538 * instance is not positioned on an element or -1 in case of error.
539 */
540int
541xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
542 int offset, int len) {
543 if ((reader == NULL) || (reader->ctxt == NULL))
544 return(-1);
545 if (reader->ctxt->wellFormed != 1)
546 return(-1);
547
548 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
549 return(0);
550 TODO
551 return(0);
552}
553
554/**
555 * xmlTextReaderReadBinHex:
556 * @reader: the xmlTextReaderPtr used
557 * @array: a byte array to store the content.
558 * @offset: the zero-based index into array where the method should
559 * begin to write.
560 * @len: the number of bytes to write.
561 *
562 * Reads and decodes the BinHex encoded contents of an element and
563 * stores the result in a byte buffer.
564 *
565 * Returns the number of bytes written to array, or zero if the current
566 * instance is not positioned on an element or -1 in case of error.
567 */
568int
569xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
570 int offset, int len) {
571 if ((reader == NULL) || (reader->ctxt == NULL))
572 return(-1);
573 if (reader->ctxt->wellFormed != 1)
574 return(-1);
575
576 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
577 return(0);
578 TODO
579 return(0);
580}
581
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000582/************************************************************************
583 * *
584 * Constructor and destructors *
585 * *
586 ************************************************************************/
587/**
588 * xmlNewTextReader:
589 * @input: the xmlParserInputBufferPtr used to read data
Daniel Veillardea7751d2002-12-20 00:16:24 +0000590 * @URI: the URI information for the source if available
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000591 *
592 * Create an xmlTextReader structure fed with @input
593 *
594 * Returns the new xmlTextReaderPtr or NULL in case of error
595 */
596xmlTextReaderPtr
Daniel Veillardea7751d2002-12-20 00:16:24 +0000597xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000598 xmlTextReaderPtr ret;
599 int val;
600
601 if (input == NULL)
602 return(NULL);
603 ret = xmlMalloc(sizeof(xmlTextReader));
604 if (ret == NULL) {
605 xmlGenericError(xmlGenericErrorContext,
606 "xmlNewTextReader : malloc failed\n");
607 return(NULL);
608 }
609 memset(ret, 0, sizeof(xmlTextReader));
610 ret->input = input;
611 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
612 if (ret->sax == NULL) {
613 xmlFree(ret);
614 xmlGenericError(xmlGenericErrorContext,
615 "xmlNewTextReader : malloc failed\n");
616 return(NULL);
617 }
618 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
619 ret->startElement = ret->sax->startElement;
620 ret->sax->startElement = xmlTextReaderStartElement;
621 ret->endElement = ret->sax->endElement;
622 ret->sax->endElement = xmlTextReaderEndElement;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000623 ret->characters = ret->sax->characters;
624 ret->sax->characters = xmlTextReaderCharacters;
625 ret->cdataBlock = ret->sax->cdataBlock;
626 ret->sax->cdataBlock = xmlTextReaderCDataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000627
Daniel Veillard67df8092002-12-16 22:04:11 +0000628 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000629 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000630 ret->curnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000631 val = xmlParserInputBufferRead(input, 4);
632 if (val >= 4) {
633 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
Daniel Veillardea7751d2002-12-20 00:16:24 +0000634 (const char *) ret->input->buffer->content, 4, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000635 ret->base = 0;
636 ret->cur = 4;
637 } else {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000638 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000639 ret->base = 0;
640 ret->cur = 0;
641 }
642 ret->ctxt->_private = ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000643 ret->ctxt->linenumbers = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000644 ret->allocs = XML_TEXTREADER_CTXT;
645 return(ret);
646
647}
648
649/**
650 * xmlNewTextReaderFilename:
651 * @URI: the URI of the resource to process
652 *
653 * Create an xmlTextReader structure fed with the resource at @URI
654 *
655 * Returns the new xmlTextReaderPtr or NULL in case of error
656 */
657xmlTextReaderPtr
658xmlNewTextReaderFilename(const char *URI) {
659 xmlParserInputBufferPtr input;
660 xmlTextReaderPtr ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000661 char *directory = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000662
663 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
664 if (input == NULL)
665 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000666 ret = xmlNewTextReader(input, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000667 if (ret == NULL) {
668 xmlFreeParserInputBuffer(input);
669 return(NULL);
670 }
671 ret->allocs |= XML_TEXTREADER_INPUT;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000672 if (ret->ctxt->directory == NULL)
673 directory = xmlParserGetDirectory(URI);
674 if ((ret->ctxt->directory == NULL) && (directory != NULL))
675 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
676 if (directory != NULL)
677 xmlFree(directory);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000678 return(ret);
679}
680
681/**
682 * xmlFreeTextReader:
683 * @reader: the xmlTextReaderPtr
684 *
685 * Deallocate all the resources associated to the reader
686 */
687void
688xmlFreeTextReader(xmlTextReaderPtr reader) {
689 if (reader == NULL)
690 return;
691 if (reader->ctxt != NULL) {
692 if (reader->ctxt->myDoc != NULL) {
693 xmlFreeDoc(reader->ctxt->myDoc);
694 reader->ctxt->myDoc = NULL;
695 }
696 if (reader->allocs & XML_TEXTREADER_CTXT)
697 xmlFreeParserCtxt(reader->ctxt);
698 }
699 if (reader->sax != NULL)
700 xmlFree(reader->sax);
701 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
702 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000703 if (reader->faketext != NULL) {
704 xmlFreeNode(reader->faketext);
705 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000706 xmlFree(reader);
707}
708
709/************************************************************************
710 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000711 * Methods for XmlTextReader *
712 * *
713 ************************************************************************/
714/**
715 * xmlTextReaderClose:
716 * @reader: the xmlTextReaderPtr used
717 *
718 * This method releases any resources allocated by the current instance
719 * changes the state to Closed and close any underlying input.
720 *
721 * Returns 0 or -1 in case of error
722 */
723int
724xmlTextReaderClose(xmlTextReaderPtr reader) {
725 if (reader == NULL)
726 return(-1);
727 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000728 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000729 reader->mode = XML_TEXTREADER_MODE_CLOSED;
730 if (reader->ctxt != NULL) {
731 if (reader->ctxt->myDoc != NULL) {
732 xmlFreeDoc(reader->ctxt->myDoc);
733 reader->ctxt->myDoc = NULL;
734 }
735 if (reader->allocs & XML_TEXTREADER_CTXT) {
736 xmlFreeParserCtxt(reader->ctxt);
737 reader->allocs -= XML_TEXTREADER_CTXT;
738 }
739 }
740 if (reader->sax != NULL) {
741 xmlFree(reader->sax);
742 reader->sax = NULL;
743 }
744 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
745 xmlFreeParserInputBuffer(reader->input);
746 reader->allocs -= XML_TEXTREADER_INPUT;
747 }
748 return(0);
749}
750
751/**
752 * xmlTextReaderGetAttributeNo:
753 * @reader: the xmlTextReaderPtr used
754 * @no: the zero-based index of the attribute relative to the containing element
755 *
756 * Provides the value of the attribute with the specified index relative
757 * to the containing element.
758 *
759 * Returns a string containing the value of the specified attribute, or NULL
760 * in case of error. The string must be deallocated by the caller.
761 */
762xmlChar *
763xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
764 xmlChar *ret;
765 int i;
766 xmlAttrPtr cur;
767 xmlNsPtr ns;
768
769 if (reader == NULL)
770 return(NULL);
771 if (reader->node == NULL)
772 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000773 if (reader->curnode != NULL)
774 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000775 /* TODO: handle the xmlDecl */
776 if (reader->node->type != XML_ELEMENT_NODE)
777 return(NULL);
778
779 ns = reader->node->nsDef;
780 for (i = 0;(i < no) && (ns != NULL);i++) {
781 ns = ns->next;
782 }
783 if (ns != NULL)
784 return(xmlStrdup(ns->href));
785
786 cur = reader->node->properties;
787 if (cur == NULL)
788 return(NULL);
789 for (;i < no;i++) {
790 cur = cur->next;
791 if (cur == NULL)
792 return(NULL);
793 }
794 /* TODO walk the DTD if present */
795
796 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
797 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
798 return(ret);
799}
800
801/**
802 * xmlTextReaderGetAttribute:
803 * @reader: the xmlTextReaderPtr used
804 * @name: the qualified name of the attribute.
805 *
806 * Provides the value of the attribute with the specified qualified name.
807 *
808 * Returns a string containing the value of the specified attribute, or NULL
809 * in case of error. The string must be deallocated by the caller.
810 */
811xmlChar *
812xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
813 xmlChar *prefix = NULL;
814 xmlChar *localname;
815 xmlNsPtr ns;
816 xmlChar *ret = NULL;
817
818 if ((reader == NULL) || (name == NULL))
819 return(NULL);
820 if (reader->node == NULL)
821 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000822 if (reader->curnode != NULL)
823 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000824
825 /* TODO: handle the xmlDecl */
826 if (reader->node->type != XML_ELEMENT_NODE)
827 return(NULL);
828
829 localname = xmlSplitQName2(name, &prefix);
830 if (localname == NULL)
831 return(xmlGetProp(reader->node, name));
832
833 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
834 if (ns != NULL)
835 ret = xmlGetNsProp(reader->node, localname, ns->href);
836
837 if (localname != NULL)
838 xmlFree(localname);
839 if (prefix != NULL)
840 xmlFree(prefix);
841 return(ret);
842}
843
844
845/**
846 * xmlTextReaderGetAttributeNs:
847 * @reader: the xmlTextReaderPtr used
848 * @localName: the local name of the attribute.
849 * @namespaceURI: the namespace URI of the attribute.
850 *
851 * Provides the value of the specified attribute
852 *
853 * Returns a string containing the value of the specified attribute, or NULL
854 * in case of error. The string must be deallocated by the caller.
855 */
856xmlChar *
857xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
858 const xmlChar *namespaceURI) {
859 if ((reader == NULL) || (localName == NULL))
860 return(NULL);
861 if (reader->node == NULL)
862 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000863 if (reader->curnode != NULL)
864 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000865
866 /* TODO: handle the xmlDecl */
867 if (reader->node->type != XML_ELEMENT_NODE)
868 return(NULL);
869
870 return(xmlGetNsProp(reader->node, localName, namespaceURI));
871}
872
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000873/**
874 * xmlTextReaderGetRemainder:
875 * @reader: the xmlTextReaderPtr used
876 *
877 * Method to get the remainder of the buffered XML. this method stops the
878 * parser, set its state to End Of File and return the input stream with
879 * what is left that the parser did not use.
880 *
881 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
882 * in case of error.
883 */
884xmlParserInputBufferPtr
885xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
886 xmlParserInputBufferPtr ret = NULL;
887
888 if (reader == NULL)
889 return(NULL);
890 if (reader->node == NULL)
891 return(NULL);
892
893 reader->node = NULL;
894 reader->curnode = NULL;
895 reader->mode = XML_TEXTREADER_MODE_EOF;
896 if (reader->ctxt != NULL) {
897 if (reader->ctxt->myDoc != NULL) {
898 xmlFreeDoc(reader->ctxt->myDoc);
899 reader->ctxt->myDoc = NULL;
900 }
901 if (reader->allocs & XML_TEXTREADER_CTXT) {
902 xmlFreeParserCtxt(reader->ctxt);
903 reader->allocs -= XML_TEXTREADER_CTXT;
904 }
905 }
906 if (reader->sax != NULL) {
907 xmlFree(reader->sax);
908 reader->sax = NULL;
909 }
910 if (reader->allocs & XML_TEXTREADER_INPUT) {
911 ret = reader->input;
912 reader->allocs -= XML_TEXTREADER_INPUT;
913 } else {
914 /*
915 * Hum, one may need to duplicate the data structure because
916 * without reference counting the input may be freed twice:
917 * - by the layer which allocated it.
918 * - by the layer to which would have been returned to.
919 */
920 TODO
921 return(NULL);
922 }
923 return(ret);
924}
925
926/**
927 * xmlTextReaderLookupNamespace:
928 * @reader: the xmlTextReaderPtr used
929 * @prefix: the prefix whose namespace URI is to be resolved. To return
930 * the default namespace, specify NULL
931 *
932 * Resolves a namespace prefix in the scope of the current element.
933 *
934 * Returns a string containing the namespace URI to which the prefix maps
935 * or NULL in case of error. The string must be deallocated by the caller.
936 */
937xmlChar *
938xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
939 xmlNsPtr ns;
940
941 if (reader == NULL)
942 return(NULL);
943 if (reader->node == NULL)
944 return(NULL);
945
946 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
947 if (ns == NULL)
948 return(NULL);
949 return(xmlStrdup(ns->href));
950}
951
952/**
953 * xmlTextReaderMoveToAttributeNo:
954 * @reader: the xmlTextReaderPtr used
955 * @no: the zero-based index of the attribute relative to the containing
956 * element.
957 *
958 * Moves the position of the current instance to the attribute with
959 * the specified index relative to the containing element.
960 *
961 * Returns 1 in case of success, -1 in case of error, 0 if not found
962 */
963int
964xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
965 int i;
966 xmlAttrPtr cur;
967 xmlNsPtr ns;
968
969 if (reader == NULL)
970 return(-1);
971 if (reader->node == NULL)
972 return(-1);
973 /* TODO: handle the xmlDecl */
974 if (reader->node->type != XML_ELEMENT_NODE)
975 return(-1);
976
977 reader->curnode = NULL;
978
979 ns = reader->node->nsDef;
980 for (i = 0;(i < no) && (ns != NULL);i++) {
981 ns = ns->next;
982 }
983 if (ns != NULL) {
984 reader->curnode = (xmlNodePtr) ns;
985 return(1);
986 }
987
988 cur = reader->node->properties;
989 if (cur == NULL)
990 return(0);
991 for (;i < no;i++) {
992 cur = cur->next;
993 if (cur == NULL)
994 return(0);
995 }
996 /* TODO walk the DTD if present */
997
998 reader->curnode = (xmlNodePtr) cur;
999 return(1);
1000}
1001
1002/**
1003 * xmlTextReaderMoveToAttribute:
1004 * @reader: the xmlTextReaderPtr used
1005 * @name: the qualified name of the attribute.
1006 *
1007 * Moves the position of the current instance to the attribute with
1008 * the specified qualified name.
1009 *
1010 * Returns 1 in case of success, -1 in case of error, 0 if not found
1011 */
1012int
1013xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1014 xmlChar *prefix = NULL;
1015 xmlChar *localname;
1016 xmlNsPtr ns;
1017 xmlAttrPtr prop;
1018
1019 if ((reader == NULL) || (name == NULL))
1020 return(-1);
1021 if (reader->node == NULL)
1022 return(-1);
1023
1024 /* TODO: handle the xmlDecl */
1025 if (reader->node->type != XML_ELEMENT_NODE)
1026 return(0);
1027
1028 localname = xmlSplitQName2(name, &prefix);
1029 if (localname == NULL) {
1030 /*
1031 * Namespace default decl
1032 */
1033 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1034 ns = reader->node->nsDef;
1035 while (ns != NULL) {
1036 if (ns->prefix == NULL) {
1037 reader->curnode = (xmlNodePtr) ns;
1038 return(1);
1039 }
1040 ns = ns->next;
1041 }
1042 return(0);
1043 }
1044
1045 prop = reader->node->properties;
1046 while (prop != NULL) {
1047 /*
1048 * One need to have
1049 * - same attribute names
1050 * - and the attribute carrying that namespace
1051 */
1052 if ((xmlStrEqual(prop->name, name)) &&
1053 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
1054 reader->curnode = (xmlNodePtr) prop;
1055 return(1);
1056 }
1057 prop = prop->next;
1058 }
1059 return(0);
1060 }
1061
1062 /*
1063 * Namespace default decl
1064 */
1065 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
1066 ns = reader->node->nsDef;
1067 while (ns != NULL) {
1068 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
1069 reader->curnode = (xmlNodePtr) ns;
1070 goto found;
1071 }
1072 ns = ns->next;
1073 }
1074 goto not_found;
1075 }
1076 prop = reader->node->properties;
1077 while (prop != NULL) {
1078 /*
1079 * One need to have
1080 * - same attribute names
1081 * - and the attribute carrying that namespace
1082 */
1083 if ((xmlStrEqual(prop->name, localname)) &&
1084 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
1085 reader->curnode = (xmlNodePtr) prop;
1086 goto found;
1087 }
1088 prop = prop->next;
1089 }
1090not_found:
1091 if (localname != NULL)
1092 xmlFree(localname);
1093 if (prefix != NULL)
1094 xmlFree(prefix);
1095 return(0);
1096
1097found:
1098 if (localname != NULL)
1099 xmlFree(localname);
1100 if (prefix != NULL)
1101 xmlFree(prefix);
1102 return(1);
1103}
1104
1105/**
1106 * xmlTextReaderMoveToAttributeNs:
1107 * @reader: the xmlTextReaderPtr used
1108 * @localName: the local name of the attribute.
1109 * @namespaceURI: the namespace URI of the attribute.
1110 *
1111 * Moves the position of the current instance to the attribute with the
1112 * specified local name and namespace URI.
1113 *
1114 * Returns 1 in case of success, -1 in case of error, 0 if not found
1115 */
1116int
1117xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1118 const xmlChar *localName, const xmlChar *namespaceURI) {
1119 xmlAttrPtr prop;
1120 xmlNodePtr node;
1121
1122 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1123 return(-1);
1124 if (reader->node == NULL)
1125 return(-1);
1126 if (reader->node->type != XML_ELEMENT_NODE)
1127 return(0);
1128 node = reader->node;
1129
1130 /*
1131 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1132 * namespace name associated to "xmlns"
1133 */
1134 prop = node->properties;
1135 while (prop != NULL) {
1136 /*
1137 * One need to have
1138 * - same attribute names
1139 * - and the attribute carrying that namespace
1140 */
1141 if (xmlStrEqual(prop->name, localName) &&
1142 ((prop->ns != NULL) &&
1143 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1144 reader->curnode = (xmlNodePtr) prop;
1145 return(1);
1146 }
1147 prop = prop->next;
1148 }
1149 return(0);
1150}
1151
1152/**
1153 * xmlTextReaderMoveToFirstAttribute:
1154 * @reader: the xmlTextReaderPtr used
1155 *
1156 * Moves the position of the current instance to the first attribute
1157 * associated with the current node.
1158 *
1159 * Returns 1 in case of success, -1 in case of error, 0 if not found
1160 */
1161int
1162xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1163 if (reader == NULL)
1164 return(-1);
1165 if (reader->node == NULL)
1166 return(-1);
1167 if (reader->node->type != XML_ELEMENT_NODE)
1168 return(0);
1169
1170 if (reader->node->nsDef != NULL) {
1171 reader->curnode = (xmlNodePtr) reader->node->nsDef;
1172 return(1);
1173 }
1174 if (reader->node->properties != NULL) {
1175 reader->curnode = (xmlNodePtr) reader->node->properties;
1176 return(1);
1177 }
1178 return(0);
1179}
1180
1181/**
1182 * xmlTextReaderMoveToNextAttribute:
1183 * @reader: the xmlTextReaderPtr used
1184 *
1185 * Moves the position of the current instance to the next attribute
1186 * associated with the current node.
1187 *
1188 * Returns 1 in case of success, -1 in case of error, 0 if not found
1189 */
1190int
1191xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1192 if (reader == NULL)
1193 return(-1);
1194 if (reader->node == NULL)
1195 return(-1);
1196 if (reader->node->type != XML_ELEMENT_NODE)
1197 return(0);
1198 if (reader->curnode == NULL)
1199 return(xmlTextReaderMoveToFirstAttribute(reader));
1200
1201 if (reader->curnode->type == XML_NAMESPACE_DECL) {
1202 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1203 if (ns->next != NULL) {
1204 reader->curnode = (xmlNodePtr) ns->next;
1205 return(1);
1206 }
1207 if (reader->node->properties != NULL) {
1208 reader->curnode = (xmlNodePtr) reader->node->properties;
1209 return(1);
1210 }
1211 return(0);
1212 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1213 (reader->curnode->next != NULL)) {
1214 reader->curnode = reader->curnode->next;
1215 return(1);
1216 }
1217 return(0);
1218}
1219
1220/**
1221 * xmlTextReaderMoveToElement:
1222 * @reader: the xmlTextReaderPtr used
1223 *
1224 * Moves the position of the current instance to the node that
1225 * contains the current Attribute node.
1226 *
1227 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1228 */
1229int
1230xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
1231 if (reader == NULL)
1232 return(-1);
1233 if (reader->node == NULL)
1234 return(-1);
1235 if (reader->node->type != XML_ELEMENT_NODE)
1236 return(0);
1237 if (reader->curnode != NULL) {
1238 reader->curnode = NULL;
1239 return(1);
1240 }
1241 return(0);
1242}
1243
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001244/**
1245 * xmlTextReaderReadAttributeValue:
1246 * @reader: the xmlTextReaderPtr used
1247 *
1248 * Parses an attribute value into one or more Text and EntityReference nodes.
1249 *
1250 * Returns 1 in case of success, 0 if the reader was not positionned on an
1251 * ttribute node or all the attribute values have been read, or -1
1252 * in case of error.
1253 */
1254int
1255xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1256 if (reader == NULL)
1257 return(-1);
1258 if (reader->node == NULL)
1259 return(-1);
1260 if (reader->curnode == NULL)
1261 return(0);
1262 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1263 if (reader->curnode->children == NULL)
1264 return(0);
1265 reader->curnode = reader->curnode->children;
1266 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1267 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1268
1269 if (reader->faketext == NULL) {
1270 reader->faketext = xmlNewDocText(reader->node->doc,
1271 ns->href);
1272 } else {
1273 if (reader->faketext->content != NULL)
1274 xmlFree(reader->faketext->content);
1275 reader->faketext->content = xmlStrdup(ns->href);
1276 }
1277 reader->curnode = reader->faketext;
1278 } else {
1279 if (reader->curnode->next == NULL)
1280 return(0);
1281 reader->curnode = reader->curnode->next;
1282 }
1283 return(1);
1284}
1285
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001286/************************************************************************
1287 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001288 * Acces API to the current node *
1289 * *
1290 ************************************************************************/
1291/**
1292 * xmlTextReaderAttributeCount:
1293 * @reader: the xmlTextReaderPtr used
1294 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001295 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001296 *
1297 * Returns 0 i no attributes, -1 in case of error or the attribute count
1298 */
1299int
1300xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1301 int ret;
1302 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00001303 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001304 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001305
1306 if (reader == NULL)
1307 return(-1);
1308 if (reader->node == NULL)
1309 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001310
1311 if (reader->curnode != NULL)
1312 node = reader->curnode;
1313 else
1314 node = reader->node;
1315
1316 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001317 return(0);
1318 if ((reader->state == XML_TEXTREADER_END) ||
1319 (reader->state == XML_TEXTREADER_BACKTRACK))
1320 return(0);
1321 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001322 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001323 while (attr != NULL) {
1324 ret++;
1325 attr = attr->next;
1326 }
Daniel Veillard67df8092002-12-16 22:04:11 +00001327 ns = node->nsDef;
1328 while (ns != NULL) {
1329 ret++;
1330 ns = ns->next;
1331 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001332 return(ret);
1333}
1334
1335/**
1336 * xmlTextReaderNodeType:
1337 * @reader: the xmlTextReaderPtr used
1338 *
1339 * Get the node type of the current node
1340 * Reference:
1341 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1342 *
1343 * Returns the xmlNodeType of the current node or -1 in case of error
1344 */
1345int
1346xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001347 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001348 if (reader == NULL)
1349 return(-1);
1350 if (reader->node == NULL)
1351 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001352 if (reader->curnode != NULL)
1353 node = reader->curnode;
1354 else
1355 node = reader->node;
1356 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001357 case XML_ELEMENT_NODE:
1358 if ((reader->state == XML_TEXTREADER_END) ||
1359 (reader->state == XML_TEXTREADER_BACKTRACK))
1360 return(15);
1361 return(1);
1362 case XML_ATTRIBUTE_NODE:
1363 return(2);
1364 case XML_TEXT_NODE:
1365 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1366 case XML_CDATA_SECTION_NODE:
1367 return(4);
1368 case XML_ENTITY_REF_NODE:
1369 return(5);
1370 case XML_ENTITY_NODE:
1371 return(6);
1372 case XML_PI_NODE:
1373 return(7);
1374 case XML_COMMENT_NODE:
1375 return(8);
1376 case XML_DOCUMENT_NODE:
1377 case XML_HTML_DOCUMENT_NODE:
1378#ifdef LIBXML_DOCB_ENABLED
1379 case XML_DOCB_DOCUMENT_NODE:
1380#endif
1381 return(9);
1382 case XML_DOCUMENT_FRAG_NODE:
1383 return(11);
1384 case XML_NOTATION_NODE:
1385 return(12);
1386 case XML_DOCUMENT_TYPE_NODE:
1387 case XML_DTD_NODE:
1388 return(10);
1389
1390 case XML_ELEMENT_DECL:
1391 case XML_ATTRIBUTE_DECL:
1392 case XML_ENTITY_DECL:
1393 case XML_NAMESPACE_DECL:
1394 case XML_XINCLUDE_START:
1395 case XML_XINCLUDE_END:
1396 return(0);
1397 }
1398 return(-1);
1399}
1400
1401/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001402 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001403 * @reader: the xmlTextReaderPtr used
1404 *
1405 * Check if the current node is empty
1406 *
1407 * Returns 1 if empty, 0 if not and -1 in case of error
1408 */
1409int
1410xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1411 if ((reader == NULL) || (reader->node == NULL))
1412 return(-1);
1413 if (reader->node->children != NULL)
1414 return(0);
1415 if ((reader->state == XML_TEXTREADER_EMPTY) ||
1416 (reader->state == XML_TEXTREADER_BACKTRACK))
1417 return(1);
1418 return(0);
1419}
1420
1421/**
1422 * xmlTextReaderLocalName:
1423 * @reader: the xmlTextReaderPtr used
1424 *
1425 * The local name of the node.
1426 *
1427 * Returns the local name or NULL if not available
1428 */
1429xmlChar *
1430xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001431 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001432 if ((reader == NULL) || (reader->node == NULL))
1433 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001434 if (reader->curnode != NULL)
1435 node = reader->curnode;
1436 else
1437 node = reader->node;
1438 if (node->type == XML_NAMESPACE_DECL) {
1439 xmlNsPtr ns = (xmlNsPtr) node;
1440 if (ns->prefix == NULL)
1441 return(xmlStrdup(BAD_CAST "xmlns"));
1442 else
1443 return(xmlStrdup(ns->prefix));
1444 }
1445 if ((node->type != XML_ELEMENT_NODE) &&
1446 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001447 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001448 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001449}
1450
1451/**
1452 * xmlTextReaderName:
1453 * @reader: the xmlTextReaderPtr used
1454 *
1455 * The qualified name of the node, equal to Prefix :LocalName.
1456 *
1457 * Returns the local name or NULL if not available
1458 */
1459xmlChar *
1460xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001461 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001462 xmlChar *ret;
1463
1464 if ((reader == NULL) || (reader->node == NULL))
1465 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001466 if (reader->curnode != NULL)
1467 node = reader->curnode;
1468 else
1469 node = reader->node;
1470 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001471 case XML_ELEMENT_NODE:
1472 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001473 if ((node->ns == NULL) ||
1474 (node->ns->prefix == NULL))
1475 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001476
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001477 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001478 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001479 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001480 return(ret);
1481 case XML_TEXT_NODE:
1482 return(xmlStrdup(BAD_CAST "#text"));
1483 case XML_CDATA_SECTION_NODE:
1484 return(xmlStrdup(BAD_CAST "#cdata-section"));
1485 case XML_ENTITY_NODE:
1486 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001487 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001488 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001489 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001490 case XML_COMMENT_NODE:
1491 return(xmlStrdup(BAD_CAST "#comment"));
1492 case XML_DOCUMENT_NODE:
1493 case XML_HTML_DOCUMENT_NODE:
1494#ifdef LIBXML_DOCB_ENABLED
1495 case XML_DOCB_DOCUMENT_NODE:
1496#endif
1497 return(xmlStrdup(BAD_CAST "#document"));
1498 case XML_DOCUMENT_FRAG_NODE:
1499 return(xmlStrdup(BAD_CAST "#document-fragment"));
1500 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001501 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001502 case XML_DOCUMENT_TYPE_NODE:
1503 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001504 return(xmlStrdup(node->name));
1505 case XML_NAMESPACE_DECL: {
1506 xmlNsPtr ns = (xmlNsPtr) node;
1507
1508 ret = xmlStrdup(BAD_CAST "xmlns");
1509 if (ns->prefix == NULL)
1510 return(ret);
1511 ret = xmlStrcat(ret, BAD_CAST ":");
1512 ret = xmlStrcat(ret, ns->prefix);
1513 return(ret);
1514 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001515
1516 case XML_ELEMENT_DECL:
1517 case XML_ATTRIBUTE_DECL:
1518 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001519 case XML_XINCLUDE_START:
1520 case XML_XINCLUDE_END:
1521 return(NULL);
1522 }
1523 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001524}
1525
1526/**
1527 * xmlTextReaderPrefix:
1528 * @reader: the xmlTextReaderPtr used
1529 *
1530 * A shorthand reference to the namespace associated with the node.
1531 *
1532 * Returns the prefix or NULL if not available
1533 */
1534xmlChar *
1535xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001536 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001537 if ((reader == NULL) || (reader->node == NULL))
1538 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001539 if (reader->curnode != NULL)
1540 node = reader->curnode;
1541 else
1542 node = reader->node;
1543 if (node->type == XML_NAMESPACE_DECL) {
1544 xmlNsPtr ns = (xmlNsPtr) node;
1545 if (ns->prefix == NULL)
1546 return(NULL);
1547 return(xmlStrdup(BAD_CAST "xmlns"));
1548 }
1549 if ((node->type != XML_ELEMENT_NODE) &&
1550 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001551 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001552 if ((node->ns != NULL) || (node->ns->prefix != NULL))
1553 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001554 return(NULL);
1555}
1556
1557/**
1558 * xmlTextReaderNamespaceUri:
1559 * @reader: the xmlTextReaderPtr used
1560 *
1561 * The URI defining the namespace associated with the node.
1562 *
1563 * Returns the namespace URI or NULL if not available
1564 */
1565xmlChar *
1566xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001567 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001568 if ((reader == NULL) || (reader->node == NULL))
1569 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001570 if (reader->curnode != NULL)
1571 node = reader->curnode;
1572 else
1573 node = reader->node;
1574 if (node->type == XML_NAMESPACE_DECL) {
1575 xmlNsPtr ns = (xmlNsPtr) node;
1576 return(xmlStrdup(ns->href));
1577 }
1578 if ((node->type != XML_ELEMENT_NODE) &&
1579 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001580 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001581 if (node->ns != NULL)
1582 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001583 return(NULL);
1584}
1585
1586/**
1587 * xmlTextReaderBaseUri:
1588 * @reader: the xmlTextReaderPtr used
1589 *
1590 * The base URI of the node.
1591 *
1592 * Returns the base URI or NULL if not available
1593 */
1594xmlChar *
1595xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
1596 if ((reader == NULL) || (reader->node == NULL))
1597 return(NULL);
1598 return(xmlNodeGetBase(NULL, reader->node));
1599}
1600
1601/**
1602 * xmlTextReaderDepth:
1603 * @reader: the xmlTextReaderPtr used
1604 *
1605 * The depth of the node in the tree.
1606 *
1607 * Returns the depth or -1 in case of error
1608 */
1609int
1610xmlTextReaderDepth(xmlTextReaderPtr reader) {
1611 if (reader == NULL)
1612 return(-1);
1613 if (reader->node == NULL)
1614 return(0);
1615
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001616 if (reader->curnode != NULL) {
1617 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
1618 (reader->curnode->type == XML_NAMESPACE_DECL))
1619 return(reader->depth + 1);
1620 return(reader->depth + 2);
1621 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001622 return(reader->depth);
1623}
1624
1625/**
1626 * xmlTextReaderHasAttributes:
1627 * @reader: the xmlTextReaderPtr used
1628 *
1629 * Whether the node has attributes.
1630 *
1631 * Returns 1 if true, 0 if false, and -1 in case or error
1632 */
1633int
1634xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001635 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001636 if (reader == NULL)
1637 return(-1);
1638 if (reader->node == NULL)
1639 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001640 if (reader->curnode != NULL)
1641 node = reader->curnode;
1642 else
1643 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001644
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001645 if ((node->type == XML_ELEMENT_NODE) &&
1646 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001647 return(1);
1648 /* TODO: handle the xmlDecl */
1649 return(0);
1650}
1651
1652/**
1653 * xmlTextReaderHasValue:
1654 * @reader: the xmlTextReaderPtr used
1655 *
1656 * Whether the node can have a text value.
1657 *
1658 * Returns 1 if true, 0 if false, and -1 in case or error
1659 */
1660int
1661xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001662 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001663 if (reader == NULL)
1664 return(-1);
1665 if (reader->node == NULL)
1666 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001667 if (reader->curnode != NULL)
1668 node = reader->curnode;
1669 else
1670 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001671
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001672 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001673 case XML_ATTRIBUTE_NODE:
1674 case XML_TEXT_NODE:
1675 case XML_CDATA_SECTION_NODE:
1676 case XML_PI_NODE:
1677 case XML_COMMENT_NODE:
1678 return(1);
1679 default:
1680 return(0);
1681 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001682 return(0);
1683}
1684
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001685/**
1686 * xmlTextReaderValue:
1687 * @reader: the xmlTextReaderPtr used
1688 *
1689 * Provides the text value of the node if present
1690 *
1691 * Returns the string or NULL if not available. The retsult must be deallocated
1692 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001693 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001694xmlChar *
1695xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001696 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001697 if (reader == NULL)
1698 return(NULL);
1699 if (reader->node == NULL)
1700 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001701 if (reader->curnode != NULL)
1702 node = reader->curnode;
1703 else
1704 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001705
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001706 switch (node->type) {
1707 case XML_NAMESPACE_DECL:
1708 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001709 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001710 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001711
1712 if (attr->parent != NULL)
1713 return (xmlNodeListGetString
1714 (attr->parent->doc, attr->children, 1));
1715 else
1716 return (xmlNodeListGetString(NULL, attr->children, 1));
1717 break;
1718 }
1719 case XML_TEXT_NODE:
1720 case XML_CDATA_SECTION_NODE:
1721 case XML_PI_NODE:
1722 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001723 if (node->content != NULL)
1724 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001725 default:
1726 return(NULL);
1727 }
1728 return(NULL);
1729}
1730
1731/**
1732 * xmlTextReaderIsDefault:
1733 * @reader: the xmlTextReaderPtr used
1734 *
1735 * Whether an Attribute node was generated from the default value
1736 * defined in the DTD or schema.
1737 *
1738 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
1739 */
1740int
1741xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
1742 if (reader == NULL)
1743 return(-1);
1744 return(0);
1745}
1746
1747/**
1748 * xmlTextReaderQuoteChar:
1749 * @reader: the xmlTextReaderPtr used
1750 *
1751 * The quotation mark character used to enclose the value of an attribute.
1752 *
1753 * Returns " or ' and -1 in case of error
1754 */
1755int
1756xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
1757 if (reader == NULL)
1758 return(-1);
1759 /* TODO maybe lookup the attribute value for " first */
1760 return((int) '"');
1761}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001762
1763/**
1764 * xmlTextReaderXmlLang:
1765 * @reader: the xmlTextReaderPtr used
1766 *
1767 * The xml:lang scope within which the node resides.
1768 *
1769 * Returns the xml:lang value or NULL if none exists.
1770 */
1771xmlChar *
1772xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
1773 if (reader == NULL)
1774 return(NULL);
1775 if (reader->node == NULL)
1776 return(NULL);
1777 return(xmlNodeGetLang(reader->node));
1778}
1779
Daniel Veillard67df8092002-12-16 22:04:11 +00001780/**
1781 * xmlTextReaderNormalization:
1782 * @reader: the xmlTextReaderPtr used
1783 *
1784 * The value indicating whether to normalize white space and attribute values.
1785 * Since attribute value and end of line normalizations are a MUST in the XML
1786 * specification only the value true is accepted. The broken bahaviour of
1787 * accepting out of range character entities like &#0; is of course not
1788 * supported either.
1789 *
1790 * Returns 1 or -1 in case of error.
1791 */
1792int
1793xmlTextReaderNormalization(xmlTextReaderPtr reader) {
1794 if (reader == NULL)
1795 return(-1);
1796 return(1);
1797}
1798
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001799/************************************************************************
1800 * *
1801 * Extensions to the base APIs *
1802 * *
1803 ************************************************************************/
1804
1805/**
1806 * xmlTextReaderSetParserProp:
1807 * @reader: the xmlTextReaderPtr used
1808 * @prop: the xmlParserProperties to set
1809 * @value: usually 0 or 1 to (de)activate it
1810 *
1811 * Change the parser processing behaviour by changing some of its internal
1812 * properties. Note that some properties can only be changed before any
1813 * read has been done.
1814 *
1815 * Returns 0 if the call was successful, or -1 in case of error
1816 */
1817int
1818xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
1819 xmlParserProperties p = (xmlParserProperties) prop;
1820 xmlParserCtxtPtr ctxt;
1821
1822 if ((reader == NULL) || (reader->ctxt == NULL))
1823 return(-1);
1824 ctxt = reader->ctxt;
1825
1826 switch (p) {
1827 case XML_PARSER_LOADDTD:
1828 if (value != 0) {
1829 if (ctxt->loadsubset == 0) {
1830 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
1831 return(-1);
1832 ctxt->loadsubset = XML_DETECT_IDS;
1833 }
1834 } else {
1835 ctxt->loadsubset = 0;
1836 }
1837 return(0);
1838 case XML_PARSER_DEFAULTATTRS:
1839 if (value != 0) {
1840 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
1841 } else {
1842 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1843 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
1844 }
1845 return(0);
1846 case XML_PARSER_VALIDATE:
1847 if (value != 0) {
1848 ctxt->validate = 1;
1849 } else {
1850 ctxt->validate = 0;
1851 }
1852 return(0);
1853 }
1854 return(-1);
1855}
1856
1857/**
1858 * xmlTextReaderGetParserProp:
1859 * @reader: the xmlTextReaderPtr used
1860 * @prop: the xmlParserProperties to get
1861 *
1862 * Read the parser internal property.
1863 *
1864 * Returns the value, usually 0 or 1, or -1 in case of error.
1865 */
1866int
1867xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
1868 xmlParserProperties p = (xmlParserProperties) prop;
1869 xmlParserCtxtPtr ctxt;
1870
1871 if ((reader == NULL) || (reader->ctxt == NULL))
1872 return(-1);
1873 ctxt = reader->ctxt;
1874
1875 switch (p) {
1876 case XML_PARSER_LOADDTD:
1877 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
1878 return(1);
1879 return(0);
1880 case XML_PARSER_DEFAULTATTRS:
1881 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1882 return(1);
1883 return(0);
1884 case XML_PARSER_VALIDATE:
1885 return(ctxt->validate);
1886 }
1887 return(-1);
1888}
1889
1890/************************************************************************
1891 * *
1892 * Utilities *
1893 * *
1894 ************************************************************************/
1895/**
1896 * xmlBase64Decode:
1897 * @in: the input buffer
1898 * @inlen: the size of the input (in), the size read from it (out)
1899 * @to: the output buffer
1900 * @tolen: the size of the output (in), the size written to (out)
1901 *
1902 * Base64 decoder, reads from @in and save in @to
1903 *
1904 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
1905 * 2 if there wasn't enough space on the output or -1 in case of error.
1906 */
1907static int
1908xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
1909 unsigned char *to, unsigned long *tolen) {
1910 unsigned long incur; /* current index in in[] */
1911 unsigned long inblk; /* last block index in in[] */
1912 unsigned long outcur; /* current index in out[] */
1913 unsigned long inmax; /* size of in[] */
1914 unsigned long outmax; /* size of out[] */
1915 unsigned char cur; /* the current value read from in[] */
1916 unsigned char intmp[3], outtmp[4]; /* temporary buffers for the convert */
1917 int nbintmp; /* number of byte in intmp[] */
1918 int is_ignore; /* cur should be ignored */
1919 int is_end = 0; /* the end of the base64 was found */
1920 int retval = 1;
1921 int i;
1922
1923 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
1924 return(-1);
1925
1926 incur = 0;
1927 inblk = 0;
1928 outcur = 0;
1929 inmax = *inlen;
1930 outmax = *tolen;
1931 nbintmp = 0;
1932
1933 while (1) {
1934 if (incur >= inmax)
1935 break;
1936 cur = in[incur++];
1937 is_ignore = 0;
1938 if ((cur >= 'A') && (cur <= 'Z'))
1939 cur = cur - 'A';
1940 else if ((cur >= 'a') && (cur <= 'z'))
1941 cur = cur - 'a' + 26;
1942 else if ((cur >= '0') && (cur <= '9'))
1943 cur = cur - '0' + 52;
1944 else if (cur == '+')
1945 cur = 62;
1946 else if (cur == '/')
1947 cur = 63;
1948 else if (cur == '.')
1949 cur = 0;
1950 else if (cur == '=') /*no op , end of the base64 stream */
1951 is_end = 1;
1952 else {
1953 is_ignore = 1;
1954 if (nbintmp == 0)
1955 inblk = incur;
1956 }
1957
1958 if (!is_ignore) {
1959 int nbouttmp = 3;
1960 int is_break = 0;
1961
1962 if (is_end) {
1963 if (nbintmp == 0)
1964 break;
1965 if ((nbintmp == 1) || (nbintmp == 2))
1966 nbouttmp = 1;
1967 else
1968 nbouttmp = 2;
1969 nbintmp = 3;
1970 is_break = 1;
1971 }
1972 intmp[nbintmp++] = cur;
1973 /*
1974 * if intmp is full, push the 4byte sequence as a 3 byte
1975 * sequence out
1976 */
1977 if (nbintmp == 4) {
1978 nbintmp = 0;
1979 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
1980 outtmp[1] =
1981 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
1982 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
1983 if (outcur + 3 >= outmax) {
1984 retval = 2;
1985 break;
1986 }
1987
1988 for (i = 0; i < nbouttmp; i++)
1989 to[outcur++] = outtmp[i];
1990 inblk = incur;
1991 }
1992
1993 if (is_break) {
1994 retval = 0;
1995 break;
1996 }
1997 }
1998 }
1999
2000 *tolen = outcur;
2001 *inlen = inblk;
2002 return (retval);
2003}
2004
2005/*
2006 * Test routine for the xmlBase64Decode function
2007 */
2008#if 0
2009int main(int argc, char **argv) {
2010 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
2011 char output[100];
2012 char output2[100];
2013 char output3[100];
2014 unsigned long inlen = strlen(input);
2015 unsigned long outlen = 100;
2016 int ret;
2017 unsigned long cons, tmp, tmp2, prod;
2018
2019 /*
2020 * Direct
2021 */
2022 ret = xmlBase64Decode(input, &inlen, output, &outlen);
2023
2024 output[outlen] = 0;
2025 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
2026
2027 /*
2028 * output chunking
2029 */
2030 cons = 0;
2031 prod = 0;
2032 while (cons < inlen) {
2033 tmp = 5;
2034 tmp2 = inlen - cons;
2035
2036 printf("%ld %ld\n", cons, prod);
2037 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
2038 cons += tmp2;
2039 prod += tmp;
2040 printf("%ld %ld\n", cons, prod);
2041 }
2042 output2[outlen] = 0;
2043 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
2044
2045 /*
2046 * input chunking
2047 */
2048 cons = 0;
2049 prod = 0;
2050 while (cons < inlen) {
2051 tmp = 100 - prod;
2052 tmp2 = inlen - cons;
2053 if (tmp2 > 5)
2054 tmp2 = 5;
2055
2056 printf("%ld %ld\n", cons, prod);
2057 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
2058 cons += tmp2;
2059 prod += tmp;
2060 printf("%ld %ld\n", cons, prod);
2061 }
2062 output3[outlen] = 0;
2063 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
2064 return(0);
2065
2066}
2067#endif