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