blob: 8109cf885dd0b77951cf1efc65540d3166f1c637 [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 Veillarde72c5082003-09-19 12:44:05 +0000138/**
139 * CONSTSTR:
140 *
141 * Macro used to return an interned string
142 */
143#define CONSTSTR(str) xmlDictLookup(reader->ctxt->dict, (str), -1)
144#define CONSTQSTR(p, str) xmlDictQLookup(reader->ctxt->dict, (p), (str))
145
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +0000146/************************************************************************
147 * *
148 * Our own version of the freeing routines as we recycle nodes *
149 * *
150 ************************************************************************/
151
152static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur);
153static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur);
154
155/**
156 * xmlTextReaderFreeEntityWrapper:
157 * @entity: An entity
158 * @name: its name
159 *
160 * Deallocate the memory used by an entities in the hash table.
161 */
162static void
163xmlTextReaderFreeEntityWrapper(xmlEntityPtr entity,
164 const xmlChar *name ATTRIBUTE_UNUSED) {
165 if (entity == NULL) return;
166
167 if ((entity->children) && (entity->owner == 1) &&
168 (entity == (xmlEntityPtr) entity->children->parent)) {
169 xmlDocPtr doc;
170 xmlTextReaderPtr reader = NULL;
171 doc = entity->doc;
172 if (doc != NULL)
173 reader = doc->_private;
174 xmlTextReaderFreeNodeList(reader, entity->children);
175 }
176 if (entity->name != NULL)
177 xmlFree((char *) entity->name);
178 if (entity->ExternalID != NULL)
179 xmlFree((char *) entity->ExternalID);
180 if (entity->SystemID != NULL)
181 xmlFree((char *) entity->SystemID);
182 if (entity->URI != NULL)
183 xmlFree((char *) entity->URI);
184 if (entity->content != NULL)
185 xmlFree((char *) entity->content);
186 if (entity->orig != NULL)
187 xmlFree((char *) entity->orig);
188 xmlFree(entity);
189}
190
191/**
192 * xmlTextReaderFreeEntitiesTable:
193 * @table: An entity table
194 *
195 * Deallocate the memory used by an entities hash table.
196 */
197static void
198xmlTextReaderFreeEntitiesTable(xmlEntitiesTablePtr table) {
199 xmlHashFree(table, (xmlHashDeallocator) xmlTextReaderFreeEntityWrapper);
200}
201
202/**
203 * xmlTextReaderFreeDtd:
204 * @cur: the DTD structure to free up
205 *
206 * Free a DTD structure.
207 */
208static void
209xmlTextReaderFreeDtd(xmlTextReaderPtr reader, xmlDtdPtr cur) {
210 if (cur == NULL) return;
211
212 if (cur->children != NULL) {
213 xmlNodePtr next, c = cur->children;
214
215 /*
216 * Cleanup all the DTD comments they are not in the DTD
217 * indexes.
218 */
219 while (c != NULL) {
220 next = c->next;
221 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) {
222 xmlUnlinkNode(c);
223 xmlTextReaderFreeNode(reader, c);
224 }
225 c = next;
226 }
227 }
228
229 if (cur->name != NULL) xmlFree((char *) cur->name);
230 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
231 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
232 /* TODO !!! */
233 if (cur->notations != NULL)
234 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
235
236 if (cur->elements != NULL)
237 xmlFreeElementTable((xmlElementTablePtr) cur->elements);
238 if (cur->attributes != NULL)
239 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
240 if (cur->pentities != NULL)
241 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
242
243 if (cur->entities != NULL)
244 xmlTextReaderFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
245
246 xmlFree(cur);
247}
248
249/**
250 * xmlTextReaderFreeProp:
251 * @reader: the xmlTextReaderPtr used
252 * @cur: the node
253 *
254 * Free a node.
255 */
256static void
257xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
258 if (cur == NULL) return;
259
260 /* Check for ID removal -> leading to invalid references ! */
261 if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
262 ((cur->parent->doc->intSubset != NULL) ||
263 (cur->parent->doc->extSubset != NULL))) {
264 if (xmlIsID(cur->parent->doc, cur->parent, cur))
265 xmlRemoveID(cur->parent->doc, cur);
266 }
267 if (cur->children != NULL)
268 xmlTextReaderFreeNodeList(reader, cur->children);
269
270 if ((reader != NULL) && (reader->ctxt != NULL) &&
271 (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) &&
272 (cur->name != NULL))
273 xmlFree((xmlChar *)cur->name);
Daniel Veillard19895052003-09-17 13:59:32 +0000274 if ((reader != NULL) && (reader->ctxt != NULL) &&
275 (reader->ctxt->freeAttrsNr < 100)) {
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +0000276 cur->next = reader->ctxt->freeAttrs;
277 reader->ctxt->freeAttrs = cur;
Daniel Veillard19895052003-09-17 13:59:32 +0000278 reader->ctxt->freeAttrsNr++;
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +0000279 } else {
280 xmlFree(cur);
281 }
282}
283
284/**
285 * xmlTextReaderFreePropList:
286 * @reader: the xmlTextReaderPtr used
287 * @cur: the first property in the list
288 *
289 * Free a property and all its siblings, all the children are freed too.
290 */
291static void
292xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) {
293 xmlAttrPtr next;
294 if (cur == NULL) return;
295 while (cur != NULL) {
296 next = cur->next;
297 xmlTextReaderFreeProp(reader, cur);
298 cur = next;
299 }
300}
301
302/**
303 * xmlTextReaderFreeNodeList:
304 * @reader: the xmlTextReaderPtr used
305 * @cur: the first node in the list
306 *
307 * Free a node and all its siblings, this is a recursive behaviour, all
308 * the children are freed too.
309 */
310static void
311xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
312 xmlNodePtr next;
313 if (cur == NULL) return;
314 if (cur->type == XML_NAMESPACE_DECL) {
315 xmlFreeNsList((xmlNsPtr) cur);
316 return;
317 }
318 if ((cur->type == XML_DOCUMENT_NODE) ||
319 (cur->type == XML_HTML_DOCUMENT_NODE)) {
320 xmlFreeDoc((xmlDocPtr) cur);
321 return;
322 }
323 while (cur != NULL) {
324 next = cur->next;
325 /* unroll to speed up freeing the document */
326 if (cur->type != XML_DTD_NODE) {
327
328 if ((cur->children != NULL) &&
329 (cur->type != XML_ENTITY_REF_NODE))
330 xmlTextReaderFreeNodeList(reader, cur->children);
331 if (((cur->type == XML_ELEMENT_NODE) ||
332 (cur->type == XML_XINCLUDE_START) ||
333 (cur->type == XML_XINCLUDE_END)) &&
334 (cur->properties != NULL))
335 xmlTextReaderFreePropList(reader, cur->properties);
336 if ((cur->type != XML_ELEMENT_NODE) &&
337 (cur->type != XML_XINCLUDE_START) &&
338 (cur->type != XML_XINCLUDE_END) &&
339 (cur->type != XML_ENTITY_REF_NODE)) {
340 if (cur->content != NULL) xmlFree(cur->content);
341 }
342 if (((cur->type == XML_ELEMENT_NODE) ||
343 (cur->type == XML_XINCLUDE_START) ||
344 (cur->type == XML_XINCLUDE_END)) &&
345 (cur->nsDef != NULL))
346 xmlFreeNsList(cur->nsDef);
347
348 /*
349 * we don't free element names here they are interned now
350 */
351 if (cur->type == XML_ELEMENT_NODE) {
352 if ((reader != NULL) && (reader->ctxt != NULL) &&
353 (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) &&
354 (cur->name != NULL))
355 xmlFree((xmlChar *)cur->name);
356 } else if ((cur->type != XML_TEXT_NODE) &&
357 (cur->type != XML_COMMENT_NODE) &&
358 (cur->name != NULL))
359 xmlFree((xmlChar *)cur->name);
Daniel Veillard19895052003-09-17 13:59:32 +0000360 if (((cur->type == XML_ELEMENT_NODE) ||
361 (cur->type == XML_TEXT_NODE)) &&
362 (reader != NULL) && (reader->ctxt != NULL) &&
363 (reader->ctxt->freeElemsNr < 100)) {
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +0000364 cur->next = reader->ctxt->freeElems;
365 reader->ctxt->freeElems = cur;
Daniel Veillard19895052003-09-17 13:59:32 +0000366 reader->ctxt->freeElemsNr++;
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +0000367 } else {
368 xmlFree(cur);
369 }
370 }
371 cur = next;
372 }
373}
374
375/**
376 * xmlTextReaderFreeNode:
377 * @reader: the xmlTextReaderPtr used
378 * @cur: the node
379 *
380 * Free a node, this is a recursive behaviour, all the children are freed too.
381 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
382 */
383static void
384xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) {
385 if (cur->type == XML_DTD_NODE) {
386 xmlTextReaderFreeDtd(reader, (xmlDtdPtr) cur);
387 return;
388 }
389 if (cur->type == XML_NAMESPACE_DECL) {
390 xmlFreeNs((xmlNsPtr) cur);
391 return;
392 }
393 if (cur->type == XML_ATTRIBUTE_NODE) {
394 xmlTextReaderFreeProp(reader, (xmlAttrPtr) cur);
395 return;
396 }
397
398 if ((cur->children != NULL) &&
399 (cur->type != XML_ENTITY_REF_NODE))
400 xmlTextReaderFreeNodeList(reader, cur->children);
401 if (((cur->type == XML_ELEMENT_NODE) ||
402 (cur->type == XML_XINCLUDE_START) ||
403 (cur->type == XML_XINCLUDE_END)) &&
404 (cur->properties != NULL))
405 xmlTextReaderFreePropList(reader, cur->properties);
406 if ((cur->type != XML_ELEMENT_NODE) &&
407 (cur->type != XML_XINCLUDE_START) &&
408 (cur->type != XML_XINCLUDE_END) &&
409 (cur->type != XML_ENTITY_REF_NODE)) {
410 if (cur->content != NULL) xmlFree(cur->content);
411 }
412 if (((cur->type == XML_ELEMENT_NODE) ||
413 (cur->type == XML_XINCLUDE_START) ||
414 (cur->type == XML_XINCLUDE_END)) &&
415 (cur->nsDef != NULL))
416 xmlFreeNsList(cur->nsDef);
417
418 /*
419 * we don't free names here they are interned now
420 */
421 if (cur->type == XML_ELEMENT_NODE) {
422 if ((reader != NULL) && (reader->ctxt != NULL) &&
423 (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) &&
424 (cur->name != NULL))
425 xmlFree((xmlChar *)cur->name);
426 } else if ((cur->type != XML_TEXT_NODE) &&
427 (cur->type != XML_COMMENT_NODE) &&
428 (cur->name != NULL))
429 xmlFree((xmlChar *)cur->name);
Daniel Veillard19895052003-09-17 13:59:32 +0000430 if (((cur->type == XML_ELEMENT_NODE) ||
431 (cur->type == XML_TEXT_NODE)) &&
432 (reader != NULL) && (reader->ctxt != NULL) &&
433 (reader->ctxt->freeElemsNr < 100)) {
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +0000434 cur->next = reader->ctxt->freeElems;
435 reader->ctxt->freeElems = cur;
Daniel Veillard19895052003-09-17 13:59:32 +0000436 reader->ctxt->freeElemsNr++;
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +0000437 } else {
438 xmlFree(cur);
439 }
440
441}
442
443/**
444 * xmlTextReaderFreeDoc:
445 * @reader: the xmlTextReaderPtr used
446 * @cur: pointer to the document
447 *
448 * Free up all the structures used by a document, tree included.
449 */
450static void
451xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) {
452 xmlDtdPtr extSubset, intSubset;
453
454 if (cur == NULL) return;
455
456 /*
457 * Do this before freeing the children list to avoid ID lookups
458 */
459 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
460 cur->ids = NULL;
461 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
462 cur->refs = NULL;
463 extSubset = cur->extSubset;
464 intSubset = cur->intSubset;
465 if (intSubset == extSubset)
466 extSubset = NULL;
467 if (extSubset != NULL) {
468 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
469 cur->extSubset = NULL;
470 xmlTextReaderFreeDtd(reader, extSubset);
471 }
472 if (intSubset != NULL) {
473 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
474 cur->intSubset = NULL;
475 xmlTextReaderFreeDtd(reader, intSubset);
476 }
477
478 if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children);
479
480 if (cur->version != NULL) xmlFree((char *) cur->version);
481 if (cur->name != NULL) xmlFree((char *) cur->name);
482 if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
483 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
484 if (cur->URL != NULL) xmlFree((char *) cur->URL);
485 xmlFree(cur);
486}
487
488/************************************************************************
489 * *
490 * The reader core parser *
491 * *
492 ************************************************************************/
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000493#ifdef DEBUG_READER
494static void
495xmlTextReaderDebug(xmlTextReaderPtr reader) {
496 if ((reader == NULL) || (reader->ctxt == NULL)) {
497 fprintf(stderr, "xmlTextReader NULL\n");
498 return;
499 }
500 fprintf(stderr, "xmlTextReader: state %d depth %d ",
501 reader->state, reader->depth);
502 if (reader->node == NULL) {
503 fprintf(stderr, "node = NULL\n");
504 } else {
505 fprintf(stderr, "node %s\n", reader->node->name);
506 }
507 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
508 reader->base, reader->cur, reader->ctxt->nodeNr);
509 if (reader->input->buffer == NULL) {
510 fprintf(stderr, "buffer is NULL\n");
511 } else {
512#ifdef LIBXML_DEBUG_ENABLED
513 xmlDebugDumpString(stderr,
514 &reader->input->buffer->content[reader->cur]);
515#endif
516 fprintf(stderr, "\n");
517 }
518}
519#endif
520
521/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000522 * xmlTextReaderEntPush:
523 * @reader: the xmlTextReaderPtr used
524 * @value: the entity reference node
525 *
526 * Pushes a new entity reference node on top of the entities stack
527 *
528 * Returns 0 in case of error, the index in the stack otherwise
529 */
530static int
531xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
532{
533 if (reader->entMax <= 0) {
534 reader->entMax = 10;
535 reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
536 sizeof(reader->entTab[0]));
537 if (reader->entTab == NULL) {
538 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
539 return (0);
540 }
541 }
542 if (reader->entNr >= reader->entMax) {
543 reader->entMax *= 2;
544 reader->entTab =
545 (xmlNodePtr *) xmlRealloc(reader->entTab,
546 reader->entMax *
547 sizeof(reader->entTab[0]));
548 if (reader->entTab == NULL) {
549 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
550 return (0);
551 }
552 }
553 reader->entTab[reader->entNr] = value;
554 reader->ent = value;
555 return (reader->entNr++);
556}
557
558/**
559 * xmlTextReaderEntPop:
560 * @reader: the xmlTextReaderPtr used
561 *
562 * Pops the top element entity from the entities stack
563 *
564 * Returns the entity just removed
565 */
566static xmlNodePtr
567xmlTextReaderEntPop(xmlTextReaderPtr reader)
568{
569 xmlNodePtr ret;
570
571 if (reader->entNr <= 0)
572 return (0);
573 reader->entNr--;
574 if (reader->entNr > 0)
575 reader->ent = reader->entTab[reader->entNr - 1];
576 else
577 reader->ent = NULL;
578 ret = reader->entTab[reader->entNr];
579 reader->entTab[reader->entNr] = 0;
580 return (ret);
581}
582
583/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000584 * xmlTextReaderStartElement:
585 * @ctx: the user data (XML parser context)
586 * @fullname: The element name, including namespace prefix
587 * @atts: An array of name/value attributes pairs, NULL terminated
588 *
589 * called when an opening tag has been processed.
590 */
591static void
592xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
593 const xmlChar **atts) {
594 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
595 xmlTextReaderPtr reader = ctxt->_private;
596
597#ifdef DEBUG_CALLBACKS
598 printf("xmlTextReaderStartElement(%s)\n", fullname);
599#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000600 if ((reader != NULL) && (reader->startElement != NULL)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000601 reader->startElement(ctx, fullname, atts);
Daniel Veillard067bae52003-01-05 01:27:54 +0000602 if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
603 (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
604 (ctxt->input->cur[1] == '>'))
605 ctxt->node->_private = (void *) xmlTextReaderIsEmpty;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000606 }
Daniel Veillard9e395c22003-01-01 14:50:44 +0000607 if (reader != NULL)
608 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000609}
610
611/**
612 * xmlTextReaderEndElement:
613 * @ctx: the user data (XML parser context)
614 * @fullname: The element name, including namespace prefix
615 *
616 * called when an ending tag has been processed.
617 */
618static void
619xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
620 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
621 xmlTextReaderPtr reader = ctxt->_private;
622
623#ifdef DEBUG_CALLBACKS
624 printf("xmlTextReaderEndElement(%s)\n", fullname);
625#endif
Daniel Veillardea7751d2002-12-20 00:16:24 +0000626 if ((reader != NULL) && (reader->endElement != NULL)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000627 reader->endElement(ctx, fullname);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000628 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000629}
630
631/**
Daniel Veillard07cb8222003-09-10 10:51:05 +0000632 * xmlTextReaderStartElementNs:
633 * @ctx: the user data (XML parser context)
634 * @localname: the local name of the element
635 * @prefix: the element namespace prefix if available
636 * @URI: the element namespace name if available
637 * @nb_namespaces: number of namespace definitions on that node
638 * @namespaces: pointer to the array of prefix/URI pairs namespace definitions
639 * @nb_attributes: the number of attributes on that node
640 * nb_defaulted: the number of defaulted attributes.
641 * @attributes: pointer to the array of (localname/prefix/URI/value/end)
642 * attribute values.
643 *
644 * called when an opening tag has been processed.
645 */
646static void
647xmlTextReaderStartElementNs(void *ctx,
648 const xmlChar *localname,
649 const xmlChar *prefix,
650 const xmlChar *URI,
651 int nb_namespaces,
652 const xmlChar **namespaces,
653 int nb_attributes,
654 int nb_defaulted,
655 const xmlChar **attributes)
656{
657 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
658 xmlTextReaderPtr reader = ctxt->_private;
659
660#ifdef DEBUG_CALLBACKS
661 printf("xmlTextReaderStartElementNs(%s)\n", fullname);
662#endif
663 if ((reader != NULL) && (reader->startElementNs != NULL)) {
664 reader->startElementNs(ctx, localname, prefix, URI, nb_namespaces,
665 namespaces, nb_attributes, nb_defaulted,
666 attributes);
667 if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
668 (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
669 (ctxt->input->cur[1] == '>'))
670 ctxt->node->_private = (void *) xmlTextReaderIsEmpty;
671 }
672 if (reader != NULL)
673 reader->state = XML_TEXTREADER_ELEMENT;
674}
675
676/**
677 * xmlTextReaderEndElementNs:
678 * @ctx: the user data (XML parser context)
679 * @localname: the local name of the element
680 * @prefix: the element namespace prefix if available
681 * @URI: the element namespace name if available
682 *
683 * called when an ending tag has been processed.
684 */
685static void
686xmlTextReaderEndElementNs(void *ctx,
687 const xmlChar * localname,
688 const xmlChar * prefix,
689 const xmlChar * URI)
690{
691 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
692 xmlTextReaderPtr reader = ctxt->_private;
693
694#ifdef DEBUG_CALLBACKS
695 printf("xmlTextReaderEndElementNs(%s)\n", fullname);
696#endif
697 if ((reader != NULL) && (reader->endElementNs != NULL)) {
698 reader->endElementNs(ctx, localname, prefix, URI);
699 }
700}
701
702
703/**
Daniel Veillardea7751d2002-12-20 00:16:24 +0000704 * xmlTextReaderCharacters:
705 * @ctx: the user data (XML parser context)
706 * @ch: a xmlChar string
707 * @len: the number of xmlChar
708 *
709 * receiving some chars from the parser.
710 */
711static void
712xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
713{
714 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
715 xmlTextReaderPtr reader = ctxt->_private;
716
717#ifdef DEBUG_CALLBACKS
718 printf("xmlTextReaderCharacters()\n");
719#endif
720 if ((reader != NULL) && (reader->characters != NULL)) {
721 reader->characters(ctx, ch, len);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000722 }
723}
724
725/**
726 * xmlTextReaderCDataBlock:
727 * @ctx: the user data (XML parser context)
728 * @value: The pcdata content
729 * @len: the block length
730 *
731 * called when a pcdata block has been parsed
732 */
733static void
734xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
735{
736 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
737 xmlTextReaderPtr reader = ctxt->_private;
738
739#ifdef DEBUG_CALLBACKS
740 printf("xmlTextReaderCDataBlock()\n");
741#endif
742 if ((reader != NULL) && (reader->cdataBlock != NULL)) {
743 reader->cdataBlock(ctx, ch, len);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000744 }
745}
746
747/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000748 * xmlTextReaderPushData:
749 * @reader: the xmlTextReaderPtr used
750 *
751 * Push data down the progressive parser until a significant callback
752 * got raised.
753 *
754 * Returns -1 in case of failure, 0 otherwise
755 */
756static int
757xmlTextReaderPushData(xmlTextReaderPtr reader) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000758 xmlBufferPtr inbuf;
Daniel Veillarda880b122003-04-21 21:36:41 +0000759 int val, s;
William M. Brack779af002003-08-01 15:55:39 +0000760 xmlTextReaderState oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000761
762 if ((reader->input == NULL) || (reader->input->buffer == NULL))
763 return(-1);
764
Daniel Veillardea7751d2002-12-20 00:16:24 +0000765 oldstate = reader->state;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000766 reader->state = XML_TEXTREADER_NONE;
767 inbuf = reader->input->buffer;
Daniel Veillarda880b122003-04-21 21:36:41 +0000768
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000769 while (reader->state == XML_TEXTREADER_NONE) {
Daniel Veillarda880b122003-04-21 21:36:41 +0000770 if (inbuf->use < reader->cur + CHUNK_SIZE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000771 /*
772 * Refill the buffer unless we are at the end of the stream
773 */
774 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
775 val = xmlParserInputBufferRead(reader->input, 4096);
Daniel Veillard53350552003-09-18 13:35:51 +0000776 if ((val == 0) &&
777 (inbuf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) {
778 if (inbuf->use == reader->cur) {
779 reader->mode = XML_TEXTREADER_MODE_EOF;
780 reader->state = oldstate;
781 if ((oldstate != XML_TEXTREADER_START) ||
782 (reader->ctxt->myDoc != NULL))
783 return(val);
784 }
785 } else if (val < 0) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000786 reader->mode = XML_TEXTREADER_MODE_EOF;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000787 reader->state = oldstate;
Daniel Veillardaaa105b2002-12-30 11:42:17 +0000788 if ((oldstate != XML_TEXTREADER_START) ||
789 (reader->ctxt->myDoc != NULL))
790 return(val);
Daniel Veillard53350552003-09-18 13:35:51 +0000791 } else if (val == 0) {
792 /* mark the end of the stream and process the remains */
793 reader->mode = XML_TEXTREADER_MODE_EOF;
794 break;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000795 }
Daniel Veillarda880b122003-04-21 21:36:41 +0000796
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000797 } else
798 break;
799 }
Daniel Veillard067bae52003-01-05 01:27:54 +0000800 /*
Daniel Veillarda880b122003-04-21 21:36:41 +0000801 * parse by block of CHUNK_SIZE bytes, various tests show that
802 * it's the best tradeoff at least on a 1.2GH Duron
Daniel Veillard067bae52003-01-05 01:27:54 +0000803 */
Daniel Veillarda880b122003-04-21 21:36:41 +0000804 if (inbuf->use >= reader->cur + CHUNK_SIZE) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000805 val = xmlParseChunk(reader->ctxt,
806 (const char *) &inbuf->content[reader->cur],
Daniel Veillarda880b122003-04-21 21:36:41 +0000807 CHUNK_SIZE, 0);
808 reader->cur += CHUNK_SIZE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000809 if (val != 0)
810 return(-1);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000811 } else {
Daniel Veillarda880b122003-04-21 21:36:41 +0000812 s = inbuf->use - reader->cur;
813 val = xmlParseChunk(reader->ctxt,
814 (const char *) &inbuf->content[reader->cur],
815 s, 0);
816 reader->cur += s;
817 if (val != 0)
818 return(-1);
819 break;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000820 }
821 }
Daniel Veillarda880b122003-04-21 21:36:41 +0000822
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000823 /*
824 * Discard the consumed input when needed and possible
825 */
Daniel Veillard67df8092002-12-16 22:04:11 +0000826 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
Daniel Veillardf6bc7c22003-09-17 22:33:22 +0000827 if ((reader->cur >= 4096) &&
828 (inbuf->use - reader->cur <= CHUNK_SIZE)) {
Daniel Veillarda880b122003-04-21 21:36:41 +0000829 val = xmlBufferShrink(inbuf, reader->cur);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000830 if (val >= 0) {
831 reader->cur -= val;
832 }
833 }
834 }
835
836 /*
837 * At the end of the stream signal that the work is done to the Push
838 * parser.
839 */
Daniel Veillarda880b122003-04-21 21:36:41 +0000840 else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000841 if (reader->mode != XML_TEXTREADER_DONE) {
Daniel Veillarda880b122003-04-21 21:36:41 +0000842 s = inbuf->use - reader->cur;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000843 val = xmlParseChunk(reader->ctxt,
Daniel Veillard067bae52003-01-05 01:27:54 +0000844 (const char *) &inbuf->content[reader->cur],
Daniel Veillarda880b122003-04-21 21:36:41 +0000845 s, 1);
846 reader->cur = inbuf->use;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000847 reader->mode = XML_TEXTREADER_DONE;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000848 if (val != 0) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000849 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000850 }
Daniel Veillardea7751d2002-12-20 00:16:24 +0000851 reader->state = oldstate;
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000852 return(0);
853}
854
855/**
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000856 * xmlTextReaderValidatePush:
857 * @reader: the xmlTextReaderPtr used
858 *
859 * Push the current node for validation
860 */
861static void
862xmlTextReaderValidatePush(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000863#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000864 xmlNodePtr node = reader->node;
865
Daniel Veillardf4e55762003-04-15 23:32:22 +0000866 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
867 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
868 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
869 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
870 reader->ctxt->myDoc, node, node->name);
871 } else {
872 /* TODO use the BuildQName interface */
873 xmlChar *qname;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000874
Daniel Veillardf4e55762003-04-15 23:32:22 +0000875 qname = xmlStrdup(node->ns->prefix);
876 qname = xmlStrcat(qname, BAD_CAST ":");
877 qname = xmlStrcat(qname, node->name);
878 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
879 reader->ctxt->myDoc, node, qname);
880 if (qname != NULL)
881 xmlFree(qname);
882 }
883#ifdef LIBXML_SCHEMAS_ENABLED
884 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
885 (reader->rngValidCtxt != NULL)) {
886 int ret;
887
888 if (reader->rngFullNode != NULL) return;
889 ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
890 reader->ctxt->myDoc,
891 node);
892 if (ret == 0) {
893 /*
894 * this element requires a full tree
895 */
896 node = xmlTextReaderExpand(reader);
897 if (node == NULL) {
898printf("Expand failed !\n");
899 ret = -1;
900 } else {
901 ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt,
902 reader->ctxt->myDoc,
903 node);
904 reader->rngFullNode = node;
905 }
906 }
907 if (ret != 1)
908 reader->rngValidErrors++;
909#endif
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000910 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000911#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000912}
Daniel Veillardf4e55762003-04-15 23:32:22 +0000913
914/**
915 * xmlTextReaderValidateCData:
916 * @reader: the xmlTextReaderPtr used
917 * @data: pointer to the CData
918 * @len: lenght of the CData block in bytes.
919 *
920 * Push some CData for validation
921 */
922static void
923xmlTextReaderValidateCData(xmlTextReaderPtr reader,
924 const xmlChar *data, int len) {
925#ifdef LIBXML_REGEXP_ENABLED
926 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
927 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
928 reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt,
929 data, len);
930#ifdef LIBXML_SCHEMAS_ENABLED
931 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
932 (reader->rngValidCtxt != NULL)) {
933 int ret;
934
935 if (reader->rngFullNode != NULL) return;
936 ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len);
937 if (ret != 1)
938 reader->rngValidErrors++;
939#endif
940 }
941#endif /* LIBXML_REGEXP_ENABLED */
942}
943
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000944/**
945 * xmlTextReaderValidatePop:
946 * @reader: the xmlTextReaderPtr used
947 *
948 * Pop the current node from validation
949 */
950static void
951xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000952#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000953 xmlNodePtr node = reader->node;
954
Daniel Veillardf4e55762003-04-15 23:32:22 +0000955 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
956 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
957 if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
958 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
959 reader->ctxt->myDoc, node, node->name);
960 } else {
961 /* TODO use the BuildQName interface */
962 xmlChar *qname;
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000963
Daniel Veillardf4e55762003-04-15 23:32:22 +0000964 qname = xmlStrdup(node->ns->prefix);
965 qname = xmlStrcat(qname, BAD_CAST ":");
966 qname = xmlStrcat(qname, node->name);
967 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
968 reader->ctxt->myDoc, node, qname);
969 if (qname != NULL)
970 xmlFree(qname);
971 }
972#ifdef LIBXML_SCHEMAS_ENABLED
973 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
974 (reader->rngValidCtxt != NULL)) {
975 int ret;
976
977 if (reader->rngFullNode != NULL) {
978 if (node == reader->rngFullNode)
979 reader->rngFullNode = NULL;
980 return;
981 }
982 ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
983 reader->ctxt->myDoc,
984 node);
985 if (ret != 1)
986 reader->rngValidErrors++;
987#endif
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000988 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +0000989#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard1fdfd112003-01-03 01:18:43 +0000990}
Daniel Veillarda80ff6e2003-01-03 12:52:08 +0000991/**
992 * xmlTextReaderValidateEntity:
993 * @reader: the xmlTextReaderPtr used
994 *
995 * Handle the validation when an entity reference is encountered and
996 * entity substitution is not activated. As a result the parser interface
997 * must walk through the entity and do the validation calls
998 */
999static void
1000xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
Daniel Veillard0e298ad2003-02-04 16:14:33 +00001001#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001002 xmlNodePtr oldnode = reader->node;
1003 xmlNodePtr node = reader->node;
1004 xmlParserCtxtPtr ctxt = reader->ctxt;
1005
1006 do {
1007 if (node->type == XML_ENTITY_REF_NODE) {
1008 /*
1009 * Case where the underlying tree is not availble, lookup the entity
1010 * and walk it.
1011 */
1012 if ((node->children == NULL) && (ctxt->sax != NULL) &&
1013 (ctxt->sax->getEntity != NULL)) {
1014 node->children = (xmlNodePtr)
1015 ctxt->sax->getEntity(ctxt, node->name);
1016 }
1017
1018 if ((node->children != NULL) &&
1019 (node->children->type == XML_ENTITY_DECL) &&
1020 (node->children->children != NULL)) {
1021 xmlTextReaderEntPush(reader, node);
1022 node = node->children->children;
1023 continue;
1024 } else {
1025 /*
1026 * The error has probably be raised already.
1027 */
1028 if (node == oldnode)
1029 break;
1030 node = node->next;
1031 }
1032 } else if (node->type == XML_ELEMENT_NODE) {
1033 reader->node = node;
1034 xmlTextReaderValidatePush(reader);
1035 } else if ((node->type == XML_TEXT_NODE) ||
1036 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00001037 xmlTextReaderValidateCData(reader, node->content,
1038 xmlStrlen(node->content));
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001039 }
1040
1041 /*
1042 * go to next node
1043 */
1044 if (node->children != NULL) {
1045 node = node->children;
1046 continue;
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00001047 } else if (node->type == XML_ELEMENT_NODE) {
1048 xmlTextReaderValidatePop(reader);
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001049 }
1050 if (node->next != NULL) {
1051 node = node->next;
1052 continue;
1053 }
1054 do {
1055 node = node->parent;
1056 if (node->type == XML_ELEMENT_NODE) {
1057 reader->node = node;
1058 xmlTextReaderValidatePop(reader);
1059 }
1060 if ((node->type == XML_ENTITY_DECL) &&
1061 (reader->ent != NULL) && (reader->ent->children == node)) {
1062 node = xmlTextReaderEntPop(reader);
1063 }
1064 if (node == oldnode)
1065 break;
1066 if (node->next != NULL) {
1067 node = node->next;
1068 break;
1069 }
1070 } while ((node != NULL) && (node != oldnode));
1071 } while ((node != NULL) && (node != oldnode));
1072 reader->node = oldnode;
Daniel Veillard0e298ad2003-02-04 16:14:33 +00001073#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001074}
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001075
1076
1077/**
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001078 * xmlTextReaderGetSuccessor:
1079 * @cur: the current node
1080 *
1081 * Get the successor of a node if available.
1082 *
1083 * Returns the successor node or NULL
1084 */
1085static xmlNodePtr
1086xmlTextReaderGetSuccessor(xmlNodePtr cur) {
1087 if (cur == NULL) return(NULL) ; /* ERROR */
1088 if (cur->next != NULL) return(cur->next) ;
1089 do {
1090 cur = cur->parent;
1091 if (cur == NULL) return(NULL);
1092 if (cur->next != NULL) return(cur->next);
1093 } while (cur != NULL);
1094 return(cur);
1095}
1096
1097/**
1098 * xmlTextReaderDoExpand:
1099 * @reader: the xmlTextReaderPtr used
1100 *
1101 * Makes sure that the current node is fully read as well as all its
1102 * descendant. It means the full DOM subtree must be available at the
1103 * end of the call.
1104 *
1105 * Returns 1 if the node was expanded successfully, 0 if there is no more
1106 * nodes to read, or -1 in case of error
1107 */
1108static int
1109xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
1110 int val;
1111
1112 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
1113 return(-1);
1114
1115 do {
1116 if (xmlTextReaderGetSuccessor(reader->node) != NULL)
1117 return(1);
Daniel Veillarda37aab82003-06-09 09:10:36 +00001118 if (reader->ctxt->nodeNr <= reader->depth)
1119 return(1);
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001120 if (reader->mode == XML_TEXTREADER_MODE_EOF)
1121 return(1);
1122 val = xmlTextReaderPushData(reader);
1123 if (val < 0)
1124 return(-1);
1125 } while(reader->mode != XML_TEXTREADER_MODE_EOF);
1126 return(1);
1127}
1128
1129/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001130 * xmlTextReaderRead:
1131 * @reader: the xmlTextReaderPtr used
1132 *
1133 * Moves the position of the current instance to the next node in
1134 * the stream, exposing its properties.
1135 *
1136 * Returns 1 if the node was read successfully, 0 if there is no more
1137 * nodes to read, or -1 in case of error
1138 */
1139int
1140xmlTextReaderRead(xmlTextReaderPtr reader) {
Daniel Veillard067bae52003-01-05 01:27:54 +00001141 int val, olddepth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001142 xmlTextReaderState oldstate = 0;
1143 xmlNodePtr oldnode = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001144
1145 if ((reader == NULL) || (reader->ctxt == NULL))
1146 return(-1);
1147 if (reader->ctxt->wellFormed != 1)
1148 return(-1);
1149
1150#ifdef DEBUG_READER
1151 fprintf(stderr, "\nREAD ");
1152 DUMP_READER
1153#endif
Daniel Veillard29b3e282002-12-29 11:14:41 +00001154 reader->curnode = NULL;
Daniel Veillard67df8092002-12-16 22:04:11 +00001155 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
1156 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001157 /*
1158 * Initial state
1159 */
1160 do {
1161 val = xmlTextReaderPushData(reader);
1162 if (val < 0)
1163 return(-1);
1164 } while ((reader->ctxt->node == NULL) &&
Daniel Veillard067bae52003-01-05 01:27:54 +00001165 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
1166 (reader->mode != XML_TEXTREADER_DONE)));
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001167 if (reader->ctxt->myDoc != NULL)
1168 reader->ctxt->myDoc->_private = reader;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001169 if (reader->ctxt->node == NULL) {
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001170 if (reader->ctxt->myDoc != NULL) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001171 reader->node = reader->ctxt->myDoc->children;
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001172 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001173 if (reader->node == NULL)
1174 return(-1);
Daniel Veillarddab8ea92003-01-02 14:16:45 +00001175 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001176 } else {
Daniel Veillard48ef4c92003-03-22 12:38:15 +00001177 if (reader->ctxt->myDoc != NULL) {
1178 reader->node = reader->ctxt->myDoc->children;
1179 }
1180 if (reader->node == NULL)
1181 reader->node = reader->ctxt->nodeTab[0];
Daniel Veillarde59494f2003-01-04 16:35:29 +00001182 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001183 }
Daniel Veillard4d8db8a2002-12-30 18:40:42 +00001184 reader->depth = 0;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001185 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001186 }
1187 oldstate = reader->state;
1188 olddepth = reader->ctxt->nodeNr;
1189 oldnode = reader->node;
Daniel Veillarddf512f42002-12-23 15:56:21 +00001190
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001191get_next_node:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001192 /*
1193 * If we are not backtracking on ancestors or examined nodes,
1194 * that the parser didn't finished or that we arent at the end
1195 * of stream, continue processing.
1196 */
Daniel Veillarda880b122003-04-21 21:36:41 +00001197 while ((reader->node->next == NULL) &&
1198 (reader->ctxt->nodeNr == olddepth) &&
1199 ((oldstate == XML_TEXTREADER_BACKTRACK) ||
Daniel Veillardea7751d2002-12-20 00:16:24 +00001200 (reader->node->children == NULL) ||
1201 (reader->node->type == XML_ENTITY_REF_NODE) ||
Daniel Veillard409a8142003-07-18 15:16:57 +00001202 ((reader->node->children != NULL) &&
1203 (reader->node->children->type == XML_TEXT_NODE) &&
1204 (reader->node->children->next == NULL)) ||
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00001205 (reader->node->type == XML_DTD_NODE) ||
1206 (reader->node->type == XML_DOCUMENT_NODE) ||
1207 (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00001208 ((reader->ctxt->node == NULL) ||
1209 (reader->ctxt->node == reader->node) ||
1210 (reader->ctxt->node == reader->node->parent)) &&
Daniel Veillardea7751d2002-12-20 00:16:24 +00001211 (reader->ctxt->instate != XML_PARSER_EOF)) {
1212 val = xmlTextReaderPushData(reader);
1213 if (val < 0)
1214 return(-1);
1215 if (reader->node == NULL)
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001216 goto node_end;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001217 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001218 if (oldstate != XML_TEXTREADER_BACKTRACK) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001219 if ((reader->node->children != NULL) &&
1220 (reader->node->type != XML_ENTITY_REF_NODE) &&
1221 (reader->node->type != XML_DTD_NODE)) {
1222 reader->node = reader->node->children;
1223 reader->depth++;
Daniel Veillarddf512f42002-12-23 15:56:21 +00001224 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001225 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001226 }
1227 }
1228 if (reader->node->next != NULL) {
1229 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillarddf512f42002-12-23 15:56:21 +00001230 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +00001231 (reader->node->children == NULL) &&
1232 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001233 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001234 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001235 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00001236 if ((reader->validate) &&
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001237 (reader->node->type == XML_ELEMENT_NODE))
1238 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001239 reader->node = reader->node->next;
1240 reader->state = XML_TEXTREADER_ELEMENT;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001241
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001242 /*
1243 * Cleanup of the old node
1244 */
Daniel Veillard4dbe77a2003-01-14 00:17:42 +00001245 if ((reader->node->prev != NULL) &&
1246 (reader->node->prev->type != XML_DTD_NODE)) {
1247 xmlNodePtr tmp = reader->node->prev;
1248 xmlUnlinkNode(tmp);
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001249 xmlTextReaderFreeNode(reader, tmp);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001250 }
1251
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001252 goto node_found;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001253 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00001254 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
Daniel Veillard571b8892002-12-30 12:37:59 +00001255 (reader->node->type == XML_ELEMENT_NODE) &&
Daniel Veillard067bae52003-01-05 01:27:54 +00001256 (reader->node->children == NULL) &&
1257 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00001258 reader->state = XML_TEXTREADER_END;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001259 goto node_found;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001260 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00001261 if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE))
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001262 xmlTextReaderValidatePop(reader);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001263 reader->node = reader->node->parent;
1264 if ((reader->node == NULL) ||
1265 (reader->node->type == XML_DOCUMENT_NODE) ||
1266#ifdef LIBXML_DOCB_ENABLED
1267 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
1268#endif
1269 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00001270 if (reader->mode != XML_TEXTREADER_DONE) {
1271 val = xmlParseChunk(reader->ctxt, "", 0, 1);
1272 reader->mode = XML_TEXTREADER_DONE;
1273 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001274 reader->node = NULL;
Daniel Veillard4d8db8a2002-12-30 18:40:42 +00001275 reader->depth = -1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001276
1277 /*
1278 * Cleanup of the old node
1279 */
1280 if (oldnode->type != XML_DTD_NODE) {
1281 xmlUnlinkNode(oldnode);
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001282 xmlTextReaderFreeNode(reader, oldnode);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001283 }
1284
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001285 goto node_end;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001286 }
1287 reader->depth--;
1288 reader->state = XML_TEXTREADER_BACKTRACK;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001289
1290node_found:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001291 DUMP_READER
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001292
1293 /*
Daniel Veillarda880b122003-04-21 21:36:41 +00001294 * If we are in the middle of a piece of CDATA make sure it's finished
1295 */
1296 if ((reader->node != NULL) &&
Daniel Veillardccc4d2b2003-09-17 21:27:31 +00001297 (reader->node->next == NULL) &&
Daniel Veillarda880b122003-04-21 21:36:41 +00001298 ((reader->node->type == XML_TEXT_NODE) ||
1299 (reader->node->type == XML_CDATA_SECTION_NODE))) {
1300 xmlTextReaderExpand(reader);
1301 }
1302
1303 /*
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001304 * Handle entities enter and exit when in entity replacement mode
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001305 */
1306 if ((reader->node != NULL) &&
1307 (reader->node->type == XML_ENTITY_REF_NODE) &&
1308 (reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
1309 /*
1310 * Case where the underlying tree is not availble, lookup the entity
1311 * and walk it.
1312 */
1313 if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
1314 (reader->ctxt->sax->getEntity != NULL)) {
1315 reader->node->children = (xmlNodePtr)
1316 reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
1317 }
1318
1319 if ((reader->node->children != NULL) &&
1320 (reader->node->children->type == XML_ENTITY_DECL) &&
1321 (reader->node->children->children != NULL)) {
1322 xmlTextReaderEntPush(reader, reader->node);
1323 reader->node = reader->node->children->children;
1324 }
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001325 } else if ((reader->node != NULL) &&
1326 (reader->node->type == XML_ENTITY_REF_NODE) &&
Daniel Veillardf4e55762003-04-15 23:32:22 +00001327 (reader->ctxt != NULL) && (reader->validate)) {
Daniel Veillarda80ff6e2003-01-03 12:52:08 +00001328 xmlTextReaderValidateEntity(reader);
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001329 }
1330 if ((reader->node != NULL) &&
1331 (reader->node->type == XML_ENTITY_DECL) &&
1332 (reader->ent != NULL) && (reader->ent->children == reader->node)) {
1333 reader->node = xmlTextReaderEntPop(reader);
1334 reader->depth++;
1335 goto get_next_node;
1336 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +00001337#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardf4e55762003-04-15 23:32:22 +00001338 if ((reader->validate) && (reader->node != NULL)) {
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001339 xmlNodePtr node = reader->node;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001340
1341 if ((node->type == XML_ELEMENT_NODE) &&
1342 ((reader->state != XML_TEXTREADER_END) &&
1343 (reader->state != XML_TEXTREADER_BACKTRACK))) {
1344 xmlTextReaderValidatePush(reader);
1345 } else if ((node->type == XML_TEXT_NODE) ||
1346 (node->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00001347 xmlTextReaderValidateCData(reader, node->content,
1348 xmlStrlen(node->content));
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001349 }
1350 }
Daniel Veillard0e298ad2003-02-04 16:14:33 +00001351#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001352 return(1);
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001353node_end:
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001354 reader->mode = XML_TEXTREADER_DONE;
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001355 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001356}
1357
Daniel Veillard67df8092002-12-16 22:04:11 +00001358/**
1359 * xmlTextReaderReadState:
1360 * @reader: the xmlTextReaderPtr used
1361 *
1362 * Gets the read state of the reader.
1363 *
1364 * Returns the state value, or -1 in case of error
1365 */
1366int
1367xmlTextReaderReadState(xmlTextReaderPtr reader) {
1368 if (reader == NULL)
1369 return(-1);
1370 return(reader->mode);
1371}
1372
1373/**
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001374 * xmlTextReaderExpand:
1375 * @reader: the xmlTextReaderPtr used
1376 *
1377 * Reads the contents of the current node and the full subtree. It then makes
Daniel Veillard61c52202003-04-30 12:20:34 +00001378 * the subtree available until the next xmlTextReaderRead() call
Daniel Veillardc6cae7b2003-04-11 09:02:11 +00001379 *
1380 * Returns a node pointer valid until the next xmlTextReaderRead() call
1381 * or NULL in case of error.
1382 */
1383xmlNodePtr
1384xmlTextReaderExpand(xmlTextReaderPtr reader) {
1385 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
1386 return(NULL);
1387 if (xmlTextReaderDoExpand(reader) < 0)
1388 return(NULL);
1389 return(reader->node);
1390}
1391
1392/**
1393 * xmlTextReaderNext:
1394 * @reader: the xmlTextReaderPtr used
1395 *
1396 * Skip to the node following the current one in document order while
1397 * avoiding the subtree if any.
1398 *
1399 * Returns 1 if the node was read successfully, 0 if there is no more
1400 * nodes to read, or -1 in case of error
1401 */
1402int
1403xmlTextReaderNext(xmlTextReaderPtr reader) {
1404 int ret;
1405 xmlNodePtr cur;
1406
1407 if (reader == NULL)
1408 return(-1);
1409 cur = reader->node;
1410 if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
1411 return(xmlTextReaderRead(reader));
1412 if (reader->state == XML_TEXTREADER_END)
1413 return(xmlTextReaderRead(reader));
1414 if (cur->_private == (void *)xmlTextReaderIsEmpty)
1415 return(xmlTextReaderRead(reader));
1416 do {
1417 ret = xmlTextReaderRead(reader);
1418 if (ret != 1)
1419 return(ret);
1420 } while (reader->node != cur);
1421 return(xmlTextReaderRead(reader));
1422}
1423
1424/**
Daniel Veillard67df8092002-12-16 22:04:11 +00001425 * xmlTextReaderReadInnerXml:
1426 * @reader: the xmlTextReaderPtr used
1427 *
1428 * Reads the contents of the current node, including child nodes and markup.
1429 *
1430 * Returns a string containing the XML content, or NULL if the current node
1431 * is neither an element nor attribute, or has no child nodes. The
1432 * string must be deallocated by the caller.
1433 */
1434xmlChar *
Daniel Veillard33300b42003-04-17 09:09:19 +00001435xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
Daniel Veillard67df8092002-12-16 22:04:11 +00001436 TODO
1437 return(NULL);
1438}
1439
1440/**
1441 * xmlTextReaderReadOuterXml:
1442 * @reader: the xmlTextReaderPtr used
1443 *
1444 * Reads the contents of the current node, including child nodes and markup.
1445 *
1446 * Returns a string containing the XML content, or NULL if the current node
1447 * is neither an element nor attribute, or has no child nodes. The
1448 * string must be deallocated by the caller.
1449 */
1450xmlChar *
Daniel Veillard33300b42003-04-17 09:09:19 +00001451xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
Daniel Veillard67df8092002-12-16 22:04:11 +00001452 TODO
1453 return(NULL);
1454}
1455
1456/**
1457 * xmlTextReaderReadString:
1458 * @reader: the xmlTextReaderPtr used
1459 *
1460 * Reads the contents of an element or a text node as a string.
1461 *
1462 * Returns a string containing the contents of the Element or Text node,
1463 * or NULL if the reader is positioned on any other type of node.
1464 * The string must be deallocated by the caller.
1465 */
1466xmlChar *
Daniel Veillard33300b42003-04-17 09:09:19 +00001467xmlTextReaderReadString(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
Daniel Veillard67df8092002-12-16 22:04:11 +00001468 TODO
1469 return(NULL);
1470}
1471
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001472#if 0
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001473/**
1474 * xmlTextReaderReadBase64:
1475 * @reader: the xmlTextReaderPtr used
1476 * @array: a byte array to store the content.
1477 * @offset: the zero-based index into array where the method should
1478 * begin to write.
1479 * @len: the number of bytes to write.
1480 *
1481 * Reads and decodes the Base64 encoded contents of an element and
1482 * stores the result in a byte buffer.
1483 *
1484 * Returns the number of bytes written to array, or zero if the current
1485 * instance is not positioned on an element or -1 in case of error.
1486 */
1487int
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001488xmlTextReaderReadBase64(xmlTextReaderPtr reader,
1489 unsigned char *array ATTRIBUTE_UNUSED,
1490 int offset ATTRIBUTE_UNUSED,
1491 int len ATTRIBUTE_UNUSED) {
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001492 if ((reader == NULL) || (reader->ctxt == NULL))
1493 return(-1);
1494 if (reader->ctxt->wellFormed != 1)
1495 return(-1);
1496
1497 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1498 return(0);
1499 TODO
1500 return(0);
1501}
1502
1503/**
1504 * xmlTextReaderReadBinHex:
1505 * @reader: the xmlTextReaderPtr used
1506 * @array: a byte array to store the content.
1507 * @offset: the zero-based index into array where the method should
1508 * begin to write.
1509 * @len: the number of bytes to write.
1510 *
1511 * Reads and decodes the BinHex encoded contents of an element and
1512 * stores the result in a byte buffer.
1513 *
1514 * Returns the number of bytes written to array, or zero if the current
1515 * instance is not positioned on an element or -1 in case of error.
1516 */
1517int
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001518xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
1519 unsigned char *array ATTRIBUTE_UNUSED,
1520 int offset ATTRIBUTE_UNUSED,
1521 int len ATTRIBUTE_UNUSED) {
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001522 if ((reader == NULL) || (reader->ctxt == NULL))
1523 return(-1);
1524 if (reader->ctxt->wellFormed != 1)
1525 return(-1);
1526
1527 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1528 return(0);
1529 TODO
1530 return(0);
1531}
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001532#endif
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001533
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001534/************************************************************************
1535 * *
1536 * Constructor and destructors *
1537 * *
1538 ************************************************************************/
1539/**
1540 * xmlNewTextReader:
1541 * @input: the xmlParserInputBufferPtr used to read data
Daniel Veillardea7751d2002-12-20 00:16:24 +00001542 * @URI: the URI information for the source if available
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001543 *
1544 * Create an xmlTextReader structure fed with @input
1545 *
1546 * Returns the new xmlTextReaderPtr or NULL in case of error
1547 */
1548xmlTextReaderPtr
Daniel Veillardea7751d2002-12-20 00:16:24 +00001549xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001550 xmlTextReaderPtr ret;
1551 int val;
1552
1553 if (input == NULL)
1554 return(NULL);
1555 ret = xmlMalloc(sizeof(xmlTextReader));
1556 if (ret == NULL) {
1557 xmlGenericError(xmlGenericErrorContext,
1558 "xmlNewTextReader : malloc failed\n");
1559 return(NULL);
1560 }
1561 memset(ret, 0, sizeof(xmlTextReader));
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001562 ret->entTab = NULL;
1563 ret->entMax = 0;
1564 ret->entNr = 0;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001565 ret->input = input;
1566 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
1567 if (ret->sax == NULL) {
1568 xmlFree(ret);
1569 xmlGenericError(xmlGenericErrorContext,
1570 "xmlNewTextReader : malloc failed\n");
1571 return(NULL);
1572 }
1573 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
1574 ret->startElement = ret->sax->startElement;
1575 ret->sax->startElement = xmlTextReaderStartElement;
1576 ret->endElement = ret->sax->endElement;
1577 ret->sax->endElement = xmlTextReaderEndElement;
Daniel Veillard07cb8222003-09-10 10:51:05 +00001578 if (ret->sax->initialized == XML_SAX2_MAGIC) {
1579 ret->startElementNs = ret->sax->startElementNs;
1580 ret->sax->startElementNs = xmlTextReaderStartElementNs;
1581 ret->endElementNs = ret->sax->endElementNs;
1582 ret->sax->endElementNs = xmlTextReaderEndElementNs;
1583 } else {
1584 ret->startElementNs = NULL;
1585 ret->endElementNs = NULL;
1586 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00001587 ret->characters = ret->sax->characters;
1588 ret->sax->characters = xmlTextReaderCharacters;
Daniel Veillard40412cd2003-09-03 13:28:32 +00001589 ret->sax->ignorableWhitespace = xmlTextReaderCharacters;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001590 ret->cdataBlock = ret->sax->cdataBlock;
1591 ret->sax->cdataBlock = xmlTextReaderCDataBlock;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001592
Daniel Veillard67df8092002-12-16 22:04:11 +00001593 ret->mode = XML_TEXTREADER_MODE_INITIAL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001594 ret->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001595 ret->curnode = NULL;
Daniel Veillard53350552003-09-18 13:35:51 +00001596 if (ret->input->buffer->use < 4) {
1597 val = xmlParserInputBufferRead(input, 4);
1598 }
1599 if (ret->input->buffer->use >= 4) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001600 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
Daniel Veillardea7751d2002-12-20 00:16:24 +00001601 (const char *) ret->input->buffer->content, 4, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001602 ret->base = 0;
1603 ret->cur = 4;
1604 } else {
Daniel Veillardea7751d2002-12-20 00:16:24 +00001605 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001606 ret->base = 0;
1607 ret->cur = 0;
1608 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001609 if (ret->ctxt == NULL) {
1610 xmlGenericError(xmlGenericErrorContext,
1611 "xmlNewTextReader : malloc failed\n");
1612 xmlFree(ret->sax);
1613 xmlFree(ret);
1614 return(NULL);
1615 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001616 ret->ctxt->_private = ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001617 ret->ctxt->linenumbers = 1;
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001618 ret->ctxt->dictNames = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001619 ret->allocs = XML_TEXTREADER_CTXT;
Daniel Veillard40412cd2003-09-03 13:28:32 +00001620 /*
1621 * use the parser dictionnary to allocate all elements and attributes names
1622 */
1623 ret->ctxt->docdict = 1;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001624 return(ret);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001625}
1626
1627/**
1628 * xmlNewTextReaderFilename:
1629 * @URI: the URI of the resource to process
1630 *
1631 * Create an xmlTextReader structure fed with the resource at @URI
1632 *
1633 * Returns the new xmlTextReaderPtr or NULL in case of error
1634 */
1635xmlTextReaderPtr
1636xmlNewTextReaderFilename(const char *URI) {
1637 xmlParserInputBufferPtr input;
1638 xmlTextReaderPtr ret;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001639 char *directory = NULL;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001640
1641 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
1642 if (input == NULL)
1643 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00001644 ret = xmlNewTextReader(input, URI);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001645 if (ret == NULL) {
1646 xmlFreeParserInputBuffer(input);
1647 return(NULL);
1648 }
1649 ret->allocs |= XML_TEXTREADER_INPUT;
Daniel Veillardea7751d2002-12-20 00:16:24 +00001650 if (ret->ctxt->directory == NULL)
1651 directory = xmlParserGetDirectory(URI);
1652 if ((ret->ctxt->directory == NULL) && (directory != NULL))
1653 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
1654 if (directory != NULL)
1655 xmlFree(directory);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001656 return(ret);
1657}
1658
1659/**
1660 * xmlFreeTextReader:
1661 * @reader: the xmlTextReaderPtr
1662 *
1663 * Deallocate all the resources associated to the reader
1664 */
1665void
1666xmlFreeTextReader(xmlTextReaderPtr reader) {
1667 if (reader == NULL)
1668 return;
Daniel Veillard37fc84d2003-05-09 19:38:15 +00001669#ifdef LIBXML_SCHEMAS_ENABLED
Daniel Veillardf4e55762003-04-15 23:32:22 +00001670 if (reader->rngSchemas != NULL) {
1671 xmlRelaxNGFree(reader->rngSchemas);
1672 reader->rngSchemas = NULL;
1673 }
1674 if (reader->rngValidCtxt != NULL) {
1675 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
1676 reader->rngValidCtxt = NULL;
1677 }
Daniel Veillard37fc84d2003-05-09 19:38:15 +00001678#endif
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001679 if (reader->ctxt != NULL) {
1680 if (reader->ctxt->myDoc != NULL) {
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00001681 xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001682 reader->ctxt->myDoc = NULL;
1683 }
Daniel Veillard336fc7d2002-12-27 19:37:04 +00001684 if ((reader->ctxt->vctxt.vstateTab != NULL) &&
1685 (reader->ctxt->vctxt.vstateMax > 0)){
1686 xmlFree(reader->ctxt->vctxt.vstateTab);
1687 reader->ctxt->vctxt.vstateTab = 0;
1688 reader->ctxt->vctxt.vstateMax = 0;
1689 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001690 if (reader->allocs & XML_TEXTREADER_CTXT)
1691 xmlFreeParserCtxt(reader->ctxt);
1692 }
1693 if (reader->sax != NULL)
1694 xmlFree(reader->sax);
1695 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
1696 xmlFreeParserInputBuffer(reader->input);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00001697 if (reader->faketext != NULL) {
1698 xmlFreeNode(reader->faketext);
1699 }
Daniel Veillard1fdfd112003-01-03 01:18:43 +00001700 if (reader->entTab != NULL)
1701 xmlFree(reader->entTab);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001702 xmlFree(reader);
1703}
1704
1705/************************************************************************
1706 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001707 * Methods for XmlTextReader *
1708 * *
1709 ************************************************************************/
1710/**
1711 * xmlTextReaderClose:
1712 * @reader: the xmlTextReaderPtr used
1713 *
1714 * This method releases any resources allocated by the current instance
1715 * changes the state to Closed and close any underlying input.
1716 *
1717 * Returns 0 or -1 in case of error
1718 */
1719int
1720xmlTextReaderClose(xmlTextReaderPtr reader) {
1721 if (reader == NULL)
1722 return(-1);
1723 reader->node = NULL;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001724 reader->curnode = NULL;
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001725 reader->mode = XML_TEXTREADER_MODE_CLOSED;
1726 if (reader->ctxt != NULL) {
1727 if (reader->ctxt->myDoc != NULL) {
1728 xmlFreeDoc(reader->ctxt->myDoc);
1729 reader->ctxt->myDoc = NULL;
1730 }
1731 if (reader->allocs & XML_TEXTREADER_CTXT) {
1732 xmlFreeParserCtxt(reader->ctxt);
1733 reader->allocs -= XML_TEXTREADER_CTXT;
1734 }
1735 }
1736 if (reader->sax != NULL) {
1737 xmlFree(reader->sax);
1738 reader->sax = NULL;
1739 }
1740 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
1741 xmlFreeParserInputBuffer(reader->input);
1742 reader->allocs -= XML_TEXTREADER_INPUT;
1743 }
1744 return(0);
1745}
1746
1747/**
1748 * xmlTextReaderGetAttributeNo:
1749 * @reader: the xmlTextReaderPtr used
1750 * @no: the zero-based index of the attribute relative to the containing element
1751 *
1752 * Provides the value of the attribute with the specified index relative
1753 * to the containing element.
1754 *
1755 * Returns a string containing the value of the specified attribute, or NULL
1756 * in case of error. The string must be deallocated by the caller.
1757 */
1758xmlChar *
1759xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
1760 xmlChar *ret;
1761 int i;
1762 xmlAttrPtr cur;
1763 xmlNsPtr ns;
1764
1765 if (reader == NULL)
1766 return(NULL);
1767 if (reader->node == NULL)
1768 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001769 if (reader->curnode != NULL)
1770 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001771 /* TODO: handle the xmlDecl */
1772 if (reader->node->type != XML_ELEMENT_NODE)
1773 return(NULL);
1774
1775 ns = reader->node->nsDef;
1776 for (i = 0;(i < no) && (ns != NULL);i++) {
1777 ns = ns->next;
1778 }
1779 if (ns != NULL)
1780 return(xmlStrdup(ns->href));
1781
1782 cur = reader->node->properties;
1783 if (cur == NULL)
1784 return(NULL);
1785 for (;i < no;i++) {
1786 cur = cur->next;
1787 if (cur == NULL)
1788 return(NULL);
1789 }
1790 /* TODO walk the DTD if present */
1791
1792 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
1793 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
1794 return(ret);
1795}
1796
1797/**
1798 * xmlTextReaderGetAttribute:
1799 * @reader: the xmlTextReaderPtr used
1800 * @name: the qualified name of the attribute.
1801 *
1802 * Provides the value of the attribute with the specified qualified name.
1803 *
1804 * Returns a string containing the value of the specified attribute, or NULL
1805 * in case of error. The string must be deallocated by the caller.
1806 */
1807xmlChar *
1808xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
1809 xmlChar *prefix = NULL;
1810 xmlChar *localname;
1811 xmlNsPtr ns;
1812 xmlChar *ret = NULL;
1813
1814 if ((reader == NULL) || (name == NULL))
1815 return(NULL);
1816 if (reader->node == NULL)
1817 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001818 if (reader->curnode != NULL)
1819 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001820
1821 /* TODO: handle the xmlDecl */
1822 if (reader->node->type != XML_ELEMENT_NODE)
1823 return(NULL);
1824
1825 localname = xmlSplitQName2(name, &prefix);
1826 if (localname == NULL)
1827 return(xmlGetProp(reader->node, name));
1828
1829 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1830 if (ns != NULL)
1831 ret = xmlGetNsProp(reader->node, localname, ns->href);
1832
1833 if (localname != NULL)
1834 xmlFree(localname);
1835 if (prefix != NULL)
1836 xmlFree(prefix);
1837 return(ret);
1838}
1839
1840
1841/**
1842 * xmlTextReaderGetAttributeNs:
1843 * @reader: the xmlTextReaderPtr used
1844 * @localName: the local name of the attribute.
1845 * @namespaceURI: the namespace URI of the attribute.
1846 *
1847 * Provides the value of the specified attribute
1848 *
1849 * Returns a string containing the value of the specified attribute, or NULL
1850 * in case of error. The string must be deallocated by the caller.
1851 */
1852xmlChar *
1853xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
1854 const xmlChar *namespaceURI) {
1855 if ((reader == NULL) || (localName == NULL))
1856 return(NULL);
1857 if (reader->node == NULL)
1858 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001859 if (reader->curnode != NULL)
1860 return(NULL);
Daniel Veillard0eb38c72002-12-14 23:00:35 +00001861
1862 /* TODO: handle the xmlDecl */
1863 if (reader->node->type != XML_ELEMENT_NODE)
1864 return(NULL);
1865
1866 return(xmlGetNsProp(reader->node, localName, namespaceURI));
1867}
1868
Daniel Veillardda46d2d2002-12-15 23:36:49 +00001869/**
1870 * xmlTextReaderGetRemainder:
1871 * @reader: the xmlTextReaderPtr used
1872 *
1873 * Method to get the remainder of the buffered XML. this method stops the
1874 * parser, set its state to End Of File and return the input stream with
1875 * what is left that the parser did not use.
1876 *
1877 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
1878 * in case of error.
1879 */
1880xmlParserInputBufferPtr
1881xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
1882 xmlParserInputBufferPtr ret = NULL;
1883
1884 if (reader == NULL)
1885 return(NULL);
1886 if (reader->node == NULL)
1887 return(NULL);
1888
1889 reader->node = NULL;
1890 reader->curnode = NULL;
1891 reader->mode = XML_TEXTREADER_MODE_EOF;
1892 if (reader->ctxt != NULL) {
1893 if (reader->ctxt->myDoc != NULL) {
1894 xmlFreeDoc(reader->ctxt->myDoc);
1895 reader->ctxt->myDoc = NULL;
1896 }
1897 if (reader->allocs & XML_TEXTREADER_CTXT) {
1898 xmlFreeParserCtxt(reader->ctxt);
1899 reader->allocs -= XML_TEXTREADER_CTXT;
1900 }
1901 }
1902 if (reader->sax != NULL) {
1903 xmlFree(reader->sax);
1904 reader->sax = NULL;
1905 }
1906 if (reader->allocs & XML_TEXTREADER_INPUT) {
1907 ret = reader->input;
1908 reader->allocs -= XML_TEXTREADER_INPUT;
1909 } else {
1910 /*
1911 * Hum, one may need to duplicate the data structure because
1912 * without reference counting the input may be freed twice:
1913 * - by the layer which allocated it.
1914 * - by the layer to which would have been returned to.
1915 */
1916 TODO
1917 return(NULL);
1918 }
1919 return(ret);
1920}
1921
1922/**
1923 * xmlTextReaderLookupNamespace:
1924 * @reader: the xmlTextReaderPtr used
1925 * @prefix: the prefix whose namespace URI is to be resolved. To return
1926 * the default namespace, specify NULL
1927 *
1928 * Resolves a namespace prefix in the scope of the current element.
1929 *
1930 * Returns a string containing the namespace URI to which the prefix maps
1931 * or NULL in case of error. The string must be deallocated by the caller.
1932 */
1933xmlChar *
1934xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
1935 xmlNsPtr ns;
1936
1937 if (reader == NULL)
1938 return(NULL);
1939 if (reader->node == NULL)
1940 return(NULL);
1941
1942 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
1943 if (ns == NULL)
1944 return(NULL);
1945 return(xmlStrdup(ns->href));
1946}
1947
1948/**
1949 * xmlTextReaderMoveToAttributeNo:
1950 * @reader: the xmlTextReaderPtr used
1951 * @no: the zero-based index of the attribute relative to the containing
1952 * element.
1953 *
1954 * Moves the position of the current instance to the attribute with
1955 * the specified index relative to the containing element.
1956 *
1957 * Returns 1 in case of success, -1 in case of error, 0 if not found
1958 */
1959int
1960xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
1961 int i;
1962 xmlAttrPtr cur;
1963 xmlNsPtr ns;
1964
1965 if (reader == NULL)
1966 return(-1);
1967 if (reader->node == NULL)
1968 return(-1);
1969 /* TODO: handle the xmlDecl */
1970 if (reader->node->type != XML_ELEMENT_NODE)
1971 return(-1);
1972
1973 reader->curnode = NULL;
1974
1975 ns = reader->node->nsDef;
1976 for (i = 0;(i < no) && (ns != NULL);i++) {
1977 ns = ns->next;
1978 }
1979 if (ns != NULL) {
1980 reader->curnode = (xmlNodePtr) ns;
1981 return(1);
1982 }
1983
1984 cur = reader->node->properties;
1985 if (cur == NULL)
1986 return(0);
1987 for (;i < no;i++) {
1988 cur = cur->next;
1989 if (cur == NULL)
1990 return(0);
1991 }
1992 /* TODO walk the DTD if present */
1993
1994 reader->curnode = (xmlNodePtr) cur;
1995 return(1);
1996}
1997
1998/**
1999 * xmlTextReaderMoveToAttribute:
2000 * @reader: the xmlTextReaderPtr used
2001 * @name: the qualified name of the attribute.
2002 *
2003 * Moves the position of the current instance to the attribute with
2004 * the specified qualified name.
2005 *
2006 * Returns 1 in case of success, -1 in case of error, 0 if not found
2007 */
2008int
2009xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
2010 xmlChar *prefix = NULL;
2011 xmlChar *localname;
2012 xmlNsPtr ns;
2013 xmlAttrPtr prop;
2014
2015 if ((reader == NULL) || (name == NULL))
2016 return(-1);
2017 if (reader->node == NULL)
2018 return(-1);
2019
2020 /* TODO: handle the xmlDecl */
2021 if (reader->node->type != XML_ELEMENT_NODE)
2022 return(0);
2023
2024 localname = xmlSplitQName2(name, &prefix);
2025 if (localname == NULL) {
2026 /*
2027 * Namespace default decl
2028 */
2029 if (xmlStrEqual(name, BAD_CAST "xmlns")) {
2030 ns = reader->node->nsDef;
2031 while (ns != NULL) {
2032 if (ns->prefix == NULL) {
2033 reader->curnode = (xmlNodePtr) ns;
2034 return(1);
2035 }
2036 ns = ns->next;
2037 }
2038 return(0);
2039 }
2040
2041 prop = reader->node->properties;
2042 while (prop != NULL) {
2043 /*
2044 * One need to have
2045 * - same attribute names
2046 * - and the attribute carrying that namespace
2047 */
2048 if ((xmlStrEqual(prop->name, name)) &&
2049 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
2050 reader->curnode = (xmlNodePtr) prop;
2051 return(1);
2052 }
2053 prop = prop->next;
2054 }
2055 return(0);
2056 }
2057
2058 /*
2059 * Namespace default decl
2060 */
2061 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
2062 ns = reader->node->nsDef;
2063 while (ns != NULL) {
2064 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
2065 reader->curnode = (xmlNodePtr) ns;
2066 goto found;
2067 }
2068 ns = ns->next;
2069 }
2070 goto not_found;
2071 }
2072 prop = reader->node->properties;
2073 while (prop != NULL) {
2074 /*
2075 * One need to have
2076 * - same attribute names
2077 * - and the attribute carrying that namespace
2078 */
2079 if ((xmlStrEqual(prop->name, localname)) &&
2080 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
2081 reader->curnode = (xmlNodePtr) prop;
2082 goto found;
2083 }
2084 prop = prop->next;
2085 }
2086not_found:
2087 if (localname != NULL)
2088 xmlFree(localname);
2089 if (prefix != NULL)
2090 xmlFree(prefix);
2091 return(0);
2092
2093found:
2094 if (localname != NULL)
2095 xmlFree(localname);
2096 if (prefix != NULL)
2097 xmlFree(prefix);
2098 return(1);
2099}
2100
2101/**
2102 * xmlTextReaderMoveToAttributeNs:
2103 * @reader: the xmlTextReaderPtr used
2104 * @localName: the local name of the attribute.
2105 * @namespaceURI: the namespace URI of the attribute.
2106 *
2107 * Moves the position of the current instance to the attribute with the
2108 * specified local name and namespace URI.
2109 *
2110 * Returns 1 in case of success, -1 in case of error, 0 if not found
2111 */
2112int
2113xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
2114 const xmlChar *localName, const xmlChar *namespaceURI) {
2115 xmlAttrPtr prop;
2116 xmlNodePtr node;
2117
2118 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
2119 return(-1);
2120 if (reader->node == NULL)
2121 return(-1);
2122 if (reader->node->type != XML_ELEMENT_NODE)
2123 return(0);
2124 node = reader->node;
2125
2126 /*
2127 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
2128 * namespace name associated to "xmlns"
2129 */
2130 prop = node->properties;
2131 while (prop != NULL) {
2132 /*
2133 * One need to have
2134 * - same attribute names
2135 * - and the attribute carrying that namespace
2136 */
2137 if (xmlStrEqual(prop->name, localName) &&
2138 ((prop->ns != NULL) &&
2139 (xmlStrEqual(prop->ns->href, namespaceURI)))) {
2140 reader->curnode = (xmlNodePtr) prop;
2141 return(1);
2142 }
2143 prop = prop->next;
2144 }
2145 return(0);
2146}
2147
2148/**
2149 * xmlTextReaderMoveToFirstAttribute:
2150 * @reader: the xmlTextReaderPtr used
2151 *
2152 * Moves the position of the current instance to the first attribute
2153 * associated with the current node.
2154 *
2155 * Returns 1 in case of success, -1 in case of error, 0 if not found
2156 */
2157int
2158xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
2159 if (reader == NULL)
2160 return(-1);
2161 if (reader->node == NULL)
2162 return(-1);
2163 if (reader->node->type != XML_ELEMENT_NODE)
2164 return(0);
2165
2166 if (reader->node->nsDef != NULL) {
2167 reader->curnode = (xmlNodePtr) reader->node->nsDef;
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}
2176
2177/**
2178 * xmlTextReaderMoveToNextAttribute:
2179 * @reader: the xmlTextReaderPtr used
2180 *
2181 * Moves the position of the current instance to the next attribute
2182 * associated with the current node.
2183 *
2184 * Returns 1 in case of success, -1 in case of error, 0 if not found
2185 */
2186int
2187xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
2188 if (reader == NULL)
2189 return(-1);
2190 if (reader->node == NULL)
2191 return(-1);
2192 if (reader->node->type != XML_ELEMENT_NODE)
2193 return(0);
2194 if (reader->curnode == NULL)
2195 return(xmlTextReaderMoveToFirstAttribute(reader));
2196
2197 if (reader->curnode->type == XML_NAMESPACE_DECL) {
2198 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2199 if (ns->next != NULL) {
2200 reader->curnode = (xmlNodePtr) ns->next;
2201 return(1);
2202 }
2203 if (reader->node->properties != NULL) {
2204 reader->curnode = (xmlNodePtr) reader->node->properties;
2205 return(1);
2206 }
2207 return(0);
2208 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
2209 (reader->curnode->next != NULL)) {
2210 reader->curnode = reader->curnode->next;
2211 return(1);
2212 }
2213 return(0);
2214}
2215
2216/**
2217 * xmlTextReaderMoveToElement:
2218 * @reader: the xmlTextReaderPtr used
2219 *
2220 * Moves the position of the current instance to the node that
2221 * contains the current Attribute node.
2222 *
2223 * Returns 1 in case of success, -1 in case of error, 0 if not moved
2224 */
2225int
2226xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
2227 if (reader == NULL)
2228 return(-1);
2229 if (reader->node == NULL)
2230 return(-1);
2231 if (reader->node->type != XML_ELEMENT_NODE)
2232 return(0);
2233 if (reader->curnode != NULL) {
2234 reader->curnode = NULL;
2235 return(1);
2236 }
2237 return(0);
2238}
2239
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002240/**
2241 * xmlTextReaderReadAttributeValue:
2242 * @reader: the xmlTextReaderPtr used
2243 *
2244 * Parses an attribute value into one or more Text and EntityReference nodes.
2245 *
2246 * Returns 1 in case of success, 0 if the reader was not positionned on an
2247 * ttribute node or all the attribute values have been read, or -1
2248 * in case of error.
2249 */
2250int
2251xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
2252 if (reader == NULL)
2253 return(-1);
2254 if (reader->node == NULL)
2255 return(-1);
2256 if (reader->curnode == NULL)
2257 return(0);
2258 if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
2259 if (reader->curnode->children == NULL)
2260 return(0);
2261 reader->curnode = reader->curnode->children;
2262 } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
2263 xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2264
2265 if (reader->faketext == NULL) {
2266 reader->faketext = xmlNewDocText(reader->node->doc,
2267 ns->href);
2268 } else {
2269 if (reader->faketext->content != NULL)
2270 xmlFree(reader->faketext->content);
2271 reader->faketext->content = xmlStrdup(ns->href);
2272 }
2273 reader->curnode = reader->faketext;
2274 } else {
2275 if (reader->curnode->next == NULL)
2276 return(0);
2277 reader->curnode = reader->curnode->next;
2278 }
2279 return(1);
2280}
2281
Daniel Veillard0eb38c72002-12-14 23:00:35 +00002282/************************************************************************
2283 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002284 * Acces API to the current node *
2285 * *
2286 ************************************************************************/
2287/**
2288 * xmlTextReaderAttributeCount:
2289 * @reader: the xmlTextReaderPtr used
2290 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002291 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002292 *
2293 * Returns 0 i no attributes, -1 in case of error or the attribute count
2294 */
2295int
2296xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
2297 int ret;
2298 xmlAttrPtr attr;
Daniel Veillard67df8092002-12-16 22:04:11 +00002299 xmlNsPtr ns;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002300 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002301
2302 if (reader == NULL)
2303 return(-1);
2304 if (reader->node == NULL)
2305 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002306
2307 if (reader->curnode != NULL)
2308 node = reader->curnode;
2309 else
2310 node = reader->node;
2311
2312 if (node->type != XML_ELEMENT_NODE)
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002313 return(0);
2314 if ((reader->state == XML_TEXTREADER_END) ||
2315 (reader->state == XML_TEXTREADER_BACKTRACK))
2316 return(0);
2317 ret = 0;
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002318 attr = node->properties;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002319 while (attr != NULL) {
2320 ret++;
2321 attr = attr->next;
2322 }
Daniel Veillard67df8092002-12-16 22:04:11 +00002323 ns = node->nsDef;
2324 while (ns != NULL) {
2325 ret++;
2326 ns = ns->next;
2327 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002328 return(ret);
2329}
2330
2331/**
2332 * xmlTextReaderNodeType:
2333 * @reader: the xmlTextReaderPtr used
2334 *
2335 * Get the node type of the current node
2336 * Reference:
2337 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
2338 *
2339 * Returns the xmlNodeType of the current node or -1 in case of error
2340 */
2341int
2342xmlTextReaderNodeType(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002343 xmlNodePtr node;
Daniel Veillardd6038e02003-07-30 16:37:18 +00002344
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002345 if (reader == NULL)
2346 return(-1);
2347 if (reader->node == NULL)
Daniel Veillardd6038e02003-07-30 16:37:18 +00002348 return(XML_READER_TYPE_NONE);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002349 if (reader->curnode != NULL)
2350 node = reader->curnode;
2351 else
2352 node = reader->node;
2353 switch (node->type) {
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002354 case XML_ELEMENT_NODE:
2355 if ((reader->state == XML_TEXTREADER_END) ||
2356 (reader->state == XML_TEXTREADER_BACKTRACK))
Daniel Veillardd6038e02003-07-30 16:37:18 +00002357 return(XML_READER_TYPE_END_ELEMENT);
2358 return(XML_READER_TYPE_ELEMENT);
Daniel Veillardecaba492002-12-30 10:55:29 +00002359 case XML_NAMESPACE_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002360 case XML_ATTRIBUTE_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002361 return(XML_READER_TYPE_ATTRIBUTE);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002362 case XML_TEXT_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002363 if (xmlIsBlankNode(reader->node)) {
2364 if (xmlNodeGetSpacePreserve(reader->node))
2365 return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
2366 else
2367 return(XML_READER_TYPE_WHITESPACE);
2368 } else {
2369 return(XML_READER_TYPE_TEXT);
2370 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002371 case XML_CDATA_SECTION_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002372 return(XML_READER_TYPE_CDATA);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002373 case XML_ENTITY_REF_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002374 return(XML_READER_TYPE_ENTITY_REFERENCE);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002375 case XML_ENTITY_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002376 return(XML_READER_TYPE_ENTITY);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002377 case XML_PI_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002378 return(XML_READER_TYPE_PROCESSING_INSTRUCTION);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002379 case XML_COMMENT_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002380 return(XML_READER_TYPE_COMMENT);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002381 case XML_DOCUMENT_NODE:
2382 case XML_HTML_DOCUMENT_NODE:
2383#ifdef LIBXML_DOCB_ENABLED
2384 case XML_DOCB_DOCUMENT_NODE:
2385#endif
Daniel Veillardd6038e02003-07-30 16:37:18 +00002386 return(XML_READER_TYPE_DOCUMENT);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002387 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002388 return(XML_READER_TYPE_DOCUMENT_FRAGMENT);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002389 case XML_NOTATION_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002390 return(XML_READER_TYPE_NOTATION);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002391 case XML_DOCUMENT_TYPE_NODE:
2392 case XML_DTD_NODE:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002393 return(XML_READER_TYPE_DOCUMENT_TYPE);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002394
2395 case XML_ELEMENT_DECL:
2396 case XML_ATTRIBUTE_DECL:
2397 case XML_ENTITY_DECL:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002398 case XML_XINCLUDE_START:
2399 case XML_XINCLUDE_END:
Daniel Veillardd6038e02003-07-30 16:37:18 +00002400 return(XML_READER_TYPE_NONE);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002401 }
2402 return(-1);
2403}
2404
2405/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002406 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002407 * @reader: the xmlTextReaderPtr used
2408 *
2409 * Check if the current node is empty
2410 *
2411 * Returns 1 if empty, 0 if not and -1 in case of error
2412 */
2413int
2414xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
2415 if ((reader == NULL) || (reader->node == NULL))
2416 return(-1);
Daniel Veillarddf512f42002-12-23 15:56:21 +00002417 if (reader->node->type != XML_ELEMENT_NODE)
2418 return(0);
Daniel Veillarde3c036e2003-01-01 15:11:05 +00002419 if (reader->curnode != NULL)
2420 return(0);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002421 if (reader->node->children != NULL)
2422 return(0);
Daniel Veillarddab8ea92003-01-02 14:16:45 +00002423 if (reader->state == XML_TEXTREADER_END)
2424 return(0);
Daniel Veillard067bae52003-01-05 01:27:54 +00002425 return(reader->node->_private == (void *)xmlTextReaderIsEmpty);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002426}
2427
2428/**
2429 * xmlTextReaderLocalName:
2430 * @reader: the xmlTextReaderPtr used
2431 *
2432 * The local name of the node.
2433 *
2434 * Returns the local name or NULL if not available
2435 */
2436xmlChar *
2437xmlTextReaderLocalName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002438 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002439 if ((reader == NULL) || (reader->node == NULL))
2440 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002441 if (reader->curnode != NULL)
2442 node = reader->curnode;
2443 else
2444 node = reader->node;
2445 if (node->type == XML_NAMESPACE_DECL) {
2446 xmlNsPtr ns = (xmlNsPtr) node;
2447 if (ns->prefix == NULL)
2448 return(xmlStrdup(BAD_CAST "xmlns"));
2449 else
2450 return(xmlStrdup(ns->prefix));
2451 }
2452 if ((node->type != XML_ELEMENT_NODE) &&
2453 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002454 return(xmlTextReaderName(reader));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002455 return(xmlStrdup(node->name));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002456}
2457
2458/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00002459 * xmlTextReaderConstLocalName:
2460 * @reader: the xmlTextReaderPtr used
2461 *
2462 * The local name of the node.
2463 *
2464 * Returns the local name or NULL if not available, the
2465 * string will be deallocated with the reader.
2466 */
2467const xmlChar *
2468xmlTextReaderConstLocalName(xmlTextReaderPtr reader) {
2469 xmlNodePtr node;
2470 if ((reader == NULL) || (reader->node == NULL))
2471 return(NULL);
2472 if (reader->curnode != NULL)
2473 node = reader->curnode;
2474 else
2475 node = reader->node;
2476 if (node->type == XML_NAMESPACE_DECL) {
2477 xmlNsPtr ns = (xmlNsPtr) node;
2478 if (ns->prefix == NULL)
2479 return(CONSTSTR(BAD_CAST "xmlns"));
2480 else
2481 return(ns->prefix);
2482 }
2483 if ((node->type != XML_ELEMENT_NODE) &&
2484 (node->type != XML_ATTRIBUTE_NODE))
2485 return(xmlTextReaderConstName(reader));
2486 return(node->name);
2487}
2488
2489/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002490 * xmlTextReaderName:
2491 * @reader: the xmlTextReaderPtr used
2492 *
2493 * The qualified name of the node, equal to Prefix :LocalName.
2494 *
2495 * Returns the local name or NULL if not available
2496 */
2497xmlChar *
2498xmlTextReaderName(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002499 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002500 xmlChar *ret;
2501
2502 if ((reader == NULL) || (reader->node == NULL))
2503 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002504 if (reader->curnode != NULL)
2505 node = reader->curnode;
2506 else
2507 node = reader->node;
2508 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002509 case XML_ELEMENT_NODE:
2510 case XML_ATTRIBUTE_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002511 if ((node->ns == NULL) ||
2512 (node->ns->prefix == NULL))
2513 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002514
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002515 ret = xmlStrdup(node->ns->prefix);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002516 ret = xmlStrcat(ret, BAD_CAST ":");
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002517 ret = xmlStrcat(ret, node->name);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002518 return(ret);
2519 case XML_TEXT_NODE:
2520 return(xmlStrdup(BAD_CAST "#text"));
2521 case XML_CDATA_SECTION_NODE:
2522 return(xmlStrdup(BAD_CAST "#cdata-section"));
2523 case XML_ENTITY_NODE:
2524 case XML_ENTITY_REF_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002525 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002526 case XML_PI_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002527 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002528 case XML_COMMENT_NODE:
2529 return(xmlStrdup(BAD_CAST "#comment"));
2530 case XML_DOCUMENT_NODE:
2531 case XML_HTML_DOCUMENT_NODE:
2532#ifdef LIBXML_DOCB_ENABLED
2533 case XML_DOCB_DOCUMENT_NODE:
2534#endif
2535 return(xmlStrdup(BAD_CAST "#document"));
2536 case XML_DOCUMENT_FRAG_NODE:
2537 return(xmlStrdup(BAD_CAST "#document-fragment"));
2538 case XML_NOTATION_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002539 return(xmlStrdup(node->name));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002540 case XML_DOCUMENT_TYPE_NODE:
2541 case XML_DTD_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002542 return(xmlStrdup(node->name));
2543 case XML_NAMESPACE_DECL: {
2544 xmlNsPtr ns = (xmlNsPtr) node;
2545
2546 ret = xmlStrdup(BAD_CAST "xmlns");
2547 if (ns->prefix == NULL)
2548 return(ret);
2549 ret = xmlStrcat(ret, BAD_CAST ":");
2550 ret = xmlStrcat(ret, ns->prefix);
2551 return(ret);
2552 }
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002553
2554 case XML_ELEMENT_DECL:
2555 case XML_ATTRIBUTE_DECL:
2556 case XML_ENTITY_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002557 case XML_XINCLUDE_START:
2558 case XML_XINCLUDE_END:
2559 return(NULL);
2560 }
2561 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002562}
2563
2564/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00002565 * xmlTextReaderConstName:
2566 * @reader: the xmlTextReaderPtr used
2567 *
2568 * The qualified name of the node, equal to Prefix :LocalName.
2569 *
2570 * Returns the local name or NULL if not available, the string is
2571 * deallocated with the reader.
2572 */
2573const xmlChar *
2574xmlTextReaderConstName(xmlTextReaderPtr reader) {
2575 xmlNodePtr node;
2576
2577 if ((reader == NULL) || (reader->node == NULL))
2578 return(NULL);
2579 if (reader->curnode != NULL)
2580 node = reader->curnode;
2581 else
2582 node = reader->node;
2583 switch (node->type) {
2584 case XML_ELEMENT_NODE:
2585 case XML_ATTRIBUTE_NODE:
2586 if ((node->ns == NULL) ||
2587 (node->ns->prefix == NULL))
2588 return(node->name);
2589 return(CONSTQSTR(node->ns->prefix, node->name));
2590 case XML_TEXT_NODE:
2591 return(CONSTSTR(BAD_CAST "#text"));
2592 case XML_CDATA_SECTION_NODE:
2593 return(CONSTSTR(BAD_CAST "#cdata-section"));
2594 case XML_ENTITY_NODE:
2595 case XML_ENTITY_REF_NODE:
2596 return(CONSTSTR(node->name));
2597 case XML_PI_NODE:
2598 return(CONSTSTR(node->name));
2599 case XML_COMMENT_NODE:
2600 return(CONSTSTR(BAD_CAST "#comment"));
2601 case XML_DOCUMENT_NODE:
2602 case XML_HTML_DOCUMENT_NODE:
2603#ifdef LIBXML_DOCB_ENABLED
2604 case XML_DOCB_DOCUMENT_NODE:
2605#endif
2606 return(CONSTSTR(BAD_CAST "#document"));
2607 case XML_DOCUMENT_FRAG_NODE:
2608 return(CONSTSTR(BAD_CAST "#document-fragment"));
2609 case XML_NOTATION_NODE:
2610 return(CONSTSTR(node->name));
2611 case XML_DOCUMENT_TYPE_NODE:
2612 case XML_DTD_NODE:
2613 return(CONSTSTR(node->name));
2614 case XML_NAMESPACE_DECL: {
2615 xmlNsPtr ns = (xmlNsPtr) node;
2616
2617 if (ns->prefix == NULL)
2618 return(CONSTSTR(BAD_CAST "xmlns"));
2619 return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix));
2620 }
2621
2622 case XML_ELEMENT_DECL:
2623 case XML_ATTRIBUTE_DECL:
2624 case XML_ENTITY_DECL:
2625 case XML_XINCLUDE_START:
2626 case XML_XINCLUDE_END:
2627 return(NULL);
2628 }
2629 return(NULL);
2630}
2631
2632/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002633 * xmlTextReaderPrefix:
2634 * @reader: the xmlTextReaderPtr used
2635 *
2636 * A shorthand reference to the namespace associated with the node.
2637 *
2638 * Returns the prefix or NULL if not available
2639 */
2640xmlChar *
2641xmlTextReaderPrefix(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002642 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002643 if ((reader == NULL) || (reader->node == NULL))
2644 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002645 if (reader->curnode != NULL)
2646 node = reader->curnode;
2647 else
2648 node = reader->node;
2649 if (node->type == XML_NAMESPACE_DECL) {
2650 xmlNsPtr ns = (xmlNsPtr) node;
2651 if (ns->prefix == NULL)
2652 return(NULL);
2653 return(xmlStrdup(BAD_CAST "xmlns"));
2654 }
2655 if ((node->type != XML_ELEMENT_NODE) &&
2656 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002657 return(NULL);
Daniel Veillard952379b2003-03-17 15:37:12 +00002658 if ((node->ns != NULL) && (node->ns->prefix != NULL))
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002659 return(xmlStrdup(node->ns->prefix));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002660 return(NULL);
2661}
2662
2663/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00002664 * xmlTextReaderConstPrefix:
2665 * @reader: the xmlTextReaderPtr used
2666 *
2667 * A shorthand reference to the namespace associated with the node.
2668 *
2669 * Returns the prefix or NULL if not available, the string is deallocated
2670 * with the reader.
2671 */
2672const xmlChar *
2673xmlTextReaderConstPrefix(xmlTextReaderPtr reader) {
2674 xmlNodePtr node;
2675 if ((reader == NULL) || (reader->node == NULL))
2676 return(NULL);
2677 if (reader->curnode != NULL)
2678 node = reader->curnode;
2679 else
2680 node = reader->node;
2681 if (node->type == XML_NAMESPACE_DECL) {
2682 xmlNsPtr ns = (xmlNsPtr) node;
2683 if (ns->prefix == NULL)
2684 return(NULL);
2685 return(CONSTSTR(BAD_CAST "xmlns"));
2686 }
2687 if ((node->type != XML_ELEMENT_NODE) &&
2688 (node->type != XML_ATTRIBUTE_NODE))
2689 return(NULL);
2690 if ((node->ns != NULL) && (node->ns->prefix != NULL))
2691 return(CONSTSTR(node->ns->prefix));
2692 return(NULL);
2693}
2694
2695/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002696 * xmlTextReaderNamespaceUri:
2697 * @reader: the xmlTextReaderPtr used
2698 *
2699 * The URI defining the namespace associated with the node.
2700 *
2701 * Returns the namespace URI or NULL if not available
2702 */
2703xmlChar *
2704xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002705 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002706 if ((reader == NULL) || (reader->node == NULL))
2707 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002708 if (reader->curnode != NULL)
2709 node = reader->curnode;
2710 else
2711 node = reader->node;
Daniel Veillardecaba492002-12-30 10:55:29 +00002712 if (node->type == XML_NAMESPACE_DECL)
2713 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002714 if ((node->type != XML_ELEMENT_NODE) &&
2715 (node->type != XML_ATTRIBUTE_NODE))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002716 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002717 if (node->ns != NULL)
2718 return(xmlStrdup(node->ns->href));
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002719 return(NULL);
2720}
2721
2722/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00002723 * xmlTextReaderConstNamespaceUri:
2724 * @reader: the xmlTextReaderPtr used
2725 *
2726 * The URI defining the namespace associated with the node.
2727 *
2728 * Returns the namespace URI or NULL if not available, the string
2729 * will be deallocated with the reader
2730 */
2731const xmlChar *
2732xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) {
2733 xmlNodePtr node;
2734 if ((reader == NULL) || (reader->node == NULL))
2735 return(NULL);
2736 if (reader->curnode != NULL)
2737 node = reader->curnode;
2738 else
2739 node = reader->node;
2740 if (node->type == XML_NAMESPACE_DECL)
2741 return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/"));
2742 if ((node->type != XML_ELEMENT_NODE) &&
2743 (node->type != XML_ATTRIBUTE_NODE))
2744 return(NULL);
2745 if (node->ns != NULL)
2746 return(CONSTSTR(node->ns->href));
2747 return(NULL);
2748}
2749
2750/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002751 * xmlTextReaderBaseUri:
2752 * @reader: the xmlTextReaderPtr used
2753 *
2754 * The base URI of the node.
2755 *
2756 * Returns the base URI or NULL if not available
2757 */
2758xmlChar *
2759xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
2760 if ((reader == NULL) || (reader->node == NULL))
2761 return(NULL);
2762 return(xmlNodeGetBase(NULL, reader->node));
2763}
2764
2765/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00002766 * xmlTextReaderConstBaseUri:
2767 * @reader: the xmlTextReaderPtr used
2768 *
2769 * The base URI of the node.
2770 *
2771 * Returns the base URI or NULL if not available, the string
2772 * will be deallocated with the reader
2773 */
2774const xmlChar *
2775xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) {
2776 xmlChar *tmp;
2777 const xmlChar *ret;
2778
2779 if ((reader == NULL) || (reader->node == NULL))
2780 return(NULL);
2781 tmp = xmlNodeGetBase(NULL, reader->node);
2782 if (tmp == NULL)
2783 return(NULL);
2784 ret = CONSTSTR(tmp);
2785 xmlFree(tmp);
2786 return(ret);
2787}
2788
2789/**
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002790 * xmlTextReaderDepth:
2791 * @reader: the xmlTextReaderPtr used
2792 *
2793 * The depth of the node in the tree.
2794 *
2795 * Returns the depth or -1 in case of error
2796 */
2797int
2798xmlTextReaderDepth(xmlTextReaderPtr reader) {
2799 if (reader == NULL)
2800 return(-1);
2801 if (reader->node == NULL)
2802 return(0);
2803
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00002804 if (reader->curnode != NULL) {
2805 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
2806 (reader->curnode->type == XML_NAMESPACE_DECL))
2807 return(reader->depth + 1);
2808 return(reader->depth + 2);
2809 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002810 return(reader->depth);
2811}
2812
2813/**
2814 * xmlTextReaderHasAttributes:
2815 * @reader: the xmlTextReaderPtr used
2816 *
2817 * Whether the node has attributes.
2818 *
2819 * Returns 1 if true, 0 if false, and -1 in case or error
2820 */
2821int
2822xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002823 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002824 if (reader == NULL)
2825 return(-1);
2826 if (reader->node == NULL)
2827 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002828 if (reader->curnode != NULL)
2829 node = reader->curnode;
2830 else
2831 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002832
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002833 if ((node->type == XML_ELEMENT_NODE) &&
2834 (node->properties != NULL))
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002835 return(1);
2836 /* TODO: handle the xmlDecl */
2837 return(0);
2838}
2839
2840/**
2841 * xmlTextReaderHasValue:
2842 * @reader: the xmlTextReaderPtr used
2843 *
2844 * Whether the node can have a text value.
2845 *
2846 * Returns 1 if true, 0 if false, and -1 in case or error
2847 */
2848int
2849xmlTextReaderHasValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002850 xmlNodePtr node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002851 if (reader == NULL)
2852 return(-1);
2853 if (reader->node == NULL)
2854 return(0);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002855 if (reader->curnode != NULL)
2856 node = reader->curnode;
2857 else
2858 node = reader->node;
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002859
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002860 switch (node->type) {
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002861 case XML_ATTRIBUTE_NODE:
2862 case XML_TEXT_NODE:
2863 case XML_CDATA_SECTION_NODE:
2864 case XML_PI_NODE:
2865 case XML_COMMENT_NODE:
Daniel Veillard9e077102003-04-10 13:36:54 +00002866 case XML_NAMESPACE_DECL:
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002867 return(1);
2868 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002869 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002870 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002871 return(0);
2872}
2873
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002874/**
2875 * xmlTextReaderValue:
2876 * @reader: the xmlTextReaderPtr used
2877 *
2878 * Provides the text value of the node if present
2879 *
2880 * Returns the string or NULL if not available. The retsult must be deallocated
2881 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002882 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002883xmlChar *
2884xmlTextReaderValue(xmlTextReaderPtr reader) {
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002885 xmlNodePtr node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002886 if (reader == NULL)
2887 return(NULL);
2888 if (reader->node == NULL)
2889 return(NULL);
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002890 if (reader->curnode != NULL)
2891 node = reader->curnode;
2892 else
2893 node = reader->node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002894
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002895 switch (node->type) {
2896 case XML_NAMESPACE_DECL:
2897 return(xmlStrdup(((xmlNsPtr) node)->href));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002898 case XML_ATTRIBUTE_NODE:{
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002899 xmlAttrPtr attr = (xmlAttrPtr) node;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002900
2901 if (attr->parent != NULL)
2902 return (xmlNodeListGetString
2903 (attr->parent->doc, attr->children, 1));
2904 else
2905 return (xmlNodeListGetString(NULL, attr->children, 1));
2906 break;
2907 }
2908 case XML_TEXT_NODE:
2909 case XML_CDATA_SECTION_NODE:
2910 case XML_PI_NODE:
2911 case XML_COMMENT_NODE:
Daniel Veillardda46d2d2002-12-15 23:36:49 +00002912 if (node->content != NULL)
2913 return (xmlStrdup(node->content));
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002914 default:
Daniel Veillard2cfd9df2003-03-22 22:39:16 +00002915 break;
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +00002916 }
2917 return(NULL);
2918}
2919
2920/**
2921 * xmlTextReaderIsDefault:
2922 * @reader: the xmlTextReaderPtr used
2923 *
2924 * Whether an Attribute node was generated from the default value
2925 * defined in the DTD or schema.
2926 *
2927 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
2928 */
2929int
2930xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
2931 if (reader == NULL)
2932 return(-1);
2933 return(0);
2934}
2935
2936/**
2937 * xmlTextReaderQuoteChar:
2938 * @reader: the xmlTextReaderPtr used
2939 *
2940 * The quotation mark character used to enclose the value of an attribute.
2941 *
2942 * Returns " or ' and -1 in case of error
2943 */
2944int
2945xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
2946 if (reader == NULL)
2947 return(-1);
2948 /* TODO maybe lookup the attribute value for " first */
2949 return((int) '"');
2950}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00002951
2952/**
2953 * xmlTextReaderXmlLang:
2954 * @reader: the xmlTextReaderPtr used
2955 *
2956 * The xml:lang scope within which the node resides.
2957 *
2958 * Returns the xml:lang value or NULL if none exists.
2959 */
2960xmlChar *
2961xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
2962 if (reader == NULL)
2963 return(NULL);
2964 if (reader->node == NULL)
2965 return(NULL);
2966 return(xmlNodeGetLang(reader->node));
2967}
2968
Daniel Veillard67df8092002-12-16 22:04:11 +00002969/**
Daniel Veillarde72c5082003-09-19 12:44:05 +00002970 * xmlTextReaderXmlLang:
2971 * @reader: the xmlTextReaderPtr used
2972 *
2973 * The xml:lang scope within which the node resides.
2974 *
2975 * Returns the xml:lang value or NULL if none exists.
2976 */
2977const xmlChar *
2978xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) {
2979 xmlChar *tmp;
2980 const xmlChar *ret;
2981
2982 if (reader == NULL)
2983 return(NULL);
2984 if (reader->node == NULL)
2985 return(NULL);
2986 tmp = xmlNodeGetLang(reader->node);
2987 if (tmp == NULL)
2988 return(NULL);
2989 ret = CONSTSTR(tmp);
2990 xmlFree(tmp);
2991 return(ret);
2992}
2993
2994/**
Daniel Veillardf85ce8e2003-09-22 10:24:45 +00002995 * xmlTextReaderConstString:
2996 * @reader: the xmlTextReaderPtr used
2997 * @str: the string to intern.
2998 *
2999 * Get an interned string from the reader, allows for example to
3000 * speedup string name comparisons
3001 *
3002 * Returns an interned copy of the string or NULL in case of error. The
3003 * string will be deallocated with the reader.
3004 */
3005const xmlChar *
3006xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) {
3007 if (reader == NULL)
3008 return(NULL);
3009 return(CONSTSTR(str));
3010}
3011
3012/**
Daniel Veillard67df8092002-12-16 22:04:11 +00003013 * xmlTextReaderNormalization:
3014 * @reader: the xmlTextReaderPtr used
3015 *
3016 * The value indicating whether to normalize white space and attribute values.
3017 * Since attribute value and end of line normalizations are a MUST in the XML
3018 * specification only the value true is accepted. The broken bahaviour of
3019 * accepting out of range character entities like &#0; is of course not
3020 * supported either.
3021 *
3022 * Returns 1 or -1 in case of error.
3023 */
3024int
3025xmlTextReaderNormalization(xmlTextReaderPtr reader) {
3026 if (reader == NULL)
3027 return(-1);
3028 return(1);
3029}
3030
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003031/************************************************************************
3032 * *
3033 * Extensions to the base APIs *
3034 * *
3035 ************************************************************************/
3036
3037/**
3038 * xmlTextReaderSetParserProp:
3039 * @reader: the xmlTextReaderPtr used
3040 * @prop: the xmlParserProperties to set
3041 * @value: usually 0 or 1 to (de)activate it
3042 *
3043 * Change the parser processing behaviour by changing some of its internal
3044 * properties. Note that some properties can only be changed before any
3045 * read has been done.
3046 *
3047 * Returns 0 if the call was successful, or -1 in case of error
3048 */
3049int
3050xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
3051 xmlParserProperties p = (xmlParserProperties) prop;
3052 xmlParserCtxtPtr ctxt;
3053
3054 if ((reader == NULL) || (reader->ctxt == NULL))
3055 return(-1);
3056 ctxt = reader->ctxt;
3057
3058 switch (p) {
3059 case XML_PARSER_LOADDTD:
3060 if (value != 0) {
3061 if (ctxt->loadsubset == 0) {
3062 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
3063 return(-1);
3064 ctxt->loadsubset = XML_DETECT_IDS;
3065 }
3066 } else {
3067 ctxt->loadsubset = 0;
3068 }
3069 return(0);
3070 case XML_PARSER_DEFAULTATTRS:
3071 if (value != 0) {
3072 ctxt->loadsubset |= XML_COMPLETE_ATTRS;
3073 } else {
3074 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3075 ctxt->loadsubset -= XML_COMPLETE_ATTRS;
3076 }
3077 return(0);
3078 case XML_PARSER_VALIDATE:
3079 if (value != 0) {
3080 ctxt->validate = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00003081 reader->validate = XML_TEXTREADER_VALIDATE_DTD;
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003082 } else {
3083 ctxt->validate = 0;
3084 }
3085 return(0);
Daniel Veillarde18fc182002-12-28 22:56:33 +00003086 case XML_PARSER_SUBST_ENTITIES:
3087 if (value != 0) {
3088 ctxt->replaceEntities = 1;
3089 } else {
3090 ctxt->replaceEntities = 0;
3091 }
3092 return(0);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003093 }
3094 return(-1);
3095}
3096
3097/**
3098 * xmlTextReaderGetParserProp:
3099 * @reader: the xmlTextReaderPtr used
3100 * @prop: the xmlParserProperties to get
3101 *
3102 * Read the parser internal property.
3103 *
3104 * Returns the value, usually 0 or 1, or -1 in case of error.
3105 */
3106int
3107xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
3108 xmlParserProperties p = (xmlParserProperties) prop;
3109 xmlParserCtxtPtr ctxt;
3110
3111 if ((reader == NULL) || (reader->ctxt == NULL))
3112 return(-1);
3113 ctxt = reader->ctxt;
3114
3115 switch (p) {
3116 case XML_PARSER_LOADDTD:
3117 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
3118 return(1);
3119 return(0);
3120 case XML_PARSER_DEFAULTATTRS:
3121 if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3122 return(1);
3123 return(0);
3124 case XML_PARSER_VALIDATE:
Daniel Veillardf4e55762003-04-15 23:32:22 +00003125 return(reader->validate);
Daniel Veillarde18fc182002-12-28 22:56:33 +00003126 case XML_PARSER_SUBST_ENTITIES:
3127 return(ctxt->replaceEntities);
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003128 }
3129 return(-1);
3130}
3131
Daniel Veillarde18fc182002-12-28 22:56:33 +00003132/**
3133 * xmlTextReaderCurrentNode:
3134 * @reader: the xmlTextReaderPtr used
3135 *
3136 * Hacking interface allowing to get the xmlNodePtr correponding to the
3137 * current node being accessed by the xmlTextReader. This is dangerous
3138 * because the underlying node may be destroyed on the next Reads.
3139 *
3140 * Returns the xmlNodePtr or NULL in case of error.
3141 */
3142xmlNodePtr
3143xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
3144 if (reader == NULL)
3145 return(NULL);
3146
3147 if (reader->curnode != NULL)
3148 return(reader->curnode);
3149 return(reader->node);
3150}
3151
3152/**
3153 * xmlTextReaderCurrentDoc:
3154 * @reader: the xmlTextReaderPtr used
3155 *
3156 * Hacking interface allowing to get the xmlDocPtr correponding to the
3157 * current document being accessed by the xmlTextReader. This is dangerous
3158 * because the associated node may be destroyed on the next Reads.
3159 *
3160 * Returns the xmlDocPtr or NULL in case of error.
3161 */
3162xmlDocPtr
3163xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
3164 if ((reader == NULL) || (reader->ctxt == NULL))
3165 return(NULL);
3166
3167 return(reader->ctxt->myDoc);
3168}
3169
Daniel Veillard37fc84d2003-05-09 19:38:15 +00003170#ifdef LIBXML_SCHEMAS_ENABLED
Daniel Veillardf4e55762003-04-15 23:32:22 +00003171/**
Daniel Veillard33300b42003-04-17 09:09:19 +00003172 * xmlTextReaderRelaxNGSetSchema:
3173 * @reader: the xmlTextReaderPtr used
3174 * @schema: a precompiled RelaxNG schema
3175 *
3176 * Use RelaxNG to validate the document as it is processed.
3177 * Activation is only possible before the first Read().
3178 * if @schema is NULL, then RelaxNG validation is desactivated.
3179 @ The @schema should not be freed until the reader is deallocated
3180 * or its use has been deactivated.
3181 *
3182 * Returns 0 in case the RelaxNG validation could be (des)activated and
3183 * -1 in case of error.
3184 */
3185int
3186xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
3187 if (schema == NULL) {
3188 if (reader->rngSchemas != NULL) {
3189 xmlRelaxNGFree(reader->rngSchemas);
3190 reader->rngSchemas = NULL;
3191 }
3192 if (reader->rngValidCtxt != NULL) {
3193 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
3194 reader->rngValidCtxt = NULL;
3195 }
3196 return(0);
3197 }
3198 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
3199 return(-1);
3200 if (reader->rngSchemas != NULL) {
3201 xmlRelaxNGFree(reader->rngSchemas);
3202 reader->rngSchemas = NULL;
3203 }
3204 if (reader->rngValidCtxt != NULL) {
3205 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
3206 reader->rngValidCtxt = NULL;
3207 }
3208 reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
3209 if (reader->rngValidCtxt == NULL)
3210 return(-1);
3211 if (reader->errorFunc != NULL) {
3212 xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
3213 (xmlRelaxNGValidityErrorFunc)reader->errorFunc,
3214 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
3215 reader->errorFuncArg);
3216 }
3217 reader->rngValidErrors = 0;
3218 reader->rngFullNode = NULL;
3219 reader->validate = XML_TEXTREADER_VALIDATE_RNG;
3220 return(0);
3221}
3222
3223/**
Daniel Veillardf4e55762003-04-15 23:32:22 +00003224 * xmlTextReaderRelaxNGValidate:
3225 * @reader: the xmlTextReaderPtr used
3226 * @rng: the path to a RelaxNG schema or NULL
3227 *
3228 * Use RelaxNG to validate the document as it is processed.
3229 * Activation is only possible before the first Read().
3230 * if @rng is NULL, then RelaxNG validation is desactivated.
3231 *
3232 * Returns 0 in case the RelaxNG validation could be (des)activated and
3233 * -1 in case of error.
3234 */
3235int
3236xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
3237 xmlRelaxNGParserCtxtPtr ctxt;
3238
3239 if (reader == NULL)
3240 return(-1);
3241
3242 if (rng == NULL) {
3243 if (reader->rngSchemas != NULL) {
3244 xmlRelaxNGFree(reader->rngSchemas);
3245 reader->rngSchemas = NULL;
3246 }
3247 if (reader->rngValidCtxt != NULL) {
3248 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
3249 reader->rngValidCtxt = NULL;
3250 }
3251 return(0);
3252 }
3253 if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
3254 return(-1);
Daniel Veillard33300b42003-04-17 09:09:19 +00003255 if (reader->rngSchemas != NULL) {
3256 xmlRelaxNGFree(reader->rngSchemas);
3257 reader->rngSchemas = NULL;
3258 }
3259 if (reader->rngValidCtxt != NULL) {
3260 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
3261 reader->rngValidCtxt = NULL;
3262 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00003263 ctxt = xmlRelaxNGNewParserCtxt(rng);
3264 if (reader->errorFunc != NULL) {
3265 xmlRelaxNGSetParserErrors(ctxt,
3266 (xmlRelaxNGValidityErrorFunc) reader->errorFunc,
3267 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
3268 reader->errorFuncArg);
3269 }
3270 reader->rngSchemas = xmlRelaxNGParse(ctxt);
3271 xmlRelaxNGFreeParserCtxt(ctxt);
3272 if (reader->rngSchemas == NULL)
3273 return(-1);
3274 reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
3275 if (reader->rngValidCtxt == NULL)
3276 return(-1);
3277 if (reader->errorFunc != NULL) {
3278 xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
3279 (xmlRelaxNGValidityErrorFunc)reader->errorFunc,
3280 (xmlRelaxNGValidityWarningFunc) reader->errorFunc,
3281 reader->errorFuncArg);
3282 }
3283 reader->rngValidErrors = 0;
3284 reader->rngFullNode = NULL;
3285 reader->validate = XML_TEXTREADER_VALIDATE_RNG;
3286 return(0);
3287}
Daniel Veillard37fc84d2003-05-09 19:38:15 +00003288#endif
Daniel Veillardf4e55762003-04-15 23:32:22 +00003289
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003290/************************************************************************
3291 * *
Daniel Veillard26f70262003-01-16 22:45:08 +00003292 * Error Handling Extensions *
3293 * *
3294 ************************************************************************/
3295
3296/* helper to build a xmlMalloc'ed string from a format and va_list */
3297static char *
3298xmlTextReaderBuildMessage(const char *msg, va_list ap) {
3299 int size;
3300 int chars;
3301 char *larger;
3302 char *str;
3303
Daniel Veillard3c908dc2003-04-19 00:07:51 +00003304 str = (char *) xmlMallocAtomic(150);
Daniel Veillard26f70262003-01-16 22:45:08 +00003305 if (str == NULL) {
3306 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
3307 return NULL;
3308 }
3309
3310 size = 150;
3311
3312 while (1) {
3313 chars = vsnprintf(str, size, msg, ap);
3314 if ((chars > -1) && (chars < size))
3315 break;
3316 if (chars > -1)
3317 size += chars + 1;
3318 else
3319 size += 100;
3320 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
3321 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
3322 xmlFree(str);
3323 return NULL;
3324 }
3325 str = larger;
3326 }
3327
3328 return str;
3329}
3330
Daniel Veillard417be3a2003-01-20 21:26:34 +00003331/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00003332 * xmlTextReaderLocatorLineNumber:
Daniel Veillard417be3a2003-01-20 21:26:34 +00003333 * @locator: the xmlTextReaderLocatorPtr used
3334 *
3335 * Obtain the line number for the given locator.
3336 *
3337 * Returns the line number or -1 in case of error.
3338 */
3339int
3340xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
3341 /* we know that locator is a xmlParserCtxtPtr */
3342 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
3343 int ret = -1;
3344
3345 if (ctx->node != NULL) {
3346 ret = xmlGetLineNo(ctx->node);
3347 }
3348 else {
3349 /* inspired from error.c */
3350 xmlParserInputPtr input;
3351 input = ctx->input;
3352 if ((input->filename == NULL) && (ctx->inputNr > 1))
3353 input = ctx->inputTab[ctx->inputNr - 2];
3354 if (input != NULL) {
3355 ret = input->line;
3356 }
3357 else {
3358 ret = -1;
3359 }
3360 }
3361
3362 return ret;
3363}
3364
3365/**
Daniel Veillard540a31a2003-01-21 11:21:07 +00003366 * xmlTextReaderLocatorBaseURI:
Daniel Veillard417be3a2003-01-20 21:26:34 +00003367 * @locator: the xmlTextReaderLocatorPtr used
3368 *
3369 * Obtain the base URI for the given locator.
3370 *
3371 * Returns the base URI or NULL in case of error.
3372 */
3373xmlChar *
3374xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
3375 /* we know that locator is a xmlParserCtxtPtr */
3376 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
3377 xmlChar *ret = NULL;
3378
3379 if (ctx->node != NULL) {
3380 ret = xmlNodeGetBase(NULL,ctx->node);
3381 }
3382 else {
3383 /* inspired from error.c */
3384 xmlParserInputPtr input;
3385 input = ctx->input;
3386 if ((input->filename == NULL) && (ctx->inputNr > 1))
3387 input = ctx->inputTab[ctx->inputNr - 2];
3388 if (input != NULL) {
Daniel Veillard580ced82003-03-21 21:22:48 +00003389 ret = xmlStrdup(BAD_CAST input->filename);
Daniel Veillard417be3a2003-01-20 21:26:34 +00003390 }
3391 else {
3392 ret = NULL;
3393 }
3394 }
3395
3396 return ret;
3397}
3398
Daniel Veillard26f70262003-01-16 22:45:08 +00003399static void
3400xmlTextReaderGenericError(void *ctxt, int severity, char *str) {
3401 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
3402 xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private;
3403
3404 if (str != NULL) {
3405 reader->errorFunc(reader->errorFuncArg,
3406 str,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003407 severity,
3408 (xmlTextReaderLocatorPtr)ctx);
Daniel Veillard26f70262003-01-16 22:45:08 +00003409 xmlFree(str);
3410 }
3411}
3412
3413static void
3414xmlTextReaderError(void *ctxt, const char *msg, ...) {
3415 va_list ap;
3416
3417 va_start(ap,msg);
3418 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003419 XML_PARSER_SEVERITY_ERROR,
Daniel Veillard26f70262003-01-16 22:45:08 +00003420 xmlTextReaderBuildMessage(msg,ap));
3421 va_end(ap);
3422
3423}
3424
3425static void
3426xmlTextReaderWarning(void *ctxt, const char *msg, ...) {
3427 va_list ap;
3428
3429 va_start(ap,msg);
3430 xmlTextReaderGenericError(ctxt,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003431 XML_PARSER_SEVERITY_WARNING,
Daniel Veillard26f70262003-01-16 22:45:08 +00003432 xmlTextReaderBuildMessage(msg,ap));
3433 va_end(ap);
3434}
3435
3436static void
3437xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
3438 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00003439 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00003440
Daniel Veillard417be3a2003-01-20 21:26:34 +00003441 if ((len > 1) && (msg[len - 2] != ':')) {
3442 /*
3443 * some callbacks only report locator information:
3444 * skip them (mimicking behaviour in error.c)
3445 */
3446 va_start(ap,msg);
3447 xmlTextReaderGenericError(ctxt,
3448 XML_PARSER_SEVERITY_VALIDITY_ERROR,
3449 xmlTextReaderBuildMessage(msg,ap));
3450 va_end(ap);
3451 }
Daniel Veillard26f70262003-01-16 22:45:08 +00003452}
3453
3454static void
3455xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
3456 va_list ap;
Daniel Veillard417be3a2003-01-20 21:26:34 +00003457 int len = xmlStrlen((const xmlChar *) msg);
Daniel Veillard26f70262003-01-16 22:45:08 +00003458
Daniel Veillard417be3a2003-01-20 21:26:34 +00003459 if ((len != 0) && (msg[len - 1] != ':')) {
3460 /*
3461 * some callbacks only report locator information:
3462 * skip them (mimicking behaviour in error.c)
3463 */
3464 va_start(ap,msg);
3465 xmlTextReaderGenericError(ctxt,
3466 XML_PARSER_SEVERITY_VALIDITY_WARNING,
3467 xmlTextReaderBuildMessage(msg,ap));
3468 va_end(ap);
3469 }
Daniel Veillard26f70262003-01-16 22:45:08 +00003470}
3471
3472/**
3473 * xmlTextReaderSetErrorHandler:
3474 * @reader: the xmlTextReaderPtr used
3475 * @f: the callback function to call on error and warnings
3476 * @arg: a user argument to pass to the callback function
3477 *
Daniel Veillard417be3a2003-01-20 21:26:34 +00003478 * Register a callback function that will be called on error and warnings.
3479 *
Daniel Veillard26f70262003-01-16 22:45:08 +00003480 * If @f is NULL, the default error and warning handlers are restored.
3481 */
3482void
3483xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
3484 xmlTextReaderErrorFunc f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003485 void *arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00003486 if (f != NULL) {
3487 reader->ctxt->sax->error = xmlTextReaderError;
3488 reader->ctxt->vctxt.error = xmlTextReaderValidityError;
3489 reader->ctxt->sax->warning = xmlTextReaderWarning;
3490 reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
3491 reader->errorFunc = f;
3492 reader->errorFuncArg = arg;
3493 }
3494 else {
3495 /* restore defaults */
3496 reader->ctxt->sax->error = xmlParserError;
3497 reader->ctxt->vctxt.error = xmlParserValidityError;
3498 reader->ctxt->sax->warning = xmlParserWarning;
3499 reader->ctxt->vctxt.warning = xmlParserValidityWarning;
3500 reader->errorFunc = NULL;
3501 reader->errorFuncArg = NULL;
3502 }
3503}
3504
Daniel Veillard417be3a2003-01-20 21:26:34 +00003505/**
Daniel Veillardf6bad792003-04-11 19:38:54 +00003506 * xmlTextReaderIsValid:
3507 * @reader: the xmlTextReaderPtr used
3508 *
3509 * Retrieve the validity status from the parser context
3510 *
3511 * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
3512 */
3513int
3514xmlTextReaderIsValid(xmlTextReaderPtr reader) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00003515 if (reader == NULL) return(-1);
3516#ifdef LIBXML_SCHEMAS_ENABLED
3517 if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
3518 return(reader->rngValidErrors == 0);
3519#endif
3520 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
3521 (reader->ctxt != NULL))
3522 return(reader->ctxt->valid);
3523 return(0);
Daniel Veillardf6bad792003-04-11 19:38:54 +00003524}
3525
3526/**
Daniel Veillard417be3a2003-01-20 21:26:34 +00003527 * xmlTextReaderGetErrorHandler:
3528 * @reader: the xmlTextReaderPtr used
3529 * @f: the callback function or NULL is no callback has been registered
3530 * @arg: a user argument
3531 *
3532 * Retrieve the error callback function and user argument.
3533 */
Daniel Veillard26f70262003-01-16 22:45:08 +00003534void
3535xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
3536 xmlTextReaderErrorFunc *f,
Daniel Veillard417be3a2003-01-20 21:26:34 +00003537 void **arg) {
Daniel Veillard26f70262003-01-16 22:45:08 +00003538 *f = reader->errorFunc;
3539 *arg = reader->errorFuncArg;
3540}
3541
3542/************************************************************************
3543 * *
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003544 * Utilities *
3545 * *
3546 ************************************************************************/
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00003547#ifdef NOT_USED_YET
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003548/**
3549 * xmlBase64Decode:
3550 * @in: the input buffer
3551 * @inlen: the size of the input (in), the size read from it (out)
3552 * @to: the output buffer
3553 * @tolen: the size of the output (in), the size written to (out)
3554 *
3555 * Base64 decoder, reads from @in and save in @to
Daniel Veillardd4310742003-02-18 21:12:46 +00003556 * TODO: tell jody when this is actually exported
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003557 *
3558 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
3559 * 2 if there wasn't enough space on the output or -1 in case of error.
3560 */
3561static int
3562xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
3563 unsigned char *to, unsigned long *tolen) {
3564 unsigned long incur; /* current index in in[] */
3565 unsigned long inblk; /* last block index in in[] */
3566 unsigned long outcur; /* current index in out[] */
3567 unsigned long inmax; /* size of in[] */
3568 unsigned long outmax; /* size of out[] */
3569 unsigned char cur; /* the current value read from in[] */
Daniel Veillardc127adc2003-07-23 15:07:08 +00003570 unsigned char intmp[4], outtmp[4]; /* temporary buffers for the convert */
Daniel Veillardbeb70bd2002-12-18 14:53:54 +00003571 int nbintmp; /* number of byte in intmp[] */
3572 int is_ignore; /* cur should be ignored */
3573 int is_end = 0; /* the end of the base64 was found */
3574 int retval = 1;
3575 int i;
3576
3577 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
3578 return(-1);
3579
3580 incur = 0;
3581 inblk = 0;
3582 outcur = 0;
3583 inmax = *inlen;
3584 outmax = *tolen;
3585 nbintmp = 0;
3586
3587 while (1) {
3588 if (incur >= inmax)
3589 break;
3590 cur = in[incur++];
3591 is_ignore = 0;
3592 if ((cur >= 'A') && (cur <= 'Z'))
3593 cur = cur - 'A';
3594 else if ((cur >= 'a') && (cur <= 'z'))
3595 cur = cur - 'a' + 26;
3596 else if ((cur >= '0') && (cur <= '9'))
3597 cur = cur - '0' + 52;
3598 else if (cur == '+')
3599 cur = 62;
3600 else if (cur == '/')
3601 cur = 63;
3602 else if (cur == '.')
3603 cur = 0;
3604 else if (cur == '=') /*no op , end of the base64 stream */
3605 is_end = 1;
3606 else {
3607 is_ignore = 1;
3608 if (nbintmp == 0)
3609 inblk = incur;
3610 }
3611
3612 if (!is_ignore) {
3613 int nbouttmp = 3;
3614 int is_break = 0;
3615
3616 if (is_end) {
3617 if (nbintmp == 0)
3618 break;
3619 if ((nbintmp == 1) || (nbintmp == 2))
3620 nbouttmp = 1;
3621 else
3622 nbouttmp = 2;
3623 nbintmp = 3;
3624 is_break = 1;
3625 }
3626 intmp[nbintmp++] = cur;
3627 /*
3628 * if intmp is full, push the 4byte sequence as a 3 byte
3629 * sequence out
3630 */
3631 if (nbintmp == 4) {
3632 nbintmp = 0;
3633 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
3634 outtmp[1] =
3635 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
3636 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
3637 if (outcur + 3 >= outmax) {
3638 retval = 2;
3639 break;
3640 }
3641
3642 for (i = 0; i < nbouttmp; i++)
3643 to[outcur++] = outtmp[i];
3644 inblk = incur;
3645 }
3646
3647 if (is_break) {
3648 retval = 0;
3649 break;
3650 }
3651 }
3652 }
3653
3654 *tolen = outcur;
3655 *inlen = inblk;
3656 return (retval);
3657}
3658
3659/*
3660 * Test routine for the xmlBase64Decode function
3661 */
3662#if 0
3663int main(int argc, char **argv) {
3664 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== ";
3665 char output[100];
3666 char output2[100];
3667 char output3[100];
3668 unsigned long inlen = strlen(input);
3669 unsigned long outlen = 100;
3670 int ret;
3671 unsigned long cons, tmp, tmp2, prod;
3672
3673 /*
3674 * Direct
3675 */
3676 ret = xmlBase64Decode(input, &inlen, output, &outlen);
3677
3678 output[outlen] = 0;
3679 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
3680
3681 /*
3682 * output chunking
3683 */
3684 cons = 0;
3685 prod = 0;
3686 while (cons < inlen) {
3687 tmp = 5;
3688 tmp2 = inlen - cons;
3689
3690 printf("%ld %ld\n", cons, prod);
3691 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
3692 cons += tmp2;
3693 prod += tmp;
3694 printf("%ld %ld\n", cons, prod);
3695 }
3696 output2[outlen] = 0;
3697 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
3698
3699 /*
3700 * input chunking
3701 */
3702 cons = 0;
3703 prod = 0;
3704 while (cons < inlen) {
3705 tmp = 100 - prod;
3706 tmp2 = inlen - cons;
3707 if (tmp2 > 5)
3708 tmp2 = 5;
3709
3710 printf("%ld %ld\n", cons, prod);
3711 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
3712 cons += tmp2;
3713 prod += tmp;
3714 printf("%ld %ld\n", cons, prod);
3715 }
3716 output3[outlen] = 0;
3717 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
3718 return(0);
3719
3720}
3721#endif
Daniel Veillard9f7eb0b2003-09-17 10:26:25 +00003722#endif /* NOT_USED_YET */