blob: 64da1bbeabf44e208e8eddfbd87db0c65e5f579d [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
Daniel Veillard7704fb12003-01-03 16:19:51 +000013/*
14 * TODOs:
15 * - provide an API to expand part of the tree
16 * - provide an API to preserve part of the tree
17 * - Streaming XInclude support
Daniel Veillard067bae52003-01-05 01:27:54 +000018 * - validation against a provided DTD
19 * - XML Schemas validation
Daniel Veillard7704fb12003-01-03 16:19:51 +000020 * - setting(s) for NoBlanks
21 * - performances and tuning ...
22 */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000023#define IN_LIBXML
24#include "libxml.h"
25
26#include <string.h> /* for memset() only ! */
Daniel Veillard26f70262003-01-16 22:45:08 +000027#include <stdarg.h>
Daniel Veillarde1ca5032002-12-09 14:13:43 +000028
29#ifdef HAVE_CTYPE_H
30#include <ctype.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35
36#include <libxml/xmlmemory.h>
37#include <libxml/xmlIO.h>
38#include <libxml/xmlreader.h>
39
40/* #define DEBUG_CALLBACKS */
41/* #define DEBUG_READER */
42
43/**
44 * TODO:
45 *
46 * macro to flag unimplemented blocks
47 */
48#define TODO \
49 xmlGenericError(xmlGenericErrorContext, \
50 "Unimplemented block at %s:%d\n", \
51 __FILE__, __LINE__);
52
53#ifdef DEBUG_READER
54#define DUMP_READER xmlTextReaderDebug(reader);
55#else
56#define DUMP_READER
57#endif
58
59/************************************************************************
60 * *
61 * The parser: maps the Text Reader API on top of the existing *
62 * parsing routines building a tree *
63 * *
64 ************************************************************************/
65
66#define XML_TEXTREADER_INPUT 1
67#define XML_TEXTREADER_CTXT 2
68
69typedef enum {
Daniel Veillard67df8092002-12-16 22:04:11 +000070 XML_TEXTREADER_MODE_INITIAL = 0,
71 XML_TEXTREADER_MODE_INTERACTIVE = 1,
72 XML_TEXTREADER_MODE_ERROR = 2,
73 XML_TEXTREADER_MODE_EOF =3,
74 XML_TEXTREADER_MODE_CLOSED = 4,
75 XML_TEXTREADER_MODE_READING = 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000076} xmlTextReaderMode;
77
78typedef enum {
79 XML_TEXTREADER_NONE = -1,
80 XML_TEXTREADER_START= 0,
81 XML_TEXTREADER_ELEMENT= 1,
82 XML_TEXTREADER_END= 2,
83 XML_TEXTREADER_EMPTY= 3,
Daniel Veillardea7751d2002-12-20 00:16:24 +000084 XML_TEXTREADER_BACKTRACK= 4,
85 XML_TEXTREADER_DONE= 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000086} xmlTextReaderState;
87
88struct _xmlTextReader {
89 int mode; /* the parsing mode */
90 int allocs; /* what structure were deallocated */
91 xmlTextReaderState state;
92 xmlParserCtxtPtr ctxt; /* the parser context */
93 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
94 xmlParserInputBufferPtr input; /* the input */
95 startElementSAXFunc startElement;/* initial SAX callbacks */
96 endElementSAXFunc endElement; /* idem */
Daniel Veillardea7751d2002-12-20 00:16:24 +000097 charactersSAXFunc characters;
98 cdataBlockSAXFunc cdataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +000099 unsigned int base; /* base of the segment in the input */
100 unsigned int cur; /* current position in the input */
101 xmlNodePtr node; /* current node */
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000102 xmlNodePtr curnode;/* current attribute node */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000103 int depth; /* depth of the current node */
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000104 xmlNodePtr faketext;/* fake xmlNs chld */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000105
106 /* entity stack when traversing entities content */
107 xmlNodePtr ent; /* Current Entity Ref Node */
108 int entNr; /* Depth of the entities stack */
109 int entMax; /* Max depth of the entities stack */
110 xmlNodePtr *entTab; /* array of entities */
Daniel Veillard26f70262003-01-16 22:45:08 +0000111
112 /* error handling */
113 xmlTextReaderErrorFunc errorFunc; /* callback function */
114 void *errorFuncArg; /* callback function user argument */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000115};
116
Daniel Veillard067bae52003-01-05 01:27:54 +0000117static const char *xmlTextReaderIsEmpty = "This element is empty";
118
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000119#ifdef DEBUG_READER
120static void
121xmlTextReaderDebug(xmlTextReaderPtr reader) {
122 if ((reader == NULL) || (reader->ctxt == NULL)) {
123 fprintf(stderr, "xmlTextReader NULL\n");
124 return;
125 }
126 fprintf(stderr, "xmlTextReader: state %d depth %d ",
127 reader->state, reader->depth);
128 if (reader->node == NULL) {
129 fprintf(stderr, "node = NULL\n");
130 } else {
131 fprintf(stderr, "node %s\n", reader->node->name);
132 }
133 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
134 reader->base, reader->cur, reader->ctxt->nodeNr);
135 if (reader->input->buffer == NULL) {
136 fprintf(stderr, "buffer is NULL\n");
137 } else {
138#ifdef LIBXML_DEBUG_ENABLED
139 xmlDebugDumpString(stderr,
140 &reader->input->buffer->content[reader->cur]);
141#endif
142 fprintf(stderr, "\n");
143 }
144}
145#endif
146
147/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000148 * xmlTextReaderEntPush:
149 * @reader: the xmlTextReaderPtr used
150 * @value: the entity reference node
151 *
152 * Pushes a new entity reference node on top of the entities stack
153 *
154 * Returns 0 in case of error, the index in the stack otherwise
155 */
156static int
157xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
158{
159 if (reader->entMax <= 0) {
160 reader->entMax = 10;
161 reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
162 sizeof(reader->entTab[0]));
163 if (reader->entTab == NULL) {
164 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
165 return (0);
166 }
167 }
168 if (reader->entNr >= reader->entMax) {
169 reader->entMax *= 2;
170 reader->entTab =
171 (xmlNodePtr *) xmlRealloc(reader->entTab,
172 reader->entMax *
173 sizeof(reader->entTab[0]));
174 if (reader->entTab == NULL) {
175 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
176 return (0);
177 }
178 }
179 reader->entTab[reader->entNr] = value;
180 reader->ent = value;
181 return (reader->entNr++);
182}
183
184/**
185 * xmlTextReaderEntPop:
186 * @reader: the xmlTextReaderPtr used
187 *
188 * Pops the top element entity from the entities stack
189 *
190 * Returns the entity just removed
191 */
192static xmlNodePtr
193xmlTextReaderEntPop(xmlTextReaderPtr reader)
194{
195 xmlNodePtr ret;
196
197 if (reader->entNr <= 0)
198 return (0);
199 reader->entNr--;
200 if (reader->entNr > 0)
201 reader->ent = reader->entTab[reader->entNr - 1];
202 else
203 reader->ent = NULL;
204 ret = reader->entTab[reader->entNr];
205 reader->entTab[reader->entNr] = 0;
206 return (ret);
207}
208
209/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000210 * xmlTextReaderStartElement:
211 * @ctx: the user data (XML parser context)
212 * @fullname: The element name, including namespace prefix
213 * @atts: An array of name/value attributes pairs, NULL terminated
214 *
215 * called when an opening tag has been processed.
216 */
217static void
218xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
219 const xmlChar **atts) {
220 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000221 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000222 xmlTextReaderPtr reader = ctxt->_private;
223
224#ifdef DEBUG_CALLBACKS
225 printf("xmlTextReaderStartElement(%s)\n", fullname);
226#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000227 if ((reader != NULL) && (reader->startElement != NULL)) {
Daniel Veillardd5896142002-12-31 14:45:26 +0000228 /*
229 * when processing an entity, the context may have been changed
230 */
231 origctxt = reader->ctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000232 reader->startElement(ctx, fullname, atts);
Daniel Veillard067bae52003-01-05 01:27:54 +0000233 if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
234 (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
235 (ctxt->input->cur[1] == '>'))
236 ctxt->node->_private = (void *) xmlTextReaderIsEmpty;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000237 }
Daniel Veillard9e395c22003-01-01 14:50:44 +0000238 if (reader != NULL)
239 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000240}
241
242/**
243 * xmlTextReaderEndElement:
244 * @ctx: the user data (XML parser context)
245 * @fullname: The element name, including namespace prefix
246 *
247 * called when an ending tag has been processed.
248 */
249static void
250xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
251 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000252 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000253 xmlTextReaderPtr reader = ctxt->_private;
254
255#ifdef DEBUG_CALLBACKS
256 printf("xmlTextReaderEndElement(%s)\n", fullname);
257#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000258 if ((reader != NULL) && (reader->endElement != NULL)) {
Daniel Veillardd5896142002-12-31 14:45:26 +0000259 /*
260 * when processing an entity, the context may have been changed
261 */
262 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000263
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000264 reader->endElement(ctx, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000265 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000266}
267
268/**
Daniel Veillardea7751d2002-12-20 00:16:24 +0000269 * xmlTextReaderCharacters:
270 * @ctx: the user data (XML parser context)
271 * @ch: a xmlChar string
272 * @len: the number of xmlChar
273 *
274 * receiving some chars from the parser.
275 */
276static void
277xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
278{
279 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000280 xmlParserCtxtPtr origctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 xmlTextReaderPtr reader = ctxt->_private;
282
283#ifdef DEBUG_CALLBACKS
284 printf("xmlTextReaderCharacters()\n");
285#endif
286 if ((reader != NULL) && (reader->characters != NULL)) {
287 reader->characters(ctx, ch, len);
Daniel Veillardd5896142002-12-31 14:45:26 +0000288 /*
289 * when processing an entity, the context may have been changed
290 */
291 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000292 }
293}
294
295/**
296 * xmlTextReaderCDataBlock:
297 * @ctx: the user data (XML parser context)
298 * @value: The pcdata content
299 * @len: the block length
300 *
301 * called when a pcdata block has been parsed
302 */
303static void
304xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
305{
306 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
307 xmlTextReaderPtr reader = ctxt->_private;
308
309#ifdef DEBUG_CALLBACKS
310 printf("xmlTextReaderCDataBlock()\n");
311#endif
312 if ((reader != NULL) && (reader->cdataBlock != NULL)) {
313 reader->cdataBlock(ctx, ch, len);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000314 }
315}
316
317/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000318 * xmlTextReaderPushData:
319 * @reader: the xmlTextReaderPtr used
320 *
321 * Push data down the progressive parser until a significant callback
322 * got raised.
323 *
324 * Returns -1 in case of failure, 0 otherwise
325 */
326static int
327xmlTextReaderPushData(xmlTextReaderPtr reader) {
328 unsigned int cur = reader->cur;
329 xmlBufferPtr inbuf;
330 int val;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000331 int oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000332
333 if ((reader->input == NULL) || (reader->input->buffer == NULL))
334 return(-1);
335
Daniel Veillardea7751d2002-12-20 00:16:24 +0000336 oldstate = reader->state;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000337 reader->state = XML_TEXTREADER_NONE;
338 inbuf = reader->input->buffer;
339 while (reader->state == XML_TEXTREADER_NONE) {
340 if (cur >= inbuf->use) {
341 /*
342 * Refill the buffer unless we are at the end of the stream
343 */
344 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
345 val = xmlParserInputBufferRead(reader->input, 4096);
346 if (val <= 0) {
347 reader->mode = XML_TEXTREADER_MODE_EOF;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000348 reader->state = oldstate;
Daniel Veillardaaa105b2002-12-30 11:42:17 +0000349 if ((oldstate != XML_TEXTREADER_START) ||
350 (reader->ctxt->myDoc != NULL))
351 return(val);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000352 }
353 } else
354 break;
355 }
Daniel Veillard067bae52003-01-05 01:27:54 +0000356 /*
357 * parse by block of 512 bytes
358 */
359 if ((cur >= reader->cur + 512) || (cur >= inbuf->use)) {
360 if (cur < inbuf->use)
361 cur = cur + 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000362 val = xmlParseChunk(reader->ctxt,
363 (const char *) &inbuf->content[reader->cur],
364 cur - reader->cur, 0);
365 if (val != 0)
366 return(-1);
367 reader->cur = cur;
368 break;
369 } else {
370 cur = cur + 1;
371
372 /*
373 * One may have to force a flush at some point when parsing really
374 * large CDATA sections
375 */
376 if ((cur - reader->cur > 4096) && (reader->base == 0) &&
Daniel Veillard67df8092002-12-16 22:04:11 +0000377 (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000378 cur = cur + 1;
379 val = xmlParseChunk(reader->ctxt,
380 (const char *) &inbuf->content[reader->cur],
381 cur - reader->cur, 0);
382 if (val != 0)
383 return(-1);
384 reader->cur = cur;
385 }
386 }
387 }
388 /*
389 * Discard the consumed input when needed and possible
390 */
Daniel Veillard67df8092002-12-16 22:04:11 +0000391 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000392 if ((reader->cur >= 4096) && (reader->base == 0)) {
393 val = xmlBufferShrink(inbuf, cur);
394 if (val >= 0) {
395 reader->cur -= val;
396 }
397 }
398 }
399
400 /*
401 * At the end of the stream signal that the work is done to the Push
402 * parser.
403 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000404 if (reader->mode == XML_TEXTREADER_MODE_EOF) {
405 if (reader->mode != XML_TEXTREADER_DONE) {
406 val = xmlParseChunk(reader->ctxt,
Daniel Veillard067bae52003-01-05 01:27:54 +0000407 (const char *) &inbuf->content[reader->cur],
408 cur - reader->cur, 1);
409 reader->cur = cur;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000410 reader->mode = XML_TEXTREADER_DONE;
411 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000412 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000413 reader->state = oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000414 return(0);
415}
416
417/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000418 * xmlTextReaderValidatePush:
419 * @reader: the xmlTextReaderPtr used
420 *
421 * Push the current node for validation
422 */
423static void
424xmlTextReaderValidatePush(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000425#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000426 xmlNodePtr node = reader->node;
427
428 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
429 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
430 reader->ctxt->myDoc, node, node->name);
431 } else {
432 xmlChar *qname;
433
434 qname = xmlStrdup(node->ns->prefix);
435 qname = xmlStrcat(qname, BAD_CAST ":");
436 qname = xmlStrcat(qname, node->name);
437 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
438 reader->ctxt->myDoc, node, qname);
439 if (qname != NULL)
440 xmlFree(qname);
441 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000442#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000443}
444/**
445 * xmlTextReaderValidatePop:
446 * @reader: the xmlTextReaderPtr used
447 *
448 * Pop the current node from validation
449 */
450static void
451xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000452#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000453 xmlNodePtr node = reader->node;
454
455 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
456 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
457 reader->ctxt->myDoc, node, node->name);
458 } else {
459 xmlChar *qname;
460
461 qname = xmlStrdup(node->ns->prefix);
462 qname = xmlStrcat(qname, BAD_CAST ":");
463 qname = xmlStrcat(qname, node->name);
464 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
465 reader->ctxt->myDoc, node, qname);
466 if (qname != NULL)
467 xmlFree(qname);
468 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000469#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000470}
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000471/**
472 * xmlTextReaderValidateEntity:
473 * @reader: the xmlTextReaderPtr used
474 *
475 * Handle the validation when an entity reference is encountered and
476 * entity substitution is not activated. As a result the parser interface
477 * must walk through the entity and do the validation calls
478 */
479static void
480xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000481#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000482 xmlNodePtr oldnode = reader->node;
483 xmlNodePtr node = reader->node;
484 xmlParserCtxtPtr ctxt = reader->ctxt;
485
486 do {
487 if (node->type == XML_ENTITY_REF_NODE) {
488 /*
489 * Case where the underlying tree is not availble, lookup the entity
490 * and walk it.
491 */
492 if ((node->children == NULL) && (ctxt->sax != NULL) &&
493 (ctxt->sax->getEntity != NULL)) {
494 node->children = (xmlNodePtr)
495 ctxt->sax->getEntity(ctxt, node->name);
496 }
497
498 if ((node->children != NULL) &&
499 (node->children->type == XML_ENTITY_DECL) &&
500 (node->children->children != NULL)) {
501 xmlTextReaderEntPush(reader, node);
502 node = node->children->children;
503 continue;
504 } else {
505 /*
506 * The error has probably be raised already.
507 */
508 if (node == oldnode)
509 break;
510 node = node->next;
511 }
512 } else if (node->type == XML_ELEMENT_NODE) {
513 reader->node = node;
514 xmlTextReaderValidatePush(reader);
515 } else if ((node->type == XML_TEXT_NODE) ||
516 (node->type == XML_CDATA_SECTION_NODE)) {
517 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt,
518 node->content, xmlStrlen(node->content));
519 }
520
521 /*
522 * go to next node
523 */
524 if (node->children != NULL) {
525 node = node->children;
526 continue;
Daniel Veillardef8dd7b2003-03-23 12:02:56 +0000527 } else if (node->type == XML_ELEMENT_NODE) {
528 xmlTextReaderValidatePop(reader);
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000529 }
530 if (node->next != NULL) {
531 node = node->next;
532 continue;
533 }
534 do {
535 node = node->parent;
536 if (node->type == XML_ELEMENT_NODE) {
537 reader->node = node;
538 xmlTextReaderValidatePop(reader);
539 }
540 if ((node->type == XML_ENTITY_DECL) &&
541 (reader->ent != NULL) && (reader->ent->children == node)) {
542 node = xmlTextReaderEntPop(reader);
543 }
544 if (node == oldnode)
545 break;
546 if (node->next != NULL) {
547 node = node->next;
548 break;
549 }
550 } while ((node != NULL) && (node != oldnode));
551 } while ((node != NULL) && (node != oldnode));
552 reader->node = oldnode;
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000553#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000554}
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000555
556
557/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000558 * xmlTextReaderRead:
559 * @reader: the xmlTextReaderPtr used
560 *
561 * Moves the position of the current instance to the next node in
562 * the stream, exposing its properties.
563 *
564 * Returns 1 if the node was read successfully, 0 if there is no more
565 * nodes to read, or -1 in case of error
566 */
567int
568xmlTextReaderRead(xmlTextReaderPtr reader) {
Daniel Veillard067bae52003-01-05 01:27:54 +0000569 int val, olddepth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000570 xmlTextReaderState oldstate = 0;
571 xmlNodePtr oldnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000572
573 if ((reader == NULL) || (reader->ctxt == NULL))
574 return(-1);
575 if (reader->ctxt->wellFormed != 1)
576 return(-1);
577
578#ifdef DEBUG_READER
579 fprintf(stderr, "\nREAD ");
580 DUMP_READER
581#endif
Daniel Veillard29b3e282002-12-29 11:14:41 +0000582 reader->curnode = NULL;
Daniel Veillard67df8092002-12-16 22:04:11 +0000583 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
584 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000585 /*
586 * Initial state
587 */
588 do {
589 val = xmlTextReaderPushData(reader);
590 if (val < 0)
591 return(-1);
592 } while ((reader->ctxt->node == NULL) &&
Daniel Veillard067bae52003-01-05 01:27:54 +0000593 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
594 (reader->mode != XML_TEXTREADER_DONE)));
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000595 if (reader->ctxt->node == NULL) {
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000596 if (reader->ctxt->myDoc != NULL) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000597 reader->node = reader->ctxt->myDoc->children;
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000598 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000599 if (reader->node == NULL)
600 return(-1);
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000601 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000602 } else {
Daniel Veillard48ef4c92003-03-22 12:38:15 +0000603 if (reader->ctxt->myDoc != NULL) {
604 reader->node = reader->ctxt->myDoc->children;
605 }
606 if (reader->node == NULL)
607 reader->node = reader->ctxt->nodeTab[0];
Daniel Veillarde59494f2003-01-04 16:35:29 +0000608 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000609 }
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000610 reader->depth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000611 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000612 }
613 oldstate = reader->state;
614 olddepth = reader->ctxt->nodeNr;
615 oldnode = reader->node;
Daniel Veillarddf512f42002-12-23 15:56:21 +0000616
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000617get_next_node:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000618 /*
619 * If we are not backtracking on ancestors or examined nodes,
620 * that the parser didn't finished or that we arent at the end
621 * of stream, continue processing.
622 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000623 while (((oldstate == XML_TEXTREADER_BACKTRACK) ||
624 (reader->node->children == NULL) ||
625 (reader->node->type == XML_ENTITY_REF_NODE) ||
Daniel Veillard4dbe77a2003-01-14 00:17:42 +0000626 (reader->node->type == XML_DTD_NODE) ||
627 (reader->node->type == XML_DOCUMENT_NODE) ||
628 (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
Daniel Veillardea7751d2002-12-20 00:16:24 +0000629 (reader->node->next == NULL) &&
Daniel Veillard4dbe77a2003-01-14 00:17:42 +0000630 ((reader->ctxt->node == NULL) ||
631 (reader->ctxt->node == reader->node) ||
632 (reader->ctxt->node == reader->node->parent)) &&
Daniel Veillardea7751d2002-12-20 00:16:24 +0000633 (reader->ctxt->nodeNr == olddepth) &&
634 (reader->ctxt->instate != XML_PARSER_EOF)) {
635 val = xmlTextReaderPushData(reader);
636 if (val < 0)
637 return(-1);
638 if (reader->node == NULL)
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000639 goto node_end;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000640 }
Daniel Veillard120e8eb2003-03-22 01:00:34 +0000641 /*
642 * If we are in the middle of a piece of CDATA make sure it's finished
643 * Maybe calling a function checking that a non-character() callback was
644 * received would be cleaner for the loop exit.
645 */
646 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
647 (reader->ctxt->instate == XML_PARSER_CDATA_SECTION)) {
648 while ((reader->ctxt->instate == XML_PARSER_CDATA_SECTION) &&
649 (((reader->node->content == NULL) &&
650 (reader->node->next != NULL) &&
651 (reader->node->next->type == XML_CDATA_SECTION_NODE) &&
652 (reader->node->next->next == NULL) &&
653 (reader->node->parent->next == NULL)) ||
654 ((reader->node->children != NULL) &&
655 (reader->node->children->type == XML_CDATA_SECTION_NODE) &&
656 (reader->node->children->next == NULL) &&
657 (reader->node->children->next == NULL)))) {
658 val = xmlTextReaderPushData(reader);
659 if (val < 0)
660 return(-1);
661 }
662 }
663 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
664 (reader->ctxt->instate == XML_PARSER_CONTENT)) {
665 while ((reader->ctxt->instate == XML_PARSER_CONTENT) &&
666 (((reader->node->content == NULL) &&
667 (reader->node->next != NULL) &&
668 (reader->node->next->type == XML_TEXT_NODE) &&
669 (reader->node->next->next == NULL) &&
670 (reader->node->parent->next == NULL)) ||
671 ((reader->node->children != NULL) &&
672 (reader->node->children->type == XML_TEXT_NODE) &&
673 (reader->node->children->next == NULL) &&
674 (reader->node->children->next == NULL)))) {
675 val = xmlTextReaderPushData(reader);
676 if (val < 0)
677 return(-1);
678 }
679 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000680 if (oldstate != XML_TEXTREADER_BACKTRACK) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000681 if ((reader->node->children != NULL) &&
682 (reader->node->type != XML_ENTITY_REF_NODE) &&
683 (reader->node->type != XML_DTD_NODE)) {
684 reader->node = reader->node->children;
685 reader->depth++;
Daniel Veillarddf512f42002-12-23 15:56:21 +0000686 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000687 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000688 }
689 }
690 if (reader->node->next != NULL) {
691 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillarddf512f42002-12-23 15:56:21 +0000692 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +0000693 (reader->node->children == NULL) &&
694 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000695 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000696 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000697 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000698 if ((reader->ctxt->validate) &&
699 (reader->node->type == XML_ELEMENT_NODE))
700 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000701 reader->node = reader->node->next;
702 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000703
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000704 /*
705 * Cleanup of the old node
706 */
Daniel Veillard4dbe77a2003-01-14 00:17:42 +0000707 if ((reader->node->prev != NULL) &&
708 (reader->node->prev->type != XML_DTD_NODE)) {
709 xmlNodePtr tmp = reader->node->prev;
710 xmlUnlinkNode(tmp);
711 xmlFreeNode(tmp);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000712 }
713
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000714 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000715 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000716 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillard571b8892002-12-30 12:37:59 +0000717 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +0000718 (reader->node->children == NULL) &&
719 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000720 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000721 goto node_found;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000722 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000723 if ((reader->ctxt->validate) && (reader->node->type == XML_ELEMENT_NODE))
724 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000725 reader->node = reader->node->parent;
726 if ((reader->node == NULL) ||
727 (reader->node->type == XML_DOCUMENT_NODE) ||
728#ifdef LIBXML_DOCB_ENABLED
729 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
730#endif
731 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000732 if (reader->mode != XML_TEXTREADER_DONE) {
733 val = xmlParseChunk(reader->ctxt, "", 0, 1);
734 reader->mode = XML_TEXTREADER_DONE;
735 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000736 reader->node = NULL;
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000737 reader->depth = -1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000738
739 /*
740 * Cleanup of the old node
741 */
742 if (oldnode->type != XML_DTD_NODE) {
743 xmlUnlinkNode(oldnode);
744 xmlFreeNode(oldnode);
745 }
746
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000747 goto node_end;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000748 }
749 reader->depth--;
750 reader->state = XML_TEXTREADER_BACKTRACK;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000751
752node_found:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000753 DUMP_READER
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000754
755 /*
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000756 * Handle entities enter and exit when in entity replacement mode
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000757 */
758 if ((reader->node != NULL) &&
759 (reader->node->type == XML_ENTITY_REF_NODE) &&
760 (reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
761 /*
762 * Case where the underlying tree is not availble, lookup the entity
763 * and walk it.
764 */
765 if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
766 (reader->ctxt->sax->getEntity != NULL)) {
767 reader->node->children = (xmlNodePtr)
768 reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
769 }
770
771 if ((reader->node->children != NULL) &&
772 (reader->node->children->type == XML_ENTITY_DECL) &&
773 (reader->node->children->children != NULL)) {
774 xmlTextReaderEntPush(reader, reader->node);
775 reader->node = reader->node->children->children;
776 }
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000777 } else if ((reader->node != NULL) &&
778 (reader->node->type == XML_ENTITY_REF_NODE) &&
779 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
780 xmlTextReaderValidateEntity(reader);
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000781 }
782 if ((reader->node != NULL) &&
783 (reader->node->type == XML_ENTITY_DECL) &&
784 (reader->ent != NULL) && (reader->ent->children == reader->node)) {
785 reader->node = xmlTextReaderEntPop(reader);
786 reader->depth++;
787 goto get_next_node;
788 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000789#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000790 if ((reader->ctxt->validate) && (reader->node != NULL)) {
791 xmlNodePtr node = reader->node;
792 xmlParserCtxtPtr ctxt = reader->ctxt;
793
794 if ((node->type == XML_ELEMENT_NODE) &&
795 ((reader->state != XML_TEXTREADER_END) &&
796 (reader->state != XML_TEXTREADER_BACKTRACK))) {
797 xmlTextReaderValidatePush(reader);
798 } else if ((node->type == XML_TEXT_NODE) ||
799 (node->type == XML_CDATA_SECTION_NODE)) {
800 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt,
801 node->content, xmlStrlen(node->content));
802 }
803 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000804#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000805 return(1);
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000806node_end:
807 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000808}
809
Daniel Veillard67df8092002-12-16 22:04:11 +0000810/**
811 * xmlTextReaderReadState:
812 * @reader: the xmlTextReaderPtr used
813 *
814 * Gets the read state of the reader.
815 *
816 * Returns the state value, or -1 in case of error
817 */
818int
819xmlTextReaderReadState(xmlTextReaderPtr reader) {
820 if (reader == NULL)
821 return(-1);
822 return(reader->mode);
823}
824
825/**
826 * xmlTextReaderReadInnerXml:
827 * @reader: the xmlTextReaderPtr used
828 *
829 * Reads the contents of the current node, including child nodes and markup.
830 *
831 * Returns a string containing the XML content, or NULL if the current node
832 * is neither an element nor attribute, or has no child nodes. The
833 * string must be deallocated by the caller.
834 */
835xmlChar *
836xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) {
837 TODO
838 return(NULL);
839}
840
841/**
842 * xmlTextReaderReadOuterXml:
843 * @reader: the xmlTextReaderPtr used
844 *
845 * Reads the contents of the current node, including child nodes and markup.
846 *
847 * Returns a string containing the XML content, or NULL if the current node
848 * is neither an element nor attribute, or has no child nodes. The
849 * string must be deallocated by the caller.
850 */
851xmlChar *
852xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) {
853 TODO
854 return(NULL);
855}
856
857/**
858 * xmlTextReaderReadString:
859 * @reader: the xmlTextReaderPtr used
860 *
861 * Reads the contents of an element or a text node as a string.
862 *
863 * Returns a string containing the contents of the Element or Text node,
864 * or NULL if the reader is positioned on any other type of node.
865 * The string must be deallocated by the caller.
866 */
867xmlChar *
868xmlTextReaderReadString(xmlTextReaderPtr reader) {
869 TODO
870 return(NULL);
871}
872
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000873/**
874 * xmlTextReaderReadBase64:
875 * @reader: the xmlTextReaderPtr used
876 * @array: a byte array to store the content.
877 * @offset: the zero-based index into array where the method should
878 * begin to write.
879 * @len: the number of bytes to write.
880 *
881 * Reads and decodes the Base64 encoded contents of an element and
882 * stores the result in a byte buffer.
883 *
884 * Returns the number of bytes written to array, or zero if the current
885 * instance is not positioned on an element or -1 in case of error.
886 */
887int
888xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
889 int offset, int len) {
890 if ((reader == NULL) || (reader->ctxt == NULL))
891 return(-1);
892 if (reader->ctxt->wellFormed != 1)
893 return(-1);
894
895 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
896 return(0);
897 TODO
898 return(0);
899}
900
901/**
902 * xmlTextReaderReadBinHex:
903 * @reader: the xmlTextReaderPtr used
904 * @array: a byte array to store the content.
905 * @offset: the zero-based index into array where the method should
906 * begin to write.
907 * @len: the number of bytes to write.
908 *
909 * Reads and decodes the BinHex encoded contents of an element and
910 * stores the result in a byte buffer.
911 *
912 * Returns the number of bytes written to array, or zero if the current
913 * instance is not positioned on an element or -1 in case of error.
914 */
915int
916xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
917 int offset, int len) {
918 if ((reader == NULL) || (reader->ctxt == NULL))
919 return(-1);
920 if (reader->ctxt->wellFormed != 1)
921 return(-1);
922
923 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
924 return(0);
925 TODO
926 return(0);
927}
928
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000929/************************************************************************
930 * *
931 * Constructor and destructors *
932 * *
933 ************************************************************************/
934/**
935 * xmlNewTextReader:
936 * @input: the xmlParserInputBufferPtr used to read data
Daniel Veillardea7751d2002-12-20 00:16:24 +0000937 * @URI: the URI information for the source if available
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000938 *
939 * Create an xmlTextReader structure fed with @input
940 *
941 * Returns the new xmlTextReaderPtr or NULL in case of error
942 */
943xmlTextReaderPtr
Daniel Veillardea7751d2002-12-20 00:16:24 +0000944xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000945 xmlTextReaderPtr ret;
946 int val;
947
948 if (input == NULL)
949 return(NULL);
950 ret = xmlMalloc(sizeof(xmlTextReader));
951 if (ret == NULL) {
952 xmlGenericError(xmlGenericErrorContext,
953 "xmlNewTextReader : malloc failed\n");
954 return(NULL);
955 }
956 memset(ret, 0, sizeof(xmlTextReader));
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000957 ret->entTab = NULL;
958 ret->entMax = 0;
959 ret->entNr = 0;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000960 ret->input = input;
961 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
962 if (ret->sax == NULL) {
963 xmlFree(ret);
964 xmlGenericError(xmlGenericErrorContext,
965 "xmlNewTextReader : malloc failed\n");
966 return(NULL);
967 }
968 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
969 ret->startElement = ret->sax->startElement;
970 ret->sax->startElement = xmlTextReaderStartElement;
971 ret->endElement = ret->sax->endElement;
972 ret->sax->endElement = xmlTextReaderEndElement;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000973 ret->characters = ret->sax->characters;
974 ret->sax->characters = xmlTextReaderCharacters;
975 ret->cdataBlock = ret->sax->cdataBlock;
976 ret->sax->cdataBlock = xmlTextReaderCDataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000977
Daniel Veillard67df8092002-12-16 22:04:11 +0000978 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000979 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000980 ret->curnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000981 val = xmlParserInputBufferRead(input, 4);
982 if (val >= 4) {
983 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
Daniel Veillardea7751d2002-12-20 00:16:24 +0000984 (const char *) ret->input->buffer->content, 4, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000985 ret->base = 0;
986 ret->cur = 4;
987 } else {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000988 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000989 ret->base = 0;
990 ret->cur = 0;
991 }
992 ret->ctxt->_private = ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000993 ret->ctxt->linenumbers = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000994 ret->allocs = XML_TEXTREADER_CTXT;
995 return(ret);
996
997}
998
999/**
1000 * xmlNewTextReaderFilename:
1001 * @URI: the URI of the resource to process
1002 *
1003 * Create an xmlTextReader structure fed with the resource at @URI
1004 *
1005 * Returns the new xmlTextReaderPtr or NULL in case of error
1006 */
1007xmlTextReaderPtr
1008xmlNewTextReaderFilename(const char *URI) {
1009 xmlParserInputBufferPtr input;
1010 xmlTextReaderPtr ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001011 char *directory = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001012
1013 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
1014 if (input == NULL)
1015 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00001016 ret = xmlNewTextReader(input, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001017 if (ret == NULL) {
1018 xmlFreeParserInputBuffer(input);
1019 return(NULL);
1020 }
1021 ret->allocs |= XML_TEXTREADER_INPUT;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001022 if (ret->ctxt->directory == NULL)
1023 directory = xmlParserGetDirectory(URI);
1024 if ((ret->ctxt->directory == NULL) && (directory != NULL))
1025 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
1026 if (directory != NULL)
1027 xmlFree(directory);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001028 return(ret);
1029}
1030
1031/**
1032 * xmlFreeTextReader:
1033 * @reader: the xmlTextReaderPtr
1034 *
1035 * Deallocate all the resources associated to the reader
1036 */
1037void
1038xmlFreeTextReader(xmlTextReaderPtr reader) {
1039 if (reader == NULL)
1040 return;
1041 if (reader->ctxt != NULL) {
1042 if (reader->ctxt->myDoc != NULL) {
1043 xmlFreeDoc(reader->ctxt->myDoc);
1044 reader->ctxt->myDoc = NULL;
1045 }
Daniel Veillard336fc7d2002-12-27 19:37:04 +00001046 if ((reader->ctxt->vctxt.vstateTab != NULL) &&
1047 (reader->ctxt->vctxt.vstateMax > 0)){
1048 xmlFree(reader->ctxt->vctxt.vstateTab);
1049 reader->ctxt->vctxt.vstateTab = 0;
1050 reader->ctxt->vctxt.vstateMax = 0;
1051 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001052 if (reader->allocs & XML_TEXTREADER_CTXT)
1053 xmlFreeParserCtxt(reader->ctxt);
1054 }
1055 if (reader->sax != NULL)
1056 xmlFree(reader->sax);
1057 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
1058 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001059 if (reader->faketext != NULL) {
1060 xmlFreeNode(reader->faketext);
1061 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001062 if (reader->entTab != NULL)
1063 xmlFree(reader->entTab);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001064 xmlFree(reader);
1065}
1066
1067/************************************************************************
1068 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001069 * Methods for XmlTextReader *
1070 * *
1071 ************************************************************************/
1072/**
1073 * xmlTextReaderClose:
1074 * @reader: the xmlTextReaderPtr used
1075 *
1076 * This method releases any resources allocated by the current instance
1077 * changes the state to Closed and close any underlying input.
1078 *
1079 * Returns 0 or -1 in case of error
1080 */
1081int
1082xmlTextReaderClose(xmlTextReaderPtr reader) {
1083 if (reader == NULL)
1084 return(-1);
1085 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001086 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001087 reader->mode = XML_TEXTREADER_MODE_CLOSED;
1088 if (reader->ctxt != NULL) {
1089 if (reader->ctxt->myDoc != NULL) {
1090 xmlFreeDoc(reader->ctxt->myDoc);
1091 reader->ctxt->myDoc = NULL;
1092 }
1093 if (reader->allocs & XML_TEXTREADER_CTXT) {
1094 xmlFreeParserCtxt(reader->ctxt);
1095 reader->allocs -= XML_TEXTREADER_CTXT;
1096 }
1097 }
1098 if (reader->sax != NULL) {
1099 xmlFree(reader->sax);
1100 reader->sax = NULL;
1101 }
1102 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
1103 xmlFreeParserInputBuffer(reader->input);
1104 reader->allocs -= XML_TEXTREADER_INPUT;
1105 }
1106 return(0);
1107}
1108
1109/**
1110 * xmlTextReaderGetAttributeNo:
1111 * @reader: the xmlTextReaderPtr used
1112 * @no: the zero-based index of the attribute relative to the containing element
1113 *
1114 * Provides the value of the attribute with the specified index relative
1115 * to the containing element.
1116 *
1117 * Returns a string containing the value of the specified attribute, or NULL
1118 * in case of error. The string must be deallocated by the caller.
1119 */
1120xmlChar *
1121xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
1122 xmlChar *ret;
1123 int i;
1124 xmlAttrPtr cur;
1125 xmlNsPtr ns;
1126
1127 if (reader == NULL)
1128 return(NULL);
1129 if (reader->node == NULL)
1130 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001131 if (reader->curnode != NULL)
1132 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001133 /* TODO: handle the xmlDecl */
1134 if (reader->node->type != XML_ELEMENT_NODE)
1135 return(NULL);
1136
1137 ns = reader->node->nsDef;
1138 for (i = 0;(i < no) && (ns != NULL);i++) {
1139 ns = ns->next;
1140 }
1141 if (ns != NULL)
1142 return(xmlStrdup(ns->href));
1143
1144 cur = reader->node->properties;
1145 if (cur == NULL)
1146 return(NULL);
1147 for (;i < no;i++) {
1148 cur = cur->next;
1149 if (cur == NULL)
1150 return(NULL);
1151 }
1152 /* TODO walk the DTD if present */
1153
1154 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
1155 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
1156 return(ret);
1157}
1158
1159/**
1160 * xmlTextReaderGetAttribute:
1161 * @reader: the xmlTextReaderPtr used
1162 * @name: the qualified name of the attribute.
1163 *
1164 * Provides the value of the attribute with the specified qualified name.
1165 *
1166 * Returns a string containing the value of the specified attribute, or NULL
1167 * in case of error. The string must be deallocated by the caller.
1168 */
1169xmlChar *
1170xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1171 xmlChar *prefix = NULL;
1172 xmlChar *localname;
1173 xmlNsPtr ns;
1174 xmlChar *ret = NULL;
1175
1176 if ((reader == NULL) || (name == NULL))
1177 return(NULL);
1178 if (reader->node == NULL)
1179 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001180 if (reader->curnode != NULL)
1181 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001182
1183 /* TODO: handle the xmlDecl */
1184 if (reader->node->type != XML_ELEMENT_NODE)
1185 return(NULL);
1186
1187 localname = xmlSplitQName2(name, &prefix);
1188 if (localname == NULL)
1189 return(xmlGetProp(reader->node, name));
1190
1191 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1192 if (ns != NULL)
1193 ret = xmlGetNsProp(reader->node, localname, ns->href);
1194
1195 if (localname != NULL)
1196 xmlFree(localname);
1197 if (prefix != NULL)
1198 xmlFree(prefix);
1199 return(ret);
1200}
1201
1202
1203/**
1204 * xmlTextReaderGetAttributeNs:
1205 * @reader: the xmlTextReaderPtr used
1206 * @localName: the local name of the attribute.
1207 * @namespaceURI: the namespace URI of the attribute.
1208 *
1209 * Provides the value of the specified attribute
1210 *
1211 * Returns a string containing the value of the specified attribute, or NULL
1212 * in case of error. The string must be deallocated by the caller.
1213 */
1214xmlChar *
1215xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
1216 const xmlChar *namespaceURI) {
1217 if ((reader == NULL) || (localName == NULL))
1218 return(NULL);
1219 if (reader->node == NULL)
1220 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001221 if (reader->curnode != NULL)
1222 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001223
1224 /* TODO: handle the xmlDecl */
1225 if (reader->node->type != XML_ELEMENT_NODE)
1226 return(NULL);
1227
1228 return(xmlGetNsProp(reader->node, localName, namespaceURI));
1229}
1230
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001231/**
1232 * xmlTextReaderGetRemainder:
1233 * @reader: the xmlTextReaderPtr used
1234 *
1235 * Method to get the remainder of the buffered XML. this method stops the
1236 * parser, set its state to End Of File and return the input stream with
1237 * what is left that the parser did not use.
1238 *
1239 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
1240 * in case of error.
1241 */
1242xmlParserInputBufferPtr
1243xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
1244 xmlParserInputBufferPtr ret = NULL;
1245
1246 if (reader == NULL)
1247 return(NULL);
1248 if (reader->node == NULL)
1249 return(NULL);
1250
1251 reader->node = NULL;
1252 reader->curnode = NULL;
1253 reader->mode = XML_TEXTREADER_MODE_EOF;
1254 if (reader->ctxt != NULL) {
1255 if (reader->ctxt->myDoc != NULL) {
1256 xmlFreeDoc(reader->ctxt->myDoc);
1257 reader->ctxt->myDoc = NULL;
1258 }
1259 if (reader->allocs & XML_TEXTREADER_CTXT) {
1260 xmlFreeParserCtxt(reader->ctxt);
1261 reader->allocs -= XML_TEXTREADER_CTXT;
1262 }
1263 }
1264 if (reader->sax != NULL) {
1265 xmlFree(reader->sax);
1266 reader->sax = NULL;
1267 }
1268 if (reader->allocs & XML_TEXTREADER_INPUT) {
1269 ret = reader->input;
1270 reader->allocs -= XML_TEXTREADER_INPUT;
1271 } else {
1272 /*
1273 * Hum, one may need to duplicate the data structure because
1274 * without reference counting the input may be freed twice:
1275 * - by the layer which allocated it.
1276 * - by the layer to which would have been returned to.
1277 */
1278 TODO
1279 return(NULL);
1280 }
1281 return(ret);
1282}
1283
1284/**
1285 * xmlTextReaderLookupNamespace:
1286 * @reader: the xmlTextReaderPtr used
1287 * @prefix: the prefix whose namespace URI is to be resolved. To return
1288 * the default namespace, specify NULL
1289 *
1290 * Resolves a namespace prefix in the scope of the current element.
1291 *
1292 * Returns a string containing the namespace URI to which the prefix maps
1293 * or NULL in case of error. The string must be deallocated by the caller.
1294 */
1295xmlChar *
1296xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
1297 xmlNsPtr ns;
1298
1299 if (reader == NULL)
1300 return(NULL);
1301 if (reader->node == NULL)
1302 return(NULL);
1303
1304 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1305 if (ns == NULL)
1306 return(NULL);
1307 return(xmlStrdup(ns->href));
1308}
1309
1310/**
1311 * xmlTextReaderMoveToAttributeNo:
1312 * @reader: the xmlTextReaderPtr used
1313 * @no: the zero-based index of the attribute relative to the containing
1314 * element.
1315 *
1316 * Moves the position of the current instance to the attribute with
1317 * the specified index relative to the containing element.
1318 *
1319 * Returns 1 in case of success, -1 in case of error, 0 if not found
1320 */
1321int
1322xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
1323 int i;
1324 xmlAttrPtr cur;
1325 xmlNsPtr ns;
1326
1327 if (reader == NULL)
1328 return(-1);
1329 if (reader->node == NULL)
1330 return(-1);
1331 /* TODO: handle the xmlDecl */
1332 if (reader->node->type != XML_ELEMENT_NODE)
1333 return(-1);
1334
1335 reader->curnode = NULL;
1336
1337 ns = reader->node->nsDef;
1338 for (i = 0;(i < no) && (ns != NULL);i++) {
1339 ns = ns->next;
1340 }
1341 if (ns != NULL) {
1342 reader->curnode = (xmlNodePtr) ns;
1343 return(1);
1344 }
1345
1346 cur = reader->node->properties;
1347 if (cur == NULL)
1348 return(0);
1349 for (;i < no;i++) {
1350 cur = cur->next;
1351 if (cur == NULL)
1352 return(0);
1353 }
1354 /* TODO walk the DTD if present */
1355
1356 reader->curnode = (xmlNodePtr) cur;
1357 return(1);
1358}
1359
1360/**
1361 * xmlTextReaderMoveToAttribute:
1362 * @reader: the xmlTextReaderPtr used
1363 * @name: the qualified name of the attribute.
1364 *
1365 * Moves the position of the current instance to the attribute with
1366 * the specified qualified name.
1367 *
1368 * Returns 1 in case of success, -1 in case of error, 0 if not found
1369 */
1370int
1371xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1372 xmlChar *prefix = NULL;
1373 xmlChar *localname;
1374 xmlNsPtr ns;
1375 xmlAttrPtr prop;
1376
1377 if ((reader == NULL) || (name == NULL))
1378 return(-1);
1379 if (reader->node == NULL)
1380 return(-1);
1381
1382 /* TODO: handle the xmlDecl */
1383 if (reader->node->type != XML_ELEMENT_NODE)
1384 return(0);
1385
1386 localname = xmlSplitQName2(name, &prefix);
1387 if (localname == NULL) {
1388 /*
1389 * Namespace default decl
1390 */
1391 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1392 ns = reader->node->nsDef;
1393 while (ns != NULL) {
1394 if (ns->prefix == NULL) {
1395 reader->curnode = (xmlNodePtr) ns;
1396 return(1);
1397 }
1398 ns = ns->next;
1399 }
1400 return(0);
1401 }
1402
1403 prop = reader->node->properties;
1404 while (prop != NULL) {
1405 /*
1406 * One need to have
1407 * - same attribute names
1408 * - and the attribute carrying that namespace
1409 */
1410 if ((xmlStrEqual(prop->name, name)) &&
1411 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
1412 reader->curnode = (xmlNodePtr) prop;
1413 return(1);
1414 }
1415 prop = prop->next;
1416 }
1417 return(0);
1418 }
1419
1420 /*
1421 * Namespace default decl
1422 */
1423 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
1424 ns = reader->node->nsDef;
1425 while (ns != NULL) {
1426 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
1427 reader->curnode = (xmlNodePtr) ns;
1428 goto found;
1429 }
1430 ns = ns->next;
1431 }
1432 goto not_found;
1433 }
1434 prop = reader->node->properties;
1435 while (prop != NULL) {
1436 /*
1437 * One need to have
1438 * - same attribute names
1439 * - and the attribute carrying that namespace
1440 */
1441 if ((xmlStrEqual(prop->name, localname)) &&
1442 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
1443 reader->curnode = (xmlNodePtr) prop;
1444 goto found;
1445 }
1446 prop = prop->next;
1447 }
1448not_found:
1449 if (localname != NULL)
1450 xmlFree(localname);
1451 if (prefix != NULL)
1452 xmlFree(prefix);
1453 return(0);
1454
1455found:
1456 if (localname != NULL)
1457 xmlFree(localname);
1458 if (prefix != NULL)
1459 xmlFree(prefix);
1460 return(1);
1461}
1462
1463/**
1464 * xmlTextReaderMoveToAttributeNs:
1465 * @reader: the xmlTextReaderPtr used
1466 * @localName: the local name of the attribute.
1467 * @namespaceURI: the namespace URI of the attribute.
1468 *
1469 * Moves the position of the current instance to the attribute with the
1470 * specified local name and namespace URI.
1471 *
1472 * Returns 1 in case of success, -1 in case of error, 0 if not found
1473 */
1474int
1475xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1476 const xmlChar *localName, const xmlChar *namespaceURI) {
1477 xmlAttrPtr prop;
1478 xmlNodePtr node;
1479
1480 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1481 return(-1);
1482 if (reader->node == NULL)
1483 return(-1);
1484 if (reader->node->type != XML_ELEMENT_NODE)
1485 return(0);
1486 node = reader->node;
1487
1488 /*
1489 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1490 * namespace name associated to "xmlns"
1491 */
1492 prop = node->properties;
1493 while (prop != NULL) {
1494 /*
1495 * One need to have
1496 * - same attribute names
1497 * - and the attribute carrying that namespace
1498 */
1499 if (xmlStrEqual(prop->name, localName) &&
1500 ((prop->ns != NULL) &&
1501 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1502 reader->curnode = (xmlNodePtr) prop;
1503 return(1);
1504 }
1505 prop = prop->next;
1506 }
1507 return(0);
1508}
1509
1510/**
1511 * xmlTextReaderMoveToFirstAttribute:
1512 * @reader: the xmlTextReaderPtr used
1513 *
1514 * Moves the position of the current instance to the first attribute
1515 * associated with the current node.
1516 *
1517 * Returns 1 in case of success, -1 in case of error, 0 if not found
1518 */
1519int
1520xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1521 if (reader == NULL)
1522 return(-1);
1523 if (reader->node == NULL)
1524 return(-1);
1525 if (reader->node->type != XML_ELEMENT_NODE)
1526 return(0);
1527
1528 if (reader->node->nsDef != NULL) {
1529 reader->curnode = (xmlNodePtr) reader->node->nsDef;
1530 return(1);
1531 }
1532 if (reader->node->properties != NULL) {
1533 reader->curnode = (xmlNodePtr) reader->node->properties;
1534 return(1);
1535 }
1536 return(0);
1537}
1538
1539/**
1540 * xmlTextReaderMoveToNextAttribute:
1541 * @reader: the xmlTextReaderPtr used
1542 *
1543 * Moves the position of the current instance to the next attribute
1544 * associated with the current node.
1545 *
1546 * Returns 1 in case of success, -1 in case of error, 0 if not found
1547 */
1548int
1549xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1550 if (reader == NULL)
1551 return(-1);
1552 if (reader->node == NULL)
1553 return(-1);
1554 if (reader->node->type != XML_ELEMENT_NODE)
1555 return(0);
1556 if (reader->curnode == NULL)
1557 return(xmlTextReaderMoveToFirstAttribute(reader));
1558
1559 if (reader->curnode->type == XML_NAMESPACE_DECL) {
1560 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1561 if (ns->next != NULL) {
1562 reader->curnode = (xmlNodePtr) ns->next;
1563 return(1);
1564 }
1565 if (reader->node->properties != NULL) {
1566 reader->curnode = (xmlNodePtr) reader->node->properties;
1567 return(1);
1568 }
1569 return(0);
1570 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1571 (reader->curnode->next != NULL)) {
1572 reader->curnode = reader->curnode->next;
1573 return(1);
1574 }
1575 return(0);
1576}
1577
1578/**
1579 * xmlTextReaderMoveToElement:
1580 * @reader: the xmlTextReaderPtr used
1581 *
1582 * Moves the position of the current instance to the node that
1583 * contains the current Attribute node.
1584 *
1585 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1586 */
1587int
1588xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
1589 if (reader == NULL)
1590 return(-1);
1591 if (reader->node == NULL)
1592 return(-1);
1593 if (reader->node->type != XML_ELEMENT_NODE)
1594 return(0);
1595 if (reader->curnode != NULL) {
1596 reader->curnode = NULL;
1597 return(1);
1598 }
1599 return(0);
1600}
1601
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001602/**
1603 * xmlTextReaderReadAttributeValue:
1604 * @reader: the xmlTextReaderPtr used
1605 *
1606 * Parses an attribute value into one or more Text and EntityReference nodes.
1607 *
1608 * Returns 1 in case of success, 0 if the reader was not positionned on an
1609 * ttribute node or all the attribute values have been read, or -1
1610 * in case of error.
1611 */
1612int
1613xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1614 if (reader == NULL)
1615 return(-1);
1616 if (reader->node == NULL)
1617 return(-1);
1618 if (reader->curnode == NULL)
1619 return(0);
1620 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1621 if (reader->curnode->children == NULL)
1622 return(0);
1623 reader->curnode = reader->curnode->children;
1624 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1625 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1626
1627 if (reader->faketext == NULL) {
1628 reader->faketext = xmlNewDocText(reader->node->doc,
1629 ns->href);
1630 } else {
1631 if (reader->faketext->content != NULL)
1632 xmlFree(reader->faketext->content);
1633 reader->faketext->content = xmlStrdup(ns->href);
1634 }
1635 reader->curnode = reader->faketext;
1636 } else {
1637 if (reader->curnode->next == NULL)
1638 return(0);
1639 reader->curnode = reader->curnode->next;
1640 }
1641 return(1);
1642}
1643
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001644/************************************************************************
1645 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001646 * Acces API to the current node *
1647 * *
1648 ************************************************************************/
1649/**
1650 * xmlTextReaderAttributeCount:
1651 * @reader: the xmlTextReaderPtr used
1652 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001653 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001654 *
1655 * Returns 0 i no attributes, -1 in case of error or the attribute count
1656 */
1657int
1658xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1659 int ret;
1660 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00001661 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001662 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001663
1664 if (reader == NULL)
1665 return(-1);
1666 if (reader->node == NULL)
1667 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001668
1669 if (reader->curnode != NULL)
1670 node = reader->curnode;
1671 else
1672 node = reader->node;
1673
1674 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001675 return(0);
1676 if ((reader->state == XML_TEXTREADER_END) ||
1677 (reader->state == XML_TEXTREADER_BACKTRACK))
1678 return(0);
1679 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001680 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001681 while (attr != NULL) {
1682 ret++;
1683 attr = attr->next;
1684 }
Daniel Veillard67df8092002-12-16 22:04:11 +00001685 ns = node->nsDef;
1686 while (ns != NULL) {
1687 ret++;
1688 ns = ns->next;
1689 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001690 return(ret);
1691}
1692
1693/**
1694 * xmlTextReaderNodeType:
1695 * @reader: the xmlTextReaderPtr used
1696 *
1697 * Get the node type of the current node
1698 * Reference:
1699 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1700 *
1701 * Returns the xmlNodeType of the current node or -1 in case of error
1702 */
1703int
1704xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001705 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001706 if (reader == NULL)
1707 return(-1);
1708 if (reader->node == NULL)
1709 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001710 if (reader->curnode != NULL)
1711 node = reader->curnode;
1712 else
1713 node = reader->node;
1714 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001715 case XML_ELEMENT_NODE:
1716 if ((reader->state == XML_TEXTREADER_END) ||
1717 (reader->state == XML_TEXTREADER_BACKTRACK))
1718 return(15);
1719 return(1);
Daniel Veillardecaba492002-12-30 10:55:29 +00001720 case XML_NAMESPACE_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001721 case XML_ATTRIBUTE_NODE:
1722 return(2);
1723 case XML_TEXT_NODE:
1724 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1725 case XML_CDATA_SECTION_NODE:
1726 return(4);
1727 case XML_ENTITY_REF_NODE:
1728 return(5);
1729 case XML_ENTITY_NODE:
1730 return(6);
1731 case XML_PI_NODE:
1732 return(7);
1733 case XML_COMMENT_NODE:
1734 return(8);
1735 case XML_DOCUMENT_NODE:
1736 case XML_HTML_DOCUMENT_NODE:
1737#ifdef LIBXML_DOCB_ENABLED
1738 case XML_DOCB_DOCUMENT_NODE:
1739#endif
1740 return(9);
1741 case XML_DOCUMENT_FRAG_NODE:
1742 return(11);
1743 case XML_NOTATION_NODE:
1744 return(12);
1745 case XML_DOCUMENT_TYPE_NODE:
1746 case XML_DTD_NODE:
1747 return(10);
1748
1749 case XML_ELEMENT_DECL:
1750 case XML_ATTRIBUTE_DECL:
1751 case XML_ENTITY_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001752 case XML_XINCLUDE_START:
1753 case XML_XINCLUDE_END:
1754 return(0);
1755 }
1756 return(-1);
1757}
1758
1759/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001760 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001761 * @reader: the xmlTextReaderPtr used
1762 *
1763 * Check if the current node is empty
1764 *
1765 * Returns 1 if empty, 0 if not and -1 in case of error
1766 */
1767int
1768xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1769 if ((reader == NULL) || (reader->node == NULL))
1770 return(-1);
Daniel Veillarddf512f42002-12-23 15:56:21 +00001771 if (reader->node->type != XML_ELEMENT_NODE)
1772 return(0);
Daniel Veillarde3c036e2003-01-01 15:11:05 +00001773 if (reader->curnode != NULL)
1774 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001775 if (reader->node->children != NULL)
1776 return(0);
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001777 if (reader->state == XML_TEXTREADER_END)
1778 return(0);
Daniel Veillard067bae52003-01-05 01:27:54 +00001779 return(reader->node->_private == (void *)xmlTextReaderIsEmpty);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001780}
1781
1782/**
1783 * xmlTextReaderLocalName:
1784 * @reader: the xmlTextReaderPtr used
1785 *
1786 * The local name of the node.
1787 *
1788 * Returns the local name or NULL if not available
1789 */
1790xmlChar *
1791xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001792 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001793 if ((reader == NULL) || (reader->node == NULL))
1794 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001795 if (reader->curnode != NULL)
1796 node = reader->curnode;
1797 else
1798 node = reader->node;
1799 if (node->type == XML_NAMESPACE_DECL) {
1800 xmlNsPtr ns = (xmlNsPtr) node;
1801 if (ns->prefix == NULL)
1802 return(xmlStrdup(BAD_CAST "xmlns"));
1803 else
1804 return(xmlStrdup(ns->prefix));
1805 }
1806 if ((node->type != XML_ELEMENT_NODE) &&
1807 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001808 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001809 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001810}
1811
1812/**
1813 * xmlTextReaderName:
1814 * @reader: the xmlTextReaderPtr used
1815 *
1816 * The qualified name of the node, equal to Prefix :LocalName.
1817 *
1818 * Returns the local name or NULL if not available
1819 */
1820xmlChar *
1821xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001822 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001823 xmlChar *ret;
1824
1825 if ((reader == NULL) || (reader->node == NULL))
1826 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001827 if (reader->curnode != NULL)
1828 node = reader->curnode;
1829 else
1830 node = reader->node;
1831 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001832 case XML_ELEMENT_NODE:
1833 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001834 if ((node->ns == NULL) ||
1835 (node->ns->prefix == NULL))
1836 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001837
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001838 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001839 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001840 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001841 return(ret);
1842 case XML_TEXT_NODE:
1843 return(xmlStrdup(BAD_CAST "#text"));
1844 case XML_CDATA_SECTION_NODE:
1845 return(xmlStrdup(BAD_CAST "#cdata-section"));
1846 case XML_ENTITY_NODE:
1847 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001848 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001849 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001850 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001851 case XML_COMMENT_NODE:
1852 return(xmlStrdup(BAD_CAST "#comment"));
1853 case XML_DOCUMENT_NODE:
1854 case XML_HTML_DOCUMENT_NODE:
1855#ifdef LIBXML_DOCB_ENABLED
1856 case XML_DOCB_DOCUMENT_NODE:
1857#endif
1858 return(xmlStrdup(BAD_CAST "#document"));
1859 case XML_DOCUMENT_FRAG_NODE:
1860 return(xmlStrdup(BAD_CAST "#document-fragment"));
1861 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001862 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001863 case XML_DOCUMENT_TYPE_NODE:
1864 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001865 return(xmlStrdup(node->name));
1866 case XML_NAMESPACE_DECL: {
1867 xmlNsPtr ns = (xmlNsPtr) node;
1868
1869 ret = xmlStrdup(BAD_CAST "xmlns");
1870 if (ns->prefix == NULL)
1871 return(ret);
1872 ret = xmlStrcat(ret, BAD_CAST ":");
1873 ret = xmlStrcat(ret, ns->prefix);
1874 return(ret);
1875 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001876
1877 case XML_ELEMENT_DECL:
1878 case XML_ATTRIBUTE_DECL:
1879 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001880 case XML_XINCLUDE_START:
1881 case XML_XINCLUDE_END:
1882 return(NULL);
1883 }
1884 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001885}
1886
1887/**
1888 * xmlTextReaderPrefix:
1889 * @reader: the xmlTextReaderPtr used
1890 *
1891 * A shorthand reference to the namespace associated with the node.
1892 *
1893 * Returns the prefix or NULL if not available
1894 */
1895xmlChar *
1896xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001897 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001898 if ((reader == NULL) || (reader->node == NULL))
1899 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001900 if (reader->curnode != NULL)
1901 node = reader->curnode;
1902 else
1903 node = reader->node;
1904 if (node->type == XML_NAMESPACE_DECL) {
1905 xmlNsPtr ns = (xmlNsPtr) node;
1906 if (ns->prefix == NULL)
1907 return(NULL);
1908 return(xmlStrdup(BAD_CAST "xmlns"));
1909 }
1910 if ((node->type != XML_ELEMENT_NODE) &&
1911 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001912 return(NULL);
Daniel Veillard952379b2003-03-17 15:37:12 +00001913 if ((node->ns != NULL) && (node->ns->prefix != NULL))
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001914 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001915 return(NULL);
1916}
1917
1918/**
1919 * xmlTextReaderNamespaceUri:
1920 * @reader: the xmlTextReaderPtr used
1921 *
1922 * The URI defining the namespace associated with the node.
1923 *
1924 * Returns the namespace URI or NULL if not available
1925 */
1926xmlChar *
1927xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001928 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001929 if ((reader == NULL) || (reader->node == NULL))
1930 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001931 if (reader->curnode != NULL)
1932 node = reader->curnode;
1933 else
1934 node = reader->node;
Daniel Veillardecaba492002-12-30 10:55:29 +00001935 if (node->type == XML_NAMESPACE_DECL)
1936 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001937 if ((node->type != XML_ELEMENT_NODE) &&
1938 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001939 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001940 if (node->ns != NULL)
1941 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001942 return(NULL);
1943}
1944
1945/**
1946 * xmlTextReaderBaseUri:
1947 * @reader: the xmlTextReaderPtr used
1948 *
1949 * The base URI of the node.
1950 *
1951 * Returns the base URI or NULL if not available
1952 */
1953xmlChar *
1954xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
1955 if ((reader == NULL) || (reader->node == NULL))
1956 return(NULL);
1957 return(xmlNodeGetBase(NULL, reader->node));
1958}
1959
1960/**
1961 * xmlTextReaderDepth:
1962 * @reader: the xmlTextReaderPtr used
1963 *
1964 * The depth of the node in the tree.
1965 *
1966 * Returns the depth or -1 in case of error
1967 */
1968int
1969xmlTextReaderDepth(xmlTextReaderPtr reader) {
1970 if (reader == NULL)
1971 return(-1);
1972 if (reader->node == NULL)
1973 return(0);
1974
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001975 if (reader->curnode != NULL) {
1976 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
1977 (reader->curnode->type == XML_NAMESPACE_DECL))
1978 return(reader->depth + 1);
1979 return(reader->depth + 2);
1980 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001981 return(reader->depth);
1982}
1983
1984/**
1985 * xmlTextReaderHasAttributes:
1986 * @reader: the xmlTextReaderPtr used
1987 *
1988 * Whether the node has attributes.
1989 *
1990 * Returns 1 if true, 0 if false, and -1 in case or error
1991 */
1992int
1993xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001994 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001995 if (reader == NULL)
1996 return(-1);
1997 if (reader->node == NULL)
1998 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001999 if (reader->curnode != NULL)
2000 node = reader->curnode;
2001 else
2002 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002003
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002004 if ((node->type == XML_ELEMENT_NODE) &&
2005 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002006 return(1);
2007 /* TODO: handle the xmlDecl */
2008 return(0);
2009}
2010
2011/**
2012 * xmlTextReaderHasValue:
2013 * @reader: the xmlTextReaderPtr used
2014 *
2015 * Whether the node can have a text value.
2016 *
2017 * Returns 1 if true, 0 if false, and -1 in case or error
2018 */
2019int
2020xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002021 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002022 if (reader == NULL)
2023 return(-1);
2024 if (reader->node == NULL)
2025 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002026 if (reader->curnode != NULL)
2027 node = reader->curnode;
2028 else
2029 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002030
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002031 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002032 case XML_ATTRIBUTE_NODE:
2033 case XML_TEXT_NODE:
2034 case XML_CDATA_SECTION_NODE:
2035 case XML_PI_NODE:
2036 case XML_COMMENT_NODE:
Daniel Veillard9e077102003-04-10 13:36:54 +00002037 case XML_NAMESPACE_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002038 return(1);
2039 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002040 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002041 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002042 return(0);
2043}
2044
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002045/**
2046 * xmlTextReaderValue:
2047 * @reader: the xmlTextReaderPtr used
2048 *
2049 * Provides the text value of the node if present
2050 *
2051 * Returns the string or NULL if not available. The retsult must be deallocated
2052 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002053 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002054xmlChar *
2055xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002056 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002057 if (reader == NULL)
2058 return(NULL);
2059 if (reader->node == NULL)
2060 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002061 if (reader->curnode != NULL)
2062 node = reader->curnode;
2063 else
2064 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002065
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002066 switch (node->type) {
2067 case XML_NAMESPACE_DECL:
2068 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002069 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002070 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002071
2072 if (attr->parent != NULL)
2073 return (xmlNodeListGetString
2074 (attr->parent->doc, attr->children, 1));
2075 else
2076 return (xmlNodeListGetString(NULL, attr->children, 1));
2077 break;
2078 }
2079 case XML_TEXT_NODE:
2080 case XML_CDATA_SECTION_NODE:
2081 case XML_PI_NODE:
2082 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002083 if (node->content != NULL)
2084 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002085 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002086 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002087 }
2088 return(NULL);
2089}
2090
2091/**
2092 * xmlTextReaderIsDefault:
2093 * @reader: the xmlTextReaderPtr used
2094 *
2095 * Whether an Attribute node was generated from the default value
2096 * defined in the DTD or schema.
2097 *
2098 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
2099 */
2100int
2101xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
2102 if (reader == NULL)
2103 return(-1);
2104 return(0);
2105}
2106
2107/**
2108 * xmlTextReaderQuoteChar:
2109 * @reader: the xmlTextReaderPtr used
2110 *
2111 * The quotation mark character used to enclose the value of an attribute.
2112 *
2113 * Returns " or ' and -1 in case of error
2114 */
2115int
2116xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
2117 if (reader == NULL)
2118 return(-1);
2119 /* TODO maybe lookup the attribute value for " first */
2120 return((int) '"');
2121}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002122
2123/**
2124 * xmlTextReaderXmlLang:
2125 * @reader: the xmlTextReaderPtr used
2126 *
2127 * The xml:lang scope within which the node resides.
2128 *
2129 * Returns the xml:lang value or NULL if none exists.
2130 */
2131xmlChar *
2132xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
2133 if (reader == NULL)
2134 return(NULL);
2135 if (reader->node == NULL)
2136 return(NULL);
2137 return(xmlNodeGetLang(reader->node));
2138}
2139
Daniel Veillard67df8092002-12-16 22:04:11 +00002140/**
2141 * xmlTextReaderNormalization:
2142 * @reader: the xmlTextReaderPtr used
2143 *
2144 * The value indicating whether to normalize white space and attribute values.
2145 * Since attribute value and end of line normalizations are a MUST in the XML
2146 * specification only the value true is accepted. The broken bahaviour of
2147 * accepting out of range character entities like &#0; is of course not
2148 * supported either.
2149 *
2150 * Returns 1 or -1 in case of error.
2151 */
2152int
2153xmlTextReaderNormalization(xmlTextReaderPtr reader) {
2154 if (reader == NULL)
2155 return(-1);
2156 return(1);
2157}
2158
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002159/************************************************************************
2160 * *
2161 * Extensions to the base APIs *
2162 * *
2163 ************************************************************************/
2164
2165/**
2166 * xmlTextReaderSetParserProp:
2167 * @reader: the xmlTextReaderPtr used
2168 * @prop: the xmlParserProperties to set
2169 * @value: usually 0 or 1 to (de)activate it
2170 *
2171 * Change the parser processing behaviour by changing some of its internal
2172 * properties. Note that some properties can only be changed before any
2173 * read has been done.
2174 *
2175 * Returns 0 if the call was successful, or -1 in case of error
2176 */
2177int
2178xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
2179 xmlParserProperties p = (xmlParserProperties) prop;
2180 xmlParserCtxtPtr ctxt;
2181
2182 if ((reader == NULL) || (reader->ctxt == NULL))
2183 return(-1);
2184 ctxt = reader->ctxt;
2185
2186 switch (p) {
2187 case XML_PARSER_LOADDTD:
2188 if (value != 0) {
2189 if (ctxt->loadsubset == 0) {
2190 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2191 return(-1);
2192 ctxt->loadsubset = XML_DETECT_IDS;
2193 }
2194 } else {
2195 ctxt->loadsubset = 0;
2196 }
2197 return(0);
2198 case XML_PARSER_DEFAULTATTRS:
2199 if (value != 0) {
2200 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
2201 } else {
2202 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2203 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
2204 }
2205 return(0);
2206 case XML_PARSER_VALIDATE:
2207 if (value != 0) {
2208 ctxt->validate = 1;
2209 } else {
2210 ctxt->validate = 0;
2211 }
2212 return(0);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002213 case XML_PARSER_SUBST_ENTITIES:
2214 if (value != 0) {
2215 ctxt->replaceEntities = 1;
2216 } else {
2217 ctxt->replaceEntities = 0;
2218 }
2219 return(0);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002220 }
2221 return(-1);
2222}
2223
2224/**
2225 * xmlTextReaderGetParserProp:
2226 * @reader: the xmlTextReaderPtr used
2227 * @prop: the xmlParserProperties to get
2228 *
2229 * Read the parser internal property.
2230 *
2231 * Returns the value, usually 0 or 1, or -1 in case of error.
2232 */
2233int
2234xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
2235 xmlParserProperties p = (xmlParserProperties) prop;
2236 xmlParserCtxtPtr ctxt;
2237
2238 if ((reader == NULL) || (reader->ctxt == NULL))
2239 return(-1);
2240 ctxt = reader->ctxt;
2241
2242 switch (p) {
2243 case XML_PARSER_LOADDTD:
2244 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
2245 return(1);
2246 return(0);
2247 case XML_PARSER_DEFAULTATTRS:
2248 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2249 return(1);
2250 return(0);
2251 case XML_PARSER_VALIDATE:
2252 return(ctxt->validate);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002253 case XML_PARSER_SUBST_ENTITIES:
2254 return(ctxt->replaceEntities);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002255 }
2256 return(-1);
2257}
2258
Daniel Veillarde18fc182002-12-28 22:56:33 +00002259/**
2260 * xmlTextReaderCurrentNode:
2261 * @reader: the xmlTextReaderPtr used
2262 *
2263 * Hacking interface allowing to get the xmlNodePtr correponding to the
2264 * current node being accessed by the xmlTextReader. This is dangerous
2265 * because the underlying node may be destroyed on the next Reads.
2266 *
2267 * Returns the xmlNodePtr or NULL in case of error.
2268 */
2269xmlNodePtr
2270xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
2271 if (reader == NULL)
2272 return(NULL);
2273
2274 if (reader->curnode != NULL)
2275 return(reader->curnode);
2276 return(reader->node);
2277}
2278
2279/**
2280 * xmlTextReaderCurrentDoc:
2281 * @reader: the xmlTextReaderPtr used
2282 *
2283 * Hacking interface allowing to get the xmlDocPtr correponding to the
2284 * current document being accessed by the xmlTextReader. This is dangerous
2285 * because the associated node may be destroyed on the next Reads.
2286 *
2287 * Returns the xmlDocPtr or NULL in case of error.
2288 */
2289xmlDocPtr
2290xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
2291 if ((reader == NULL) || (reader->ctxt == NULL))
2292 return(NULL);
2293
2294 return(reader->ctxt->myDoc);
2295}
2296
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002297/************************************************************************
2298 * *
Daniel Veillard26f70262003-01-16 22:45:08 +00002299 * Error Handling Extensions *
2300 * *
2301 ************************************************************************/
2302
2303/* helper to build a xmlMalloc'ed string from a format and va_list */
2304static char *
2305xmlTextReaderBuildMessage(const char *msg, va_list ap) {
2306 int size;
2307 int chars;
2308 char *larger;
2309 char *str;
2310
2311 str = (char *) xmlMalloc(150);
2312 if (str == NULL) {
2313 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
2314 return NULL;
2315 }
2316
2317 size = 150;
2318
2319 while (1) {
2320 chars = vsnprintf(str, size, msg, ap);
2321 if ((chars > -1) && (chars < size))
2322 break;
2323 if (chars > -1)
2324 size += chars + 1;
2325 else
2326 size += 100;
2327 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
2328 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
2329 xmlFree(str);
2330 return NULL;
2331 }
2332 str = larger;
2333 }
2334
2335 return str;
2336}
2337
Daniel Veillard417be3a2003-01-20 21:26:34 +00002338/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00002339 * xmlTextReaderLocatorLineNumber:
Daniel Veillard417be3a2003-01-20 21:26:34 +00002340 * @locator: the xmlTextReaderLocatorPtr used
2341 *
2342 * Obtain the line number for the given locator.
2343 *
2344 * Returns the line number or -1 in case of error.
2345 */
2346int
2347xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
2348 /* we know that locator is a xmlParserCtxtPtr */
2349 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
2350 int ret = -1;
2351
2352 if (ctx->node != NULL) {
2353 ret = xmlGetLineNo(ctx->node);
2354 }
2355 else {
2356 /* inspired from error.c */
2357 xmlParserInputPtr input;
2358 input = ctx->input;
2359 if ((input->filename == NULL) && (ctx->inputNr > 1))
2360 input = ctx->inputTab[ctx->inputNr - 2];
2361 if (input != NULL) {
2362 ret = input->line;
2363 }
2364 else {
2365 ret = -1;
2366 }
2367 }
2368
2369 return ret;
2370}
2371
2372/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00002373 * xmlTextReaderLocatorBaseURI:
Daniel Veillard417be3a2003-01-20 21:26:34 +00002374 * @locator: the xmlTextReaderLocatorPtr used
2375 *
2376 * Obtain the base URI for the given locator.
2377 *
2378 * Returns the base URI or NULL in case of error.
2379 */
2380xmlChar *
2381xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
2382 /* we know that locator is a xmlParserCtxtPtr */
2383 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
2384 xmlChar *ret = NULL;
2385
2386 if (ctx->node != NULL) {
2387 ret = xmlNodeGetBase(NULL,ctx->node);
2388 }
2389 else {
2390 /* inspired from error.c */
2391 xmlParserInputPtr input;
2392 input = ctx->input;
2393 if ((input->filename == NULL) && (ctx->inputNr > 1))
2394 input = ctx->inputTab[ctx->inputNr - 2];
2395 if (input != NULL) {
Daniel Veillard580ced82003-03-21 21:22:48 +00002396 ret = xmlStrdup(BAD_CAST input->filename);
Daniel Veillard417be3a2003-01-20 21:26:34 +00002397 }
2398 else {
2399 ret = NULL;
2400 }
2401 }
2402
2403 return ret;
2404}
2405
Daniel Veillard26f70262003-01-16 22:45:08 +00002406static void
2407xmlTextReaderGenericError(void *ctxt, int severity, char *str) {
2408 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
2409 xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private;
2410
2411 if (str != NULL) {
2412 reader->errorFunc(reader->errorFuncArg,
2413 str,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002414 severity,
2415 (xmlTextReaderLocatorPtr)ctx);
Daniel Veillard26f70262003-01-16 22:45:08 +00002416 xmlFree(str);
2417 }
2418}
2419
2420static void
2421xmlTextReaderError(void *ctxt, const char *msg, ...) {
2422 va_list ap;
2423
2424 va_start(ap,msg);
2425 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002426 XML_PARSER_SEVERITY_ERROR,
Daniel Veillard26f70262003-01-16 22:45:08 +00002427 xmlTextReaderBuildMessage(msg,ap));
2428 va_end(ap);
2429
2430}
2431
2432static void
2433xmlTextReaderWarning(void *ctxt, const char *msg, ...) {
2434 va_list ap;
2435
2436 va_start(ap,msg);
2437 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002438 XML_PARSER_SEVERITY_WARNING,
Daniel Veillard26f70262003-01-16 22:45:08 +00002439 xmlTextReaderBuildMessage(msg,ap));
2440 va_end(ap);
2441}
2442
2443static void
2444xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
2445 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00002446 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00002447
Daniel Veillard417be3a2003-01-20 21:26:34 +00002448 if ((len > 1) && (msg[len - 2] != ':')) {
2449 /*
2450 * some callbacks only report locator information:
2451 * skip them (mimicking behaviour in error.c)
2452 */
2453 va_start(ap,msg);
2454 xmlTextReaderGenericError(ctxt,
2455 XML_PARSER_SEVERITY_VALIDITY_ERROR,
2456 xmlTextReaderBuildMessage(msg,ap));
2457 va_end(ap);
2458 }
Daniel Veillard26f70262003-01-16 22:45:08 +00002459}
2460
2461static void
2462xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
2463 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00002464 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00002465
Daniel Veillard417be3a2003-01-20 21:26:34 +00002466 if ((len != 0) && (msg[len - 1] != ':')) {
2467 /*
2468 * some callbacks only report locator information:
2469 * skip them (mimicking behaviour in error.c)
2470 */
2471 va_start(ap,msg);
2472 xmlTextReaderGenericError(ctxt,
2473 XML_PARSER_SEVERITY_VALIDITY_WARNING,
2474 xmlTextReaderBuildMessage(msg,ap));
2475 va_end(ap);
2476 }
Daniel Veillard26f70262003-01-16 22:45:08 +00002477}
2478
2479/**
2480 * xmlTextReaderSetErrorHandler:
2481 * @reader: the xmlTextReaderPtr used
2482 * @f: the callback function to call on error and warnings
2483 * @arg: a user argument to pass to the callback function
2484 *
Daniel Veillard417be3a2003-01-20 21:26:34 +00002485 * Register a callback function that will be called on error and warnings.
2486 *
Daniel Veillard26f70262003-01-16 22:45:08 +00002487 * If @f is NULL, the default error and warning handlers are restored.
2488 */
2489void
2490xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
2491 xmlTextReaderErrorFunc f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002492 void *arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00002493 if (f != NULL) {
2494 reader->ctxt->sax->error = xmlTextReaderError;
2495 reader->ctxt->vctxt.error = xmlTextReaderValidityError;
2496 reader->ctxt->sax->warning = xmlTextReaderWarning;
2497 reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
2498 reader->errorFunc = f;
2499 reader->errorFuncArg = arg;
2500 }
2501 else {
2502 /* restore defaults */
2503 reader->ctxt->sax->error = xmlParserError;
2504 reader->ctxt->vctxt.error = xmlParserValidityError;
2505 reader->ctxt->sax->warning = xmlParserWarning;
2506 reader->ctxt->vctxt.warning = xmlParserValidityWarning;
2507 reader->errorFunc = NULL;
2508 reader->errorFuncArg = NULL;
2509 }
2510}
2511
Daniel Veillard417be3a2003-01-20 21:26:34 +00002512/**
2513 * xmlTextReaderGetErrorHandler:
2514 * @reader: the xmlTextReaderPtr used
2515 * @f: the callback function or NULL is no callback has been registered
2516 * @arg: a user argument
2517 *
2518 * Retrieve the error callback function and user argument.
2519 */
Daniel Veillard26f70262003-01-16 22:45:08 +00002520void
2521xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
2522 xmlTextReaderErrorFunc *f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00002523 void **arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00002524 *f = reader->errorFunc;
2525 *arg = reader->errorFuncArg;
2526}
2527
2528/************************************************************************
2529 * *
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002530 * Utilities *
2531 * *
2532 ************************************************************************/
2533/**
2534 * xmlBase64Decode:
2535 * @in: the input buffer
2536 * @inlen: the size of the input (in), the size read from it (out)
2537 * @to: the output buffer
2538 * @tolen: the size of the output (in), the size written to (out)
2539 *
2540 * Base64 decoder, reads from @in and save in @to
Daniel Veillardd4310742003-02-18 21:12:46 +00002541 * TODO: tell jody when this is actually exported
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002542 *
2543 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
2544 * 2 if there wasn't enough space on the output or -1 in case of error.
2545 */
2546static int
2547xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
2548 unsigned char *to, unsigned long *tolen) {
2549 unsigned long incur; /* current index in in[] */
2550 unsigned long inblk; /* last block index in in[] */
2551 unsigned long outcur; /* current index in out[] */
2552 unsigned long inmax; /* size of in[] */
2553 unsigned long outmax; /* size of out[] */
2554 unsigned char cur; /* the current value read from in[] */
2555 unsigned char intmp[3], outtmp[4]; /* temporary buffers for the convert */
2556 int nbintmp; /* number of byte in intmp[] */
2557 int is_ignore; /* cur should be ignored */
2558 int is_end = 0; /* the end of the base64 was found */
2559 int retval = 1;
2560 int i;
2561
2562 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
2563 return(-1);
2564
2565 incur = 0;
2566 inblk = 0;
2567 outcur = 0;
2568 inmax = *inlen;
2569 outmax = *tolen;
2570 nbintmp = 0;
2571
2572 while (1) {
2573 if (incur >= inmax)
2574 break;
2575 cur = in[incur++];
2576 is_ignore = 0;
2577 if ((cur >= 'A') && (cur <= 'Z'))
2578 cur = cur - 'A';
2579 else if ((cur >= 'a') && (cur <= 'z'))
2580 cur = cur - 'a' + 26;
2581 else if ((cur >= '0') && (cur <= '9'))
2582 cur = cur - '0' + 52;
2583 else if (cur == '+')
2584 cur = 62;
2585 else if (cur == '/')
2586 cur = 63;
2587 else if (cur == '.')
2588 cur = 0;
2589 else if (cur == '=') /*no op , end of the base64 stream */
2590 is_end = 1;
2591 else {
2592 is_ignore = 1;
2593 if (nbintmp == 0)
2594 inblk = incur;
2595 }
2596
2597 if (!is_ignore) {
2598 int nbouttmp = 3;
2599 int is_break = 0;
2600
2601 if (is_end) {
2602 if (nbintmp == 0)
2603 break;
2604 if ((nbintmp == 1) || (nbintmp == 2))
2605 nbouttmp = 1;
2606 else
2607 nbouttmp = 2;
2608 nbintmp = 3;
2609 is_break = 1;
2610 }
2611 intmp[nbintmp++] = cur;
2612 /*
2613 * if intmp is full, push the 4byte sequence as a 3 byte
2614 * sequence out
2615 */
2616 if (nbintmp == 4) {
2617 nbintmp = 0;
2618 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
2619 outtmp[1] =
2620 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
2621 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
2622 if (outcur + 3 >= outmax) {
2623 retval = 2;
2624 break;
2625 }
2626
2627 for (i = 0; i < nbouttmp; i++)
2628 to[outcur++] = outtmp[i];
2629 inblk = incur;
2630 }
2631
2632 if (is_break) {
2633 retval = 0;
2634 break;
2635 }
2636 }
2637 }
2638
2639 *tolen = outcur;
2640 *inlen = inblk;
2641 return (retval);
2642}
2643
2644/*
2645 * Test routine for the xmlBase64Decode function
2646 */
2647#if 0
2648int main(int argc, char **argv) {
2649 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
2650 char output[100];
2651 char output2[100];
2652 char output3[100];
2653 unsigned long inlen = strlen(input);
2654 unsigned long outlen = 100;
2655 int ret;
2656 unsigned long cons, tmp, tmp2, prod;
2657
2658 /*
2659 * Direct
2660 */
2661 ret = xmlBase64Decode(input, &inlen, output, &outlen);
2662
2663 output[outlen] = 0;
2664 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
2665
2666 /*
2667 * output chunking
2668 */
2669 cons = 0;
2670 prod = 0;
2671 while (cons < inlen) {
2672 tmp = 5;
2673 tmp2 = inlen - cons;
2674
2675 printf("%ld %ld\n", cons, prod);
2676 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
2677 cons += tmp2;
2678 prod += tmp;
2679 printf("%ld %ld\n", cons, prod);
2680 }
2681 output2[outlen] = 0;
2682 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
2683
2684 /*
2685 * input chunking
2686 */
2687 cons = 0;
2688 prod = 0;
2689 while (cons < inlen) {
2690 tmp = 100 - prod;
2691 tmp2 = inlen - cons;
2692 if (tmp2 > 5)
2693 tmp2 = 5;
2694
2695 printf("%ld %ld\n", cons, prod);
2696 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
2697 cons += tmp2;
2698 prod += tmp;
2699 printf("%ld %ld\n", cons, prod);
2700 }
2701 output3[outlen] = 0;
2702 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
2703 return(0);
2704
2705}
2706#endif