blob: 930ec53bcc614ef975273976a5f221c6b858824e [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) {
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000385 if (reader->ctxt->myDoc != NULL) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000386 reader->node = reader->ctxt->myDoc->children;
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000387 if ((reader->ctxt->input != NULL) &&
388 (reader->ctxt->input->cur != NULL) &&
389 (reader->ctxt->input->cur[-2] != '/'))
390 reader->wasempty = -1;
391 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000392 if (reader->node == NULL)
393 return(-1);
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000394 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000395 } else {
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000396 reader->node = reader->ctxt->nodeTab[0];
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000397 }
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000398 reader->depth = 0;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000399 return(1);
400 }
401 oldstate = reader->state;
402 olddepth = reader->ctxt->nodeNr;
403 oldnode = reader->node;
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000404 /*
405 * the <p></p> vs. <p/> distinction at the API level royally sucks,
406 * Microsoft priviledge ...
407 */
408 if (reader->wasempty == -1)
409 wasempty = 0;
410 else
411 wasempty = (((reader->wasempty == 1) && (reader->ctxt->node != NULL) &&
Daniel Veillarde3c036e2003-01-01 15:11:05 +0000412 (reader->ctxt->node->last == reader->node)) ||
413 (reader->node != reader->ctxt->node));
Daniel Veillarddf512f42002-12-23 15:56:21 +0000414
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000415 /*
416 * If we are not backtracking on ancestors or examined nodes,
417 * that the parser didn't finished or that we arent at the end
418 * of stream, continue processing.
419 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000420 while (((oldstate == XML_TEXTREADER_BACKTRACK) ||
421 (reader->node->children == NULL) ||
422 (reader->node->type == XML_ENTITY_REF_NODE) ||
423 (reader->node->type == XML_DTD_NODE)) &&
424 (reader->node->next == NULL) &&
425 (reader->ctxt->nodeNr == olddepth) &&
426 (reader->ctxt->instate != XML_PARSER_EOF)) {
427 val = xmlTextReaderPushData(reader);
428 if (val < 0)
429 return(-1);
430 if (reader->node == NULL)
431 return(0);
432 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000433 if (oldstate != XML_TEXTREADER_BACKTRACK) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000434 if ((reader->node->children != NULL) &&
435 (reader->node->type != XML_ENTITY_REF_NODE) &&
436 (reader->node->type != XML_DTD_NODE)) {
437 reader->node = reader->node->children;
438 reader->depth++;
Daniel Veillarddf512f42002-12-23 15:56:21 +0000439 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000440 DUMP_READER
441 return(1);
442 }
443 }
444 if (reader->node->next != NULL) {
445 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillarddf512f42002-12-23 15:56:21 +0000446 (reader->node->type == XML_ELEMENT_NODE) &&
447 (wasempty == 0)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000448 reader->state = XML_TEXTREADER_END;
449 DUMP_READER
450 return(1);
451 }
452 reader->node = reader->node->next;
453 reader->state = XML_TEXTREADER_ELEMENT;
454 DUMP_READER
455 /*
456 * Cleanup of the old node
457 */
458 if (oldnode->type != XML_DTD_NODE) {
459 xmlUnlinkNode(oldnode);
460 xmlFreeNode(oldnode);
461 }
462
463 return(1);
464 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000465 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillard571b8892002-12-30 12:37:59 +0000466 (reader->node->type == XML_ELEMENT_NODE) &&
467 (wasempty == 0)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000468 reader->state = XML_TEXTREADER_END;
469 DUMP_READER
470 return(1);
471 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000472 reader->node = reader->node->parent;
473 if ((reader->node == NULL) ||
474 (reader->node->type == XML_DOCUMENT_NODE) ||
475#ifdef LIBXML_DOCB_ENABLED
476 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
477#endif
478 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000479 if (reader->mode != XML_TEXTREADER_DONE) {
480 val = xmlParseChunk(reader->ctxt, "", 0, 1);
481 reader->mode = XML_TEXTREADER_DONE;
482 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000483 reader->node = NULL;
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000484 reader->depth = -1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000485
486 /*
487 * Cleanup of the old node
488 */
489 if (oldnode->type != XML_DTD_NODE) {
490 xmlUnlinkNode(oldnode);
491 xmlFreeNode(oldnode);
492 }
493
494 return(0);
495 }
496 reader->depth--;
497 reader->state = XML_TEXTREADER_BACKTRACK;
498 DUMP_READER
499 return(1);
500}
501
Daniel Veillard67df8092002-12-16 22:04:11 +0000502/**
503 * xmlTextReaderReadState:
504 * @reader: the xmlTextReaderPtr used
505 *
506 * Gets the read state of the reader.
507 *
508 * Returns the state value, or -1 in case of error
509 */
510int
511xmlTextReaderReadState(xmlTextReaderPtr reader) {
512 if (reader == NULL)
513 return(-1);
514 return(reader->mode);
515}
516
517/**
518 * xmlTextReaderReadInnerXml:
519 * @reader: the xmlTextReaderPtr used
520 *
521 * Reads the contents of the current node, including child nodes and markup.
522 *
523 * Returns a string containing the XML content, or NULL if the current node
524 * is neither an element nor attribute, or has no child nodes. The
525 * string must be deallocated by the caller.
526 */
527xmlChar *
528xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) {
529 TODO
530 return(NULL);
531}
532
533/**
534 * xmlTextReaderReadOuterXml:
535 * @reader: the xmlTextReaderPtr used
536 *
537 * Reads the contents of the current node, including child nodes and markup.
538 *
539 * Returns a string containing the XML content, or NULL if the current node
540 * is neither an element nor attribute, or has no child nodes. The
541 * string must be deallocated by the caller.
542 */
543xmlChar *
544xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) {
545 TODO
546 return(NULL);
547}
548
549/**
550 * xmlTextReaderReadString:
551 * @reader: the xmlTextReaderPtr used
552 *
553 * Reads the contents of an element or a text node as a string.
554 *
555 * Returns a string containing the contents of the Element or Text node,
556 * or NULL if the reader is positioned on any other type of node.
557 * The string must be deallocated by the caller.
558 */
559xmlChar *
560xmlTextReaderReadString(xmlTextReaderPtr reader) {
561 TODO
562 return(NULL);
563}
564
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000565/**
566 * xmlTextReaderReadBase64:
567 * @reader: the xmlTextReaderPtr used
568 * @array: a byte array to store the content.
569 * @offset: the zero-based index into array where the method should
570 * begin to write.
571 * @len: the number of bytes to write.
572 *
573 * Reads and decodes the Base64 encoded contents of an element and
574 * stores the result in a byte buffer.
575 *
576 * Returns the number of bytes written to array, or zero if the current
577 * instance is not positioned on an element or -1 in case of error.
578 */
579int
580xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
581 int offset, int len) {
582 if ((reader == NULL) || (reader->ctxt == NULL))
583 return(-1);
584 if (reader->ctxt->wellFormed != 1)
585 return(-1);
586
587 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
588 return(0);
589 TODO
590 return(0);
591}
592
593/**
594 * xmlTextReaderReadBinHex:
595 * @reader: the xmlTextReaderPtr used
596 * @array: a byte array to store the content.
597 * @offset: the zero-based index into array where the method should
598 * begin to write.
599 * @len: the number of bytes to write.
600 *
601 * Reads and decodes the BinHex encoded contents of an element and
602 * stores the result in a byte buffer.
603 *
604 * Returns the number of bytes written to array, or zero if the current
605 * instance is not positioned on an element or -1 in case of error.
606 */
607int
608xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
609 int offset, int len) {
610 if ((reader == NULL) || (reader->ctxt == NULL))
611 return(-1);
612 if (reader->ctxt->wellFormed != 1)
613 return(-1);
614
615 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
616 return(0);
617 TODO
618 return(0);
619}
620
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000621/************************************************************************
622 * *
623 * Constructor and destructors *
624 * *
625 ************************************************************************/
626/**
627 * xmlNewTextReader:
628 * @input: the xmlParserInputBufferPtr used to read data
Daniel Veillardea7751d2002-12-20 00:16:24 +0000629 * @URI: the URI information for the source if available
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000630 *
631 * Create an xmlTextReader structure fed with @input
632 *
633 * Returns the new xmlTextReaderPtr or NULL in case of error
634 */
635xmlTextReaderPtr
Daniel Veillardea7751d2002-12-20 00:16:24 +0000636xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000637 xmlTextReaderPtr ret;
638 int val;
639
640 if (input == NULL)
641 return(NULL);
642 ret = xmlMalloc(sizeof(xmlTextReader));
643 if (ret == NULL) {
644 xmlGenericError(xmlGenericErrorContext,
645 "xmlNewTextReader : malloc failed\n");
646 return(NULL);
647 }
648 memset(ret, 0, sizeof(xmlTextReader));
649 ret->input = input;
650 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
651 if (ret->sax == NULL) {
652 xmlFree(ret);
653 xmlGenericError(xmlGenericErrorContext,
654 "xmlNewTextReader : malloc failed\n");
655 return(NULL);
656 }
657 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
658 ret->startElement = ret->sax->startElement;
659 ret->sax->startElement = xmlTextReaderStartElement;
660 ret->endElement = ret->sax->endElement;
661 ret->sax->endElement = xmlTextReaderEndElement;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000662 ret->characters = ret->sax->characters;
663 ret->sax->characters = xmlTextReaderCharacters;
664 ret->cdataBlock = ret->sax->cdataBlock;
665 ret->sax->cdataBlock = xmlTextReaderCDataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000666
Daniel Veillard67df8092002-12-16 22:04:11 +0000667 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000668 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000669 ret->curnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000670 val = xmlParserInputBufferRead(input, 4);
671 if (val >= 4) {
672 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
Daniel Veillardea7751d2002-12-20 00:16:24 +0000673 (const char *) ret->input->buffer->content, 4, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000674 ret->base = 0;
675 ret->cur = 4;
676 } else {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000677 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000678 ret->base = 0;
679 ret->cur = 0;
680 }
681 ret->ctxt->_private = ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000682 ret->ctxt->linenumbers = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000683 ret->allocs = XML_TEXTREADER_CTXT;
684 return(ret);
685
686}
687
688/**
689 * xmlNewTextReaderFilename:
690 * @URI: the URI of the resource to process
691 *
692 * Create an xmlTextReader structure fed with the resource at @URI
693 *
694 * Returns the new xmlTextReaderPtr or NULL in case of error
695 */
696xmlTextReaderPtr
697xmlNewTextReaderFilename(const char *URI) {
698 xmlParserInputBufferPtr input;
699 xmlTextReaderPtr ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000700 char *directory = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000701
702 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
703 if (input == NULL)
704 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000705 ret = xmlNewTextReader(input, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000706 if (ret == NULL) {
707 xmlFreeParserInputBuffer(input);
708 return(NULL);
709 }
710 ret->allocs |= XML_TEXTREADER_INPUT;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000711 if (ret->ctxt->directory == NULL)
712 directory = xmlParserGetDirectory(URI);
713 if ((ret->ctxt->directory == NULL) && (directory != NULL))
714 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
715 if (directory != NULL)
716 xmlFree(directory);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000717 return(ret);
718}
719
720/**
721 * xmlFreeTextReader:
722 * @reader: the xmlTextReaderPtr
723 *
724 * Deallocate all the resources associated to the reader
725 */
726void
727xmlFreeTextReader(xmlTextReaderPtr reader) {
728 if (reader == NULL)
729 return;
730 if (reader->ctxt != NULL) {
731 if (reader->ctxt->myDoc != NULL) {
732 xmlFreeDoc(reader->ctxt->myDoc);
733 reader->ctxt->myDoc = NULL;
734 }
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000735 if ((reader->ctxt->vctxt.vstateTab != NULL) &&
736 (reader->ctxt->vctxt.vstateMax > 0)){
737 xmlFree(reader->ctxt->vctxt.vstateTab);
738 reader->ctxt->vctxt.vstateTab = 0;
739 reader->ctxt->vctxt.vstateMax = 0;
740 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000741 if (reader->allocs & XML_TEXTREADER_CTXT)
742 xmlFreeParserCtxt(reader->ctxt);
743 }
744 if (reader->sax != NULL)
745 xmlFree(reader->sax);
746 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
747 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000748 if (reader->faketext != NULL) {
749 xmlFreeNode(reader->faketext);
750 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000751 xmlFree(reader);
752}
753
754/************************************************************************
755 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000756 * Methods for XmlTextReader *
757 * *
758 ************************************************************************/
759/**
760 * xmlTextReaderClose:
761 * @reader: the xmlTextReaderPtr used
762 *
763 * This method releases any resources allocated by the current instance
764 * changes the state to Closed and close any underlying input.
765 *
766 * Returns 0 or -1 in case of error
767 */
768int
769xmlTextReaderClose(xmlTextReaderPtr reader) {
770 if (reader == NULL)
771 return(-1);
772 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000773 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000774 reader->mode = XML_TEXTREADER_MODE_CLOSED;
775 if (reader->ctxt != NULL) {
776 if (reader->ctxt->myDoc != NULL) {
777 xmlFreeDoc(reader->ctxt->myDoc);
778 reader->ctxt->myDoc = NULL;
779 }
780 if (reader->allocs & XML_TEXTREADER_CTXT) {
781 xmlFreeParserCtxt(reader->ctxt);
782 reader->allocs -= XML_TEXTREADER_CTXT;
783 }
784 }
785 if (reader->sax != NULL) {
786 xmlFree(reader->sax);
787 reader->sax = NULL;
788 }
789 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
790 xmlFreeParserInputBuffer(reader->input);
791 reader->allocs -= XML_TEXTREADER_INPUT;
792 }
793 return(0);
794}
795
796/**
797 * xmlTextReaderGetAttributeNo:
798 * @reader: the xmlTextReaderPtr used
799 * @no: the zero-based index of the attribute relative to the containing element
800 *
801 * Provides the value of the attribute with the specified index relative
802 * to the containing element.
803 *
804 * Returns a string containing the value of the specified attribute, or NULL
805 * in case of error. The string must be deallocated by the caller.
806 */
807xmlChar *
808xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
809 xmlChar *ret;
810 int i;
811 xmlAttrPtr cur;
812 xmlNsPtr ns;
813
814 if (reader == NULL)
815 return(NULL);
816 if (reader->node == NULL)
817 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000818 if (reader->curnode != NULL)
819 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000820 /* TODO: handle the xmlDecl */
821 if (reader->node->type != XML_ELEMENT_NODE)
822 return(NULL);
823
824 ns = reader->node->nsDef;
825 for (i = 0;(i < no) && (ns != NULL);i++) {
826 ns = ns->next;
827 }
828 if (ns != NULL)
829 return(xmlStrdup(ns->href));
830
831 cur = reader->node->properties;
832 if (cur == NULL)
833 return(NULL);
834 for (;i < no;i++) {
835 cur = cur->next;
836 if (cur == NULL)
837 return(NULL);
838 }
839 /* TODO walk the DTD if present */
840
841 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
842 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
843 return(ret);
844}
845
846/**
847 * xmlTextReaderGetAttribute:
848 * @reader: the xmlTextReaderPtr used
849 * @name: the qualified name of the attribute.
850 *
851 * Provides the value of the attribute with the specified qualified name.
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 *
857xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
858 xmlChar *prefix = NULL;
859 xmlChar *localname;
860 xmlNsPtr ns;
861 xmlChar *ret = NULL;
862
863 if ((reader == NULL) || (name == NULL))
864 return(NULL);
865 if (reader->node == NULL)
866 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000867 if (reader->curnode != NULL)
868 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000869
870 /* TODO: handle the xmlDecl */
871 if (reader->node->type != XML_ELEMENT_NODE)
872 return(NULL);
873
874 localname = xmlSplitQName2(name, &prefix);
875 if (localname == NULL)
876 return(xmlGetProp(reader->node, name));
877
878 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
879 if (ns != NULL)
880 ret = xmlGetNsProp(reader->node, localname, ns->href);
881
882 if (localname != NULL)
883 xmlFree(localname);
884 if (prefix != NULL)
885 xmlFree(prefix);
886 return(ret);
887}
888
889
890/**
891 * xmlTextReaderGetAttributeNs:
892 * @reader: the xmlTextReaderPtr used
893 * @localName: the local name of the attribute.
894 * @namespaceURI: the namespace URI of the attribute.
895 *
896 * Provides the value of the specified attribute
897 *
898 * Returns a string containing the value of the specified attribute, or NULL
899 * in case of error. The string must be deallocated by the caller.
900 */
901xmlChar *
902xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
903 const xmlChar *namespaceURI) {
904 if ((reader == NULL) || (localName == NULL))
905 return(NULL);
906 if (reader->node == NULL)
907 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000908 if (reader->curnode != NULL)
909 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000910
911 /* TODO: handle the xmlDecl */
912 if (reader->node->type != XML_ELEMENT_NODE)
913 return(NULL);
914
915 return(xmlGetNsProp(reader->node, localName, namespaceURI));
916}
917
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000918/**
919 * xmlTextReaderGetRemainder:
920 * @reader: the xmlTextReaderPtr used
921 *
922 * Method to get the remainder of the buffered XML. this method stops the
923 * parser, set its state to End Of File and return the input stream with
924 * what is left that the parser did not use.
925 *
926 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
927 * in case of error.
928 */
929xmlParserInputBufferPtr
930xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
931 xmlParserInputBufferPtr ret = NULL;
932
933 if (reader == NULL)
934 return(NULL);
935 if (reader->node == NULL)
936 return(NULL);
937
938 reader->node = NULL;
939 reader->curnode = NULL;
940 reader->mode = XML_TEXTREADER_MODE_EOF;
941 if (reader->ctxt != NULL) {
942 if (reader->ctxt->myDoc != NULL) {
943 xmlFreeDoc(reader->ctxt->myDoc);
944 reader->ctxt->myDoc = NULL;
945 }
946 if (reader->allocs & XML_TEXTREADER_CTXT) {
947 xmlFreeParserCtxt(reader->ctxt);
948 reader->allocs -= XML_TEXTREADER_CTXT;
949 }
950 }
951 if (reader->sax != NULL) {
952 xmlFree(reader->sax);
953 reader->sax = NULL;
954 }
955 if (reader->allocs & XML_TEXTREADER_INPUT) {
956 ret = reader->input;
957 reader->allocs -= XML_TEXTREADER_INPUT;
958 } else {
959 /*
960 * Hum, one may need to duplicate the data structure because
961 * without reference counting the input may be freed twice:
962 * - by the layer which allocated it.
963 * - by the layer to which would have been returned to.
964 */
965 TODO
966 return(NULL);
967 }
968 return(ret);
969}
970
971/**
972 * xmlTextReaderLookupNamespace:
973 * @reader: the xmlTextReaderPtr used
974 * @prefix: the prefix whose namespace URI is to be resolved. To return
975 * the default namespace, specify NULL
976 *
977 * Resolves a namespace prefix in the scope of the current element.
978 *
979 * Returns a string containing the namespace URI to which the prefix maps
980 * or NULL in case of error. The string must be deallocated by the caller.
981 */
982xmlChar *
983xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
984 xmlNsPtr ns;
985
986 if (reader == NULL)
987 return(NULL);
988 if (reader->node == NULL)
989 return(NULL);
990
991 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
992 if (ns == NULL)
993 return(NULL);
994 return(xmlStrdup(ns->href));
995}
996
997/**
998 * xmlTextReaderMoveToAttributeNo:
999 * @reader: the xmlTextReaderPtr used
1000 * @no: the zero-based index of the attribute relative to the containing
1001 * element.
1002 *
1003 * Moves the position of the current instance to the attribute with
1004 * the specified index relative to the containing element.
1005 *
1006 * Returns 1 in case of success, -1 in case of error, 0 if not found
1007 */
1008int
1009xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
1010 int i;
1011 xmlAttrPtr cur;
1012 xmlNsPtr ns;
1013
1014 if (reader == NULL)
1015 return(-1);
1016 if (reader->node == NULL)
1017 return(-1);
1018 /* TODO: handle the xmlDecl */
1019 if (reader->node->type != XML_ELEMENT_NODE)
1020 return(-1);
1021
1022 reader->curnode = NULL;
1023
1024 ns = reader->node->nsDef;
1025 for (i = 0;(i < no) && (ns != NULL);i++) {
1026 ns = ns->next;
1027 }
1028 if (ns != NULL) {
1029 reader->curnode = (xmlNodePtr) ns;
1030 return(1);
1031 }
1032
1033 cur = reader->node->properties;
1034 if (cur == NULL)
1035 return(0);
1036 for (;i < no;i++) {
1037 cur = cur->next;
1038 if (cur == NULL)
1039 return(0);
1040 }
1041 /* TODO walk the DTD if present */
1042
1043 reader->curnode = (xmlNodePtr) cur;
1044 return(1);
1045}
1046
1047/**
1048 * xmlTextReaderMoveToAttribute:
1049 * @reader: the xmlTextReaderPtr used
1050 * @name: the qualified name of the attribute.
1051 *
1052 * Moves the position of the current instance to the attribute with
1053 * the specified qualified name.
1054 *
1055 * Returns 1 in case of success, -1 in case of error, 0 if not found
1056 */
1057int
1058xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1059 xmlChar *prefix = NULL;
1060 xmlChar *localname;
1061 xmlNsPtr ns;
1062 xmlAttrPtr prop;
1063
1064 if ((reader == NULL) || (name == NULL))
1065 return(-1);
1066 if (reader->node == NULL)
1067 return(-1);
1068
1069 /* TODO: handle the xmlDecl */
1070 if (reader->node->type != XML_ELEMENT_NODE)
1071 return(0);
1072
1073 localname = xmlSplitQName2(name, &prefix);
1074 if (localname == NULL) {
1075 /*
1076 * Namespace default decl
1077 */
1078 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1079 ns = reader->node->nsDef;
1080 while (ns != NULL) {
1081 if (ns->prefix == NULL) {
1082 reader->curnode = (xmlNodePtr) ns;
1083 return(1);
1084 }
1085 ns = ns->next;
1086 }
1087 return(0);
1088 }
1089
1090 prop = reader->node->properties;
1091 while (prop != NULL) {
1092 /*
1093 * One need to have
1094 * - same attribute names
1095 * - and the attribute carrying that namespace
1096 */
1097 if ((xmlStrEqual(prop->name, name)) &&
1098 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
1099 reader->curnode = (xmlNodePtr) prop;
1100 return(1);
1101 }
1102 prop = prop->next;
1103 }
1104 return(0);
1105 }
1106
1107 /*
1108 * Namespace default decl
1109 */
1110 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
1111 ns = reader->node->nsDef;
1112 while (ns != NULL) {
1113 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
1114 reader->curnode = (xmlNodePtr) ns;
1115 goto found;
1116 }
1117 ns = ns->next;
1118 }
1119 goto not_found;
1120 }
1121 prop = reader->node->properties;
1122 while (prop != NULL) {
1123 /*
1124 * One need to have
1125 * - same attribute names
1126 * - and the attribute carrying that namespace
1127 */
1128 if ((xmlStrEqual(prop->name, localname)) &&
1129 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
1130 reader->curnode = (xmlNodePtr) prop;
1131 goto found;
1132 }
1133 prop = prop->next;
1134 }
1135not_found:
1136 if (localname != NULL)
1137 xmlFree(localname);
1138 if (prefix != NULL)
1139 xmlFree(prefix);
1140 return(0);
1141
1142found:
1143 if (localname != NULL)
1144 xmlFree(localname);
1145 if (prefix != NULL)
1146 xmlFree(prefix);
1147 return(1);
1148}
1149
1150/**
1151 * xmlTextReaderMoveToAttributeNs:
1152 * @reader: the xmlTextReaderPtr used
1153 * @localName: the local name of the attribute.
1154 * @namespaceURI: the namespace URI of the attribute.
1155 *
1156 * Moves the position of the current instance to the attribute with the
1157 * specified local name and namespace URI.
1158 *
1159 * Returns 1 in case of success, -1 in case of error, 0 if not found
1160 */
1161int
1162xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1163 const xmlChar *localName, const xmlChar *namespaceURI) {
1164 xmlAttrPtr prop;
1165 xmlNodePtr node;
1166
1167 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1168 return(-1);
1169 if (reader->node == NULL)
1170 return(-1);
1171 if (reader->node->type != XML_ELEMENT_NODE)
1172 return(0);
1173 node = reader->node;
1174
1175 /*
1176 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1177 * namespace name associated to "xmlns"
1178 */
1179 prop = node->properties;
1180 while (prop != NULL) {
1181 /*
1182 * One need to have
1183 * - same attribute names
1184 * - and the attribute carrying that namespace
1185 */
1186 if (xmlStrEqual(prop->name, localName) &&
1187 ((prop->ns != NULL) &&
1188 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1189 reader->curnode = (xmlNodePtr) prop;
1190 return(1);
1191 }
1192 prop = prop->next;
1193 }
1194 return(0);
1195}
1196
1197/**
1198 * xmlTextReaderMoveToFirstAttribute:
1199 * @reader: the xmlTextReaderPtr used
1200 *
1201 * Moves the position of the current instance to the first attribute
1202 * associated with the current node.
1203 *
1204 * Returns 1 in case of success, -1 in case of error, 0 if not found
1205 */
1206int
1207xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1208 if (reader == NULL)
1209 return(-1);
1210 if (reader->node == NULL)
1211 return(-1);
1212 if (reader->node->type != XML_ELEMENT_NODE)
1213 return(0);
1214
1215 if (reader->node->nsDef != NULL) {
1216 reader->curnode = (xmlNodePtr) reader->node->nsDef;
1217 return(1);
1218 }
1219 if (reader->node->properties != NULL) {
1220 reader->curnode = (xmlNodePtr) reader->node->properties;
1221 return(1);
1222 }
1223 return(0);
1224}
1225
1226/**
1227 * xmlTextReaderMoveToNextAttribute:
1228 * @reader: the xmlTextReaderPtr used
1229 *
1230 * Moves the position of the current instance to the next attribute
1231 * associated with the current node.
1232 *
1233 * Returns 1 in case of success, -1 in case of error, 0 if not found
1234 */
1235int
1236xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1237 if (reader == NULL)
1238 return(-1);
1239 if (reader->node == NULL)
1240 return(-1);
1241 if (reader->node->type != XML_ELEMENT_NODE)
1242 return(0);
1243 if (reader->curnode == NULL)
1244 return(xmlTextReaderMoveToFirstAttribute(reader));
1245
1246 if (reader->curnode->type == XML_NAMESPACE_DECL) {
1247 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1248 if (ns->next != NULL) {
1249 reader->curnode = (xmlNodePtr) ns->next;
1250 return(1);
1251 }
1252 if (reader->node->properties != NULL) {
1253 reader->curnode = (xmlNodePtr) reader->node->properties;
1254 return(1);
1255 }
1256 return(0);
1257 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1258 (reader->curnode->next != NULL)) {
1259 reader->curnode = reader->curnode->next;
1260 return(1);
1261 }
1262 return(0);
1263}
1264
1265/**
1266 * xmlTextReaderMoveToElement:
1267 * @reader: the xmlTextReaderPtr used
1268 *
1269 * Moves the position of the current instance to the node that
1270 * contains the current Attribute node.
1271 *
1272 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1273 */
1274int
1275xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
1276 if (reader == NULL)
1277 return(-1);
1278 if (reader->node == NULL)
1279 return(-1);
1280 if (reader->node->type != XML_ELEMENT_NODE)
1281 return(0);
1282 if (reader->curnode != NULL) {
1283 reader->curnode = NULL;
1284 return(1);
1285 }
1286 return(0);
1287}
1288
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001289/**
1290 * xmlTextReaderReadAttributeValue:
1291 * @reader: the xmlTextReaderPtr used
1292 *
1293 * Parses an attribute value into one or more Text and EntityReference nodes.
1294 *
1295 * Returns 1 in case of success, 0 if the reader was not positionned on an
1296 * ttribute node or all the attribute values have been read, or -1
1297 * in case of error.
1298 */
1299int
1300xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1301 if (reader == NULL)
1302 return(-1);
1303 if (reader->node == NULL)
1304 return(-1);
1305 if (reader->curnode == NULL)
1306 return(0);
1307 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1308 if (reader->curnode->children == NULL)
1309 return(0);
1310 reader->curnode = reader->curnode->children;
1311 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1312 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1313
1314 if (reader->faketext == NULL) {
1315 reader->faketext = xmlNewDocText(reader->node->doc,
1316 ns->href);
1317 } else {
1318 if (reader->faketext->content != NULL)
1319 xmlFree(reader->faketext->content);
1320 reader->faketext->content = xmlStrdup(ns->href);
1321 }
1322 reader->curnode = reader->faketext;
1323 } else {
1324 if (reader->curnode->next == NULL)
1325 return(0);
1326 reader->curnode = reader->curnode->next;
1327 }
1328 return(1);
1329}
1330
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001331/************************************************************************
1332 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001333 * Acces API to the current node *
1334 * *
1335 ************************************************************************/
1336/**
1337 * xmlTextReaderAttributeCount:
1338 * @reader: the xmlTextReaderPtr used
1339 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001340 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001341 *
1342 * Returns 0 i no attributes, -1 in case of error or the attribute count
1343 */
1344int
1345xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1346 int ret;
1347 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00001348 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001349 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001350
1351 if (reader == NULL)
1352 return(-1);
1353 if (reader->node == NULL)
1354 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001355
1356 if (reader->curnode != NULL)
1357 node = reader->curnode;
1358 else
1359 node = reader->node;
1360
1361 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001362 return(0);
1363 if ((reader->state == XML_TEXTREADER_END) ||
1364 (reader->state == XML_TEXTREADER_BACKTRACK))
1365 return(0);
1366 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001367 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001368 while (attr != NULL) {
1369 ret++;
1370 attr = attr->next;
1371 }
Daniel Veillard67df8092002-12-16 22:04:11 +00001372 ns = node->nsDef;
1373 while (ns != NULL) {
1374 ret++;
1375 ns = ns->next;
1376 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001377 return(ret);
1378}
1379
1380/**
1381 * xmlTextReaderNodeType:
1382 * @reader: the xmlTextReaderPtr used
1383 *
1384 * Get the node type of the current node
1385 * Reference:
1386 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1387 *
1388 * Returns the xmlNodeType of the current node or -1 in case of error
1389 */
1390int
1391xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001392 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001393 if (reader == NULL)
1394 return(-1);
1395 if (reader->node == NULL)
1396 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001397 if (reader->curnode != NULL)
1398 node = reader->curnode;
1399 else
1400 node = reader->node;
1401 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001402 case XML_ELEMENT_NODE:
1403 if ((reader->state == XML_TEXTREADER_END) ||
1404 (reader->state == XML_TEXTREADER_BACKTRACK))
1405 return(15);
1406 return(1);
Daniel Veillardecaba492002-12-30 10:55:29 +00001407 case XML_NAMESPACE_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001408 case XML_ATTRIBUTE_NODE:
1409 return(2);
1410 case XML_TEXT_NODE:
1411 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1412 case XML_CDATA_SECTION_NODE:
1413 return(4);
1414 case XML_ENTITY_REF_NODE:
1415 return(5);
1416 case XML_ENTITY_NODE:
1417 return(6);
1418 case XML_PI_NODE:
1419 return(7);
1420 case XML_COMMENT_NODE:
1421 return(8);
1422 case XML_DOCUMENT_NODE:
1423 case XML_HTML_DOCUMENT_NODE:
1424#ifdef LIBXML_DOCB_ENABLED
1425 case XML_DOCB_DOCUMENT_NODE:
1426#endif
1427 return(9);
1428 case XML_DOCUMENT_FRAG_NODE:
1429 return(11);
1430 case XML_NOTATION_NODE:
1431 return(12);
1432 case XML_DOCUMENT_TYPE_NODE:
1433 case XML_DTD_NODE:
1434 return(10);
1435
1436 case XML_ELEMENT_DECL:
1437 case XML_ATTRIBUTE_DECL:
1438 case XML_ENTITY_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001439 case XML_XINCLUDE_START:
1440 case XML_XINCLUDE_END:
1441 return(0);
1442 }
1443 return(-1);
1444}
1445
1446/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001447 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001448 * @reader: the xmlTextReaderPtr used
1449 *
1450 * Check if the current node is empty
1451 *
1452 * Returns 1 if empty, 0 if not and -1 in case of error
1453 */
1454int
1455xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1456 if ((reader == NULL) || (reader->node == NULL))
1457 return(-1);
Daniel Veillarddf512f42002-12-23 15:56:21 +00001458 if (reader->node->type != XML_ELEMENT_NODE)
1459 return(0);
Daniel Veillarde3c036e2003-01-01 15:11:05 +00001460 if (reader->curnode != NULL)
1461 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001462 if (reader->node->children != NULL)
1463 return(0);
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001464 if (reader->state == XML_TEXTREADER_END)
1465 return(0);
1466 if (reader->wasempty == -1)
1467 return(0);
Daniel Veillarddf512f42002-12-23 15:56:21 +00001468 if (reader->node != reader->ctxt->node)
1469 return(1);
1470 if ((reader->ctxt->node != NULL) &&
1471 (reader->node == reader->ctxt->node->last) &&
1472 (reader->wasempty == 1))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001473 return(1);
1474 return(0);
1475}
1476
1477/**
1478 * xmlTextReaderLocalName:
1479 * @reader: the xmlTextReaderPtr used
1480 *
1481 * The local name of the node.
1482 *
1483 * Returns the local name or NULL if not available
1484 */
1485xmlChar *
1486xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001487 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001488 if ((reader == NULL) || (reader->node == NULL))
1489 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001490 if (reader->curnode != NULL)
1491 node = reader->curnode;
1492 else
1493 node = reader->node;
1494 if (node->type == XML_NAMESPACE_DECL) {
1495 xmlNsPtr ns = (xmlNsPtr) node;
1496 if (ns->prefix == NULL)
1497 return(xmlStrdup(BAD_CAST "xmlns"));
1498 else
1499 return(xmlStrdup(ns->prefix));
1500 }
1501 if ((node->type != XML_ELEMENT_NODE) &&
1502 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001503 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001504 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001505}
1506
1507/**
1508 * xmlTextReaderName:
1509 * @reader: the xmlTextReaderPtr used
1510 *
1511 * The qualified name of the node, equal to Prefix :LocalName.
1512 *
1513 * Returns the local name or NULL if not available
1514 */
1515xmlChar *
1516xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001517 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001518 xmlChar *ret;
1519
1520 if ((reader == NULL) || (reader->node == NULL))
1521 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001522 if (reader->curnode != NULL)
1523 node = reader->curnode;
1524 else
1525 node = reader->node;
1526 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001527 case XML_ELEMENT_NODE:
1528 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001529 if ((node->ns == NULL) ||
1530 (node->ns->prefix == NULL))
1531 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001532
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001533 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001534 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001535 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001536 return(ret);
1537 case XML_TEXT_NODE:
1538 return(xmlStrdup(BAD_CAST "#text"));
1539 case XML_CDATA_SECTION_NODE:
1540 return(xmlStrdup(BAD_CAST "#cdata-section"));
1541 case XML_ENTITY_NODE:
1542 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001543 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001544 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001545 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001546 case XML_COMMENT_NODE:
1547 return(xmlStrdup(BAD_CAST "#comment"));
1548 case XML_DOCUMENT_NODE:
1549 case XML_HTML_DOCUMENT_NODE:
1550#ifdef LIBXML_DOCB_ENABLED
1551 case XML_DOCB_DOCUMENT_NODE:
1552#endif
1553 return(xmlStrdup(BAD_CAST "#document"));
1554 case XML_DOCUMENT_FRAG_NODE:
1555 return(xmlStrdup(BAD_CAST "#document-fragment"));
1556 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001557 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001558 case XML_DOCUMENT_TYPE_NODE:
1559 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001560 return(xmlStrdup(node->name));
1561 case XML_NAMESPACE_DECL: {
1562 xmlNsPtr ns = (xmlNsPtr) node;
1563
1564 ret = xmlStrdup(BAD_CAST "xmlns");
1565 if (ns->prefix == NULL)
1566 return(ret);
1567 ret = xmlStrcat(ret, BAD_CAST ":");
1568 ret = xmlStrcat(ret, ns->prefix);
1569 return(ret);
1570 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001571
1572 case XML_ELEMENT_DECL:
1573 case XML_ATTRIBUTE_DECL:
1574 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001575 case XML_XINCLUDE_START:
1576 case XML_XINCLUDE_END:
1577 return(NULL);
1578 }
1579 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001580}
1581
1582/**
1583 * xmlTextReaderPrefix:
1584 * @reader: the xmlTextReaderPtr used
1585 *
1586 * A shorthand reference to the namespace associated with the node.
1587 *
1588 * Returns the prefix or NULL if not available
1589 */
1590xmlChar *
1591xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001592 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001593 if ((reader == NULL) || (reader->node == NULL))
1594 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001595 if (reader->curnode != NULL)
1596 node = reader->curnode;
1597 else
1598 node = reader->node;
1599 if (node->type == XML_NAMESPACE_DECL) {
1600 xmlNsPtr ns = (xmlNsPtr) node;
1601 if (ns->prefix == NULL)
1602 return(NULL);
1603 return(xmlStrdup(BAD_CAST "xmlns"));
1604 }
1605 if ((node->type != XML_ELEMENT_NODE) &&
1606 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001607 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001608 if ((node->ns != NULL) || (node->ns->prefix != NULL))
1609 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001610 return(NULL);
1611}
1612
1613/**
1614 * xmlTextReaderNamespaceUri:
1615 * @reader: the xmlTextReaderPtr used
1616 *
1617 * The URI defining the namespace associated with the node.
1618 *
1619 * Returns the namespace URI or NULL if not available
1620 */
1621xmlChar *
1622xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001623 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001624 if ((reader == NULL) || (reader->node == NULL))
1625 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001626 if (reader->curnode != NULL)
1627 node = reader->curnode;
1628 else
1629 node = reader->node;
Daniel Veillardecaba492002-12-30 10:55:29 +00001630 if (node->type == XML_NAMESPACE_DECL)
1631 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001632 if ((node->type != XML_ELEMENT_NODE) &&
1633 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001634 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001635 if (node->ns != NULL)
1636 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001637 return(NULL);
1638}
1639
1640/**
1641 * xmlTextReaderBaseUri:
1642 * @reader: the xmlTextReaderPtr used
1643 *
1644 * The base URI of the node.
1645 *
1646 * Returns the base URI or NULL if not available
1647 */
1648xmlChar *
1649xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
1650 if ((reader == NULL) || (reader->node == NULL))
1651 return(NULL);
1652 return(xmlNodeGetBase(NULL, reader->node));
1653}
1654
1655/**
1656 * xmlTextReaderDepth:
1657 * @reader: the xmlTextReaderPtr used
1658 *
1659 * The depth of the node in the tree.
1660 *
1661 * Returns the depth or -1 in case of error
1662 */
1663int
1664xmlTextReaderDepth(xmlTextReaderPtr reader) {
1665 if (reader == NULL)
1666 return(-1);
1667 if (reader->node == NULL)
1668 return(0);
1669
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001670 if (reader->curnode != NULL) {
1671 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
1672 (reader->curnode->type == XML_NAMESPACE_DECL))
1673 return(reader->depth + 1);
1674 return(reader->depth + 2);
1675 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001676 return(reader->depth);
1677}
1678
1679/**
1680 * xmlTextReaderHasAttributes:
1681 * @reader: the xmlTextReaderPtr used
1682 *
1683 * Whether the node has attributes.
1684 *
1685 * Returns 1 if true, 0 if false, and -1 in case or error
1686 */
1687int
1688xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001689 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001690 if (reader == NULL)
1691 return(-1);
1692 if (reader->node == NULL)
1693 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001694 if (reader->curnode != NULL)
1695 node = reader->curnode;
1696 else
1697 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001698
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001699 if ((node->type == XML_ELEMENT_NODE) &&
1700 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001701 return(1);
1702 /* TODO: handle the xmlDecl */
1703 return(0);
1704}
1705
1706/**
1707 * xmlTextReaderHasValue:
1708 * @reader: the xmlTextReaderPtr used
1709 *
1710 * Whether the node can have a text value.
1711 *
1712 * Returns 1 if true, 0 if false, and -1 in case or error
1713 */
1714int
1715xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001716 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001717 if (reader == NULL)
1718 return(-1);
1719 if (reader->node == NULL)
1720 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001721 if (reader->curnode != NULL)
1722 node = reader->curnode;
1723 else
1724 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001725
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001726 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001727 case XML_ATTRIBUTE_NODE:
1728 case XML_TEXT_NODE:
1729 case XML_CDATA_SECTION_NODE:
1730 case XML_PI_NODE:
1731 case XML_COMMENT_NODE:
1732 return(1);
1733 default:
1734 return(0);
1735 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001736 return(0);
1737}
1738
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001739/**
1740 * xmlTextReaderValue:
1741 * @reader: the xmlTextReaderPtr used
1742 *
1743 * Provides the text value of the node if present
1744 *
1745 * Returns the string or NULL if not available. The retsult must be deallocated
1746 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001747 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001748xmlChar *
1749xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001750 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001751 if (reader == NULL)
1752 return(NULL);
1753 if (reader->node == NULL)
1754 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001755 if (reader->curnode != NULL)
1756 node = reader->curnode;
1757 else
1758 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001759
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001760 switch (node->type) {
1761 case XML_NAMESPACE_DECL:
1762 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001763 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001764 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001765
1766 if (attr->parent != NULL)
1767 return (xmlNodeListGetString
1768 (attr->parent->doc, attr->children, 1));
1769 else
1770 return (xmlNodeListGetString(NULL, attr->children, 1));
1771 break;
1772 }
1773 case XML_TEXT_NODE:
1774 case XML_CDATA_SECTION_NODE:
1775 case XML_PI_NODE:
1776 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001777 if (node->content != NULL)
1778 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001779 default:
1780 return(NULL);
1781 }
1782 return(NULL);
1783}
1784
1785/**
1786 * xmlTextReaderIsDefault:
1787 * @reader: the xmlTextReaderPtr used
1788 *
1789 * Whether an Attribute node was generated from the default value
1790 * defined in the DTD or schema.
1791 *
1792 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
1793 */
1794int
1795xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
1796 if (reader == NULL)
1797 return(-1);
1798 return(0);
1799}
1800
1801/**
1802 * xmlTextReaderQuoteChar:
1803 * @reader: the xmlTextReaderPtr used
1804 *
1805 * The quotation mark character used to enclose the value of an attribute.
1806 *
1807 * Returns " or ' and -1 in case of error
1808 */
1809int
1810xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
1811 if (reader == NULL)
1812 return(-1);
1813 /* TODO maybe lookup the attribute value for " first */
1814 return((int) '"');
1815}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001816
1817/**
1818 * xmlTextReaderXmlLang:
1819 * @reader: the xmlTextReaderPtr used
1820 *
1821 * The xml:lang scope within which the node resides.
1822 *
1823 * Returns the xml:lang value or NULL if none exists.
1824 */
1825xmlChar *
1826xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
1827 if (reader == NULL)
1828 return(NULL);
1829 if (reader->node == NULL)
1830 return(NULL);
1831 return(xmlNodeGetLang(reader->node));
1832}
1833
Daniel Veillard67df8092002-12-16 22:04:11 +00001834/**
1835 * xmlTextReaderNormalization:
1836 * @reader: the xmlTextReaderPtr used
1837 *
1838 * The value indicating whether to normalize white space and attribute values.
1839 * Since attribute value and end of line normalizations are a MUST in the XML
1840 * specification only the value true is accepted. The broken bahaviour of
1841 * accepting out of range character entities like &#0; is of course not
1842 * supported either.
1843 *
1844 * Returns 1 or -1 in case of error.
1845 */
1846int
1847xmlTextReaderNormalization(xmlTextReaderPtr reader) {
1848 if (reader == NULL)
1849 return(-1);
1850 return(1);
1851}
1852
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001853/************************************************************************
1854 * *
1855 * Extensions to the base APIs *
1856 * *
1857 ************************************************************************/
1858
1859/**
1860 * xmlTextReaderSetParserProp:
1861 * @reader: the xmlTextReaderPtr used
1862 * @prop: the xmlParserProperties to set
1863 * @value: usually 0 or 1 to (de)activate it
1864 *
1865 * Change the parser processing behaviour by changing some of its internal
1866 * properties. Note that some properties can only be changed before any
1867 * read has been done.
1868 *
1869 * Returns 0 if the call was successful, or -1 in case of error
1870 */
1871int
1872xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
1873 xmlParserProperties p = (xmlParserProperties) prop;
1874 xmlParserCtxtPtr ctxt;
1875
1876 if ((reader == NULL) || (reader->ctxt == NULL))
1877 return(-1);
1878 ctxt = reader->ctxt;
1879
1880 switch (p) {
1881 case XML_PARSER_LOADDTD:
1882 if (value != 0) {
1883 if (ctxt->loadsubset == 0) {
1884 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
1885 return(-1);
1886 ctxt->loadsubset = XML_DETECT_IDS;
1887 }
1888 } else {
1889 ctxt->loadsubset = 0;
1890 }
1891 return(0);
1892 case XML_PARSER_DEFAULTATTRS:
1893 if (value != 0) {
1894 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
1895 } else {
1896 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1897 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
1898 }
1899 return(0);
1900 case XML_PARSER_VALIDATE:
1901 if (value != 0) {
1902 ctxt->validate = 1;
1903 } else {
1904 ctxt->validate = 0;
1905 }
1906 return(0);
Daniel Veillarde18fc182002-12-28 22:56:33 +00001907 case XML_PARSER_SUBST_ENTITIES:
1908 if (value != 0) {
1909 ctxt->replaceEntities = 1;
1910 } else {
1911 ctxt->replaceEntities = 0;
1912 }
1913 return(0);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001914 }
1915 return(-1);
1916}
1917
1918/**
1919 * xmlTextReaderGetParserProp:
1920 * @reader: the xmlTextReaderPtr used
1921 * @prop: the xmlParserProperties to get
1922 *
1923 * Read the parser internal property.
1924 *
1925 * Returns the value, usually 0 or 1, or -1 in case of error.
1926 */
1927int
1928xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
1929 xmlParserProperties p = (xmlParserProperties) prop;
1930 xmlParserCtxtPtr ctxt;
1931
1932 if ((reader == NULL) || (reader->ctxt == NULL))
1933 return(-1);
1934 ctxt = reader->ctxt;
1935
1936 switch (p) {
1937 case XML_PARSER_LOADDTD:
1938 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
1939 return(1);
1940 return(0);
1941 case XML_PARSER_DEFAULTATTRS:
1942 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
1943 return(1);
1944 return(0);
1945 case XML_PARSER_VALIDATE:
1946 return(ctxt->validate);
Daniel Veillarde18fc182002-12-28 22:56:33 +00001947 case XML_PARSER_SUBST_ENTITIES:
1948 return(ctxt->replaceEntities);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001949 }
1950 return(-1);
1951}
1952
Daniel Veillarde18fc182002-12-28 22:56:33 +00001953/**
1954 * xmlTextReaderCurrentNode:
1955 * @reader: the xmlTextReaderPtr used
1956 *
1957 * Hacking interface allowing to get the xmlNodePtr correponding to the
1958 * current node being accessed by the xmlTextReader. This is dangerous
1959 * because the underlying node may be destroyed on the next Reads.
1960 *
1961 * Returns the xmlNodePtr or NULL in case of error.
1962 */
1963xmlNodePtr
1964xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
1965 if (reader == NULL)
1966 return(NULL);
1967
1968 if (reader->curnode != NULL)
1969 return(reader->curnode);
1970 return(reader->node);
1971}
1972
1973/**
1974 * xmlTextReaderCurrentDoc:
1975 * @reader: the xmlTextReaderPtr used
1976 *
1977 * Hacking interface allowing to get the xmlDocPtr correponding to the
1978 * current document being accessed by the xmlTextReader. This is dangerous
1979 * because the associated node may be destroyed on the next Reads.
1980 *
1981 * Returns the xmlDocPtr or NULL in case of error.
1982 */
1983xmlDocPtr
1984xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
1985 if ((reader == NULL) || (reader->ctxt == NULL))
1986 return(NULL);
1987
1988 return(reader->ctxt->myDoc);
1989}
1990
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001991/************************************************************************
1992 * *
1993 * Utilities *
1994 * *
1995 ************************************************************************/
1996/**
1997 * xmlBase64Decode:
1998 * @in: the input buffer
1999 * @inlen: the size of the input (in), the size read from it (out)
2000 * @to: the output buffer
2001 * @tolen: the size of the output (in), the size written to (out)
2002 *
2003 * Base64 decoder, reads from @in and save in @to
2004 *
2005 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
2006 * 2 if there wasn't enough space on the output or -1 in case of error.
2007 */
2008static int
2009xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
2010 unsigned char *to, unsigned long *tolen) {
2011 unsigned long incur; /* current index in in[] */
2012 unsigned long inblk; /* last block index in in[] */
2013 unsigned long outcur; /* current index in out[] */
2014 unsigned long inmax; /* size of in[] */
2015 unsigned long outmax; /* size of out[] */
2016 unsigned char cur; /* the current value read from in[] */
2017 unsigned char intmp[3], outtmp[4]; /* temporary buffers for the convert */
2018 int nbintmp; /* number of byte in intmp[] */
2019 int is_ignore; /* cur should be ignored */
2020 int is_end = 0; /* the end of the base64 was found */
2021 int retval = 1;
2022 int i;
2023
2024 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
2025 return(-1);
2026
2027 incur = 0;
2028 inblk = 0;
2029 outcur = 0;
2030 inmax = *inlen;
2031 outmax = *tolen;
2032 nbintmp = 0;
2033
2034 while (1) {
2035 if (incur >= inmax)
2036 break;
2037 cur = in[incur++];
2038 is_ignore = 0;
2039 if ((cur >= 'A') && (cur <= 'Z'))
2040 cur = cur - 'A';
2041 else if ((cur >= 'a') && (cur <= 'z'))
2042 cur = cur - 'a' + 26;
2043 else if ((cur >= '0') && (cur <= '9'))
2044 cur = cur - '0' + 52;
2045 else if (cur == '+')
2046 cur = 62;
2047 else if (cur == '/')
2048 cur = 63;
2049 else if (cur == '.')
2050 cur = 0;
2051 else if (cur == '=') /*no op , end of the base64 stream */
2052 is_end = 1;
2053 else {
2054 is_ignore = 1;
2055 if (nbintmp == 0)
2056 inblk = incur;
2057 }
2058
2059 if (!is_ignore) {
2060 int nbouttmp = 3;
2061 int is_break = 0;
2062
2063 if (is_end) {
2064 if (nbintmp == 0)
2065 break;
2066 if ((nbintmp == 1) || (nbintmp == 2))
2067 nbouttmp = 1;
2068 else
2069 nbouttmp = 2;
2070 nbintmp = 3;
2071 is_break = 1;
2072 }
2073 intmp[nbintmp++] = cur;
2074 /*
2075 * if intmp is full, push the 4byte sequence as a 3 byte
2076 * sequence out
2077 */
2078 if (nbintmp == 4) {
2079 nbintmp = 0;
2080 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
2081 outtmp[1] =
2082 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
2083 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
2084 if (outcur + 3 >= outmax) {
2085 retval = 2;
2086 break;
2087 }
2088
2089 for (i = 0; i < nbouttmp; i++)
2090 to[outcur++] = outtmp[i];
2091 inblk = incur;
2092 }
2093
2094 if (is_break) {
2095 retval = 0;
2096 break;
2097 }
2098 }
2099 }
2100
2101 *tolen = outcur;
2102 *inlen = inblk;
2103 return (retval);
2104}
2105
2106/*
2107 * Test routine for the xmlBase64Decode function
2108 */
2109#if 0
2110int main(int argc, char **argv) {
2111 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
2112 char output[100];
2113 char output2[100];
2114 char output3[100];
2115 unsigned long inlen = strlen(input);
2116 unsigned long outlen = 100;
2117 int ret;
2118 unsigned long cons, tmp, tmp2, prod;
2119
2120 /*
2121 * Direct
2122 */
2123 ret = xmlBase64Decode(input, &inlen, output, &outlen);
2124
2125 output[outlen] = 0;
2126 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
2127
2128 /*
2129 * output chunking
2130 */
2131 cons = 0;
2132 prod = 0;
2133 while (cons < inlen) {
2134 tmp = 5;
2135 tmp2 = inlen - cons;
2136
2137 printf("%ld %ld\n", cons, prod);
2138 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
2139 cons += tmp2;
2140 prod += tmp;
2141 printf("%ld %ld\n", cons, prod);
2142 }
2143 output2[outlen] = 0;
2144 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
2145
2146 /*
2147 * input chunking
2148 */
2149 cons = 0;
2150 prod = 0;
2151 while (cons < inlen) {
2152 tmp = 100 - prod;
2153 tmp2 = inlen - cons;
2154 if (tmp2 > 5)
2155 tmp2 = 5;
2156
2157 printf("%ld %ld\n", cons, prod);
2158 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
2159 cons += tmp2;
2160 prod += tmp;
2161 printf("%ld %ld\n", cons, prod);
2162 }
2163 output3[outlen] = 0;
2164 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
2165 return(0);
2166
2167}
2168#endif