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