blob: 1d65df6bc5dd74249eebbcf69b875a81317e6c30 [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 Veillarddf512f42002-12-23 15:56:21 +000094 int wasempty;/* was the last node empty */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000095};
96
97#ifdef DEBUG_READER
98static void
99xmlTextReaderDebug(xmlTextReaderPtr reader) {
100 if ((reader == NULL) || (reader->ctxt == NULL)) {
101 fprintf(stderr, "xmlTextReader NULL\n");
102 return;
103 }
104 fprintf(stderr, "xmlTextReader: state %d depth %d ",
105 reader->state, reader->depth);
106 if (reader->node == NULL) {
107 fprintf(stderr, "node = NULL\n");
108 } else {
109 fprintf(stderr, "node %s\n", reader->node->name);
110 }
111 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
112 reader->base, reader->cur, reader->ctxt->nodeNr);
113 if (reader->input->buffer == NULL) {
114 fprintf(stderr, "buffer is NULL\n");
115 } else {
116#ifdef LIBXML_DEBUG_ENABLED
117 xmlDebugDumpString(stderr,
118 &reader->input->buffer->content[reader->cur]);
119#endif
120 fprintf(stderr, "\n");
121 }
122}
123#endif
124
125/**
126 * xmlTextReaderStartElement:
127 * @ctx: the user data (XML parser context)
128 * @fullname: The element name, including namespace prefix
129 * @atts: An array of name/value attributes pairs, NULL terminated
130 *
131 * called when an opening tag has been processed.
132 */
133static void
134xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
135 const xmlChar **atts) {
136 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000137 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000138 xmlTextReaderPtr reader = ctxt->_private;
139
140#ifdef DEBUG_CALLBACKS
141 printf("xmlTextReaderStartElement(%s)\n", fullname);
142#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000143 if ((reader != NULL) && (reader->startElement != NULL)) {
Daniel Veillardd5896142002-12-31 14:45:26 +0000144 /*
145 * when processing an entity, the context may have been changed
146 */
147 origctxt = reader->ctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000148 reader->startElement(ctx, fullname, atts);
Daniel Veillardd5896142002-12-31 14:45:26 +0000149 if (origctxt->validate) {
150 ctxt->valid &= xmlValidatePushElement(&origctxt->vctxt,
151 ctxt->myDoc, ctxt->node, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000152 }
153 }
Daniel Veillard9e395c22003-01-01 14:50:44 +0000154 if (reader != NULL)
155 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000156}
157
158/**
159 * xmlTextReaderEndElement:
160 * @ctx: the user data (XML parser context)
161 * @fullname: The element name, including namespace prefix
162 *
163 * called when an ending tag has been processed.
164 */
165static void
166xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
167 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000168 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000169 xmlTextReaderPtr reader = ctxt->_private;
170
171#ifdef DEBUG_CALLBACKS
172 printf("xmlTextReaderEndElement(%s)\n", fullname);
173#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000174 if ((reader != NULL) && (reader->endElement != NULL)) {
175 xmlNodePtr node = ctxt->node;
Daniel Veillardd5896142002-12-31 14:45:26 +0000176 /*
177 * when processing an entity, the context may have been changed
178 */
179 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000180
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000181 reader->endElement(ctx, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000182
Daniel Veillardd5896142002-12-31 14:45:26 +0000183 if (origctxt->validate) {
184 ctxt->valid &= xmlValidatePopElement(&origctxt->vctxt,
185 ctxt->myDoc, node, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000186 }
187 }
Daniel Veillard9e395c22003-01-01 14:50:44 +0000188 if (reader != NULL) {
189 if (reader->state == XML_TEXTREADER_ELEMENT)
190 reader->wasempty = 1;
191 else
192 reader->wasempty = 0;
193 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000194}
195
196/**
Daniel Veillardea7751d2002-12-20 00:16:24 +0000197 * xmlTextReaderCharacters:
198 * @ctx: the user data (XML parser context)
199 * @ch: a xmlChar string
200 * @len: the number of xmlChar
201 *
202 * receiving some chars from the parser.
203 */
204static void
205xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
206{
207 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000208 xmlParserCtxtPtr origctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000209 xmlTextReaderPtr reader = ctxt->_private;
210
211#ifdef DEBUG_CALLBACKS
212 printf("xmlTextReaderCharacters()\n");
213#endif
214 if ((reader != NULL) && (reader->characters != NULL)) {
215 reader->characters(ctx, ch, len);
Daniel Veillardd5896142002-12-31 14:45:26 +0000216 /*
217 * when processing an entity, the context may have been changed
218 */
219 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000220
Daniel Veillardd5896142002-12-31 14:45:26 +0000221 if (origctxt->validate) {
222 ctxt->valid &= xmlValidatePushCData(&origctxt->vctxt, ch, len);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000223 }
224 }
225}
226
227/**
228 * xmlTextReaderCDataBlock:
229 * @ctx: the user data (XML parser context)
230 * @value: The pcdata content
231 * @len: the block length
232 *
233 * called when a pcdata block has been parsed
234 */
235static void
236xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
237{
238 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
239 xmlTextReaderPtr reader = ctxt->_private;
240
241#ifdef DEBUG_CALLBACKS
242 printf("xmlTextReaderCDataBlock()\n");
243#endif
244 if ((reader != NULL) && (reader->cdataBlock != NULL)) {
245 reader->cdataBlock(ctx, ch, len);
246
247 if (ctxt->validate) {
248 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt, ch, len);
249 }
250 }
251}
252
253/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000254 * xmlTextReaderPushData:
255 * @reader: the xmlTextReaderPtr used
256 *
257 * Push data down the progressive parser until a significant callback
258 * got raised.
259 *
260 * Returns -1 in case of failure, 0 otherwise
261 */
262static int
263xmlTextReaderPushData(xmlTextReaderPtr reader) {
264 unsigned int cur = reader->cur;
265 xmlBufferPtr inbuf;
266 int val;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000267 int oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000268
269 if ((reader->input == NULL) || (reader->input->buffer == NULL))
270 return(-1);
271
Daniel Veillardea7751d2002-12-20 00:16:24 +0000272 oldstate = reader->state;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000273 reader->state = XML_TEXTREADER_NONE;
274 inbuf = reader->input->buffer;
275 while (reader->state == XML_TEXTREADER_NONE) {
276 if (cur >= inbuf->use) {
277 /*
278 * Refill the buffer unless we are at the end of the stream
279 */
280 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
281 val = xmlParserInputBufferRead(reader->input, 4096);
282 if (val <= 0) {
283 reader->mode = XML_TEXTREADER_MODE_EOF;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000284 reader->state = oldstate;
Daniel Veillardaaa105b2002-12-30 11:42:17 +0000285 if ((oldstate != XML_TEXTREADER_START) ||
286 (reader->ctxt->myDoc != NULL))
287 return(val);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000288 }
289 } else
290 break;
291 }
292 if ((inbuf->content[cur] == '>') || (inbuf->content[cur] == '&')) {
293 cur = cur + 1;
294 val = xmlParseChunk(reader->ctxt,
295 (const char *) &inbuf->content[reader->cur],
296 cur - reader->cur, 0);
297 if (val != 0)
298 return(-1);
299 reader->cur = cur;
300 break;
301 } else {
302 cur = cur + 1;
303
304 /*
305 * One may have to force a flush at some point when parsing really
306 * large CDATA sections
307 */
308 if ((cur - reader->cur > 4096) && (reader->base == 0) &&
Daniel Veillard67df8092002-12-16 22:04:11 +0000309 (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000310 cur = cur + 1;
311 val = xmlParseChunk(reader->ctxt,
312 (const char *) &inbuf->content[reader->cur],
313 cur - reader->cur, 0);
314 if (val != 0)
315 return(-1);
316 reader->cur = cur;
317 }
318 }
319 }
320 /*
321 * Discard the consumed input when needed and possible
322 */
Daniel Veillard67df8092002-12-16 22:04:11 +0000323 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000324 if ((reader->cur >= 4096) && (reader->base == 0)) {
325 val = xmlBufferShrink(inbuf, cur);
326 if (val >= 0) {
327 reader->cur -= val;
328 }
329 }
330 }
331
332 /*
333 * At the end of the stream signal that the work is done to the Push
334 * parser.
335 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000336 if (reader->mode == XML_TEXTREADER_MODE_EOF) {
337 if (reader->mode != XML_TEXTREADER_DONE) {
338 val = xmlParseChunk(reader->ctxt,
339 (const char *) &inbuf->content[reader->cur], 0, 1);
340 reader->mode = XML_TEXTREADER_DONE;
341 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000342 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000343 reader->state = oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000344 return(0);
345}
346
347/**
348 * xmlTextReaderRead:
349 * @reader: the xmlTextReaderPtr used
350 *
351 * Moves the position of the current instance to the next node in
352 * the stream, exposing its properties.
353 *
354 * Returns 1 if the node was read successfully, 0 if there is no more
355 * nodes to read, or -1 in case of error
356 */
357int
358xmlTextReaderRead(xmlTextReaderPtr reader) {
Daniel Veillarddf512f42002-12-23 15:56:21 +0000359 int val, olddepth, wasempty;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000360 xmlTextReaderState oldstate;
361 xmlNodePtr oldnode;
362
363 if ((reader == NULL) || (reader->ctxt == NULL))
364 return(-1);
365 if (reader->ctxt->wellFormed != 1)
366 return(-1);
367
368#ifdef DEBUG_READER
369 fprintf(stderr, "\nREAD ");
370 DUMP_READER
371#endif
Daniel Veillard29b3e282002-12-29 11:14:41 +0000372 reader->curnode = NULL;
Daniel Veillard67df8092002-12-16 22:04:11 +0000373 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
374 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000375 /*
376 * Initial state
377 */
378 do {
379 val = xmlTextReaderPushData(reader);
380 if (val < 0)
381 return(-1);
382 } while ((reader->ctxt->node == NULL) &&
383 (reader->mode != XML_TEXTREADER_MODE_EOF));
384 if (reader->ctxt->node == NULL) {
385 if (reader->ctxt->myDoc != NULL)
386 reader->node = reader->ctxt->myDoc->children;
387 if (reader->node == NULL)
388 return(-1);
389 } else {
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000390 reader->node = reader->ctxt->nodeTab[0];
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000391 }
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000392 reader->depth = 0;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000393 return(1);
394 }
395 oldstate = reader->state;
396 olddepth = reader->ctxt->nodeNr;
397 oldnode = reader->node;
Daniel Veillarde3c036e2003-01-01 15:11:05 +0000398 wasempty = (((reader->wasempty == 1) && (reader->ctxt->node != NULL) &&
399 (reader->ctxt->node->last == reader->node)) ||
400 (reader->node != reader->ctxt->node));
Daniel Veillarddf512f42002-12-23 15:56:21 +0000401
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000402 /*
403 * If we are not backtracking on ancestors or examined nodes,
404 * that the parser didn't finished or that we arent at the end
405 * of stream, continue processing.
406 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000407 while (((oldstate == XML_TEXTREADER_BACKTRACK) ||
408 (reader->node->children == NULL) ||
409 (reader->node->type == XML_ENTITY_REF_NODE) ||
410 (reader->node->type == XML_DTD_NODE)) &&
411 (reader->node->next == NULL) &&
412 (reader->ctxt->nodeNr == olddepth) &&
413 (reader->ctxt->instate != XML_PARSER_EOF)) {
414 val = xmlTextReaderPushData(reader);
415 if (val < 0)
416 return(-1);
417 if (reader->node == NULL)
418 return(0);
419 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000420 if (oldstate != XML_TEXTREADER_BACKTRACK) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000421 if ((reader->node->children != NULL) &&
422 (reader->node->type != XML_ENTITY_REF_NODE) &&
423 (reader->node->type != XML_DTD_NODE)) {
424 reader->node = reader->node->children;
425 reader->depth++;
Daniel Veillarddf512f42002-12-23 15:56:21 +0000426 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000427 DUMP_READER
428 return(1);
429 }
430 }
431 if (reader->node->next != NULL) {
432 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillarddf512f42002-12-23 15:56:21 +0000433 (reader->node->type == XML_ELEMENT_NODE) &&
434 (wasempty == 0)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000435 reader->state = XML_TEXTREADER_END;
436 DUMP_READER
437 return(1);
438 }
439 reader->node = reader->node->next;
440 reader->state = XML_TEXTREADER_ELEMENT;
441 DUMP_READER
442 /*
443 * Cleanup of the old node
444 */
445 if (oldnode->type != XML_DTD_NODE) {
446 xmlUnlinkNode(oldnode);
447 xmlFreeNode(oldnode);
448 }
449
450 return(1);
451 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000452 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillard571b8892002-12-30 12:37:59 +0000453 (reader->node->type == XML_ELEMENT_NODE) &&
454 (wasempty == 0)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000455 reader->state = XML_TEXTREADER_END;
456 DUMP_READER
457 return(1);
458 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000459 reader->node = reader->node->parent;
460 if ((reader->node == NULL) ||
461 (reader->node->type == XML_DOCUMENT_NODE) ||
462#ifdef LIBXML_DOCB_ENABLED
463 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
464#endif
465 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000466 if (reader->mode != XML_TEXTREADER_DONE) {
467 val = xmlParseChunk(reader->ctxt, "", 0, 1);
468 reader->mode = XML_TEXTREADER_DONE;
469 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000470 reader->node = NULL;
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000471 reader->depth = -1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000472
473 /*
474 * Cleanup of the old node
475 */
476 if (oldnode->type != XML_DTD_NODE) {
477 xmlUnlinkNode(oldnode);
478 xmlFreeNode(oldnode);
479 }
480
481 return(0);
482 }
483 reader->depth--;
484 reader->state = XML_TEXTREADER_BACKTRACK;
485 DUMP_READER
486 return(1);
487}
488
Daniel Veillard67df8092002-12-16 22:04:11 +0000489/**
490 * xmlTextReaderReadState:
491 * @reader: the xmlTextReaderPtr used
492 *
493 * Gets the read state of the reader.
494 *
495 * Returns the state value, or -1 in case of error
496 */
497int
498xmlTextReaderReadState(xmlTextReaderPtr reader) {
499 if (reader == NULL)
500 return(-1);
501 return(reader->mode);
502}
503
504/**
505 * xmlTextReaderReadInnerXml:
506 * @reader: the xmlTextReaderPtr used
507 *
508 * Reads the contents of the current node, including child nodes and markup.
509 *
510 * Returns a string containing the XML content, or NULL if the current node
511 * is neither an element nor attribute, or has no child nodes. The
512 * string must be deallocated by the caller.
513 */
514xmlChar *
515xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) {
516 TODO
517 return(NULL);
518}
519
520/**
521 * xmlTextReaderReadOuterXml:
522 * @reader: the xmlTextReaderPtr used
523 *
524 * Reads the contents of the current node, including child nodes and markup.
525 *
526 * Returns a string containing the XML content, or NULL if the current node
527 * is neither an element nor attribute, or has no child nodes. The
528 * string must be deallocated by the caller.
529 */
530xmlChar *
531xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) {
532 TODO
533 return(NULL);
534}
535
536/**
537 * xmlTextReaderReadString:
538 * @reader: the xmlTextReaderPtr used
539 *
540 * Reads the contents of an element or a text node as a string.
541 *
542 * Returns a string containing the contents of the Element or Text node,
543 * or NULL if the reader is positioned on any other type of node.
544 * The string must be deallocated by the caller.
545 */
546xmlChar *
547xmlTextReaderReadString(xmlTextReaderPtr reader) {
548 TODO
549 return(NULL);
550}
551
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000552/**
553 * xmlTextReaderReadBase64:
554 * @reader: the xmlTextReaderPtr used
555 * @array: a byte array to store the content.
556 * @offset: the zero-based index into array where the method should
557 * begin to write.
558 * @len: the number of bytes to write.
559 *
560 * Reads and decodes the Base64 encoded contents of an element and
561 * stores the result in a byte buffer.
562 *
563 * Returns the number of bytes written to array, or zero if the current
564 * instance is not positioned on an element or -1 in case of error.
565 */
566int
567xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
568 int offset, int len) {
569 if ((reader == NULL) || (reader->ctxt == NULL))
570 return(-1);
571 if (reader->ctxt->wellFormed != 1)
572 return(-1);
573
574 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
575 return(0);
576 TODO
577 return(0);
578}
579
580/**
581 * xmlTextReaderReadBinHex:
582 * @reader: the xmlTextReaderPtr used
583 * @array: a byte array to store the content.
584 * @offset: the zero-based index into array where the method should
585 * begin to write.
586 * @len: the number of bytes to write.
587 *
588 * Reads and decodes the BinHex encoded contents of an element and
589 * stores the result in a byte buffer.
590 *
591 * Returns the number of bytes written to array, or zero if the current
592 * instance is not positioned on an element or -1 in case of error.
593 */
594int
595xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
596 int offset, int len) {
597 if ((reader == NULL) || (reader->ctxt == NULL))
598 return(-1);
599 if (reader->ctxt->wellFormed != 1)
600 return(-1);
601
602 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
603 return(0);
604 TODO
605 return(0);
606}
607
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000608/************************************************************************
609 * *
610 * Constructor and destructors *
611 * *
612 ************************************************************************/
613/**
614 * xmlNewTextReader:
615 * @input: the xmlParserInputBufferPtr used to read data
Daniel Veillardea7751d2002-12-20 00:16:24 +0000616 * @URI: the URI information for the source if available
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000617 *
618 * Create an xmlTextReader structure fed with @input
619 *
620 * Returns the new xmlTextReaderPtr or NULL in case of error
621 */
622xmlTextReaderPtr
Daniel Veillardea7751d2002-12-20 00:16:24 +0000623xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000624 xmlTextReaderPtr ret;
625 int val;
626
627 if (input == NULL)
628 return(NULL);
629 ret = xmlMalloc(sizeof(xmlTextReader));
630 if (ret == NULL) {
631 xmlGenericError(xmlGenericErrorContext,
632 "xmlNewTextReader : malloc failed\n");
633 return(NULL);
634 }
635 memset(ret, 0, sizeof(xmlTextReader));
636 ret->input = input;
637 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
638 if (ret->sax == NULL) {
639 xmlFree(ret);
640 xmlGenericError(xmlGenericErrorContext,
641 "xmlNewTextReader : malloc failed\n");
642 return(NULL);
643 }
644 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
645 ret->startElement = ret->sax->startElement;
646 ret->sax->startElement = xmlTextReaderStartElement;
647 ret->endElement = ret->sax->endElement;
648 ret->sax->endElement = xmlTextReaderEndElement;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000649 ret->characters = ret->sax->characters;
650 ret->sax->characters = xmlTextReaderCharacters;
651 ret->cdataBlock = ret->sax->cdataBlock;
652 ret->sax->cdataBlock = xmlTextReaderCDataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000653
Daniel Veillard67df8092002-12-16 22:04:11 +0000654 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000655 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000656 ret->curnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000657 val = xmlParserInputBufferRead(input, 4);
658 if (val >= 4) {
659 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
Daniel Veillardea7751d2002-12-20 00:16:24 +0000660 (const char *) ret->input->buffer->content, 4, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000661 ret->base = 0;
662 ret->cur = 4;
663 } else {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000664 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000665 ret->base = 0;
666 ret->cur = 0;
667 }
668 ret->ctxt->_private = ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000669 ret->ctxt->linenumbers = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000670 ret->allocs = XML_TEXTREADER_CTXT;
671 return(ret);
672
673}
674
675/**
676 * xmlNewTextReaderFilename:
677 * @URI: the URI of the resource to process
678 *
679 * Create an xmlTextReader structure fed with the resource at @URI
680 *
681 * Returns the new xmlTextReaderPtr or NULL in case of error
682 */
683xmlTextReaderPtr
684xmlNewTextReaderFilename(const char *URI) {
685 xmlParserInputBufferPtr input;
686 xmlTextReaderPtr ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000687 char *directory = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000688
689 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
690 if (input == NULL)
691 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000692 ret = xmlNewTextReader(input, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000693 if (ret == NULL) {
694 xmlFreeParserInputBuffer(input);
695 return(NULL);
696 }
697 ret->allocs |= XML_TEXTREADER_INPUT;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000698 if (ret->ctxt->directory == NULL)
699 directory = xmlParserGetDirectory(URI);
700 if ((ret->ctxt->directory == NULL) && (directory != NULL))
701 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
702 if (directory != NULL)
703 xmlFree(directory);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000704 return(ret);
705}
706
707/**
708 * xmlFreeTextReader:
709 * @reader: the xmlTextReaderPtr
710 *
711 * Deallocate all the resources associated to the reader
712 */
713void
714xmlFreeTextReader(xmlTextReaderPtr reader) {
715 if (reader == NULL)
716 return;
717 if (reader->ctxt != NULL) {
718 if (reader->ctxt->myDoc != NULL) {
719 xmlFreeDoc(reader->ctxt->myDoc);
720 reader->ctxt->myDoc = NULL;
721 }
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000722 if ((reader->ctxt->vctxt.vstateTab != NULL) &&
723 (reader->ctxt->vctxt.vstateMax > 0)){
724 xmlFree(reader->ctxt->vctxt.vstateTab);
725 reader->ctxt->vctxt.vstateTab = 0;
726 reader->ctxt->vctxt.vstateMax = 0;
727 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000728 if (reader->allocs & XML_TEXTREADER_CTXT)
729 xmlFreeParserCtxt(reader->ctxt);
730 }
731 if (reader->sax != NULL)
732 xmlFree(reader->sax);
733 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
734 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000735 if (reader->faketext != NULL) {
736 xmlFreeNode(reader->faketext);
737 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000738 xmlFree(reader);
739}
740
741/************************************************************************
742 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000743 * Methods for XmlTextReader *
744 * *
745 ************************************************************************/
746/**
747 * xmlTextReaderClose:
748 * @reader: the xmlTextReaderPtr used
749 *
750 * This method releases any resources allocated by the current instance
751 * changes the state to Closed and close any underlying input.
752 *
753 * Returns 0 or -1 in case of error
754 */
755int
756xmlTextReaderClose(xmlTextReaderPtr reader) {
757 if (reader == NULL)
758 return(-1);
759 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000760 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000761 reader->mode = XML_TEXTREADER_MODE_CLOSED;
762 if (reader->ctxt != NULL) {
763 if (reader->ctxt->myDoc != NULL) {
764 xmlFreeDoc(reader->ctxt->myDoc);
765 reader->ctxt->myDoc = NULL;
766 }
767 if (reader->allocs & XML_TEXTREADER_CTXT) {
768 xmlFreeParserCtxt(reader->ctxt);
769 reader->allocs -= XML_TEXTREADER_CTXT;
770 }
771 }
772 if (reader->sax != NULL) {
773 xmlFree(reader->sax);
774 reader->sax = NULL;
775 }
776 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
777 xmlFreeParserInputBuffer(reader->input);
778 reader->allocs -= XML_TEXTREADER_INPUT;
779 }
780 return(0);
781}
782
783/**
784 * xmlTextReaderGetAttributeNo:
785 * @reader: the xmlTextReaderPtr used
786 * @no: the zero-based index of the attribute relative to the containing element
787 *
788 * Provides the value of the attribute with the specified index relative
789 * to the containing element.
790 *
791 * Returns a string containing the value of the specified attribute, or NULL
792 * in case of error. The string must be deallocated by the caller.
793 */
794xmlChar *
795xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
796 xmlChar *ret;
797 int i;
798 xmlAttrPtr cur;
799 xmlNsPtr ns;
800
801 if (reader == NULL)
802 return(NULL);
803 if (reader->node == NULL)
804 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000805 if (reader->curnode != NULL)
806 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000807 /* TODO: handle the xmlDecl */
808 if (reader->node->type != XML_ELEMENT_NODE)
809 return(NULL);
810
811 ns = reader->node->nsDef;
812 for (i = 0;(i < no) && (ns != NULL);i++) {
813 ns = ns->next;
814 }
815 if (ns != NULL)
816 return(xmlStrdup(ns->href));
817
818 cur = reader->node->properties;
819 if (cur == NULL)
820 return(NULL);
821 for (;i < no;i++) {
822 cur = cur->next;
823 if (cur == NULL)
824 return(NULL);
825 }
826 /* TODO walk the DTD if present */
827
828 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
829 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
830 return(ret);
831}
832
833/**
834 * xmlTextReaderGetAttribute:
835 * @reader: the xmlTextReaderPtr used
836 * @name: the qualified name of the attribute.
837 *
838 * Provides the value of the attribute with the specified qualified name.
839 *
840 * Returns a string containing the value of the specified attribute, or NULL
841 * in case of error. The string must be deallocated by the caller.
842 */
843xmlChar *
844xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
845 xmlChar *prefix = NULL;
846 xmlChar *localname;
847 xmlNsPtr ns;
848 xmlChar *ret = NULL;
849
850 if ((reader == NULL) || (name == NULL))
851 return(NULL);
852 if (reader->node == NULL)
853 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000854 if (reader->curnode != NULL)
855 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000856
857 /* TODO: handle the xmlDecl */
858 if (reader->node->type != XML_ELEMENT_NODE)
859 return(NULL);
860
861 localname = xmlSplitQName2(name, &prefix);
862 if (localname == NULL)
863 return(xmlGetProp(reader->node, name));
864
865 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
866 if (ns != NULL)
867 ret = xmlGetNsProp(reader->node, localname, ns->href);
868
869 if (localname != NULL)
870 xmlFree(localname);
871 if (prefix != NULL)
872 xmlFree(prefix);
873 return(ret);
874}
875
876
877/**
878 * xmlTextReaderGetAttributeNs:
879 * @reader: the xmlTextReaderPtr used
880 * @localName: the local name of the attribute.
881 * @namespaceURI: the namespace URI of the attribute.
882 *
883 * Provides the value of the specified attribute
884 *
885 * Returns a string containing the value of the specified attribute, or NULL
886 * in case of error. The string must be deallocated by the caller.
887 */
888xmlChar *
889xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
890 const xmlChar *namespaceURI) {
891 if ((reader == NULL) || (localName == NULL))
892 return(NULL);
893 if (reader->node == NULL)
894 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000895 if (reader->curnode != NULL)
896 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000897
898 /* TODO: handle the xmlDecl */
899 if (reader->node->type != XML_ELEMENT_NODE)
900 return(NULL);
901
902 return(xmlGetNsProp(reader->node, localName, namespaceURI));
903}
904
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000905/**
906 * xmlTextReaderGetRemainder:
907 * @reader: the xmlTextReaderPtr used
908 *
909 * Method to get the remainder of the buffered XML. this method stops the
910 * parser, set its state to End Of File and return the input stream with
911 * what is left that the parser did not use.
912 *
913 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
914 * in case of error.
915 */
916xmlParserInputBufferPtr
917xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
918 xmlParserInputBufferPtr ret = NULL;
919
920 if (reader == NULL)
921 return(NULL);
922 if (reader->node == NULL)
923 return(NULL);
924
925 reader->node = NULL;
926 reader->curnode = NULL;
927 reader->mode = XML_TEXTREADER_MODE_EOF;
928 if (reader->ctxt != NULL) {
929 if (reader->ctxt->myDoc != NULL) {
930 xmlFreeDoc(reader->ctxt->myDoc);
931 reader->ctxt->myDoc = NULL;
932 }
933 if (reader->allocs & XML_TEXTREADER_CTXT) {
934 xmlFreeParserCtxt(reader->ctxt);
935 reader->allocs -= XML_TEXTREADER_CTXT;
936 }
937 }
938 if (reader->sax != NULL) {
939 xmlFree(reader->sax);
940 reader->sax = NULL;
941 }
942 if (reader->allocs & XML_TEXTREADER_INPUT) {
943 ret = reader->input;
944 reader->allocs -= XML_TEXTREADER_INPUT;
945 } else {
946 /*
947 * Hum, one may need to duplicate the data structure because
948 * without reference counting the input may be freed twice:
949 * - by the layer which allocated it.
950 * - by the layer to which would have been returned to.
951 */
952 TODO
953 return(NULL);
954 }
955 return(ret);
956}
957
958/**
959 * xmlTextReaderLookupNamespace:
960 * @reader: the xmlTextReaderPtr used
961 * @prefix: the prefix whose namespace URI is to be resolved. To return
962 * the default namespace, specify NULL
963 *
964 * Resolves a namespace prefix in the scope of the current element.
965 *
966 * Returns a string containing the namespace URI to which the prefix maps
967 * or NULL in case of error. The string must be deallocated by the caller.
968 */
969xmlChar *
970xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
971 xmlNsPtr ns;
972
973 if (reader == NULL)
974 return(NULL);
975 if (reader->node == NULL)
976 return(NULL);
977
978 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
979 if (ns == NULL)
980 return(NULL);
981 return(xmlStrdup(ns->href));
982}
983
984/**
985 * xmlTextReaderMoveToAttributeNo:
986 * @reader: the xmlTextReaderPtr used
987 * @no: the zero-based index of the attribute relative to the containing
988 * element.
989 *
990 * Moves the position of the current instance to the attribute with
991 * the specified index relative to the containing element.
992 *
993 * Returns 1 in case of success, -1 in case of error, 0 if not found
994 */
995int
996xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
997 int i;
998 xmlAttrPtr cur;
999 xmlNsPtr ns;
1000
1001 if (reader == NULL)
1002 return(-1);
1003 if (reader->node == NULL)
1004 return(-1);
1005 /* TODO: handle the xmlDecl */
1006 if (reader->node->type != XML_ELEMENT_NODE)
1007 return(-1);
1008
1009 reader->curnode = NULL;
1010
1011 ns = reader->node->nsDef;
1012 for (i = 0;(i < no) && (ns != NULL);i++) {
1013 ns = ns->next;
1014 }
1015 if (ns != NULL) {
1016 reader->curnode = (xmlNodePtr) ns;
1017 return(1);
1018 }
1019
1020 cur = reader->node->properties;
1021 if (cur == NULL)
1022 return(0);
1023 for (;i < no;i++) {
1024 cur = cur->next;
1025 if (cur == NULL)
1026 return(0);
1027 }
1028 /* TODO walk the DTD if present */
1029
1030 reader->curnode = (xmlNodePtr) cur;
1031 return(1);
1032}
1033
1034/**
1035 * xmlTextReaderMoveToAttribute:
1036 * @reader: the xmlTextReaderPtr used
1037 * @name: the qualified name of the attribute.
1038 *
1039 * Moves the position of the current instance to the attribute with
1040 * the specified qualified name.
1041 *
1042 * Returns 1 in case of success, -1 in case of error, 0 if not found
1043 */
1044int
1045xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1046 xmlChar *prefix = NULL;
1047 xmlChar *localname;
1048 xmlNsPtr ns;
1049 xmlAttrPtr prop;
1050
1051 if ((reader == NULL) || (name == NULL))
1052 return(-1);
1053 if (reader->node == NULL)
1054 return(-1);
1055
1056 /* TODO: handle the xmlDecl */
1057 if (reader->node->type != XML_ELEMENT_NODE)
1058 return(0);
1059
1060 localname = xmlSplitQName2(name, &prefix);
1061 if (localname == NULL) {
1062 /*
1063 * Namespace default decl
1064 */
1065 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1066 ns = reader->node->nsDef;
1067 while (ns != NULL) {
1068 if (ns->prefix == NULL) {
1069 reader->curnode = (xmlNodePtr) ns;
1070 return(1);
1071 }
1072 ns = ns->next;
1073 }
1074 return(0);
1075 }
1076
1077 prop = reader->node->properties;
1078 while (prop != NULL) {
1079 /*
1080 * One need to have
1081 * - same attribute names
1082 * - and the attribute carrying that namespace
1083 */
1084 if ((xmlStrEqual(prop->name, name)) &&
1085 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
1086 reader->curnode = (xmlNodePtr) prop;
1087 return(1);
1088 }
1089 prop = prop->next;
1090 }
1091 return(0);
1092 }
1093
1094 /*
1095 * Namespace default decl
1096 */
1097 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
1098 ns = reader->node->nsDef;
1099 while (ns != NULL) {
1100 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
1101 reader->curnode = (xmlNodePtr) ns;
1102 goto found;
1103 }
1104 ns = ns->next;
1105 }
1106 goto not_found;
1107 }
1108 prop = reader->node->properties;
1109 while (prop != NULL) {
1110 /*
1111 * One need to have
1112 * - same attribute names
1113 * - and the attribute carrying that namespace
1114 */
1115 if ((xmlStrEqual(prop->name, localname)) &&
1116 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
1117 reader->curnode = (xmlNodePtr) prop;
1118 goto found;
1119 }
1120 prop = prop->next;
1121 }
1122not_found:
1123 if (localname != NULL)
1124 xmlFree(localname);
1125 if (prefix != NULL)
1126 xmlFree(prefix);
1127 return(0);
1128
1129found:
1130 if (localname != NULL)
1131 xmlFree(localname);
1132 if (prefix != NULL)
1133 xmlFree(prefix);
1134 return(1);
1135}
1136
1137/**
1138 * xmlTextReaderMoveToAttributeNs:
1139 * @reader: the xmlTextReaderPtr used
1140 * @localName: the local name of the attribute.
1141 * @namespaceURI: the namespace URI of the attribute.
1142 *
1143 * Moves the position of the current instance to the attribute with the
1144 * specified local name and namespace URI.
1145 *
1146 * Returns 1 in case of success, -1 in case of error, 0 if not found
1147 */
1148int
1149xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1150 const xmlChar *localName, const xmlChar *namespaceURI) {
1151 xmlAttrPtr prop;
1152 xmlNodePtr node;
1153
1154 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1155 return(-1);
1156 if (reader->node == NULL)
1157 return(-1);
1158 if (reader->node->type != XML_ELEMENT_NODE)
1159 return(0);
1160 node = reader->node;
1161
1162 /*
1163 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1164 * namespace name associated to "xmlns"
1165 */
1166 prop = node->properties;
1167 while (prop != NULL) {
1168 /*
1169 * One need to have
1170 * - same attribute names
1171 * - and the attribute carrying that namespace
1172 */
1173 if (xmlStrEqual(prop->name, localName) &&
1174 ((prop->ns != NULL) &&
1175 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1176 reader->curnode = (xmlNodePtr) prop;
1177 return(1);
1178 }
1179 prop = prop->next;
1180 }
1181 return(0);
1182}
1183
1184/**
1185 * xmlTextReaderMoveToFirstAttribute:
1186 * @reader: the xmlTextReaderPtr used
1187 *
1188 * Moves the position of the current instance to the first attribute
1189 * associated with the current node.
1190 *
1191 * Returns 1 in case of success, -1 in case of error, 0 if not found
1192 */
1193int
1194xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1195 if (reader == NULL)
1196 return(-1);
1197 if (reader->node == NULL)
1198 return(-1);
1199 if (reader->node->type != XML_ELEMENT_NODE)
1200 return(0);
1201
1202 if (reader->node->nsDef != NULL) {
1203 reader->curnode = (xmlNodePtr) reader->node->nsDef;
1204 return(1);
1205 }
1206 if (reader->node->properties != NULL) {
1207 reader->curnode = (xmlNodePtr) reader->node->properties;
1208 return(1);
1209 }
1210 return(0);
1211}
1212
1213/**
1214 * xmlTextReaderMoveToNextAttribute:
1215 * @reader: the xmlTextReaderPtr used
1216 *
1217 * Moves the position of the current instance to the next attribute
1218 * associated with the current node.
1219 *
1220 * Returns 1 in case of success, -1 in case of error, 0 if not found
1221 */
1222int
1223xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1224 if (reader == NULL)
1225 return(-1);
1226 if (reader->node == NULL)
1227 return(-1);
1228 if (reader->node->type != XML_ELEMENT_NODE)
1229 return(0);
1230 if (reader->curnode == NULL)
1231 return(xmlTextReaderMoveToFirstAttribute(reader));
1232
1233 if (reader->curnode->type == XML_NAMESPACE_DECL) {
1234 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1235 if (ns->next != NULL) {
1236 reader->curnode = (xmlNodePtr) ns->next;
1237 return(1);
1238 }
1239 if (reader->node->properties != NULL) {
1240 reader->curnode = (xmlNodePtr) reader->node->properties;
1241 return(1);
1242 }
1243 return(0);
1244 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1245 (reader->curnode->next != NULL)) {
1246 reader->curnode = reader->curnode->next;
1247 return(1);
1248 }
1249 return(0);
1250}
1251
1252/**
1253 * xmlTextReaderMoveToElement:
1254 * @reader: the xmlTextReaderPtr used
1255 *
1256 * Moves the position of the current instance to the node that
1257 * contains the current Attribute node.
1258 *
1259 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1260 */
1261int
1262xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
1263 if (reader == NULL)
1264 return(-1);
1265 if (reader->node == NULL)
1266 return(-1);
1267 if (reader->node->type != XML_ELEMENT_NODE)
1268 return(0);
1269 if (reader->curnode != NULL) {
1270 reader->curnode = NULL;
1271 return(1);
1272 }
1273 return(0);
1274}
1275
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001276/**
1277 * xmlTextReaderReadAttributeValue:
1278 * @reader: the xmlTextReaderPtr used
1279 *
1280 * Parses an attribute value into one or more Text and EntityReference nodes.
1281 *
1282 * Returns 1 in case of success, 0 if the reader was not positionned on an
1283 * ttribute node or all the attribute values have been read, or -1
1284 * in case of error.
1285 */
1286int
1287xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1288 if (reader == NULL)
1289 return(-1);
1290 if (reader->node == NULL)
1291 return(-1);
1292 if (reader->curnode == NULL)
1293 return(0);
1294 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1295 if (reader->curnode->children == NULL)
1296 return(0);
1297 reader->curnode = reader->curnode->children;
1298 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1299 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1300
1301 if (reader->faketext == NULL) {
1302 reader->faketext = xmlNewDocText(reader->node->doc,
1303 ns->href);
1304 } else {
1305 if (reader->faketext->content != NULL)
1306 xmlFree(reader->faketext->content);
1307 reader->faketext->content = xmlStrdup(ns->href);
1308 }
1309 reader->curnode = reader->faketext;
1310 } else {
1311 if (reader->curnode->next == NULL)
1312 return(0);
1313 reader->curnode = reader->curnode->next;
1314 }
1315 return(1);
1316}
1317
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001318/************************************************************************
1319 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001320 * Acces API to the current node *
1321 * *
1322 ************************************************************************/
1323/**
1324 * xmlTextReaderAttributeCount:
1325 * @reader: the xmlTextReaderPtr used
1326 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001327 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001328 *
1329 * Returns 0 i no attributes, -1 in case of error or the attribute count
1330 */
1331int
1332xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1333 int ret;
1334 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00001335 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001336 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001337
1338 if (reader == NULL)
1339 return(-1);
1340 if (reader->node == NULL)
1341 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001342
1343 if (reader->curnode != NULL)
1344 node = reader->curnode;
1345 else
1346 node = reader->node;
1347
1348 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001349 return(0);
1350 if ((reader->state == XML_TEXTREADER_END) ||
1351 (reader->state == XML_TEXTREADER_BACKTRACK))
1352 return(0);
1353 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001354 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001355 while (attr != NULL) {
1356 ret++;
1357 attr = attr->next;
1358 }
Daniel Veillard67df8092002-12-16 22:04:11 +00001359 ns = node->nsDef;
1360 while (ns != NULL) {
1361 ret++;
1362 ns = ns->next;
1363 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001364 return(ret);
1365}
1366
1367/**
1368 * xmlTextReaderNodeType:
1369 * @reader: the xmlTextReaderPtr used
1370 *
1371 * Get the node type of the current node
1372 * Reference:
1373 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1374 *
1375 * Returns the xmlNodeType of the current node or -1 in case of error
1376 */
1377int
1378xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001379 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001380 if (reader == NULL)
1381 return(-1);
1382 if (reader->node == NULL)
1383 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001384 if (reader->curnode != NULL)
1385 node = reader->curnode;
1386 else
1387 node = reader->node;
1388 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001389 case XML_ELEMENT_NODE:
1390 if ((reader->state == XML_TEXTREADER_END) ||
1391 (reader->state == XML_TEXTREADER_BACKTRACK))
1392 return(15);
1393 return(1);
Daniel Veillardecaba492002-12-30 10:55:29 +00001394 case XML_NAMESPACE_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001395 case XML_ATTRIBUTE_NODE:
1396 return(2);
1397 case XML_TEXT_NODE:
1398 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1399 case XML_CDATA_SECTION_NODE:
1400 return(4);
1401 case XML_ENTITY_REF_NODE:
1402 return(5);
1403 case XML_ENTITY_NODE:
1404 return(6);
1405 case XML_PI_NODE:
1406 return(7);
1407 case XML_COMMENT_NODE:
1408 return(8);
1409 case XML_DOCUMENT_NODE:
1410 case XML_HTML_DOCUMENT_NODE:
1411#ifdef LIBXML_DOCB_ENABLED
1412 case XML_DOCB_DOCUMENT_NODE:
1413#endif
1414 return(9);
1415 case XML_DOCUMENT_FRAG_NODE:
1416 return(11);
1417 case XML_NOTATION_NODE:
1418 return(12);
1419 case XML_DOCUMENT_TYPE_NODE:
1420 case XML_DTD_NODE:
1421 return(10);
1422
1423 case XML_ELEMENT_DECL:
1424 case XML_ATTRIBUTE_DECL:
1425 case XML_ENTITY_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001426 case XML_XINCLUDE_START:
1427 case XML_XINCLUDE_END:
1428 return(0);
1429 }
1430 return(-1);
1431}
1432
1433/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001434 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001435 * @reader: the xmlTextReaderPtr used
1436 *
1437 * Check if the current node is empty
1438 *
1439 * Returns 1 if empty, 0 if not and -1 in case of error
1440 */
1441int
1442xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1443 if ((reader == NULL) || (reader->node == NULL))
1444 return(-1);
Daniel Veillarddf512f42002-12-23 15:56:21 +00001445 if (reader->node->type != XML_ELEMENT_NODE)
1446 return(0);
Daniel Veillarde3c036e2003-01-01 15:11:05 +00001447 if (reader->curnode != NULL)
1448 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001449 if (reader->node->children != NULL)
1450 return(0);
Daniel Veillarddf512f42002-12-23 15:56:21 +00001451 if (reader->node != reader->ctxt->node)
1452 return(1);
1453 if ((reader->ctxt->node != NULL) &&
1454 (reader->node == reader->ctxt->node->last) &&
1455 (reader->wasempty == 1))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001456 return(1);
1457 return(0);
1458}
1459
1460/**
1461 * xmlTextReaderLocalName:
1462 * @reader: the xmlTextReaderPtr used
1463 *
1464 * The local name of the node.
1465 *
1466 * Returns the local name or NULL if not available
1467 */
1468xmlChar *
1469xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001470 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001471 if ((reader == NULL) || (reader->node == NULL))
1472 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001473 if (reader->curnode != NULL)
1474 node = reader->curnode;
1475 else
1476 node = reader->node;
1477 if (node->type == XML_NAMESPACE_DECL) {
1478 xmlNsPtr ns = (xmlNsPtr) node;
1479 if (ns->prefix == NULL)
1480 return(xmlStrdup(BAD_CAST "xmlns"));
1481 else
1482 return(xmlStrdup(ns->prefix));
1483 }
1484 if ((node->type != XML_ELEMENT_NODE) &&
1485 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001486 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001487 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001488}
1489
1490/**
1491 * xmlTextReaderName:
1492 * @reader: the xmlTextReaderPtr used
1493 *
1494 * The qualified name of the node, equal to Prefix :LocalName.
1495 *
1496 * Returns the local name or NULL if not available
1497 */
1498xmlChar *
1499xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001500 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001501 xmlChar *ret;
1502
1503 if ((reader == NULL) || (reader->node == NULL))
1504 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001505 if (reader->curnode != NULL)
1506 node = reader->curnode;
1507 else
1508 node = reader->node;
1509 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001510 case XML_ELEMENT_NODE:
1511 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001512 if ((node->ns == NULL) ||
1513 (node->ns->prefix == NULL))
1514 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001515
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001516 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001517 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001518 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001519 return(ret);
1520 case XML_TEXT_NODE:
1521 return(xmlStrdup(BAD_CAST "#text"));
1522 case XML_CDATA_SECTION_NODE:
1523 return(xmlStrdup(BAD_CAST "#cdata-section"));
1524 case XML_ENTITY_NODE:
1525 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001526 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001527 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001528 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001529 case XML_COMMENT_NODE:
1530 return(xmlStrdup(BAD_CAST "#comment"));
1531 case XML_DOCUMENT_NODE:
1532 case XML_HTML_DOCUMENT_NODE:
1533#ifdef LIBXML_DOCB_ENABLED
1534 case XML_DOCB_DOCUMENT_NODE:
1535#endif
1536 return(xmlStrdup(BAD_CAST "#document"));
1537 case XML_DOCUMENT_FRAG_NODE:
1538 return(xmlStrdup(BAD_CAST "#document-fragment"));
1539 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001540 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001541 case XML_DOCUMENT_TYPE_NODE:
1542 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001543 return(xmlStrdup(node->name));
1544 case XML_NAMESPACE_DECL: {
1545 xmlNsPtr ns = (xmlNsPtr) node;
1546
1547 ret = xmlStrdup(BAD_CAST "xmlns");
1548 if (ns->prefix == NULL)
1549 return(ret);
1550 ret = xmlStrcat(ret, BAD_CAST ":");
1551 ret = xmlStrcat(ret, ns->prefix);
1552 return(ret);
1553 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001554
1555 case XML_ELEMENT_DECL:
1556 case XML_ATTRIBUTE_DECL:
1557 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001558 case XML_XINCLUDE_START:
1559 case XML_XINCLUDE_END:
1560 return(NULL);
1561 }
1562 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001563}
1564
1565/**
1566 * xmlTextReaderPrefix:
1567 * @reader: the xmlTextReaderPtr used
1568 *
1569 * A shorthand reference to the namespace associated with the node.
1570 *
1571 * Returns the prefix or NULL if not available
1572 */
1573xmlChar *
1574xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001575 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001576 if ((reader == NULL) || (reader->node == NULL))
1577 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001578 if (reader->curnode != NULL)
1579 node = reader->curnode;
1580 else
1581 node = reader->node;
1582 if (node->type == XML_NAMESPACE_DECL) {
1583 xmlNsPtr ns = (xmlNsPtr) node;
1584 if (ns->prefix == NULL)
1585 return(NULL);
1586 return(xmlStrdup(BAD_CAST "xmlns"));
1587 }
1588 if ((node->type != XML_ELEMENT_NODE) &&
1589 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001590 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001591 if ((node->ns != NULL) || (node->ns->prefix != NULL))
1592 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001593 return(NULL);
1594}
1595
1596/**
1597 * xmlTextReaderNamespaceUri:
1598 * @reader: the xmlTextReaderPtr used
1599 *
1600 * The URI defining the namespace associated with the node.
1601 *
1602 * Returns the namespace URI or NULL if not available
1603 */
1604xmlChar *
1605xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001606 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001607 if ((reader == NULL) || (reader->node == NULL))
1608 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001609 if (reader->curnode != NULL)
1610 node = reader->curnode;
1611 else
1612 node = reader->node;
Daniel Veillardecaba492002-12-30 10:55:29 +00001613 if (node->type == XML_NAMESPACE_DECL)
1614 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001615 if ((node->type != XML_ELEMENT_NODE) &&
1616 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001617 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001618 if (node->ns != NULL)
1619 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001620 return(NULL);
1621}
1622
1623/**
1624 * xmlTextReaderBaseUri:
1625 * @reader: the xmlTextReaderPtr used
1626 *
1627 * The base URI of the node.
1628 *
1629 * Returns the base URI or NULL if not available
1630 */
1631xmlChar *
1632xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
1633 if ((reader == NULL) || (reader->node == NULL))
1634 return(NULL);
1635 return(xmlNodeGetBase(NULL, reader->node));
1636}
1637
1638/**
1639 * xmlTextReaderDepth:
1640 * @reader: the xmlTextReaderPtr used
1641 *
1642 * The depth of the node in the tree.
1643 *
1644 * Returns the depth or -1 in case of error
1645 */
1646int
1647xmlTextReaderDepth(xmlTextReaderPtr reader) {
1648 if (reader == NULL)
1649 return(-1);
1650 if (reader->node == NULL)
1651 return(0);
1652
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001653 if (reader->curnode != NULL) {
1654 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
1655 (reader->curnode->type == XML_NAMESPACE_DECL))
1656 return(reader->depth + 1);
1657 return(reader->depth + 2);
1658 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001659 return(reader->depth);
1660}
1661
1662/**
1663 * xmlTextReaderHasAttributes:
1664 * @reader: the xmlTextReaderPtr used
1665 *
1666 * Whether the node has attributes.
1667 *
1668 * Returns 1 if true, 0 if false, and -1 in case or error
1669 */
1670int
1671xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001672 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001673 if (reader == NULL)
1674 return(-1);
1675 if (reader->node == NULL)
1676 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001677 if (reader->curnode != NULL)
1678 node = reader->curnode;
1679 else
1680 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001681
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001682 if ((node->type == XML_ELEMENT_NODE) &&
1683 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001684 return(1);
1685 /* TODO: handle the xmlDecl */
1686 return(0);
1687}
1688
1689/**
1690 * xmlTextReaderHasValue:
1691 * @reader: the xmlTextReaderPtr used
1692 *
1693 * Whether the node can have a text value.
1694 *
1695 * Returns 1 if true, 0 if false, and -1 in case or error
1696 */
1697int
1698xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001699 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001700 if (reader == NULL)
1701 return(-1);
1702 if (reader->node == NULL)
1703 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001704 if (reader->curnode != NULL)
1705 node = reader->curnode;
1706 else
1707 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001708
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001709 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001710 case XML_ATTRIBUTE_NODE:
1711 case XML_TEXT_NODE:
1712 case XML_CDATA_SECTION_NODE:
1713 case XML_PI_NODE:
1714 case XML_COMMENT_NODE:
1715 return(1);
1716 default:
1717 return(0);
1718 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001719 return(0);
1720}
1721
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001722/**
1723 * xmlTextReaderValue:
1724 * @reader: the xmlTextReaderPtr used
1725 *
1726 * Provides the text value of the node if present
1727 *
1728 * Returns the string or NULL if not available. The retsult must be deallocated
1729 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001730 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001731xmlChar *
1732xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001733 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001734 if (reader == NULL)
1735 return(NULL);
1736 if (reader->node == NULL)
1737 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001738 if (reader->curnode != NULL)
1739 node = reader->curnode;
1740 else
1741 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001742
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001743 switch (node->type) {
1744 case XML_NAMESPACE_DECL:
1745 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001746 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001747 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001748
1749 if (attr->parent != NULL)
1750 return (xmlNodeListGetString
1751 (attr->parent->doc, attr->children, 1));
1752 else
1753 return (xmlNodeListGetString(NULL, attr->children, 1));
1754 break;
1755 }
1756 case XML_TEXT_NODE:
1757 case XML_CDATA_SECTION_NODE:
1758 case XML_PI_NODE:
1759 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001760 if (node->content != NULL)
1761 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001762 default:
1763 return(NULL);
1764 }
1765 return(NULL);
1766}
1767
1768/**
1769 * xmlTextReaderIsDefault:
1770 * @reader: the xmlTextReaderPtr used
1771 *
1772 * Whether an Attribute node was generated from the default value
1773 * defined in the DTD or schema.
1774 *
1775 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
1776 */
1777int
1778xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
1779 if (reader == NULL)
1780 return(-1);
1781 return(0);
1782}
1783
1784/**
1785 * xmlTextReaderQuoteChar:
1786 * @reader: the xmlTextReaderPtr used
1787 *
1788 * The quotation mark character used to enclose the value of an attribute.
1789 *
1790 * Returns " or ' and -1 in case of error
1791 */
1792int
1793xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
1794 if (reader == NULL)
1795 return(-1);
1796 /* TODO maybe lookup the attribute value for " first */
1797 return((int) '"');
1798}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001799
1800/**
1801 * xmlTextReaderXmlLang:
1802 * @reader: the xmlTextReaderPtr used
1803 *
1804 * The xml:lang scope within which the node resides.
1805 *
1806 * Returns the xml:lang value or NULL if none exists.
1807 */
1808xmlChar *
1809xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
1810 if (reader == NULL)
1811 return(NULL);
1812 if (reader->node == NULL)
1813 return(NULL);
1814 return(xmlNodeGetLang(reader->node));
1815}
1816
Daniel Veillard67df8092002-12-16 22:04:11 +00001817/**
1818 * xmlTextReaderNormalization:
1819 * @reader: the xmlTextReaderPtr used
1820 *
1821 * The value indicating whether to normalize white space and attribute values.
1822 * Since attribute value and end of line normalizations are a MUST in the XML
1823 * specification only the value true is accepted. The broken bahaviour of
1824 * accepting out of range character entities like &#0; is of course not
1825 * supported either.
1826 *
1827 * Returns 1 or -1 in case of error.
1828 */
1829int
1830xmlTextReaderNormalization(xmlTextReaderPtr reader) {
1831 if (reader == NULL)
1832 return(-1);
1833 return(1);
1834}
1835
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001836/************************************************************************
1837 * *
1838 * Extensions to the base APIs *
1839 * *
1840 ************************************************************************/
1841
1842/**
1843 * xmlTextReaderSetParserProp:
1844 * @reader: the xmlTextReaderPtr used
1845 * @prop: the xmlParserProperties to set
1846 * @value: usually 0 or 1 to (de)activate it
1847 *
1848 * Change the parser processing behaviour by changing some of its internal
1849 * properties. Note that some properties can only be changed before any
1850 * read has been done.
1851 *
1852 * Returns 0 if the call was successful, or -1 in case of error
1853 */
1854int
1855xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
1856 xmlParserProperties p = (xmlParserProperties) prop;
1857 xmlParserCtxtPtr ctxt;
1858
1859 if ((reader == NULL) || (reader->ctxt == NULL))
1860 return(-1);
1861 ctxt = reader->ctxt;
1862
1863 switch (p) {
1864 case XML_PARSER_LOADDTD:
1865 if (value != 0) {
1866 if (ctxt->loadsubset == 0) {
1867 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
1868 return(-1);
1869 ctxt->loadsubset = XML_DETECT_IDS;
1870 }
1871 } else {
1872 ctxt->loadsubset = 0;
1873 }
1874 return(0);
1875 case XML_PARSER_DEFAULTATTRS:
1876 if (value != 0) {
1877 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
1878 } else {
1879 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1880 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
1881 }
1882 return(0);
1883 case XML_PARSER_VALIDATE:
1884 if (value != 0) {
1885 ctxt->validate = 1;
1886 } else {
1887 ctxt->validate = 0;
1888 }
1889 return(0);
Daniel Veillarde18fc182002-12-28 22:56:33 +00001890 case XML_PARSER_SUBST_ENTITIES:
1891 if (value != 0) {
1892 ctxt->replaceEntities = 1;
1893 } else {
1894 ctxt->replaceEntities = 0;
1895 }
1896 return(0);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001897 }
1898 return(-1);
1899}
1900
1901/**
1902 * xmlTextReaderGetParserProp:
1903 * @reader: the xmlTextReaderPtr used
1904 * @prop: the xmlParserProperties to get
1905 *
1906 * Read the parser internal property.
1907 *
1908 * Returns the value, usually 0 or 1, or -1 in case of error.
1909 */
1910int
1911xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
1912 xmlParserProperties p = (xmlParserProperties) prop;
1913 xmlParserCtxtPtr ctxt;
1914
1915 if ((reader == NULL) || (reader->ctxt == NULL))
1916 return(-1);
1917 ctxt = reader->ctxt;
1918
1919 switch (p) {
1920 case XML_PARSER_LOADDTD:
1921 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
1922 return(1);
1923 return(0);
1924 case XML_PARSER_DEFAULTATTRS:
1925 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1926 return(1);
1927 return(0);
1928 case XML_PARSER_VALIDATE:
1929 return(ctxt->validate);
Daniel Veillarde18fc182002-12-28 22:56:33 +00001930 case XML_PARSER_SUBST_ENTITIES:
1931 return(ctxt->replaceEntities);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001932 }
1933 return(-1);
1934}
1935
Daniel Veillarde18fc182002-12-28 22:56:33 +00001936/**
1937 * xmlTextReaderCurrentNode:
1938 * @reader: the xmlTextReaderPtr used
1939 *
1940 * Hacking interface allowing to get the xmlNodePtr correponding to the
1941 * current node being accessed by the xmlTextReader. This is dangerous
1942 * because the underlying node may be destroyed on the next Reads.
1943 *
1944 * Returns the xmlNodePtr or NULL in case of error.
1945 */
1946xmlNodePtr
1947xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
1948 if (reader == NULL)
1949 return(NULL);
1950
1951 if (reader->curnode != NULL)
1952 return(reader->curnode);
1953 return(reader->node);
1954}
1955
1956/**
1957 * xmlTextReaderCurrentDoc:
1958 * @reader: the xmlTextReaderPtr used
1959 *
1960 * Hacking interface allowing to get the xmlDocPtr correponding to the
1961 * current document being accessed by the xmlTextReader. This is dangerous
1962 * because the associated node may be destroyed on the next Reads.
1963 *
1964 * Returns the xmlDocPtr or NULL in case of error.
1965 */
1966xmlDocPtr
1967xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
1968 if ((reader == NULL) || (reader->ctxt == NULL))
1969 return(NULL);
1970
1971 return(reader->ctxt->myDoc);
1972}
1973
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001974/************************************************************************
1975 * *
1976 * Utilities *
1977 * *
1978 ************************************************************************/
1979/**
1980 * xmlBase64Decode:
1981 * @in: the input buffer
1982 * @inlen: the size of the input (in), the size read from it (out)
1983 * @to: the output buffer
1984 * @tolen: the size of the output (in), the size written to (out)
1985 *
1986 * Base64 decoder, reads from @in and save in @to
1987 *
1988 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
1989 * 2 if there wasn't enough space on the output or -1 in case of error.
1990 */
1991static int
1992xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
1993 unsigned char *to, unsigned long *tolen) {
1994 unsigned long incur; /* current index in in[] */
1995 unsigned long inblk; /* last block index in in[] */
1996 unsigned long outcur; /* current index in out[] */
1997 unsigned long inmax; /* size of in[] */
1998 unsigned long outmax; /* size of out[] */
1999 unsigned char cur; /* the current value read from in[] */
2000 unsigned char intmp[3], outtmp[4]; /* temporary buffers for the convert */
2001 int nbintmp; /* number of byte in intmp[] */
2002 int is_ignore; /* cur should be ignored */
2003 int is_end = 0; /* the end of the base64 was found */
2004 int retval = 1;
2005 int i;
2006
2007 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
2008 return(-1);
2009
2010 incur = 0;
2011 inblk = 0;
2012 outcur = 0;
2013 inmax = *inlen;
2014 outmax = *tolen;
2015 nbintmp = 0;
2016
2017 while (1) {
2018 if (incur >= inmax)
2019 break;
2020 cur = in[incur++];
2021 is_ignore = 0;
2022 if ((cur >= 'A') && (cur <= 'Z'))
2023 cur = cur - 'A';
2024 else if ((cur >= 'a') && (cur <= 'z'))
2025 cur = cur - 'a' + 26;
2026 else if ((cur >= '0') && (cur <= '9'))
2027 cur = cur - '0' + 52;
2028 else if (cur == '+')
2029 cur = 62;
2030 else if (cur == '/')
2031 cur = 63;
2032 else if (cur == '.')
2033 cur = 0;
2034 else if (cur == '=') /*no op , end of the base64 stream */
2035 is_end = 1;
2036 else {
2037 is_ignore = 1;
2038 if (nbintmp == 0)
2039 inblk = incur;
2040 }
2041
2042 if (!is_ignore) {
2043 int nbouttmp = 3;
2044 int is_break = 0;
2045
2046 if (is_end) {
2047 if (nbintmp == 0)
2048 break;
2049 if ((nbintmp == 1) || (nbintmp == 2))
2050 nbouttmp = 1;
2051 else
2052 nbouttmp = 2;
2053 nbintmp = 3;
2054 is_break = 1;
2055 }
2056 intmp[nbintmp++] = cur;
2057 /*
2058 * if intmp is full, push the 4byte sequence as a 3 byte
2059 * sequence out
2060 */
2061 if (nbintmp == 4) {
2062 nbintmp = 0;
2063 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
2064 outtmp[1] =
2065 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
2066 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
2067 if (outcur + 3 >= outmax) {
2068 retval = 2;
2069 break;
2070 }
2071
2072 for (i = 0; i < nbouttmp; i++)
2073 to[outcur++] = outtmp[i];
2074 inblk = incur;
2075 }
2076
2077 if (is_break) {
2078 retval = 0;
2079 break;
2080 }
2081 }
2082 }
2083
2084 *tolen = outcur;
2085 *inlen = inblk;
2086 return (retval);
2087}
2088
2089/*
2090 * Test routine for the xmlBase64Decode function
2091 */
2092#if 0
2093int main(int argc, char **argv) {
2094 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
2095 char output[100];
2096 char output2[100];
2097 char output3[100];
2098 unsigned long inlen = strlen(input);
2099 unsigned long outlen = 100;
2100 int ret;
2101 unsigned long cons, tmp, tmp2, prod;
2102
2103 /*
2104 * Direct
2105 */
2106 ret = xmlBase64Decode(input, &inlen, output, &outlen);
2107
2108 output[outlen] = 0;
2109 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
2110
2111 /*
2112 * output chunking
2113 */
2114 cons = 0;
2115 prod = 0;
2116 while (cons < inlen) {
2117 tmp = 5;
2118 tmp2 = inlen - cons;
2119
2120 printf("%ld %ld\n", cons, prod);
2121 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
2122 cons += tmp2;
2123 prod += tmp;
2124 printf("%ld %ld\n", cons, prod);
2125 }
2126 output2[outlen] = 0;
2127 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
2128
2129 /*
2130 * input chunking
2131 */
2132 cons = 0;
2133 prod = 0;
2134 while (cons < inlen) {
2135 tmp = 100 - prod;
2136 tmp2 = inlen - cons;
2137 if (tmp2 > 5)
2138 tmp2 = 5;
2139
2140 printf("%ld %ld\n", cons, prod);
2141 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
2142 cons += tmp2;
2143 prod += tmp;
2144 printf("%ld %ld\n", cons, prod);
2145 }
2146 output3[outlen] = 0;
2147 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
2148 return(0);
2149
2150}
2151#endif