blob: eea9a287f74f22aff8e4e7c0caa7d6eec485ed19 [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:
Daniel Veillard7704fb12003-01-03 16:19:51 +000015 * - provide an API to preserve part of the tree
16 * - Streaming XInclude support
Daniel Veillard067bae52003-01-05 01:27:54 +000017 * - validation against a provided DTD
18 * - XML Schemas validation
Daniel Veillard7704fb12003-01-03 16:19:51 +000019 * - setting(s) for NoBlanks
20 * - performances and tuning ...
21 */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000022#define IN_LIBXML
23#include "libxml.h"
24
25#include <string.h> /* for memset() only ! */
Daniel Veillard26f70262003-01-16 22:45:08 +000026#include <stdarg.h>
Daniel Veillarde1ca5032002-12-09 14:13:43 +000027
28#ifdef HAVE_CTYPE_H
29#include <ctype.h>
30#endif
31#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
34
35#include <libxml/xmlmemory.h>
36#include <libxml/xmlIO.h>
37#include <libxml/xmlreader.h>
Daniel Veillardf4e55762003-04-15 23:32:22 +000038#include <libxml/relaxng.h>
Daniel Veillarde1ca5032002-12-09 14:13:43 +000039
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
Daniel Veillarda880b122003-04-21 21:36:41 +000059#define CHUNK_SIZE 512
Daniel Veillarde1ca5032002-12-09 14:13:43 +000060/************************************************************************
61 * *
62 * The parser: maps the Text Reader API on top of the existing *
63 * parsing routines building a tree *
64 * *
65 ************************************************************************/
66
67#define XML_TEXTREADER_INPUT 1
68#define XML_TEXTREADER_CTXT 2
69
70typedef enum {
Daniel Veillard67df8092002-12-16 22:04:11 +000071 XML_TEXTREADER_MODE_INITIAL = 0,
72 XML_TEXTREADER_MODE_INTERACTIVE = 1,
73 XML_TEXTREADER_MODE_ERROR = 2,
74 XML_TEXTREADER_MODE_EOF =3,
75 XML_TEXTREADER_MODE_CLOSED = 4,
76 XML_TEXTREADER_MODE_READING = 5
Daniel Veillarde1ca5032002-12-09 14:13:43 +000077} xmlTextReaderMode;
78
79typedef enum {
80 XML_TEXTREADER_NONE = -1,
81 XML_TEXTREADER_START= 0,
82 XML_TEXTREADER_ELEMENT= 1,
83 XML_TEXTREADER_END= 2,
84 XML_TEXTREADER_EMPTY= 3,
Daniel Veillardea7751d2002-12-20 00:16:24 +000085 XML_TEXTREADER_BACKTRACK= 4,
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000086 XML_TEXTREADER_DONE= 5,
87 XML_TEXTREADER_ERROR= 6
Daniel Veillarde1ca5032002-12-09 14:13:43 +000088} xmlTextReaderState;
89
Daniel Veillardf4e55762003-04-15 23:32:22 +000090typedef enum {
91 XML_TEXTREADER_NOT_VALIDATE = 0,
92 XML_TEXTREADER_VALIDATE_DTD = 1,
93 XML_TEXTREADER_VALIDATE_RNG = 2
94} xmlTextReaderValidate;
95
Daniel Veillarde1ca5032002-12-09 14:13:43 +000096struct _xmlTextReader {
97 int mode; /* the parsing mode */
Daniel Veillardf4e55762003-04-15 23:32:22 +000098 xmlTextReaderValidate validate;/* is there any validation */
Daniel Veillarde1ca5032002-12-09 14:13:43 +000099 int allocs; /* what structure were deallocated */
100 xmlTextReaderState state;
101 xmlParserCtxtPtr ctxt; /* the parser context */
102 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
103 xmlParserInputBufferPtr input; /* the input */
104 startElementSAXFunc startElement;/* initial SAX callbacks */
105 endElementSAXFunc endElement; /* idem */
Daniel Veillard07cb8222003-09-10 10:51:05 +0000106 startElementNsSAX2Func startElementNs;/* idem */
107 endElementNsSAX2Func endElementNs; /* idem */
Daniel Veillardea7751d2002-12-20 00:16:24 +0000108 charactersSAXFunc characters;
109 cdataBlockSAXFunc cdataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000110 unsigned int base; /* base of the segment in the input */
111 unsigned int cur; /* current position in the input */
112 xmlNodePtr node; /* current node */
Daniel Veillardda46d2d2002-12-15 23:36:49 +0000113 xmlNodePtr curnode;/* current attribute node */
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000114 int depth; /* depth of the current node */
Daniel Veillardbeb70bd2002-12-18 14:53:54 +0000115 xmlNodePtr faketext;/* fake xmlNs chld */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000116
117 /* entity stack when traversing entities content */
118 xmlNodePtr ent; /* Current Entity Ref Node */
119 int entNr; /* Depth of the entities stack */
120 int entMax; /* Max depth of the entities stack */
121 xmlNodePtr *entTab; /* array of entities */
Daniel Veillard26f70262003-01-16 22:45:08 +0000122
123 /* error handling */
124 xmlTextReaderErrorFunc errorFunc; /* callback function */
125 void *errorFuncArg; /* callback function user argument */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000126
127#ifdef LIBXML_SCHEMAS_ENABLED
128 /* Handling of RelaxNG validation */
129 xmlRelaxNGPtr rngSchemas; /* The Relax NG schemas */
130 xmlRelaxNGValidCtxtPtr rngValidCtxt; /* The Relax NG validation context */
131 int rngValidErrors; /* The number of errors detected */
132 xmlNodePtr rngFullNode; /* the node if RNG not progressive */
133#endif
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000134};
135
Daniel Veillard067bae52003-01-05 01:27:54 +0000136static const char *xmlTextReaderIsEmpty = "This element is empty";
137
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +0000138/************************************************************************
139 * *
140 * Our own version of the freeing routines as we recycle nodes *
141 * *
142 ************************************************************************/
143
144static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur);
145static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur);
146
147/**
148 * xmlTextReaderFreeEntityWrapper:
149 * @entity: An entity
150 * @name: its name
151 *
152 * Deallocate the memory used by an entities in the hash table.
153 */
154static void
155xmlTextReaderFreeEntityWrapper(xmlEntityPtr entity,
156 const xmlChar *name ATTRIBUTE_UNUSED) {
157 if (entity == NULL) return;
158
159 if ((entity->children) && (entity->owner == 1) &&
160 (entity == (xmlEntityPtr) entity->children->parent)) {
161 xmlDocPtr doc;
162 xmlTextReaderPtr reader = NULL;
163 doc = entity->doc;
164 if (doc != NULL)
165 reader = doc->_private;
166 xmlTextReaderFreeNodeList(reader, entity->children);
167 }
168 if (entity->name != NULL)
169 xmlFree((char *) entity->name);
170 if (entity->ExternalID != NULL)
171 xmlFree((char *) entity->ExternalID);
172 if (entity->SystemID != NULL)
173 xmlFree((char *) entity->SystemID);
174 if (entity->URI != NULL)
175 xmlFree((char *) entity->URI);
176 if (entity->content != NULL)
177 xmlFree((char *) entity->content);
178 if (entity->orig != NULL)
179 xmlFree((char *) entity->orig);
180 xmlFree(entity);
181}
182
183/**
184 * xmlTextReaderFreeEntitiesTable:
185 * @table: An entity table
186 *
187 * Deallocate the memory used by an entities hash table.
188 */
189static void
190xmlTextReaderFreeEntitiesTable(xmlEntitiesTablePtr table) {
191 xmlHashFree(table, (xmlHashDeallocator) xmlTextReaderFreeEntityWrapper);
192}
193
194/**
195 * xmlTextReaderFreeDtd:
196 * @cur: the DTD structure to free up
197 *
198 * Free a DTD structure.
199 */
200static void
201xmlTextReaderFreeDtd(xmlTextReaderPtr reader, xmlDtdPtr cur) {
202 if (cur == NULL) return;
203
204 if (cur->children != NULL) {
205 xmlNodePtr next, c = cur->children;
206
207 /*
208 * Cleanup all the DTD comments they are not in the DTD
209 * indexes.
210 */
211 while (c != NULL) {
212 next = c->next;
213 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
214 xmlUnlinkNode(c);
215 xmlTextReaderFreeNode(reader, c);
216 }
217 c = next;
218 }
219 }
220
221 if (cur->name != NULL) xmlFree((char *) cur->name);
222 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
223 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
224 /* TODO !!! */
225 if (cur->notations != NULL)
226 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
227
228 if (cur->elements != NULL)
229 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
230 if (cur->attributes != NULL)
231 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
232 if (cur->pentities != NULL)
233 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
234
235 if (cur->entities != NULL)
236 xmlTextReaderFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
237
238 xmlFree(cur);
239}
240
241/**
242 * xmlTextReaderFreeProp:
243 * @reader: the xmlTextReaderPtr used
244 * @cur: the node
245 *
246 * Free a node.
247 */
248static void
249xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
250 if (cur == NULL) return;
251
252 /* Check for ID removal -> leading to invalid references ! */
253 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
254 ((cur->parent->doc->intSubset != NULL) ||
255 (cur->parent->doc->extSubset != NULL))) {
256 if (xmlIsID(cur->parent->doc, cur->parent, cur))
257 xmlRemoveID(cur->parent->doc, cur);
258 }
259 if (cur->children != NULL)
260 xmlTextReaderFreeNodeList(reader, cur->children);
261
262 if ((reader != NULL) && (reader->ctxt != NULL) &&
263 (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) &&
264 (cur->name != NULL))
265 xmlFree((xmlChar *)cur->name);
266 if ((reader != NULL) && (reader->ctxt != NULL)) {
267 cur->next = reader->ctxt->freeAttrs;
268 reader->ctxt->freeAttrs = cur;
269 } else {
270 xmlFree(cur);
271 }
272}
273
274/**
275 * xmlTextReaderFreePropList:
276 * @reader: the xmlTextReaderPtr used
277 * @cur: the first property in the list
278 *
279 * Free a property and all its siblings, all the children are freed too.
280 */
281static void
282xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) {
283 xmlAttrPtr next;
284 if (cur == NULL) return;
285 while (cur != NULL) {
286 next = cur->next;
287 xmlTextReaderFreeProp(reader, cur);
288 cur = next;
289 }
290}
291
292/**
293 * xmlTextReaderFreeNodeList:
294 * @reader: the xmlTextReaderPtr used
295 * @cur: the first node in the list
296 *
297 * Free a node and all its siblings, this is a recursive behaviour, all
298 * the children are freed too.
299 */
300static void
301xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
302 xmlNodePtr next;
303 if (cur == NULL) return;
304 if (cur->type == XML_NAMESPACE_DECL) {
305 xmlFreeNsList((xmlNsPtr) cur);
306 return;
307 }
308 if ((cur->type == XML_DOCUMENT_NODE) ||
309 (cur->type == XML_HTML_DOCUMENT_NODE)) {
310 xmlFreeDoc((xmlDocPtr) cur);
311 return;
312 }
313 while (cur != NULL) {
314 next = cur->next;
315 /* unroll to speed up freeing the document */
316 if (cur->type != XML_DTD_NODE) {
317
318 if ((cur->children != NULL) &&
319 (cur->type != XML_ENTITY_REF_NODE))
320 xmlTextReaderFreeNodeList(reader, cur->children);
321 if (((cur->type == XML_ELEMENT_NODE) ||
322 (cur->type == XML_XINCLUDE_START) ||
323 (cur->type == XML_XINCLUDE_END)) &&
324 (cur->properties != NULL))
325 xmlTextReaderFreePropList(reader, cur->properties);
326 if ((cur->type != XML_ELEMENT_NODE) &&
327 (cur->type != XML_XINCLUDE_START) &&
328 (cur->type != XML_XINCLUDE_END) &&
329 (cur->type != XML_ENTITY_REF_NODE)) {
330 if (cur->content != NULL) xmlFree(cur->content);
331 }
332 if (((cur->type == XML_ELEMENT_NODE) ||
333 (cur->type == XML_XINCLUDE_START) ||
334 (cur->type == XML_XINCLUDE_END)) &&
335 (cur->nsDef != NULL))
336 xmlFreeNsList(cur->nsDef);
337
338 /*
339 * we don't free element names here they are interned now
340 */
341 if (cur->type == XML_ELEMENT_NODE) {
342 if ((reader != NULL) && (reader->ctxt != NULL) &&
343 (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) &&
344 (cur->name != NULL))
345 xmlFree((xmlChar *)cur->name);
346 } else if ((cur->type != XML_TEXT_NODE) &&
347 (cur->type != XML_COMMENT_NODE) &&
348 (cur->name != NULL))
349 xmlFree((xmlChar *)cur->name);
350 if ((cur->type == XML_ELEMENT_NODE) &&
351 (reader != NULL) && (reader->ctxt != NULL)) {
352 cur->next = reader->ctxt->freeElems;
353 reader->ctxt->freeElems = cur;
354 } else {
355 xmlFree(cur);
356 }
357 }
358 cur = next;
359 }
360}
361
362/**
363 * xmlTextReaderFreeNode:
364 * @reader: the xmlTextReaderPtr used
365 * @cur: the node
366 *
367 * Free a node, this is a recursive behaviour, all the children are freed too.
368 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
369 */
370static void
371xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) {
372 if (cur->type == XML_DTD_NODE) {
373 xmlTextReaderFreeDtd(reader, (xmlDtdPtr) cur);
374 return;
375 }
376 if (cur->type == XML_NAMESPACE_DECL) {
377 xmlFreeNs((xmlNsPtr) cur);
378 return;
379 }
380 if (cur->type == XML_ATTRIBUTE_NODE) {
381 xmlTextReaderFreeProp(reader, (xmlAttrPtr) cur);
382 return;
383 }
384
385 if ((cur->children != NULL) &&
386 (cur->type != XML_ENTITY_REF_NODE))
387 xmlTextReaderFreeNodeList(reader, cur->children);
388 if (((cur->type == XML_ELEMENT_NODE) ||
389 (cur->type == XML_XINCLUDE_START) ||
390 (cur->type == XML_XINCLUDE_END)) &&
391 (cur->properties != NULL))
392 xmlTextReaderFreePropList(reader, cur->properties);
393 if ((cur->type != XML_ELEMENT_NODE) &&
394 (cur->type != XML_XINCLUDE_START) &&
395 (cur->type != XML_XINCLUDE_END) &&
396 (cur->type != XML_ENTITY_REF_NODE)) {
397 if (cur->content != NULL) xmlFree(cur->content);
398 }
399 if (((cur->type == XML_ELEMENT_NODE) ||
400 (cur->type == XML_XINCLUDE_START) ||
401 (cur->type == XML_XINCLUDE_END)) &&
402 (cur->nsDef != NULL))
403 xmlFreeNsList(cur->nsDef);
404
405 /*
406 * we don't free names here they are interned now
407 */
408 if (cur->type == XML_ELEMENT_NODE) {
409 if ((reader != NULL) && (reader->ctxt != NULL) &&
410 (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) &&
411 (cur->name != NULL))
412 xmlFree((xmlChar *)cur->name);
413 } else if ((cur->type != XML_TEXT_NODE) &&
414 (cur->type != XML_COMMENT_NODE) &&
415 (cur->name != NULL))
416 xmlFree((xmlChar *)cur->name);
417 if ((cur->type == XML_ELEMENT_NODE) &&
418 (reader != NULL) && (reader->ctxt != NULL)) {
419 cur->next = reader->ctxt->freeElems;
420 reader->ctxt->freeElems = cur;
421 } else {
422 xmlFree(cur);
423 }
424
425}
426
427/**
428 * xmlTextReaderFreeDoc:
429 * @reader: the xmlTextReaderPtr used
430 * @cur: pointer to the document
431 *
432 * Free up all the structures used by a document, tree included.
433 */
434static void
435xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) {
436 xmlDtdPtr extSubset, intSubset;
437
438 if (cur == NULL) return;
439
440 /*
441 * Do this before freeing the children list to avoid ID lookups
442 */
443 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
444 cur->ids = NULL;
445 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
446 cur->refs = NULL;
447 extSubset = cur->extSubset;
448 intSubset = cur->intSubset;
449 if (intSubset == extSubset)
450 extSubset = NULL;
451 if (extSubset != NULL) {
452 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
453 cur->extSubset = NULL;
454 xmlTextReaderFreeDtd(reader, extSubset);
455 }
456 if (intSubset != NULL) {
457 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
458 cur->intSubset = NULL;
459 xmlTextReaderFreeDtd(reader, intSubset);
460 }
461
462 if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children);
463
464 if (cur->version != NULL) xmlFree((char *) cur->version);
465 if (cur->name != NULL) xmlFree((char *) cur->name);
466 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
467 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
468 if (cur->URL != NULL) xmlFree((char *) cur->URL);
469 xmlFree(cur);
470}
471
472/************************************************************************
473 * *
474 * The reader core parser *
475 * *
476 ************************************************************************/
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000477#ifdef DEBUG_READER
478static void
479xmlTextReaderDebug(xmlTextReaderPtr reader) {
480 if ((reader == NULL) || (reader->ctxt == NULL)) {
481 fprintf(stderr, "xmlTextReader NULL\n");
482 return;
483 }
484 fprintf(stderr, "xmlTextReader: state %d depth %d ",
485 reader->state, reader->depth);
486 if (reader->node == NULL) {
487 fprintf(stderr, "node = NULL\n");
488 } else {
489 fprintf(stderr, "node %s\n", reader->node->name);
490 }
491 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
492 reader->base, reader->cur, reader->ctxt->nodeNr);
493 if (reader->input->buffer == NULL) {
494 fprintf(stderr, "buffer is NULL\n");
495 } else {
496#ifdef LIBXML_DEBUG_ENABLED
497 xmlDebugDumpString(stderr,
498 &reader->input->buffer->content[reader->cur]);
499#endif
500 fprintf(stderr, "\n");
501 }
502}
503#endif
504
505/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000506 * xmlTextReaderEntPush:
507 * @reader: the xmlTextReaderPtr used
508 * @value: the entity reference node
509 *
510 * Pushes a new entity reference node on top of the entities stack
511 *
512 * Returns 0 in case of error, the index in the stack otherwise
513 */
514static int
515xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
516{
517 if (reader->entMax <= 0) {
518 reader->entMax = 10;
519 reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
520 sizeof(reader->entTab[0]));
521 if (reader->entTab == NULL) {
522 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
523 return (0);
524 }
525 }
526 if (reader->entNr >= reader->entMax) {
527 reader->entMax *= 2;
528 reader->entTab =
529 (xmlNodePtr *) xmlRealloc(reader->entTab,
530 reader->entMax *
531 sizeof(reader->entTab[0]));
532 if (reader->entTab == NULL) {
533 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
534 return (0);
535 }
536 }
537 reader->entTab[reader->entNr] = value;
538 reader->ent = value;
539 return (reader->entNr++);
540}
541
542/**
543 * xmlTextReaderEntPop:
544 * @reader: the xmlTextReaderPtr used
545 *
546 * Pops the top element entity from the entities stack
547 *
548 * Returns the entity just removed
549 */
550static xmlNodePtr
551xmlTextReaderEntPop(xmlTextReaderPtr reader)
552{
553 xmlNodePtr ret;
554
555 if (reader->entNr <= 0)
556 return (0);
557 reader->entNr--;
558 if (reader->entNr > 0)
559 reader->ent = reader->entTab[reader->entNr - 1];
560 else
561 reader->ent = NULL;
562 ret = reader->entTab[reader->entNr];
563 reader->entTab[reader->entNr] = 0;
564 return (ret);
565}
566
567/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000568 * xmlTextReaderStartElement:
569 * @ctx: the user data (XML parser context)
570 * @fullname: The element name, including namespace prefix
571 * @atts: An array of name/value attributes pairs, NULL terminated
572 *
573 * called when an opening tag has been processed.
574 */
575static void
576xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
577 const xmlChar **atts) {
578 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
579 xmlTextReaderPtr reader = ctxt->_private;
580
581#ifdef DEBUG_CALLBACKS
582 printf("xmlTextReaderStartElement(%s)\n", fullname);
583#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000584 if ((reader != NULL) && (reader->startElement != NULL)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000585 reader->startElement(ctx, fullname, atts);
Daniel Veillard067bae52003-01-05 01:27:54 +0000586 if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
587 (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
588 (ctxt->input->cur[1] == '>'))
589 ctxt->node->_private = (void *) xmlTextReaderIsEmpty;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000590 }
Daniel Veillard9e395c22003-01-01 14:50:44 +0000591 if (reader != NULL)
592 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000593}
594
595/**
596 * xmlTextReaderEndElement:
597 * @ctx: the user data (XML parser context)
598 * @fullname: The element name, including namespace prefix
599 *
600 * called when an ending tag has been processed.
601 */
602static void
603xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
604 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
605 xmlTextReaderPtr reader = ctxt->_private;
606
607#ifdef DEBUG_CALLBACKS
608 printf("xmlTextReaderEndElement(%s)\n", fullname);
609#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000610 if ((reader != NULL) && (reader->endElement != NULL)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000611 reader->endElement(ctx, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000612 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000613}
614
615/**
Daniel Veillard07cb8222003-09-10 10:51:05 +0000616 * xmlTextReaderStartElementNs:
617 * @ctx: the user data (XML parser context)
618 * @localname: the local name of the element
619 * @prefix: the element namespace prefix if available
620 * @URI: the element namespace name if available
621 * @nb_namespaces: number of namespace definitions on that node
622 * @namespaces: pointer to the array of prefix/URI pairs namespace definitions
623 * @nb_attributes: the number of attributes on that node
624 * nb_defaulted: the number of defaulted attributes.
625 * @attributes: pointer to the array of (localname/prefix/URI/value/end)
626 * attribute values.
627 *
628 * called when an opening tag has been processed.
629 */
630static void
631xmlTextReaderStartElementNs(void *ctx,
632 const xmlChar *localname,
633 const xmlChar *prefix,
634 const xmlChar *URI,
635 int nb_namespaces,
636 const xmlChar **namespaces,
637 int nb_attributes,
638 int nb_defaulted,
639 const xmlChar **attributes)
640{
641 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
642 xmlTextReaderPtr reader = ctxt->_private;
643
644#ifdef DEBUG_CALLBACKS
645 printf("xmlTextReaderStartElementNs(%s)\n", fullname);
646#endif
647 if ((reader != NULL) && (reader->startElementNs != NULL)) {
648 reader->startElementNs(ctx, localname, prefix, URI, nb_namespaces,
649 namespaces, nb_attributes, nb_defaulted,
650 attributes);
651 if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
652 (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
653 (ctxt->input->cur[1] == '>'))
654 ctxt->node->_private = (void *) xmlTextReaderIsEmpty;
655 }
656 if (reader != NULL)
657 reader->state = XML_TEXTREADER_ELEMENT;
658}
659
660/**
661 * xmlTextReaderEndElementNs:
662 * @ctx: the user data (XML parser context)
663 * @localname: the local name of the element
664 * @prefix: the element namespace prefix if available
665 * @URI: the element namespace name if available
666 *
667 * called when an ending tag has been processed.
668 */
669static void
670xmlTextReaderEndElementNs(void *ctx,
671 const xmlChar * localname,
672 const xmlChar * prefix,
673 const xmlChar * URI)
674{
675 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
676 xmlTextReaderPtr reader = ctxt->_private;
677
678#ifdef DEBUG_CALLBACKS
679 printf("xmlTextReaderEndElementNs(%s)\n", fullname);
680#endif
681 if ((reader != NULL) && (reader->endElementNs != NULL)) {
682 reader->endElementNs(ctx, localname, prefix, URI);
683 }
684}
685
686
687/**
Daniel Veillardea7751d2002-12-20 00:16:24 +0000688 * xmlTextReaderCharacters:
689 * @ctx: the user data (XML parser context)
690 * @ch: a xmlChar string
691 * @len: the number of xmlChar
692 *
693 * receiving some chars from the parser.
694 */
695static void
696xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
697{
698 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
699 xmlTextReaderPtr reader = ctxt->_private;
700
701#ifdef DEBUG_CALLBACKS
702 printf("xmlTextReaderCharacters()\n");
703#endif
704 if ((reader != NULL) && (reader->characters != NULL)) {
705 reader->characters(ctx, ch, len);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000706 }
707}
708
709/**
710 * xmlTextReaderCDataBlock:
711 * @ctx: the user data (XML parser context)
712 * @value: The pcdata content
713 * @len: the block length
714 *
715 * called when a pcdata block has been parsed
716 */
717static void
718xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
719{
720 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
721 xmlTextReaderPtr reader = ctxt->_private;
722
723#ifdef DEBUG_CALLBACKS
724 printf("xmlTextReaderCDataBlock()\n");
725#endif
726 if ((reader != NULL) && (reader->cdataBlock != NULL)) {
727 reader->cdataBlock(ctx, ch, len);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000728 }
729}
730
731/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000732 * xmlTextReaderPushData:
733 * @reader: the xmlTextReaderPtr used
734 *
735 * Push data down the progressive parser until a significant callback
736 * got raised.
737 *
738 * Returns -1 in case of failure, 0 otherwise
739 */
740static int
741xmlTextReaderPushData(xmlTextReaderPtr reader) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000742 xmlBufferPtr inbuf;
Daniel Veillarda880b122003-04-21 21:36:41 +0000743 int val, s;
William M. Brack779af002003-08-01 15:55:39 +0000744 xmlTextReaderState oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000745
746 if ((reader->input == NULL) || (reader->input->buffer == NULL))
747 return(-1);
748
Daniel Veillardea7751d2002-12-20 00:16:24 +0000749 oldstate = reader->state;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000750 reader->state = XML_TEXTREADER_NONE;
751 inbuf = reader->input->buffer;
Daniel Veillarda880b122003-04-21 21:36:41 +0000752
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000753 while (reader->state == XML_TEXTREADER_NONE) {
Daniel Veillarda880b122003-04-21 21:36:41 +0000754 if (inbuf->use < reader->cur + CHUNK_SIZE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000755 /*
756 * Refill the buffer unless we are at the end of the stream
757 */
758 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
759 val = xmlParserInputBufferRead(reader->input, 4096);
760 if (val <= 0) {
761 reader->mode = XML_TEXTREADER_MODE_EOF;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000762 reader->state = oldstate;
Daniel Veillardaaa105b2002-12-30 11:42:17 +0000763 if ((oldstate != XML_TEXTREADER_START) ||
764 (reader->ctxt->myDoc != NULL))
765 return(val);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000766 }
Daniel Veillarda880b122003-04-21 21:36:41 +0000767
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000768 } else
769 break;
770 }
Daniel Veillard067bae52003-01-05 01:27:54 +0000771 /*
Daniel Veillarda880b122003-04-21 21:36:41 +0000772 * parse by block of CHUNK_SIZE bytes, various tests show that
773 * it's the best tradeoff at least on a 1.2GH Duron
Daniel Veillard067bae52003-01-05 01:27:54 +0000774 */
Daniel Veillarda880b122003-04-21 21:36:41 +0000775 if (inbuf->use >= reader->cur + CHUNK_SIZE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000776 val = xmlParseChunk(reader->ctxt,
777 (const char *) &inbuf->content[reader->cur],
Daniel Veillarda880b122003-04-21 21:36:41 +0000778 CHUNK_SIZE, 0);
779 reader->cur += CHUNK_SIZE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000780 if (val != 0)
781 return(-1);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000782 } else {
Daniel Veillarda880b122003-04-21 21:36:41 +0000783 s = inbuf->use - reader->cur;
784 val = xmlParseChunk(reader->ctxt,
785 (const char *) &inbuf->content[reader->cur],
786 s, 0);
787 reader->cur += s;
788 if (val != 0)
789 return(-1);
790 break;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000791 }
792 }
Daniel Veillarda880b122003-04-21 21:36:41 +0000793
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000794 /*
795 * Discard the consumed input when needed and possible
796 */
Daniel Veillard67df8092002-12-16 22:04:11 +0000797 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
Daniel Veillarda880b122003-04-21 21:36:41 +0000798 if (reader->cur >= 4096) {
799 val = xmlBufferShrink(inbuf, reader->cur);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000800 if (val >= 0) {
801 reader->cur -= val;
802 }
803 }
804 }
805
806 /*
807 * At the end of the stream signal that the work is done to the Push
808 * parser.
809 */
Daniel Veillarda880b122003-04-21 21:36:41 +0000810 else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000811 if (reader->mode != XML_TEXTREADER_DONE) {
Daniel Veillarda880b122003-04-21 21:36:41 +0000812 s = inbuf->use - reader->cur;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000813 val = xmlParseChunk(reader->ctxt,
Daniel Veillard067bae52003-01-05 01:27:54 +0000814 (const char *) &inbuf->content[reader->cur],
Daniel Veillarda880b122003-04-21 21:36:41 +0000815 s, 1);
816 reader->cur = inbuf->use;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000817 reader->mode = XML_TEXTREADER_DONE;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000818 if (val != 0) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000819 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000820 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000821 reader->state = oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000822 return(0);
823}
824
825/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000826 * xmlTextReaderValidatePush:
827 * @reader: the xmlTextReaderPtr used
828 *
829 * Push the current node for validation
830 */
831static void
832xmlTextReaderValidatePush(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000833#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000834 xmlNodePtr node = reader->node;
835
Daniel Veillardf4e55762003-04-15 23:32:22 +0000836 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
837 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
838 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
839 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
840 reader->ctxt->myDoc, node, node->name);
841 } else {
842 /* TODO use the BuildQName interface */
843 xmlChar *qname;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000844
Daniel Veillardf4e55762003-04-15 23:32:22 +0000845 qname = xmlStrdup(node->ns->prefix);
846 qname = xmlStrcat(qname, BAD_CAST ":");
847 qname = xmlStrcat(qname, node->name);
848 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
849 reader->ctxt->myDoc, node, qname);
850 if (qname != NULL)
851 xmlFree(qname);
852 }
853#ifdef LIBXML_SCHEMAS_ENABLED
854 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
855 (reader->rngValidCtxt != NULL)) {
856 int ret;
857
858 if (reader->rngFullNode != NULL) return;
859 ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
860 reader->ctxt->myDoc,
861 node);
862 if (ret == 0) {
863 /*
864 * this element requires a full tree
865 */
866 node = xmlTextReaderExpand(reader);
867 if (node == NULL) {
868printf("Expand failed !\n");
869 ret = -1;
870 } else {
871 ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt,
872 reader->ctxt->myDoc,
873 node);
874 reader->rngFullNode = node;
875 }
876 }
877 if (ret != 1)
878 reader->rngValidErrors++;
879#endif
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000880 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000881#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000882}
Daniel Veillardf4e55762003-04-15 23:32:22 +0000883
884/**
885 * xmlTextReaderValidateCData:
886 * @reader: the xmlTextReaderPtr used
887 * @data: pointer to the CData
888 * @len: lenght of the CData block in bytes.
889 *
890 * Push some CData for validation
891 */
892static void
893xmlTextReaderValidateCData(xmlTextReaderPtr reader,
894 const xmlChar *data, int len) {
895#ifdef LIBXML_REGEXP_ENABLED
896 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
897 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
898 reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt,
899 data, len);
900#ifdef LIBXML_SCHEMAS_ENABLED
901 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
902 (reader->rngValidCtxt != NULL)) {
903 int ret;
904
905 if (reader->rngFullNode != NULL) return;
906 ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len);
907 if (ret != 1)
908 reader->rngValidErrors++;
909#endif
910 }
911#endif /* LIBXML_REGEXP_ENABLED */
912}
913
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000914/**
915 * xmlTextReaderValidatePop:
916 * @reader: the xmlTextReaderPtr used
917 *
918 * Pop the current node from validation
919 */
920static void
921xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000922#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000923 xmlNodePtr node = reader->node;
924
Daniel Veillardf4e55762003-04-15 23:32:22 +0000925 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
926 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
927 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
928 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
929 reader->ctxt->myDoc, node, node->name);
930 } else {
931 /* TODO use the BuildQName interface */
932 xmlChar *qname;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000933
Daniel Veillardf4e55762003-04-15 23:32:22 +0000934 qname = xmlStrdup(node->ns->prefix);
935 qname = xmlStrcat(qname, BAD_CAST ":");
936 qname = xmlStrcat(qname, node->name);
937 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
938 reader->ctxt->myDoc, node, qname);
939 if (qname != NULL)
940 xmlFree(qname);
941 }
942#ifdef LIBXML_SCHEMAS_ENABLED
943 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
944 (reader->rngValidCtxt != NULL)) {
945 int ret;
946
947 if (reader->rngFullNode != NULL) {
948 if (node == reader->rngFullNode)
949 reader->rngFullNode = NULL;
950 return;
951 }
952 ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
953 reader->ctxt->myDoc,
954 node);
955 if (ret != 1)
956 reader->rngValidErrors++;
957#endif
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000958 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000959#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000960}
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000961/**
962 * xmlTextReaderValidateEntity:
963 * @reader: the xmlTextReaderPtr used
964 *
965 * Handle the validation when an entity reference is encountered and
966 * entity substitution is not activated. As a result the parser interface
967 * must walk through the entity and do the validation calls
968 */
969static void
970xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000971#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000972 xmlNodePtr oldnode = reader->node;
973 xmlNodePtr node = reader->node;
974 xmlParserCtxtPtr ctxt = reader->ctxt;
975
976 do {
977 if (node->type == XML_ENTITY_REF_NODE) {
978 /*
979 * Case where the underlying tree is not availble, lookup the entity
980 * and walk it.
981 */
982 if ((node->children == NULL) && (ctxt->sax != NULL) &&
983 (ctxt->sax->getEntity != NULL)) {
984 node->children = (xmlNodePtr)
985 ctxt->sax->getEntity(ctxt, node->name);
986 }
987
988 if ((node->children != NULL) &&
989 (node->children->type == XML_ENTITY_DECL) &&
990 (node->children->children != NULL)) {
991 xmlTextReaderEntPush(reader, node);
992 node = node->children->children;
993 continue;
994 } else {
995 /*
996 * The error has probably be raised already.
997 */
998 if (node == oldnode)
999 break;
1000 node = node->next;
1001 }
1002 } else if (node->type == XML_ELEMENT_NODE) {
1003 reader->node = node;
1004 xmlTextReaderValidatePush(reader);
1005 } else if ((node->type == XML_TEXT_NODE) ||
1006 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00001007 xmlTextReaderValidateCData(reader, node->content,
1008 xmlStrlen(node->content));
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001009 }
1010
1011 /*
1012 * go to next node
1013 */
1014 if (node->children != NULL) {
1015 node = node->children;
1016 continue;
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00001017 } else if (node->type == XML_ELEMENT_NODE) {
1018 xmlTextReaderValidatePop(reader);
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001019 }
1020 if (node->next != NULL) {
1021 node = node->next;
1022 continue;
1023 }
1024 do {
1025 node = node->parent;
1026 if (node->type == XML_ELEMENT_NODE) {
1027 reader->node = node;
1028 xmlTextReaderValidatePop(reader);
1029 }
1030 if ((node->type == XML_ENTITY_DECL) &&
1031 (reader->ent != NULL) && (reader->ent->children == node)) {
1032 node = xmlTextReaderEntPop(reader);
1033 }
1034 if (node == oldnode)
1035 break;
1036 if (node->next != NULL) {
1037 node = node->next;
1038 break;
1039 }
1040 } while ((node != NULL) && (node != oldnode));
1041 } while ((node != NULL) && (node != oldnode));
1042 reader->node = oldnode;
Daniel Veillard0e298ad2003-02-04 16:14:33 +00001043#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001044}
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001045
1046
1047/**
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001048 * xmlTextReaderGetSuccessor:
1049 * @cur: the current node
1050 *
1051 * Get the successor of a node if available.
1052 *
1053 * Returns the successor node or NULL
1054 */
1055static xmlNodePtr
1056xmlTextReaderGetSuccessor(xmlNodePtr cur) {
1057 if (cur == NULL) return(NULL) ; /* ERROR */
1058 if (cur->next != NULL) return(cur->next) ;
1059 do {
1060 cur = cur->parent;
1061 if (cur == NULL) return(NULL);
1062 if (cur->next != NULL) return(cur->next);
1063 } while (cur != NULL);
1064 return(cur);
1065}
1066
1067/**
1068 * xmlTextReaderDoExpand:
1069 * @reader: the xmlTextReaderPtr used
1070 *
1071 * Makes sure that the current node is fully read as well as all its
1072 * descendant. It means the full DOM subtree must be available at the
1073 * end of the call.
1074 *
1075 * Returns 1 if the node was expanded successfully, 0 if there is no more
1076 * nodes to read, or -1 in case of error
1077 */
1078static int
1079xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
1080 int val;
1081
1082 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
1083 return(-1);
1084
1085 do {
1086 if (xmlTextReaderGetSuccessor(reader->node) != NULL)
1087 return(1);
Daniel Veillarda37aab82003-06-09 09:10:36 +00001088 if (reader->ctxt->nodeNr <= reader->depth)
1089 return(1);
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001090 if (reader->mode == XML_TEXTREADER_MODE_EOF)
1091 return(1);
1092 val = xmlTextReaderPushData(reader);
1093 if (val < 0)
1094 return(-1);
1095 } while(reader->mode != XML_TEXTREADER_MODE_EOF);
1096 return(1);
1097}
1098
1099/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001100 * xmlTextReaderRead:
1101 * @reader: the xmlTextReaderPtr used
1102 *
1103 * Moves the position of the current instance to the next node in
1104 * the stream, exposing its properties.
1105 *
1106 * Returns 1 if the node was read successfully, 0 if there is no more
1107 * nodes to read, or -1 in case of error
1108 */
1109int
1110xmlTextReaderRead(xmlTextReaderPtr reader) {
Daniel Veillard067bae52003-01-05 01:27:54 +00001111 int val, olddepth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001112 xmlTextReaderState oldstate = 0;
1113 xmlNodePtr oldnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001114
1115 if ((reader == NULL) || (reader->ctxt == NULL))
1116 return(-1);
1117 if (reader->ctxt->wellFormed != 1)
1118 return(-1);
1119
1120#ifdef DEBUG_READER
1121 fprintf(stderr, "\nREAD ");
1122 DUMP_READER
1123#endif
Daniel Veillard29b3e282002-12-29 11:14:41 +00001124 reader->curnode = NULL;
Daniel Veillard67df8092002-12-16 22:04:11 +00001125 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
1126 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001127 /*
1128 * Initial state
1129 */
1130 do {
1131 val = xmlTextReaderPushData(reader);
1132 if (val < 0)
1133 return(-1);
1134 } while ((reader->ctxt->node == NULL) &&
Daniel Veillard067bae52003-01-05 01:27:54 +00001135 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
1136 (reader->mode != XML_TEXTREADER_DONE)));
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001137 if (reader->ctxt->myDoc != NULL)
1138 reader->ctxt->myDoc->_private = reader;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001139 if (reader->ctxt->node == NULL) {
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001140 if (reader->ctxt->myDoc != NULL) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001141 reader->node = reader->ctxt->myDoc->children;
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001142 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001143 if (reader->node == NULL)
1144 return(-1);
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001145 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001146 } else {
Daniel Veillard48ef4c92003-03-22 12:38:15 +00001147 if (reader->ctxt->myDoc != NULL) {
1148 reader->node = reader->ctxt->myDoc->children;
1149 }
1150 if (reader->node == NULL)
1151 reader->node = reader->ctxt->nodeTab[0];
Daniel Veillarde59494f2003-01-04 16:35:29 +00001152 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001153 }
Daniel Veillard4d8db8a2002-12-30 18:40:42 +00001154 reader->depth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001155 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001156 }
1157 oldstate = reader->state;
1158 olddepth = reader->ctxt->nodeNr;
1159 oldnode = reader->node;
Daniel Veillarddf512f42002-12-23 15:56:21 +00001160
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001161get_next_node:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001162 /*
1163 * If we are not backtracking on ancestors or examined nodes,
1164 * that the parser didn't finished or that we arent at the end
1165 * of stream, continue processing.
1166 */
Daniel Veillarda880b122003-04-21 21:36:41 +00001167 while ((reader->node->next == NULL) &&
1168 (reader->ctxt->nodeNr == olddepth) &&
1169 ((oldstate == XML_TEXTREADER_BACKTRACK) ||
Daniel Veillardea7751d2002-12-20 00:16:24 +00001170 (reader->node->children == NULL) ||
1171 (reader->node->type == XML_ENTITY_REF_NODE) ||
Daniel Veillard409a8142003-07-18 15:16:57 +00001172 ((reader->node->children != NULL) &&
1173 (reader->node->children->type == XML_TEXT_NODE) &&
1174 (reader->node->children->next == NULL)) ||
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00001175 (reader->node->type == XML_DTD_NODE) ||
1176 (reader->node->type == XML_DOCUMENT_NODE) ||
1177 (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00001178 ((reader->ctxt->node == NULL) ||
1179 (reader->ctxt->node == reader->node) ||
1180 (reader->ctxt->node == reader->node->parent)) &&
Daniel Veillardea7751d2002-12-20 00:16:24 +00001181 (reader->ctxt->instate != XML_PARSER_EOF)) {
1182 val = xmlTextReaderPushData(reader);
1183 if (val < 0)
1184 return(-1);
1185 if (reader->node == NULL)
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001186 goto node_end;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001187 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001188 if (oldstate != XML_TEXTREADER_BACKTRACK) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001189 if ((reader->node->children != NULL) &&
1190 (reader->node->type != XML_ENTITY_REF_NODE) &&
1191 (reader->node->type != XML_DTD_NODE)) {
1192 reader->node = reader->node->children;
1193 reader->depth++;
Daniel Veillarddf512f42002-12-23 15:56:21 +00001194 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001195 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001196 }
1197 }
1198 if (reader->node->next != NULL) {
1199 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillarddf512f42002-12-23 15:56:21 +00001200 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +00001201 (reader->node->children == NULL) &&
1202 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001203 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001204 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001205 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00001206 if ((reader->validate) &&
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001207 (reader->node->type == XML_ELEMENT_NODE))
1208 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001209 reader->node = reader->node->next;
1210 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001211
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001212 /*
1213 * Cleanup of the old node
1214 */
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00001215 if ((reader->node->prev != NULL) &&
1216 (reader->node->prev->type != XML_DTD_NODE)) {
1217 xmlNodePtr tmp = reader->node->prev;
1218 xmlUnlinkNode(tmp);
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001219 xmlTextReaderFreeNode(reader, tmp);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001220 }
1221
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001222 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001223 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00001224 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillard571b8892002-12-30 12:37:59 +00001225 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +00001226 (reader->node->children == NULL) &&
1227 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00001228 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001229 goto node_found;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001230 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00001231 if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE))
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001232 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001233 reader->node = reader->node->parent;
1234 if ((reader->node == NULL) ||
1235 (reader->node->type == XML_DOCUMENT_NODE) ||
1236#ifdef LIBXML_DOCB_ENABLED
1237 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
1238#endif
1239 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00001240 if (reader->mode != XML_TEXTREADER_DONE) {
1241 val = xmlParseChunk(reader->ctxt, "", 0, 1);
1242 reader->mode = XML_TEXTREADER_DONE;
1243 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001244 reader->node = NULL;
Daniel Veillard4d8db8a2002-12-30 18:40:42 +00001245 reader->depth = -1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001246
1247 /*
1248 * Cleanup of the old node
1249 */
1250 if (oldnode->type != XML_DTD_NODE) {
1251 xmlUnlinkNode(oldnode);
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001252 xmlTextReaderFreeNode(reader, oldnode);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001253 }
1254
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001255 goto node_end;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001256 }
1257 reader->depth--;
1258 reader->state = XML_TEXTREADER_BACKTRACK;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001259
1260node_found:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001261 DUMP_READER
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001262
1263 /*
Daniel Veillarda880b122003-04-21 21:36:41 +00001264 * If we are in the middle of a piece of CDATA make sure it's finished
1265 */
1266 if ((reader->node != NULL) &&
1267 ((reader->node->type == XML_TEXT_NODE) ||
1268 (reader->node->type == XML_CDATA_SECTION_NODE))) {
1269 xmlTextReaderExpand(reader);
1270 }
1271
1272 /*
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001273 * Handle entities enter and exit when in entity replacement mode
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001274 */
1275 if ((reader->node != NULL) &&
1276 (reader->node->type == XML_ENTITY_REF_NODE) &&
1277 (reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
1278 /*
1279 * Case where the underlying tree is not availble, lookup the entity
1280 * and walk it.
1281 */
1282 if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
1283 (reader->ctxt->sax->getEntity != NULL)) {
1284 reader->node->children = (xmlNodePtr)
1285 reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
1286 }
1287
1288 if ((reader->node->children != NULL) &&
1289 (reader->node->children->type == XML_ENTITY_DECL) &&
1290 (reader->node->children->children != NULL)) {
1291 xmlTextReaderEntPush(reader, reader->node);
1292 reader->node = reader->node->children->children;
1293 }
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001294 } else if ((reader->node != NULL) &&
1295 (reader->node->type == XML_ENTITY_REF_NODE) &&
Daniel Veillardf4e55762003-04-15 23:32:22 +00001296 (reader->ctxt != NULL) && (reader->validate)) {
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001297 xmlTextReaderValidateEntity(reader);
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001298 }
1299 if ((reader->node != NULL) &&
1300 (reader->node->type == XML_ENTITY_DECL) &&
1301 (reader->ent != NULL) && (reader->ent->children == reader->node)) {
1302 reader->node = xmlTextReaderEntPop(reader);
1303 reader->depth++;
1304 goto get_next_node;
1305 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +00001306#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardf4e55762003-04-15 23:32:22 +00001307 if ((reader->validate) && (reader->node != NULL)) {
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001308 xmlNodePtr node = reader->node;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001309
1310 if ((node->type == XML_ELEMENT_NODE) &&
1311 ((reader->state != XML_TEXTREADER_END) &&
1312 (reader->state != XML_TEXTREADER_BACKTRACK))) {
1313 xmlTextReaderValidatePush(reader);
1314 } else if ((node->type == XML_TEXT_NODE) ||
1315 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00001316 xmlTextReaderValidateCData(reader, node->content,
1317 xmlStrlen(node->content));
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001318 }
1319 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +00001320#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001321 return(1);
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001322node_end:
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001323 reader->mode = XML_TEXTREADER_DONE;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001324 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001325}
1326
Daniel Veillard67df8092002-12-16 22:04:11 +00001327/**
1328 * xmlTextReaderReadState:
1329 * @reader: the xmlTextReaderPtr used
1330 *
1331 * Gets the read state of the reader.
1332 *
1333 * Returns the state value, or -1 in case of error
1334 */
1335int
1336xmlTextReaderReadState(xmlTextReaderPtr reader) {
1337 if (reader == NULL)
1338 return(-1);
1339 return(reader->mode);
1340}
1341
1342/**
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001343 * xmlTextReaderExpand:
1344 * @reader: the xmlTextReaderPtr used
1345 *
1346 * Reads the contents of the current node and the full subtree. It then makes
Daniel Veillard61c52202003-04-30 12:20:34 +00001347 * the subtree available until the next xmlTextReaderRead() call
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001348 *
1349 * Returns a node pointer valid until the next xmlTextReaderRead() call
1350 * or NULL in case of error.
1351 */
1352xmlNodePtr
1353xmlTextReaderExpand(xmlTextReaderPtr reader) {
1354 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
1355 return(NULL);
1356 if (xmlTextReaderDoExpand(reader) < 0)
1357 return(NULL);
1358 return(reader->node);
1359}
1360
1361/**
1362 * xmlTextReaderNext:
1363 * @reader: the xmlTextReaderPtr used
1364 *
1365 * Skip to the node following the current one in document order while
1366 * avoiding the subtree if any.
1367 *
1368 * Returns 1 if the node was read successfully, 0 if there is no more
1369 * nodes to read, or -1 in case of error
1370 */
1371int
1372xmlTextReaderNext(xmlTextReaderPtr reader) {
1373 int ret;
1374 xmlNodePtr cur;
1375
1376 if (reader == NULL)
1377 return(-1);
1378 cur = reader->node;
1379 if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
1380 return(xmlTextReaderRead(reader));
1381 if (reader->state == XML_TEXTREADER_END)
1382 return(xmlTextReaderRead(reader));
1383 if (cur->_private == (void *)xmlTextReaderIsEmpty)
1384 return(xmlTextReaderRead(reader));
1385 do {
1386 ret = xmlTextReaderRead(reader);
1387 if (ret != 1)
1388 return(ret);
1389 } while (reader->node != cur);
1390 return(xmlTextReaderRead(reader));
1391}
1392
1393/**
Daniel Veillard67df8092002-12-16 22:04:11 +00001394 * xmlTextReaderReadInnerXml:
1395 * @reader: the xmlTextReaderPtr used
1396 *
1397 * Reads the contents of the current node, including child nodes and markup.
1398 *
1399 * Returns a string containing the XML content, or NULL if the current node
1400 * is neither an element nor attribute, or has no child nodes. The
1401 * string must be deallocated by the caller.
1402 */
1403xmlChar *
Daniel Veillard33300b42003-04-17 09:09:19 +00001404xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
Daniel Veillard67df8092002-12-16 22:04:11 +00001405 TODO
1406 return(NULL);
1407}
1408
1409/**
1410 * xmlTextReaderReadOuterXml:
1411 * @reader: the xmlTextReaderPtr used
1412 *
1413 * Reads the contents of the current node, including child nodes and markup.
1414 *
1415 * Returns a string containing the XML content, or NULL if the current node
1416 * is neither an element nor attribute, or has no child nodes. The
1417 * string must be deallocated by the caller.
1418 */
1419xmlChar *
Daniel Veillard33300b42003-04-17 09:09:19 +00001420xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
Daniel Veillard67df8092002-12-16 22:04:11 +00001421 TODO
1422 return(NULL);
1423}
1424
1425/**
1426 * xmlTextReaderReadString:
1427 * @reader: the xmlTextReaderPtr used
1428 *
1429 * Reads the contents of an element or a text node as a string.
1430 *
1431 * Returns a string containing the contents of the Element or Text node,
1432 * or NULL if the reader is positioned on any other type of node.
1433 * The string must be deallocated by the caller.
1434 */
1435xmlChar *
Daniel Veillard33300b42003-04-17 09:09:19 +00001436xmlTextReaderReadString(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
Daniel Veillard67df8092002-12-16 22:04:11 +00001437 TODO
1438 return(NULL);
1439}
1440
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001441#if 0
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001442/**
1443 * xmlTextReaderReadBase64:
1444 * @reader: the xmlTextReaderPtr used
1445 * @array: a byte array to store the content.
1446 * @offset: the zero-based index into array where the method should
1447 * begin to write.
1448 * @len: the number of bytes to write.
1449 *
1450 * Reads and decodes the Base64 encoded contents of an element and
1451 * stores the result in a byte buffer.
1452 *
1453 * Returns the number of bytes written to array, or zero if the current
1454 * instance is not positioned on an element or -1 in case of error.
1455 */
1456int
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001457xmlTextReaderReadBase64(xmlTextReaderPtr reader,
1458 unsigned char *array ATTRIBUTE_UNUSED,
1459 int offset ATTRIBUTE_UNUSED,
1460 int len ATTRIBUTE_UNUSED) {
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001461 if ((reader == NULL) || (reader->ctxt == NULL))
1462 return(-1);
1463 if (reader->ctxt->wellFormed != 1)
1464 return(-1);
1465
1466 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1467 return(0);
1468 TODO
1469 return(0);
1470}
1471
1472/**
1473 * xmlTextReaderReadBinHex:
1474 * @reader: the xmlTextReaderPtr used
1475 * @array: a byte array to store the content.
1476 * @offset: the zero-based index into array where the method should
1477 * begin to write.
1478 * @len: the number of bytes to write.
1479 *
1480 * Reads and decodes the BinHex encoded contents of an element and
1481 * stores the result in a byte buffer.
1482 *
1483 * Returns the number of bytes written to array, or zero if the current
1484 * instance is not positioned on an element or -1 in case of error.
1485 */
1486int
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001487xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
1488 unsigned char *array ATTRIBUTE_UNUSED,
1489 int offset ATTRIBUTE_UNUSED,
1490 int len ATTRIBUTE_UNUSED) {
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001491 if ((reader == NULL) || (reader->ctxt == NULL))
1492 return(-1);
1493 if (reader->ctxt->wellFormed != 1)
1494 return(-1);
1495
1496 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1497 return(0);
1498 TODO
1499 return(0);
1500}
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001501#endif
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001502
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001503/************************************************************************
1504 * *
1505 * Constructor and destructors *
1506 * *
1507 ************************************************************************/
1508/**
1509 * xmlNewTextReader:
1510 * @input: the xmlParserInputBufferPtr used to read data
Daniel Veillardea7751d2002-12-20 00:16:24 +00001511 * @URI: the URI information for the source if available
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001512 *
1513 * Create an xmlTextReader structure fed with @input
1514 *
1515 * Returns the new xmlTextReaderPtr or NULL in case of error
1516 */
1517xmlTextReaderPtr
Daniel Veillardea7751d2002-12-20 00:16:24 +00001518xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001519 xmlTextReaderPtr ret;
1520 int val;
1521
1522 if (input == NULL)
1523 return(NULL);
1524 ret = xmlMalloc(sizeof(xmlTextReader));
1525 if (ret == NULL) {
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlNewTextReader : malloc failed\n");
1528 return(NULL);
1529 }
1530 memset(ret, 0, sizeof(xmlTextReader));
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001531 ret->entTab = NULL;
1532 ret->entMax = 0;
1533 ret->entNr = 0;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001534 ret->input = input;
1535 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
1536 if (ret->sax == NULL) {
1537 xmlFree(ret);
1538 xmlGenericError(xmlGenericErrorContext,
1539 "xmlNewTextReader : malloc failed\n");
1540 return(NULL);
1541 }
1542 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
1543 ret->startElement = ret->sax->startElement;
1544 ret->sax->startElement = xmlTextReaderStartElement;
1545 ret->endElement = ret->sax->endElement;
1546 ret->sax->endElement = xmlTextReaderEndElement;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001547 if (ret->sax->initialized == XML_SAX2_MAGIC) {
1548 ret->startElementNs = ret->sax->startElementNs;
1549 ret->sax->startElementNs = xmlTextReaderStartElementNs;
1550 ret->endElementNs = ret->sax->endElementNs;
1551 ret->sax->endElementNs = xmlTextReaderEndElementNs;
1552 } else {
1553 ret->startElementNs = NULL;
1554 ret->endElementNs = NULL;
1555 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00001556 ret->characters = ret->sax->characters;
1557 ret->sax->characters = xmlTextReaderCharacters;
Daniel Veillard40412cd2003-09-03 13:28:32 +00001558 ret->sax->ignorableWhitespace = xmlTextReaderCharacters;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001559 ret->cdataBlock = ret->sax->cdataBlock;
1560 ret->sax->cdataBlock = xmlTextReaderCDataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001561
Daniel Veillard67df8092002-12-16 22:04:11 +00001562 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001563 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001564 ret->curnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001565 val = xmlParserInputBufferRead(input, 4);
1566 if (val >= 4) {
1567 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
Daniel Veillardea7751d2002-12-20 00:16:24 +00001568 (const char *) ret->input->buffer->content, 4, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001569 ret->base = 0;
1570 ret->cur = 4;
1571 } else {
Daniel Veillardea7751d2002-12-20 00:16:24 +00001572 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001573 ret->base = 0;
1574 ret->cur = 0;
1575 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001576 if (ret->ctxt == NULL) {
1577 xmlGenericError(xmlGenericErrorContext,
1578 "xmlNewTextReader : malloc failed\n");
1579 xmlFree(ret->sax);
1580 xmlFree(ret);
1581 return(NULL);
1582 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001583 ret->ctxt->_private = ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001584 ret->ctxt->linenumbers = 1;
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001585 ret->ctxt->dictNames = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001586 ret->allocs = XML_TEXTREADER_CTXT;
Daniel Veillard40412cd2003-09-03 13:28:32 +00001587 /*
1588 * use the parser dictionnary to allocate all elements and attributes names
1589 */
1590 ret->ctxt->docdict = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001591 return(ret);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001592}
1593
1594/**
1595 * xmlNewTextReaderFilename:
1596 * @URI: the URI of the resource to process
1597 *
1598 * Create an xmlTextReader structure fed with the resource at @URI
1599 *
1600 * Returns the new xmlTextReaderPtr or NULL in case of error
1601 */
1602xmlTextReaderPtr
1603xmlNewTextReaderFilename(const char *URI) {
1604 xmlParserInputBufferPtr input;
1605 xmlTextReaderPtr ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001606 char *directory = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001607
1608 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
1609 if (input == NULL)
1610 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00001611 ret = xmlNewTextReader(input, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001612 if (ret == NULL) {
1613 xmlFreeParserInputBuffer(input);
1614 return(NULL);
1615 }
1616 ret->allocs |= XML_TEXTREADER_INPUT;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001617 if (ret->ctxt->directory == NULL)
1618 directory = xmlParserGetDirectory(URI);
1619 if ((ret->ctxt->directory == NULL) && (directory != NULL))
1620 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
1621 if (directory != NULL)
1622 xmlFree(directory);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001623 return(ret);
1624}
1625
1626/**
1627 * xmlFreeTextReader:
1628 * @reader: the xmlTextReaderPtr
1629 *
1630 * Deallocate all the resources associated to the reader
1631 */
1632void
1633xmlFreeTextReader(xmlTextReaderPtr reader) {
1634 if (reader == NULL)
1635 return;
Daniel Veillard37fc84d2003-05-09 19:38:15 +00001636#ifdef LIBXML_SCHEMAS_ENABLED
Daniel Veillardf4e55762003-04-15 23:32:22 +00001637 if (reader->rngSchemas != NULL) {
1638 xmlRelaxNGFree(reader->rngSchemas);
1639 reader->rngSchemas = NULL;
1640 }
1641 if (reader->rngValidCtxt != NULL) {
1642 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
1643 reader->rngValidCtxt = NULL;
1644 }
Daniel Veillard37fc84d2003-05-09 19:38:15 +00001645#endif
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001646 if (reader->ctxt != NULL) {
1647 if (reader->ctxt->myDoc != NULL) {
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001648 xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001649 reader->ctxt->myDoc = NULL;
1650 }
Daniel Veillard336fc7d2002-12-27 19:37:04 +00001651 if ((reader->ctxt->vctxt.vstateTab != NULL) &&
1652 (reader->ctxt->vctxt.vstateMax > 0)){
1653 xmlFree(reader->ctxt->vctxt.vstateTab);
1654 reader->ctxt->vctxt.vstateTab = 0;
1655 reader->ctxt->vctxt.vstateMax = 0;
1656 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001657 if (reader->allocs & XML_TEXTREADER_CTXT)
1658 xmlFreeParserCtxt(reader->ctxt);
1659 }
1660 if (reader->sax != NULL)
1661 xmlFree(reader->sax);
1662 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
1663 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001664 if (reader->faketext != NULL) {
1665 xmlFreeNode(reader->faketext);
1666 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001667 if (reader->entTab != NULL)
1668 xmlFree(reader->entTab);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001669 xmlFree(reader);
1670}
1671
1672/************************************************************************
1673 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001674 * Methods for XmlTextReader *
1675 * *
1676 ************************************************************************/
1677/**
1678 * xmlTextReaderClose:
1679 * @reader: the xmlTextReaderPtr used
1680 *
1681 * This method releases any resources allocated by the current instance
1682 * changes the state to Closed and close any underlying input.
1683 *
1684 * Returns 0 or -1 in case of error
1685 */
1686int
1687xmlTextReaderClose(xmlTextReaderPtr reader) {
1688 if (reader == NULL)
1689 return(-1);
1690 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001691 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001692 reader->mode = XML_TEXTREADER_MODE_CLOSED;
1693 if (reader->ctxt != NULL) {
1694 if (reader->ctxt->myDoc != NULL) {
1695 xmlFreeDoc(reader->ctxt->myDoc);
1696 reader->ctxt->myDoc = NULL;
1697 }
1698 if (reader->allocs & XML_TEXTREADER_CTXT) {
1699 xmlFreeParserCtxt(reader->ctxt);
1700 reader->allocs -= XML_TEXTREADER_CTXT;
1701 }
1702 }
1703 if (reader->sax != NULL) {
1704 xmlFree(reader->sax);
1705 reader->sax = NULL;
1706 }
1707 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
1708 xmlFreeParserInputBuffer(reader->input);
1709 reader->allocs -= XML_TEXTREADER_INPUT;
1710 }
1711 return(0);
1712}
1713
1714/**
1715 * xmlTextReaderGetAttributeNo:
1716 * @reader: the xmlTextReaderPtr used
1717 * @no: the zero-based index of the attribute relative to the containing element
1718 *
1719 * Provides the value of the attribute with the specified index relative
1720 * to the containing element.
1721 *
1722 * Returns a string containing the value of the specified attribute, or NULL
1723 * in case of error. The string must be deallocated by the caller.
1724 */
1725xmlChar *
1726xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
1727 xmlChar *ret;
1728 int i;
1729 xmlAttrPtr cur;
1730 xmlNsPtr ns;
1731
1732 if (reader == NULL)
1733 return(NULL);
1734 if (reader->node == NULL)
1735 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001736 if (reader->curnode != NULL)
1737 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001738 /* TODO: handle the xmlDecl */
1739 if (reader->node->type != XML_ELEMENT_NODE)
1740 return(NULL);
1741
1742 ns = reader->node->nsDef;
1743 for (i = 0;(i < no) && (ns != NULL);i++) {
1744 ns = ns->next;
1745 }
1746 if (ns != NULL)
1747 return(xmlStrdup(ns->href));
1748
1749 cur = reader->node->properties;
1750 if (cur == NULL)
1751 return(NULL);
1752 for (;i < no;i++) {
1753 cur = cur->next;
1754 if (cur == NULL)
1755 return(NULL);
1756 }
1757 /* TODO walk the DTD if present */
1758
1759 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
1760 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
1761 return(ret);
1762}
1763
1764/**
1765 * xmlTextReaderGetAttribute:
1766 * @reader: the xmlTextReaderPtr used
1767 * @name: the qualified name of the attribute.
1768 *
1769 * Provides the value of the attribute with the specified qualified name.
1770 *
1771 * Returns a string containing the value of the specified attribute, or NULL
1772 * in case of error. The string must be deallocated by the caller.
1773 */
1774xmlChar *
1775xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1776 xmlChar *prefix = NULL;
1777 xmlChar *localname;
1778 xmlNsPtr ns;
1779 xmlChar *ret = NULL;
1780
1781 if ((reader == NULL) || (name == NULL))
1782 return(NULL);
1783 if (reader->node == NULL)
1784 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001785 if (reader->curnode != NULL)
1786 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001787
1788 /* TODO: handle the xmlDecl */
1789 if (reader->node->type != XML_ELEMENT_NODE)
1790 return(NULL);
1791
1792 localname = xmlSplitQName2(name, &prefix);
1793 if (localname == NULL)
1794 return(xmlGetProp(reader->node, name));
1795
1796 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1797 if (ns != NULL)
1798 ret = xmlGetNsProp(reader->node, localname, ns->href);
1799
1800 if (localname != NULL)
1801 xmlFree(localname);
1802 if (prefix != NULL)
1803 xmlFree(prefix);
1804 return(ret);
1805}
1806
1807
1808/**
1809 * xmlTextReaderGetAttributeNs:
1810 * @reader: the xmlTextReaderPtr used
1811 * @localName: the local name of the attribute.
1812 * @namespaceURI: the namespace URI of the attribute.
1813 *
1814 * Provides the value of the specified attribute
1815 *
1816 * Returns a string containing the value of the specified attribute, or NULL
1817 * in case of error. The string must be deallocated by the caller.
1818 */
1819xmlChar *
1820xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
1821 const xmlChar *namespaceURI) {
1822 if ((reader == NULL) || (localName == NULL))
1823 return(NULL);
1824 if (reader->node == NULL)
1825 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001826 if (reader->curnode != NULL)
1827 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001828
1829 /* TODO: handle the xmlDecl */
1830 if (reader->node->type != XML_ELEMENT_NODE)
1831 return(NULL);
1832
1833 return(xmlGetNsProp(reader->node, localName, namespaceURI));
1834}
1835
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001836/**
1837 * xmlTextReaderGetRemainder:
1838 * @reader: the xmlTextReaderPtr used
1839 *
1840 * Method to get the remainder of the buffered XML. this method stops the
1841 * parser, set its state to End Of File and return the input stream with
1842 * what is left that the parser did not use.
1843 *
1844 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
1845 * in case of error.
1846 */
1847xmlParserInputBufferPtr
1848xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
1849 xmlParserInputBufferPtr ret = NULL;
1850
1851 if (reader == NULL)
1852 return(NULL);
1853 if (reader->node == NULL)
1854 return(NULL);
1855
1856 reader->node = NULL;
1857 reader->curnode = NULL;
1858 reader->mode = XML_TEXTREADER_MODE_EOF;
1859 if (reader->ctxt != NULL) {
1860 if (reader->ctxt->myDoc != NULL) {
1861 xmlFreeDoc(reader->ctxt->myDoc);
1862 reader->ctxt->myDoc = NULL;
1863 }
1864 if (reader->allocs & XML_TEXTREADER_CTXT) {
1865 xmlFreeParserCtxt(reader->ctxt);
1866 reader->allocs -= XML_TEXTREADER_CTXT;
1867 }
1868 }
1869 if (reader->sax != NULL) {
1870 xmlFree(reader->sax);
1871 reader->sax = NULL;
1872 }
1873 if (reader->allocs & XML_TEXTREADER_INPUT) {
1874 ret = reader->input;
1875 reader->allocs -= XML_TEXTREADER_INPUT;
1876 } else {
1877 /*
1878 * Hum, one may need to duplicate the data structure because
1879 * without reference counting the input may be freed twice:
1880 * - by the layer which allocated it.
1881 * - by the layer to which would have been returned to.
1882 */
1883 TODO
1884 return(NULL);
1885 }
1886 return(ret);
1887}
1888
1889/**
1890 * xmlTextReaderLookupNamespace:
1891 * @reader: the xmlTextReaderPtr used
1892 * @prefix: the prefix whose namespace URI is to be resolved. To return
1893 * the default namespace, specify NULL
1894 *
1895 * Resolves a namespace prefix in the scope of the current element.
1896 *
1897 * Returns a string containing the namespace URI to which the prefix maps
1898 * or NULL in case of error. The string must be deallocated by the caller.
1899 */
1900xmlChar *
1901xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
1902 xmlNsPtr ns;
1903
1904 if (reader == NULL)
1905 return(NULL);
1906 if (reader->node == NULL)
1907 return(NULL);
1908
1909 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1910 if (ns == NULL)
1911 return(NULL);
1912 return(xmlStrdup(ns->href));
1913}
1914
1915/**
1916 * xmlTextReaderMoveToAttributeNo:
1917 * @reader: the xmlTextReaderPtr used
1918 * @no: the zero-based index of the attribute relative to the containing
1919 * element.
1920 *
1921 * Moves the position of the current instance to the attribute with
1922 * the specified index relative to the containing element.
1923 *
1924 * Returns 1 in case of success, -1 in case of error, 0 if not found
1925 */
1926int
1927xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
1928 int i;
1929 xmlAttrPtr cur;
1930 xmlNsPtr ns;
1931
1932 if (reader == NULL)
1933 return(-1);
1934 if (reader->node == NULL)
1935 return(-1);
1936 /* TODO: handle the xmlDecl */
1937 if (reader->node->type != XML_ELEMENT_NODE)
1938 return(-1);
1939
1940 reader->curnode = NULL;
1941
1942 ns = reader->node->nsDef;
1943 for (i = 0;(i < no) && (ns != NULL);i++) {
1944 ns = ns->next;
1945 }
1946 if (ns != NULL) {
1947 reader->curnode = (xmlNodePtr) ns;
1948 return(1);
1949 }
1950
1951 cur = reader->node->properties;
1952 if (cur == NULL)
1953 return(0);
1954 for (;i < no;i++) {
1955 cur = cur->next;
1956 if (cur == NULL)
1957 return(0);
1958 }
1959 /* TODO walk the DTD if present */
1960
1961 reader->curnode = (xmlNodePtr) cur;
1962 return(1);
1963}
1964
1965/**
1966 * xmlTextReaderMoveToAttribute:
1967 * @reader: the xmlTextReaderPtr used
1968 * @name: the qualified name of the attribute.
1969 *
1970 * Moves the position of the current instance to the attribute with
1971 * the specified qualified name.
1972 *
1973 * Returns 1 in case of success, -1 in case of error, 0 if not found
1974 */
1975int
1976xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1977 xmlChar *prefix = NULL;
1978 xmlChar *localname;
1979 xmlNsPtr ns;
1980 xmlAttrPtr prop;
1981
1982 if ((reader == NULL) || (name == NULL))
1983 return(-1);
1984 if (reader->node == NULL)
1985 return(-1);
1986
1987 /* TODO: handle the xmlDecl */
1988 if (reader->node->type != XML_ELEMENT_NODE)
1989 return(0);
1990
1991 localname = xmlSplitQName2(name, &prefix);
1992 if (localname == NULL) {
1993 /*
1994 * Namespace default decl
1995 */
1996 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
1997 ns = reader->node->nsDef;
1998 while (ns != NULL) {
1999 if (ns->prefix == NULL) {
2000 reader->curnode = (xmlNodePtr) ns;
2001 return(1);
2002 }
2003 ns = ns->next;
2004 }
2005 return(0);
2006 }
2007
2008 prop = reader->node->properties;
2009 while (prop != NULL) {
2010 /*
2011 * One need to have
2012 * - same attribute names
2013 * - and the attribute carrying that namespace
2014 */
2015 if ((xmlStrEqual(prop->name, name)) &&
2016 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
2017 reader->curnode = (xmlNodePtr) prop;
2018 return(1);
2019 }
2020 prop = prop->next;
2021 }
2022 return(0);
2023 }
2024
2025 /*
2026 * Namespace default decl
2027 */
2028 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
2029 ns = reader->node->nsDef;
2030 while (ns != NULL) {
2031 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
2032 reader->curnode = (xmlNodePtr) ns;
2033 goto found;
2034 }
2035 ns = ns->next;
2036 }
2037 goto not_found;
2038 }
2039 prop = reader->node->properties;
2040 while (prop != NULL) {
2041 /*
2042 * One need to have
2043 * - same attribute names
2044 * - and the attribute carrying that namespace
2045 */
2046 if ((xmlStrEqual(prop->name, localname)) &&
2047 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
2048 reader->curnode = (xmlNodePtr) prop;
2049 goto found;
2050 }
2051 prop = prop->next;
2052 }
2053not_found:
2054 if (localname != NULL)
2055 xmlFree(localname);
2056 if (prefix != NULL)
2057 xmlFree(prefix);
2058 return(0);
2059
2060found:
2061 if (localname != NULL)
2062 xmlFree(localname);
2063 if (prefix != NULL)
2064 xmlFree(prefix);
2065 return(1);
2066}
2067
2068/**
2069 * xmlTextReaderMoveToAttributeNs:
2070 * @reader: the xmlTextReaderPtr used
2071 * @localName: the local name of the attribute.
2072 * @namespaceURI: the namespace URI of the attribute.
2073 *
2074 * Moves the position of the current instance to the attribute with the
2075 * specified local name and namespace URI.
2076 *
2077 * Returns 1 in case of success, -1 in case of error, 0 if not found
2078 */
2079int
2080xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
2081 const xmlChar *localName, const xmlChar *namespaceURI) {
2082 xmlAttrPtr prop;
2083 xmlNodePtr node;
2084
2085 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
2086 return(-1);
2087 if (reader->node == NULL)
2088 return(-1);
2089 if (reader->node->type != XML_ELEMENT_NODE)
2090 return(0);
2091 node = reader->node;
2092
2093 /*
2094 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
2095 * namespace name associated to "xmlns"
2096 */
2097 prop = node->properties;
2098 while (prop != NULL) {
2099 /*
2100 * One need to have
2101 * - same attribute names
2102 * - and the attribute carrying that namespace
2103 */
2104 if (xmlStrEqual(prop->name, localName) &&
2105 ((prop->ns != NULL) &&
2106 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
2107 reader->curnode = (xmlNodePtr) prop;
2108 return(1);
2109 }
2110 prop = prop->next;
2111 }
2112 return(0);
2113}
2114
2115/**
2116 * xmlTextReaderMoveToFirstAttribute:
2117 * @reader: the xmlTextReaderPtr used
2118 *
2119 * Moves the position of the current instance to the first attribute
2120 * associated with the current node.
2121 *
2122 * Returns 1 in case of success, -1 in case of error, 0 if not found
2123 */
2124int
2125xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
2126 if (reader == NULL)
2127 return(-1);
2128 if (reader->node == NULL)
2129 return(-1);
2130 if (reader->node->type != XML_ELEMENT_NODE)
2131 return(0);
2132
2133 if (reader->node->nsDef != NULL) {
2134 reader->curnode = (xmlNodePtr) reader->node->nsDef;
2135 return(1);
2136 }
2137 if (reader->node->properties != NULL) {
2138 reader->curnode = (xmlNodePtr) reader->node->properties;
2139 return(1);
2140 }
2141 return(0);
2142}
2143
2144/**
2145 * xmlTextReaderMoveToNextAttribute:
2146 * @reader: the xmlTextReaderPtr used
2147 *
2148 * Moves the position of the current instance to the next attribute
2149 * associated with the current node.
2150 *
2151 * Returns 1 in case of success, -1 in case of error, 0 if not found
2152 */
2153int
2154xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
2155 if (reader == NULL)
2156 return(-1);
2157 if (reader->node == NULL)
2158 return(-1);
2159 if (reader->node->type != XML_ELEMENT_NODE)
2160 return(0);
2161 if (reader->curnode == NULL)
2162 return(xmlTextReaderMoveToFirstAttribute(reader));
2163
2164 if (reader->curnode->type == XML_NAMESPACE_DECL) {
2165 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2166 if (ns->next != NULL) {
2167 reader->curnode = (xmlNodePtr) ns->next;
2168 return(1);
2169 }
2170 if (reader->node->properties != NULL) {
2171 reader->curnode = (xmlNodePtr) reader->node->properties;
2172 return(1);
2173 }
2174 return(0);
2175 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
2176 (reader->curnode->next != NULL)) {
2177 reader->curnode = reader->curnode->next;
2178 return(1);
2179 }
2180 return(0);
2181}
2182
2183/**
2184 * xmlTextReaderMoveToElement:
2185 * @reader: the xmlTextReaderPtr used
2186 *
2187 * Moves the position of the current instance to the node that
2188 * contains the current Attribute node.
2189 *
2190 * Returns 1 in case of success, -1 in case of error, 0 if not moved
2191 */
2192int
2193xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
2194 if (reader == NULL)
2195 return(-1);
2196 if (reader->node == NULL)
2197 return(-1);
2198 if (reader->node->type != XML_ELEMENT_NODE)
2199 return(0);
2200 if (reader->curnode != NULL) {
2201 reader->curnode = NULL;
2202 return(1);
2203 }
2204 return(0);
2205}
2206
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002207/**
2208 * xmlTextReaderReadAttributeValue:
2209 * @reader: the xmlTextReaderPtr used
2210 *
2211 * Parses an attribute value into one or more Text and EntityReference nodes.
2212 *
2213 * Returns 1 in case of success, 0 if the reader was not positionned on an
2214 * ttribute node or all the attribute values have been read, or -1
2215 * in case of error.
2216 */
2217int
2218xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
2219 if (reader == NULL)
2220 return(-1);
2221 if (reader->node == NULL)
2222 return(-1);
2223 if (reader->curnode == NULL)
2224 return(0);
2225 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
2226 if (reader->curnode->children == NULL)
2227 return(0);
2228 reader->curnode = reader->curnode->children;
2229 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
2230 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2231
2232 if (reader->faketext == NULL) {
2233 reader->faketext = xmlNewDocText(reader->node->doc,
2234 ns->href);
2235 } else {
2236 if (reader->faketext->content != NULL)
2237 xmlFree(reader->faketext->content);
2238 reader->faketext->content = xmlStrdup(ns->href);
2239 }
2240 reader->curnode = reader->faketext;
2241 } else {
2242 if (reader->curnode->next == NULL)
2243 return(0);
2244 reader->curnode = reader->curnode->next;
2245 }
2246 return(1);
2247}
2248
Daniel Veillard0eb38c72002-12-14 23:00:35 +00002249/************************************************************************
2250 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002251 * Acces API to the current node *
2252 * *
2253 ************************************************************************/
2254/**
2255 * xmlTextReaderAttributeCount:
2256 * @reader: the xmlTextReaderPtr used
2257 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002258 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002259 *
2260 * Returns 0 i no attributes, -1 in case of error or the attribute count
2261 */
2262int
2263xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
2264 int ret;
2265 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00002266 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002267 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002268
2269 if (reader == NULL)
2270 return(-1);
2271 if (reader->node == NULL)
2272 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002273
2274 if (reader->curnode != NULL)
2275 node = reader->curnode;
2276 else
2277 node = reader->node;
2278
2279 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002280 return(0);
2281 if ((reader->state == XML_TEXTREADER_END) ||
2282 (reader->state == XML_TEXTREADER_BACKTRACK))
2283 return(0);
2284 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002285 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002286 while (attr != NULL) {
2287 ret++;
2288 attr = attr->next;
2289 }
Daniel Veillard67df8092002-12-16 22:04:11 +00002290 ns = node->nsDef;
2291 while (ns != NULL) {
2292 ret++;
2293 ns = ns->next;
2294 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002295 return(ret);
2296}
2297
2298/**
2299 * xmlTextReaderNodeType:
2300 * @reader: the xmlTextReaderPtr used
2301 *
2302 * Get the node type of the current node
2303 * Reference:
2304 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
2305 *
2306 * Returns the xmlNodeType of the current node or -1 in case of error
2307 */
2308int
2309xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002310 xmlNodePtr node;
Daniel Veillardd6038e02003-07-30 16:37:18 +00002311
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002312 if (reader == NULL)
2313 return(-1);
2314 if (reader->node == NULL)
Daniel Veillardd6038e02003-07-30 16:37:18 +00002315 return(XML_READER_TYPE_NONE);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002316 if (reader->curnode != NULL)
2317 node = reader->curnode;
2318 else
2319 node = reader->node;
2320 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002321 case XML_ELEMENT_NODE:
2322 if ((reader->state == XML_TEXTREADER_END) ||
2323 (reader->state == XML_TEXTREADER_BACKTRACK))
Daniel Veillardd6038e02003-07-30 16:37:18 +00002324 return(XML_READER_TYPE_END_ELEMENT);
2325 return(XML_READER_TYPE_ELEMENT);
Daniel Veillardecaba492002-12-30 10:55:29 +00002326 case XML_NAMESPACE_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002327 case XML_ATTRIBUTE_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002328 return(XML_READER_TYPE_ATTRIBUTE);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002329 case XML_TEXT_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002330 if (xmlIsBlankNode(reader->node)) {
2331 if (xmlNodeGetSpacePreserve(reader->node))
2332 return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
2333 else
2334 return(XML_READER_TYPE_WHITESPACE);
2335 } else {
2336 return(XML_READER_TYPE_TEXT);
2337 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002338 case XML_CDATA_SECTION_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002339 return(XML_READER_TYPE_CDATA);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002340 case XML_ENTITY_REF_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002341 return(XML_READER_TYPE_ENTITY_REFERENCE);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002342 case XML_ENTITY_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002343 return(XML_READER_TYPE_ENTITY);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002344 case XML_PI_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002345 return(XML_READER_TYPE_PROCESSING_INSTRUCTION);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002346 case XML_COMMENT_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002347 return(XML_READER_TYPE_COMMENT);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002348 case XML_DOCUMENT_NODE:
2349 case XML_HTML_DOCUMENT_NODE:
2350#ifdef LIBXML_DOCB_ENABLED
2351 case XML_DOCB_DOCUMENT_NODE:
2352#endif
Daniel Veillardd6038e02003-07-30 16:37:18 +00002353 return(XML_READER_TYPE_DOCUMENT);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002354 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002355 return(XML_READER_TYPE_DOCUMENT_FRAGMENT);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002356 case XML_NOTATION_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002357 return(XML_READER_TYPE_NOTATION);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002358 case XML_DOCUMENT_TYPE_NODE:
2359 case XML_DTD_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002360 return(XML_READER_TYPE_DOCUMENT_TYPE);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002361
2362 case XML_ELEMENT_DECL:
2363 case XML_ATTRIBUTE_DECL:
2364 case XML_ENTITY_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002365 case XML_XINCLUDE_START:
2366 case XML_XINCLUDE_END:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002367 return(XML_READER_TYPE_NONE);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002368 }
2369 return(-1);
2370}
2371
2372/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002373 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002374 * @reader: the xmlTextReaderPtr used
2375 *
2376 * Check if the current node is empty
2377 *
2378 * Returns 1 if empty, 0 if not and -1 in case of error
2379 */
2380int
2381xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
2382 if ((reader == NULL) || (reader->node == NULL))
2383 return(-1);
Daniel Veillarddf512f42002-12-23 15:56:21 +00002384 if (reader->node->type != XML_ELEMENT_NODE)
2385 return(0);
Daniel Veillarde3c036e2003-01-01 15:11:05 +00002386 if (reader->curnode != NULL)
2387 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002388 if (reader->node->children != NULL)
2389 return(0);
Daniel Veillarddab8ea92003-01-02 14:16:45 +00002390 if (reader->state == XML_TEXTREADER_END)
2391 return(0);
Daniel Veillard067bae52003-01-05 01:27:54 +00002392 return(reader->node->_private == (void *)xmlTextReaderIsEmpty);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002393}
2394
2395/**
2396 * xmlTextReaderLocalName:
2397 * @reader: the xmlTextReaderPtr used
2398 *
2399 * The local name of the node.
2400 *
2401 * Returns the local name or NULL if not available
2402 */
2403xmlChar *
2404xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002405 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002406 if ((reader == NULL) || (reader->node == NULL))
2407 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002408 if (reader->curnode != NULL)
2409 node = reader->curnode;
2410 else
2411 node = reader->node;
2412 if (node->type == XML_NAMESPACE_DECL) {
2413 xmlNsPtr ns = (xmlNsPtr) node;
2414 if (ns->prefix == NULL)
2415 return(xmlStrdup(BAD_CAST "xmlns"));
2416 else
2417 return(xmlStrdup(ns->prefix));
2418 }
2419 if ((node->type != XML_ELEMENT_NODE) &&
2420 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002421 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002422 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002423}
2424
2425/**
2426 * xmlTextReaderName:
2427 * @reader: the xmlTextReaderPtr used
2428 *
2429 * The qualified name of the node, equal to Prefix :LocalName.
2430 *
2431 * Returns the local name or NULL if not available
2432 */
2433xmlChar *
2434xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002435 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002436 xmlChar *ret;
2437
2438 if ((reader == NULL) || (reader->node == NULL))
2439 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002440 if (reader->curnode != NULL)
2441 node = reader->curnode;
2442 else
2443 node = reader->node;
2444 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002445 case XML_ELEMENT_NODE:
2446 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002447 if ((node->ns == NULL) ||
2448 (node->ns->prefix == NULL))
2449 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002450
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002451 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002452 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002453 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002454 return(ret);
2455 case XML_TEXT_NODE:
2456 return(xmlStrdup(BAD_CAST "#text"));
2457 case XML_CDATA_SECTION_NODE:
2458 return(xmlStrdup(BAD_CAST "#cdata-section"));
2459 case XML_ENTITY_NODE:
2460 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002461 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002462 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002463 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002464 case XML_COMMENT_NODE:
2465 return(xmlStrdup(BAD_CAST "#comment"));
2466 case XML_DOCUMENT_NODE:
2467 case XML_HTML_DOCUMENT_NODE:
2468#ifdef LIBXML_DOCB_ENABLED
2469 case XML_DOCB_DOCUMENT_NODE:
2470#endif
2471 return(xmlStrdup(BAD_CAST "#document"));
2472 case XML_DOCUMENT_FRAG_NODE:
2473 return(xmlStrdup(BAD_CAST "#document-fragment"));
2474 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002475 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002476 case XML_DOCUMENT_TYPE_NODE:
2477 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002478 return(xmlStrdup(node->name));
2479 case XML_NAMESPACE_DECL: {
2480 xmlNsPtr ns = (xmlNsPtr) node;
2481
2482 ret = xmlStrdup(BAD_CAST "xmlns");
2483 if (ns->prefix == NULL)
2484 return(ret);
2485 ret = xmlStrcat(ret, BAD_CAST ":");
2486 ret = xmlStrcat(ret, ns->prefix);
2487 return(ret);
2488 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002489
2490 case XML_ELEMENT_DECL:
2491 case XML_ATTRIBUTE_DECL:
2492 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002493 case XML_XINCLUDE_START:
2494 case XML_XINCLUDE_END:
2495 return(NULL);
2496 }
2497 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002498}
2499
2500/**
2501 * xmlTextReaderPrefix:
2502 * @reader: the xmlTextReaderPtr used
2503 *
2504 * A shorthand reference to the namespace associated with the node.
2505 *
2506 * Returns the prefix or NULL if not available
2507 */
2508xmlChar *
2509xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002510 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002511 if ((reader == NULL) || (reader->node == NULL))
2512 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002513 if (reader->curnode != NULL)
2514 node = reader->curnode;
2515 else
2516 node = reader->node;
2517 if (node->type == XML_NAMESPACE_DECL) {
2518 xmlNsPtr ns = (xmlNsPtr) node;
2519 if (ns->prefix == NULL)
2520 return(NULL);
2521 return(xmlStrdup(BAD_CAST "xmlns"));
2522 }
2523 if ((node->type != XML_ELEMENT_NODE) &&
2524 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002525 return(NULL);
Daniel Veillard952379b2003-03-17 15:37:12 +00002526 if ((node->ns != NULL) && (node->ns->prefix != NULL))
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002527 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002528 return(NULL);
2529}
2530
2531/**
2532 * xmlTextReaderNamespaceUri:
2533 * @reader: the xmlTextReaderPtr used
2534 *
2535 * The URI defining the namespace associated with the node.
2536 *
2537 * Returns the namespace URI or NULL if not available
2538 */
2539xmlChar *
2540xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002541 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002542 if ((reader == NULL) || (reader->node == NULL))
2543 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002544 if (reader->curnode != NULL)
2545 node = reader->curnode;
2546 else
2547 node = reader->node;
Daniel Veillardecaba492002-12-30 10:55:29 +00002548 if (node->type == XML_NAMESPACE_DECL)
2549 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002550 if ((node->type != XML_ELEMENT_NODE) &&
2551 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002552 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002553 if (node->ns != NULL)
2554 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002555 return(NULL);
2556}
2557
2558/**
2559 * xmlTextReaderBaseUri:
2560 * @reader: the xmlTextReaderPtr used
2561 *
2562 * The base URI of the node.
2563 *
2564 * Returns the base URI or NULL if not available
2565 */
2566xmlChar *
2567xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
2568 if ((reader == NULL) || (reader->node == NULL))
2569 return(NULL);
2570 return(xmlNodeGetBase(NULL, reader->node));
2571}
2572
2573/**
2574 * xmlTextReaderDepth:
2575 * @reader: the xmlTextReaderPtr used
2576 *
2577 * The depth of the node in the tree.
2578 *
2579 * Returns the depth or -1 in case of error
2580 */
2581int
2582xmlTextReaderDepth(xmlTextReaderPtr reader) {
2583 if (reader == NULL)
2584 return(-1);
2585 if (reader->node == NULL)
2586 return(0);
2587
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002588 if (reader->curnode != NULL) {
2589 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
2590 (reader->curnode->type == XML_NAMESPACE_DECL))
2591 return(reader->depth + 1);
2592 return(reader->depth + 2);
2593 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002594 return(reader->depth);
2595}
2596
2597/**
2598 * xmlTextReaderHasAttributes:
2599 * @reader: the xmlTextReaderPtr used
2600 *
2601 * Whether the node has attributes.
2602 *
2603 * Returns 1 if true, 0 if false, and -1 in case or error
2604 */
2605int
2606xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002607 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002608 if (reader == NULL)
2609 return(-1);
2610 if (reader->node == NULL)
2611 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002612 if (reader->curnode != NULL)
2613 node = reader->curnode;
2614 else
2615 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002616
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002617 if ((node->type == XML_ELEMENT_NODE) &&
2618 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002619 return(1);
2620 /* TODO: handle the xmlDecl */
2621 return(0);
2622}
2623
2624/**
2625 * xmlTextReaderHasValue:
2626 * @reader: the xmlTextReaderPtr used
2627 *
2628 * Whether the node can have a text value.
2629 *
2630 * Returns 1 if true, 0 if false, and -1 in case or error
2631 */
2632int
2633xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002634 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002635 if (reader == NULL)
2636 return(-1);
2637 if (reader->node == NULL)
2638 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002639 if (reader->curnode != NULL)
2640 node = reader->curnode;
2641 else
2642 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002643
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002644 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002645 case XML_ATTRIBUTE_NODE:
2646 case XML_TEXT_NODE:
2647 case XML_CDATA_SECTION_NODE:
2648 case XML_PI_NODE:
2649 case XML_COMMENT_NODE:
Daniel Veillard9e077102003-04-10 13:36:54 +00002650 case XML_NAMESPACE_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002651 return(1);
2652 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002653 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002654 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002655 return(0);
2656}
2657
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002658/**
2659 * xmlTextReaderValue:
2660 * @reader: the xmlTextReaderPtr used
2661 *
2662 * Provides the text value of the node if present
2663 *
2664 * Returns the string or NULL if not available. The retsult must be deallocated
2665 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002666 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002667xmlChar *
2668xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002669 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002670 if (reader == NULL)
2671 return(NULL);
2672 if (reader->node == NULL)
2673 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002674 if (reader->curnode != NULL)
2675 node = reader->curnode;
2676 else
2677 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002678
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002679 switch (node->type) {
2680 case XML_NAMESPACE_DECL:
2681 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002682 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002683 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002684
2685 if (attr->parent != NULL)
2686 return (xmlNodeListGetString
2687 (attr->parent->doc, attr->children, 1));
2688 else
2689 return (xmlNodeListGetString(NULL, attr->children, 1));
2690 break;
2691 }
2692 case XML_TEXT_NODE:
2693 case XML_CDATA_SECTION_NODE:
2694 case XML_PI_NODE:
2695 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002696 if (node->content != NULL)
2697 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002698 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002699 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002700 }
2701 return(NULL);
2702}
2703
2704/**
2705 * xmlTextReaderIsDefault:
2706 * @reader: the xmlTextReaderPtr used
2707 *
2708 * Whether an Attribute node was generated from the default value
2709 * defined in the DTD or schema.
2710 *
2711 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
2712 */
2713int
2714xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
2715 if (reader == NULL)
2716 return(-1);
2717 return(0);
2718}
2719
2720/**
2721 * xmlTextReaderQuoteChar:
2722 * @reader: the xmlTextReaderPtr used
2723 *
2724 * The quotation mark character used to enclose the value of an attribute.
2725 *
2726 * Returns " or ' and -1 in case of error
2727 */
2728int
2729xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
2730 if (reader == NULL)
2731 return(-1);
2732 /* TODO maybe lookup the attribute value for " first */
2733 return((int) '"');
2734}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002735
2736/**
2737 * xmlTextReaderXmlLang:
2738 * @reader: the xmlTextReaderPtr used
2739 *
2740 * The xml:lang scope within which the node resides.
2741 *
2742 * Returns the xml:lang value or NULL if none exists.
2743 */
2744xmlChar *
2745xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
2746 if (reader == NULL)
2747 return(NULL);
2748 if (reader->node == NULL)
2749 return(NULL);
2750 return(xmlNodeGetLang(reader->node));
2751}
2752
Daniel Veillard67df8092002-12-16 22:04:11 +00002753/**
2754 * xmlTextReaderNormalization:
2755 * @reader: the xmlTextReaderPtr used
2756 *
2757 * The value indicating whether to normalize white space and attribute values.
2758 * Since attribute value and end of line normalizations are a MUST in the XML
2759 * specification only the value true is accepted. The broken bahaviour of
2760 * accepting out of range character entities like &#0; is of course not
2761 * supported either.
2762 *
2763 * Returns 1 or -1 in case of error.
2764 */
2765int
2766xmlTextReaderNormalization(xmlTextReaderPtr reader) {
2767 if (reader == NULL)
2768 return(-1);
2769 return(1);
2770}
2771
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002772/************************************************************************
2773 * *
2774 * Extensions to the base APIs *
2775 * *
2776 ************************************************************************/
2777
2778/**
2779 * xmlTextReaderSetParserProp:
2780 * @reader: the xmlTextReaderPtr used
2781 * @prop: the xmlParserProperties to set
2782 * @value: usually 0 or 1 to (de)activate it
2783 *
2784 * Change the parser processing behaviour by changing some of its internal
2785 * properties. Note that some properties can only be changed before any
2786 * read has been done.
2787 *
2788 * Returns 0 if the call was successful, or -1 in case of error
2789 */
2790int
2791xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
2792 xmlParserProperties p = (xmlParserProperties) prop;
2793 xmlParserCtxtPtr ctxt;
2794
2795 if ((reader == NULL) || (reader->ctxt == NULL))
2796 return(-1);
2797 ctxt = reader->ctxt;
2798
2799 switch (p) {
2800 case XML_PARSER_LOADDTD:
2801 if (value != 0) {
2802 if (ctxt->loadsubset == 0) {
2803 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2804 return(-1);
2805 ctxt->loadsubset = XML_DETECT_IDS;
2806 }
2807 } else {
2808 ctxt->loadsubset = 0;
2809 }
2810 return(0);
2811 case XML_PARSER_DEFAULTATTRS:
2812 if (value != 0) {
2813 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
2814 } else {
2815 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2816 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
2817 }
2818 return(0);
2819 case XML_PARSER_VALIDATE:
2820 if (value != 0) {
2821 ctxt->validate = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00002822 reader->validate = XML_TEXTREADER_VALIDATE_DTD;
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002823 } else {
2824 ctxt->validate = 0;
2825 }
2826 return(0);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002827 case XML_PARSER_SUBST_ENTITIES:
2828 if (value != 0) {
2829 ctxt->replaceEntities = 1;
2830 } else {
2831 ctxt->replaceEntities = 0;
2832 }
2833 return(0);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002834 }
2835 return(-1);
2836}
2837
2838/**
2839 * xmlTextReaderGetParserProp:
2840 * @reader: the xmlTextReaderPtr used
2841 * @prop: the xmlParserProperties to get
2842 *
2843 * Read the parser internal property.
2844 *
2845 * Returns the value, usually 0 or 1, or -1 in case of error.
2846 */
2847int
2848xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
2849 xmlParserProperties p = (xmlParserProperties) prop;
2850 xmlParserCtxtPtr ctxt;
2851
2852 if ((reader == NULL) || (reader->ctxt == NULL))
2853 return(-1);
2854 ctxt = reader->ctxt;
2855
2856 switch (p) {
2857 case XML_PARSER_LOADDTD:
2858 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
2859 return(1);
2860 return(0);
2861 case XML_PARSER_DEFAULTATTRS:
2862 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
2863 return(1);
2864 return(0);
2865 case XML_PARSER_VALIDATE:
Daniel Veillardf4e55762003-04-15 23:32:22 +00002866 return(reader->validate);
Daniel Veillarde18fc182002-12-28 22:56:33 +00002867 case XML_PARSER_SUBST_ENTITIES:
2868 return(ctxt->replaceEntities);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002869 }
2870 return(-1);
2871}
2872
Daniel Veillarde18fc182002-12-28 22:56:33 +00002873/**
2874 * xmlTextReaderCurrentNode:
2875 * @reader: the xmlTextReaderPtr used
2876 *
2877 * Hacking interface allowing to get the xmlNodePtr correponding to the
2878 * current node being accessed by the xmlTextReader. This is dangerous
2879 * because the underlying node may be destroyed on the next Reads.
2880 *
2881 * Returns the xmlNodePtr or NULL in case of error.
2882 */
2883xmlNodePtr
2884xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
2885 if (reader == NULL)
2886 return(NULL);
2887
2888 if (reader->curnode != NULL)
2889 return(reader->curnode);
2890 return(reader->node);
2891}
2892
2893/**
2894 * xmlTextReaderCurrentDoc:
2895 * @reader: the xmlTextReaderPtr used
2896 *
2897 * Hacking interface allowing to get the xmlDocPtr correponding to the
2898 * current document being accessed by the xmlTextReader. This is dangerous
2899 * because the associated node may be destroyed on the next Reads.
2900 *
2901 * Returns the xmlDocPtr or NULL in case of error.
2902 */
2903xmlDocPtr
2904xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
2905 if ((reader == NULL) || (reader->ctxt == NULL))
2906 return(NULL);
2907
2908 return(reader->ctxt->myDoc);
2909}
2910
Daniel Veillard37fc84d2003-05-09 19:38:15 +00002911#ifdef LIBXML_SCHEMAS_ENABLED
Daniel Veillardf4e55762003-04-15 23:32:22 +00002912/**
Daniel Veillard33300b42003-04-17 09:09:19 +00002913 * xmlTextReaderRelaxNGSetSchema:
2914 * @reader: the xmlTextReaderPtr used
2915 * @schema: a precompiled RelaxNG schema
2916 *
2917 * Use RelaxNG to validate the document as it is processed.
2918 * Activation is only possible before the first Read().
2919 * if @schema is NULL, then RelaxNG validation is desactivated.
2920 @ The @schema should not be freed until the reader is deallocated
2921 * or its use has been deactivated.
2922 *
2923 * Returns 0 in case the RelaxNG validation could be (des)activated and
2924 * -1 in case of error.
2925 */
2926int
2927xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
2928 if (schema == NULL) {
2929 if (reader->rngSchemas != NULL) {
2930 xmlRelaxNGFree(reader->rngSchemas);
2931 reader->rngSchemas = NULL;
2932 }
2933 if (reader->rngValidCtxt != NULL) {
2934 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2935 reader->rngValidCtxt = NULL;
2936 }
2937 return(0);
2938 }
2939 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2940 return(-1);
2941 if (reader->rngSchemas != NULL) {
2942 xmlRelaxNGFree(reader->rngSchemas);
2943 reader->rngSchemas = NULL;
2944 }
2945 if (reader->rngValidCtxt != NULL) {
2946 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2947 reader->rngValidCtxt = NULL;
2948 }
2949 reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
2950 if (reader->rngValidCtxt == NULL)
2951 return(-1);
2952 if (reader->errorFunc != NULL) {
2953 xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
2954 (xmlRelaxNGValidityErrorFunc)reader->errorFunc,
2955 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
2956 reader->errorFuncArg);
2957 }
2958 reader->rngValidErrors = 0;
2959 reader->rngFullNode = NULL;
2960 reader->validate = XML_TEXTREADER_VALIDATE_RNG;
2961 return(0);
2962}
2963
2964/**
Daniel Veillardf4e55762003-04-15 23:32:22 +00002965 * xmlTextReaderRelaxNGValidate:
2966 * @reader: the xmlTextReaderPtr used
2967 * @rng: the path to a RelaxNG schema or NULL
2968 *
2969 * Use RelaxNG to validate the document as it is processed.
2970 * Activation is only possible before the first Read().
2971 * if @rng is NULL, then RelaxNG validation is desactivated.
2972 *
2973 * Returns 0 in case the RelaxNG validation could be (des)activated and
2974 * -1 in case of error.
2975 */
2976int
2977xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
2978 xmlRelaxNGParserCtxtPtr ctxt;
2979
2980 if (reader == NULL)
2981 return(-1);
2982
2983 if (rng == NULL) {
2984 if (reader->rngSchemas != NULL) {
2985 xmlRelaxNGFree(reader->rngSchemas);
2986 reader->rngSchemas = NULL;
2987 }
2988 if (reader->rngValidCtxt != NULL) {
2989 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2990 reader->rngValidCtxt = NULL;
2991 }
2992 return(0);
2993 }
2994 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
2995 return(-1);
Daniel Veillard33300b42003-04-17 09:09:19 +00002996 if (reader->rngSchemas != NULL) {
2997 xmlRelaxNGFree(reader->rngSchemas);
2998 reader->rngSchemas = NULL;
2999 }
3000 if (reader->rngValidCtxt != NULL) {
3001 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
3002 reader->rngValidCtxt = NULL;
3003 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00003004 ctxt = xmlRelaxNGNewParserCtxt(rng);
3005 if (reader->errorFunc != NULL) {
3006 xmlRelaxNGSetParserErrors(ctxt,
3007 (xmlRelaxNGValidityErrorFunc) reader->errorFunc,
3008 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
3009 reader->errorFuncArg);
3010 }
3011 reader->rngSchemas = xmlRelaxNGParse(ctxt);
3012 xmlRelaxNGFreeParserCtxt(ctxt);
3013 if (reader->rngSchemas == NULL)
3014 return(-1);
3015 reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
3016 if (reader->rngValidCtxt == NULL)
3017 return(-1);
3018 if (reader->errorFunc != NULL) {
3019 xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
3020 (xmlRelaxNGValidityErrorFunc)reader->errorFunc,
3021 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
3022 reader->errorFuncArg);
3023 }
3024 reader->rngValidErrors = 0;
3025 reader->rngFullNode = NULL;
3026 reader->validate = XML_TEXTREADER_VALIDATE_RNG;
3027 return(0);
3028}
Daniel Veillard37fc84d2003-05-09 19:38:15 +00003029#endif
Daniel Veillardf4e55762003-04-15 23:32:22 +00003030
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003031/************************************************************************
3032 * *
Daniel Veillard26f70262003-01-16 22:45:08 +00003033 * Error Handling Extensions *
3034 * *
3035 ************************************************************************/
3036
3037/* helper to build a xmlMalloc'ed string from a format and va_list */
3038static char *
3039xmlTextReaderBuildMessage(const char *msg, va_list ap) {
3040 int size;
3041 int chars;
3042 char *larger;
3043 char *str;
3044
Daniel Veillard3c908dc2003-04-19 00:07:51 +00003045 str = (char *) xmlMallocAtomic(150);
Daniel Veillard26f70262003-01-16 22:45:08 +00003046 if (str == NULL) {
3047 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
3048 return NULL;
3049 }
3050
3051 size = 150;
3052
3053 while (1) {
3054 chars = vsnprintf(str, size, msg, ap);
3055 if ((chars > -1) && (chars < size))
3056 break;
3057 if (chars > -1)
3058 size += chars + 1;
3059 else
3060 size += 100;
3061 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
3062 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
3063 xmlFree(str);
3064 return NULL;
3065 }
3066 str = larger;
3067 }
3068
3069 return str;
3070}
3071
Daniel Veillard417be3a2003-01-20 21:26:34 +00003072/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00003073 * xmlTextReaderLocatorLineNumber:
Daniel Veillard417be3a2003-01-20 21:26:34 +00003074 * @locator: the xmlTextReaderLocatorPtr used
3075 *
3076 * Obtain the line number for the given locator.
3077 *
3078 * Returns the line number or -1 in case of error.
3079 */
3080int
3081xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
3082 /* we know that locator is a xmlParserCtxtPtr */
3083 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
3084 int ret = -1;
3085
3086 if (ctx->node != NULL) {
3087 ret = xmlGetLineNo(ctx->node);
3088 }
3089 else {
3090 /* inspired from error.c */
3091 xmlParserInputPtr input;
3092 input = ctx->input;
3093 if ((input->filename == NULL) && (ctx->inputNr > 1))
3094 input = ctx->inputTab[ctx->inputNr - 2];
3095 if (input != NULL) {
3096 ret = input->line;
3097 }
3098 else {
3099 ret = -1;
3100 }
3101 }
3102
3103 return ret;
3104}
3105
3106/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00003107 * xmlTextReaderLocatorBaseURI:
Daniel Veillard417be3a2003-01-20 21:26:34 +00003108 * @locator: the xmlTextReaderLocatorPtr used
3109 *
3110 * Obtain the base URI for the given locator.
3111 *
3112 * Returns the base URI or NULL in case of error.
3113 */
3114xmlChar *
3115xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
3116 /* we know that locator is a xmlParserCtxtPtr */
3117 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
3118 xmlChar *ret = NULL;
3119
3120 if (ctx->node != NULL) {
3121 ret = xmlNodeGetBase(NULL,ctx->node);
3122 }
3123 else {
3124 /* inspired from error.c */
3125 xmlParserInputPtr input;
3126 input = ctx->input;
3127 if ((input->filename == NULL) && (ctx->inputNr > 1))
3128 input = ctx->inputTab[ctx->inputNr - 2];
3129 if (input != NULL) {
Daniel Veillard580ced82003-03-21 21:22:48 +00003130 ret = xmlStrdup(BAD_CAST input->filename);
Daniel Veillard417be3a2003-01-20 21:26:34 +00003131 }
3132 else {
3133 ret = NULL;
3134 }
3135 }
3136
3137 return ret;
3138}
3139
Daniel Veillard26f70262003-01-16 22:45:08 +00003140static void
3141xmlTextReaderGenericError(void *ctxt, int severity, char *str) {
3142 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
3143 xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private;
3144
3145 if (str != NULL) {
3146 reader->errorFunc(reader->errorFuncArg,
3147 str,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003148 severity,
3149 (xmlTextReaderLocatorPtr)ctx);
Daniel Veillard26f70262003-01-16 22:45:08 +00003150 xmlFree(str);
3151 }
3152}
3153
3154static void
3155xmlTextReaderError(void *ctxt, const char *msg, ...) {
3156 va_list ap;
3157
3158 va_start(ap,msg);
3159 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003160 XML_PARSER_SEVERITY_ERROR,
Daniel Veillard26f70262003-01-16 22:45:08 +00003161 xmlTextReaderBuildMessage(msg,ap));
3162 va_end(ap);
3163
3164}
3165
3166static void
3167xmlTextReaderWarning(void *ctxt, const char *msg, ...) {
3168 va_list ap;
3169
3170 va_start(ap,msg);
3171 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003172 XML_PARSER_SEVERITY_WARNING,
Daniel Veillard26f70262003-01-16 22:45:08 +00003173 xmlTextReaderBuildMessage(msg,ap));
3174 va_end(ap);
3175}
3176
3177static void
3178xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
3179 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00003180 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00003181
Daniel Veillard417be3a2003-01-20 21:26:34 +00003182 if ((len > 1) && (msg[len - 2] != ':')) {
3183 /*
3184 * some callbacks only report locator information:
3185 * skip them (mimicking behaviour in error.c)
3186 */
3187 va_start(ap,msg);
3188 xmlTextReaderGenericError(ctxt,
3189 XML_PARSER_SEVERITY_VALIDITY_ERROR,
3190 xmlTextReaderBuildMessage(msg,ap));
3191 va_end(ap);
3192 }
Daniel Veillard26f70262003-01-16 22:45:08 +00003193}
3194
3195static void
3196xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
3197 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00003198 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00003199
Daniel Veillard417be3a2003-01-20 21:26:34 +00003200 if ((len != 0) && (msg[len - 1] != ':')) {
3201 /*
3202 * some callbacks only report locator information:
3203 * skip them (mimicking behaviour in error.c)
3204 */
3205 va_start(ap,msg);
3206 xmlTextReaderGenericError(ctxt,
3207 XML_PARSER_SEVERITY_VALIDITY_WARNING,
3208 xmlTextReaderBuildMessage(msg,ap));
3209 va_end(ap);
3210 }
Daniel Veillard26f70262003-01-16 22:45:08 +00003211}
3212
3213/**
3214 * xmlTextReaderSetErrorHandler:
3215 * @reader: the xmlTextReaderPtr used
3216 * @f: the callback function to call on error and warnings
3217 * @arg: a user argument to pass to the callback function
3218 *
Daniel Veillard417be3a2003-01-20 21:26:34 +00003219 * Register a callback function that will be called on error and warnings.
3220 *
Daniel Veillard26f70262003-01-16 22:45:08 +00003221 * If @f is NULL, the default error and warning handlers are restored.
3222 */
3223void
3224xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
3225 xmlTextReaderErrorFunc f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003226 void *arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00003227 if (f != NULL) {
3228 reader->ctxt->sax->error = xmlTextReaderError;
3229 reader->ctxt->vctxt.error = xmlTextReaderValidityError;
3230 reader->ctxt->sax->warning = xmlTextReaderWarning;
3231 reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
3232 reader->errorFunc = f;
3233 reader->errorFuncArg = arg;
3234 }
3235 else {
3236 /* restore defaults */
3237 reader->ctxt->sax->error = xmlParserError;
3238 reader->ctxt->vctxt.error = xmlParserValidityError;
3239 reader->ctxt->sax->warning = xmlParserWarning;
3240 reader->ctxt->vctxt.warning = xmlParserValidityWarning;
3241 reader->errorFunc = NULL;
3242 reader->errorFuncArg = NULL;
3243 }
3244}
3245
Daniel Veillard417be3a2003-01-20 21:26:34 +00003246/**
Daniel Veillardf6bad792003-04-11 19:38:54 +00003247 * xmlTextReaderIsValid:
3248 * @reader: the xmlTextReaderPtr used
3249 *
3250 * Retrieve the validity status from the parser context
3251 *
3252 * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
3253 */
3254int
3255xmlTextReaderIsValid(xmlTextReaderPtr reader) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00003256 if (reader == NULL) return(-1);
3257#ifdef LIBXML_SCHEMAS_ENABLED
3258 if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
3259 return(reader->rngValidErrors == 0);
3260#endif
3261 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
3262 (reader->ctxt != NULL))
3263 return(reader->ctxt->valid);
3264 return(0);
Daniel Veillardf6bad792003-04-11 19:38:54 +00003265}
3266
3267/**
Daniel Veillard417be3a2003-01-20 21:26:34 +00003268 * xmlTextReaderGetErrorHandler:
3269 * @reader: the xmlTextReaderPtr used
3270 * @f: the callback function or NULL is no callback has been registered
3271 * @arg: a user argument
3272 *
3273 * Retrieve the error callback function and user argument.
3274 */
Daniel Veillard26f70262003-01-16 22:45:08 +00003275void
3276xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
3277 xmlTextReaderErrorFunc *f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003278 void **arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00003279 *f = reader->errorFunc;
3280 *arg = reader->errorFuncArg;
3281}
3282
3283/************************************************************************
3284 * *
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003285 * Utilities *
3286 * *
3287 ************************************************************************/
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00003288#ifdef NOT_USED_YET
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003289/**
3290 * xmlBase64Decode:
3291 * @in: the input buffer
3292 * @inlen: the size of the input (in), the size read from it (out)
3293 * @to: the output buffer
3294 * @tolen: the size of the output (in), the size written to (out)
3295 *
3296 * Base64 decoder, reads from @in and save in @to
Daniel Veillardd4310742003-02-18 21:12:46 +00003297 * TODO: tell jody when this is actually exported
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003298 *
3299 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
3300 * 2 if there wasn't enough space on the output or -1 in case of error.
3301 */
3302static int
3303xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
3304 unsigned char *to, unsigned long *tolen) {
3305 unsigned long incur; /* current index in in[] */
3306 unsigned long inblk; /* last block index in in[] */
3307 unsigned long outcur; /* current index in out[] */
3308 unsigned long inmax; /* size of in[] */
3309 unsigned long outmax; /* size of out[] */
3310 unsigned char cur; /* the current value read from in[] */
Daniel Veillardc127adc2003-07-23 15:07:08 +00003311 unsigned char intmp[4], outtmp[4]; /* temporary buffers for the convert */
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003312 int nbintmp; /* number of byte in intmp[] */
3313 int is_ignore; /* cur should be ignored */
3314 int is_end = 0; /* the end of the base64 was found */
3315 int retval = 1;
3316 int i;
3317
3318 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
3319 return(-1);
3320
3321 incur = 0;
3322 inblk = 0;
3323 outcur = 0;
3324 inmax = *inlen;
3325 outmax = *tolen;
3326 nbintmp = 0;
3327
3328 while (1) {
3329 if (incur >= inmax)
3330 break;
3331 cur = in[incur++];
3332 is_ignore = 0;
3333 if ((cur >= 'A') && (cur <= 'Z'))
3334 cur = cur - 'A';
3335 else if ((cur >= 'a') && (cur <= 'z'))
3336 cur = cur - 'a' + 26;
3337 else if ((cur >= '0') && (cur <= '9'))
3338 cur = cur - '0' + 52;
3339 else if (cur == '+')
3340 cur = 62;
3341 else if (cur == '/')
3342 cur = 63;
3343 else if (cur == '.')
3344 cur = 0;
3345 else if (cur == '=') /*no op , end of the base64 stream */
3346 is_end = 1;
3347 else {
3348 is_ignore = 1;
3349 if (nbintmp == 0)
3350 inblk = incur;
3351 }
3352
3353 if (!is_ignore) {
3354 int nbouttmp = 3;
3355 int is_break = 0;
3356
3357 if (is_end) {
3358 if (nbintmp == 0)
3359 break;
3360 if ((nbintmp == 1) || (nbintmp == 2))
3361 nbouttmp = 1;
3362 else
3363 nbouttmp = 2;
3364 nbintmp = 3;
3365 is_break = 1;
3366 }
3367 intmp[nbintmp++] = cur;
3368 /*
3369 * if intmp is full, push the 4byte sequence as a 3 byte
3370 * sequence out
3371 */
3372 if (nbintmp == 4) {
3373 nbintmp = 0;
3374 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
3375 outtmp[1] =
3376 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
3377 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
3378 if (outcur + 3 >= outmax) {
3379 retval = 2;
3380 break;
3381 }
3382
3383 for (i = 0; i < nbouttmp; i++)
3384 to[outcur++] = outtmp[i];
3385 inblk = incur;
3386 }
3387
3388 if (is_break) {
3389 retval = 0;
3390 break;
3391 }
3392 }
3393 }
3394
3395 *tolen = outcur;
3396 *inlen = inblk;
3397 return (retval);
3398}
3399
3400/*
3401 * Test routine for the xmlBase64Decode function
3402 */
3403#if 0
3404int main(int argc, char **argv) {
3405 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
3406 char output[100];
3407 char output2[100];
3408 char output3[100];
3409 unsigned long inlen = strlen(input);
3410 unsigned long outlen = 100;
3411 int ret;
3412 unsigned long cons, tmp, tmp2, prod;
3413
3414 /*
3415 * Direct
3416 */
3417 ret = xmlBase64Decode(input, &inlen, output, &outlen);
3418
3419 output[outlen] = 0;
3420 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
3421
3422 /*
3423 * output chunking
3424 */
3425 cons = 0;
3426 prod = 0;
3427 while (cons < inlen) {
3428 tmp = 5;
3429 tmp2 = inlen - cons;
3430
3431 printf("%ld %ld\n", cons, prod);
3432 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
3433 cons += tmp2;
3434 prod += tmp;
3435 printf("%ld %ld\n", cons, prod);
3436 }
3437 output2[outlen] = 0;
3438 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
3439
3440 /*
3441 * input chunking
3442 */
3443 cons = 0;
3444 prod = 0;
3445 while (cons < inlen) {
3446 tmp = 100 - prod;
3447 tmp2 = inlen - cons;
3448 if (tmp2 > 5)
3449 tmp2 = 5;
3450
3451 printf("%ld %ld\n", cons, prod);
3452 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
3453 cons += tmp2;
3454 prod += tmp;
3455 printf("%ld %ld\n", cons, prod);
3456 }
3457 output3[outlen] = 0;
3458 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
3459 return(0);
3460
3461}
3462#endif
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00003463#endif /* NOT_USED_YET */