xmlreader.c revision 9e395c289ffd624c9a17460a02af7fc6026eb16a
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#define IN_LIBXML 14#include "libxml.h" 15 16#include <string.h> /* for memset() only ! */ 17 18#ifdef HAVE_CTYPE_H 19#include <ctype.h> 20#endif 21#ifdef HAVE_STDLIB_H 22#include <stdlib.h> 23#endif 24 25#include <libxml/xmlmemory.h> 26#include <libxml/xmlIO.h> 27#include <libxml/xmlreader.h> 28 29/* #define DEBUG_CALLBACKS */ 30/* #define DEBUG_READER */ 31 32/** 33 * TODO: 34 * 35 * macro to flag unimplemented blocks 36 */ 37#define TODO \ 38 xmlGenericError(xmlGenericErrorContext, \ 39 "Unimplemented block at %s:%d\n", \ 40 __FILE__, __LINE__); 41 42#ifdef DEBUG_READER 43#define DUMP_READER xmlTextReaderDebug(reader); 44#else 45#define DUMP_READER 46#endif 47 48/************************************************************************ 49 * * 50 * The parser: maps the Text Reader API on top of the existing * 51 * parsing routines building a tree * 52 * * 53 ************************************************************************/ 54 55#define XML_TEXTREADER_INPUT 1 56#define XML_TEXTREADER_CTXT 2 57 58typedef enum { 59 XML_TEXTREADER_MODE_INITIAL = 0, 60 XML_TEXTREADER_MODE_INTERACTIVE = 1, 61 XML_TEXTREADER_MODE_ERROR = 2, 62 XML_TEXTREADER_MODE_EOF =3, 63 XML_TEXTREADER_MODE_CLOSED = 4, 64 XML_TEXTREADER_MODE_READING = 5 65} xmlTextReaderMode; 66 67typedef enum { 68 XML_TEXTREADER_NONE = -1, 69 XML_TEXTREADER_START= 0, 70 XML_TEXTREADER_ELEMENT= 1, 71 XML_TEXTREADER_END= 2, 72 XML_TEXTREADER_EMPTY= 3, 73 XML_TEXTREADER_BACKTRACK= 4, 74 XML_TEXTREADER_DONE= 5 75} xmlTextReaderState; 76 77struct _xmlTextReader { 78 int mode; /* the parsing mode */ 79 int allocs; /* what structure were deallocated */ 80 xmlTextReaderState state; 81 xmlParserCtxtPtr ctxt; /* the parser context */ 82 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */ 83 xmlParserInputBufferPtr input; /* the input */ 84 startElementSAXFunc startElement;/* initial SAX callbacks */ 85 endElementSAXFunc endElement; /* idem */ 86 charactersSAXFunc characters; 87 cdataBlockSAXFunc cdataBlock; 88 unsigned int base; /* base of the segment in the input */ 89 unsigned int cur; /* current position in the input */ 90 xmlNodePtr node; /* current node */ 91 xmlNodePtr curnode;/* current attribute node */ 92 int depth; /* depth of the current node */ 93 xmlNodePtr faketext;/* fake xmlNs chld */ 94 int wasempty;/* was the last node empty */ 95}; 96 97#ifdef DEBUG_READER 98static void 99xmlTextReaderDebug(xmlTextReaderPtr reader) { 100 if ((reader == NULL) || (reader->ctxt == NULL)) { 101 fprintf(stderr, "xmlTextReader NULL\n"); 102 return; 103 } 104 fprintf(stderr, "xmlTextReader: state %d depth %d ", 105 reader->state, reader->depth); 106 if (reader->node == NULL) { 107 fprintf(stderr, "node = NULL\n"); 108 } else { 109 fprintf(stderr, "node %s\n", reader->node->name); 110 } 111 fprintf(stderr, " input: base %d, cur %d, depth %d: ", 112 reader->base, reader->cur, reader->ctxt->nodeNr); 113 if (reader->input->buffer == NULL) { 114 fprintf(stderr, "buffer is NULL\n"); 115 } else { 116#ifdef LIBXML_DEBUG_ENABLED 117 xmlDebugDumpString(stderr, 118 &reader->input->buffer->content[reader->cur]); 119#endif 120 fprintf(stderr, "\n"); 121 } 122} 123#endif 124 125/** 126 * xmlTextReaderStartElement: 127 * @ctx: the user data (XML parser context) 128 * @fullname: The element name, including namespace prefix 129 * @atts: An array of name/value attributes pairs, NULL terminated 130 * 131 * called when an opening tag has been processed. 132 */ 133static void 134xmlTextReaderStartElement(void *ctx, const xmlChar *fullname, 135 const xmlChar **atts) { 136 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 137 xmlParserCtxtPtr origctxt; 138 xmlTextReaderPtr reader = ctxt->_private; 139 140#ifdef DEBUG_CALLBACKS 141 printf("xmlTextReaderStartElement(%s)\n", fullname); 142#endif 143 if ((reader != NULL) && (reader->startElement != NULL)) { 144 /* 145 * when processing an entity, the context may have been changed 146 */ 147 origctxt = reader->ctxt; 148 reader->startElement(ctx, fullname, atts); 149 if (origctxt->validate) { 150 ctxt->valid &= xmlValidatePushElement(&origctxt->vctxt, 151 ctxt->myDoc, ctxt->node, fullname); 152 } 153 } 154 if (reader != NULL) 155 reader->state = XML_TEXTREADER_ELEMENT; 156} 157 158/** 159 * xmlTextReaderEndElement: 160 * @ctx: the user data (XML parser context) 161 * @fullname: The element name, including namespace prefix 162 * 163 * called when an ending tag has been processed. 164 */ 165static void 166xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) { 167 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 168 xmlParserCtxtPtr origctxt; 169 xmlTextReaderPtr reader = ctxt->_private; 170 171#ifdef DEBUG_CALLBACKS 172 printf("xmlTextReaderEndElement(%s)\n", fullname); 173#endif 174 if ((reader != NULL) && (reader->endElement != NULL)) { 175 xmlNodePtr node = ctxt->node; 176 /* 177 * when processing an entity, the context may have been changed 178 */ 179 origctxt = reader->ctxt; 180 181 reader->endElement(ctx, fullname); 182 183 if (origctxt->validate) { 184 ctxt->valid &= xmlValidatePopElement(&origctxt->vctxt, 185 ctxt->myDoc, node, fullname); 186 } 187 } 188 if (reader != NULL) { 189 if (reader->state == XML_TEXTREADER_ELEMENT) 190 reader->wasempty = 1; 191 else 192 reader->wasempty = 0; 193 } 194} 195 196/** 197 * xmlTextReaderCharacters: 198 * @ctx: the user data (XML parser context) 199 * @ch: a xmlChar string 200 * @len: the number of xmlChar 201 * 202 * receiving some chars from the parser. 203 */ 204static void 205xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len) 206{ 207 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 208 xmlParserCtxtPtr origctxt; 209 xmlTextReaderPtr reader = ctxt->_private; 210 211#ifdef DEBUG_CALLBACKS 212 printf("xmlTextReaderCharacters()\n"); 213#endif 214 if ((reader != NULL) && (reader->characters != NULL)) { 215 reader->characters(ctx, ch, len); 216 /* 217 * when processing an entity, the context may have been changed 218 */ 219 origctxt = reader->ctxt; 220 221 if (origctxt->validate) { 222 ctxt->valid &= xmlValidatePushCData(&origctxt->vctxt, ch, len); 223 } 224 } 225} 226 227/** 228 * xmlTextReaderCDataBlock: 229 * @ctx: the user data (XML parser context) 230 * @value: The pcdata content 231 * @len: the block length 232 * 233 * called when a pcdata block has been parsed 234 */ 235static void 236xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len) 237{ 238 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 239 xmlTextReaderPtr reader = ctxt->_private; 240 241#ifdef DEBUG_CALLBACKS 242 printf("xmlTextReaderCDataBlock()\n"); 243#endif 244 if ((reader != NULL) && (reader->cdataBlock != NULL)) { 245 reader->cdataBlock(ctx, ch, len); 246 247 if (ctxt->validate) { 248 ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt, ch, len); 249 } 250 } 251} 252 253/** 254 * xmlTextReaderPushData: 255 * @reader: the xmlTextReaderPtr used 256 * 257 * Push data down the progressive parser until a significant callback 258 * got raised. 259 * 260 * Returns -1 in case of failure, 0 otherwise 261 */ 262static int 263xmlTextReaderPushData(xmlTextReaderPtr reader) { 264 unsigned int cur = reader->cur; 265 xmlBufferPtr inbuf; 266 int val; 267 int oldstate; 268 269 if ((reader->input == NULL) || (reader->input->buffer == NULL)) 270 return(-1); 271 272 oldstate = reader->state; 273 reader->state = XML_TEXTREADER_NONE; 274 inbuf = reader->input->buffer; 275 while (reader->state == XML_TEXTREADER_NONE) { 276 if (cur >= inbuf->use) { 277 /* 278 * Refill the buffer unless we are at the end of the stream 279 */ 280 if (reader->mode != XML_TEXTREADER_MODE_EOF) { 281 val = xmlParserInputBufferRead(reader->input, 4096); 282 if (val <= 0) { 283 reader->mode = XML_TEXTREADER_MODE_EOF; 284 reader->state = oldstate; 285 if ((oldstate != XML_TEXTREADER_START) || 286 (reader->ctxt->myDoc != NULL)) 287 return(val); 288 } 289 } else 290 break; 291 } 292 if ((inbuf->content[cur] == '>') || (inbuf->content[cur] == '&')) { 293 cur = cur + 1; 294 val = xmlParseChunk(reader->ctxt, 295 (const char *) &inbuf->content[reader->cur], 296 cur - reader->cur, 0); 297 if (val != 0) 298 return(-1); 299 reader->cur = cur; 300 break; 301 } else { 302 cur = cur + 1; 303 304 /* 305 * One may have to force a flush at some point when parsing really 306 * large CDATA sections 307 */ 308 if ((cur - reader->cur > 4096) && (reader->base == 0) && 309 (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) { 310 cur = cur + 1; 311 val = xmlParseChunk(reader->ctxt, 312 (const char *) &inbuf->content[reader->cur], 313 cur - reader->cur, 0); 314 if (val != 0) 315 return(-1); 316 reader->cur = cur; 317 } 318 } 319 } 320 /* 321 * Discard the consumed input when needed and possible 322 */ 323 if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) { 324 if ((reader->cur >= 4096) && (reader->base == 0)) { 325 val = xmlBufferShrink(inbuf, cur); 326 if (val >= 0) { 327 reader->cur -= val; 328 } 329 } 330 } 331 332 /* 333 * At the end of the stream signal that the work is done to the Push 334 * parser. 335 */ 336 if (reader->mode == XML_TEXTREADER_MODE_EOF) { 337 if (reader->mode != XML_TEXTREADER_DONE) { 338 val = xmlParseChunk(reader->ctxt, 339 (const char *) &inbuf->content[reader->cur], 0, 1); 340 reader->mode = XML_TEXTREADER_DONE; 341 } 342 } 343 reader->state = oldstate; 344 return(0); 345} 346 347/** 348 * xmlTextReaderRead: 349 * @reader: the xmlTextReaderPtr used 350 * 351 * Moves the position of the current instance to the next node in 352 * the stream, exposing its properties. 353 * 354 * Returns 1 if the node was read successfully, 0 if there is no more 355 * nodes to read, or -1 in case of error 356 */ 357int 358xmlTextReaderRead(xmlTextReaderPtr reader) { 359 int val, olddepth, wasempty; 360 xmlTextReaderState oldstate; 361 xmlNodePtr oldnode; 362 363 if ((reader == NULL) || (reader->ctxt == NULL)) 364 return(-1); 365 if (reader->ctxt->wellFormed != 1) 366 return(-1); 367 368#ifdef DEBUG_READER 369 fprintf(stderr, "\nREAD "); 370 DUMP_READER 371#endif 372 reader->curnode = NULL; 373 if (reader->mode == XML_TEXTREADER_MODE_INITIAL) { 374 reader->mode = XML_TEXTREADER_MODE_INTERACTIVE; 375 /* 376 * Initial state 377 */ 378 do { 379 val = xmlTextReaderPushData(reader); 380 if (val < 0) 381 return(-1); 382 } while ((reader->ctxt->node == NULL) && 383 (reader->mode != XML_TEXTREADER_MODE_EOF)); 384 if (reader->ctxt->node == NULL) { 385 if (reader->ctxt->myDoc != NULL) 386 reader->node = reader->ctxt->myDoc->children; 387 if (reader->node == NULL) 388 return(-1); 389 } else { 390 reader->node = reader->ctxt->nodeTab[0]; 391 } 392 reader->depth = 0; 393 return(1); 394 } 395 oldstate = reader->state; 396 olddepth = reader->ctxt->nodeNr; 397 oldnode = reader->node; 398 wasempty = ((reader->wasempty == 1) && (reader->ctxt->node != NULL) && 399 (reader->ctxt->node->last == reader->node)); 400 401 /* 402 * If we are not backtracking on ancestors or examined nodes, 403 * that the parser didn't finished or that we arent at the end 404 * of stream, continue processing. 405 */ 406 while (((oldstate == XML_TEXTREADER_BACKTRACK) || 407 (reader->node->children == NULL) || 408 (reader->node->type == XML_ENTITY_REF_NODE) || 409 (reader->node->type == XML_DTD_NODE)) && 410 (reader->node->next == NULL) && 411 (reader->ctxt->nodeNr == olddepth) && 412 (reader->ctxt->instate != XML_PARSER_EOF)) { 413 val = xmlTextReaderPushData(reader); 414 if (val < 0) 415 return(-1); 416 if (reader->node == NULL) 417 return(0); 418 } 419 if (oldstate != XML_TEXTREADER_BACKTRACK) { 420 if ((reader->node->children != NULL) && 421 (reader->node->type != XML_ENTITY_REF_NODE) && 422 (reader->node->type != XML_DTD_NODE)) { 423 reader->node = reader->node->children; 424 reader->depth++; 425 reader->state = XML_TEXTREADER_ELEMENT; 426 DUMP_READER 427 return(1); 428 } 429 } 430 if (reader->node->next != NULL) { 431 if ((oldstate == XML_TEXTREADER_ELEMENT) && 432 (reader->node->type == XML_ELEMENT_NODE) && 433 (wasempty == 0)) { 434 reader->state = XML_TEXTREADER_END; 435 DUMP_READER 436 return(1); 437 } 438 reader->node = reader->node->next; 439 reader->state = XML_TEXTREADER_ELEMENT; 440 DUMP_READER 441 /* 442 * Cleanup of the old node 443 */ 444 if (oldnode->type != XML_DTD_NODE) { 445 xmlUnlinkNode(oldnode); 446 xmlFreeNode(oldnode); 447 } 448 449 return(1); 450 } 451 if ((oldstate == XML_TEXTREADER_ELEMENT) && 452 (reader->node->type == XML_ELEMENT_NODE) && 453 (wasempty == 0)) { 454 reader->state = XML_TEXTREADER_END; 455 DUMP_READER 456 return(1); 457 } 458 reader->node = reader->node->parent; 459 if ((reader->node == NULL) || 460 (reader->node->type == XML_DOCUMENT_NODE) || 461#ifdef LIBXML_DOCB_ENABLED 462 (reader->node->type == XML_DOCB_DOCUMENT_NODE) || 463#endif 464 (reader->node->type == XML_HTML_DOCUMENT_NODE)) { 465 if (reader->mode != XML_TEXTREADER_DONE) { 466 val = xmlParseChunk(reader->ctxt, "", 0, 1); 467 reader->mode = XML_TEXTREADER_DONE; 468 } 469 reader->node = NULL; 470 reader->depth = -1; 471 472 /* 473 * Cleanup of the old node 474 */ 475 if (oldnode->type != XML_DTD_NODE) { 476 xmlUnlinkNode(oldnode); 477 xmlFreeNode(oldnode); 478 } 479 480 return(0); 481 } 482 reader->depth--; 483 reader->state = XML_TEXTREADER_BACKTRACK; 484 DUMP_READER 485 return(1); 486} 487 488/** 489 * xmlTextReaderReadState: 490 * @reader: the xmlTextReaderPtr used 491 * 492 * Gets the read state of the reader. 493 * 494 * Returns the state value, or -1 in case of error 495 */ 496int 497xmlTextReaderReadState(xmlTextReaderPtr reader) { 498 if (reader == NULL) 499 return(-1); 500 return(reader->mode); 501} 502 503/** 504 * xmlTextReaderReadInnerXml: 505 * @reader: the xmlTextReaderPtr used 506 * 507 * Reads the contents of the current node, including child nodes and markup. 508 * 509 * Returns a string containing the XML content, or NULL if the current node 510 * is neither an element nor attribute, or has no child nodes. The 511 * string must be deallocated by the caller. 512 */ 513xmlChar * 514xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) { 515 TODO 516 return(NULL); 517} 518 519/** 520 * xmlTextReaderReadOuterXml: 521 * @reader: the xmlTextReaderPtr used 522 * 523 * Reads the contents of the current node, including child nodes and markup. 524 * 525 * Returns a string containing the XML content, or NULL if the current node 526 * is neither an element nor attribute, or has no child nodes. The 527 * string must be deallocated by the caller. 528 */ 529xmlChar * 530xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) { 531 TODO 532 return(NULL); 533} 534 535/** 536 * xmlTextReaderReadString: 537 * @reader: the xmlTextReaderPtr used 538 * 539 * Reads the contents of an element or a text node as a string. 540 * 541 * Returns a string containing the contents of the Element or Text node, 542 * or NULL if the reader is positioned on any other type of node. 543 * The string must be deallocated by the caller. 544 */ 545xmlChar * 546xmlTextReaderReadString(xmlTextReaderPtr reader) { 547 TODO 548 return(NULL); 549} 550 551/** 552 * xmlTextReaderReadBase64: 553 * @reader: the xmlTextReaderPtr used 554 * @array: a byte array to store the content. 555 * @offset: the zero-based index into array where the method should 556 * begin to write. 557 * @len: the number of bytes to write. 558 * 559 * Reads and decodes the Base64 encoded contents of an element and 560 * stores the result in a byte buffer. 561 * 562 * Returns the number of bytes written to array, or zero if the current 563 * instance is not positioned on an element or -1 in case of error. 564 */ 565int 566xmlTextReaderReadBase64(xmlTextReaderPtr reader, unsigned char *array, 567 int offset, int len) { 568 if ((reader == NULL) || (reader->ctxt == NULL)) 569 return(-1); 570 if (reader->ctxt->wellFormed != 1) 571 return(-1); 572 573 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) 574 return(0); 575 TODO 576 return(0); 577} 578 579/** 580 * xmlTextReaderReadBinHex: 581 * @reader: the xmlTextReaderPtr used 582 * @array: a byte array to store the content. 583 * @offset: the zero-based index into array where the method should 584 * begin to write. 585 * @len: the number of bytes to write. 586 * 587 * Reads and decodes the BinHex encoded contents of an element and 588 * stores the result in a byte buffer. 589 * 590 * Returns the number of bytes written to array, or zero if the current 591 * instance is not positioned on an element or -1 in case of error. 592 */ 593int 594xmlTextReaderReadBinHex(xmlTextReaderPtr reader, unsigned char *array, 595 int offset, int len) { 596 if ((reader == NULL) || (reader->ctxt == NULL)) 597 return(-1); 598 if (reader->ctxt->wellFormed != 1) 599 return(-1); 600 601 if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) 602 return(0); 603 TODO 604 return(0); 605} 606 607/************************************************************************ 608 * * 609 * Constructor and destructors * 610 * * 611 ************************************************************************/ 612/** 613 * xmlNewTextReader: 614 * @input: the xmlParserInputBufferPtr used to read data 615 * @URI: the URI information for the source if available 616 * 617 * Create an xmlTextReader structure fed with @input 618 * 619 * Returns the new xmlTextReaderPtr or NULL in case of error 620 */ 621xmlTextReaderPtr 622xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { 623 xmlTextReaderPtr ret; 624 int val; 625 626 if (input == NULL) 627 return(NULL); 628 ret = xmlMalloc(sizeof(xmlTextReader)); 629 if (ret == NULL) { 630 xmlGenericError(xmlGenericErrorContext, 631 "xmlNewTextReader : malloc failed\n"); 632 return(NULL); 633 } 634 memset(ret, 0, sizeof(xmlTextReader)); 635 ret->input = input; 636 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler)); 637 if (ret->sax == NULL) { 638 xmlFree(ret); 639 xmlGenericError(xmlGenericErrorContext, 640 "xmlNewTextReader : malloc failed\n"); 641 return(NULL); 642 } 643 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler)); 644 ret->startElement = ret->sax->startElement; 645 ret->sax->startElement = xmlTextReaderStartElement; 646 ret->endElement = ret->sax->endElement; 647 ret->sax->endElement = xmlTextReaderEndElement; 648 ret->characters = ret->sax->characters; 649 ret->sax->characters = xmlTextReaderCharacters; 650 ret->cdataBlock = ret->sax->cdataBlock; 651 ret->sax->cdataBlock = xmlTextReaderCDataBlock; 652 653 ret->mode = XML_TEXTREADER_MODE_INITIAL; 654 ret->node = NULL; 655 ret->curnode = NULL; 656 val = xmlParserInputBufferRead(input, 4); 657 if (val >= 4) { 658 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, 659 (const char *) ret->input->buffer->content, 4, URI); 660 ret->base = 0; 661 ret->cur = 4; 662 } else { 663 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI); 664 ret->base = 0; 665 ret->cur = 0; 666 } 667 ret->ctxt->_private = ret; 668 ret->ctxt->linenumbers = 1; 669 ret->allocs = XML_TEXTREADER_CTXT; 670 return(ret); 671 672} 673 674/** 675 * xmlNewTextReaderFilename: 676 * @URI: the URI of the resource to process 677 * 678 * Create an xmlTextReader structure fed with the resource at @URI 679 * 680 * Returns the new xmlTextReaderPtr or NULL in case of error 681 */ 682xmlTextReaderPtr 683xmlNewTextReaderFilename(const char *URI) { 684 xmlParserInputBufferPtr input; 685 xmlTextReaderPtr ret; 686 char *directory = NULL; 687 688 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE); 689 if (input == NULL) 690 return(NULL); 691 ret = xmlNewTextReader(input, URI); 692 if (ret == NULL) { 693 xmlFreeParserInputBuffer(input); 694 return(NULL); 695 } 696 ret->allocs |= XML_TEXTREADER_INPUT; 697 if (ret->ctxt->directory == NULL) 698 directory = xmlParserGetDirectory(URI); 699 if ((ret->ctxt->directory == NULL) && (directory != NULL)) 700 ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory); 701 if (directory != NULL) 702 xmlFree(directory); 703 return(ret); 704} 705 706/** 707 * xmlFreeTextReader: 708 * @reader: the xmlTextReaderPtr 709 * 710 * Deallocate all the resources associated to the reader 711 */ 712void 713xmlFreeTextReader(xmlTextReaderPtr reader) { 714 if (reader == NULL) 715 return; 716 if (reader->ctxt != NULL) { 717 if (reader->ctxt->myDoc != NULL) { 718 xmlFreeDoc(reader->ctxt->myDoc); 719 reader->ctxt->myDoc = NULL; 720 } 721 if ((reader->ctxt->vctxt.vstateTab != NULL) && 722 (reader->ctxt->vctxt.vstateMax > 0)){ 723 xmlFree(reader->ctxt->vctxt.vstateTab); 724 reader->ctxt->vctxt.vstateTab = 0; 725 reader->ctxt->vctxt.vstateMax = 0; 726 } 727 if (reader->allocs & XML_TEXTREADER_CTXT) 728 xmlFreeParserCtxt(reader->ctxt); 729 } 730 if (reader->sax != NULL) 731 xmlFree(reader->sax); 732 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) 733 xmlFreeParserInputBuffer(reader->input); 734 if (reader->faketext != NULL) { 735 xmlFreeNode(reader->faketext); 736 } 737 xmlFree(reader); 738} 739 740/************************************************************************ 741 * * 742 * Methods for XmlTextReader * 743 * * 744 ************************************************************************/ 745/** 746 * xmlTextReaderClose: 747 * @reader: the xmlTextReaderPtr used 748 * 749 * This method releases any resources allocated by the current instance 750 * changes the state to Closed and close any underlying input. 751 * 752 * Returns 0 or -1 in case of error 753 */ 754int 755xmlTextReaderClose(xmlTextReaderPtr reader) { 756 if (reader == NULL) 757 return(-1); 758 reader->node = NULL; 759 reader->curnode = NULL; 760 reader->mode = XML_TEXTREADER_MODE_CLOSED; 761 if (reader->ctxt != NULL) { 762 if (reader->ctxt->myDoc != NULL) { 763 xmlFreeDoc(reader->ctxt->myDoc); 764 reader->ctxt->myDoc = NULL; 765 } 766 if (reader->allocs & XML_TEXTREADER_CTXT) { 767 xmlFreeParserCtxt(reader->ctxt); 768 reader->allocs -= XML_TEXTREADER_CTXT; 769 } 770 } 771 if (reader->sax != NULL) { 772 xmlFree(reader->sax); 773 reader->sax = NULL; 774 } 775 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) { 776 xmlFreeParserInputBuffer(reader->input); 777 reader->allocs -= XML_TEXTREADER_INPUT; 778 } 779 return(0); 780} 781 782/** 783 * xmlTextReaderGetAttributeNo: 784 * @reader: the xmlTextReaderPtr used 785 * @no: the zero-based index of the attribute relative to the containing element 786 * 787 * Provides the value of the attribute with the specified index relative 788 * to the containing element. 789 * 790 * Returns a string containing the value of the specified attribute, or NULL 791 * in case of error. The string must be deallocated by the caller. 792 */ 793xmlChar * 794xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) { 795 xmlChar *ret; 796 int i; 797 xmlAttrPtr cur; 798 xmlNsPtr ns; 799 800 if (reader == NULL) 801 return(NULL); 802 if (reader->node == NULL) 803 return(NULL); 804 if (reader->curnode != NULL) 805 return(NULL); 806 /* TODO: handle the xmlDecl */ 807 if (reader->node->type != XML_ELEMENT_NODE) 808 return(NULL); 809 810 ns = reader->node->nsDef; 811 for (i = 0;(i < no) && (ns != NULL);i++) { 812 ns = ns->next; 813 } 814 if (ns != NULL) 815 return(xmlStrdup(ns->href)); 816 817 cur = reader->node->properties; 818 if (cur == NULL) 819 return(NULL); 820 for (;i < no;i++) { 821 cur = cur->next; 822 if (cur == NULL) 823 return(NULL); 824 } 825 /* TODO walk the DTD if present */ 826 827 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1); 828 if (ret == NULL) return(xmlStrdup((xmlChar *)"")); 829 return(ret); 830} 831 832/** 833 * xmlTextReaderGetAttribute: 834 * @reader: the xmlTextReaderPtr used 835 * @name: the qualified name of the attribute. 836 * 837 * Provides the value of the attribute with the specified qualified name. 838 * 839 * Returns a string containing the value of the specified attribute, or NULL 840 * in case of error. The string must be deallocated by the caller. 841 */ 842xmlChar * 843xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) { 844 xmlChar *prefix = NULL; 845 xmlChar *localname; 846 xmlNsPtr ns; 847 xmlChar *ret = NULL; 848 849 if ((reader == NULL) || (name == NULL)) 850 return(NULL); 851 if (reader->node == NULL) 852 return(NULL); 853 if (reader->curnode != NULL) 854 return(NULL); 855 856 /* TODO: handle the xmlDecl */ 857 if (reader->node->type != XML_ELEMENT_NODE) 858 return(NULL); 859 860 localname = xmlSplitQName2(name, &prefix); 861 if (localname == NULL) 862 return(xmlGetProp(reader->node, name)); 863 864 ns = xmlSearchNs(reader->node->doc, reader->node, prefix); 865 if (ns != NULL) 866 ret = xmlGetNsProp(reader->node, localname, ns->href); 867 868 if (localname != NULL) 869 xmlFree(localname); 870 if (prefix != NULL) 871 xmlFree(prefix); 872 return(ret); 873} 874 875 876/** 877 * xmlTextReaderGetAttributeNs: 878 * @reader: the xmlTextReaderPtr used 879 * @localName: the local name of the attribute. 880 * @namespaceURI: the namespace URI of the attribute. 881 * 882 * Provides the value of the specified attribute 883 * 884 * Returns a string containing the value of the specified attribute, or NULL 885 * in case of error. The string must be deallocated by the caller. 886 */ 887xmlChar * 888xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName, 889 const xmlChar *namespaceURI) { 890 if ((reader == NULL) || (localName == NULL)) 891 return(NULL); 892 if (reader->node == NULL) 893 return(NULL); 894 if (reader->curnode != NULL) 895 return(NULL); 896 897 /* TODO: handle the xmlDecl */ 898 if (reader->node->type != XML_ELEMENT_NODE) 899 return(NULL); 900 901 return(xmlGetNsProp(reader->node, localName, namespaceURI)); 902} 903 904/** 905 * xmlTextReaderGetRemainder: 906 * @reader: the xmlTextReaderPtr used 907 * 908 * Method to get the remainder of the buffered XML. this method stops the 909 * parser, set its state to End Of File and return the input stream with 910 * what is left that the parser did not use. 911 * 912 * Returns the xmlParserInputBufferPtr attached to the XML or NULL 913 * in case of error. 914 */ 915xmlParserInputBufferPtr 916xmlTextReaderGetRemainder(xmlTextReaderPtr reader) { 917 xmlParserInputBufferPtr ret = NULL; 918 919 if (reader == NULL) 920 return(NULL); 921 if (reader->node == NULL) 922 return(NULL); 923 924 reader->node = NULL; 925 reader->curnode = NULL; 926 reader->mode = XML_TEXTREADER_MODE_EOF; 927 if (reader->ctxt != NULL) { 928 if (reader->ctxt->myDoc != NULL) { 929 xmlFreeDoc(reader->ctxt->myDoc); 930 reader->ctxt->myDoc = NULL; 931 } 932 if (reader->allocs & XML_TEXTREADER_CTXT) { 933 xmlFreeParserCtxt(reader->ctxt); 934 reader->allocs -= XML_TEXTREADER_CTXT; 935 } 936 } 937 if (reader->sax != NULL) { 938 xmlFree(reader->sax); 939 reader->sax = NULL; 940 } 941 if (reader->allocs & XML_TEXTREADER_INPUT) { 942 ret = reader->input; 943 reader->allocs -= XML_TEXTREADER_INPUT; 944 } else { 945 /* 946 * Hum, one may need to duplicate the data structure because 947 * without reference counting the input may be freed twice: 948 * - by the layer which allocated it. 949 * - by the layer to which would have been returned to. 950 */ 951 TODO 952 return(NULL); 953 } 954 return(ret); 955} 956 957/** 958 * xmlTextReaderLookupNamespace: 959 * @reader: the xmlTextReaderPtr used 960 * @prefix: the prefix whose namespace URI is to be resolved. To return 961 * the default namespace, specify NULL 962 * 963 * Resolves a namespace prefix in the scope of the current element. 964 * 965 * Returns a string containing the namespace URI to which the prefix maps 966 * or NULL in case of error. The string must be deallocated by the caller. 967 */ 968xmlChar * 969xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) { 970 xmlNsPtr ns; 971 972 if (reader == NULL) 973 return(NULL); 974 if (reader->node == NULL) 975 return(NULL); 976 977 ns = xmlSearchNs(reader->node->doc, reader->node, prefix); 978 if (ns == NULL) 979 return(NULL); 980 return(xmlStrdup(ns->href)); 981} 982 983/** 984 * xmlTextReaderMoveToAttributeNo: 985 * @reader: the xmlTextReaderPtr used 986 * @no: the zero-based index of the attribute relative to the containing 987 * element. 988 * 989 * Moves the position of the current instance to the attribute with 990 * the specified index relative to the containing element. 991 * 992 * Returns 1 in case of success, -1 in case of error, 0 if not found 993 */ 994int 995xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) { 996 int i; 997 xmlAttrPtr cur; 998 xmlNsPtr ns; 999 1000 if (reader == NULL) 1001 return(-1); 1002 if (reader->node == NULL) 1003 return(-1); 1004 /* TODO: handle the xmlDecl */ 1005 if (reader->node->type != XML_ELEMENT_NODE) 1006 return(-1); 1007 1008 reader->curnode = NULL; 1009 1010 ns = reader->node->nsDef; 1011 for (i = 0;(i < no) && (ns != NULL);i++) { 1012 ns = ns->next; 1013 } 1014 if (ns != NULL) { 1015 reader->curnode = (xmlNodePtr) ns; 1016 return(1); 1017 } 1018 1019 cur = reader->node->properties; 1020 if (cur == NULL) 1021 return(0); 1022 for (;i < no;i++) { 1023 cur = cur->next; 1024 if (cur == NULL) 1025 return(0); 1026 } 1027 /* TODO walk the DTD if present */ 1028 1029 reader->curnode = (xmlNodePtr) cur; 1030 return(1); 1031} 1032 1033/** 1034 * xmlTextReaderMoveToAttribute: 1035 * @reader: the xmlTextReaderPtr used 1036 * @name: the qualified name of the attribute. 1037 * 1038 * Moves the position of the current instance to the attribute with 1039 * the specified qualified name. 1040 * 1041 * Returns 1 in case of success, -1 in case of error, 0 if not found 1042 */ 1043int 1044xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) { 1045 xmlChar *prefix = NULL; 1046 xmlChar *localname; 1047 xmlNsPtr ns; 1048 xmlAttrPtr prop; 1049 1050 if ((reader == NULL) || (name == NULL)) 1051 return(-1); 1052 if (reader->node == NULL) 1053 return(-1); 1054 1055 /* TODO: handle the xmlDecl */ 1056 if (reader->node->type != XML_ELEMENT_NODE) 1057 return(0); 1058 1059 localname = xmlSplitQName2(name, &prefix); 1060 if (localname == NULL) { 1061 /* 1062 * Namespace default decl 1063 */ 1064 if (xmlStrEqual(name, BAD_CAST "xmlns")) { 1065 ns = reader->node->nsDef; 1066 while (ns != NULL) { 1067 if (ns->prefix == NULL) { 1068 reader->curnode = (xmlNodePtr) ns; 1069 return(1); 1070 } 1071 ns = ns->next; 1072 } 1073 return(0); 1074 } 1075 1076 prop = reader->node->properties; 1077 while (prop != NULL) { 1078 /* 1079 * One need to have 1080 * - same attribute names 1081 * - and the attribute carrying that namespace 1082 */ 1083 if ((xmlStrEqual(prop->name, name)) && 1084 ((prop->ns == NULL) || (prop->ns->prefix == NULL))) { 1085 reader->curnode = (xmlNodePtr) prop; 1086 return(1); 1087 } 1088 prop = prop->next; 1089 } 1090 return(0); 1091 } 1092 1093 /* 1094 * Namespace default decl 1095 */ 1096 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { 1097 ns = reader->node->nsDef; 1098 while (ns != NULL) { 1099 if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) { 1100 reader->curnode = (xmlNodePtr) ns; 1101 goto found; 1102 } 1103 ns = ns->next; 1104 } 1105 goto not_found; 1106 } 1107 prop = reader->node->properties; 1108 while (prop != NULL) { 1109 /* 1110 * One need to have 1111 * - same attribute names 1112 * - and the attribute carrying that namespace 1113 */ 1114 if ((xmlStrEqual(prop->name, localname)) && 1115 (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) { 1116 reader->curnode = (xmlNodePtr) prop; 1117 goto found; 1118 } 1119 prop = prop->next; 1120 } 1121not_found: 1122 if (localname != NULL) 1123 xmlFree(localname); 1124 if (prefix != NULL) 1125 xmlFree(prefix); 1126 return(0); 1127 1128found: 1129 if (localname != NULL) 1130 xmlFree(localname); 1131 if (prefix != NULL) 1132 xmlFree(prefix); 1133 return(1); 1134} 1135 1136/** 1137 * xmlTextReaderMoveToAttributeNs: 1138 * @reader: the xmlTextReaderPtr used 1139 * @localName: the local name of the attribute. 1140 * @namespaceURI: the namespace URI of the attribute. 1141 * 1142 * Moves the position of the current instance to the attribute with the 1143 * specified local name and namespace URI. 1144 * 1145 * Returns 1 in case of success, -1 in case of error, 0 if not found 1146 */ 1147int 1148xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader, 1149 const xmlChar *localName, const xmlChar *namespaceURI) { 1150 xmlAttrPtr prop; 1151 xmlNodePtr node; 1152 1153 if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL)) 1154 return(-1); 1155 if (reader->node == NULL) 1156 return(-1); 1157 if (reader->node->type != XML_ELEMENT_NODE) 1158 return(0); 1159 node = reader->node; 1160 1161 /* 1162 * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no 1163 * namespace name associated to "xmlns" 1164 */ 1165 prop = node->properties; 1166 while (prop != NULL) { 1167 /* 1168 * One need to have 1169 * - same attribute names 1170 * - and the attribute carrying that namespace 1171 */ 1172 if (xmlStrEqual(prop->name, localName) && 1173 ((prop->ns != NULL) && 1174 (xmlStrEqual(prop->ns->href, namespaceURI)))) { 1175 reader->curnode = (xmlNodePtr) prop; 1176 return(1); 1177 } 1178 prop = prop->next; 1179 } 1180 return(0); 1181} 1182 1183/** 1184 * xmlTextReaderMoveToFirstAttribute: 1185 * @reader: the xmlTextReaderPtr used 1186 * 1187 * Moves the position of the current instance to the first attribute 1188 * associated with the current node. 1189 * 1190 * Returns 1 in case of success, -1 in case of error, 0 if not found 1191 */ 1192int 1193xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) { 1194 if (reader == NULL) 1195 return(-1); 1196 if (reader->node == NULL) 1197 return(-1); 1198 if (reader->node->type != XML_ELEMENT_NODE) 1199 return(0); 1200 1201 if (reader->node->nsDef != NULL) { 1202 reader->curnode = (xmlNodePtr) reader->node->nsDef; 1203 return(1); 1204 } 1205 if (reader->node->properties != NULL) { 1206 reader->curnode = (xmlNodePtr) reader->node->properties; 1207 return(1); 1208 } 1209 return(0); 1210} 1211 1212/** 1213 * xmlTextReaderMoveToNextAttribute: 1214 * @reader: the xmlTextReaderPtr used 1215 * 1216 * Moves the position of the current instance to the next attribute 1217 * associated with the current node. 1218 * 1219 * Returns 1 in case of success, -1 in case of error, 0 if not found 1220 */ 1221int 1222xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) { 1223 if (reader == NULL) 1224 return(-1); 1225 if (reader->node == NULL) 1226 return(-1); 1227 if (reader->node->type != XML_ELEMENT_NODE) 1228 return(0); 1229 if (reader->curnode == NULL) 1230 return(xmlTextReaderMoveToFirstAttribute(reader)); 1231 1232 if (reader->curnode->type == XML_NAMESPACE_DECL) { 1233 xmlNsPtr ns = (xmlNsPtr) reader->curnode; 1234 if (ns->next != NULL) { 1235 reader->curnode = (xmlNodePtr) ns->next; 1236 return(1); 1237 } 1238 if (reader->node->properties != NULL) { 1239 reader->curnode = (xmlNodePtr) reader->node->properties; 1240 return(1); 1241 } 1242 return(0); 1243 } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) && 1244 (reader->curnode->next != NULL)) { 1245 reader->curnode = reader->curnode->next; 1246 return(1); 1247 } 1248 return(0); 1249} 1250 1251/** 1252 * xmlTextReaderMoveToElement: 1253 * @reader: the xmlTextReaderPtr used 1254 * 1255 * Moves the position of the current instance to the node that 1256 * contains the current Attribute node. 1257 * 1258 * Returns 1 in case of success, -1 in case of error, 0 if not moved 1259 */ 1260int 1261xmlTextReaderMoveToElement(xmlTextReaderPtr reader) { 1262 if (reader == NULL) 1263 return(-1); 1264 if (reader->node == NULL) 1265 return(-1); 1266 if (reader->node->type != XML_ELEMENT_NODE) 1267 return(0); 1268 if (reader->curnode != NULL) { 1269 reader->curnode = NULL; 1270 return(1); 1271 } 1272 return(0); 1273} 1274 1275/** 1276 * xmlTextReaderReadAttributeValue: 1277 * @reader: the xmlTextReaderPtr used 1278 * 1279 * Parses an attribute value into one or more Text and EntityReference nodes. 1280 * 1281 * Returns 1 in case of success, 0 if the reader was not positionned on an 1282 * ttribute node or all the attribute values have been read, or -1 1283 * in case of error. 1284 */ 1285int 1286xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) { 1287 if (reader == NULL) 1288 return(-1); 1289 if (reader->node == NULL) 1290 return(-1); 1291 if (reader->curnode == NULL) 1292 return(0); 1293 if (reader->curnode->type == XML_ATTRIBUTE_NODE) { 1294 if (reader->curnode->children == NULL) 1295 return(0); 1296 reader->curnode = reader->curnode->children; 1297 } else if (reader->curnode->type == XML_NAMESPACE_DECL) { 1298 xmlNsPtr ns = (xmlNsPtr) reader->curnode; 1299 1300 if (reader->faketext == NULL) { 1301 reader->faketext = xmlNewDocText(reader->node->doc, 1302 ns->href); 1303 } else { 1304 if (reader->faketext->content != NULL) 1305 xmlFree(reader->faketext->content); 1306 reader->faketext->content = xmlStrdup(ns->href); 1307 } 1308 reader->curnode = reader->faketext; 1309 } else { 1310 if (reader->curnode->next == NULL) 1311 return(0); 1312 reader->curnode = reader->curnode->next; 1313 } 1314 return(1); 1315} 1316 1317/************************************************************************ 1318 * * 1319 * Acces API to the current node * 1320 * * 1321 ************************************************************************/ 1322/** 1323 * xmlTextReaderAttributeCount: 1324 * @reader: the xmlTextReaderPtr used 1325 * 1326 * Provides the number of attributes of the current node 1327 * 1328 * Returns 0 i no attributes, -1 in case of error or the attribute count 1329 */ 1330int 1331xmlTextReaderAttributeCount(xmlTextReaderPtr reader) { 1332 int ret; 1333 xmlAttrPtr attr; 1334 xmlNsPtr ns; 1335 xmlNodePtr node; 1336 1337 if (reader == NULL) 1338 return(-1); 1339 if (reader->node == NULL) 1340 return(0); 1341 1342 if (reader->curnode != NULL) 1343 node = reader->curnode; 1344 else 1345 node = reader->node; 1346 1347 if (node->type != XML_ELEMENT_NODE) 1348 return(0); 1349 if ((reader->state == XML_TEXTREADER_END) || 1350 (reader->state == XML_TEXTREADER_BACKTRACK)) 1351 return(0); 1352 ret = 0; 1353 attr = node->properties; 1354 while (attr != NULL) { 1355 ret++; 1356 attr = attr->next; 1357 } 1358 ns = node->nsDef; 1359 while (ns != NULL) { 1360 ret++; 1361 ns = ns->next; 1362 } 1363 return(ret); 1364} 1365 1366/** 1367 * xmlTextReaderNodeType: 1368 * @reader: the xmlTextReaderPtr used 1369 * 1370 * Get the node type of the current node 1371 * Reference: 1372 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html 1373 * 1374 * Returns the xmlNodeType of the current node or -1 in case of error 1375 */ 1376int 1377xmlTextReaderNodeType(xmlTextReaderPtr reader) { 1378 xmlNodePtr node; 1379 if (reader == NULL) 1380 return(-1); 1381 if (reader->node == NULL) 1382 return(0); 1383 if (reader->curnode != NULL) 1384 node = reader->curnode; 1385 else 1386 node = reader->node; 1387 switch (node->type) { 1388 case XML_ELEMENT_NODE: 1389 if ((reader->state == XML_TEXTREADER_END) || 1390 (reader->state == XML_TEXTREADER_BACKTRACK)) 1391 return(15); 1392 return(1); 1393 case XML_NAMESPACE_DECL: 1394 case XML_ATTRIBUTE_NODE: 1395 return(2); 1396 case XML_TEXT_NODE: 1397 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */ 1398 case XML_CDATA_SECTION_NODE: 1399 return(4); 1400 case XML_ENTITY_REF_NODE: 1401 return(5); 1402 case XML_ENTITY_NODE: 1403 return(6); 1404 case XML_PI_NODE: 1405 return(7); 1406 case XML_COMMENT_NODE: 1407 return(8); 1408 case XML_DOCUMENT_NODE: 1409 case XML_HTML_DOCUMENT_NODE: 1410#ifdef LIBXML_DOCB_ENABLED 1411 case XML_DOCB_DOCUMENT_NODE: 1412#endif 1413 return(9); 1414 case XML_DOCUMENT_FRAG_NODE: 1415 return(11); 1416 case XML_NOTATION_NODE: 1417 return(12); 1418 case XML_DOCUMENT_TYPE_NODE: 1419 case XML_DTD_NODE: 1420 return(10); 1421 1422 case XML_ELEMENT_DECL: 1423 case XML_ATTRIBUTE_DECL: 1424 case XML_ENTITY_DECL: 1425 case XML_XINCLUDE_START: 1426 case XML_XINCLUDE_END: 1427 return(0); 1428 } 1429 return(-1); 1430} 1431 1432/** 1433 * xmlTextReaderIsEmptyElement: 1434 * @reader: the xmlTextReaderPtr used 1435 * 1436 * Check if the current node is empty 1437 * 1438 * Returns 1 if empty, 0 if not and -1 in case of error 1439 */ 1440int 1441xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) { 1442 if ((reader == NULL) || (reader->node == NULL)) 1443 return(-1); 1444 if (reader->node->type != XML_ELEMENT_NODE) 1445 return(0); 1446 if (reader->node->children != NULL) 1447 return(0); 1448 if (reader->node != reader->ctxt->node) 1449 return(1); 1450 if ((reader->ctxt->node != NULL) && 1451 (reader->node == reader->ctxt->node->last) && 1452 (reader->wasempty == 1)) 1453 return(1); 1454 return(0); 1455} 1456 1457/** 1458 * xmlTextReaderLocalName: 1459 * @reader: the xmlTextReaderPtr used 1460 * 1461 * The local name of the node. 1462 * 1463 * Returns the local name or NULL if not available 1464 */ 1465xmlChar * 1466xmlTextReaderLocalName(xmlTextReaderPtr reader) { 1467 xmlNodePtr node; 1468 if ((reader == NULL) || (reader->node == NULL)) 1469 return(NULL); 1470 if (reader->curnode != NULL) 1471 node = reader->curnode; 1472 else 1473 node = reader->node; 1474 if (node->type == XML_NAMESPACE_DECL) { 1475 xmlNsPtr ns = (xmlNsPtr) node; 1476 if (ns->prefix == NULL) 1477 return(xmlStrdup(BAD_CAST "xmlns")); 1478 else 1479 return(xmlStrdup(ns->prefix)); 1480 } 1481 if ((node->type != XML_ELEMENT_NODE) && 1482 (node->type != XML_ATTRIBUTE_NODE)) 1483 return(xmlTextReaderName(reader)); 1484 return(xmlStrdup(node->name)); 1485} 1486 1487/** 1488 * xmlTextReaderName: 1489 * @reader: the xmlTextReaderPtr used 1490 * 1491 * The qualified name of the node, equal to Prefix :LocalName. 1492 * 1493 * Returns the local name or NULL if not available 1494 */ 1495xmlChar * 1496xmlTextReaderName(xmlTextReaderPtr reader) { 1497 xmlNodePtr node; 1498 xmlChar *ret; 1499 1500 if ((reader == NULL) || (reader->node == NULL)) 1501 return(NULL); 1502 if (reader->curnode != NULL) 1503 node = reader->curnode; 1504 else 1505 node = reader->node; 1506 switch (node->type) { 1507 case XML_ELEMENT_NODE: 1508 case XML_ATTRIBUTE_NODE: 1509 if ((node->ns == NULL) || 1510 (node->ns->prefix == NULL)) 1511 return(xmlStrdup(node->name)); 1512 1513 ret = xmlStrdup(node->ns->prefix); 1514 ret = xmlStrcat(ret, BAD_CAST ":"); 1515 ret = xmlStrcat(ret, node->name); 1516 return(ret); 1517 case XML_TEXT_NODE: 1518 return(xmlStrdup(BAD_CAST "#text")); 1519 case XML_CDATA_SECTION_NODE: 1520 return(xmlStrdup(BAD_CAST "#cdata-section")); 1521 case XML_ENTITY_NODE: 1522 case XML_ENTITY_REF_NODE: 1523 return(xmlStrdup(node->name)); 1524 case XML_PI_NODE: 1525 return(xmlStrdup(node->name)); 1526 case XML_COMMENT_NODE: 1527 return(xmlStrdup(BAD_CAST "#comment")); 1528 case XML_DOCUMENT_NODE: 1529 case XML_HTML_DOCUMENT_NODE: 1530#ifdef LIBXML_DOCB_ENABLED 1531 case XML_DOCB_DOCUMENT_NODE: 1532#endif 1533 return(xmlStrdup(BAD_CAST "#document")); 1534 case XML_DOCUMENT_FRAG_NODE: 1535 return(xmlStrdup(BAD_CAST "#document-fragment")); 1536 case XML_NOTATION_NODE: 1537 return(xmlStrdup(node->name)); 1538 case XML_DOCUMENT_TYPE_NODE: 1539 case XML_DTD_NODE: 1540 return(xmlStrdup(node->name)); 1541 case XML_NAMESPACE_DECL: { 1542 xmlNsPtr ns = (xmlNsPtr) node; 1543 1544 ret = xmlStrdup(BAD_CAST "xmlns"); 1545 if (ns->prefix == NULL) 1546 return(ret); 1547 ret = xmlStrcat(ret, BAD_CAST ":"); 1548 ret = xmlStrcat(ret, ns->prefix); 1549 return(ret); 1550 } 1551 1552 case XML_ELEMENT_DECL: 1553 case XML_ATTRIBUTE_DECL: 1554 case XML_ENTITY_DECL: 1555 case XML_XINCLUDE_START: 1556 case XML_XINCLUDE_END: 1557 return(NULL); 1558 } 1559 return(NULL); 1560} 1561 1562/** 1563 * xmlTextReaderPrefix: 1564 * @reader: the xmlTextReaderPtr used 1565 * 1566 * A shorthand reference to the namespace associated with the node. 1567 * 1568 * Returns the prefix or NULL if not available 1569 */ 1570xmlChar * 1571xmlTextReaderPrefix(xmlTextReaderPtr reader) { 1572 xmlNodePtr node; 1573 if ((reader == NULL) || (reader->node == NULL)) 1574 return(NULL); 1575 if (reader->curnode != NULL) 1576 node = reader->curnode; 1577 else 1578 node = reader->node; 1579 if (node->type == XML_NAMESPACE_DECL) { 1580 xmlNsPtr ns = (xmlNsPtr) node; 1581 if (ns->prefix == NULL) 1582 return(NULL); 1583 return(xmlStrdup(BAD_CAST "xmlns")); 1584 } 1585 if ((node->type != XML_ELEMENT_NODE) && 1586 (node->type != XML_ATTRIBUTE_NODE)) 1587 return(NULL); 1588 if ((node->ns != NULL) || (node->ns->prefix != NULL)) 1589 return(xmlStrdup(node->ns->prefix)); 1590 return(NULL); 1591} 1592 1593/** 1594 * xmlTextReaderNamespaceUri: 1595 * @reader: the xmlTextReaderPtr used 1596 * 1597 * The URI defining the namespace associated with the node. 1598 * 1599 * Returns the namespace URI or NULL if not available 1600 */ 1601xmlChar * 1602xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) { 1603 xmlNodePtr node; 1604 if ((reader == NULL) || (reader->node == NULL)) 1605 return(NULL); 1606 if (reader->curnode != NULL) 1607 node = reader->curnode; 1608 else 1609 node = reader->node; 1610 if (node->type == XML_NAMESPACE_DECL) 1611 return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/")); 1612 if ((node->type != XML_ELEMENT_NODE) && 1613 (node->type != XML_ATTRIBUTE_NODE)) 1614 return(NULL); 1615 if (node->ns != NULL) 1616 return(xmlStrdup(node->ns->href)); 1617 return(NULL); 1618} 1619 1620/** 1621 * xmlTextReaderBaseUri: 1622 * @reader: the xmlTextReaderPtr used 1623 * 1624 * The base URI of the node. 1625 * 1626 * Returns the base URI or NULL if not available 1627 */ 1628xmlChar * 1629xmlTextReaderBaseUri(xmlTextReaderPtr reader) { 1630 if ((reader == NULL) || (reader->node == NULL)) 1631 return(NULL); 1632 return(xmlNodeGetBase(NULL, reader->node)); 1633} 1634 1635/** 1636 * xmlTextReaderDepth: 1637 * @reader: the xmlTextReaderPtr used 1638 * 1639 * The depth of the node in the tree. 1640 * 1641 * Returns the depth or -1 in case of error 1642 */ 1643int 1644xmlTextReaderDepth(xmlTextReaderPtr reader) { 1645 if (reader == NULL) 1646 return(-1); 1647 if (reader->node == NULL) 1648 return(0); 1649 1650 if (reader->curnode != NULL) { 1651 if ((reader->curnode->type == XML_ATTRIBUTE_NODE) || 1652 (reader->curnode->type == XML_NAMESPACE_DECL)) 1653 return(reader->depth + 1); 1654 return(reader->depth + 2); 1655 } 1656 return(reader->depth); 1657} 1658 1659/** 1660 * xmlTextReaderHasAttributes: 1661 * @reader: the xmlTextReaderPtr used 1662 * 1663 * Whether the node has attributes. 1664 * 1665 * Returns 1 if true, 0 if false, and -1 in case or error 1666 */ 1667int 1668xmlTextReaderHasAttributes(xmlTextReaderPtr reader) { 1669 xmlNodePtr node; 1670 if (reader == NULL) 1671 return(-1); 1672 if (reader->node == NULL) 1673 return(0); 1674 if (reader->curnode != NULL) 1675 node = reader->curnode; 1676 else 1677 node = reader->node; 1678 1679 if ((node->type == XML_ELEMENT_NODE) && 1680 (node->properties != NULL)) 1681 return(1); 1682 /* TODO: handle the xmlDecl */ 1683 return(0); 1684} 1685 1686/** 1687 * xmlTextReaderHasValue: 1688 * @reader: the xmlTextReaderPtr used 1689 * 1690 * Whether the node can have a text value. 1691 * 1692 * Returns 1 if true, 0 if false, and -1 in case or error 1693 */ 1694int 1695xmlTextReaderHasValue(xmlTextReaderPtr reader) { 1696 xmlNodePtr node; 1697 if (reader == NULL) 1698 return(-1); 1699 if (reader->node == NULL) 1700 return(0); 1701 if (reader->curnode != NULL) 1702 node = reader->curnode; 1703 else 1704 node = reader->node; 1705 1706 switch (node->type) { 1707 case XML_ATTRIBUTE_NODE: 1708 case XML_TEXT_NODE: 1709 case XML_CDATA_SECTION_NODE: 1710 case XML_PI_NODE: 1711 case XML_COMMENT_NODE: 1712 return(1); 1713 default: 1714 return(0); 1715 } 1716 return(0); 1717} 1718 1719/** 1720 * xmlTextReaderValue: 1721 * @reader: the xmlTextReaderPtr used 1722 * 1723 * Provides the text value of the node if present 1724 * 1725 * Returns the string or NULL if not available. The retsult must be deallocated 1726 * with xmlFree() 1727 */ 1728xmlChar * 1729xmlTextReaderValue(xmlTextReaderPtr reader) { 1730 xmlNodePtr node; 1731 if (reader == NULL) 1732 return(NULL); 1733 if (reader->node == NULL) 1734 return(NULL); 1735 if (reader->curnode != NULL) 1736 node = reader->curnode; 1737 else 1738 node = reader->node; 1739 1740 switch (node->type) { 1741 case XML_NAMESPACE_DECL: 1742 return(xmlStrdup(((xmlNsPtr) node)->href)); 1743 case XML_ATTRIBUTE_NODE:{ 1744 xmlAttrPtr attr = (xmlAttrPtr) node; 1745 1746 if (attr->parent != NULL) 1747 return (xmlNodeListGetString 1748 (attr->parent->doc, attr->children, 1)); 1749 else 1750 return (xmlNodeListGetString(NULL, attr->children, 1)); 1751 break; 1752 } 1753 case XML_TEXT_NODE: 1754 case XML_CDATA_SECTION_NODE: 1755 case XML_PI_NODE: 1756 case XML_COMMENT_NODE: 1757 if (node->content != NULL) 1758 return (xmlStrdup(node->content)); 1759 default: 1760 return(NULL); 1761 } 1762 return(NULL); 1763} 1764 1765/** 1766 * xmlTextReaderIsDefault: 1767 * @reader: the xmlTextReaderPtr used 1768 * 1769 * Whether an Attribute node was generated from the default value 1770 * defined in the DTD or schema. 1771 * 1772 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error 1773 */ 1774int 1775xmlTextReaderIsDefault(xmlTextReaderPtr reader) { 1776 if (reader == NULL) 1777 return(-1); 1778 return(0); 1779} 1780 1781/** 1782 * xmlTextReaderQuoteChar: 1783 * @reader: the xmlTextReaderPtr used 1784 * 1785 * The quotation mark character used to enclose the value of an attribute. 1786 * 1787 * Returns " or ' and -1 in case of error 1788 */ 1789int 1790xmlTextReaderQuoteChar(xmlTextReaderPtr reader) { 1791 if (reader == NULL) 1792 return(-1); 1793 /* TODO maybe lookup the attribute value for " first */ 1794 return((int) '"'); 1795} 1796 1797/** 1798 * xmlTextReaderXmlLang: 1799 * @reader: the xmlTextReaderPtr used 1800 * 1801 * The xml:lang scope within which the node resides. 1802 * 1803 * Returns the xml:lang value or NULL if none exists. 1804 */ 1805xmlChar * 1806xmlTextReaderXmlLang(xmlTextReaderPtr reader) { 1807 if (reader == NULL) 1808 return(NULL); 1809 if (reader->node == NULL) 1810 return(NULL); 1811 return(xmlNodeGetLang(reader->node)); 1812} 1813 1814/** 1815 * xmlTextReaderNormalization: 1816 * @reader: the xmlTextReaderPtr used 1817 * 1818 * The value indicating whether to normalize white space and attribute values. 1819 * Since attribute value and end of line normalizations are a MUST in the XML 1820 * specification only the value true is accepted. The broken bahaviour of 1821 * accepting out of range character entities like � is of course not 1822 * supported either. 1823 * 1824 * Returns 1 or -1 in case of error. 1825 */ 1826int 1827xmlTextReaderNormalization(xmlTextReaderPtr reader) { 1828 if (reader == NULL) 1829 return(-1); 1830 return(1); 1831} 1832 1833/************************************************************************ 1834 * * 1835 * Extensions to the base APIs * 1836 * * 1837 ************************************************************************/ 1838 1839/** 1840 * xmlTextReaderSetParserProp: 1841 * @reader: the xmlTextReaderPtr used 1842 * @prop: the xmlParserProperties to set 1843 * @value: usually 0 or 1 to (de)activate it 1844 * 1845 * Change the parser processing behaviour by changing some of its internal 1846 * properties. Note that some properties can only be changed before any 1847 * read has been done. 1848 * 1849 * Returns 0 if the call was successful, or -1 in case of error 1850 */ 1851int 1852xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) { 1853 xmlParserProperties p = (xmlParserProperties) prop; 1854 xmlParserCtxtPtr ctxt; 1855 1856 if ((reader == NULL) || (reader->ctxt == NULL)) 1857 return(-1); 1858 ctxt = reader->ctxt; 1859 1860 switch (p) { 1861 case XML_PARSER_LOADDTD: 1862 if (value != 0) { 1863 if (ctxt->loadsubset == 0) { 1864 if (reader->mode != XML_TEXTREADER_MODE_INITIAL) 1865 return(-1); 1866 ctxt->loadsubset = XML_DETECT_IDS; 1867 } 1868 } else { 1869 ctxt->loadsubset = 0; 1870 } 1871 return(0); 1872 case XML_PARSER_DEFAULTATTRS: 1873 if (value != 0) { 1874 ctxt->loadsubset |= XML_COMPLETE_ATTRS; 1875 } else { 1876 if (ctxt->loadsubset & XML_COMPLETE_ATTRS) 1877 ctxt->loadsubset -= XML_COMPLETE_ATTRS; 1878 } 1879 return(0); 1880 case XML_PARSER_VALIDATE: 1881 if (value != 0) { 1882 ctxt->validate = 1; 1883 } else { 1884 ctxt->validate = 0; 1885 } 1886 return(0); 1887 case XML_PARSER_SUBST_ENTITIES: 1888 if (value != 0) { 1889 ctxt->replaceEntities = 1; 1890 } else { 1891 ctxt->replaceEntities = 0; 1892 } 1893 return(0); 1894 } 1895 return(-1); 1896} 1897 1898/** 1899 * xmlTextReaderGetParserProp: 1900 * @reader: the xmlTextReaderPtr used 1901 * @prop: the xmlParserProperties to get 1902 * 1903 * Read the parser internal property. 1904 * 1905 * Returns the value, usually 0 or 1, or -1 in case of error. 1906 */ 1907int 1908xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) { 1909 xmlParserProperties p = (xmlParserProperties) prop; 1910 xmlParserCtxtPtr ctxt; 1911 1912 if ((reader == NULL) || (reader->ctxt == NULL)) 1913 return(-1); 1914 ctxt = reader->ctxt; 1915 1916 switch (p) { 1917 case XML_PARSER_LOADDTD: 1918 if ((ctxt->loadsubset != 0) || (ctxt->validate != 0)) 1919 return(1); 1920 return(0); 1921 case XML_PARSER_DEFAULTATTRS: 1922 if (ctxt->loadsubset & XML_COMPLETE_ATTRS) 1923 return(1); 1924 return(0); 1925 case XML_PARSER_VALIDATE: 1926 return(ctxt->validate); 1927 case XML_PARSER_SUBST_ENTITIES: 1928 return(ctxt->replaceEntities); 1929 } 1930 return(-1); 1931} 1932 1933/** 1934 * xmlTextReaderCurrentNode: 1935 * @reader: the xmlTextReaderPtr used 1936 * 1937 * Hacking interface allowing to get the xmlNodePtr correponding to the 1938 * current node being accessed by the xmlTextReader. This is dangerous 1939 * because the underlying node may be destroyed on the next Reads. 1940 * 1941 * Returns the xmlNodePtr or NULL in case of error. 1942 */ 1943xmlNodePtr 1944xmlTextReaderCurrentNode(xmlTextReaderPtr reader) { 1945 if (reader == NULL) 1946 return(NULL); 1947 1948 if (reader->curnode != NULL) 1949 return(reader->curnode); 1950 return(reader->node); 1951} 1952 1953/** 1954 * xmlTextReaderCurrentDoc: 1955 * @reader: the xmlTextReaderPtr used 1956 * 1957 * Hacking interface allowing to get the xmlDocPtr correponding to the 1958 * current document being accessed by the xmlTextReader. This is dangerous 1959 * because the associated node may be destroyed on the next Reads. 1960 * 1961 * Returns the xmlDocPtr or NULL in case of error. 1962 */ 1963xmlDocPtr 1964xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) { 1965 if ((reader == NULL) || (reader->ctxt == NULL)) 1966 return(NULL); 1967 1968 return(reader->ctxt->myDoc); 1969} 1970 1971/************************************************************************ 1972 * * 1973 * Utilities * 1974 * * 1975 ************************************************************************/ 1976/** 1977 * xmlBase64Decode: 1978 * @in: the input buffer 1979 * @inlen: the size of the input (in), the size read from it (out) 1980 * @to: the output buffer 1981 * @tolen: the size of the output (in), the size written to (out) 1982 * 1983 * Base64 decoder, reads from @in and save in @to 1984 * 1985 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached, 1986 * 2 if there wasn't enough space on the output or -1 in case of error. 1987 */ 1988static int 1989xmlBase64Decode(const unsigned char *in, unsigned long *inlen, 1990 unsigned char *to, unsigned long *tolen) { 1991 unsigned long incur; /* current index in in[] */ 1992 unsigned long inblk; /* last block index in in[] */ 1993 unsigned long outcur; /* current index in out[] */ 1994 unsigned long inmax; /* size of in[] */ 1995 unsigned long outmax; /* size of out[] */ 1996 unsigned char cur; /* the current value read from in[] */ 1997 unsigned char intmp[3], outtmp[4]; /* temporary buffers for the convert */ 1998 int nbintmp; /* number of byte in intmp[] */ 1999 int is_ignore; /* cur should be ignored */ 2000 int is_end = 0; /* the end of the base64 was found */ 2001 int retval = 1; 2002 int i; 2003 2004 if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL)) 2005 return(-1); 2006 2007 incur = 0; 2008 inblk = 0; 2009 outcur = 0; 2010 inmax = *inlen; 2011 outmax = *tolen; 2012 nbintmp = 0; 2013 2014 while (1) { 2015 if (incur >= inmax) 2016 break; 2017 cur = in[incur++]; 2018 is_ignore = 0; 2019 if ((cur >= 'A') && (cur <= 'Z')) 2020 cur = cur - 'A'; 2021 else if ((cur >= 'a') && (cur <= 'z')) 2022 cur = cur - 'a' + 26; 2023 else if ((cur >= '0') && (cur <= '9')) 2024 cur = cur - '0' + 52; 2025 else if (cur == '+') 2026 cur = 62; 2027 else if (cur == '/') 2028 cur = 63; 2029 else if (cur == '.') 2030 cur = 0; 2031 else if (cur == '=') /*no op , end of the base64 stream */ 2032 is_end = 1; 2033 else { 2034 is_ignore = 1; 2035 if (nbintmp == 0) 2036 inblk = incur; 2037 } 2038 2039 if (!is_ignore) { 2040 int nbouttmp = 3; 2041 int is_break = 0; 2042 2043 if (is_end) { 2044 if (nbintmp == 0) 2045 break; 2046 if ((nbintmp == 1) || (nbintmp == 2)) 2047 nbouttmp = 1; 2048 else 2049 nbouttmp = 2; 2050 nbintmp = 3; 2051 is_break = 1; 2052 } 2053 intmp[nbintmp++] = cur; 2054 /* 2055 * if intmp is full, push the 4byte sequence as a 3 byte 2056 * sequence out 2057 */ 2058 if (nbintmp == 4) { 2059 nbintmp = 0; 2060 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4); 2061 outtmp[1] = 2062 ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2); 2063 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F); 2064 if (outcur + 3 >= outmax) { 2065 retval = 2; 2066 break; 2067 } 2068 2069 for (i = 0; i < nbouttmp; i++) 2070 to[outcur++] = outtmp[i]; 2071 inblk = incur; 2072 } 2073 2074 if (is_break) { 2075 retval = 0; 2076 break; 2077 } 2078 } 2079 } 2080 2081 *tolen = outcur; 2082 *inlen = inblk; 2083 return (retval); 2084} 2085 2086/* 2087 * Test routine for the xmlBase64Decode function 2088 */ 2089#if 0 2090int main(int argc, char **argv) { 2091 char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== "; 2092 char output[100]; 2093 char output2[100]; 2094 char output3[100]; 2095 unsigned long inlen = strlen(input); 2096 unsigned long outlen = 100; 2097 int ret; 2098 unsigned long cons, tmp, tmp2, prod; 2099 2100 /* 2101 * Direct 2102 */ 2103 ret = xmlBase64Decode(input, &inlen, output, &outlen); 2104 2105 output[outlen] = 0; 2106 printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output); 2107 2108 /* 2109 * output chunking 2110 */ 2111 cons = 0; 2112 prod = 0; 2113 while (cons < inlen) { 2114 tmp = 5; 2115 tmp2 = inlen - cons; 2116 2117 printf("%ld %ld\n", cons, prod); 2118 ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp); 2119 cons += tmp2; 2120 prod += tmp; 2121 printf("%ld %ld\n", cons, prod); 2122 } 2123 output2[outlen] = 0; 2124 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2); 2125 2126 /* 2127 * input chunking 2128 */ 2129 cons = 0; 2130 prod = 0; 2131 while (cons < inlen) { 2132 tmp = 100 - prod; 2133 tmp2 = inlen - cons; 2134 if (tmp2 > 5) 2135 tmp2 = 5; 2136 2137 printf("%ld %ld\n", cons, prod); 2138 ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp); 2139 cons += tmp2; 2140 prod += tmp; 2141 printf("%ld %ld\n", cons, prod); 2142 } 2143 output3[outlen] = 0; 2144 printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3); 2145 return(0); 2146 2147} 2148#endif 2149