xmlreader.c revision 1989505ac76a2fb386050a7116f1f61a0ec37bfd
1/* 2 * xmlreader.c: implements the xmlTextReader streaming node API 3 * 4 * NOTE: 5 * XmlTextReader.Normalization Property won't be supported, since 6 * it makes the parser non compliant to the XML recommendation 7 * 8 * See Copyright for the status of this software. 9 * 10 * daniel@veillard.com 11 */ 12 13/* 14 * TODOs: 15 * - provide an API to preserve part of the tree 16 * - Streaming XInclude support 17 * - validation against a provided DTD 18 * - XML Schemas validation 19 * - setting(s) for NoBlanks 20 * - performances and tuning ... 21 */ 22#define IN_LIBXML 23#include "libxml.h" 24 25#include <string.h> /* for memset() only ! */ 26#include <stdarg.h> 27 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> 38#include <libxml/relaxng.h> 39 40/* #define DEBUG_CALLBACKS */ 41/* #define DEBUG_READER */ 42 43/** 44 * TODO: 45 * 46 * macro to flag unimplemented blocks 47 */ 48#define TODO \ 49 xmlGenericError(xmlGenericErrorContext, \ 50 "Unimplemented block at %s:%d\n", \ 51 __FILE__, __LINE__); 52 53#ifdef DEBUG_READER 54#define DUMP_READER xmlTextReaderDebug(reader); 55#else 56#define DUMP_READER 57#endif 58 59#define CHUNK_SIZE 512 60/************************************************************************ 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 { 71 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 77} 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, 85 XML_TEXTREADER_BACKTRACK= 4, 86 XML_TEXTREADER_DONE= 5, 87 XML_TEXTREADER_ERROR= 6 88} xmlTextReaderState; 89 90typedef enum { 91 XML_TEXTREADER_NOT_VALIDATE = 0, 92 XML_TEXTREADER_VALIDATE_DTD = 1, 93 XML_TEXTREADER_VALIDATE_RNG = 2 94} xmlTextReaderValidate; 95 96struct _xmlTextReader { 97 int mode; /* the parsing mode */ 98 xmlTextReaderValidate validate;/* is there any validation */ 99 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 */ 106 startElementNsSAX2Func startElementNs;/* idem */ 107 endElementNsSAX2Func endElementNs; /* idem */ 108 charactersSAXFunc characters; 109 cdataBlockSAXFunc cdataBlock; 110 unsigned int base; /* base of the segment in the input */ 111 unsigned int cur; /* current position in the input */ 112 xmlNodePtr node; /* current node */ 113 xmlNodePtr curnode;/* current attribute node */ 114 int depth; /* depth of the current node */ 115 xmlNodePtr faketext;/* fake xmlNs chld */ 116 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 */ 122 123 /* error handling */ 124 xmlTextReaderErrorFunc errorFunc; /* callback function */ 125 void *errorFuncArg; /* callback function user argument */ 126 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 134}; 135 136static const char *xmlTextReaderIsEmpty = "This element is empty"; 137 138/************************************************************************ 139 * * 140 * Our own version of the freeing routines as we recycle nodes * 141 * * 142 ************************************************************************/ 143 144static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur); 145static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur); 146 147/** 148 * xmlTextReaderFreeEntityWrapper: 149 * @entity: An entity 150 * @name: its name 151 * 152 * Deallocate the memory used by an entities in the hash table. 153 */ 154static void 155xmlTextReaderFreeEntityWrapper(xmlEntityPtr entity, 156 const xmlChar *name ATTRIBUTE_UNUSED) { 157 if (entity == NULL) return; 158 159 if ((entity->children) && (entity->owner == 1) && 160 (entity == (xmlEntityPtr) entity->children->parent)) { 161 xmlDocPtr doc; 162 xmlTextReaderPtr reader = NULL; 163 doc = entity->doc; 164 if (doc != NULL) 165 reader = doc->_private; 166 xmlTextReaderFreeNodeList(reader, entity->children); 167 } 168 if (entity->name != NULL) 169 xmlFree((char *) entity->name); 170 if (entity->ExternalID != NULL) 171 xmlFree((char *) entity->ExternalID); 172 if (entity->SystemID != NULL) 173 xmlFree((char *) entity->SystemID); 174 if (entity->URI != NULL) 175 xmlFree((char *) entity->URI); 176 if (entity->content != NULL) 177 xmlFree((char *) entity->content); 178 if (entity->orig != NULL) 179 xmlFree((char *) entity->orig); 180 xmlFree(entity); 181} 182 183/** 184 * xmlTextReaderFreeEntitiesTable: 185 * @table: An entity table 186 * 187 * Deallocate the memory used by an entities hash table. 188 */ 189static void 190xmlTextReaderFreeEntitiesTable(xmlEntitiesTablePtr table) { 191 xmlHashFree(table, (xmlHashDeallocator) xmlTextReaderFreeEntityWrapper); 192} 193 194/** 195 * xmlTextReaderFreeDtd: 196 * @cur: the DTD structure to free up 197 * 198 * Free a DTD structure. 199 */ 200static void 201xmlTextReaderFreeDtd(xmlTextReaderPtr reader, xmlDtdPtr cur) { 202 if (cur == NULL) return; 203 204 if (cur->children != NULL) { 205 xmlNodePtr next, c = cur->children; 206 207 /* 208 * Cleanup all the DTD comments they are not in the DTD 209 * indexes. 210 */ 211 while (c != NULL) { 212 next = c->next; 213 if ((c->type == XML_COMMENT_NODE) || (c->type == XML_PI_NODE)) { 214 xmlUnlinkNode(c); 215 xmlTextReaderFreeNode(reader, c); 216 } 217 c = next; 218 } 219 } 220 221 if (cur->name != NULL) xmlFree((char *) cur->name); 222 if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID); 223 if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID); 224 /* TODO !!! */ 225 if (cur->notations != NULL) 226 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations); 227 228 if (cur->elements != NULL) 229 xmlFreeElementTable((xmlElementTablePtr) cur->elements); 230 if (cur->attributes != NULL) 231 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes); 232 if (cur->pentities != NULL) 233 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities); 234 235 if (cur->entities != NULL) 236 xmlTextReaderFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities); 237 238 xmlFree(cur); 239} 240 241/** 242 * xmlTextReaderFreeProp: 243 * @reader: the xmlTextReaderPtr used 244 * @cur: the node 245 * 246 * Free a node. 247 */ 248static void 249xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) { 250 if (cur == NULL) return; 251 252 /* Check for ID removal -> leading to invalid references ! */ 253 if ((cur->parent != NULL) && (cur->parent->doc != NULL) && 254 ((cur->parent->doc->intSubset != NULL) || 255 (cur->parent->doc->extSubset != NULL))) { 256 if (xmlIsID(cur->parent->doc, cur->parent, cur)) 257 xmlRemoveID(cur->parent->doc, cur); 258 } 259 if (cur->children != NULL) 260 xmlTextReaderFreeNodeList(reader, cur->children); 261 262 if ((reader != NULL) && (reader->ctxt != NULL) && 263 (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) && 264 (cur->name != NULL)) 265 xmlFree((xmlChar *)cur->name); 266 if ((reader != NULL) && (reader->ctxt != NULL) && 267 (reader->ctxt->freeAttrsNr < 100)) { 268 cur->next = reader->ctxt->freeAttrs; 269 reader->ctxt->freeAttrs = cur; 270 reader->ctxt->freeAttrsNr++; 271 } else { 272 xmlFree(cur); 273 } 274} 275 276/** 277 * xmlTextReaderFreePropList: 278 * @reader: the xmlTextReaderPtr used 279 * @cur: the first property in the list 280 * 281 * Free a property and all its siblings, all the children are freed too. 282 */ 283static void 284xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) { 285 xmlAttrPtr next; 286 if (cur == NULL) return; 287 while (cur != NULL) { 288 next = cur->next; 289 xmlTextReaderFreeProp(reader, cur); 290 cur = next; 291 } 292} 293 294/** 295 * xmlTextReaderFreeNodeList: 296 * @reader: the xmlTextReaderPtr used 297 * @cur: the first node in the list 298 * 299 * Free a node and all its siblings, this is a recursive behaviour, all 300 * the children are freed too. 301 */ 302static void 303xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) { 304 xmlNodePtr next; 305 if (cur == NULL) return; 306 if (cur->type == XML_NAMESPACE_DECL) { 307 xmlFreeNsList((xmlNsPtr) cur); 308 return; 309 } 310 if ((cur->type == XML_DOCUMENT_NODE) || 311 (cur->type == XML_HTML_DOCUMENT_NODE)) { 312 xmlFreeDoc((xmlDocPtr) cur); 313 return; 314 } 315 while (cur != NULL) { 316 next = cur->next; 317 /* unroll to speed up freeing the document */ 318 if (cur->type != XML_DTD_NODE) { 319 320 if ((cur->children != NULL) && 321 (cur->type != XML_ENTITY_REF_NODE)) 322 xmlTextReaderFreeNodeList(reader, cur->children); 323 if (((cur->type == XML_ELEMENT_NODE) || 324 (cur->type == XML_XINCLUDE_START) || 325 (cur->type == XML_XINCLUDE_END)) && 326 (cur->properties != NULL)) 327 xmlTextReaderFreePropList(reader, cur->properties); 328 if ((cur->type != XML_ELEMENT_NODE) && 329 (cur->type != XML_XINCLUDE_START) && 330 (cur->type != XML_XINCLUDE_END) && 331 (cur->type != XML_ENTITY_REF_NODE)) { 332 if (cur->content != NULL) xmlFree(cur->content); 333 } 334 if (((cur->type == XML_ELEMENT_NODE) || 335 (cur->type == XML_XINCLUDE_START) || 336 (cur->type == XML_XINCLUDE_END)) && 337 (cur->nsDef != NULL)) 338 xmlFreeNsList(cur->nsDef); 339 340 /* 341 * we don't free element names here they are interned now 342 */ 343 if (cur->type == XML_ELEMENT_NODE) { 344 if ((reader != NULL) && (reader->ctxt != NULL) && 345 (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) && 346 (cur->name != NULL)) 347 xmlFree((xmlChar *)cur->name); 348 } else if ((cur->type != XML_TEXT_NODE) && 349 (cur->type != XML_COMMENT_NODE) && 350 (cur->name != NULL)) 351 xmlFree((xmlChar *)cur->name); 352 if (((cur->type == XML_ELEMENT_NODE) || 353 (cur->type == XML_TEXT_NODE)) && 354 (reader != NULL) && (reader->ctxt != NULL) && 355 (reader->ctxt->freeElemsNr < 100)) { 356 cur->next = reader->ctxt->freeElems; 357 reader->ctxt->freeElems = cur; 358 reader->ctxt->freeElemsNr++; 359 } else { 360 xmlFree(cur); 361 } 362 } 363 cur = next; 364 } 365} 366 367/** 368 * xmlTextReaderFreeNode: 369 * @reader: the xmlTextReaderPtr used 370 * @cur: the node 371 * 372 * Free a node, this is a recursive behaviour, all the children are freed too. 373 * This doesn't unlink the child from the list, use xmlUnlinkNode() first. 374 */ 375static void 376xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) { 377 if (cur->type == XML_DTD_NODE) { 378 xmlTextReaderFreeDtd(reader, (xmlDtdPtr) cur); 379 return; 380 } 381 if (cur->type == XML_NAMESPACE_DECL) { 382 xmlFreeNs((xmlNsPtr) cur); 383 return; 384 } 385 if (cur->type == XML_ATTRIBUTE_NODE) { 386 xmlTextReaderFreeProp(reader, (xmlAttrPtr) cur); 387 return; 388 } 389 390 if ((cur->children != NULL) && 391 (cur->type != XML_ENTITY_REF_NODE)) 392 xmlTextReaderFreeNodeList(reader, cur->children); 393 if (((cur->type == XML_ELEMENT_NODE) || 394 (cur->type == XML_XINCLUDE_START) || 395 (cur->type == XML_XINCLUDE_END)) && 396 (cur->properties != NULL)) 397 xmlTextReaderFreePropList(reader, cur->properties); 398 if ((cur->type != XML_ELEMENT_NODE) && 399 (cur->type != XML_XINCLUDE_START) && 400 (cur->type != XML_XINCLUDE_END) && 401 (cur->type != XML_ENTITY_REF_NODE)) { 402 if (cur->content != NULL) xmlFree(cur->content); 403 } 404 if (((cur->type == XML_ELEMENT_NODE) || 405 (cur->type == XML_XINCLUDE_START) || 406 (cur->type == XML_XINCLUDE_END)) && 407 (cur->nsDef != NULL)) 408 xmlFreeNsList(cur->nsDef); 409 410 /* 411 * we don't free names here they are interned now 412 */ 413 if (cur->type == XML_ELEMENT_NODE) { 414 if ((reader != NULL) && (reader->ctxt != NULL) && 415 (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) && 416 (cur->name != NULL)) 417 xmlFree((xmlChar *)cur->name); 418 } else if ((cur->type != XML_TEXT_NODE) && 419 (cur->type != XML_COMMENT_NODE) && 420 (cur->name != NULL)) 421 xmlFree((xmlChar *)cur->name); 422 if (((cur->type == XML_ELEMENT_NODE) || 423 (cur->type == XML_TEXT_NODE)) && 424 (reader != NULL) && (reader->ctxt != NULL) && 425 (reader->ctxt->freeElemsNr < 100)) { 426 cur->next = reader->ctxt->freeElems; 427 reader->ctxt->freeElems = cur; 428 reader->ctxt->freeElemsNr++; 429 } else { 430 xmlFree(cur); 431 } 432 433} 434 435/** 436 * xmlTextReaderFreeDoc: 437 * @reader: the xmlTextReaderPtr used 438 * @cur: pointer to the document 439 * 440 * Free up all the structures used by a document, tree included. 441 */ 442static void 443xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) { 444 xmlDtdPtr extSubset, intSubset; 445 446 if (cur == NULL) return; 447 448 /* 449 * Do this before freeing the children list to avoid ID lookups 450 */ 451 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids); 452 cur->ids = NULL; 453 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs); 454 cur->refs = NULL; 455 extSubset = cur->extSubset; 456 intSubset = cur->intSubset; 457 if (intSubset == extSubset) 458 extSubset = NULL; 459 if (extSubset != NULL) { 460 xmlUnlinkNode((xmlNodePtr) cur->extSubset); 461 cur->extSubset = NULL; 462 xmlTextReaderFreeDtd(reader, extSubset); 463 } 464 if (intSubset != NULL) { 465 xmlUnlinkNode((xmlNodePtr) cur->intSubset); 466 cur->intSubset = NULL; 467 xmlTextReaderFreeDtd(reader, intSubset); 468 } 469 470 if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children); 471 472 if (cur->version != NULL) xmlFree((char *) cur->version); 473 if (cur->name != NULL) xmlFree((char *) cur->name); 474 if (cur->encoding != NULL) xmlFree((char *) cur->encoding); 475 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs); 476 if (cur->URL != NULL) xmlFree((char *) cur->URL); 477 xmlFree(cur); 478} 479 480/************************************************************************ 481 * * 482 * The reader core parser * 483 * * 484 ************************************************************************/ 485#ifdef DEBUG_READER 486static void 487xmlTextReaderDebug(xmlTextReaderPtr reader) { 488 if ((reader == NULL) || (reader->ctxt == NULL)) { 489 fprintf(stderr, "xmlTextReader NULL\n"); 490 return; 491 } 492 fprintf(stderr, "xmlTextReader: state %d depth %d ", 493 reader->state, reader->depth); 494 if (reader->node == NULL) { 495 fprintf(stderr, "node = NULL\n"); 496 } else { 497 fprintf(stderr, "node %s\n", reader->node->name); 498 } 499 fprintf(stderr, " input: base %d, cur %d, depth %d: ", 500 reader->base, reader->cur, reader->ctxt->nodeNr); 501 if (reader->input->buffer == NULL) { 502 fprintf(stderr, "buffer is NULL\n"); 503 } else { 504#ifdef LIBXML_DEBUG_ENABLED 505 xmlDebugDumpString(stderr, 506 &reader->input->buffer->content[reader->cur]); 507#endif 508 fprintf(stderr, "\n"); 509 } 510} 511#endif 512 513/** 514 * xmlTextReaderEntPush: 515 * @reader: the xmlTextReaderPtr used 516 * @value: the entity reference node 517 * 518 * Pushes a new entity reference node on top of the entities stack 519 * 520 * Returns 0 in case of error, the index in the stack otherwise 521 */ 522static int 523xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value) 524{ 525 if (reader->entMax <= 0) { 526 reader->entMax = 10; 527 reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax * 528 sizeof(reader->entTab[0])); 529 if (reader->entTab == NULL) { 530 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n"); 531 return (0); 532 } 533 } 534 if (reader->entNr >= reader->entMax) { 535 reader->entMax *= 2; 536 reader->entTab = 537 (xmlNodePtr *) xmlRealloc(reader->entTab, 538 reader->entMax * 539 sizeof(reader->entTab[0])); 540 if (reader->entTab == NULL) { 541 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); 542 return (0); 543 } 544 } 545 reader->entTab[reader->entNr] = value; 546 reader->ent = value; 547 return (reader->entNr++); 548} 549 550/** 551 * xmlTextReaderEntPop: 552 * @reader: the xmlTextReaderPtr used 553 * 554 * Pops the top element entity from the entities stack 555 * 556 * Returns the entity just removed 557 */ 558static xmlNodePtr 559xmlTextReaderEntPop(xmlTextReaderPtr reader) 560{ 561 xmlNodePtr ret; 562 563 if (reader->entNr <= 0) 564 return (0); 565 reader->entNr--; 566 if (reader->entNr > 0) 567 reader->ent = reader->entTab[reader->entNr - 1]; 568 else 569 reader->ent = NULL; 570 ret = reader->entTab[reader->entNr]; 571 reader->entTab[reader->entNr] = 0; 572 return (ret); 573} 574 575/** 576 * xmlTextReaderStartElement: 577 * @ctx: the user data (XML parser context) 578 * @fullname: The element name, including namespace prefix 579 * @atts: An array of name/value attributes pairs, NULL terminated 580 * 581 * called when an opening tag has been processed. 582 */ 583static void 584xmlTextReaderStartElement(void *ctx, const xmlChar *fullname, 585 const xmlChar **atts) { 586 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 587 xmlTextReaderPtr reader = ctxt->_private; 588 589#ifdef DEBUG_CALLBACKS 590 printf("xmlTextReaderStartElement(%s)\n", fullname); 591#endif 592 if ((reader != NULL) && (reader->startElement != NULL)) { 593 reader->startElement(ctx, fullname, atts); 594 if ((ctxt->node != NULL) && (ctxt->input != NULL) && 595 (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') && 596 (ctxt->input->cur[1] == '>')) 597 ctxt->node->_private = (void *) xmlTextReaderIsEmpty; 598 } 599 if (reader != NULL) 600 reader->state = XML_TEXTREADER_ELEMENT; 601} 602 603/** 604 * xmlTextReaderEndElement: 605 * @ctx: the user data (XML parser context) 606 * @fullname: The element name, including namespace prefix 607 * 608 * called when an ending tag has been processed. 609 */ 610static void 611xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) { 612 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 613 xmlTextReaderPtr reader = ctxt->_private; 614 615#ifdef DEBUG_CALLBACKS 616 printf("xmlTextReaderEndElement(%s)\n", fullname); 617#endif 618 if ((reader != NULL) && (reader->endElement != NULL)) { 619 reader->endElement(ctx, fullname); 620 } 621} 622 623/** 624 * xmlTextReaderStartElementNs: 625 * @ctx: the user data (XML parser context) 626 * @localname: the local name of the element 627 * @prefix: the element namespace prefix if available 628 * @URI: the element namespace name if available 629 * @nb_namespaces: number of namespace definitions on that node 630 * @namespaces: pointer to the array of prefix/URI pairs namespace definitions 631 * @nb_attributes: the number of attributes on that node 632 * nb_defaulted: the number of defaulted attributes. 633 * @attributes: pointer to the array of (localname/prefix/URI/value/end) 634 * attribute values. 635 * 636 * called when an opening tag has been processed. 637 */ 638static void 639xmlTextReaderStartElementNs(void *ctx, 640 const xmlChar *localname, 641 const xmlChar *prefix, 642 const xmlChar *URI, 643 int nb_namespaces, 644 const xmlChar **namespaces, 645 int nb_attributes, 646 int nb_defaulted, 647 const xmlChar **attributes) 648{ 649 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 650 xmlTextReaderPtr reader = ctxt->_private; 651 652#ifdef DEBUG_CALLBACKS 653 printf("xmlTextReaderStartElementNs(%s)\n", fullname); 654#endif 655 if ((reader != NULL) && (reader->startElementNs != NULL)) { 656 reader->startElementNs(ctx, localname, prefix, URI, nb_namespaces, 657 namespaces, nb_attributes, nb_defaulted, 658 attributes); 659 if ((ctxt->node != NULL) && (ctxt->input != NULL) && 660 (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') && 661 (ctxt->input->cur[1] == '>')) 662 ctxt->node->_private = (void *) xmlTextReaderIsEmpty; 663 } 664 if (reader != NULL) 665 reader->state = XML_TEXTREADER_ELEMENT; 666} 667 668/** 669 * xmlTextReaderEndElementNs: 670 * @ctx: the user data (XML parser context) 671 * @localname: the local name of the element 672 * @prefix: the element namespace prefix if available 673 * @URI: the element namespace name if available 674 * 675 * called when an ending tag has been processed. 676 */ 677static void 678xmlTextReaderEndElementNs(void *ctx, 679 const xmlChar * localname, 680 const xmlChar * prefix, 681 const xmlChar * URI) 682{ 683 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 684 xmlTextReaderPtr reader = ctxt->_private; 685 686#ifdef DEBUG_CALLBACKS 687 printf("xmlTextReaderEndElementNs(%s)\n", fullname); 688#endif 689 if ((reader != NULL) && (reader->endElementNs != NULL)) { 690 reader->endElementNs(ctx, localname, prefix, URI); 691 } 692} 693 694 695/** 696 * xmlTextReaderCharacters: 697 * @ctx: the user data (XML parser context) 698 * @ch: a xmlChar string 699 * @len: the number of xmlChar 700 * 701 * receiving some chars from the parser. 702 */ 703static void 704xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len) 705{ 706 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 707 xmlTextReaderPtr reader = ctxt->_private; 708 709#ifdef DEBUG_CALLBACKS 710 printf("xmlTextReaderCharacters()\n"); 711#endif 712 if ((reader != NULL) && (reader->characters != NULL)) { 713 reader->characters(ctx, ch, len); 714 } 715} 716 717/** 718 * xmlTextReaderCDataBlock: 719 * @ctx: the user data (XML parser context) 720 * @value: The pcdata content 721 * @len: the block length 722 * 723 * called when a pcdata block has been parsed 724 */ 725static void 726xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len) 727{ 728 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 729 xmlTextReaderPtr reader = ctxt->_private; 730 731#ifdef DEBUG_CALLBACKS 732 printf("xmlTextReaderCDataBlock()\n"); 733#endif 734 if ((reader != NULL) && (reader->cdataBlock != NULL)) { 735 reader->cdataBlock(ctx, ch, len); 736 } 737} 738 739/** 740 * xmlTextReaderPushData: 741 * @reader: the xmlTextReaderPtr used 742 * 743 * Push data down the progressive parser until a significant callback 744 * got raised. 745 * 746 * Returns -1 in case of failure, 0 otherwise 747 */ 748static int 749xmlTextReaderPushData(xmlTextReaderPtr reader) { 750 xmlBufferPtr inbuf; 751 int val, s; 752 xmlTextReaderState oldstate; 753 754 if ((reader->input == NULL) || (reader->input->buffer == NULL)) 755 return(-1); 756 757 oldstate = reader->state; 758 reader->state = XML_TEXTREADER_NONE; 759 inbuf = reader->input->buffer; 760 761 while (reader->state == XML_TEXTREADER_NONE) { 762 if (inbuf->use < reader->cur + CHUNK_SIZE) { 763 /* 764 * Refill the buffer unless we are at the end of the stream 765 */ 766 if (reader->mode != XML_TEXTREADER_MODE_EOF) { 767 val = xmlParserInputBufferRead(reader->input, 4096); 768 if (val <= 0) { 769 reader->mode = XML_TEXTREADER_MODE_EOF; 770 reader->state = oldstate; 771 if ((oldstate != XML_TEXTREADER_START) || 772 (reader->ctxt->myDoc != NULL)) 773 return(val); 774 } 775 776 } else 777 break; 778 } 779 /* 780 * parse by block of CHUNK_SIZE bytes, various tests show that 781 * it's the best tradeoff at least on a 1.2GH Duron 782 */ 783 if (inbuf->use >= reader->cur + CHUNK_SIZE) { 784 val = xmlParseChunk(reader->ctxt, 785 (const char *) &inbuf->content[reader->cur], 786 CHUNK_SIZE, 0); 787 reader->cur += CHUNK_SIZE; 788 if (val != 0) 789 return(-1); 790 } else { 791 s = inbuf->use - reader->cur; 792 val = xmlParseChunk(reader->ctxt, 793 (const char *) &inbuf->content[reader->cur], 794 s, 0); 795 reader->cur += s; 796 if (val != 0) 797 return(-1); 798 break; 799 } 800 } 801 802 /* 803 * Discard the consumed input when needed and possible 804 */ 805 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) { 806 if (reader->cur >= 4096) { 807 val = xmlBufferShrink(inbuf, reader->cur); 808 if (val >= 0) { 809 reader->cur -= val; 810 } 811 } 812 } 813 814 /* 815 * At the end of the stream signal that the work is done to the Push 816 * parser. 817 */ 818 else if (reader->mode == XML_TEXTREADER_MODE_EOF) { 819 if (reader->mode != XML_TEXTREADER_DONE) { 820 s = inbuf->use - reader->cur; 821 val = xmlParseChunk(reader->ctxt, 822 (const char *) &inbuf->content[reader->cur], 823 s, 1); 824 reader->cur = inbuf->use; 825 reader->mode = XML_TEXTREADER_DONE; 826 if (val != 0) return(-1); 827 } 828 } 829 reader->state = oldstate; 830 return(0); 831} 832 833/** 834 * xmlTextReaderValidatePush: 835 * @reader: the xmlTextReaderPtr used 836 * 837 * Push the current node for validation 838 */ 839static void 840xmlTextReaderValidatePush(xmlTextReaderPtr reader) { 841#ifdef LIBXML_REGEXP_ENABLED 842 xmlNodePtr node = reader->node; 843 844 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) && 845 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) { 846 if ((node->ns == NULL) || (node->ns->prefix == NULL)) { 847 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt, 848 reader->ctxt->myDoc, node, node->name); 849 } else { 850 /* TODO use the BuildQName interface */ 851 xmlChar *qname; 852 853 qname = xmlStrdup(node->ns->prefix); 854 qname = xmlStrcat(qname, BAD_CAST ":"); 855 qname = xmlStrcat(qname, node->name); 856 reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt, 857 reader->ctxt->myDoc, node, qname); 858 if (qname != NULL) 859 xmlFree(qname); 860 } 861#ifdef LIBXML_SCHEMAS_ENABLED 862 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) && 863 (reader->rngValidCtxt != NULL)) { 864 int ret; 865 866 if (reader->rngFullNode != NULL) return; 867 ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt, 868 reader->ctxt->myDoc, 869 node); 870 if (ret == 0) { 871 /* 872 * this element requires a full tree 873 */ 874 node = xmlTextReaderExpand(reader); 875 if (node == NULL) { 876printf("Expand failed !\n"); 877 ret = -1; 878 } else { 879 ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt, 880 reader->ctxt->myDoc, 881 node); 882 reader->rngFullNode = node; 883 } 884 } 885 if (ret != 1) 886 reader->rngValidErrors++; 887#endif 888 } 889#endif /* LIBXML_REGEXP_ENABLED */ 890} 891 892/** 893 * xmlTextReaderValidateCData: 894 * @reader: the xmlTextReaderPtr used 895 * @data: pointer to the CData 896 * @len: lenght of the CData block in bytes. 897 * 898 * Push some CData for validation 899 */ 900static void 901xmlTextReaderValidateCData(xmlTextReaderPtr reader, 902 const xmlChar *data, int len) { 903#ifdef LIBXML_REGEXP_ENABLED 904 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) && 905 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) { 906 reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt, 907 data, len); 908#ifdef LIBXML_SCHEMAS_ENABLED 909 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) && 910 (reader->rngValidCtxt != NULL)) { 911 int ret; 912 913 if (reader->rngFullNode != NULL) return; 914 ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len); 915 if (ret != 1) 916 reader->rngValidErrors++; 917#endif 918 } 919#endif /* LIBXML_REGEXP_ENABLED */ 920} 921 922/** 923 * xmlTextReaderValidatePop: 924 * @reader: the xmlTextReaderPtr used 925 * 926 * Pop the current node from validation 927 */ 928static void 929xmlTextReaderValidatePop(xmlTextReaderPtr reader) { 930#ifdef LIBXML_REGEXP_ENABLED 931 xmlNodePtr node = reader->node; 932 933 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) && 934 (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) { 935 if ((node->ns == NULL) || (node->ns->prefix == NULL)) { 936 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt, 937 reader->ctxt->myDoc, node, node->name); 938 } else { 939 /* TODO use the BuildQName interface */ 940 xmlChar *qname; 941 942 qname = xmlStrdup(node->ns->prefix); 943 qname = xmlStrcat(qname, BAD_CAST ":"); 944 qname = xmlStrcat(qname, node->name); 945 reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt, 946 reader->ctxt->myDoc, node, qname); 947 if (qname != NULL) 948 xmlFree(qname); 949 } 950#ifdef LIBXML_SCHEMAS_ENABLED 951 } else if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) && 952 (reader->rngValidCtxt != NULL)) { 953 int ret; 954 955 if (reader->rngFullNode != NULL) { 956 if (node == reader->rngFullNode) 957 reader->rngFullNode = NULL; 958 return; 959 } 960 ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt, 961 reader->ctxt->myDoc, 962 node); 963 if (ret != 1) 964 reader->rngValidErrors++; 965#endif 966 } 967#endif /* LIBXML_REGEXP_ENABLED */ 968} 969/** 970 * xmlTextReaderValidateEntity: 971 * @reader: the xmlTextReaderPtr used 972 * 973 * Handle the validation when an entity reference is encountered and 974 * entity substitution is not activated. As a result the parser interface 975 * must walk through the entity and do the validation calls 976 */ 977static void 978xmlTextReaderValidateEntity(xmlTextReaderPtr reader) { 979#ifdef LIBXML_REGEXP_ENABLED 980 xmlNodePtr oldnode = reader->node; 981 xmlNodePtr node = reader->node; 982 xmlParserCtxtPtr ctxt = reader->ctxt; 983 984 do { 985 if (node->type == XML_ENTITY_REF_NODE) { 986 /* 987 * Case where the underlying tree is not availble, lookup the entity 988 * and walk it. 989 */ 990 if ((node->children == NULL) && (ctxt->sax != NULL) && 991 (ctxt->sax->getEntity != NULL)) { 992 node->children = (xmlNodePtr) 993 ctxt->sax->getEntity(ctxt, node->name); 994 } 995 996 if ((node->children != NULL) && 997 (node->children->type == XML_ENTITY_DECL) && 998 (node->children->children != NULL)) { 999 xmlTextReaderEntPush(reader, node); 1000 node = node->children->children; 1001 continue; 1002 } else { 1003 /* 1004 * The error has probably be raised already. 1005 */ 1006 if (node == oldnode) 1007 break; 1008 node = node->next; 1009 } 1010 } else if (node->type == XML_ELEMENT_NODE) { 1011 reader->node = node; 1012 xmlTextReaderValidatePush(reader); 1013 } else if ((node->type == XML_TEXT_NODE) || 1014 (node->type == XML_CDATA_SECTION_NODE)) { 1015 xmlTextReaderValidateCData(reader, node->content, 1016 xmlStrlen(node->content)); 1017 } 1018 1019 /* 1020 * go to next node 1021 */ 1022 if (node->children != NULL) { 1023 node = node->children; 1024 continue; 1025 } else if (node->type == XML_ELEMENT_NODE) { 1026 xmlTextReaderValidatePop(reader); 1027 } 1028 if (node->next != NULL) { 1029 node = node->next; 1030 continue; 1031 } 1032 do { 1033 node = node->parent; 1034 if (node->type == XML_ELEMENT_NODE) { 1035 reader->node = node; 1036 xmlTextReaderValidatePop(reader); 1037 } 1038 if ((node->type == XML_ENTITY_DECL) && 1039 (reader->ent != NULL) && (reader->ent->children == node)) { 1040 node = xmlTextReaderEntPop(reader); 1041 } 1042 if (node == oldnode) 1043 break; 1044 if (node->next != NULL) { 1045 node = node->next; 1046 break; 1047 } 1048 } while ((node != NULL) && (node != oldnode)); 1049 } while ((node != NULL) && (node != oldnode)); 1050 reader->node = oldnode; 1051#endif /* LIBXML_REGEXP_ENABLED */ 1052} 1053 1054 1055/** 1056 * xmlTextReaderGetSuccessor: 1057 * @cur: the current node 1058 * 1059 * Get the successor of a node if available. 1060 * 1061 * Returns the successor node or NULL 1062 */ 1063static xmlNodePtr 1064xmlTextReaderGetSuccessor(xmlNodePtr cur) { 1065 if (cur == NULL) return(NULL) ; /* ERROR */ 1066 if (cur->next != NULL) return(cur->next) ; 1067 do { 1068 cur = cur->parent; 1069 if (cur == NULL) return(NULL); 1070 if (cur->next != NULL) return(cur->next); 1071 } while (cur != NULL); 1072 return(cur); 1073} 1074 1075/** 1076 * xmlTextReaderDoExpand: 1077 * @reader: the xmlTextReaderPtr used 1078 * 1079 * Makes sure that the current node is fully read as well as all its 1080 * descendant. It means the full DOM subtree must be available at the 1081 * end of the call. 1082 * 1083 * Returns 1 if the node was expanded successfully, 0 if there is no more 1084 * nodes to read, or -1 in case of error 1085 */ 1086static int 1087xmlTextReaderDoExpand(xmlTextReaderPtr reader) { 1088 int val; 1089 1090 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL)) 1091 return(-1); 1092 1093 do { 1094 if (xmlTextReaderGetSuccessor(reader->node) != NULL) 1095 return(1); 1096 if (reader->ctxt->nodeNr <= reader->depth) 1097 return(1); 1098 if (reader->mode == XML_TEXTREADER_MODE_EOF) 1099 return(1); 1100 val = xmlTextReaderPushData(reader); 1101 if (val < 0) 1102 return(-1); 1103 } while(reader->mode != XML_TEXTREADER_MODE_EOF); 1104 return(1); 1105} 1106 1107/** 1108 * xmlTextReaderRead: 1109 * @reader: the xmlTextReaderPtr used 1110 * 1111 * Moves the position of the current instance to the next node in 1112 * the stream, exposing its properties. 1113 * 1114 * Returns 1 if the node was read successfully, 0 if there is no more 1115 * nodes to read, or -1 in case of error 1116 */ 1117int 1118xmlTextReaderRead(xmlTextReaderPtr reader) { 1119 int val, olddepth = 0; 1120 xmlTextReaderState oldstate = 0; 1121 xmlNodePtr oldnode = NULL; 1122 1123 if ((reader == NULL) || (reader->ctxt == NULL)) 1124 return(-1); 1125 if (reader->ctxt->wellFormed != 1) 1126 return(-1); 1127 1128#ifdef DEBUG_READER 1129 fprintf(stderr, "\nREAD "); 1130 DUMP_READER 1131#endif 1132 reader->curnode = NULL; 1133 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) { 1134 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE; 1135 /* 1136 * Initial state 1137 */ 1138 do { 1139 val = xmlTextReaderPushData(reader); 1140 if (val < 0) 1141 return(-1); 1142 } while ((reader->ctxt->node == NULL) && 1143 ((reader->mode != XML_TEXTREADER_MODE_EOF) && 1144 (reader->mode != XML_TEXTREADER_DONE))); 1145 if (reader->ctxt->myDoc != NULL) 1146 reader->ctxt->myDoc->_private = reader; 1147 if (reader->ctxt->node == NULL) { 1148 if (reader->ctxt->myDoc != NULL) { 1149 reader->node = reader->ctxt->myDoc->children; 1150 } 1151 if (reader->node == NULL) 1152 return(-1); 1153 reader->state = XML_TEXTREADER_ELEMENT; 1154 } else { 1155 if (reader->ctxt->myDoc != NULL) { 1156 reader->node = reader->ctxt->myDoc->children; 1157 } 1158 if (reader->node == NULL) 1159 reader->node = reader->ctxt->nodeTab[0]; 1160 reader->state = XML_TEXTREADER_ELEMENT; 1161 } 1162 reader->depth = 0; 1163 goto node_found; 1164 } 1165 oldstate = reader->state; 1166 olddepth = reader->ctxt->nodeNr; 1167 oldnode = reader->node; 1168 1169get_next_node: 1170 /* 1171 * If we are not backtracking on ancestors or examined nodes, 1172 * that the parser didn't finished or that we arent at the end 1173 * of stream, continue processing. 1174 */ 1175 while ((reader->node->next == NULL) && 1176 (reader->ctxt->nodeNr == olddepth) && 1177 ((oldstate == XML_TEXTREADER_BACKTRACK) || 1178 (reader->node->children == NULL) || 1179 (reader->node->type == XML_ENTITY_REF_NODE) || 1180 ((reader->node->children != NULL) && 1181 (reader->node->children->type == XML_TEXT_NODE) && 1182 (reader->node->children->next == NULL)) || 1183 (reader->node->type == XML_DTD_NODE) || 1184 (reader->node->type == XML_DOCUMENT_NODE) || 1185 (reader->node->type == XML_HTML_DOCUMENT_NODE)) && 1186 ((reader->ctxt->node == NULL) || 1187 (reader->ctxt->node == reader->node) || 1188 (reader->ctxt->node == reader->node->parent)) && 1189 (reader->ctxt->instate != XML_PARSER_EOF)) { 1190 val = xmlTextReaderPushData(reader); 1191 if (val < 0) 1192 return(-1); 1193 if (reader->node == NULL) 1194 goto node_end; 1195 } 1196 if (oldstate != XML_TEXTREADER_BACKTRACK) { 1197 if ((reader->node->children != NULL) && 1198 (reader->node->type != XML_ENTITY_REF_NODE) && 1199 (reader->node->type != XML_DTD_NODE)) { 1200 reader->node = reader->node->children; 1201 reader->depth++; 1202 reader->state = XML_TEXTREADER_ELEMENT; 1203 goto node_found; 1204 } 1205 } 1206 if (reader->node->next != NULL) { 1207 if ((oldstate == XML_TEXTREADER_ELEMENT) && 1208 (reader->node->type == XML_ELEMENT_NODE) && 1209 (reader->node->children == NULL) && 1210 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) { 1211 reader->state = XML_TEXTREADER_END; 1212 goto node_found; 1213 } 1214 if ((reader->validate) && 1215 (reader->node->type == XML_ELEMENT_NODE)) 1216 xmlTextReaderValidatePop(reader); 1217 reader->node = reader->node->next; 1218 reader->state = XML_TEXTREADER_ELEMENT; 1219 1220 /* 1221 * Cleanup of the old node 1222 */ 1223 if ((reader->node->prev != NULL) && 1224 (reader->node->prev->type != XML_DTD_NODE)) { 1225 xmlNodePtr tmp = reader->node->prev; 1226 xmlUnlinkNode(tmp); 1227 xmlTextReaderFreeNode(reader, tmp); 1228 } 1229 1230 goto node_found; 1231 } 1232 if ((oldstate == XML_TEXTREADER_ELEMENT) && 1233 (reader->node->type == XML_ELEMENT_NODE) && 1234 (reader->node->children == NULL) && 1235 (reader->node->_private != (void *)xmlTextReaderIsEmpty)) { 1236 reader->state = XML_TEXTREADER_END; 1237 goto node_found; 1238 } 1239 if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE)) 1240 xmlTextReaderValidatePop(reader); 1241 reader->node = reader->node->parent; 1242 if ((reader->node == NULL) || 1243 (reader->node->type == XML_DOCUMENT_NODE) || 1244#ifdef LIBXML_DOCB_ENABLED 1245 (reader->node->type == XML_DOCB_DOCUMENT_NODE) || 1246#endif 1247 (reader->node->type == XML_HTML_DOCUMENT_NODE)) { 1248 if (reader->mode != XML_TEXTREADER_DONE) { 1249 val = xmlParseChunk(reader->ctxt, "", 0, 1); 1250 reader->mode = XML_TEXTREADER_DONE; 1251 } 1252 reader->node = NULL; 1253 reader->depth = -1; 1254 1255 /* 1256 * Cleanup of the old node 1257 */ 1258 if (oldnode->type != XML_DTD_NODE) { 1259 xmlUnlinkNode(oldnode); 1260 xmlTextReaderFreeNode(reader, oldnode); 1261 } 1262 1263 goto node_end; 1264 } 1265 reader->depth--; 1266 reader->state = XML_TEXTREADER_BACKTRACK; 1267 1268node_found: 1269 DUMP_READER 1270 1271 /* 1272 * If we are in the middle of a piece of CDATA make sure it's finished 1273 */ 1274 if ((reader->node != NULL) && 1275 ((reader->node->type == XML_TEXT_NODE) || 1276 (reader->node->type == XML_CDATA_SECTION_NODE))) { 1277 xmlTextReaderExpand(reader); 1278 } 1279 1280 /* 1281 * Handle entities enter and exit when in entity replacement mode 1282 */ 1283 if ((reader->node != NULL) && 1284 (reader->node->type == XML_ENTITY_REF_NODE) && 1285 (reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) { 1286 /* 1287 * Case where the underlying tree is not availble, lookup the entity 1288 * and walk it. 1289 */ 1290 if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) && 1291 (reader->ctxt->sax->getEntity != NULL)) { 1292 reader->node->children = (xmlNodePtr) 1293 reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name); 1294 } 1295 1296 if ((reader->node->children != NULL) && 1297 (reader->node->children->type == XML_ENTITY_DECL) && 1298 (reader->node->children->children != NULL)) { 1299 xmlTextReaderEntPush(reader, reader->node); 1300 reader->node = reader->node->children->children; 1301 } 1302 } else if ((reader->node != NULL) && 1303 (reader->node->type == XML_ENTITY_REF_NODE) && 1304 (reader->ctxt != NULL) && (reader->validate)) { 1305 xmlTextReaderValidateEntity(reader); 1306 } 1307 if ((reader->node != NULL) && 1308 (reader->node->type == XML_ENTITY_DECL) && 1309 (reader->ent != NULL) && (reader->ent->children == reader->node)) { 1310 reader->node = xmlTextReaderEntPop(reader); 1311 reader->depth++; 1312 goto get_next_node; 1313 } 1314#ifdef LIBXML_REGEXP_ENABLED 1315 if ((reader->validate) && (reader->node != NULL)) { 1316 xmlNodePtr node = reader->node; 1317 1318 if ((node->type == XML_ELEMENT_NODE) && 1319 ((reader->state != XML_TEXTREADER_END) && 1320 (reader->state != XML_TEXTREADER_BACKTRACK))) { 1321 xmlTextReaderValidatePush(reader); 1322 } else if ((node->type == XML_TEXT_NODE) || 1323 (node->type == XML_CDATA_SECTION_NODE)) { 1324 xmlTextReaderValidateCData(reader, node->content, 1325 xmlStrlen(node->content)); 1326 } 1327 } 1328#endif /* LIBXML_REGEXP_ENABLED */ 1329 return(1); 1330node_end: 1331 reader->mode = XML_TEXTREADER_DONE; 1332 return(0); 1333} 1334 1335/** 1336 * xmlTextReaderReadState: 1337 * @reader: the xmlTextReaderPtr used 1338 * 1339 * Gets the read state of the reader. 1340 * 1341 * Returns the state value, or -1 in case of error 1342 */ 1343int 1344xmlTextReaderReadState(xmlTextReaderPtr reader) { 1345 if (reader == NULL) 1346 return(-1); 1347 return(reader->mode); 1348} 1349 1350/** 1351 * xmlTextReaderExpand: 1352 * @reader: the xmlTextReaderPtr used 1353 * 1354 * Reads the contents of the current node and the full subtree. It then makes 1355 * the subtree available until the next xmlTextReaderRead() call 1356 * 1357 * Returns a node pointer valid until the next xmlTextReaderRead() call 1358 * or NULL in case of error. 1359 */ 1360xmlNodePtr 1361xmlTextReaderExpand(xmlTextReaderPtr reader) { 1362 if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL)) 1363 return(NULL); 1364 if (xmlTextReaderDoExpand(reader) < 0) 1365 return(NULL); 1366 return(reader->node); 1367} 1368 1369/** 1370 * xmlTextReaderNext: 1371 * @reader: the xmlTextReaderPtr used 1372 * 1373 * Skip to the node following the current one in document order while 1374 * avoiding the subtree if any. 1375 * 1376 * Returns 1 if the node was read successfully, 0 if there is no more 1377 * nodes to read, or -1 in case of error 1378 */ 1379int 1380xmlTextReaderNext(xmlTextReaderPtr reader) { 1381 int ret; 1382 xmlNodePtr cur; 1383 1384 if (reader == NULL) 1385 return(-1); 1386 cur = reader->node; 1387 if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) 1388 return(xmlTextReaderRead(reader)); 1389 if (reader->state == XML_TEXTREADER_END) 1390 return(xmlTextReaderRead(reader)); 1391 if (cur->_private == (void *)xmlTextReaderIsEmpty) 1392 return(xmlTextReaderRead(reader)); 1393 do { 1394 ret = xmlTextReaderRead(reader); 1395 if (ret != 1) 1396 return(ret); 1397 } while (reader->node != cur); 1398 return(xmlTextReaderRead(reader)); 1399} 1400 1401/** 1402 * xmlTextReaderReadInnerXml: 1403 * @reader: the xmlTextReaderPtr used 1404 * 1405 * Reads the contents of the current node, including child nodes and markup. 1406 * 1407 * Returns a string containing the XML content, or NULL if the current node 1408 * is neither an element nor attribute, or has no child nodes. The 1409 * string must be deallocated by the caller. 1410 */ 1411xmlChar * 1412xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { 1413 TODO 1414 return(NULL); 1415} 1416 1417/** 1418 * xmlTextReaderReadOuterXml: 1419 * @reader: the xmlTextReaderPtr used 1420 * 1421 * Reads the contents of the current node, including child nodes and markup. 1422 * 1423 * Returns a string containing the XML content, or NULL if the current node 1424 * is neither an element nor attribute, or has no child nodes. The 1425 * string must be deallocated by the caller. 1426 */ 1427xmlChar * 1428xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { 1429 TODO 1430 return(NULL); 1431} 1432 1433/** 1434 * xmlTextReaderReadString: 1435 * @reader: the xmlTextReaderPtr used 1436 * 1437 * Reads the contents of an element or a text node as a string. 1438 * 1439 * Returns a string containing the contents of the Element or Text node, 1440 * or NULL if the reader is positioned on any other type of node. 1441 * The string must be deallocated by the caller. 1442 */ 1443xmlChar * 1444xmlTextReaderReadString(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { 1445 TODO 1446 return(NULL); 1447} 1448 1449#if 0 1450/** 1451 * xmlTextReaderReadBase64: 1452 * @reader: the xmlTextReaderPtr used 1453 * @array: a byte array to store the content. 1454 * @offset: the zero-based index into array where the method should 1455 * begin to write. 1456 * @len: the number of bytes to write. 1457 * 1458 * Reads and decodes the Base64 encoded contents of an element and 1459 * stores the result in a byte buffer. 1460 * 1461 * Returns the number of bytes written to array, or zero if the current 1462 * instance is not positioned on an element or -1 in case of error. 1463 */ 1464int 1465xmlTextReaderReadBase64(xmlTextReaderPtr reader, 1466 unsigned char *array ATTRIBUTE_UNUSED, 1467 int offset ATTRIBUTE_UNUSED, 1468 int len ATTRIBUTE_UNUSED) { 1469 if ((reader == NULL) || (reader->ctxt == NULL)) 1470 return(-1); 1471 if (reader->ctxt->wellFormed != 1) 1472 return(-1); 1473 1474 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) 1475 return(0); 1476 TODO 1477 return(0); 1478} 1479 1480/** 1481 * xmlTextReaderReadBinHex: 1482 * @reader: the xmlTextReaderPtr used 1483 * @array: a byte array to store the content. 1484 * @offset: the zero-based index into array where the method should 1485 * begin to write. 1486 * @len: the number of bytes to write. 1487 * 1488 * Reads and decodes the BinHex encoded contents of an element and 1489 * stores the result in a byte buffer. 1490 * 1491 * Returns the number of bytes written to array, or zero if the current 1492 * instance is not positioned on an element or -1 in case of error. 1493 */ 1494int 1495xmlTextReaderReadBinHex(xmlTextReaderPtr reader, 1496 unsigned char *array ATTRIBUTE_UNUSED, 1497 int offset ATTRIBUTE_UNUSED, 1498 int len ATTRIBUTE_UNUSED) { 1499 if ((reader == NULL) || (reader->ctxt == NULL)) 1500 return(-1); 1501 if (reader->ctxt->wellFormed != 1) 1502 return(-1); 1503 1504 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) 1505 return(0); 1506 TODO 1507 return(0); 1508} 1509#endif 1510 1511/************************************************************************ 1512 * * 1513 * Constructor and destructors * 1514 * * 1515 ************************************************************************/ 1516/** 1517 * xmlNewTextReader: 1518 * @input: the xmlParserInputBufferPtr used to read data 1519 * @URI: the URI information for the source if available 1520 * 1521 * Create an xmlTextReader structure fed with @input 1522 * 1523 * Returns the new xmlTextReaderPtr or NULL in case of error 1524 */ 1525xmlTextReaderPtr 1526xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { 1527 xmlTextReaderPtr ret; 1528 int val; 1529 1530 if (input == NULL) 1531 return(NULL); 1532 ret = xmlMalloc(sizeof(xmlTextReader)); 1533 if (ret == NULL) { 1534 xmlGenericError(xmlGenericErrorContext, 1535 "xmlNewTextReader : malloc failed\n"); 1536 return(NULL); 1537 } 1538 memset(ret, 0, sizeof(xmlTextReader)); 1539 ret->entTab = NULL; 1540 ret->entMax = 0; 1541 ret->entNr = 0; 1542 ret->input = input; 1543 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler)); 1544 if (ret->sax == NULL) { 1545 xmlFree(ret); 1546 xmlGenericError(xmlGenericErrorContext, 1547 "xmlNewTextReader : malloc failed\n"); 1548 return(NULL); 1549 } 1550 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler)); 1551 ret->startElement = ret->sax->startElement; 1552 ret->sax->startElement = xmlTextReaderStartElement; 1553 ret->endElement = ret->sax->endElement; 1554 ret->sax->endElement = xmlTextReaderEndElement; 1555 if (ret->sax->initialized == XML_SAX2_MAGIC) { 1556 ret->startElementNs = ret->sax->startElementNs; 1557 ret->sax->startElementNs = xmlTextReaderStartElementNs; 1558 ret->endElementNs = ret->sax->endElementNs; 1559 ret->sax->endElementNs = xmlTextReaderEndElementNs; 1560 } else { 1561 ret->startElementNs = NULL; 1562 ret->endElementNs = NULL; 1563 } 1564 ret->characters = ret->sax->characters; 1565 ret->sax->characters = xmlTextReaderCharacters; 1566 ret->sax->ignorableWhitespace = xmlTextReaderCharacters; 1567 ret->cdataBlock = ret->sax->cdataBlock; 1568 ret->sax->cdataBlock = xmlTextReaderCDataBlock; 1569 1570 ret->mode = XML_TEXTREADER_MODE_INITIAL; 1571 ret->node = NULL; 1572 ret->curnode = NULL; 1573 val = xmlParserInputBufferRead(input, 4); 1574 if (val >= 4) { 1575 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, 1576 (const char *) ret->input->buffer->content, 4, URI); 1577 ret->base = 0; 1578 ret->cur = 4; 1579 } else { 1580 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI); 1581 ret->base = 0; 1582 ret->cur = 0; 1583 } 1584 if (ret->ctxt == NULL) { 1585 xmlGenericError(xmlGenericErrorContext, 1586 "xmlNewTextReader : malloc failed\n"); 1587 xmlFree(ret->sax); 1588 xmlFree(ret); 1589 return(NULL); 1590 } 1591 ret->ctxt->_private = ret; 1592 ret->ctxt->linenumbers = 1; 1593 ret->ctxt->dictNames = 1; 1594 ret->allocs = XML_TEXTREADER_CTXT; 1595 /* 1596 * use the parser dictionnary to allocate all elements and attributes names 1597 */ 1598 ret->ctxt->docdict = 1; 1599 return(ret); 1600} 1601 1602/** 1603 * xmlNewTextReaderFilename: 1604 * @URI: the URI of the resource to process 1605 * 1606 * Create an xmlTextReader structure fed with the resource at @URI 1607 * 1608 * Returns the new xmlTextReaderPtr or NULL in case of error 1609 */ 1610xmlTextReaderPtr 1611xmlNewTextReaderFilename(const char *URI) { 1612 xmlParserInputBufferPtr input; 1613 xmlTextReaderPtr ret; 1614 char *directory = NULL; 1615 1616 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE); 1617 if (input == NULL) 1618 return(NULL); 1619 ret = xmlNewTextReader(input, URI); 1620 if (ret == NULL) { 1621 xmlFreeParserInputBuffer(input); 1622 return(NULL); 1623 } 1624 ret->allocs |= XML_TEXTREADER_INPUT; 1625 if (ret->ctxt->directory == NULL) 1626 directory = xmlParserGetDirectory(URI); 1627 if ((ret->ctxt->directory == NULL) && (directory != NULL)) 1628 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory); 1629 if (directory != NULL) 1630 xmlFree(directory); 1631 return(ret); 1632} 1633 1634/** 1635 * xmlFreeTextReader: 1636 * @reader: the xmlTextReaderPtr 1637 * 1638 * Deallocate all the resources associated to the reader 1639 */ 1640void 1641xmlFreeTextReader(xmlTextReaderPtr reader) { 1642 if (reader == NULL) 1643 return; 1644#ifdef LIBXML_SCHEMAS_ENABLED 1645 if (reader->rngSchemas != NULL) { 1646 xmlRelaxNGFree(reader->rngSchemas); 1647 reader->rngSchemas = NULL; 1648 } 1649 if (reader->rngValidCtxt != NULL) { 1650 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); 1651 reader->rngValidCtxt = NULL; 1652 } 1653#endif 1654 if (reader->ctxt != NULL) { 1655 if (reader->ctxt->myDoc != NULL) { 1656 xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc); 1657 reader->ctxt->myDoc = NULL; 1658 } 1659 if ((reader->ctxt->vctxt.vstateTab != NULL) && 1660 (reader->ctxt->vctxt.vstateMax > 0)){ 1661 xmlFree(reader->ctxt->vctxt.vstateTab); 1662 reader->ctxt->vctxt.vstateTab = 0; 1663 reader->ctxt->vctxt.vstateMax = 0; 1664 } 1665 if (reader->allocs & XML_TEXTREADER_CTXT) 1666 xmlFreeParserCtxt(reader->ctxt); 1667 } 1668 if (reader->sax != NULL) 1669 xmlFree(reader->sax); 1670 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) 1671 xmlFreeParserInputBuffer(reader->input); 1672 if (reader->faketext != NULL) { 1673 xmlFreeNode(reader->faketext); 1674 } 1675 if (reader->entTab != NULL) 1676 xmlFree(reader->entTab); 1677 xmlFree(reader); 1678} 1679 1680/************************************************************************ 1681 * * 1682 * Methods for XmlTextReader * 1683 * * 1684 ************************************************************************/ 1685/** 1686 * xmlTextReaderClose: 1687 * @reader: the xmlTextReaderPtr used 1688 * 1689 * This method releases any resources allocated by the current instance 1690 * changes the state to Closed and close any underlying input. 1691 * 1692 * Returns 0 or -1 in case of error 1693 */ 1694int 1695xmlTextReaderClose(xmlTextReaderPtr reader) { 1696 if (reader == NULL) 1697 return(-1); 1698 reader->node = NULL; 1699 reader->curnode = NULL; 1700 reader->mode = XML_TEXTREADER_MODE_CLOSED; 1701 if (reader->ctxt != NULL) { 1702 if (reader->ctxt->myDoc != NULL) { 1703 xmlFreeDoc(reader->ctxt->myDoc); 1704 reader->ctxt->myDoc = NULL; 1705 } 1706 if (reader->allocs & XML_TEXTREADER_CTXT) { 1707 xmlFreeParserCtxt(reader->ctxt); 1708 reader->allocs -= XML_TEXTREADER_CTXT; 1709 } 1710 } 1711 if (reader->sax != NULL) { 1712 xmlFree(reader->sax); 1713 reader->sax = NULL; 1714 } 1715 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) { 1716 xmlFreeParserInputBuffer(reader->input); 1717 reader->allocs -= XML_TEXTREADER_INPUT; 1718 } 1719 return(0); 1720} 1721 1722/** 1723 * xmlTextReaderGetAttributeNo: 1724 * @reader: the xmlTextReaderPtr used 1725 * @no: the zero-based index of the attribute relative to the containing element 1726 * 1727 * Provides the value of the attribute with the specified index relative 1728 * to the containing element. 1729 * 1730 * Returns a string containing the value of the specified attribute, or NULL 1731 * in case of error. The string must be deallocated by the caller. 1732 */ 1733xmlChar * 1734xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) { 1735 xmlChar *ret; 1736 int i; 1737 xmlAttrPtr cur; 1738 xmlNsPtr ns; 1739 1740 if (reader == NULL) 1741 return(NULL); 1742 if (reader->node == NULL) 1743 return(NULL); 1744 if (reader->curnode != NULL) 1745 return(NULL); 1746 /* TODO: handle the xmlDecl */ 1747 if (reader->node->type != XML_ELEMENT_NODE) 1748 return(NULL); 1749 1750 ns = reader->node->nsDef; 1751 for (i = 0;(i < no) && (ns != NULL);i++) { 1752 ns = ns->next; 1753 } 1754 if (ns != NULL) 1755 return(xmlStrdup(ns->href)); 1756 1757 cur = reader->node->properties; 1758 if (cur == NULL) 1759 return(NULL); 1760 for (;i < no;i++) { 1761 cur = cur->next; 1762 if (cur == NULL) 1763 return(NULL); 1764 } 1765 /* TODO walk the DTD if present */ 1766 1767 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1); 1768 if (ret == NULL) return(xmlStrdup((xmlChar *)"")); 1769 return(ret); 1770} 1771 1772/** 1773 * xmlTextReaderGetAttribute: 1774 * @reader: the xmlTextReaderPtr used 1775 * @name: the qualified name of the attribute. 1776 * 1777 * Provides the value of the attribute with the specified qualified name. 1778 * 1779 * Returns a string containing the value of the specified attribute, or NULL 1780 * in case of error. The string must be deallocated by the caller. 1781 */ 1782xmlChar * 1783xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) { 1784 xmlChar *prefix = NULL; 1785 xmlChar *localname; 1786 xmlNsPtr ns; 1787 xmlChar *ret = NULL; 1788 1789 if ((reader == NULL) || (name == NULL)) 1790 return(NULL); 1791 if (reader->node == NULL) 1792 return(NULL); 1793 if (reader->curnode != NULL) 1794 return(NULL); 1795 1796 /* TODO: handle the xmlDecl */ 1797 if (reader->node->type != XML_ELEMENT_NODE) 1798 return(NULL); 1799 1800 localname = xmlSplitQName2(name, &prefix); 1801 if (localname == NULL) 1802 return(xmlGetProp(reader->node, name)); 1803 1804 ns = xmlSearchNs(reader->node->doc, reader->node, prefix); 1805 if (ns != NULL) 1806 ret = xmlGetNsProp(reader->node, localname, ns->href); 1807 1808 if (localname != NULL) 1809 xmlFree(localname); 1810 if (prefix != NULL) 1811 xmlFree(prefix); 1812 return(ret); 1813} 1814 1815 1816/** 1817 * xmlTextReaderGetAttributeNs: 1818 * @reader: the xmlTextReaderPtr used 1819 * @localName: the local name of the attribute. 1820 * @namespaceURI: the namespace URI of the attribute. 1821 * 1822 * Provides the value of the specified attribute 1823 * 1824 * Returns a string containing the value of the specified attribute, or NULL 1825 * in case of error. The string must be deallocated by the caller. 1826 */ 1827xmlChar * 1828xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName, 1829 const xmlChar *namespaceURI) { 1830 if ((reader == NULL) || (localName == NULL)) 1831 return(NULL); 1832 if (reader->node == NULL) 1833 return(NULL); 1834 if (reader->curnode != NULL) 1835 return(NULL); 1836 1837 /* TODO: handle the xmlDecl */ 1838 if (reader->node->type != XML_ELEMENT_NODE) 1839 return(NULL); 1840 1841 return(xmlGetNsProp(reader->node, localName, namespaceURI)); 1842} 1843 1844/** 1845 * xmlTextReaderGetRemainder: 1846 * @reader: the xmlTextReaderPtr used 1847 * 1848 * Method to get the remainder of the buffered XML. this method stops the 1849 * parser, set its state to End Of File and return the input stream with 1850 * what is left that the parser did not use. 1851 * 1852 * Returns the xmlParserInputBufferPtr attached to the XML or NULL 1853 * in case of error. 1854 */ 1855xmlParserInputBufferPtr 1856xmlTextReaderGetRemainder(xmlTextReaderPtr reader) { 1857 xmlParserInputBufferPtr ret = NULL; 1858 1859 if (reader == NULL) 1860 return(NULL); 1861 if (reader->node == NULL) 1862 return(NULL); 1863 1864 reader->node = NULL; 1865 reader->curnode = NULL; 1866 reader->mode = XML_TEXTREADER_MODE_EOF; 1867 if (reader->ctxt != NULL) { 1868 if (reader->ctxt->myDoc != NULL) { 1869 xmlFreeDoc(reader->ctxt->myDoc); 1870 reader->ctxt->myDoc = NULL; 1871 } 1872 if (reader->allocs & XML_TEXTREADER_CTXT) { 1873 xmlFreeParserCtxt(reader->ctxt); 1874 reader->allocs -= XML_TEXTREADER_CTXT; 1875 } 1876 } 1877 if (reader->sax != NULL) { 1878 xmlFree(reader->sax); 1879 reader->sax = NULL; 1880 } 1881 if (reader->allocs & XML_TEXTREADER_INPUT) { 1882 ret = reader->input; 1883 reader->allocs -= XML_TEXTREADER_INPUT; 1884 } else { 1885 /* 1886 * Hum, one may need to duplicate the data structure because 1887 * without reference counting the input may be freed twice: 1888 * - by the layer which allocated it. 1889 * - by the layer to which would have been returned to. 1890 */ 1891 TODO 1892 return(NULL); 1893 } 1894 return(ret); 1895} 1896 1897/** 1898 * xmlTextReaderLookupNamespace: 1899 * @reader: the xmlTextReaderPtr used 1900 * @prefix: the prefix whose namespace URI is to be resolved. To return 1901 * the default namespace, specify NULL 1902 * 1903 * Resolves a namespace prefix in the scope of the current element. 1904 * 1905 * Returns a string containing the namespace URI to which the prefix maps 1906 * or NULL in case of error. The string must be deallocated by the caller. 1907 */ 1908xmlChar * 1909xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) { 1910 xmlNsPtr ns; 1911 1912 if (reader == NULL) 1913 return(NULL); 1914 if (reader->node == NULL) 1915 return(NULL); 1916 1917 ns = xmlSearchNs(reader->node->doc, reader->node, prefix); 1918 if (ns == NULL) 1919 return(NULL); 1920 return(xmlStrdup(ns->href)); 1921} 1922 1923/** 1924 * xmlTextReaderMoveToAttributeNo: 1925 * @reader: the xmlTextReaderPtr used 1926 * @no: the zero-based index of the attribute relative to the containing 1927 * element. 1928 * 1929 * Moves the position of the current instance to the attribute with 1930 * the specified index relative to the containing element. 1931 * 1932 * Returns 1 in case of success, -1 in case of error, 0 if not found 1933 */ 1934int 1935xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) { 1936 int i; 1937 xmlAttrPtr cur; 1938 xmlNsPtr ns; 1939 1940 if (reader == NULL) 1941 return(-1); 1942 if (reader->node == NULL) 1943 return(-1); 1944 /* TODO: handle the xmlDecl */ 1945 if (reader->node->type != XML_ELEMENT_NODE) 1946 return(-1); 1947 1948 reader->curnode = NULL; 1949 1950 ns = reader->node->nsDef; 1951 for (i = 0;(i < no) && (ns != NULL);i++) { 1952 ns = ns->next; 1953 } 1954 if (ns != NULL) { 1955 reader->curnode = (xmlNodePtr) ns; 1956 return(1); 1957 } 1958 1959 cur = reader->node->properties; 1960 if (cur == NULL) 1961 return(0); 1962 for (;i < no;i++) { 1963 cur = cur->next; 1964 if (cur == NULL) 1965 return(0); 1966 } 1967 /* TODO walk the DTD if present */ 1968 1969 reader->curnode = (xmlNodePtr) cur; 1970 return(1); 1971} 1972 1973/** 1974 * xmlTextReaderMoveToAttribute: 1975 * @reader: the xmlTextReaderPtr used 1976 * @name: the qualified name of the attribute. 1977 * 1978 * Moves the position of the current instance to the attribute with 1979 * the specified qualified name. 1980 * 1981 * Returns 1 in case of success, -1 in case of error, 0 if not found 1982 */ 1983int 1984xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) { 1985 xmlChar *prefix = NULL; 1986 xmlChar *localname; 1987 xmlNsPtr ns; 1988 xmlAttrPtr prop; 1989 1990 if ((reader == NULL) || (name == NULL)) 1991 return(-1); 1992 if (reader->node == NULL) 1993 return(-1); 1994 1995 /* TODO: handle the xmlDecl */ 1996 if (reader->node->type != XML_ELEMENT_NODE) 1997 return(0); 1998 1999 localname = xmlSplitQName2(name, &prefix); 2000 if (localname == NULL) { 2001 /* 2002 * Namespace default decl 2003 */ 2004 if (xmlStrEqual(name, BAD_CAST "xmlns")) { 2005 ns = reader->node->nsDef; 2006 while (ns != NULL) { 2007 if (ns->prefix == NULL) { 2008 reader->curnode = (xmlNodePtr) ns; 2009 return(1); 2010 } 2011 ns = ns->next; 2012 } 2013 return(0); 2014 } 2015 2016 prop = reader->node->properties; 2017 while (prop != NULL) { 2018 /* 2019 * One need to have 2020 * - same attribute names 2021 * - and the attribute carrying that namespace 2022 */ 2023 if ((xmlStrEqual(prop->name, name)) && 2024 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) { 2025 reader->curnode = (xmlNodePtr) prop; 2026 return(1); 2027 } 2028 prop = prop->next; 2029 } 2030 return(0); 2031 } 2032 2033 /* 2034 * Namespace default decl 2035 */ 2036 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { 2037 ns = reader->node->nsDef; 2038 while (ns != NULL) { 2039 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) { 2040 reader->curnode = (xmlNodePtr) ns; 2041 goto found; 2042 } 2043 ns = ns->next; 2044 } 2045 goto not_found; 2046 } 2047 prop = reader->node->properties; 2048 while (prop != NULL) { 2049 /* 2050 * One need to have 2051 * - same attribute names 2052 * - and the attribute carrying that namespace 2053 */ 2054 if ((xmlStrEqual(prop->name, localname)) && 2055 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) { 2056 reader->curnode = (xmlNodePtr) prop; 2057 goto found; 2058 } 2059 prop = prop->next; 2060 } 2061not_found: 2062 if (localname != NULL) 2063 xmlFree(localname); 2064 if (prefix != NULL) 2065 xmlFree(prefix); 2066 return(0); 2067 2068found: 2069 if (localname != NULL) 2070 xmlFree(localname); 2071 if (prefix != NULL) 2072 xmlFree(prefix); 2073 return(1); 2074} 2075 2076/** 2077 * xmlTextReaderMoveToAttributeNs: 2078 * @reader: the xmlTextReaderPtr used 2079 * @localName: the local name of the attribute. 2080 * @namespaceURI: the namespace URI of the attribute. 2081 * 2082 * Moves the position of the current instance to the attribute with the 2083 * specified local name and namespace URI. 2084 * 2085 * Returns 1 in case of success, -1 in case of error, 0 if not found 2086 */ 2087int 2088xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader, 2089 const xmlChar *localName, const xmlChar *namespaceURI) { 2090 xmlAttrPtr prop; 2091 xmlNodePtr node; 2092 2093 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL)) 2094 return(-1); 2095 if (reader->node == NULL) 2096 return(-1); 2097 if (reader->node->type != XML_ELEMENT_NODE) 2098 return(0); 2099 node = reader->node; 2100 2101 /* 2102 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no 2103 * namespace name associated to "xmlns" 2104 */ 2105 prop = node->properties; 2106 while (prop != NULL) { 2107 /* 2108 * One need to have 2109 * - same attribute names 2110 * - and the attribute carrying that namespace 2111 */ 2112 if (xmlStrEqual(prop->name, localName) && 2113 ((prop->ns != NULL) && 2114 (xmlStrEqual(prop->ns->href, namespaceURI)))) { 2115 reader->curnode = (xmlNodePtr) prop; 2116 return(1); 2117 } 2118 prop = prop->next; 2119 } 2120 return(0); 2121} 2122 2123/** 2124 * xmlTextReaderMoveToFirstAttribute: 2125 * @reader: the xmlTextReaderPtr used 2126 * 2127 * Moves the position of the current instance to the first attribute 2128 * associated with the current node. 2129 * 2130 * Returns 1 in case of success, -1 in case of error, 0 if not found 2131 */ 2132int 2133xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) { 2134 if (reader == NULL) 2135 return(-1); 2136 if (reader->node == NULL) 2137 return(-1); 2138 if (reader->node->type != XML_ELEMENT_NODE) 2139 return(0); 2140 2141 if (reader->node->nsDef != NULL) { 2142 reader->curnode = (xmlNodePtr) reader->node->nsDef; 2143 return(1); 2144 } 2145 if (reader->node->properties != NULL) { 2146 reader->curnode = (xmlNodePtr) reader->node->properties; 2147 return(1); 2148 } 2149 return(0); 2150} 2151 2152/** 2153 * xmlTextReaderMoveToNextAttribute: 2154 * @reader: the xmlTextReaderPtr used 2155 * 2156 * Moves the position of the current instance to the next attribute 2157 * associated with the current node. 2158 * 2159 * Returns 1 in case of success, -1 in case of error, 0 if not found 2160 */ 2161int 2162xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) { 2163 if (reader == NULL) 2164 return(-1); 2165 if (reader->node == NULL) 2166 return(-1); 2167 if (reader->node->type != XML_ELEMENT_NODE) 2168 return(0); 2169 if (reader->curnode == NULL) 2170 return(xmlTextReaderMoveToFirstAttribute(reader)); 2171 2172 if (reader->curnode->type == XML_NAMESPACE_DECL) { 2173 xmlNsPtr ns = (xmlNsPtr) reader->curnode; 2174 if (ns->next != NULL) { 2175 reader->curnode = (xmlNodePtr) ns->next; 2176 return(1); 2177 } 2178 if (reader->node->properties != NULL) { 2179 reader->curnode = (xmlNodePtr) reader->node->properties; 2180 return(1); 2181 } 2182 return(0); 2183 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) && 2184 (reader->curnode->next != NULL)) { 2185 reader->curnode = reader->curnode->next; 2186 return(1); 2187 } 2188 return(0); 2189} 2190 2191/** 2192 * xmlTextReaderMoveToElement: 2193 * @reader: the xmlTextReaderPtr used 2194 * 2195 * Moves the position of the current instance to the node that 2196 * contains the current Attribute node. 2197 * 2198 * Returns 1 in case of success, -1 in case of error, 0 if not moved 2199 */ 2200int 2201xmlTextReaderMoveToElement(xmlTextReaderPtr reader) { 2202 if (reader == NULL) 2203 return(-1); 2204 if (reader->node == NULL) 2205 return(-1); 2206 if (reader->node->type != XML_ELEMENT_NODE) 2207 return(0); 2208 if (reader->curnode != NULL) { 2209 reader->curnode = NULL; 2210 return(1); 2211 } 2212 return(0); 2213} 2214 2215/** 2216 * xmlTextReaderReadAttributeValue: 2217 * @reader: the xmlTextReaderPtr used 2218 * 2219 * Parses an attribute value into one or more Text and EntityReference nodes. 2220 * 2221 * Returns 1 in case of success, 0 if the reader was not positionned on an 2222 * ttribute node or all the attribute values have been read, or -1 2223 * in case of error. 2224 */ 2225int 2226xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) { 2227 if (reader == NULL) 2228 return(-1); 2229 if (reader->node == NULL) 2230 return(-1); 2231 if (reader->curnode == NULL) 2232 return(0); 2233 if (reader->curnode->type == XML_ATTRIBUTE_NODE) { 2234 if (reader->curnode->children == NULL) 2235 return(0); 2236 reader->curnode = reader->curnode->children; 2237 } else if (reader->curnode->type == XML_NAMESPACE_DECL) { 2238 xmlNsPtr ns = (xmlNsPtr) reader->curnode; 2239 2240 if (reader->faketext == NULL) { 2241 reader->faketext = xmlNewDocText(reader->node->doc, 2242 ns->href); 2243 } else { 2244 if (reader->faketext->content != NULL) 2245 xmlFree(reader->faketext->content); 2246 reader->faketext->content = xmlStrdup(ns->href); 2247 } 2248 reader->curnode = reader->faketext; 2249 } else { 2250 if (reader->curnode->next == NULL) 2251 return(0); 2252 reader->curnode = reader->curnode->next; 2253 } 2254 return(1); 2255} 2256 2257/************************************************************************ 2258 * * 2259 * Acces API to the current node * 2260 * * 2261 ************************************************************************/ 2262/** 2263 * xmlTextReaderAttributeCount: 2264 * @reader: the xmlTextReaderPtr used 2265 * 2266 * Provides the number of attributes of the current node 2267 * 2268 * Returns 0 i no attributes, -1 in case of error or the attribute count 2269 */ 2270int 2271xmlTextReaderAttributeCount(xmlTextReaderPtr reader) { 2272 int ret; 2273 xmlAttrPtr attr; 2274 xmlNsPtr ns; 2275 xmlNodePtr node; 2276 2277 if (reader == NULL) 2278 return(-1); 2279 if (reader->node == NULL) 2280 return(0); 2281 2282 if (reader->curnode != NULL) 2283 node = reader->curnode; 2284 else 2285 node = reader->node; 2286 2287 if (node->type != XML_ELEMENT_NODE) 2288 return(0); 2289 if ((reader->state == XML_TEXTREADER_END) || 2290 (reader->state == XML_TEXTREADER_BACKTRACK)) 2291 return(0); 2292 ret = 0; 2293 attr = node->properties; 2294 while (attr != NULL) { 2295 ret++; 2296 attr = attr->next; 2297 } 2298 ns = node->nsDef; 2299 while (ns != NULL) { 2300 ret++; 2301 ns = ns->next; 2302 } 2303 return(ret); 2304} 2305 2306/** 2307 * xmlTextReaderNodeType: 2308 * @reader: the xmlTextReaderPtr used 2309 * 2310 * Get the node type of the current node 2311 * Reference: 2312 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html 2313 * 2314 * Returns the xmlNodeType of the current node or -1 in case of error 2315 */ 2316int 2317xmlTextReaderNodeType(xmlTextReaderPtr reader) { 2318 xmlNodePtr node; 2319 2320 if (reader == NULL) 2321 return(-1); 2322 if (reader->node == NULL) 2323 return(XML_READER_TYPE_NONE); 2324 if (reader->curnode != NULL) 2325 node = reader->curnode; 2326 else 2327 node = reader->node; 2328 switch (node->type) { 2329 case XML_ELEMENT_NODE: 2330 if ((reader->state == XML_TEXTREADER_END) || 2331 (reader->state == XML_TEXTREADER_BACKTRACK)) 2332 return(XML_READER_TYPE_END_ELEMENT); 2333 return(XML_READER_TYPE_ELEMENT); 2334 case XML_NAMESPACE_DECL: 2335 case XML_ATTRIBUTE_NODE: 2336 return(XML_READER_TYPE_ATTRIBUTE); 2337 case XML_TEXT_NODE: 2338 if (xmlIsBlankNode(reader->node)) { 2339 if (xmlNodeGetSpacePreserve(reader->node)) 2340 return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE); 2341 else 2342 return(XML_READER_TYPE_WHITESPACE); 2343 } else { 2344 return(XML_READER_TYPE_TEXT); 2345 } 2346 case XML_CDATA_SECTION_NODE: 2347 return(XML_READER_TYPE_CDATA); 2348 case XML_ENTITY_REF_NODE: 2349 return(XML_READER_TYPE_ENTITY_REFERENCE); 2350 case XML_ENTITY_NODE: 2351 return(XML_READER_TYPE_ENTITY); 2352 case XML_PI_NODE: 2353 return(XML_READER_TYPE_PROCESSING_INSTRUCTION); 2354 case XML_COMMENT_NODE: 2355 return(XML_READER_TYPE_COMMENT); 2356 case XML_DOCUMENT_NODE: 2357 case XML_HTML_DOCUMENT_NODE: 2358#ifdef LIBXML_DOCB_ENABLED 2359 case XML_DOCB_DOCUMENT_NODE: 2360#endif 2361 return(XML_READER_TYPE_DOCUMENT); 2362 case XML_DOCUMENT_FRAG_NODE: 2363 return(XML_READER_TYPE_DOCUMENT_FRAGMENT); 2364 case XML_NOTATION_NODE: 2365 return(XML_READER_TYPE_NOTATION); 2366 case XML_DOCUMENT_TYPE_NODE: 2367 case XML_DTD_NODE: 2368 return(XML_READER_TYPE_DOCUMENT_TYPE); 2369 2370 case XML_ELEMENT_DECL: 2371 case XML_ATTRIBUTE_DECL: 2372 case XML_ENTITY_DECL: 2373 case XML_XINCLUDE_START: 2374 case XML_XINCLUDE_END: 2375 return(XML_READER_TYPE_NONE); 2376 } 2377 return(-1); 2378} 2379 2380/** 2381 * xmlTextReaderIsEmptyElement: 2382 * @reader: the xmlTextReaderPtr used 2383 * 2384 * Check if the current node is empty 2385 * 2386 * Returns 1 if empty, 0 if not and -1 in case of error 2387 */ 2388int 2389xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) { 2390 if ((reader == NULL) || (reader->node == NULL)) 2391 return(-1); 2392 if (reader->node->type != XML_ELEMENT_NODE) 2393 return(0); 2394 if (reader->curnode != NULL) 2395 return(0); 2396 if (reader->node->children != NULL) 2397 return(0); 2398 if (reader->state == XML_TEXTREADER_END) 2399 return(0); 2400 return(reader->node->_private == (void *)xmlTextReaderIsEmpty); 2401} 2402 2403/** 2404 * xmlTextReaderLocalName: 2405 * @reader: the xmlTextReaderPtr used 2406 * 2407 * The local name of the node. 2408 * 2409 * Returns the local name or NULL if not available 2410 */ 2411xmlChar * 2412xmlTextReaderLocalName(xmlTextReaderPtr reader) { 2413 xmlNodePtr node; 2414 if ((reader == NULL) || (reader->node == NULL)) 2415 return(NULL); 2416 if (reader->curnode != NULL) 2417 node = reader->curnode; 2418 else 2419 node = reader->node; 2420 if (node->type == XML_NAMESPACE_DECL) { 2421 xmlNsPtr ns = (xmlNsPtr) node; 2422 if (ns->prefix == NULL) 2423 return(xmlStrdup(BAD_CAST "xmlns")); 2424 else 2425 return(xmlStrdup(ns->prefix)); 2426 } 2427 if ((node->type != XML_ELEMENT_NODE) && 2428 (node->type != XML_ATTRIBUTE_NODE)) 2429 return(xmlTextReaderName(reader)); 2430 return(xmlStrdup(node->name)); 2431} 2432 2433/** 2434 * xmlTextReaderName: 2435 * @reader: the xmlTextReaderPtr used 2436 * 2437 * The qualified name of the node, equal to Prefix :LocalName. 2438 * 2439 * Returns the local name or NULL if not available 2440 */ 2441xmlChar * 2442xmlTextReaderName(xmlTextReaderPtr reader) { 2443 xmlNodePtr node; 2444 xmlChar *ret; 2445 2446 if ((reader == NULL) || (reader->node == NULL)) 2447 return(NULL); 2448 if (reader->curnode != NULL) 2449 node = reader->curnode; 2450 else 2451 node = reader->node; 2452 switch (node->type) { 2453 case XML_ELEMENT_NODE: 2454 case XML_ATTRIBUTE_NODE: 2455 if ((node->ns == NULL) || 2456 (node->ns->prefix == NULL)) 2457 return(xmlStrdup(node->name)); 2458 2459 ret = xmlStrdup(node->ns->prefix); 2460 ret = xmlStrcat(ret, BAD_CAST ":"); 2461 ret = xmlStrcat(ret, node->name); 2462 return(ret); 2463 case XML_TEXT_NODE: 2464 return(xmlStrdup(BAD_CAST "#text")); 2465 case XML_CDATA_SECTION_NODE: 2466 return(xmlStrdup(BAD_CAST "#cdata-section")); 2467 case XML_ENTITY_NODE: 2468 case XML_ENTITY_REF_NODE: 2469 return(xmlStrdup(node->name)); 2470 case XML_PI_NODE: 2471 return(xmlStrdup(node->name)); 2472 case XML_COMMENT_NODE: 2473 return(xmlStrdup(BAD_CAST "#comment")); 2474 case XML_DOCUMENT_NODE: 2475 case XML_HTML_DOCUMENT_NODE: 2476#ifdef LIBXML_DOCB_ENABLED 2477 case XML_DOCB_DOCUMENT_NODE: 2478#endif 2479 return(xmlStrdup(BAD_CAST "#document")); 2480 case XML_DOCUMENT_FRAG_NODE: 2481 return(xmlStrdup(BAD_CAST "#document-fragment")); 2482 case XML_NOTATION_NODE: 2483 return(xmlStrdup(node->name)); 2484 case XML_DOCUMENT_TYPE_NODE: 2485 case XML_DTD_NODE: 2486 return(xmlStrdup(node->name)); 2487 case XML_NAMESPACE_DECL: { 2488 xmlNsPtr ns = (xmlNsPtr) node; 2489 2490 ret = xmlStrdup(BAD_CAST "xmlns"); 2491 if (ns->prefix == NULL) 2492 return(ret); 2493 ret = xmlStrcat(ret, BAD_CAST ":"); 2494 ret = xmlStrcat(ret, ns->prefix); 2495 return(ret); 2496 } 2497 2498 case XML_ELEMENT_DECL: 2499 case XML_ATTRIBUTE_DECL: 2500 case XML_ENTITY_DECL: 2501 case XML_XINCLUDE_START: 2502 case XML_XINCLUDE_END: 2503 return(NULL); 2504 } 2505 return(NULL); 2506} 2507 2508/** 2509 * xmlTextReaderPrefix: 2510 * @reader: the xmlTextReaderPtr used 2511 * 2512 * A shorthand reference to the namespace associated with the node. 2513 * 2514 * Returns the prefix or NULL if not available 2515 */ 2516xmlChar * 2517xmlTextReaderPrefix(xmlTextReaderPtr reader) { 2518 xmlNodePtr node; 2519 if ((reader == NULL) || (reader->node == NULL)) 2520 return(NULL); 2521 if (reader->curnode != NULL) 2522 node = reader->curnode; 2523 else 2524 node = reader->node; 2525 if (node->type == XML_NAMESPACE_DECL) { 2526 xmlNsPtr ns = (xmlNsPtr) node; 2527 if (ns->prefix == NULL) 2528 return(NULL); 2529 return(xmlStrdup(BAD_CAST "xmlns")); 2530 } 2531 if ((node->type != XML_ELEMENT_NODE) && 2532 (node->type != XML_ATTRIBUTE_NODE)) 2533 return(NULL); 2534 if ((node->ns != NULL) && (node->ns->prefix != NULL)) 2535 return(xmlStrdup(node->ns->prefix)); 2536 return(NULL); 2537} 2538 2539/** 2540 * xmlTextReaderNamespaceUri: 2541 * @reader: the xmlTextReaderPtr used 2542 * 2543 * The URI defining the namespace associated with the node. 2544 * 2545 * Returns the namespace URI or NULL if not available 2546 */ 2547xmlChar * 2548xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) { 2549 xmlNodePtr node; 2550 if ((reader == NULL) || (reader->node == NULL)) 2551 return(NULL); 2552 if (reader->curnode != NULL) 2553 node = reader->curnode; 2554 else 2555 node = reader->node; 2556 if (node->type == XML_NAMESPACE_DECL) 2557 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/")); 2558 if ((node->type != XML_ELEMENT_NODE) && 2559 (node->type != XML_ATTRIBUTE_NODE)) 2560 return(NULL); 2561 if (node->ns != NULL) 2562 return(xmlStrdup(node->ns->href)); 2563 return(NULL); 2564} 2565 2566/** 2567 * xmlTextReaderBaseUri: 2568 * @reader: the xmlTextReaderPtr used 2569 * 2570 * The base URI of the node. 2571 * 2572 * Returns the base URI or NULL if not available 2573 */ 2574xmlChar * 2575xmlTextReaderBaseUri(xmlTextReaderPtr reader) { 2576 if ((reader == NULL) || (reader->node == NULL)) 2577 return(NULL); 2578 return(xmlNodeGetBase(NULL, reader->node)); 2579} 2580 2581/** 2582 * xmlTextReaderDepth: 2583 * @reader: the xmlTextReaderPtr used 2584 * 2585 * The depth of the node in the tree. 2586 * 2587 * Returns the depth or -1 in case of error 2588 */ 2589int 2590xmlTextReaderDepth(xmlTextReaderPtr reader) { 2591 if (reader == NULL) 2592 return(-1); 2593 if (reader->node == NULL) 2594 return(0); 2595 2596 if (reader->curnode != NULL) { 2597 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) || 2598 (reader->curnode->type == XML_NAMESPACE_DECL)) 2599 return(reader->depth + 1); 2600 return(reader->depth + 2); 2601 } 2602 return(reader->depth); 2603} 2604 2605/** 2606 * xmlTextReaderHasAttributes: 2607 * @reader: the xmlTextReaderPtr used 2608 * 2609 * Whether the node has attributes. 2610 * 2611 * Returns 1 if true, 0 if false, and -1 in case or error 2612 */ 2613int 2614xmlTextReaderHasAttributes(xmlTextReaderPtr reader) { 2615 xmlNodePtr node; 2616 if (reader == NULL) 2617 return(-1); 2618 if (reader->node == NULL) 2619 return(0); 2620 if (reader->curnode != NULL) 2621 node = reader->curnode; 2622 else 2623 node = reader->node; 2624 2625 if ((node->type == XML_ELEMENT_NODE) && 2626 (node->properties != NULL)) 2627 return(1); 2628 /* TODO: handle the xmlDecl */ 2629 return(0); 2630} 2631 2632/** 2633 * xmlTextReaderHasValue: 2634 * @reader: the xmlTextReaderPtr used 2635 * 2636 * Whether the node can have a text value. 2637 * 2638 * Returns 1 if true, 0 if false, and -1 in case or error 2639 */ 2640int 2641xmlTextReaderHasValue(xmlTextReaderPtr reader) { 2642 xmlNodePtr node; 2643 if (reader == NULL) 2644 return(-1); 2645 if (reader->node == NULL) 2646 return(0); 2647 if (reader->curnode != NULL) 2648 node = reader->curnode; 2649 else 2650 node = reader->node; 2651 2652 switch (node->type) { 2653 case XML_ATTRIBUTE_NODE: 2654 case XML_TEXT_NODE: 2655 case XML_CDATA_SECTION_NODE: 2656 case XML_PI_NODE: 2657 case XML_COMMENT_NODE: 2658 case XML_NAMESPACE_DECL: 2659 return(1); 2660 default: 2661 break; 2662 } 2663 return(0); 2664} 2665 2666/** 2667 * xmlTextReaderValue: 2668 * @reader: the xmlTextReaderPtr used 2669 * 2670 * Provides the text value of the node if present 2671 * 2672 * Returns the string or NULL if not available. The retsult must be deallocated 2673 * with xmlFree() 2674 */ 2675xmlChar * 2676xmlTextReaderValue(xmlTextReaderPtr reader) { 2677 xmlNodePtr node; 2678 if (reader == NULL) 2679 return(NULL); 2680 if (reader->node == NULL) 2681 return(NULL); 2682 if (reader->curnode != NULL) 2683 node = reader->curnode; 2684 else 2685 node = reader->node; 2686 2687 switch (node->type) { 2688 case XML_NAMESPACE_DECL: 2689 return(xmlStrdup(((xmlNsPtr) node)->href)); 2690 case XML_ATTRIBUTE_NODE:{ 2691 xmlAttrPtr attr = (xmlAttrPtr) node; 2692 2693 if (attr->parent != NULL) 2694 return (xmlNodeListGetString 2695 (attr->parent->doc, attr->children, 1)); 2696 else 2697 return (xmlNodeListGetString(NULL, attr->children, 1)); 2698 break; 2699 } 2700 case XML_TEXT_NODE: 2701 case XML_CDATA_SECTION_NODE: 2702 case XML_PI_NODE: 2703 case XML_COMMENT_NODE: 2704 if (node->content != NULL) 2705 return (xmlStrdup(node->content)); 2706 default: 2707 break; 2708 } 2709 return(NULL); 2710} 2711 2712/** 2713 * xmlTextReaderIsDefault: 2714 * @reader: the xmlTextReaderPtr used 2715 * 2716 * Whether an Attribute node was generated from the default value 2717 * defined in the DTD or schema. 2718 * 2719 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error 2720 */ 2721int 2722xmlTextReaderIsDefault(xmlTextReaderPtr reader) { 2723 if (reader == NULL) 2724 return(-1); 2725 return(0); 2726} 2727 2728/** 2729 * xmlTextReaderQuoteChar: 2730 * @reader: the xmlTextReaderPtr used 2731 * 2732 * The quotation mark character used to enclose the value of an attribute. 2733 * 2734 * Returns " or ' and -1 in case of error 2735 */ 2736int 2737xmlTextReaderQuoteChar(xmlTextReaderPtr reader) { 2738 if (reader == NULL) 2739 return(-1); 2740 /* TODO maybe lookup the attribute value for " first */ 2741 return((int) '"'); 2742} 2743 2744/** 2745 * xmlTextReaderXmlLang: 2746 * @reader: the xmlTextReaderPtr used 2747 * 2748 * The xml:lang scope within which the node resides. 2749 * 2750 * Returns the xml:lang value or NULL if none exists. 2751 */ 2752xmlChar * 2753xmlTextReaderXmlLang(xmlTextReaderPtr reader) { 2754 if (reader == NULL) 2755 return(NULL); 2756 if (reader->node == NULL) 2757 return(NULL); 2758 return(xmlNodeGetLang(reader->node)); 2759} 2760 2761/** 2762 * xmlTextReaderNormalization: 2763 * @reader: the xmlTextReaderPtr used 2764 * 2765 * The value indicating whether to normalize white space and attribute values. 2766 * Since attribute value and end of line normalizations are a MUST in the XML 2767 * specification only the value true is accepted. The broken bahaviour of 2768 * accepting out of range character entities like � is of course not 2769 * supported either. 2770 * 2771 * Returns 1 or -1 in case of error. 2772 */ 2773int 2774xmlTextReaderNormalization(xmlTextReaderPtr reader) { 2775 if (reader == NULL) 2776 return(-1); 2777 return(1); 2778} 2779 2780/************************************************************************ 2781 * * 2782 * Extensions to the base APIs * 2783 * * 2784 ************************************************************************/ 2785 2786/** 2787 * xmlTextReaderSetParserProp: 2788 * @reader: the xmlTextReaderPtr used 2789 * @prop: the xmlParserProperties to set 2790 * @value: usually 0 or 1 to (de)activate it 2791 * 2792 * Change the parser processing behaviour by changing some of its internal 2793 * properties. Note that some properties can only be changed before any 2794 * read has been done. 2795 * 2796 * Returns 0 if the call was successful, or -1 in case of error 2797 */ 2798int 2799xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) { 2800 xmlParserProperties p = (xmlParserProperties) prop; 2801 xmlParserCtxtPtr ctxt; 2802 2803 if ((reader == NULL) || (reader->ctxt == NULL)) 2804 return(-1); 2805 ctxt = reader->ctxt; 2806 2807 switch (p) { 2808 case XML_PARSER_LOADDTD: 2809 if (value != 0) { 2810 if (ctxt->loadsubset == 0) { 2811 if (reader->mode != XML_TEXTREADER_MODE_INITIAL) 2812 return(-1); 2813 ctxt->loadsubset = XML_DETECT_IDS; 2814 } 2815 } else { 2816 ctxt->loadsubset = 0; 2817 } 2818 return(0); 2819 case XML_PARSER_DEFAULTATTRS: 2820 if (value != 0) { 2821 ctxt->loadsubset |= XML_COMPLETE_ATTRS; 2822 } else { 2823 if (ctxt->loadsubset & XML_COMPLETE_ATTRS) 2824 ctxt->loadsubset -= XML_COMPLETE_ATTRS; 2825 } 2826 return(0); 2827 case XML_PARSER_VALIDATE: 2828 if (value != 0) { 2829 ctxt->validate = 1; 2830 reader->validate = XML_TEXTREADER_VALIDATE_DTD; 2831 } else { 2832 ctxt->validate = 0; 2833 } 2834 return(0); 2835 case XML_PARSER_SUBST_ENTITIES: 2836 if (value != 0) { 2837 ctxt->replaceEntities = 1; 2838 } else { 2839 ctxt->replaceEntities = 0; 2840 } 2841 return(0); 2842 } 2843 return(-1); 2844} 2845 2846/** 2847 * xmlTextReaderGetParserProp: 2848 * @reader: the xmlTextReaderPtr used 2849 * @prop: the xmlParserProperties to get 2850 * 2851 * Read the parser internal property. 2852 * 2853 * Returns the value, usually 0 or 1, or -1 in case of error. 2854 */ 2855int 2856xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) { 2857 xmlParserProperties p = (xmlParserProperties) prop; 2858 xmlParserCtxtPtr ctxt; 2859 2860 if ((reader == NULL) || (reader->ctxt == NULL)) 2861 return(-1); 2862 ctxt = reader->ctxt; 2863 2864 switch (p) { 2865 case XML_PARSER_LOADDTD: 2866 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0)) 2867 return(1); 2868 return(0); 2869 case XML_PARSER_DEFAULTATTRS: 2870 if (ctxt->loadsubset & XML_COMPLETE_ATTRS) 2871 return(1); 2872 return(0); 2873 case XML_PARSER_VALIDATE: 2874 return(reader->validate); 2875 case XML_PARSER_SUBST_ENTITIES: 2876 return(ctxt->replaceEntities); 2877 } 2878 return(-1); 2879} 2880 2881/** 2882 * xmlTextReaderCurrentNode: 2883 * @reader: the xmlTextReaderPtr used 2884 * 2885 * Hacking interface allowing to get the xmlNodePtr correponding to the 2886 * current node being accessed by the xmlTextReader. This is dangerous 2887 * because the underlying node may be destroyed on the next Reads. 2888 * 2889 * Returns the xmlNodePtr or NULL in case of error. 2890 */ 2891xmlNodePtr 2892xmlTextReaderCurrentNode(xmlTextReaderPtr reader) { 2893 if (reader == NULL) 2894 return(NULL); 2895 2896 if (reader->curnode != NULL) 2897 return(reader->curnode); 2898 return(reader->node); 2899} 2900 2901/** 2902 * xmlTextReaderCurrentDoc: 2903 * @reader: the xmlTextReaderPtr used 2904 * 2905 * Hacking interface allowing to get the xmlDocPtr correponding to the 2906 * current document being accessed by the xmlTextReader. This is dangerous 2907 * because the associated node may be destroyed on the next Reads. 2908 * 2909 * Returns the xmlDocPtr or NULL in case of error. 2910 */ 2911xmlDocPtr 2912xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) { 2913 if ((reader == NULL) || (reader->ctxt == NULL)) 2914 return(NULL); 2915 2916 return(reader->ctxt->myDoc); 2917} 2918 2919#ifdef LIBXML_SCHEMAS_ENABLED 2920/** 2921 * xmlTextReaderRelaxNGSetSchema: 2922 * @reader: the xmlTextReaderPtr used 2923 * @schema: a precompiled RelaxNG schema 2924 * 2925 * Use RelaxNG to validate the document as it is processed. 2926 * Activation is only possible before the first Read(). 2927 * if @schema is NULL, then RelaxNG validation is desactivated. 2928 @ The @schema should not be freed until the reader is deallocated 2929 * or its use has been deactivated. 2930 * 2931 * Returns 0 in case the RelaxNG validation could be (des)activated and 2932 * -1 in case of error. 2933 */ 2934int 2935xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) { 2936 if (schema == NULL) { 2937 if (reader->rngSchemas != NULL) { 2938 xmlRelaxNGFree(reader->rngSchemas); 2939 reader->rngSchemas = NULL; 2940 } 2941 if (reader->rngValidCtxt != NULL) { 2942 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); 2943 reader->rngValidCtxt = NULL; 2944 } 2945 return(0); 2946 } 2947 if (reader->mode != XML_TEXTREADER_MODE_INITIAL) 2948 return(-1); 2949 if (reader->rngSchemas != NULL) { 2950 xmlRelaxNGFree(reader->rngSchemas); 2951 reader->rngSchemas = NULL; 2952 } 2953 if (reader->rngValidCtxt != NULL) { 2954 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); 2955 reader->rngValidCtxt = NULL; 2956 } 2957 reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema); 2958 if (reader->rngValidCtxt == NULL) 2959 return(-1); 2960 if (reader->errorFunc != NULL) { 2961 xmlRelaxNGSetValidErrors(reader->rngValidCtxt, 2962 (xmlRelaxNGValidityErrorFunc)reader->errorFunc, 2963 (xmlRelaxNGValidityWarningFunc) reader->errorFunc, 2964 reader->errorFuncArg); 2965 } 2966 reader->rngValidErrors = 0; 2967 reader->rngFullNode = NULL; 2968 reader->validate = XML_TEXTREADER_VALIDATE_RNG; 2969 return(0); 2970} 2971 2972/** 2973 * xmlTextReaderRelaxNGValidate: 2974 * @reader: the xmlTextReaderPtr used 2975 * @rng: the path to a RelaxNG schema or NULL 2976 * 2977 * Use RelaxNG to validate the document as it is processed. 2978 * Activation is only possible before the first Read(). 2979 * if @rng is NULL, then RelaxNG validation is desactivated. 2980 * 2981 * Returns 0 in case the RelaxNG validation could be (des)activated and 2982 * -1 in case of error. 2983 */ 2984int 2985xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) { 2986 xmlRelaxNGParserCtxtPtr ctxt; 2987 2988 if (reader == NULL) 2989 return(-1); 2990 2991 if (rng == NULL) { 2992 if (reader->rngSchemas != NULL) { 2993 xmlRelaxNGFree(reader->rngSchemas); 2994 reader->rngSchemas = NULL; 2995 } 2996 if (reader->rngValidCtxt != NULL) { 2997 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); 2998 reader->rngValidCtxt = NULL; 2999 } 3000 return(0); 3001 } 3002 if (reader->mode != XML_TEXTREADER_MODE_INITIAL) 3003 return(-1); 3004 if (reader->rngSchemas != NULL) { 3005 xmlRelaxNGFree(reader->rngSchemas); 3006 reader->rngSchemas = NULL; 3007 } 3008 if (reader->rngValidCtxt != NULL) { 3009 xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); 3010 reader->rngValidCtxt = NULL; 3011 } 3012 ctxt = xmlRelaxNGNewParserCtxt(rng); 3013 if (reader->errorFunc != NULL) { 3014 xmlRelaxNGSetParserErrors(ctxt, 3015 (xmlRelaxNGValidityErrorFunc) reader->errorFunc, 3016 (xmlRelaxNGValidityWarningFunc) reader->errorFunc, 3017 reader->errorFuncArg); 3018 } 3019 reader->rngSchemas = xmlRelaxNGParse(ctxt); 3020 xmlRelaxNGFreeParserCtxt(ctxt); 3021 if (reader->rngSchemas == NULL) 3022 return(-1); 3023 reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas); 3024 if (reader->rngValidCtxt == NULL) 3025 return(-1); 3026 if (reader->errorFunc != NULL) { 3027 xmlRelaxNGSetValidErrors(reader->rngValidCtxt, 3028 (xmlRelaxNGValidityErrorFunc)reader->errorFunc, 3029 (xmlRelaxNGValidityWarningFunc) reader->errorFunc, 3030 reader->errorFuncArg); 3031 } 3032 reader->rngValidErrors = 0; 3033 reader->rngFullNode = NULL; 3034 reader->validate = XML_TEXTREADER_VALIDATE_RNG; 3035 return(0); 3036} 3037#endif 3038 3039/************************************************************************ 3040 * * 3041 * Error Handling Extensions * 3042 * * 3043 ************************************************************************/ 3044 3045/* helper to build a xmlMalloc'ed string from a format and va_list */ 3046static char * 3047xmlTextReaderBuildMessage(const char *msg, va_list ap) { 3048 int size; 3049 int chars; 3050 char *larger; 3051 char *str; 3052 3053 str = (char *) xmlMallocAtomic(150); 3054 if (str == NULL) { 3055 xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n"); 3056 return NULL; 3057 } 3058 3059 size = 150; 3060 3061 while (1) { 3062 chars = vsnprintf(str, size, msg, ap); 3063 if ((chars > -1) && (chars < size)) 3064 break; 3065 if (chars > -1) 3066 size += chars + 1; 3067 else 3068 size += 100; 3069 if ((larger = (char *) xmlRealloc(str, size)) == NULL) { 3070 xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); 3071 xmlFree(str); 3072 return NULL; 3073 } 3074 str = larger; 3075 } 3076 3077 return str; 3078} 3079 3080/** 3081 * xmlTextReaderLocatorLineNumber: 3082 * @locator: the xmlTextReaderLocatorPtr used 3083 * 3084 * Obtain the line number for the given locator. 3085 * 3086 * Returns the line number or -1 in case of error. 3087 */ 3088int 3089xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) { 3090 /* we know that locator is a xmlParserCtxtPtr */ 3091 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator; 3092 int ret = -1; 3093 3094 if (ctx->node != NULL) { 3095 ret = xmlGetLineNo(ctx->node); 3096 } 3097 else { 3098 /* inspired from error.c */ 3099 xmlParserInputPtr input; 3100 input = ctx->input; 3101 if ((input->filename == NULL) && (ctx->inputNr > 1)) 3102 input = ctx->inputTab[ctx->inputNr - 2]; 3103 if (input != NULL) { 3104 ret = input->line; 3105 } 3106 else { 3107 ret = -1; 3108 } 3109 } 3110 3111 return ret; 3112} 3113 3114/** 3115 * xmlTextReaderLocatorBaseURI: 3116 * @locator: the xmlTextReaderLocatorPtr used 3117 * 3118 * Obtain the base URI for the given locator. 3119 * 3120 * Returns the base URI or NULL in case of error. 3121 */ 3122xmlChar * 3123xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) { 3124 /* we know that locator is a xmlParserCtxtPtr */ 3125 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator; 3126 xmlChar *ret = NULL; 3127 3128 if (ctx->node != NULL) { 3129 ret = xmlNodeGetBase(NULL,ctx->node); 3130 } 3131 else { 3132 /* inspired from error.c */ 3133 xmlParserInputPtr input; 3134 input = ctx->input; 3135 if ((input->filename == NULL) && (ctx->inputNr > 1)) 3136 input = ctx->inputTab[ctx->inputNr - 2]; 3137 if (input != NULL) { 3138 ret = xmlStrdup(BAD_CAST input->filename); 3139 } 3140 else { 3141 ret = NULL; 3142 } 3143 } 3144 3145 return ret; 3146} 3147 3148static void 3149xmlTextReaderGenericError(void *ctxt, int severity, char *str) { 3150 xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt; 3151 xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private; 3152 3153 if (str != NULL) { 3154 reader->errorFunc(reader->errorFuncArg, 3155 str, 3156 severity, 3157 (xmlTextReaderLocatorPtr)ctx); 3158 xmlFree(str); 3159 } 3160} 3161 3162static void 3163xmlTextReaderError(void *ctxt, const char *msg, ...) { 3164 va_list ap; 3165 3166 va_start(ap,msg); 3167 xmlTextReaderGenericError(ctxt, 3168 XML_PARSER_SEVERITY_ERROR, 3169 xmlTextReaderBuildMessage(msg,ap)); 3170 va_end(ap); 3171 3172} 3173 3174static void 3175xmlTextReaderWarning(void *ctxt, const char *msg, ...) { 3176 va_list ap; 3177 3178 va_start(ap,msg); 3179 xmlTextReaderGenericError(ctxt, 3180 XML_PARSER_SEVERITY_WARNING, 3181 xmlTextReaderBuildMessage(msg,ap)); 3182 va_end(ap); 3183} 3184 3185static void 3186xmlTextReaderValidityError(void *ctxt, const char *msg, ...) { 3187 va_list ap; 3188 int len = xmlStrlen((const xmlChar *) msg); 3189 3190 if ((len > 1) && (msg[len - 2] != ':')) { 3191 /* 3192 * some callbacks only report locator information: 3193 * skip them (mimicking behaviour in error.c) 3194 */ 3195 va_start(ap,msg); 3196 xmlTextReaderGenericError(ctxt, 3197 XML_PARSER_SEVERITY_VALIDITY_ERROR, 3198 xmlTextReaderBuildMessage(msg,ap)); 3199 va_end(ap); 3200 } 3201} 3202 3203static void 3204xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) { 3205 va_list ap; 3206 int len = xmlStrlen((const xmlChar *) msg); 3207 3208 if ((len != 0) && (msg[len - 1] != ':')) { 3209 /* 3210 * some callbacks only report locator information: 3211 * skip them (mimicking behaviour in error.c) 3212 */ 3213 va_start(ap,msg); 3214 xmlTextReaderGenericError(ctxt, 3215 XML_PARSER_SEVERITY_VALIDITY_WARNING, 3216 xmlTextReaderBuildMessage(msg,ap)); 3217 va_end(ap); 3218 } 3219} 3220 3221/** 3222 * xmlTextReaderSetErrorHandler: 3223 * @reader: the xmlTextReaderPtr used 3224 * @f: the callback function to call on error and warnings 3225 * @arg: a user argument to pass to the callback function 3226 * 3227 * Register a callback function that will be called on error and warnings. 3228 * 3229 * If @f is NULL, the default error and warning handlers are restored. 3230 */ 3231void 3232xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader, 3233 xmlTextReaderErrorFunc f, 3234 void *arg) { 3235 if (f != NULL) { 3236 reader->ctxt->sax->error = xmlTextReaderError; 3237 reader->ctxt->vctxt.error = xmlTextReaderValidityError; 3238 reader->ctxt->sax->warning = xmlTextReaderWarning; 3239 reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning; 3240 reader->errorFunc = f; 3241 reader->errorFuncArg = arg; 3242 } 3243 else { 3244 /* restore defaults */ 3245 reader->ctxt->sax->error = xmlParserError; 3246 reader->ctxt->vctxt.error = xmlParserValidityError; 3247 reader->ctxt->sax->warning = xmlParserWarning; 3248 reader->ctxt->vctxt.warning = xmlParserValidityWarning; 3249 reader->errorFunc = NULL; 3250 reader->errorFuncArg = NULL; 3251 } 3252} 3253 3254/** 3255 * xmlTextReaderIsValid: 3256 * @reader: the xmlTextReaderPtr used 3257 * 3258 * Retrieve the validity status from the parser context 3259 * 3260 * Returns the flag value 1 if valid, 0 if no, and -1 in case of error 3261 */ 3262int 3263xmlTextReaderIsValid(xmlTextReaderPtr reader) { 3264 if (reader == NULL) return(-1); 3265#ifdef LIBXML_SCHEMAS_ENABLED 3266 if (reader->validate == XML_TEXTREADER_VALIDATE_RNG) 3267 return(reader->rngValidErrors == 0); 3268#endif 3269 if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) && 3270 (reader->ctxt != NULL)) 3271 return(reader->ctxt->valid); 3272 return(0); 3273} 3274 3275/** 3276 * xmlTextReaderGetErrorHandler: 3277 * @reader: the xmlTextReaderPtr used 3278 * @f: the callback function or NULL is no callback has been registered 3279 * @arg: a user argument 3280 * 3281 * Retrieve the error callback function and user argument. 3282 */ 3283void 3284xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader, 3285 xmlTextReaderErrorFunc *f, 3286 void **arg) { 3287 *f = reader->errorFunc; 3288 *arg = reader->errorFuncArg; 3289} 3290 3291/************************************************************************ 3292 * * 3293 * Utilities * 3294 * * 3295 ************************************************************************/ 3296#ifdef NOT_USED_YET 3297/** 3298 * xmlBase64Decode: 3299 * @in: the input buffer 3300 * @inlen: the size of the input (in), the size read from it (out) 3301 * @to: the output buffer 3302 * @tolen: the size of the output (in), the size written to (out) 3303 * 3304 * Base64 decoder, reads from @in and save in @to 3305 * TODO: tell jody when this is actually exported 3306 * 3307 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached, 3308 * 2 if there wasn't enough space on the output or -1 in case of error. 3309 */ 3310static int 3311xmlBase64Decode(const unsigned char *in, unsigned long *inlen, 3312 unsigned char *to, unsigned long *tolen) { 3313 unsigned long incur; /* current index in in[] */ 3314 unsigned long inblk; /* last block index in in[] */ 3315 unsigned long outcur; /* current index in out[] */ 3316 unsigned long inmax; /* size of in[] */ 3317 unsigned long outmax; /* size of out[] */ 3318 unsigned char cur; /* the current value read from in[] */ 3319 unsigned char intmp[4], outtmp[4]; /* temporary buffers for the convert */ 3320 int nbintmp; /* number of byte in intmp[] */ 3321 int is_ignore; /* cur should be ignored */ 3322 int is_end = 0; /* the end of the base64 was found */ 3323 int retval = 1; 3324 int i; 3325 3326 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL)) 3327 return(-1); 3328 3329 incur = 0; 3330 inblk = 0; 3331 outcur = 0; 3332 inmax = *inlen; 3333 outmax = *tolen; 3334 nbintmp = 0; 3335 3336 while (1) { 3337 if (incur >= inmax) 3338 break; 3339 cur = in[incur++]; 3340 is_ignore = 0; 3341 if ((cur >= 'A') && (cur <= 'Z')) 3342 cur = cur - 'A'; 3343 else if ((cur >= 'a') && (cur <= 'z')) 3344 cur = cur - 'a' + 26; 3345 else if ((cur >= '0') && (cur <= '9')) 3346 cur = cur - '0' + 52; 3347 else if (cur == '+') 3348 cur = 62; 3349 else if (cur == '/') 3350 cur = 63; 3351 else if (cur == '.') 3352 cur = 0; 3353 else if (cur == '=') /*no op , end of the base64 stream */ 3354 is_end = 1; 3355 else { 3356 is_ignore = 1; 3357 if (nbintmp == 0) 3358 inblk = incur; 3359 } 3360 3361 if (!is_ignore) { 3362 int nbouttmp = 3; 3363 int is_break = 0; 3364 3365 if (is_end) { 3366 if (nbintmp == 0) 3367 break; 3368 if ((nbintmp == 1) || (nbintmp == 2)) 3369 nbouttmp = 1; 3370 else 3371 nbouttmp = 2; 3372 nbintmp = 3; 3373 is_break = 1; 3374 } 3375 intmp[nbintmp++] = cur; 3376 /* 3377 * if intmp is full, push the 4byte sequence as a 3 byte 3378 * sequence out 3379 */ 3380 if (nbintmp == 4) { 3381 nbintmp = 0; 3382 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4); 3383 outtmp[1] = 3384 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2); 3385 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F); 3386 if (outcur + 3 >= outmax) { 3387 retval = 2; 3388 break; 3389 } 3390 3391 for (i = 0; i < nbouttmp; i++) 3392 to[outcur++] = outtmp[i]; 3393 inblk = incur; 3394 } 3395 3396 if (is_break) { 3397 retval = 0; 3398 break; 3399 } 3400 } 3401 } 3402 3403 *tolen = outcur; 3404 *inlen = inblk; 3405 return (retval); 3406} 3407 3408/* 3409 * Test routine for the xmlBase64Decode function 3410 */ 3411#if 0 3412int main(int argc, char **argv) { 3413 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== "; 3414 char output[100]; 3415 char output2[100]; 3416 char output3[100]; 3417 unsigned long inlen = strlen(input); 3418 unsigned long outlen = 100; 3419 int ret; 3420 unsigned long cons, tmp, tmp2, prod; 3421 3422 /* 3423 * Direct 3424 */ 3425 ret = xmlBase64Decode(input, &inlen, output, &outlen); 3426 3427 output[outlen] = 0; 3428 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output); 3429 3430 /* 3431 * output chunking 3432 */ 3433 cons = 0; 3434 prod = 0; 3435 while (cons < inlen) { 3436 tmp = 5; 3437 tmp2 = inlen - cons; 3438 3439 printf("%ld %ld\n", cons, prod); 3440 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp); 3441 cons += tmp2; 3442 prod += tmp; 3443 printf("%ld %ld\n", cons, prod); 3444 } 3445 output2[outlen] = 0; 3446 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2); 3447 3448 /* 3449 * input chunking 3450 */ 3451 cons = 0; 3452 prod = 0; 3453 while (cons < inlen) { 3454 tmp = 100 - prod; 3455 tmp2 = inlen - cons; 3456 if (tmp2 > 5) 3457 tmp2 = 5; 3458 3459 printf("%ld %ld\n", cons, prod); 3460 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp); 3461 cons += tmp2; 3462 prod += tmp; 3463 printf("%ld %ld\n", cons, prod); 3464 } 3465 output3[outlen] = 0; 3466 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3); 3467 return(0); 3468 3469} 3470#endif 3471#endif /* NOT_USED_YET */ 3472