blob: 5bf93553051f0006bacdf417c24bba66adabe59a [file] [log] [blame]
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001/*
2 * xmlreader.c: implements the xmlTextReader streaming node API
3 *
Daniel Veillard67df8092002-12-16 22:04:11 +00004 * NOTE:
5 * XmlTextReader.Normalization Property won't be supported, since
6 * it makes the parser non compliant to the XML recommendation
7 *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00008 * See Copyright for the status of this software.
9 *
10 * daniel@veillard.com
11 */
12
13#define IN_LIBXML
14#include "libxml.h"
15
16#include <string.h> /* for memset() only ! */
17
18#ifdef HAVE_CTYPE_H
19#include <ctype.h>
20#endif
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
24
25#include <libxml/xmlmemory.h>
26#include <libxml/xmlIO.h>
27#include <libxml/xmlreader.h>
28
29/* #define DEBUG_CALLBACKS */
30/* #define DEBUG_READER */
31
32/**
33 * TODO:
34 *
35 * macro to flag unimplemented blocks
36 */
37#define TODO \
38 xmlGenericError(xmlGenericErrorContext, \
39 "Unimplemented block at %s:%d\n", \
40 __FILE__, __LINE__);
41
42#ifdef DEBUG_READER
43#define DUMP_READER xmlTextReaderDebug(reader);
44#else
45#define DUMP_READER
46#endif
47
48/************************************************************************
49 * *
50 * The parser: maps the Text Reader API on top of the existing *
51 * parsing routines building a tree *
52 * *
53 ************************************************************************/
54
55#define XML_TEXTREADER_INPUT 1
56#define XML_TEXTREADER_CTXT 2
57
58typedef enum {
Daniel Veillard67df8092002-12-16 22:04:11 +000059 XML_TEXTREADER_MODE_INITIAL = 0,
60 XML_TEXTREADER_MODE_INTERACTIVE = 1,
61 XML_TEXTREADER_MODE_ERROR = 2,
62 XML_TEXTREADER_MODE_EOF =3,
63 XML_TEXTREADER_MODE_CLOSED = 4,
64 XML_TEXTREADER_MODE_READING = 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000065} xmlTextReaderMode;
66
67typedef enum {
68 XML_TEXTREADER_NONE = -1,
69 XML_TEXTREADER_START= 0,
70 XML_TEXTREADER_ELEMENT= 1,
71 XML_TEXTREADER_END= 2,
72 XML_TEXTREADER_EMPTY= 3,
Daniel Veillardea7751d2002-12-20 00:16:24 +000073 XML_TEXTREADER_BACKTRACK= 4,
74 XML_TEXTREADER_DONE= 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000075} xmlTextReaderState;
76
77struct _xmlTextReader {
78 int mode; /* the parsing mode */
79 int allocs; /* what structure were deallocated */
80 xmlTextReaderState state;
81 xmlParserCtxtPtr ctxt; /* the parser context */
82 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
83 xmlParserInputBufferPtr input; /* the input */
84 startElementSAXFunc startElement;/* initial SAX callbacks */
85 endElementSAXFunc endElement; /* idem */
Daniel Veillardea7751d2002-12-20 00:16:24 +000086 charactersSAXFunc characters;
87 cdataBlockSAXFunc cdataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +000088 unsigned int base; /* base of the segment in the input */
89 unsigned int cur; /* current position in the input */
90 xmlNodePtr node; /* current node */
Daniel Veillardda46d2d2002-12-15 23:36:49 +000091 xmlNodePtr curnode;/* current attribute node */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000092 int depth; /* depth of the current node */
Daniel Veillardbeb70bd2002-12-18 14:53:54 +000093 xmlNodePtr faketext;/* fake xmlNs chld */
Daniel Veillarddf512f42002-12-23 15:56:21 +000094 int wasempty;/* was the last node empty */
Daniel Veillard1fdfd112003-01-03 01:18:43 +000095
96 /* entity stack when traversing entities content */
97 xmlNodePtr ent; /* Current Entity Ref Node */
98 int entNr; /* Depth of the entities stack */
99 int entMax; /* Max depth of the entities stack */
100 xmlNodePtr *entTab; /* array of entities */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000101};
102
103#ifdef DEBUG_READER
104static void
105xmlTextReaderDebug(xmlTextReaderPtr reader) {
106 if ((reader == NULL) || (reader->ctxt == NULL)) {
107 fprintf(stderr, "xmlTextReader NULL\n");
108 return;
109 }
110 fprintf(stderr, "xmlTextReader: state %d depth %d ",
111 reader->state, reader->depth);
112 if (reader->node == NULL) {
113 fprintf(stderr, "node = NULL\n");
114 } else {
115 fprintf(stderr, "node %s\n", reader->node->name);
116 }
117 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
118 reader->base, reader->cur, reader->ctxt->nodeNr);
119 if (reader->input->buffer == NULL) {
120 fprintf(stderr, "buffer is NULL\n");
121 } else {
122#ifdef LIBXML_DEBUG_ENABLED
123 xmlDebugDumpString(stderr,
124 &reader->input->buffer->content[reader->cur]);
125#endif
126 fprintf(stderr, "\n");
127 }
128}
129#endif
130
131/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000132 * xmlTextReaderEntPush:
133 * @reader: the xmlTextReaderPtr used
134 * @value: the entity reference node
135 *
136 * Pushes a new entity reference node on top of the entities stack
137 *
138 * Returns 0 in case of error, the index in the stack otherwise
139 */
140static int
141xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
142{
143 if (reader->entMax <= 0) {
144 reader->entMax = 10;
145 reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
146 sizeof(reader->entTab[0]));
147 if (reader->entTab == NULL) {
148 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
149 return (0);
150 }
151 }
152 if (reader->entNr >= reader->entMax) {
153 reader->entMax *= 2;
154 reader->entTab =
155 (xmlNodePtr *) xmlRealloc(reader->entTab,
156 reader->entMax *
157 sizeof(reader->entTab[0]));
158 if (reader->entTab == NULL) {
159 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
160 return (0);
161 }
162 }
163 reader->entTab[reader->entNr] = value;
164 reader->ent = value;
165 return (reader->entNr++);
166}
167
168/**
169 * xmlTextReaderEntPop:
170 * @reader: the xmlTextReaderPtr used
171 *
172 * Pops the top element entity from the entities stack
173 *
174 * Returns the entity just removed
175 */
176static xmlNodePtr
177xmlTextReaderEntPop(xmlTextReaderPtr reader)
178{
179 xmlNodePtr ret;
180
181 if (reader->entNr <= 0)
182 return (0);
183 reader->entNr--;
184 if (reader->entNr > 0)
185 reader->ent = reader->entTab[reader->entNr - 1];
186 else
187 reader->ent = NULL;
188 ret = reader->entTab[reader->entNr];
189 reader->entTab[reader->entNr] = 0;
190 return (ret);
191}
192
193/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000194 * xmlTextReaderStartElement:
195 * @ctx: the user data (XML parser context)
196 * @fullname: The element name, including namespace prefix
197 * @atts: An array of name/value attributes pairs, NULL terminated
198 *
199 * called when an opening tag has been processed.
200 */
201static void
202xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
203 const xmlChar **atts) {
204 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000205 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000206 xmlTextReaderPtr reader = ctxt->_private;
207
208#ifdef DEBUG_CALLBACKS
209 printf("xmlTextReaderStartElement(%s)\n", fullname);
210#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000211 if ((reader != NULL) && (reader->startElement != NULL)) {
Daniel Veillardd5896142002-12-31 14:45:26 +0000212 /*
213 * when processing an entity, the context may have been changed
214 */
215 origctxt = reader->ctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000216 reader->startElement(ctx, fullname, atts);
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000217#if 0
218 123
Daniel Veillardd5896142002-12-31 14:45:26 +0000219 if (origctxt->validate) {
220 ctxt->valid &= xmlValidatePushElement(&origctxt->vctxt,
221 ctxt->myDoc, ctxt->node, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000222 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000223#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000224 }
Daniel Veillard9e395c22003-01-01 14:50:44 +0000225 if (reader != NULL)
226 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000227}
228
229/**
230 * xmlTextReaderEndElement:
231 * @ctx: the user data (XML parser context)
232 * @fullname: The element name, including namespace prefix
233 *
234 * called when an ending tag has been processed.
235 */
236static void
237xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
238 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000239 xmlParserCtxtPtr origctxt;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000240 xmlTextReaderPtr reader = ctxt->_private;
241
242#ifdef DEBUG_CALLBACKS
243 printf("xmlTextReaderEndElement(%s)\n", fullname);
244#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000245 if ((reader != NULL) && (reader->endElement != NULL)) {
Daniel Veillardd5896142002-12-31 14:45:26 +0000246 /*
247 * when processing an entity, the context may have been changed
248 */
249 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000250
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000251 reader->endElement(ctx, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000252 }
Daniel Veillard9e395c22003-01-01 14:50:44 +0000253 if (reader != NULL) {
254 if (reader->state == XML_TEXTREADER_ELEMENT)
255 reader->wasempty = 1;
256 else
257 reader->wasempty = 0;
258 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000259}
260
261/**
Daniel Veillardea7751d2002-12-20 00:16:24 +0000262 * xmlTextReaderCharacters:
263 * @ctx: the user data (XML parser context)
264 * @ch: a xmlChar string
265 * @len: the number of xmlChar
266 *
267 * receiving some chars from the parser.
268 */
269static void
270xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
271{
272 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillardd5896142002-12-31 14:45:26 +0000273 xmlParserCtxtPtr origctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000274 xmlTextReaderPtr reader = ctxt->_private;
275
276#ifdef DEBUG_CALLBACKS
277 printf("xmlTextReaderCharacters()\n");
278#endif
279 if ((reader != NULL) && (reader->characters != NULL)) {
280 reader->characters(ctx, ch, len);
Daniel Veillardd5896142002-12-31 14:45:26 +0000281 /*
282 * when processing an entity, the context may have been changed
283 */
284 origctxt = reader->ctxt;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000285
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000286#if 0
287 123
Daniel Veillardd5896142002-12-31 14:45:26 +0000288 if (origctxt->validate) {
289 ctxt->valid &= xmlValidatePushCData(&origctxt->vctxt, ch, len);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000290 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000291#endif
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);
314
315 if (ctxt->validate) {
316 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt, ch, len);
317 }
318 }
319}
320
321/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000322 * xmlTextReaderPushData:
323 * @reader: the xmlTextReaderPtr used
324 *
325 * Push data down the progressive parser until a significant callback
326 * got raised.
327 *
328 * Returns -1 in case of failure, 0 otherwise
329 */
330static int
331xmlTextReaderPushData(xmlTextReaderPtr reader) {
332 unsigned int cur = reader->cur;
333 xmlBufferPtr inbuf;
334 int val;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000335 int oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000336
337 if ((reader->input == NULL) || (reader->input->buffer == NULL))
338 return(-1);
339
Daniel Veillardea7751d2002-12-20 00:16:24 +0000340 oldstate = reader->state;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000341 reader->state = XML_TEXTREADER_NONE;
342 inbuf = reader->input->buffer;
343 while (reader->state == XML_TEXTREADER_NONE) {
344 if (cur >= inbuf->use) {
345 /*
346 * Refill the buffer unless we are at the end of the stream
347 */
348 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
349 val = xmlParserInputBufferRead(reader->input, 4096);
350 if (val <= 0) {
351 reader->mode = XML_TEXTREADER_MODE_EOF;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000352 reader->state = oldstate;
Daniel Veillardaaa105b2002-12-30 11:42:17 +0000353 if ((oldstate != XML_TEXTREADER_START) ||
354 (reader->ctxt->myDoc != NULL))
355 return(val);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000356 }
357 } else
358 break;
359 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000360 if ((inbuf->content[cur] == '>') || (inbuf->content[cur] == '&') ||
361 (inbuf->content[cur] == ';')) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000362 cur = cur + 1;
363 val = xmlParseChunk(reader->ctxt,
364 (const char *) &inbuf->content[reader->cur],
365 cur - reader->cur, 0);
366 if (val != 0)
367 return(-1);
368 reader->cur = cur;
369 break;
370 } else {
371 cur = cur + 1;
372
373 /*
374 * One may have to force a flush at some point when parsing really
375 * large CDATA sections
376 */
377 if ((cur - reader->cur > 4096) && (reader->base == 0) &&
Daniel Veillard67df8092002-12-16 22:04:11 +0000378 (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000379 cur = cur + 1;
380 val = xmlParseChunk(reader->ctxt,
381 (const char *) &inbuf->content[reader->cur],
382 cur - reader->cur, 0);
383 if (val != 0)
384 return(-1);
385 reader->cur = cur;
386 }
387 }
388 }
389 /*
390 * Discard the consumed input when needed and possible
391 */
Daniel Veillard67df8092002-12-16 22:04:11 +0000392 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000393 if ((reader->cur >= 4096) && (reader->base == 0)) {
394 val = xmlBufferShrink(inbuf, cur);
395 if (val >= 0) {
396 reader->cur -= val;
397 }
398 }
399 }
400
401 /*
402 * At the end of the stream signal that the work is done to the Push
403 * parser.
404 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000405 if (reader->mode == XML_TEXTREADER_MODE_EOF) {
406 if (reader->mode != XML_TEXTREADER_DONE) {
407 val = xmlParseChunk(reader->ctxt,
408 (const char *) &inbuf->content[reader->cur], 0, 1);
409 reader->mode = XML_TEXTREADER_DONE;
410 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000411 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000412 reader->state = oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000413 return(0);
414}
415
416/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000417 * xmlTextReaderValidatePush:
418 * @reader: the xmlTextReaderPtr used
419 *
420 * Push the current node for validation
421 */
422static void
423xmlTextReaderValidatePush(xmlTextReaderPtr reader) {
424 xmlNodePtr node = reader->node;
425
426 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
427 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
428 reader->ctxt->myDoc, node, node->name);
429 } else {
430 xmlChar *qname;
431
432 qname = xmlStrdup(node->ns->prefix);
433 qname = xmlStrcat(qname, BAD_CAST ":");
434 qname = xmlStrcat(qname, node->name);
435 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
436 reader->ctxt->myDoc, node, qname);
437 if (qname != NULL)
438 xmlFree(qname);
439 }
440}
441/**
442 * xmlTextReaderValidatePop:
443 * @reader: the xmlTextReaderPtr used
444 *
445 * Pop the current node from validation
446 */
447static void
448xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
449 xmlNodePtr node = reader->node;
450
451 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
452 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
453 reader->ctxt->myDoc, node, node->name);
454 } else {
455 xmlChar *qname;
456
457 qname = xmlStrdup(node->ns->prefix);
458 qname = xmlStrcat(qname, BAD_CAST ":");
459 qname = xmlStrcat(qname, node->name);
460 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
461 reader->ctxt->myDoc, node, qname);
462 if (qname != NULL)
463 xmlFree(qname);
464 }
465}
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000466/**
467 * xmlTextReaderValidateEntity:
468 * @reader: the xmlTextReaderPtr used
469 *
470 * Handle the validation when an entity reference is encountered and
471 * entity substitution is not activated. As a result the parser interface
472 * must walk through the entity and do the validation calls
473 */
474static void
475xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
476 xmlNodePtr oldnode = reader->node;
477 xmlNodePtr node = reader->node;
478 xmlParserCtxtPtr ctxt = reader->ctxt;
479
480 do {
481 if (node->type == XML_ENTITY_REF_NODE) {
482 /*
483 * Case where the underlying tree is not availble, lookup the entity
484 * and walk it.
485 */
486 if ((node->children == NULL) && (ctxt->sax != NULL) &&
487 (ctxt->sax->getEntity != NULL)) {
488 node->children = (xmlNodePtr)
489 ctxt->sax->getEntity(ctxt, node->name);
490 }
491
492 if ((node->children != NULL) &&
493 (node->children->type == XML_ENTITY_DECL) &&
494 (node->children->children != NULL)) {
495 xmlTextReaderEntPush(reader, node);
496 node = node->children->children;
497 continue;
498 } else {
499 /*
500 * The error has probably be raised already.
501 */
502 if (node == oldnode)
503 break;
504 node = node->next;
505 }
506 } else if (node->type == XML_ELEMENT_NODE) {
507 reader->node = node;
508 xmlTextReaderValidatePush(reader);
509 } else if ((node->type == XML_TEXT_NODE) ||
510 (node->type == XML_CDATA_SECTION_NODE)) {
511 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt,
512 node->content, xmlStrlen(node->content));
513 }
514
515 /*
516 * go to next node
517 */
518 if (node->children != NULL) {
519 node = node->children;
520 continue;
521 }
522 if (node->next != NULL) {
523 node = node->next;
524 continue;
525 }
526 do {
527 node = node->parent;
528 if (node->type == XML_ELEMENT_NODE) {
529 reader->node = node;
530 xmlTextReaderValidatePop(reader);
531 }
532 if ((node->type == XML_ENTITY_DECL) &&
533 (reader->ent != NULL) && (reader->ent->children == node)) {
534 node = xmlTextReaderEntPop(reader);
535 }
536 if (node == oldnode)
537 break;
538 if (node->next != NULL) {
539 node = node->next;
540 break;
541 }
542 } while ((node != NULL) && (node != oldnode));
543 } while ((node != NULL) && (node != oldnode));
544 reader->node = oldnode;
545}
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000546
547
548/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000549 * xmlTextReaderRead:
550 * @reader: the xmlTextReaderPtr used
551 *
552 * Moves the position of the current instance to the next node in
553 * the stream, exposing its properties.
554 *
555 * Returns 1 if the node was read successfully, 0 if there is no more
556 * nodes to read, or -1 in case of error
557 */
558int
559xmlTextReaderRead(xmlTextReaderPtr reader) {
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000560 int val, olddepth = 0, wasempty = 0;
561 xmlTextReaderState oldstate = 0;
562 xmlNodePtr oldnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000563
564 if ((reader == NULL) || (reader->ctxt == NULL))
565 return(-1);
566 if (reader->ctxt->wellFormed != 1)
567 return(-1);
568
569#ifdef DEBUG_READER
570 fprintf(stderr, "\nREAD ");
571 DUMP_READER
572#endif
Daniel Veillard29b3e282002-12-29 11:14:41 +0000573 reader->curnode = NULL;
Daniel Veillard67df8092002-12-16 22:04:11 +0000574 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
575 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000576 /*
577 * Initial state
578 */
579 do {
580 val = xmlTextReaderPushData(reader);
581 if (val < 0)
582 return(-1);
583 } while ((reader->ctxt->node == NULL) &&
584 (reader->mode != XML_TEXTREADER_MODE_EOF));
585 if (reader->ctxt->node == NULL) {
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000586 if (reader->ctxt->myDoc != NULL) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000587 reader->node = reader->ctxt->myDoc->children;
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000588 if ((reader->ctxt->input != NULL) &&
589 (reader->ctxt->input->cur != NULL) &&
590 (reader->ctxt->input->cur[-2] != '/'))
591 reader->wasempty = -1;
592 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000593 if (reader->node == NULL)
594 return(-1);
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000595 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000596 } else {
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000597 reader->node = reader->ctxt->nodeTab[0];
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000598 }
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000599 reader->depth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000600 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000601 }
602 oldstate = reader->state;
603 olddepth = reader->ctxt->nodeNr;
604 oldnode = reader->node;
Daniel Veillarddab8ea92003-01-02 14:16:45 +0000605 /*
606 * the <p></p> vs. <p/> distinction at the API level royally sucks,
607 * Microsoft priviledge ...
608 */
609 if (reader->wasempty == -1)
610 wasempty = 0;
611 else
612 wasempty = (((reader->wasempty == 1) && (reader->ctxt->node != NULL) &&
Daniel Veillarde3c036e2003-01-01 15:11:05 +0000613 (reader->ctxt->node->last == reader->node)) ||
614 (reader->node != reader->ctxt->node));
Daniel Veillarddf512f42002-12-23 15:56:21 +0000615
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000616get_next_node:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000617 /*
618 * If we are not backtracking on ancestors or examined nodes,
619 * that the parser didn't finished or that we arent at the end
620 * of stream, continue processing.
621 */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000622 while (((oldstate == XML_TEXTREADER_BACKTRACK) ||
623 (reader->node->children == NULL) ||
624 (reader->node->type == XML_ENTITY_REF_NODE) ||
625 (reader->node->type == XML_DTD_NODE)) &&
626 (reader->node->next == NULL) &&
627 (reader->ctxt->nodeNr == olddepth) &&
628 (reader->ctxt->instate != XML_PARSER_EOF)) {
629 val = xmlTextReaderPushData(reader);
630 if (val < 0)
631 return(-1);
632 if (reader->node == NULL)
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000633 goto node_end;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000634 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000635 if (oldstate != XML_TEXTREADER_BACKTRACK) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000636 if ((reader->node->children != NULL) &&
637 (reader->node->type != XML_ENTITY_REF_NODE) &&
638 (reader->node->type != XML_DTD_NODE)) {
639 reader->node = reader->node->children;
640 reader->depth++;
Daniel Veillarddf512f42002-12-23 15:56:21 +0000641 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000642 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000643 }
644 }
645 if (reader->node->next != NULL) {
646 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillarddf512f42002-12-23 15:56:21 +0000647 (reader->node->type == XML_ELEMENT_NODE) &&
648 (wasempty == 0)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000649 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000650 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000651 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000652 if ((reader->ctxt->validate) &&
653 (reader->node->type == XML_ELEMENT_NODE))
654 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000655 reader->node = reader->node->next;
656 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000657
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000658 /*
659 * Cleanup of the old node
660 */
661 if (oldnode->type != XML_DTD_NODE) {
662 xmlUnlinkNode(oldnode);
663 xmlFreeNode(oldnode);
664 }
665
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000666 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000667 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000668 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillard571b8892002-12-30 12:37:59 +0000669 (reader->node->type == XML_ELEMENT_NODE) &&
670 (wasempty == 0)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000671 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000672 goto node_found;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000673 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000674 if ((reader->ctxt->validate) && (reader->node->type == XML_ELEMENT_NODE))
675 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000676 reader->node = reader->node->parent;
677 if ((reader->node == NULL) ||
678 (reader->node->type == XML_DOCUMENT_NODE) ||
679#ifdef LIBXML_DOCB_ENABLED
680 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
681#endif
682 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000683 if (reader->mode != XML_TEXTREADER_DONE) {
684 val = xmlParseChunk(reader->ctxt, "", 0, 1);
685 reader->mode = XML_TEXTREADER_DONE;
686 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000687 reader->node = NULL;
Daniel Veillard4d8db8a2002-12-30 18:40:42 +0000688 reader->depth = -1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000689
690 /*
691 * Cleanup of the old node
692 */
693 if (oldnode->type != XML_DTD_NODE) {
694 xmlUnlinkNode(oldnode);
695 xmlFreeNode(oldnode);
696 }
697
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000698 goto node_end;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000699 }
700 reader->depth--;
701 reader->state = XML_TEXTREADER_BACKTRACK;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000702
703node_found:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000704 DUMP_READER
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000705
706 /*
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000707 * Handle entities enter and exit when in entity replacement mode
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000708 */
709 if ((reader->node != NULL) &&
710 (reader->node->type == XML_ENTITY_REF_NODE) &&
711 (reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
712 /*
713 * Case where the underlying tree is not availble, lookup the entity
714 * and walk it.
715 */
716 if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
717 (reader->ctxt->sax->getEntity != NULL)) {
718 reader->node->children = (xmlNodePtr)
719 reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
720 }
721
722 if ((reader->node->children != NULL) &&
723 (reader->node->children->type == XML_ENTITY_DECL) &&
724 (reader->node->children->children != NULL)) {
725 xmlTextReaderEntPush(reader, reader->node);
726 reader->node = reader->node->children->children;
727 }
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000728 } else if ((reader->node != NULL) &&
729 (reader->node->type == XML_ENTITY_REF_NODE) &&
730 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
731 xmlTextReaderValidateEntity(reader);
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000732 }
733 if ((reader->node != NULL) &&
734 (reader->node->type == XML_ENTITY_DECL) &&
735 (reader->ent != NULL) && (reader->ent->children == reader->node)) {
736 reader->node = xmlTextReaderEntPop(reader);
737 reader->depth++;
738 goto get_next_node;
739 }
740 if ((reader->ctxt->validate) && (reader->node != NULL)) {
741 xmlNodePtr node = reader->node;
742 xmlParserCtxtPtr ctxt = reader->ctxt;
743
744 if ((node->type == XML_ELEMENT_NODE) &&
745 ((reader->state != XML_TEXTREADER_END) &&
746 (reader->state != XML_TEXTREADER_BACKTRACK))) {
747 xmlTextReaderValidatePush(reader);
748 } else if ((node->type == XML_TEXT_NODE) ||
749 (node->type == XML_CDATA_SECTION_NODE)) {
750 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt,
751 node->content, xmlStrlen(node->content));
752 }
753 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000754 return(1);
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000755node_end:
756 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000757}
758
Daniel Veillard67df8092002-12-16 22:04:11 +0000759/**
760 * xmlTextReaderReadState:
761 * @reader: the xmlTextReaderPtr used
762 *
763 * Gets the read state of the reader.
764 *
765 * Returns the state value, or -1 in case of error
766 */
767int
768xmlTextReaderReadState(xmlTextReaderPtr reader) {
769 if (reader == NULL)
770 return(-1);
771 return(reader->mode);
772}
773
774/**
775 * xmlTextReaderReadInnerXml:
776 * @reader: the xmlTextReaderPtr used
777 *
778 * Reads the contents of the current node, including child nodes and markup.
779 *
780 * Returns a string containing the XML content, or NULL if the current node
781 * is neither an element nor attribute, or has no child nodes. The
782 * string must be deallocated by the caller.
783 */
784xmlChar *
785xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) {
786 TODO
787 return(NULL);
788}
789
790/**
791 * xmlTextReaderReadOuterXml:
792 * @reader: the xmlTextReaderPtr used
793 *
794 * Reads the contents of the current node, including child nodes and markup.
795 *
796 * Returns a string containing the XML content, or NULL if the current node
797 * is neither an element nor attribute, or has no child nodes. The
798 * string must be deallocated by the caller.
799 */
800xmlChar *
801xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) {
802 TODO
803 return(NULL);
804}
805
806/**
807 * xmlTextReaderReadString:
808 * @reader: the xmlTextReaderPtr used
809 *
810 * Reads the contents of an element or a text node as a string.
811 *
812 * Returns a string containing the contents of the Element or Text node,
813 * or NULL if the reader is positioned on any other type of node.
814 * The string must be deallocated by the caller.
815 */
816xmlChar *
817xmlTextReaderReadString(xmlTextReaderPtr reader) {
818 TODO
819 return(NULL);
820}
821
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000822/**
823 * xmlTextReaderReadBase64:
824 * @reader: the xmlTextReaderPtr used
825 * @array: a byte array to store the content.
826 * @offset: the zero-based index into array where the method should
827 * begin to write.
828 * @len: the number of bytes to write.
829 *
830 * Reads and decodes the Base64 encoded contents of an element and
831 * stores the result in a byte buffer.
832 *
833 * Returns the number of bytes written to array, or zero if the current
834 * instance is not positioned on an element or -1 in case of error.
835 */
836int
837xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array,
838 int offset, int len) {
839 if ((reader == NULL) || (reader->ctxt == NULL))
840 return(-1);
841 if (reader->ctxt->wellFormed != 1)
842 return(-1);
843
844 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
845 return(0);
846 TODO
847 return(0);
848}
849
850/**
851 * xmlTextReaderReadBinHex:
852 * @reader: the xmlTextReaderPtr used
853 * @array: a byte array to store the content.
854 * @offset: the zero-based index into array where the method should
855 * begin to write.
856 * @len: the number of bytes to write.
857 *
858 * Reads and decodes the BinHex encoded contents of an element and
859 * stores the result in a byte buffer.
860 *
861 * Returns the number of bytes written to array, or zero if the current
862 * instance is not positioned on an element or -1 in case of error.
863 */
864int
865xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array,
866 int offset, int len) {
867 if ((reader == NULL) || (reader->ctxt == NULL))
868 return(-1);
869 if (reader->ctxt->wellFormed != 1)
870 return(-1);
871
872 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
873 return(0);
874 TODO
875 return(0);
876}
877
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000878/************************************************************************
879 * *
880 * Constructor and destructors *
881 * *
882 ************************************************************************/
883/**
884 * xmlNewTextReader:
885 * @input: the xmlParserInputBufferPtr used to read data
Daniel Veillardea7751d2002-12-20 00:16:24 +0000886 * @URI: the URI information for the source if available
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000887 *
888 * Create an xmlTextReader structure fed with @input
889 *
890 * Returns the new xmlTextReaderPtr or NULL in case of error
891 */
892xmlTextReaderPtr
Daniel Veillardea7751d2002-12-20 00:16:24 +0000893xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000894 xmlTextReaderPtr ret;
895 int val;
896
897 if (input == NULL)
898 return(NULL);
899 ret = xmlMalloc(sizeof(xmlTextReader));
900 if (ret == NULL) {
901 xmlGenericError(xmlGenericErrorContext,
902 "xmlNewTextReader : malloc failed\n");
903 return(NULL);
904 }
905 memset(ret, 0, sizeof(xmlTextReader));
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000906 ret->entTab = NULL;
907 ret->entMax = 0;
908 ret->entNr = 0;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000909 ret->input = input;
910 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
911 if (ret->sax == NULL) {
912 xmlFree(ret);
913 xmlGenericError(xmlGenericErrorContext,
914 "xmlNewTextReader : malloc failed\n");
915 return(NULL);
916 }
917 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
918 ret->startElement = ret->sax->startElement;
919 ret->sax->startElement = xmlTextReaderStartElement;
920 ret->endElement = ret->sax->endElement;
921 ret->sax->endElement = xmlTextReaderEndElement;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000922 ret->characters = ret->sax->characters;
923 ret->sax->characters = xmlTextReaderCharacters;
924 ret->cdataBlock = ret->sax->cdataBlock;
925 ret->sax->cdataBlock = xmlTextReaderCDataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000926
Daniel Veillard67df8092002-12-16 22:04:11 +0000927 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000928 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000929 ret->curnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000930 val = xmlParserInputBufferRead(input, 4);
931 if (val >= 4) {
932 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
Daniel Veillardea7751d2002-12-20 00:16:24 +0000933 (const char *) ret->input->buffer->content, 4, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000934 ret->base = 0;
935 ret->cur = 4;
936 } else {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000937 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000938 ret->base = 0;
939 ret->cur = 0;
940 }
941 ret->ctxt->_private = ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000942 ret->ctxt->linenumbers = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000943 ret->allocs = XML_TEXTREADER_CTXT;
944 return(ret);
945
946}
947
948/**
949 * xmlNewTextReaderFilename:
950 * @URI: the URI of the resource to process
951 *
952 * Create an xmlTextReader structure fed with the resource at @URI
953 *
954 * Returns the new xmlTextReaderPtr or NULL in case of error
955 */
956xmlTextReaderPtr
957xmlNewTextReaderFilename(const char *URI) {
958 xmlParserInputBufferPtr input;
959 xmlTextReaderPtr ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000960 char *directory = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000961
962 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
963 if (input == NULL)
964 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000965 ret = xmlNewTextReader(input, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000966 if (ret == NULL) {
967 xmlFreeParserInputBuffer(input);
968 return(NULL);
969 }
970 ret->allocs |= XML_TEXTREADER_INPUT;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000971 if (ret->ctxt->directory == NULL)
972 directory = xmlParserGetDirectory(URI);
973 if ((ret->ctxt->directory == NULL) && (directory != NULL))
974 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
975 if (directory != NULL)
976 xmlFree(directory);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000977 return(ret);
978}
979
980/**
981 * xmlFreeTextReader:
982 * @reader: the xmlTextReaderPtr
983 *
984 * Deallocate all the resources associated to the reader
985 */
986void
987xmlFreeTextReader(xmlTextReaderPtr reader) {
988 if (reader == NULL)
989 return;
990 if (reader->ctxt != NULL) {
991 if (reader->ctxt->myDoc != NULL) {
992 xmlFreeDoc(reader->ctxt->myDoc);
993 reader->ctxt->myDoc = NULL;
994 }
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000995 if ((reader->ctxt->vctxt.vstateTab != NULL) &&
996 (reader->ctxt->vctxt.vstateMax > 0)){
997 xmlFree(reader->ctxt->vctxt.vstateTab);
998 reader->ctxt->vctxt.vstateTab = 0;
999 reader->ctxt->vctxt.vstateMax = 0;
1000 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001001 if (reader->allocs & XML_TEXTREADER_CTXT)
1002 xmlFreeParserCtxt(reader->ctxt);
1003 }
1004 if (reader->sax != NULL)
1005 xmlFree(reader->sax);
1006 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
1007 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001008 if (reader->faketext != NULL) {
1009 xmlFreeNode(reader->faketext);
1010 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001011 if (reader->entTab != NULL)
1012 xmlFree(reader->entTab);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001013 xmlFree(reader);
1014}
1015
1016/************************************************************************
1017 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001018 * Methods for XmlTextReader *
1019 * *
1020 ************************************************************************/
1021/**
1022 * xmlTextReaderClose:
1023 * @reader: the xmlTextReaderPtr used
1024 *
1025 * This method releases any resources allocated by the current instance
1026 * changes the state to Closed and close any underlying input.
1027 *
1028 * Returns 0 or -1 in case of error
1029 */
1030int
1031xmlTextReaderClose(xmlTextReaderPtr reader) {
1032 if (reader == NULL)
1033 return(-1);
1034 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001035 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001036 reader->mode = XML_TEXTREADER_MODE_CLOSED;
1037 if (reader->ctxt != NULL) {
1038 if (reader->ctxt->myDoc != NULL) {
1039 xmlFreeDoc(reader->ctxt->myDoc);
1040 reader->ctxt->myDoc = NULL;
1041 }
1042 if (reader->allocs & XML_TEXTREADER_CTXT) {
1043 xmlFreeParserCtxt(reader->ctxt);
1044 reader->allocs -= XML_TEXTREADER_CTXT;
1045 }
1046 }
1047 if (reader->sax != NULL) {
1048 xmlFree(reader->sax);
1049 reader->sax = NULL;
1050 }
1051 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
1052 xmlFreeParserInputBuffer(reader->input);
1053 reader->allocs -= XML_TEXTREADER_INPUT;
1054 }
1055 return(0);
1056}
1057
1058/**
1059 * xmlTextReaderGetAttributeNo:
1060 * @reader: the xmlTextReaderPtr used
1061 * @no: the zero-based index of the attribute relative to the containing element
1062 *
1063 * Provides the value of the attribute with the specified index relative
1064 * to the containing element.
1065 *
1066 * Returns a string containing the value of the specified attribute, or NULL
1067 * in case of error. The string must be deallocated by the caller.
1068 */
1069xmlChar *
1070xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
1071 xmlChar *ret;
1072 int i;
1073 xmlAttrPtr cur;
1074 xmlNsPtr ns;
1075
1076 if (reader == NULL)
1077 return(NULL);
1078 if (reader->node == NULL)
1079 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001080 if (reader->curnode != NULL)
1081 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001082 /* TODO: handle the xmlDecl */
1083 if (reader->node->type != XML_ELEMENT_NODE)
1084 return(NULL);
1085
1086 ns = reader->node->nsDef;
1087 for (i = 0;(i < no) && (ns != NULL);i++) {
1088 ns = ns->next;
1089 }
1090 if (ns != NULL)
1091 return(xmlStrdup(ns->href));
1092
1093 cur = reader->node->properties;
1094 if (cur == NULL)
1095 return(NULL);
1096 for (;i < no;i++) {
1097 cur = cur->next;
1098 if (cur == NULL)
1099 return(NULL);
1100 }
1101 /* TODO walk the DTD if present */
1102
1103 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
1104 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
1105 return(ret);
1106}
1107
1108/**
1109 * xmlTextReaderGetAttribute:
1110 * @reader: the xmlTextReaderPtr used
1111 * @name: the qualified name of the attribute.
1112 *
1113 * Provides the value of the attribute with the specified qualified name.
1114 *
1115 * Returns a string containing the value of the specified attribute, or NULL
1116 * in case of error. The string must be deallocated by the caller.
1117 */
1118xmlChar *
1119xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1120 xmlChar *prefix = NULL;
1121 xmlChar *localname;
1122 xmlNsPtr ns;
1123 xmlChar *ret = NULL;
1124
1125 if ((reader == NULL) || (name == NULL))
1126 return(NULL);
1127 if (reader->node == NULL)
1128 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001129 if (reader->curnode != NULL)
1130 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001131
1132 /* TODO: handle the xmlDecl */
1133 if (reader->node->type != XML_ELEMENT_NODE)
1134 return(NULL);
1135
1136 localname = xmlSplitQName2(name, &prefix);
1137 if (localname == NULL)
1138 return(xmlGetProp(reader->node, name));
1139
1140 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1141 if (ns != NULL)
1142 ret = xmlGetNsProp(reader->node, localname, ns->href);
1143
1144 if (localname != NULL)
1145 xmlFree(localname);
1146 if (prefix != NULL)
1147 xmlFree(prefix);
1148 return(ret);
1149}
1150
1151
1152/**
1153 * xmlTextReaderGetAttributeNs:
1154 * @reader: the xmlTextReaderPtr used
1155 * @localName: the local name of the attribute.
1156 * @namespaceURI: the namespace URI of the attribute.
1157 *
1158 * Provides the value of the specified attribute
1159 *
1160 * Returns a string containing the value of the specified attribute, or NULL
1161 * in case of error. The string must be deallocated by the caller.
1162 */
1163xmlChar *
1164xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
1165 const xmlChar *namespaceURI) {
1166 if ((reader == NULL) || (localName == NULL))
1167 return(NULL);
1168 if (reader->node == NULL)
1169 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001170 if (reader->curnode != NULL)
1171 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001172
1173 /* TODO: handle the xmlDecl */
1174 if (reader->node->type != XML_ELEMENT_NODE)
1175 return(NULL);
1176
1177 return(xmlGetNsProp(reader->node, localName, namespaceURI));
1178}
1179
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001180/**
1181 * xmlTextReaderGetRemainder:
1182 * @reader: the xmlTextReaderPtr used
1183 *
1184 * Method to get the remainder of the buffered XML. this method stops the
1185 * parser, set its state to End Of File and return the input stream with
1186 * what is left that the parser did not use.
1187 *
1188 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
1189 * in case of error.
1190 */
1191xmlParserInputBufferPtr
1192xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
1193 xmlParserInputBufferPtr ret = NULL;
1194
1195 if (reader == NULL)
1196 return(NULL);
1197 if (reader->node == NULL)
1198 return(NULL);
1199
1200 reader->node = NULL;
1201 reader->curnode = NULL;
1202 reader->mode = XML_TEXTREADER_MODE_EOF;
1203 if (reader->ctxt != NULL) {
1204 if (reader->ctxt->myDoc != NULL) {
1205 xmlFreeDoc(reader->ctxt->myDoc);
1206 reader->ctxt->myDoc = NULL;
1207 }
1208 if (reader->allocs & XML_TEXTREADER_CTXT) {
1209 xmlFreeParserCtxt(reader->ctxt);
1210 reader->allocs -= XML_TEXTREADER_CTXT;
1211 }
1212 }
1213 if (reader->sax != NULL) {
1214 xmlFree(reader->sax);
1215 reader->sax = NULL;
1216 }
1217 if (reader->allocs & XML_TEXTREADER_INPUT) {
1218 ret = reader->input;
1219 reader->allocs -= XML_TEXTREADER_INPUT;
1220 } else {
1221 /*
1222 * Hum, one may need to duplicate the data structure because
1223 * without reference counting the input may be freed twice:
1224 * - by the layer which allocated it.
1225 * - by the layer to which would have been returned to.
1226 */
1227 TODO
1228 return(NULL);
1229 }
1230 return(ret);
1231}
1232
1233/**
1234 * xmlTextReaderLookupNamespace:
1235 * @reader: the xmlTextReaderPtr used
1236 * @prefix: the prefix whose namespace URI is to be resolved. To return
1237 * the default namespace, specify NULL
1238 *
1239 * Resolves a namespace prefix in the scope of the current element.
1240 *
1241 * Returns a string containing the namespace URI to which the prefix maps
1242 * or NULL in case of error. The string must be deallocated by the caller.
1243 */
1244xmlChar *
1245xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
1246 xmlNsPtr ns;
1247
1248 if (reader == NULL)
1249 return(NULL);
1250 if (reader->node == NULL)
1251 return(NULL);
1252
1253 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1254 if (ns == NULL)
1255 return(NULL);
1256 return(xmlStrdup(ns->href));
1257}
1258
1259/**
1260 * xmlTextReaderMoveToAttributeNo:
1261 * @reader: the xmlTextReaderPtr used
1262 * @no: the zero-based index of the attribute relative to the containing
1263 * element.
1264 *
1265 * Moves the position of the current instance to the attribute with
1266 * the specified index relative to the containing element.
1267 *
1268 * Returns 1 in case of success, -1 in case of error, 0 if not found
1269 */
1270int
1271xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
1272 int i;
1273 xmlAttrPtr cur;
1274 xmlNsPtr ns;
1275
1276 if (reader == NULL)
1277 return(-1);
1278 if (reader->node == NULL)
1279 return(-1);
1280 /* TODO: handle the xmlDecl */
1281 if (reader->node->type != XML_ELEMENT_NODE)
1282 return(-1);
1283
1284 reader->curnode = NULL;
1285
1286 ns = reader->node->nsDef;
1287 for (i = 0;(i < no) && (ns != NULL);i++) {
1288 ns = ns->next;
1289 }
1290 if (ns != NULL) {
1291 reader->curnode = (xmlNodePtr) ns;
1292 return(1);
1293 }
1294
1295 cur = reader->node->properties;
1296 if (cur == NULL)
1297 return(0);
1298 for (;i < no;i++) {
1299 cur = cur->next;
1300 if (cur == NULL)
1301 return(0);
1302 }
1303 /* TODO walk the DTD if present */
1304
1305 reader->curnode = (xmlNodePtr) cur;
1306 return(1);
1307}
1308
1309/**
1310 * xmlTextReaderMoveToAttribute:
1311 * @reader: the xmlTextReaderPtr used
1312 * @name: the qualified name of the attribute.
1313 *
1314 * Moves the position of the current instance to the attribute with
1315 * the specified qualified name.
1316 *
1317 * Returns 1 in case of success, -1 in case of error, 0 if not found
1318 */
1319int
1320xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1321 xmlChar *prefix = NULL;
1322 xmlChar *localname;
1323 xmlNsPtr ns;
1324 xmlAttrPtr prop;
1325
1326 if ((reader == NULL) || (name == NULL))
1327 return(-1);
1328 if (reader->node == NULL)
1329 return(-1);
1330
1331 /* TODO: handle the xmlDecl */
1332 if (reader->node->type != XML_ELEMENT_NODE)
1333 return(0);
1334
1335 localname = xmlSplitQName2(name, &prefix);
1336 if (localname == NULL) {
1337 /*
1338 * Namespace default decl
1339 */
1340 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1341 ns = reader->node->nsDef;
1342 while (ns != NULL) {
1343 if (ns->prefix == NULL) {
1344 reader->curnode = (xmlNodePtr) ns;
1345 return(1);
1346 }
1347 ns = ns->next;
1348 }
1349 return(0);
1350 }
1351
1352 prop = reader->node->properties;
1353 while (prop != NULL) {
1354 /*
1355 * One need to have
1356 * - same attribute names
1357 * - and the attribute carrying that namespace
1358 */
1359 if ((xmlStrEqual(prop->name, name)) &&
1360 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
1361 reader->curnode = (xmlNodePtr) prop;
1362 return(1);
1363 }
1364 prop = prop->next;
1365 }
1366 return(0);
1367 }
1368
1369 /*
1370 * Namespace default decl
1371 */
1372 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
1373 ns = reader->node->nsDef;
1374 while (ns != NULL) {
1375 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
1376 reader->curnode = (xmlNodePtr) ns;
1377 goto found;
1378 }
1379 ns = ns->next;
1380 }
1381 goto not_found;
1382 }
1383 prop = reader->node->properties;
1384 while (prop != NULL) {
1385 /*
1386 * One need to have
1387 * - same attribute names
1388 * - and the attribute carrying that namespace
1389 */
1390 if ((xmlStrEqual(prop->name, localname)) &&
1391 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
1392 reader->curnode = (xmlNodePtr) prop;
1393 goto found;
1394 }
1395 prop = prop->next;
1396 }
1397not_found:
1398 if (localname != NULL)
1399 xmlFree(localname);
1400 if (prefix != NULL)
1401 xmlFree(prefix);
1402 return(0);
1403
1404found:
1405 if (localname != NULL)
1406 xmlFree(localname);
1407 if (prefix != NULL)
1408 xmlFree(prefix);
1409 return(1);
1410}
1411
1412/**
1413 * xmlTextReaderMoveToAttributeNs:
1414 * @reader: the xmlTextReaderPtr used
1415 * @localName: the local name of the attribute.
1416 * @namespaceURI: the namespace URI of the attribute.
1417 *
1418 * Moves the position of the current instance to the attribute with the
1419 * specified local name and namespace URI.
1420 *
1421 * Returns 1 in case of success, -1 in case of error, 0 if not found
1422 */
1423int
1424xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
1425 const xmlChar *localName, const xmlChar *namespaceURI) {
1426 xmlAttrPtr prop;
1427 xmlNodePtr node;
1428
1429 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
1430 return(-1);
1431 if (reader->node == NULL)
1432 return(-1);
1433 if (reader->node->type != XML_ELEMENT_NODE)
1434 return(0);
1435 node = reader->node;
1436
1437 /*
1438 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
1439 * namespace name associated to "xmlns"
1440 */
1441 prop = node->properties;
1442 while (prop != NULL) {
1443 /*
1444 * One need to have
1445 * - same attribute names
1446 * - and the attribute carrying that namespace
1447 */
1448 if (xmlStrEqual(prop->name, localName) &&
1449 ((prop->ns != NULL) &&
1450 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
1451 reader->curnode = (xmlNodePtr) prop;
1452 return(1);
1453 }
1454 prop = prop->next;
1455 }
1456 return(0);
1457}
1458
1459/**
1460 * xmlTextReaderMoveToFirstAttribute:
1461 * @reader: the xmlTextReaderPtr used
1462 *
1463 * Moves the position of the current instance to the first attribute
1464 * associated with the current node.
1465 *
1466 * Returns 1 in case of success, -1 in case of error, 0 if not found
1467 */
1468int
1469xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
1470 if (reader == NULL)
1471 return(-1);
1472 if (reader->node == NULL)
1473 return(-1);
1474 if (reader->node->type != XML_ELEMENT_NODE)
1475 return(0);
1476
1477 if (reader->node->nsDef != NULL) {
1478 reader->curnode = (xmlNodePtr) reader->node->nsDef;
1479 return(1);
1480 }
1481 if (reader->node->properties != NULL) {
1482 reader->curnode = (xmlNodePtr) reader->node->properties;
1483 return(1);
1484 }
1485 return(0);
1486}
1487
1488/**
1489 * xmlTextReaderMoveToNextAttribute:
1490 * @reader: the xmlTextReaderPtr used
1491 *
1492 * Moves the position of the current instance to the next attribute
1493 * associated with the current node.
1494 *
1495 * Returns 1 in case of success, -1 in case of error, 0 if not found
1496 */
1497int
1498xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
1499 if (reader == NULL)
1500 return(-1);
1501 if (reader->node == NULL)
1502 return(-1);
1503 if (reader->node->type != XML_ELEMENT_NODE)
1504 return(0);
1505 if (reader->curnode == NULL)
1506 return(xmlTextReaderMoveToFirstAttribute(reader));
1507
1508 if (reader->curnode->type == XML_NAMESPACE_DECL) {
1509 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1510 if (ns->next != NULL) {
1511 reader->curnode = (xmlNodePtr) ns->next;
1512 return(1);
1513 }
1514 if (reader->node->properties != NULL) {
1515 reader->curnode = (xmlNodePtr) reader->node->properties;
1516 return(1);
1517 }
1518 return(0);
1519 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
1520 (reader->curnode->next != NULL)) {
1521 reader->curnode = reader->curnode->next;
1522 return(1);
1523 }
1524 return(0);
1525}
1526
1527/**
1528 * xmlTextReaderMoveToElement:
1529 * @reader: the xmlTextReaderPtr used
1530 *
1531 * Moves the position of the current instance to the node that
1532 * contains the current Attribute node.
1533 *
1534 * Returns 1 in case of success, -1 in case of error, 0 if not moved
1535 */
1536int
1537xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
1538 if (reader == NULL)
1539 return(-1);
1540 if (reader->node == NULL)
1541 return(-1);
1542 if (reader->node->type != XML_ELEMENT_NODE)
1543 return(0);
1544 if (reader->curnode != NULL) {
1545 reader->curnode = NULL;
1546 return(1);
1547 }
1548 return(0);
1549}
1550
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001551/**
1552 * xmlTextReaderReadAttributeValue:
1553 * @reader: the xmlTextReaderPtr used
1554 *
1555 * Parses an attribute value into one or more Text and EntityReference nodes.
1556 *
1557 * Returns 1 in case of success, 0 if the reader was not positionned on an
1558 * ttribute node or all the attribute values have been read, or -1
1559 * in case of error.
1560 */
1561int
1562xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
1563 if (reader == NULL)
1564 return(-1);
1565 if (reader->node == NULL)
1566 return(-1);
1567 if (reader->curnode == NULL)
1568 return(0);
1569 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
1570 if (reader->curnode->children == NULL)
1571 return(0);
1572 reader->curnode = reader->curnode->children;
1573 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
1574 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
1575
1576 if (reader->faketext == NULL) {
1577 reader->faketext = xmlNewDocText(reader->node->doc,
1578 ns->href);
1579 } else {
1580 if (reader->faketext->content != NULL)
1581 xmlFree(reader->faketext->content);
1582 reader->faketext->content = xmlStrdup(ns->href);
1583 }
1584 reader->curnode = reader->faketext;
1585 } else {
1586 if (reader->curnode->next == NULL)
1587 return(0);
1588 reader->curnode = reader->curnode->next;
1589 }
1590 return(1);
1591}
1592
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001593/************************************************************************
1594 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001595 * Acces API to the current node *
1596 * *
1597 ************************************************************************/
1598/**
1599 * xmlTextReaderAttributeCount:
1600 * @reader: the xmlTextReaderPtr used
1601 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001602 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001603 *
1604 * Returns 0 i no attributes, -1 in case of error or the attribute count
1605 */
1606int
1607xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
1608 int ret;
1609 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00001610 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001611 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001612
1613 if (reader == NULL)
1614 return(-1);
1615 if (reader->node == NULL)
1616 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001617
1618 if (reader->curnode != NULL)
1619 node = reader->curnode;
1620 else
1621 node = reader->node;
1622
1623 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001624 return(0);
1625 if ((reader->state == XML_TEXTREADER_END) ||
1626 (reader->state == XML_TEXTREADER_BACKTRACK))
1627 return(0);
1628 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001629 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001630 while (attr != NULL) {
1631 ret++;
1632 attr = attr->next;
1633 }
Daniel Veillard67df8092002-12-16 22:04:11 +00001634 ns = node->nsDef;
1635 while (ns != NULL) {
1636 ret++;
1637 ns = ns->next;
1638 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001639 return(ret);
1640}
1641
1642/**
1643 * xmlTextReaderNodeType:
1644 * @reader: the xmlTextReaderPtr used
1645 *
1646 * Get the node type of the current node
1647 * Reference:
1648 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
1649 *
1650 * Returns the xmlNodeType of the current node or -1 in case of error
1651 */
1652int
1653xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001654 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001655 if (reader == NULL)
1656 return(-1);
1657 if (reader->node == NULL)
1658 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001659 if (reader->curnode != NULL)
1660 node = reader->curnode;
1661 else
1662 node = reader->node;
1663 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001664 case XML_ELEMENT_NODE:
1665 if ((reader->state == XML_TEXTREADER_END) ||
1666 (reader->state == XML_TEXTREADER_BACKTRACK))
1667 return(15);
1668 return(1);
Daniel Veillardecaba492002-12-30 10:55:29 +00001669 case XML_NAMESPACE_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001670 case XML_ATTRIBUTE_NODE:
1671 return(2);
1672 case XML_TEXT_NODE:
1673 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
1674 case XML_CDATA_SECTION_NODE:
1675 return(4);
1676 case XML_ENTITY_REF_NODE:
1677 return(5);
1678 case XML_ENTITY_NODE:
1679 return(6);
1680 case XML_PI_NODE:
1681 return(7);
1682 case XML_COMMENT_NODE:
1683 return(8);
1684 case XML_DOCUMENT_NODE:
1685 case XML_HTML_DOCUMENT_NODE:
1686#ifdef LIBXML_DOCB_ENABLED
1687 case XML_DOCB_DOCUMENT_NODE:
1688#endif
1689 return(9);
1690 case XML_DOCUMENT_FRAG_NODE:
1691 return(11);
1692 case XML_NOTATION_NODE:
1693 return(12);
1694 case XML_DOCUMENT_TYPE_NODE:
1695 case XML_DTD_NODE:
1696 return(10);
1697
1698 case XML_ELEMENT_DECL:
1699 case XML_ATTRIBUTE_DECL:
1700 case XML_ENTITY_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001701 case XML_XINCLUDE_START:
1702 case XML_XINCLUDE_END:
1703 return(0);
1704 }
1705 return(-1);
1706}
1707
1708/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001709 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001710 * @reader: the xmlTextReaderPtr used
1711 *
1712 * Check if the current node is empty
1713 *
1714 * Returns 1 if empty, 0 if not and -1 in case of error
1715 */
1716int
1717xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
1718 if ((reader == NULL) || (reader->node == NULL))
1719 return(-1);
Daniel Veillarddf512f42002-12-23 15:56:21 +00001720 if (reader->node->type != XML_ELEMENT_NODE)
1721 return(0);
Daniel Veillarde3c036e2003-01-01 15:11:05 +00001722 if (reader->curnode != NULL)
1723 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001724 if (reader->node->children != NULL)
1725 return(0);
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001726 if (reader->state == XML_TEXTREADER_END)
1727 return(0);
1728 if (reader->wasempty == -1)
1729 return(0);
Daniel Veillarddf512f42002-12-23 15:56:21 +00001730 if (reader->node != reader->ctxt->node)
1731 return(1);
1732 if ((reader->ctxt->node != NULL) &&
1733 (reader->node == reader->ctxt->node->last) &&
1734 (reader->wasempty == 1))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001735 return(1);
1736 return(0);
1737}
1738
1739/**
1740 * xmlTextReaderLocalName:
1741 * @reader: the xmlTextReaderPtr used
1742 *
1743 * The local name of the node.
1744 *
1745 * Returns the local name or NULL if not available
1746 */
1747xmlChar *
1748xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001749 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001750 if ((reader == NULL) || (reader->node == NULL))
1751 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001752 if (reader->curnode != NULL)
1753 node = reader->curnode;
1754 else
1755 node = reader->node;
1756 if (node->type == XML_NAMESPACE_DECL) {
1757 xmlNsPtr ns = (xmlNsPtr) node;
1758 if (ns->prefix == NULL)
1759 return(xmlStrdup(BAD_CAST "xmlns"));
1760 else
1761 return(xmlStrdup(ns->prefix));
1762 }
1763 if ((node->type != XML_ELEMENT_NODE) &&
1764 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001765 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001766 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001767}
1768
1769/**
1770 * xmlTextReaderName:
1771 * @reader: the xmlTextReaderPtr used
1772 *
1773 * The qualified name of the node, equal to Prefix :LocalName.
1774 *
1775 * Returns the local name or NULL if not available
1776 */
1777xmlChar *
1778xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001779 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001780 xmlChar *ret;
1781
1782 if ((reader == NULL) || (reader->node == NULL))
1783 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001784 if (reader->curnode != NULL)
1785 node = reader->curnode;
1786 else
1787 node = reader->node;
1788 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001789 case XML_ELEMENT_NODE:
1790 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001791 if ((node->ns == NULL) ||
1792 (node->ns->prefix == NULL))
1793 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001794
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001795 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001796 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001797 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001798 return(ret);
1799 case XML_TEXT_NODE:
1800 return(xmlStrdup(BAD_CAST "#text"));
1801 case XML_CDATA_SECTION_NODE:
1802 return(xmlStrdup(BAD_CAST "#cdata-section"));
1803 case XML_ENTITY_NODE:
1804 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001805 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001806 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001807 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001808 case XML_COMMENT_NODE:
1809 return(xmlStrdup(BAD_CAST "#comment"));
1810 case XML_DOCUMENT_NODE:
1811 case XML_HTML_DOCUMENT_NODE:
1812#ifdef LIBXML_DOCB_ENABLED
1813 case XML_DOCB_DOCUMENT_NODE:
1814#endif
1815 return(xmlStrdup(BAD_CAST "#document"));
1816 case XML_DOCUMENT_FRAG_NODE:
1817 return(xmlStrdup(BAD_CAST "#document-fragment"));
1818 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001819 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001820 case XML_DOCUMENT_TYPE_NODE:
1821 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001822 return(xmlStrdup(node->name));
1823 case XML_NAMESPACE_DECL: {
1824 xmlNsPtr ns = (xmlNsPtr) node;
1825
1826 ret = xmlStrdup(BAD_CAST "xmlns");
1827 if (ns->prefix == NULL)
1828 return(ret);
1829 ret = xmlStrcat(ret, BAD_CAST ":");
1830 ret = xmlStrcat(ret, ns->prefix);
1831 return(ret);
1832 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001833
1834 case XML_ELEMENT_DECL:
1835 case XML_ATTRIBUTE_DECL:
1836 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001837 case XML_XINCLUDE_START:
1838 case XML_XINCLUDE_END:
1839 return(NULL);
1840 }
1841 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001842}
1843
1844/**
1845 * xmlTextReaderPrefix:
1846 * @reader: the xmlTextReaderPtr used
1847 *
1848 * A shorthand reference to the namespace associated with the node.
1849 *
1850 * Returns the prefix or NULL if not available
1851 */
1852xmlChar *
1853xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001854 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001855 if ((reader == NULL) || (reader->node == NULL))
1856 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001857 if (reader->curnode != NULL)
1858 node = reader->curnode;
1859 else
1860 node = reader->node;
1861 if (node->type == XML_NAMESPACE_DECL) {
1862 xmlNsPtr ns = (xmlNsPtr) node;
1863 if (ns->prefix == NULL)
1864 return(NULL);
1865 return(xmlStrdup(BAD_CAST "xmlns"));
1866 }
1867 if ((node->type != XML_ELEMENT_NODE) &&
1868 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001869 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001870 if ((node->ns != NULL) || (node->ns->prefix != NULL))
1871 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001872 return(NULL);
1873}
1874
1875/**
1876 * xmlTextReaderNamespaceUri:
1877 * @reader: the xmlTextReaderPtr used
1878 *
1879 * The URI defining the namespace associated with the node.
1880 *
1881 * Returns the namespace URI or NULL if not available
1882 */
1883xmlChar *
1884xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001885 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001886 if ((reader == NULL) || (reader->node == NULL))
1887 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001888 if (reader->curnode != NULL)
1889 node = reader->curnode;
1890 else
1891 node = reader->node;
Daniel Veillardecaba492002-12-30 10:55:29 +00001892 if (node->type == XML_NAMESPACE_DECL)
1893 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001894 if ((node->type != XML_ELEMENT_NODE) &&
1895 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001896 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001897 if (node->ns != NULL)
1898 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001899 return(NULL);
1900}
1901
1902/**
1903 * xmlTextReaderBaseUri:
1904 * @reader: the xmlTextReaderPtr used
1905 *
1906 * The base URI of the node.
1907 *
1908 * Returns the base URI or NULL if not available
1909 */
1910xmlChar *
1911xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
1912 if ((reader == NULL) || (reader->node == NULL))
1913 return(NULL);
1914 return(xmlNodeGetBase(NULL, reader->node));
1915}
1916
1917/**
1918 * xmlTextReaderDepth:
1919 * @reader: the xmlTextReaderPtr used
1920 *
1921 * The depth of the node in the tree.
1922 *
1923 * Returns the depth or -1 in case of error
1924 */
1925int
1926xmlTextReaderDepth(xmlTextReaderPtr reader) {
1927 if (reader == NULL)
1928 return(-1);
1929 if (reader->node == NULL)
1930 return(0);
1931
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001932 if (reader->curnode != NULL) {
1933 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
1934 (reader->curnode->type == XML_NAMESPACE_DECL))
1935 return(reader->depth + 1);
1936 return(reader->depth + 2);
1937 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001938 return(reader->depth);
1939}
1940
1941/**
1942 * xmlTextReaderHasAttributes:
1943 * @reader: the xmlTextReaderPtr used
1944 *
1945 * Whether the node has attributes.
1946 *
1947 * Returns 1 if true, 0 if false, and -1 in case or error
1948 */
1949int
1950xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001951 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001952 if (reader == NULL)
1953 return(-1);
1954 if (reader->node == NULL)
1955 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001956 if (reader->curnode != NULL)
1957 node = reader->curnode;
1958 else
1959 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001960
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001961 if ((node->type == XML_ELEMENT_NODE) &&
1962 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001963 return(1);
1964 /* TODO: handle the xmlDecl */
1965 return(0);
1966}
1967
1968/**
1969 * xmlTextReaderHasValue:
1970 * @reader: the xmlTextReaderPtr used
1971 *
1972 * Whether the node can have a text value.
1973 *
1974 * Returns 1 if true, 0 if false, and -1 in case or error
1975 */
1976int
1977xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001978 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001979 if (reader == NULL)
1980 return(-1);
1981 if (reader->node == NULL)
1982 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001983 if (reader->curnode != NULL)
1984 node = reader->curnode;
1985 else
1986 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001987
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001988 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00001989 case XML_ATTRIBUTE_NODE:
1990 case XML_TEXT_NODE:
1991 case XML_CDATA_SECTION_NODE:
1992 case XML_PI_NODE:
1993 case XML_COMMENT_NODE:
1994 return(1);
1995 default:
1996 return(0);
1997 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001998 return(0);
1999}
2000
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002001/**
2002 * xmlTextReaderValue:
2003 * @reader: the xmlTextReaderPtr used
2004 *
2005 * Provides the text value of the node if present
2006 *
2007 * Returns the string or NULL if not available. The retsult must be deallocated
2008 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002009 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002010xmlChar *
2011xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002012 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002013 if (reader == NULL)
2014 return(NULL);
2015 if (reader->node == NULL)
2016 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002017 if (reader->curnode != NULL)
2018 node = reader->curnode;
2019 else
2020 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002021
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002022 switch (node->type) {
2023 case XML_NAMESPACE_DECL:
2024 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002025 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002026 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002027
2028 if (attr->parent != NULL)
2029 return (xmlNodeListGetString
2030 (attr->parent->doc, attr->children, 1));
2031 else
2032 return (xmlNodeListGetString(NULL, attr->children, 1));
2033 break;
2034 }
2035 case XML_TEXT_NODE:
2036 case XML_CDATA_SECTION_NODE:
2037 case XML_PI_NODE:
2038 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002039 if (node->content != NULL)
2040 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002041 default:
2042 return(NULL);
2043 }
2044 return(NULL);
2045}
2046
2047/**
2048 * xmlTextReaderIsDefault:
2049 * @reader: the xmlTextReaderPtr used
2050 *
2051 * Whether an Attribute node was generated from the default value
2052 * defined in the DTD or schema.
2053 *
2054 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
2055 */
2056int
2057xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
2058 if (reader == NULL)
2059 return(-1);
2060 return(0);
2061}
2062
2063/**
2064 * xmlTextReaderQuoteChar:
2065 * @reader: the xmlTextReaderPtr used
2066 *
2067 * The quotation mark character used to enclose the value of an attribute.
2068 *
2069 * Returns " or ' and -1 in case of error
2070 */
2071int
2072xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
2073 if (reader == NULL)
2074 return(-1);
2075 /* TODO maybe lookup the attribute value for " first */
2076 return((int) '"');
2077}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002078
2079/**
2080 * xmlTextReaderXmlLang:
2081 * @reader: the xmlTextReaderPtr used
2082 *
2083 * The xml:lang scope within which the node resides.
2084 *
2085 * Returns the xml:lang value or NULL if none exists.
2086 */
2087xmlChar *
2088xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
2089 if (reader == NULL)
2090 return(NULL);
2091 if (reader->node == NULL)
2092 return(NULL);
2093 return(xmlNodeGetLang(reader->node));
2094}
2095
Daniel Veillard67df8092002-12-16 22:04:11 +00002096/**
2097 * xmlTextReaderNormalization:
2098 * @reader: the xmlTextReaderPtr used
2099 *
2100 * The value indicating whether to normalize white space and attribute values.
2101 * Since attribute value and end of line normalizations are a MUST in the XML
2102 * specification only the value true is accepted. The broken bahaviour of
2103 * accepting out of range character entities like &#0; is of course not
2104 * supported either.
2105 *
2106 * Returns 1 or -1 in case of error.
2107 */
2108int
2109xmlTextReaderNormalization(xmlTextReaderPtr reader) {
2110 if (reader == NULL)
2111 return(-1);
2112 return(1);
2113}
2114
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002115/************************************************************************
2116 * *
2117 * Extensions to the base APIs *
2118 * *
2119 ************************************************************************/
2120
2121/**
2122 * xmlTextReaderSetParserProp:
2123 * @reader: the xmlTextReaderPtr used
2124 * @prop: the xmlParserProperties to set
2125 * @value: usually 0 or 1 to (de)activate it
2126 *
2127 * Change the parser processing behaviour by changing some of its internal
2128 * properties. Note that some properties can only be changed before any
2129 * read has been done.
2130 *
2131 * Returns 0 if the call was successful, or -1 in case of error
2132 */
2133int
2134xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
2135 xmlParserProperties p = (xmlParserProperties) prop;
2136 xmlParserCtxtPtr ctxt;
2137
2138 if ((reader == NULL) || (reader->ctxt == NULL))
2139 return(-1);
2140 ctxt = reader->ctxt;
2141
2142 switch (p) {
2143 case XML_PARSER_LOADDTD:
2144 if (value != 0) {
2145 if (ctxt->loadsubset == 0) {
2146 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2147 return(-1);
2148 ctxt->loadsubset = XML_DETECT_IDS;
2149 }
2150 } else {
2151 ctxt->loadsubset = 0;
2152 }
2153 return(0);
2154 case XML_PARSER_DEFAULTATTRS:
2155 if (value != 0) {
2156 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
2157 } else {
2158 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2159 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
2160 }
2161 return(0);
2162 case XML_PARSER_VALIDATE:
2163 if (value != 0) {
2164 ctxt->validate = 1;
2165 } else {
2166 ctxt->validate = 0;
2167 }
2168 return(0);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002169 case XML_PARSER_SUBST_ENTITIES:
2170 if (value != 0) {
2171 ctxt->replaceEntities = 1;
2172 } else {
2173 ctxt->replaceEntities = 0;
2174 }
2175 return(0);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002176 }
2177 return(-1);
2178}
2179
2180/**
2181 * xmlTextReaderGetParserProp:
2182 * @reader: the xmlTextReaderPtr used
2183 * @prop: the xmlParserProperties to get
2184 *
2185 * Read the parser internal property.
2186 *
2187 * Returns the value, usually 0 or 1, or -1 in case of error.
2188 */
2189int
2190xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
2191 xmlParserProperties p = (xmlParserProperties) prop;
2192 xmlParserCtxtPtr ctxt;
2193
2194 if ((reader == NULL) || (reader->ctxt == NULL))
2195 return(-1);
2196 ctxt = reader->ctxt;
2197
2198 switch (p) {
2199 case XML_PARSER_LOADDTD:
2200 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
2201 return(1);
2202 return(0);
2203 case XML_PARSER_DEFAULTATTRS:
2204 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2205 return(1);
2206 return(0);
2207 case XML_PARSER_VALIDATE:
2208 return(ctxt->validate);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002209 case XML_PARSER_SUBST_ENTITIES:
2210 return(ctxt->replaceEntities);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002211 }
2212 return(-1);
2213}
2214
Daniel Veillarde18fc182002-12-28 22:56:33 +00002215/**
2216 * xmlTextReaderCurrentNode:
2217 * @reader: the xmlTextReaderPtr used
2218 *
2219 * Hacking interface allowing to get the xmlNodePtr correponding to the
2220 * current node being accessed by the xmlTextReader. This is dangerous
2221 * because the underlying node may be destroyed on the next Reads.
2222 *
2223 * Returns the xmlNodePtr or NULL in case of error.
2224 */
2225xmlNodePtr
2226xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
2227 if (reader == NULL)
2228 return(NULL);
2229
2230 if (reader->curnode != NULL)
2231 return(reader->curnode);
2232 return(reader->node);
2233}
2234
2235/**
2236 * xmlTextReaderCurrentDoc:
2237 * @reader: the xmlTextReaderPtr used
2238 *
2239 * Hacking interface allowing to get the xmlDocPtr correponding to the
2240 * current document being accessed by the xmlTextReader. This is dangerous
2241 * because the associated node may be destroyed on the next Reads.
2242 *
2243 * Returns the xmlDocPtr or NULL in case of error.
2244 */
2245xmlDocPtr
2246xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
2247 if ((reader == NULL) || (reader->ctxt == NULL))
2248 return(NULL);
2249
2250 return(reader->ctxt->myDoc);
2251}
2252
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002253/************************************************************************
2254 * *
2255 * Utilities *
2256 * *
2257 ************************************************************************/
2258/**
2259 * xmlBase64Decode:
2260 * @in: the input buffer
2261 * @inlen: the size of the input (in), the size read from it (out)
2262 * @to: the output buffer
2263 * @tolen: the size of the output (in), the size written to (out)
2264 *
2265 * Base64 decoder, reads from @in and save in @to
2266 *
2267 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
2268 * 2 if there wasn't enough space on the output or -1 in case of error.
2269 */
2270static int
2271xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
2272 unsigned char *to, unsigned long *tolen) {
2273 unsigned long incur; /* current index in in[] */
2274 unsigned long inblk; /* last block index in in[] */
2275 unsigned long outcur; /* current index in out[] */
2276 unsigned long inmax; /* size of in[] */
2277 unsigned long outmax; /* size of out[] */
2278 unsigned char cur; /* the current value read from in[] */
2279 unsigned char intmp[3], outtmp[4]; /* temporary buffers for the convert */
2280 int nbintmp; /* number of byte in intmp[] */
2281 int is_ignore; /* cur should be ignored */
2282 int is_end = 0; /* the end of the base64 was found */
2283 int retval = 1;
2284 int i;
2285
2286 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
2287 return(-1);
2288
2289 incur = 0;
2290 inblk = 0;
2291 outcur = 0;
2292 inmax = *inlen;
2293 outmax = *tolen;
2294 nbintmp = 0;
2295
2296 while (1) {
2297 if (incur >= inmax)
2298 break;
2299 cur = in[incur++];
2300 is_ignore = 0;
2301 if ((cur >= 'A') && (cur <= 'Z'))
2302 cur = cur - 'A';
2303 else if ((cur >= 'a') && (cur <= 'z'))
2304 cur = cur - 'a' + 26;
2305 else if ((cur >= '0') && (cur <= '9'))
2306 cur = cur - '0' + 52;
2307 else if (cur == '+')
2308 cur = 62;
2309 else if (cur == '/')
2310 cur = 63;
2311 else if (cur == '.')
2312 cur = 0;
2313 else if (cur == '=') /*no op , end of the base64 stream */
2314 is_end = 1;
2315 else {
2316 is_ignore = 1;
2317 if (nbintmp == 0)
2318 inblk = incur;
2319 }
2320
2321 if (!is_ignore) {
2322 int nbouttmp = 3;
2323 int is_break = 0;
2324
2325 if (is_end) {
2326 if (nbintmp == 0)
2327 break;
2328 if ((nbintmp == 1) || (nbintmp == 2))
2329 nbouttmp = 1;
2330 else
2331 nbouttmp = 2;
2332 nbintmp = 3;
2333 is_break = 1;
2334 }
2335 intmp[nbintmp++] = cur;
2336 /*
2337 * if intmp is full, push the 4byte sequence as a 3 byte
2338 * sequence out
2339 */
2340 if (nbintmp == 4) {
2341 nbintmp = 0;
2342 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
2343 outtmp[1] =
2344 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
2345 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
2346 if (outcur + 3 >= outmax) {
2347 retval = 2;
2348 break;
2349 }
2350
2351 for (i = 0; i < nbouttmp; i++)
2352 to[outcur++] = outtmp[i];
2353 inblk = incur;
2354 }
2355
2356 if (is_break) {
2357 retval = 0;
2358 break;
2359 }
2360 }
2361 }
2362
2363 *tolen = outcur;
2364 *inlen = inblk;
2365 return (retval);
2366}
2367
2368/*
2369 * Test routine for the xmlBase64Decode function
2370 */
2371#if 0
2372int main(int argc, char **argv) {
2373 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
2374 char output[100];
2375 char output2[100];
2376 char output3[100];
2377 unsigned long inlen = strlen(input);
2378 unsigned long outlen = 100;
2379 int ret;
2380 unsigned long cons, tmp, tmp2, prod;
2381
2382 /*
2383 * Direct
2384 */
2385 ret = xmlBase64Decode(input, &inlen, output, &outlen);
2386
2387 output[outlen] = 0;
2388 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
2389
2390 /*
2391 * output chunking
2392 */
2393 cons = 0;
2394 prod = 0;
2395 while (cons < inlen) {
2396 tmp = 5;
2397 tmp2 = inlen - cons;
2398
2399 printf("%ld %ld\n", cons, prod);
2400 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
2401 cons += tmp2;
2402 prod += tmp;
2403 printf("%ld %ld\n", cons, prod);
2404 }
2405 output2[outlen] = 0;
2406 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
2407
2408 /*
2409 * input chunking
2410 */
2411 cons = 0;
2412 prod = 0;
2413 while (cons < inlen) {
2414 tmp = 100 - prod;
2415 tmp2 = inlen - cons;
2416 if (tmp2 > 5)
2417 tmp2 = 5;
2418
2419 printf("%ld %ld\n", cons, prod);
2420 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
2421 cons += tmp2;
2422 prod += tmp;
2423 printf("%ld %ld\n", cons, prod);
2424 }
2425 output3[outlen] = 0;
2426 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
2427 return(0);
2428
2429}
2430#endif