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