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