1/* 2 * tree.c : implementation of access function for an XML tree. 3 * 4 * References: 5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/ 6 * 7 * See Copyright for the status of this software. 8 * 9 * daniel@veillard.com 10 * 11 */ 12 13#define IN_LIBXML 14#include "libxml.h" 15 16#include <string.h> /* for memset() only ! */ 17 18#ifdef HAVE_CTYPE_H 19#include <ctype.h> 20#endif 21#ifdef HAVE_STDLIB_H 22#include <stdlib.h> 23#endif 24#ifdef HAVE_ZLIB_H 25#include <zlib.h> 26#endif 27 28#include <libxml/xmlmemory.h> 29#include <libxml/tree.h> 30#include <libxml/parser.h> 31#include <libxml/uri.h> 32#include <libxml/entities.h> 33#include <libxml/valid.h> 34#include <libxml/xmlerror.h> 35#include <libxml/parserInternals.h> 36#include <libxml/globals.h> 37#ifdef LIBXML_HTML_ENABLED 38#include <libxml/HTMLtree.h> 39#endif 40#ifdef LIBXML_DEBUG_ENABLED 41#include <libxml/debugXML.h> 42#endif 43 44int __xmlRegisterCallbacks = 0; 45 46/************************************************************************ 47 * * 48 * Forward declarations * 49 * * 50 ************************************************************************/ 51 52xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns); 53 54static xmlChar* xmlGetPropNodeValueInternal(xmlAttrPtr prop); 55 56/************************************************************************ 57 * * 58 * Tree memory error handler * 59 * * 60 ************************************************************************/ 61/** 62 * xmlTreeErrMemory: 63 * @extra: extra informations 64 * 65 * Handle an out of memory condition 66 */ 67static void 68xmlTreeErrMemory(const char *extra) 69{ 70 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra); 71} 72 73/** 74 * xmlTreeErr: 75 * @code: the error number 76 * @extra: extra informations 77 * 78 * Handle an out of memory condition 79 */ 80static void 81xmlTreeErr(int code, xmlNodePtr node, const char *extra) 82{ 83 const char *msg = NULL; 84 85 switch(code) { 86 case XML_TREE_INVALID_HEX: 87 msg = "invalid hexadecimal character value\n"; 88 break; 89 case XML_TREE_INVALID_DEC: 90 msg = "invalid decimal character value\n"; 91 break; 92 case XML_TREE_UNTERMINATED_ENTITY: 93 msg = "unterminated entity reference %15s\n"; 94 break; 95 case XML_TREE_NOT_UTF8: 96 msg = "string is not in UTF-8\n"; 97 break; 98 default: 99 msg = "unexpected error number\n"; 100 } 101 __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra); 102} 103 104/************************************************************************ 105 * * 106 * A few static variables and macros * 107 * * 108 ************************************************************************/ 109/* #undef xmlStringText */ 110const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 }; 111/* #undef xmlStringTextNoenc */ 112const xmlChar xmlStringTextNoenc[] = 113 { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 }; 114/* #undef xmlStringComment */ 115const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 }; 116 117static int xmlCompressMode = 0; 118static int xmlCheckDTD = 1; 119 120#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \ 121 xmlNodePtr ulccur = (n)->children; \ 122 if (ulccur == NULL) { \ 123 (n)->last = NULL; \ 124 } else { \ 125 while (ulccur->next != NULL) { \ 126 ulccur->parent = (n); \ 127 ulccur = ulccur->next; \ 128 } \ 129 ulccur->parent = (n); \ 130 (n)->last = ulccur; \ 131}} 132 133#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \ 134 (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0)) 135 136/* #define DEBUG_BUFFER */ 137/* #define DEBUG_TREE */ 138 139/************************************************************************ 140 * * 141 * Functions to move to entities.c once the * 142 * API freeze is smoothen and they can be made public. * 143 * * 144 ************************************************************************/ 145#include <libxml/hash.h> 146 147#ifdef LIBXML_TREE_ENABLED 148/** 149 * xmlGetEntityFromDtd: 150 * @dtd: A pointer to the DTD to search 151 * @name: The entity name 152 * 153 * Do an entity lookup in the DTD entity hash table and 154 * return the corresponding entity, if found. 155 * 156 * Returns A pointer to the entity structure or NULL if not found. 157 */ 158static xmlEntityPtr 159xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) { 160 xmlEntitiesTablePtr table; 161 162 if((dtd != NULL) && (dtd->entities != NULL)) { 163 table = (xmlEntitiesTablePtr) dtd->entities; 164 return((xmlEntityPtr) xmlHashLookup(table, name)); 165 /* return(xmlGetEntityFromTable(table, name)); */ 166 } 167 return(NULL); 168} 169/** 170 * xmlGetParameterEntityFromDtd: 171 * @dtd: A pointer to the DTD to search 172 * @name: The entity name 173 * 174 * Do an entity lookup in the DTD pararmeter entity hash table and 175 * return the corresponding entity, if found. 176 * 177 * Returns A pointer to the entity structure or NULL if not found. 178 */ 179static xmlEntityPtr 180xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) { 181 xmlEntitiesTablePtr table; 182 183 if ((dtd != NULL) && (dtd->pentities != NULL)) { 184 table = (xmlEntitiesTablePtr) dtd->pentities; 185 return((xmlEntityPtr) xmlHashLookup(table, name)); 186 /* return(xmlGetEntityFromTable(table, name)); */ 187 } 188 return(NULL); 189} 190#endif /* LIBXML_TREE_ENABLED */ 191 192/************************************************************************ 193 * * 194 * QName handling helper * 195 * * 196 ************************************************************************/ 197 198/** 199 * xmlBuildQName: 200 * @ncname: the Name 201 * @prefix: the prefix 202 * @memory: preallocated memory 203 * @len: preallocated memory length 204 * 205 * Builds the QName @prefix:@ncname in @memory if there is enough space 206 * and prefix is not NULL nor empty, otherwise allocate a new string. 207 * If prefix is NULL or empty it returns ncname. 208 * 209 * Returns the new string which must be freed by the caller if different from 210 * @memory and @ncname or NULL in case of error 211 */ 212xmlChar * 213xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix, 214 xmlChar *memory, int len) { 215 int lenn, lenp; 216 xmlChar *ret; 217 218 if (ncname == NULL) return(NULL); 219 if (prefix == NULL) return((xmlChar *) ncname); 220 221 lenn = strlen((char *) ncname); 222 lenp = strlen((char *) prefix); 223 224 if ((memory == NULL) || (len < lenn + lenp + 2)) { 225 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); 226 if (ret == NULL) { 227 xmlTreeErrMemory("building QName"); 228 return(NULL); 229 } 230 } else { 231 ret = memory; 232 } 233 memcpy(&ret[0], prefix, lenp); 234 ret[lenp] = ':'; 235 memcpy(&ret[lenp + 1], ncname, lenn); 236 ret[lenn + lenp + 1] = 0; 237 return(ret); 238} 239 240/** 241 * xmlSplitQName2: 242 * @name: the full QName 243 * @prefix: a xmlChar ** 244 * 245 * parse an XML qualified name string 246 * 247 * [NS 5] QName ::= (Prefix ':')? LocalPart 248 * 249 * [NS 6] Prefix ::= NCName 250 * 251 * [NS 7] LocalPart ::= NCName 252 * 253 * Returns NULL if not a QName, otherwise the local part, and prefix 254 * is updated to get the Prefix if any. 255 */ 256 257xmlChar * 258xmlSplitQName2(const xmlChar *name, xmlChar **prefix) { 259 int len = 0; 260 xmlChar *ret = NULL; 261 262 if (prefix == NULL) return(NULL); 263 *prefix = NULL; 264 if (name == NULL) return(NULL); 265 266#ifndef XML_XML_NAMESPACE 267 /* xml: prefix is not really a namespace */ 268 if ((name[0] == 'x') && (name[1] == 'm') && 269 (name[2] == 'l') && (name[3] == ':')) 270 return(NULL); 271#endif 272 273 /* nasty but valid */ 274 if (name[0] == ':') 275 return(NULL); 276 277 /* 278 * we are not trying to validate but just to cut, and yes it will 279 * work even if this is as set of UTF-8 encoded chars 280 */ 281 while ((name[len] != 0) && (name[len] != ':')) 282 len++; 283 284 if (name[len] == 0) 285 return(NULL); 286 287 *prefix = xmlStrndup(name, len); 288 if (*prefix == NULL) { 289 xmlTreeErrMemory("QName split"); 290 return(NULL); 291 } 292 ret = xmlStrdup(&name[len + 1]); 293 if (ret == NULL) { 294 xmlTreeErrMemory("QName split"); 295 if (*prefix != NULL) { 296 xmlFree(*prefix); 297 *prefix = NULL; 298 } 299 return(NULL); 300 } 301 302 return(ret); 303} 304 305/** 306 * xmlSplitQName3: 307 * @name: the full QName 308 * @len: an int * 309 * 310 * parse an XML qualified name string,i 311 * 312 * returns NULL if it is not a Qualified Name, otherwise, update len 313 * with the lenght in byte of the prefix and return a pointer 314 * to the start of the name without the prefix 315 */ 316 317const xmlChar * 318xmlSplitQName3(const xmlChar *name, int *len) { 319 int l = 0; 320 321 if (name == NULL) return(NULL); 322 if (len == NULL) return(NULL); 323 324 /* nasty but valid */ 325 if (name[0] == ':') 326 return(NULL); 327 328 /* 329 * we are not trying to validate but just to cut, and yes it will 330 * work even if this is as set of UTF-8 encoded chars 331 */ 332 while ((name[l] != 0) && (name[l] != ':')) 333 l++; 334 335 if (name[l] == 0) 336 return(NULL); 337 338 *len = l; 339 340 return(&name[l+1]); 341} 342 343/************************************************************************ 344 * * 345 * Check Name, NCName and QName strings * 346 * * 347 ************************************************************************/ 348 349#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l) 350 351#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) 352/** 353 * xmlValidateNCName: 354 * @value: the value to check 355 * @space: allow spaces in front and end of the string 356 * 357 * Check that a value conforms to the lexical space of NCName 358 * 359 * Returns 0 if this validates, a positive error code number otherwise 360 * and -1 in case of internal or API error. 361 */ 362int 363xmlValidateNCName(const xmlChar *value, int space) { 364 const xmlChar *cur = value; 365 int c,l; 366 367 if (value == NULL) 368 return(-1); 369 370 /* 371 * First quick algorithm for ASCII range 372 */ 373 if (space) 374 while (IS_BLANK_CH(*cur)) cur++; 375 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || 376 (*cur == '_')) 377 cur++; 378 else 379 goto try_complex; 380 while (((*cur >= 'a') && (*cur <= 'z')) || 381 ((*cur >= 'A') && (*cur <= 'Z')) || 382 ((*cur >= '0') && (*cur <= '9')) || 383 (*cur == '_') || (*cur == '-') || (*cur == '.')) 384 cur++; 385 if (space) 386 while (IS_BLANK_CH(*cur)) cur++; 387 if (*cur == 0) 388 return(0); 389 390try_complex: 391 /* 392 * Second check for chars outside the ASCII range 393 */ 394 cur = value; 395 c = CUR_SCHAR(cur, l); 396 if (space) { 397 while (IS_BLANK(c)) { 398 cur += l; 399 c = CUR_SCHAR(cur, l); 400 } 401 } 402 if ((!IS_LETTER(c)) && (c != '_')) 403 return(1); 404 cur += l; 405 c = CUR_SCHAR(cur, l); 406 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || 407 (c == '-') || (c == '_') || IS_COMBINING(c) || 408 IS_EXTENDER(c)) { 409 cur += l; 410 c = CUR_SCHAR(cur, l); 411 } 412 if (space) { 413 while (IS_BLANK(c)) { 414 cur += l; 415 c = CUR_SCHAR(cur, l); 416 } 417 } 418 if (c != 0) 419 return(1); 420 421 return(0); 422} 423#endif 424 425#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 426/** 427 * xmlValidateQName: 428 * @value: the value to check 429 * @space: allow spaces in front and end of the string 430 * 431 * Check that a value conforms to the lexical space of QName 432 * 433 * Returns 0 if this validates, a positive error code number otherwise 434 * and -1 in case of internal or API error. 435 */ 436int 437xmlValidateQName(const xmlChar *value, int space) { 438 const xmlChar *cur = value; 439 int c,l; 440 441 if (value == NULL) 442 return(-1); 443 /* 444 * First quick algorithm for ASCII range 445 */ 446 if (space) 447 while (IS_BLANK_CH(*cur)) cur++; 448 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || 449 (*cur == '_')) 450 cur++; 451 else 452 goto try_complex; 453 while (((*cur >= 'a') && (*cur <= 'z')) || 454 ((*cur >= 'A') && (*cur <= 'Z')) || 455 ((*cur >= '0') && (*cur <= '9')) || 456 (*cur == '_') || (*cur == '-') || (*cur == '.')) 457 cur++; 458 if (*cur == ':') { 459 cur++; 460 if (((*cur >= 'a') && (*cur <= 'z')) || 461 ((*cur >= 'A') && (*cur <= 'Z')) || 462 (*cur == '_')) 463 cur++; 464 else 465 goto try_complex; 466 while (((*cur >= 'a') && (*cur <= 'z')) || 467 ((*cur >= 'A') && (*cur <= 'Z')) || 468 ((*cur >= '0') && (*cur <= '9')) || 469 (*cur == '_') || (*cur == '-') || (*cur == '.')) 470 cur++; 471 } 472 if (space) 473 while (IS_BLANK_CH(*cur)) cur++; 474 if (*cur == 0) 475 return(0); 476 477try_complex: 478 /* 479 * Second check for chars outside the ASCII range 480 */ 481 cur = value; 482 c = CUR_SCHAR(cur, l); 483 if (space) { 484 while (IS_BLANK(c)) { 485 cur += l; 486 c = CUR_SCHAR(cur, l); 487 } 488 } 489 if ((!IS_LETTER(c)) && (c != '_')) 490 return(1); 491 cur += l; 492 c = CUR_SCHAR(cur, l); 493 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || 494 (c == '-') || (c == '_') || IS_COMBINING(c) || 495 IS_EXTENDER(c)) { 496 cur += l; 497 c = CUR_SCHAR(cur, l); 498 } 499 if (c == ':') { 500 cur += l; 501 c = CUR_SCHAR(cur, l); 502 if ((!IS_LETTER(c)) && (c != '_')) 503 return(1); 504 cur += l; 505 c = CUR_SCHAR(cur, l); 506 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || 507 (c == '-') || (c == '_') || IS_COMBINING(c) || 508 IS_EXTENDER(c)) { 509 cur += l; 510 c = CUR_SCHAR(cur, l); 511 } 512 } 513 if (space) { 514 while (IS_BLANK(c)) { 515 cur += l; 516 c = CUR_SCHAR(cur, l); 517 } 518 } 519 if (c != 0) 520 return(1); 521 return(0); 522} 523 524/** 525 * xmlValidateName: 526 * @value: the value to check 527 * @space: allow spaces in front and end of the string 528 * 529 * Check that a value conforms to the lexical space of Name 530 * 531 * Returns 0 if this validates, a positive error code number otherwise 532 * and -1 in case of internal or API error. 533 */ 534int 535xmlValidateName(const xmlChar *value, int space) { 536 const xmlChar *cur = value; 537 int c,l; 538 539 if (value == NULL) 540 return(-1); 541 /* 542 * First quick algorithm for ASCII range 543 */ 544 if (space) 545 while (IS_BLANK_CH(*cur)) cur++; 546 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || 547 (*cur == '_') || (*cur == ':')) 548 cur++; 549 else 550 goto try_complex; 551 while (((*cur >= 'a') && (*cur <= 'z')) || 552 ((*cur >= 'A') && (*cur <= 'Z')) || 553 ((*cur >= '0') && (*cur <= '9')) || 554 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) 555 cur++; 556 if (space) 557 while (IS_BLANK_CH(*cur)) cur++; 558 if (*cur == 0) 559 return(0); 560 561try_complex: 562 /* 563 * Second check for chars outside the ASCII range 564 */ 565 cur = value; 566 c = CUR_SCHAR(cur, l); 567 if (space) { 568 while (IS_BLANK(c)) { 569 cur += l; 570 c = CUR_SCHAR(cur, l); 571 } 572 } 573 if ((!IS_LETTER(c)) && (c != '_') && (c != ':')) 574 return(1); 575 cur += l; 576 c = CUR_SCHAR(cur, l); 577 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || 578 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { 579 cur += l; 580 c = CUR_SCHAR(cur, l); 581 } 582 if (space) { 583 while (IS_BLANK(c)) { 584 cur += l; 585 c = CUR_SCHAR(cur, l); 586 } 587 } 588 if (c != 0) 589 return(1); 590 return(0); 591} 592 593/** 594 * xmlValidateNMToken: 595 * @value: the value to check 596 * @space: allow spaces in front and end of the string 597 * 598 * Check that a value conforms to the lexical space of NMToken 599 * 600 * Returns 0 if this validates, a positive error code number otherwise 601 * and -1 in case of internal or API error. 602 */ 603int 604xmlValidateNMToken(const xmlChar *value, int space) { 605 const xmlChar *cur = value; 606 int c,l; 607 608 if (value == NULL) 609 return(-1); 610 /* 611 * First quick algorithm for ASCII range 612 */ 613 if (space) 614 while (IS_BLANK_CH(*cur)) cur++; 615 if (((*cur >= 'a') && (*cur <= 'z')) || 616 ((*cur >= 'A') && (*cur <= 'Z')) || 617 ((*cur >= '0') && (*cur <= '9')) || 618 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) 619 cur++; 620 else 621 goto try_complex; 622 while (((*cur >= 'a') && (*cur <= 'z')) || 623 ((*cur >= 'A') && (*cur <= 'Z')) || 624 ((*cur >= '0') && (*cur <= '9')) || 625 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) 626 cur++; 627 if (space) 628 while (IS_BLANK_CH(*cur)) cur++; 629 if (*cur == 0) 630 return(0); 631 632try_complex: 633 /* 634 * Second check for chars outside the ASCII range 635 */ 636 cur = value; 637 c = CUR_SCHAR(cur, l); 638 if (space) { 639 while (IS_BLANK(c)) { 640 cur += l; 641 c = CUR_SCHAR(cur, l); 642 } 643 } 644 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || 645 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c))) 646 return(1); 647 cur += l; 648 c = CUR_SCHAR(cur, l); 649 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || 650 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { 651 cur += l; 652 c = CUR_SCHAR(cur, l); 653 } 654 if (space) { 655 while (IS_BLANK(c)) { 656 cur += l; 657 c = CUR_SCHAR(cur, l); 658 } 659 } 660 if (c != 0) 661 return(1); 662 return(0); 663} 664#endif /* LIBXML_TREE_ENABLED */ 665 666/************************************************************************ 667 * * 668 * Allocation and deallocation of basic structures * 669 * * 670 ************************************************************************/ 671 672/** 673 * xmlSetBufferAllocationScheme: 674 * @scheme: allocation method to use 675 * 676 * Set the buffer allocation method. Types are 677 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down 678 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, 679 * improves performance 680 */ 681void 682xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) { 683 if ((scheme == XML_BUFFER_ALLOC_EXACT) || 684 (scheme == XML_BUFFER_ALLOC_DOUBLEIT)) 685 xmlBufferAllocScheme = scheme; 686} 687 688/** 689 * xmlGetBufferAllocationScheme: 690 * 691 * Types are 692 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down 693 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, 694 * improves performance 695 * 696 * Returns the current allocation scheme 697 */ 698xmlBufferAllocationScheme 699xmlGetBufferAllocationScheme(void) { 700 return(xmlBufferAllocScheme); 701} 702 703/** 704 * xmlNewNs: 705 * @node: the element carrying the namespace 706 * @href: the URI associated 707 * @prefix: the prefix for the namespace 708 * 709 * Creation of a new Namespace. This function will refuse to create 710 * a namespace with a similar prefix than an existing one present on this 711 * node. 712 * We use href==NULL in the case of an element creation where the namespace 713 * was not defined. 714 * Returns a new namespace pointer or NULL 715 */ 716xmlNsPtr 717xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { 718 xmlNsPtr cur; 719 720 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) 721 return(NULL); 722 723 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) 724 return(NULL); 725 726 /* 727 * Allocate a new Namespace and fill the fields. 728 */ 729 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 730 if (cur == NULL) { 731 xmlTreeErrMemory("building namespace"); 732 return(NULL); 733 } 734 memset(cur, 0, sizeof(xmlNs)); 735 cur->type = XML_LOCAL_NAMESPACE; 736 737 if (href != NULL) 738 cur->href = xmlStrdup(href); 739 if (prefix != NULL) 740 cur->prefix = xmlStrdup(prefix); 741 742 /* 743 * Add it at the end to preserve parsing order ... 744 * and checks for existing use of the prefix 745 */ 746 if (node != NULL) { 747 if (node->nsDef == NULL) { 748 node->nsDef = cur; 749 } else { 750 xmlNsPtr prev = node->nsDef; 751 752 if (((prev->prefix == NULL) && (cur->prefix == NULL)) || 753 (xmlStrEqual(prev->prefix, cur->prefix))) { 754 xmlFreeNs(cur); 755 return(NULL); 756 } 757 while (prev->next != NULL) { 758 prev = prev->next; 759 if (((prev->prefix == NULL) && (cur->prefix == NULL)) || 760 (xmlStrEqual(prev->prefix, cur->prefix))) { 761 xmlFreeNs(cur); 762 return(NULL); 763 } 764 } 765 prev->next = cur; 766 } 767 } 768 return(cur); 769} 770 771/** 772 * xmlSetNs: 773 * @node: a node in the document 774 * @ns: a namespace pointer 775 * 776 * Associate a namespace to a node, a posteriori. 777 */ 778void 779xmlSetNs(xmlNodePtr node, xmlNsPtr ns) { 780 if (node == NULL) { 781#ifdef DEBUG_TREE 782 xmlGenericError(xmlGenericErrorContext, 783 "xmlSetNs: node == NULL\n"); 784#endif 785 return; 786 } 787 node->ns = ns; 788} 789 790/** 791 * xmlFreeNs: 792 * @cur: the namespace pointer 793 * 794 * Free up the structures associated to a namespace 795 */ 796void 797xmlFreeNs(xmlNsPtr cur) { 798 if (cur == NULL) { 799#ifdef DEBUG_TREE 800 xmlGenericError(xmlGenericErrorContext, 801 "xmlFreeNs : ns == NULL\n"); 802#endif 803 return; 804 } 805 if (cur->href != NULL) xmlFree((char *) cur->href); 806 if (cur->prefix != NULL) xmlFree((char *) cur->prefix); 807 xmlFree(cur); 808} 809 810/** 811 * xmlFreeNsList: 812 * @cur: the first namespace pointer 813 * 814 * Free up all the structures associated to the chained namespaces. 815 */ 816void 817xmlFreeNsList(xmlNsPtr cur) { 818 xmlNsPtr next; 819 if (cur == NULL) { 820#ifdef DEBUG_TREE 821 xmlGenericError(xmlGenericErrorContext, 822 "xmlFreeNsList : ns == NULL\n"); 823#endif 824 return; 825 } 826 while (cur != NULL) { 827 next = cur->next; 828 xmlFreeNs(cur); 829 cur = next; 830 } 831} 832 833/** 834 * xmlNewDtd: 835 * @doc: the document pointer 836 * @name: the DTD name 837 * @ExternalID: the external ID 838 * @SystemID: the system ID 839 * 840 * Creation of a new DTD for the external subset. To create an 841 * internal subset, use xmlCreateIntSubset(). 842 * 843 * Returns a pointer to the new DTD structure 844 */ 845xmlDtdPtr 846xmlNewDtd(xmlDocPtr doc, const xmlChar *name, 847 const xmlChar *ExternalID, const xmlChar *SystemID) { 848 xmlDtdPtr cur; 849 850 if ((doc != NULL) && (doc->extSubset != NULL)) { 851#ifdef DEBUG_TREE 852 xmlGenericError(xmlGenericErrorContext, 853 "xmlNewDtd(%s): document %s already have a DTD %s\n", 854 /* !!! */ (char *) name, doc->name, 855 /* !!! */ (char *)doc->extSubset->name); 856#endif 857 return(NULL); 858 } 859 860 /* 861 * Allocate a new DTD and fill the fields. 862 */ 863 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); 864 if (cur == NULL) { 865 xmlTreeErrMemory("building DTD"); 866 return(NULL); 867 } 868 memset(cur, 0 , sizeof(xmlDtd)); 869 cur->type = XML_DTD_NODE; 870 871 if (name != NULL) 872 cur->name = xmlStrdup(name); 873 if (ExternalID != NULL) 874 cur->ExternalID = xmlStrdup(ExternalID); 875 if (SystemID != NULL) 876 cur->SystemID = xmlStrdup(SystemID); 877 if (doc != NULL) 878 doc->extSubset = cur; 879 cur->doc = doc; 880 881 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 882 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 883 return(cur); 884} 885 886/** 887 * xmlGetIntSubset: 888 * @doc: the document pointer 889 * 890 * Get the internal subset of a document 891 * Returns a pointer to the DTD structure or NULL if not found 892 */ 893 894xmlDtdPtr 895xmlGetIntSubset(xmlDocPtr doc) { 896 xmlNodePtr cur; 897 898 if (doc == NULL) 899 return(NULL); 900 cur = doc->children; 901 while (cur != NULL) { 902 if (cur->type == XML_DTD_NODE) 903 return((xmlDtdPtr) cur); 904 cur = cur->next; 905 } 906 return((xmlDtdPtr) doc->intSubset); 907} 908 909/** 910 * xmlCreateIntSubset: 911 * @doc: the document pointer 912 * @name: the DTD name 913 * @ExternalID: the external (PUBLIC) ID 914 * @SystemID: the system ID 915 * 916 * Create the internal subset of a document 917 * Returns a pointer to the new DTD structure 918 */ 919xmlDtdPtr 920xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, 921 const xmlChar *ExternalID, const xmlChar *SystemID) { 922 xmlDtdPtr cur; 923 924 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) { 925#ifdef DEBUG_TREE 926 xmlGenericError(xmlGenericErrorContext, 927 928 "xmlCreateIntSubset(): document %s already have an internal subset\n", 929 doc->name); 930#endif 931 return(NULL); 932 } 933 934 /* 935 * Allocate a new DTD and fill the fields. 936 */ 937 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); 938 if (cur == NULL) { 939 xmlTreeErrMemory("building internal subset"); 940 return(NULL); 941 } 942 memset(cur, 0, sizeof(xmlDtd)); 943 cur->type = XML_DTD_NODE; 944 945 if (name != NULL) { 946 cur->name = xmlStrdup(name); 947 if (cur->name == NULL) { 948 xmlTreeErrMemory("building internal subset"); 949 xmlFree(cur); 950 return(NULL); 951 } 952 } 953 if (ExternalID != NULL) { 954 cur->ExternalID = xmlStrdup(ExternalID); 955 if (cur->ExternalID == NULL) { 956 xmlTreeErrMemory("building internal subset"); 957 if (cur->name != NULL) 958 xmlFree((char *)cur->name); 959 xmlFree(cur); 960 return(NULL); 961 } 962 } 963 if (SystemID != NULL) { 964 cur->SystemID = xmlStrdup(SystemID); 965 if (cur->SystemID == NULL) { 966 xmlTreeErrMemory("building internal subset"); 967 if (cur->name != NULL) 968 xmlFree((char *)cur->name); 969 if (cur->ExternalID != NULL) 970 xmlFree((char *)cur->ExternalID); 971 xmlFree(cur); 972 return(NULL); 973 } 974 } 975 if (doc != NULL) { 976 doc->intSubset = cur; 977 cur->parent = doc; 978 cur->doc = doc; 979 if (doc->children == NULL) { 980 doc->children = (xmlNodePtr) cur; 981 doc->last = (xmlNodePtr) cur; 982 } else { 983 if (doc->type == XML_HTML_DOCUMENT_NODE) { 984 xmlNodePtr prev; 985 986 prev = doc->children; 987 prev->prev = (xmlNodePtr) cur; 988 cur->next = prev; 989 doc->children = (xmlNodePtr) cur; 990 } else { 991 xmlNodePtr next; 992 993 next = doc->children; 994 while ((next != NULL) && (next->type != XML_ELEMENT_NODE)) 995 next = next->next; 996 if (next == NULL) { 997 cur->prev = doc->last; 998 cur->prev->next = (xmlNodePtr) cur; 999 cur->next = NULL; 1000 doc->last = (xmlNodePtr) cur; 1001 } else { 1002 cur->next = next; 1003 cur->prev = next->prev; 1004 if (cur->prev == NULL) 1005 doc->children = (xmlNodePtr) cur; 1006 else 1007 cur->prev->next = (xmlNodePtr) cur; 1008 next->prev = (xmlNodePtr) cur; 1009 } 1010 } 1011 } 1012 } 1013 1014 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 1015 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 1016 return(cur); 1017} 1018 1019/** 1020 * DICT_FREE: 1021 * @str: a string 1022 * 1023 * Free a string if it is not owned by the "dict" dictionnary in the 1024 * current scope 1025 */ 1026#define DICT_FREE(str) \ 1027 if ((str) && ((!dict) || \ 1028 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ 1029 xmlFree((char *)(str)); 1030 1031 1032/** 1033 * DICT_COPY: 1034 * @str: a string 1035 * 1036 * Copy a string using a "dict" dictionnary in the current scope, 1037 * if availabe. 1038 */ 1039#define DICT_COPY(str, cpy) \ 1040 if (str) { \ 1041 if (dict) { \ 1042 if (xmlDictOwns(dict, (const xmlChar *)(str))) \ 1043 cpy = (xmlChar *) (str); \ 1044 else \ 1045 cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \ 1046 } else \ 1047 cpy = xmlStrdup((const xmlChar *)(str)); } 1048 1049/** 1050 * DICT_CONST_COPY: 1051 * @str: a string 1052 * 1053 * Copy a string using a "dict" dictionnary in the current scope, 1054 * if availabe. 1055 */ 1056#define DICT_CONST_COPY(str, cpy) \ 1057 if (str) { \ 1058 if (dict) { \ 1059 if (xmlDictOwns(dict, (const xmlChar *)(str))) \ 1060 cpy = (const xmlChar *) (str); \ 1061 else \ 1062 cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \ 1063 } else \ 1064 cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); } 1065 1066 1067/** 1068 * xmlFreeDtd: 1069 * @cur: the DTD structure to free up 1070 * 1071 * Free a DTD structure. 1072 */ 1073void 1074xmlFreeDtd(xmlDtdPtr cur) { 1075 xmlDictPtr dict = NULL; 1076 1077 if (cur == NULL) { 1078 return; 1079 } 1080 if (cur->doc != NULL) dict = cur->doc->dict; 1081 1082 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 1083 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); 1084 1085 if (cur->children != NULL) { 1086 xmlNodePtr next, c = cur->children; 1087 1088 /* 1089 * Cleanup all nodes which are not part of the specific lists 1090 * of notations, elements, attributes and entities. 1091 */ 1092 while (c != NULL) { 1093 next = c->next; 1094 if ((c->type != XML_NOTATION_NODE) && 1095 (c->type != XML_ELEMENT_DECL) && 1096 (c->type != XML_ATTRIBUTE_DECL) && 1097 (c->type != XML_ENTITY_DECL)) { 1098 xmlUnlinkNode(c); 1099 xmlFreeNode(c); 1100 } 1101 c = next; 1102 } 1103 } 1104 DICT_FREE(cur->name) 1105 DICT_FREE(cur->SystemID) 1106 DICT_FREE(cur->ExternalID) 1107 /* TODO !!! */ 1108 if (cur->notations != NULL) 1109 xmlFreeNotationTable((xmlNotationTablePtr) cur->notations); 1110 1111 if (cur->elements != NULL) 1112 xmlFreeElementTable((xmlElementTablePtr) cur->elements); 1113 if (cur->attributes != NULL) 1114 xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes); 1115 if (cur->entities != NULL) 1116 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities); 1117 if (cur->pentities != NULL) 1118 xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities); 1119 1120 xmlFree(cur); 1121} 1122 1123/** 1124 * xmlNewDoc: 1125 * @version: xmlChar string giving the version of XML "1.0" 1126 * 1127 * Creates a new XML document 1128 * 1129 * Returns a new document 1130 */ 1131xmlDocPtr 1132xmlNewDoc(const xmlChar *version) { 1133 xmlDocPtr cur; 1134 1135 if (version == NULL) 1136 version = (const xmlChar *) "1.0"; 1137 1138 /* 1139 * Allocate a new document and fill the fields. 1140 */ 1141 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc)); 1142 if (cur == NULL) { 1143 xmlTreeErrMemory("building doc"); 1144 return(NULL); 1145 } 1146 memset(cur, 0, sizeof(xmlDoc)); 1147 cur->type = XML_DOCUMENT_NODE; 1148 1149 cur->version = xmlStrdup(version); 1150 if (cur->version == NULL) { 1151 xmlTreeErrMemory("building doc"); 1152 xmlFree(cur); 1153 return(NULL); 1154 } 1155 cur->standalone = -1; 1156 cur->compression = -1; /* not initialized */ 1157 cur->doc = cur; 1158 cur->parseFlags = 0; 1159 cur->properties = XML_DOC_USERBUILT; 1160 /* 1161 * The in memory encoding is always UTF8 1162 * This field will never change and would 1163 * be obsolete if not for binary compatibility. 1164 */ 1165 cur->charset = XML_CHAR_ENCODING_UTF8; 1166 1167 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 1168 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 1169 return(cur); 1170} 1171 1172/** 1173 * xmlFreeDoc: 1174 * @cur: pointer to the document 1175 * 1176 * Free up all the structures used by a document, tree included. 1177 */ 1178void 1179xmlFreeDoc(xmlDocPtr cur) { 1180 xmlDtdPtr extSubset, intSubset; 1181 xmlDictPtr dict = NULL; 1182 1183 if (cur == NULL) { 1184#ifdef DEBUG_TREE 1185 xmlGenericError(xmlGenericErrorContext, 1186 "xmlFreeDoc : document == NULL\n"); 1187#endif 1188 return; 1189 } 1190#ifdef LIBXML_DEBUG_RUNTIME 1191#ifdef LIBXML_DEBUG_ENABLED 1192 xmlDebugCheckDocument(stderr, cur); 1193#endif 1194#endif 1195 1196 if (cur != NULL) dict = cur->dict; 1197 1198 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 1199 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); 1200 1201 /* 1202 * Do this before freeing the children list to avoid ID lookups 1203 */ 1204 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids); 1205 cur->ids = NULL; 1206 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs); 1207 cur->refs = NULL; 1208 extSubset = cur->extSubset; 1209 intSubset = cur->intSubset; 1210 if (intSubset == extSubset) 1211 extSubset = NULL; 1212 if (extSubset != NULL) { 1213 xmlUnlinkNode((xmlNodePtr) cur->extSubset); 1214 cur->extSubset = NULL; 1215 xmlFreeDtd(extSubset); 1216 } 1217 if (intSubset != NULL) { 1218 xmlUnlinkNode((xmlNodePtr) cur->intSubset); 1219 cur->intSubset = NULL; 1220 xmlFreeDtd(intSubset); 1221 } 1222 1223 if (cur->children != NULL) xmlFreeNodeList(cur->children); 1224 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs); 1225 1226 DICT_FREE(cur->version) 1227 DICT_FREE(cur->name) 1228 DICT_FREE(cur->encoding) 1229 DICT_FREE(cur->URL) 1230 xmlFree(cur); 1231 if (dict) xmlDictFree(dict); 1232} 1233 1234/** 1235 * xmlStringLenGetNodeList: 1236 * @doc: the document 1237 * @value: the value of the text 1238 * @len: the length of the string value 1239 * 1240 * Parse the value string and build the node list associated. Should 1241 * produce a flat tree with only TEXTs and ENTITY_REFs. 1242 * Returns a pointer to the first child 1243 */ 1244xmlNodePtr 1245xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) { 1246 xmlNodePtr ret = NULL, last = NULL; 1247 xmlNodePtr node; 1248 xmlChar *val; 1249 const xmlChar *cur = value, *end = cur + len; 1250 const xmlChar *q; 1251 xmlEntityPtr ent; 1252 1253 if (value == NULL) return(NULL); 1254 1255 q = cur; 1256 while ((cur < end) && (*cur != 0)) { 1257 if (cur[0] == '&') { 1258 int charval = 0; 1259 xmlChar tmp; 1260 1261 /* 1262 * Save the current text. 1263 */ 1264 if (cur != q) { 1265 if ((last != NULL) && (last->type == XML_TEXT_NODE)) { 1266 xmlNodeAddContentLen(last, q, cur - q); 1267 } else { 1268 node = xmlNewDocTextLen(doc, q, cur - q); 1269 if (node == NULL) return(ret); 1270 if (last == NULL) 1271 last = ret = node; 1272 else { 1273 last->next = node; 1274 node->prev = last; 1275 last = node; 1276 } 1277 } 1278 } 1279 q = cur; 1280 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) { 1281 cur += 3; 1282 if (cur < end) 1283 tmp = *cur; 1284 else 1285 tmp = 0; 1286 while (tmp != ';') { /* Non input consuming loop */ 1287 if ((tmp >= '0') && (tmp <= '9')) 1288 charval = charval * 16 + (tmp - '0'); 1289 else if ((tmp >= 'a') && (tmp <= 'f')) 1290 charval = charval * 16 + (tmp - 'a') + 10; 1291 else if ((tmp >= 'A') && (tmp <= 'F')) 1292 charval = charval * 16 + (tmp - 'A') + 10; 1293 else { 1294 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, 1295 NULL); 1296 charval = 0; 1297 break; 1298 } 1299 cur++; 1300 if (cur < end) 1301 tmp = *cur; 1302 else 1303 tmp = 0; 1304 } 1305 if (tmp == ';') 1306 cur++; 1307 q = cur; 1308 } else if ((cur + 1 < end) && (cur[1] == '#')) { 1309 cur += 2; 1310 if (cur < end) 1311 tmp = *cur; 1312 else 1313 tmp = 0; 1314 while (tmp != ';') { /* Non input consuming loops */ 1315 if ((tmp >= '0') && (tmp <= '9')) 1316 charval = charval * 10 + (tmp - '0'); 1317 else { 1318 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, 1319 NULL); 1320 charval = 0; 1321 break; 1322 } 1323 cur++; 1324 if (cur < end) 1325 tmp = *cur; 1326 else 1327 tmp = 0; 1328 } 1329 if (tmp == ';') 1330 cur++; 1331 q = cur; 1332 } else { 1333 /* 1334 * Read the entity string 1335 */ 1336 cur++; 1337 q = cur; 1338 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++; 1339 if ((cur >= end) || (*cur == 0)) { 1340 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc, 1341 (const char *) q); 1342 return(ret); 1343 } 1344 if (cur != q) { 1345 /* 1346 * Predefined entities don't generate nodes 1347 */ 1348 val = xmlStrndup(q, cur - q); 1349 ent = xmlGetDocEntity(doc, val); 1350 if ((ent != NULL) && 1351 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { 1352 if (last == NULL) { 1353 node = xmlNewDocText(doc, ent->content); 1354 last = ret = node; 1355 } else if (last->type != XML_TEXT_NODE) { 1356 node = xmlNewDocText(doc, ent->content); 1357 last = xmlAddNextSibling(last, node); 1358 } else 1359 xmlNodeAddContent(last, ent->content); 1360 1361 } else { 1362 /* 1363 * Create a new REFERENCE_REF node 1364 */ 1365 node = xmlNewReference(doc, val); 1366 if (node == NULL) { 1367 if (val != NULL) xmlFree(val); 1368 return(ret); 1369 } 1370 else if ((ent != NULL) && (ent->children == NULL)) { 1371 xmlNodePtr temp; 1372 1373 ent->children = xmlStringGetNodeList(doc, 1374 (const xmlChar*)node->content); 1375 ent->owner = 1; 1376 temp = ent->children; 1377 while (temp) { 1378 temp->parent = (xmlNodePtr)ent; 1379 ent->last = temp; 1380 temp = temp->next; 1381 } 1382 } 1383 if (last == NULL) { 1384 last = ret = node; 1385 } else { 1386 last = xmlAddNextSibling(last, node); 1387 } 1388 } 1389 xmlFree(val); 1390 } 1391 cur++; 1392 q = cur; 1393 } 1394 if (charval != 0) { 1395 xmlChar buf[10]; 1396 int l; 1397 1398 l = xmlCopyCharMultiByte(buf, charval); 1399 buf[l] = 0; 1400 node = xmlNewDocText(doc, buf); 1401 if (node != NULL) { 1402 if (last == NULL) { 1403 last = ret = node; 1404 } else { 1405 last = xmlAddNextSibling(last, node); 1406 } 1407 } 1408 charval = 0; 1409 } 1410 } else 1411 cur++; 1412 } 1413 if ((cur != q) || (ret == NULL)) { 1414 /* 1415 * Handle the last piece of text. 1416 */ 1417 if ((last != NULL) && (last->type == XML_TEXT_NODE)) { 1418 xmlNodeAddContentLen(last, q, cur - q); 1419 } else { 1420 node = xmlNewDocTextLen(doc, q, cur - q); 1421 if (node == NULL) return(ret); 1422 if (last == NULL) { 1423 last = ret = node; 1424 } else { 1425 last = xmlAddNextSibling(last, node); 1426 } 1427 } 1428 } 1429 return(ret); 1430} 1431 1432/** 1433 * xmlStringGetNodeList: 1434 * @doc: the document 1435 * @value: the value of the attribute 1436 * 1437 * Parse the value string and build the node list associated. Should 1438 * produce a flat tree with only TEXTs and ENTITY_REFs. 1439 * Returns a pointer to the first child 1440 */ 1441xmlNodePtr 1442xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) { 1443 xmlNodePtr ret = NULL, last = NULL; 1444 xmlNodePtr node; 1445 xmlChar *val; 1446 const xmlChar *cur = value; 1447 const xmlChar *q; 1448 xmlEntityPtr ent; 1449 1450 if (value == NULL) return(NULL); 1451 1452 q = cur; 1453 while (*cur != 0) { 1454 if (cur[0] == '&') { 1455 int charval = 0; 1456 xmlChar tmp; 1457 1458 /* 1459 * Save the current text. 1460 */ 1461 if (cur != q) { 1462 if ((last != NULL) && (last->type == XML_TEXT_NODE)) { 1463 xmlNodeAddContentLen(last, q, cur - q); 1464 } else { 1465 node = xmlNewDocTextLen(doc, q, cur - q); 1466 if (node == NULL) return(ret); 1467 if (last == NULL) 1468 last = ret = node; 1469 else { 1470 last->next = node; 1471 node->prev = last; 1472 last = node; 1473 } 1474 } 1475 } 1476 q = cur; 1477 if ((cur[1] == '#') && (cur[2] == 'x')) { 1478 cur += 3; 1479 tmp = *cur; 1480 while (tmp != ';') { /* Non input consuming loop */ 1481 if ((tmp >= '0') && (tmp <= '9')) 1482 charval = charval * 16 + (tmp - '0'); 1483 else if ((tmp >= 'a') && (tmp <= 'f')) 1484 charval = charval * 16 + (tmp - 'a') + 10; 1485 else if ((tmp >= 'A') && (tmp <= 'F')) 1486 charval = charval * 16 + (tmp - 'A') + 10; 1487 else { 1488 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, 1489 NULL); 1490 charval = 0; 1491 break; 1492 } 1493 cur++; 1494 tmp = *cur; 1495 } 1496 if (tmp == ';') 1497 cur++; 1498 q = cur; 1499 } else if (cur[1] == '#') { 1500 cur += 2; 1501 tmp = *cur; 1502 while (tmp != ';') { /* Non input consuming loops */ 1503 if ((tmp >= '0') && (tmp <= '9')) 1504 charval = charval * 10 + (tmp - '0'); 1505 else { 1506 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, 1507 NULL); 1508 charval = 0; 1509 break; 1510 } 1511 cur++; 1512 tmp = *cur; 1513 } 1514 if (tmp == ';') 1515 cur++; 1516 q = cur; 1517 } else { 1518 /* 1519 * Read the entity string 1520 */ 1521 cur++; 1522 q = cur; 1523 while ((*cur != 0) && (*cur != ';')) cur++; 1524 if (*cur == 0) { 1525 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, 1526 (xmlNodePtr) doc, (const char *) q); 1527 return(ret); 1528 } 1529 if (cur != q) { 1530 /* 1531 * Predefined entities don't generate nodes 1532 */ 1533 val = xmlStrndup(q, cur - q); 1534 ent = xmlGetDocEntity(doc, val); 1535 if ((ent != NULL) && 1536 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { 1537 if (last == NULL) { 1538 node = xmlNewDocText(doc, ent->content); 1539 last = ret = node; 1540 } else if (last->type != XML_TEXT_NODE) { 1541 node = xmlNewDocText(doc, ent->content); 1542 last = xmlAddNextSibling(last, node); 1543 } else 1544 xmlNodeAddContent(last, ent->content); 1545 1546 } else { 1547 /* 1548 * Create a new REFERENCE_REF node 1549 */ 1550 node = xmlNewReference(doc, val); 1551 if (node == NULL) { 1552 if (val != NULL) xmlFree(val); 1553 return(ret); 1554 } 1555 else if ((ent != NULL) && (ent->children == NULL)) { 1556 xmlNodePtr temp; 1557 1558 ent->children = xmlStringGetNodeList(doc, 1559 (const xmlChar*)node->content); 1560 ent->owner = 1; 1561 temp = ent->children; 1562 while (temp) { 1563 temp->parent = (xmlNodePtr)ent; 1564 temp = temp->next; 1565 } 1566 } 1567 if (last == NULL) { 1568 last = ret = node; 1569 } else { 1570 last = xmlAddNextSibling(last, node); 1571 } 1572 } 1573 xmlFree(val); 1574 } 1575 cur++; 1576 q = cur; 1577 } 1578 if (charval != 0) { 1579 xmlChar buf[10]; 1580 int len; 1581 1582 len = xmlCopyCharMultiByte(buf, charval); 1583 buf[len] = 0; 1584 node = xmlNewDocText(doc, buf); 1585 if (node != NULL) { 1586 if (last == NULL) { 1587 last = ret = node; 1588 } else { 1589 last = xmlAddNextSibling(last, node); 1590 } 1591 } 1592 1593 charval = 0; 1594 } 1595 } else 1596 cur++; 1597 } 1598 if ((cur != q) || (ret == NULL)) { 1599 /* 1600 * Handle the last piece of text. 1601 */ 1602 if ((last != NULL) && (last->type == XML_TEXT_NODE)) { 1603 xmlNodeAddContentLen(last, q, cur - q); 1604 } else { 1605 node = xmlNewDocTextLen(doc, q, cur - q); 1606 if (node == NULL) return(ret); 1607 if (last == NULL) { 1608 last = ret = node; 1609 } else { 1610 last = xmlAddNextSibling(last, node); 1611 } 1612 } 1613 } 1614 return(ret); 1615} 1616 1617/** 1618 * xmlNodeListGetString: 1619 * @doc: the document 1620 * @list: a Node list 1621 * @inLine: should we replace entity contents or show their external form 1622 * 1623 * Build the string equivalent to the text contained in the Node list 1624 * made of TEXTs and ENTITY_REFs 1625 * 1626 * Returns a pointer to the string copy, the caller must free it with xmlFree(). 1627 */ 1628xmlChar * 1629xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) 1630{ 1631 xmlNodePtr node = list; 1632 xmlChar *ret = NULL; 1633 xmlEntityPtr ent; 1634 1635 if (list == NULL) 1636 return (NULL); 1637 1638 while (node != NULL) { 1639 if ((node->type == XML_TEXT_NODE) || 1640 (node->type == XML_CDATA_SECTION_NODE)) { 1641 if (inLine) { 1642 ret = xmlStrcat(ret, node->content); 1643 } else { 1644 xmlChar *buffer; 1645 1646 buffer = xmlEncodeEntitiesReentrant(doc, node->content); 1647 if (buffer != NULL) { 1648 ret = xmlStrcat(ret, buffer); 1649 xmlFree(buffer); 1650 } 1651 } 1652 } else if (node->type == XML_ENTITY_REF_NODE) { 1653 if (inLine) { 1654 ent = xmlGetDocEntity(doc, node->name); 1655 if (ent != NULL) { 1656 xmlChar *buffer; 1657 1658 /* an entity content can be any "well balanced chunk", 1659 * i.e. the result of the content [43] production: 1660 * http://www.w3.org/TR/REC-xml#NT-content. 1661 * So it can contain text, CDATA section or nested 1662 * entity reference nodes (among others). 1663 * -> we recursive call xmlNodeListGetString() 1664 * which handles these types */ 1665 buffer = xmlNodeListGetString(doc, ent->children, 1); 1666 if (buffer != NULL) { 1667 ret = xmlStrcat(ret, buffer); 1668 xmlFree(buffer); 1669 } 1670 } else { 1671 ret = xmlStrcat(ret, node->content); 1672 } 1673 } else { 1674 xmlChar buf[2]; 1675 1676 buf[0] = '&'; 1677 buf[1] = 0; 1678 ret = xmlStrncat(ret, buf, 1); 1679 ret = xmlStrcat(ret, node->name); 1680 buf[0] = ';'; 1681 buf[1] = 0; 1682 ret = xmlStrncat(ret, buf, 1); 1683 } 1684 } 1685#if 0 1686 else { 1687 xmlGenericError(xmlGenericErrorContext, 1688 "xmlGetNodeListString : invalid node type %d\n", 1689 node->type); 1690 } 1691#endif 1692 node = node->next; 1693 } 1694 return (ret); 1695} 1696 1697#ifdef LIBXML_TREE_ENABLED 1698/** 1699 * xmlNodeListGetRawString: 1700 * @doc: the document 1701 * @list: a Node list 1702 * @inLine: should we replace entity contents or show their external form 1703 * 1704 * Builds the string equivalent to the text contained in the Node list 1705 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString() 1706 * this function doesn't do any character encoding handling. 1707 * 1708 * Returns a pointer to the string copy, the caller must free it with xmlFree(). 1709 */ 1710xmlChar * 1711xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) 1712{ 1713 xmlNodePtr node = list; 1714 xmlChar *ret = NULL; 1715 xmlEntityPtr ent; 1716 1717 if (list == NULL) 1718 return (NULL); 1719 1720 while (node != NULL) { 1721 if ((node->type == XML_TEXT_NODE) || 1722 (node->type == XML_CDATA_SECTION_NODE)) { 1723 if (inLine) { 1724 ret = xmlStrcat(ret, node->content); 1725 } else { 1726 xmlChar *buffer; 1727 1728 buffer = xmlEncodeSpecialChars(doc, node->content); 1729 if (buffer != NULL) { 1730 ret = xmlStrcat(ret, buffer); 1731 xmlFree(buffer); 1732 } 1733 } 1734 } else if (node->type == XML_ENTITY_REF_NODE) { 1735 if (inLine) { 1736 ent = xmlGetDocEntity(doc, node->name); 1737 if (ent != NULL) { 1738 xmlChar *buffer; 1739 1740 /* an entity content can be any "well balanced chunk", 1741 * i.e. the result of the content [43] production: 1742 * http://www.w3.org/TR/REC-xml#NT-content. 1743 * So it can contain text, CDATA section or nested 1744 * entity reference nodes (among others). 1745 * -> we recursive call xmlNodeListGetRawString() 1746 * which handles these types */ 1747 buffer = 1748 xmlNodeListGetRawString(doc, ent->children, 1); 1749 if (buffer != NULL) { 1750 ret = xmlStrcat(ret, buffer); 1751 xmlFree(buffer); 1752 } 1753 } else { 1754 ret = xmlStrcat(ret, node->content); 1755 } 1756 } else { 1757 xmlChar buf[2]; 1758 1759 buf[0] = '&'; 1760 buf[1] = 0; 1761 ret = xmlStrncat(ret, buf, 1); 1762 ret = xmlStrcat(ret, node->name); 1763 buf[0] = ';'; 1764 buf[1] = 0; 1765 ret = xmlStrncat(ret, buf, 1); 1766 } 1767 } 1768#if 0 1769 else { 1770 xmlGenericError(xmlGenericErrorContext, 1771 "xmlGetNodeListString : invalid node type %d\n", 1772 node->type); 1773 } 1774#endif 1775 node = node->next; 1776 } 1777 return (ret); 1778} 1779#endif /* LIBXML_TREE_ENABLED */ 1780 1781static xmlAttrPtr 1782xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, 1783 const xmlChar * name, const xmlChar * value, 1784 int eatname) 1785{ 1786 xmlAttrPtr cur; 1787 xmlDocPtr doc = NULL; 1788 1789 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) { 1790 if ((eatname == 1) && 1791 ((node->doc == NULL) || 1792 (!(xmlDictOwns(node->doc->dict, name))))) 1793 xmlFree((xmlChar *) name); 1794 return (NULL); 1795 } 1796 1797 /* 1798 * Allocate a new property and fill the fields. 1799 */ 1800 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); 1801 if (cur == NULL) { 1802 if ((eatname == 1) && 1803 ((node->doc == NULL) || 1804 (!(xmlDictOwns(node->doc->dict, name))))) 1805 xmlFree((xmlChar *) name); 1806 xmlTreeErrMemory("building attribute"); 1807 return (NULL); 1808 } 1809 memset(cur, 0, sizeof(xmlAttr)); 1810 cur->type = XML_ATTRIBUTE_NODE; 1811 1812 cur->parent = node; 1813 if (node != NULL) { 1814 doc = node->doc; 1815 cur->doc = doc; 1816 } 1817 cur->ns = ns; 1818 1819 if (eatname == 0) { 1820 if ((doc != NULL) && (doc->dict != NULL)) 1821 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1); 1822 else 1823 cur->name = xmlStrdup(name); 1824 } else 1825 cur->name = name; 1826 1827 if (value != NULL) { 1828 xmlNodePtr tmp; 1829 1830 if(!xmlCheckUTF8(value)) { 1831 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) doc, 1832 NULL); 1833 if (doc != NULL) 1834 doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); 1835 } 1836 cur->children = xmlNewDocText(doc, value); 1837 cur->last = NULL; 1838 tmp = cur->children; 1839 while (tmp != NULL) { 1840 tmp->parent = (xmlNodePtr) cur; 1841 if (tmp->next == NULL) 1842 cur->last = tmp; 1843 tmp = tmp->next; 1844 } 1845 } 1846 1847 /* 1848 * Add it at the end to preserve parsing order ... 1849 */ 1850 if (node != NULL) { 1851 if (node->properties == NULL) { 1852 node->properties = cur; 1853 } else { 1854 xmlAttrPtr prev = node->properties; 1855 1856 while (prev->next != NULL) 1857 prev = prev->next; 1858 prev->next = cur; 1859 cur->prev = prev; 1860 } 1861 } 1862 1863 if (xmlIsID((node == NULL) ? NULL : node->doc, node, cur) == 1) 1864 xmlAddID(NULL, node->doc, value, cur); 1865 1866 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 1867 xmlRegisterNodeDefaultValue((xmlNodePtr) cur); 1868 return (cur); 1869} 1870 1871#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ 1872 defined(LIBXML_SCHEMAS_ENABLED) 1873/** 1874 * xmlNewProp: 1875 * @node: the holding node 1876 * @name: the name of the attribute 1877 * @value: the value of the attribute 1878 * 1879 * Create a new property carried by a node. 1880 * Returns a pointer to the attribute 1881 */ 1882xmlAttrPtr 1883xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { 1884 1885 if (name == NULL) { 1886#ifdef DEBUG_TREE 1887 xmlGenericError(xmlGenericErrorContext, 1888 "xmlNewProp : name == NULL\n"); 1889#endif 1890 return(NULL); 1891 } 1892 1893 return xmlNewPropInternal(node, NULL, name, value, 0); 1894} 1895#endif /* LIBXML_TREE_ENABLED */ 1896 1897/** 1898 * xmlNewNsProp: 1899 * @node: the holding node 1900 * @ns: the namespace 1901 * @name: the name of the attribute 1902 * @value: the value of the attribute 1903 * 1904 * Create a new property tagged with a namespace and carried by a node. 1905 * Returns a pointer to the attribute 1906 */ 1907xmlAttrPtr 1908xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, 1909 const xmlChar *value) { 1910 1911 if (name == NULL) { 1912#ifdef DEBUG_TREE 1913 xmlGenericError(xmlGenericErrorContext, 1914 "xmlNewNsProp : name == NULL\n"); 1915#endif 1916 return(NULL); 1917 } 1918 1919 return xmlNewPropInternal(node, ns, name, value, 0); 1920} 1921 1922/** 1923 * xmlNewNsPropEatName: 1924 * @node: the holding node 1925 * @ns: the namespace 1926 * @name: the name of the attribute 1927 * @value: the value of the attribute 1928 * 1929 * Create a new property tagged with a namespace and carried by a node. 1930 * Returns a pointer to the attribute 1931 */ 1932xmlAttrPtr 1933xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name, 1934 const xmlChar *value) { 1935 1936 if (name == NULL) { 1937#ifdef DEBUG_TREE 1938 xmlGenericError(xmlGenericErrorContext, 1939 "xmlNewNsPropEatName : name == NULL\n"); 1940#endif 1941 return(NULL); 1942 } 1943 1944 return xmlNewPropInternal(node, ns, name, value, 1); 1945} 1946 1947/** 1948 * xmlNewDocProp: 1949 * @doc: the document 1950 * @name: the name of the attribute 1951 * @value: the value of the attribute 1952 * 1953 * Create a new property carried by a document. 1954 * Returns a pointer to the attribute 1955 */ 1956xmlAttrPtr 1957xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { 1958 xmlAttrPtr cur; 1959 1960 if (name == NULL) { 1961#ifdef DEBUG_TREE 1962 xmlGenericError(xmlGenericErrorContext, 1963 "xmlNewDocProp : name == NULL\n"); 1964#endif 1965 return(NULL); 1966 } 1967 1968 /* 1969 * Allocate a new property and fill the fields. 1970 */ 1971 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); 1972 if (cur == NULL) { 1973 xmlTreeErrMemory("building attribute"); 1974 return(NULL); 1975 } 1976 memset(cur, 0, sizeof(xmlAttr)); 1977 cur->type = XML_ATTRIBUTE_NODE; 1978 1979 if ((doc != NULL) && (doc->dict != NULL)) 1980 cur->name = xmlDictLookup(doc->dict, name, -1); 1981 else 1982 cur->name = xmlStrdup(name); 1983 cur->doc = doc; 1984 if (value != NULL) { 1985 xmlNodePtr tmp; 1986 1987 cur->children = xmlStringGetNodeList(doc, value); 1988 cur->last = NULL; 1989 1990 tmp = cur->children; 1991 while (tmp != NULL) { 1992 tmp->parent = (xmlNodePtr) cur; 1993 if (tmp->next == NULL) 1994 cur->last = tmp; 1995 tmp = tmp->next; 1996 } 1997 } 1998 1999 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2000 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 2001 return(cur); 2002} 2003 2004/** 2005 * xmlFreePropList: 2006 * @cur: the first property in the list 2007 * 2008 * Free a property and all its siblings, all the children are freed too. 2009 */ 2010void 2011xmlFreePropList(xmlAttrPtr cur) { 2012 xmlAttrPtr next; 2013 if (cur == NULL) return; 2014 while (cur != NULL) { 2015 next = cur->next; 2016 xmlFreeProp(cur); 2017 cur = next; 2018 } 2019} 2020 2021/** 2022 * xmlFreeProp: 2023 * @cur: an attribute 2024 * 2025 * Free one attribute, all the content is freed too 2026 */ 2027void 2028xmlFreeProp(xmlAttrPtr cur) { 2029 xmlDictPtr dict = NULL; 2030 if (cur == NULL) return; 2031 2032 if (cur->doc != NULL) dict = cur->doc->dict; 2033 2034 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 2035 xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); 2036 2037 /* Check for ID removal -> leading to invalid references ! */ 2038 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) { 2039 xmlRemoveID(cur->doc, cur); 2040 } 2041 if (cur->children != NULL) xmlFreeNodeList(cur->children); 2042 DICT_FREE(cur->name) 2043 xmlFree(cur); 2044} 2045 2046/** 2047 * xmlRemoveProp: 2048 * @cur: an attribute 2049 * 2050 * Unlink and free one attribute, all the content is freed too 2051 * Note this doesn't work for namespace definition attributes 2052 * 2053 * Returns 0 if success and -1 in case of error. 2054 */ 2055int 2056xmlRemoveProp(xmlAttrPtr cur) { 2057 xmlAttrPtr tmp; 2058 if (cur == NULL) { 2059#ifdef DEBUG_TREE 2060 xmlGenericError(xmlGenericErrorContext, 2061 "xmlRemoveProp : cur == NULL\n"); 2062#endif 2063 return(-1); 2064 } 2065 if (cur->parent == NULL) { 2066#ifdef DEBUG_TREE 2067 xmlGenericError(xmlGenericErrorContext, 2068 "xmlRemoveProp : cur->parent == NULL\n"); 2069#endif 2070 return(-1); 2071 } 2072 tmp = cur->parent->properties; 2073 if (tmp == cur) { 2074 cur->parent->properties = cur->next; 2075 if (cur->next != NULL) 2076 cur->next->prev = NULL; 2077 xmlFreeProp(cur); 2078 return(0); 2079 } 2080 while (tmp != NULL) { 2081 if (tmp->next == cur) { 2082 tmp->next = cur->next; 2083 if (tmp->next != NULL) 2084 tmp->next->prev = tmp; 2085 xmlFreeProp(cur); 2086 return(0); 2087 } 2088 tmp = tmp->next; 2089 } 2090#ifdef DEBUG_TREE 2091 xmlGenericError(xmlGenericErrorContext, 2092 "xmlRemoveProp : attribute not owned by its node\n"); 2093#endif 2094 return(-1); 2095} 2096 2097/** 2098 * xmlNewDocPI: 2099 * @doc: the target document 2100 * @name: the processing instruction name 2101 * @content: the PI content 2102 * 2103 * Creation of a processing instruction element. 2104 * Returns a pointer to the new node object. 2105 */ 2106xmlNodePtr 2107xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) { 2108 xmlNodePtr cur; 2109 2110 if (name == NULL) { 2111#ifdef DEBUG_TREE 2112 xmlGenericError(xmlGenericErrorContext, 2113 "xmlNewPI : name == NULL\n"); 2114#endif 2115 return(NULL); 2116 } 2117 2118 /* 2119 * Allocate a new node and fill the fields. 2120 */ 2121 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2122 if (cur == NULL) { 2123 xmlTreeErrMemory("building PI"); 2124 return(NULL); 2125 } 2126 memset(cur, 0, sizeof(xmlNode)); 2127 cur->type = XML_PI_NODE; 2128 2129 if ((doc != NULL) && (doc->dict != NULL)) 2130 cur->name = xmlDictLookup(doc->dict, name, -1); 2131 else 2132 cur->name = xmlStrdup(name); 2133 if (content != NULL) { 2134 cur->content = xmlStrdup(content); 2135 } 2136 cur->doc = doc; 2137 2138 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2139 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 2140 return(cur); 2141} 2142 2143/** 2144 * xmlNewPI: 2145 * @name: the processing instruction name 2146 * @content: the PI content 2147 * 2148 * Creation of a processing instruction element. 2149 * Use xmlDocNewPI preferably to get string interning 2150 * 2151 * Returns a pointer to the new node object. 2152 */ 2153xmlNodePtr 2154xmlNewPI(const xmlChar *name, const xmlChar *content) { 2155 return(xmlNewDocPI(NULL, name, content)); 2156} 2157 2158/** 2159 * xmlNewNode: 2160 * @ns: namespace if any 2161 * @name: the node name 2162 * 2163 * Creation of a new node element. @ns is optional (NULL). 2164 * 2165 * Returns a pointer to the new node object. Uses xmlStrdup() to make 2166 * copy of @name. 2167 */ 2168xmlNodePtr 2169xmlNewNode(xmlNsPtr ns, const xmlChar *name) { 2170 xmlNodePtr cur; 2171 2172 if (name == NULL) { 2173#ifdef DEBUG_TREE 2174 xmlGenericError(xmlGenericErrorContext, 2175 "xmlNewNode : name == NULL\n"); 2176#endif 2177 return(NULL); 2178 } 2179 2180 /* 2181 * Allocate a new node and fill the fields. 2182 */ 2183 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2184 if (cur == NULL) { 2185 xmlTreeErrMemory("building node"); 2186 return(NULL); 2187 } 2188 memset(cur, 0, sizeof(xmlNode)); 2189 cur->type = XML_ELEMENT_NODE; 2190 2191 cur->name = xmlStrdup(name); 2192 cur->ns = ns; 2193 2194 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2195 xmlRegisterNodeDefaultValue(cur); 2196 return(cur); 2197} 2198 2199/** 2200 * xmlNewNodeEatName: 2201 * @ns: namespace if any 2202 * @name: the node name 2203 * 2204 * Creation of a new node element. @ns is optional (NULL). 2205 * 2206 * Returns a pointer to the new node object, with pointer @name as 2207 * new node's name. Use xmlNewNode() if a copy of @name string is 2208 * is needed as new node's name. 2209 */ 2210xmlNodePtr 2211xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) { 2212 xmlNodePtr cur; 2213 2214 if (name == NULL) { 2215#ifdef DEBUG_TREE 2216 xmlGenericError(xmlGenericErrorContext, 2217 "xmlNewNode : name == NULL\n"); 2218#endif 2219 return(NULL); 2220 } 2221 2222 /* 2223 * Allocate a new node and fill the fields. 2224 */ 2225 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2226 if (cur == NULL) { 2227 xmlTreeErrMemory("building node"); 2228 /* we can't check here that name comes from the doc dictionnary */ 2229 return(NULL); 2230 } 2231 memset(cur, 0, sizeof(xmlNode)); 2232 cur->type = XML_ELEMENT_NODE; 2233 2234 cur->name = name; 2235 cur->ns = ns; 2236 2237 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2238 xmlRegisterNodeDefaultValue((xmlNodePtr)cur); 2239 return(cur); 2240} 2241 2242/** 2243 * xmlNewDocNode: 2244 * @doc: the document 2245 * @ns: namespace if any 2246 * @name: the node name 2247 * @content: the XML text content if any 2248 * 2249 * Creation of a new node element within a document. @ns and @content 2250 * are optional (NULL). 2251 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities 2252 * references, but XML special chars need to be escaped first by using 2253 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't 2254 * need entities support. 2255 * 2256 * Returns a pointer to the new node object. 2257 */ 2258xmlNodePtr 2259xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns, 2260 const xmlChar *name, const xmlChar *content) { 2261 xmlNodePtr cur; 2262 2263 if ((doc != NULL) && (doc->dict != NULL)) 2264 cur = xmlNewNodeEatName(ns, (xmlChar *) 2265 xmlDictLookup(doc->dict, name, -1)); 2266 else 2267 cur = xmlNewNode(ns, name); 2268 if (cur != NULL) { 2269 cur->doc = doc; 2270 if (content != NULL) { 2271 cur->children = xmlStringGetNodeList(doc, content); 2272 UPDATE_LAST_CHILD_AND_PARENT(cur) 2273 } 2274 } 2275 2276 return(cur); 2277} 2278 2279/** 2280 * xmlNewDocNodeEatName: 2281 * @doc: the document 2282 * @ns: namespace if any 2283 * @name: the node name 2284 * @content: the XML text content if any 2285 * 2286 * Creation of a new node element within a document. @ns and @content 2287 * are optional (NULL). 2288 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities 2289 * references, but XML special chars need to be escaped first by using 2290 * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't 2291 * need entities support. 2292 * 2293 * Returns a pointer to the new node object. 2294 */ 2295xmlNodePtr 2296xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns, 2297 xmlChar *name, const xmlChar *content) { 2298 xmlNodePtr cur; 2299 2300 cur = xmlNewNodeEatName(ns, name); 2301 if (cur != NULL) { 2302 cur->doc = doc; 2303 if (content != NULL) { 2304 cur->children = xmlStringGetNodeList(doc, content); 2305 UPDATE_LAST_CHILD_AND_PARENT(cur) 2306 } 2307 } else { 2308 /* if name don't come from the doc dictionnary free it here */ 2309 if ((name != NULL) && (doc != NULL) && 2310 (!(xmlDictOwns(doc->dict, name)))) 2311 xmlFree(name); 2312 } 2313 return(cur); 2314} 2315 2316#ifdef LIBXML_TREE_ENABLED 2317/** 2318 * xmlNewDocRawNode: 2319 * @doc: the document 2320 * @ns: namespace if any 2321 * @name: the node name 2322 * @content: the text content if any 2323 * 2324 * Creation of a new node element within a document. @ns and @content 2325 * are optional (NULL). 2326 * 2327 * Returns a pointer to the new node object. 2328 */ 2329xmlNodePtr 2330xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, 2331 const xmlChar *name, const xmlChar *content) { 2332 xmlNodePtr cur; 2333 2334 cur = xmlNewDocNode(doc, ns, name, NULL); 2335 if (cur != NULL) { 2336 cur->doc = doc; 2337 if (content != NULL) { 2338 cur->children = xmlNewDocText(doc, content); 2339 UPDATE_LAST_CHILD_AND_PARENT(cur) 2340 } 2341 } 2342 return(cur); 2343} 2344 2345/** 2346 * xmlNewDocFragment: 2347 * @doc: the document owning the fragment 2348 * 2349 * Creation of a new Fragment node. 2350 * Returns a pointer to the new node object. 2351 */ 2352xmlNodePtr 2353xmlNewDocFragment(xmlDocPtr doc) { 2354 xmlNodePtr cur; 2355 2356 /* 2357 * Allocate a new DocumentFragment node and fill the fields. 2358 */ 2359 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2360 if (cur == NULL) { 2361 xmlTreeErrMemory("building fragment"); 2362 return(NULL); 2363 } 2364 memset(cur, 0, sizeof(xmlNode)); 2365 cur->type = XML_DOCUMENT_FRAG_NODE; 2366 2367 cur->doc = doc; 2368 2369 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2370 xmlRegisterNodeDefaultValue(cur); 2371 return(cur); 2372} 2373#endif /* LIBXML_TREE_ENABLED */ 2374 2375/** 2376 * xmlNewText: 2377 * @content: the text content 2378 * 2379 * Creation of a new text node. 2380 * Returns a pointer to the new node object. 2381 */ 2382xmlNodePtr 2383xmlNewText(const xmlChar *content) { 2384 xmlNodePtr cur; 2385 2386 /* 2387 * Allocate a new node and fill the fields. 2388 */ 2389 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2390 if (cur == NULL) { 2391 xmlTreeErrMemory("building text"); 2392 return(NULL); 2393 } 2394 memset(cur, 0, sizeof(xmlNode)); 2395 cur->type = XML_TEXT_NODE; 2396 2397 cur->name = xmlStringText; 2398 if (content != NULL) { 2399 cur->content = xmlStrdup(content); 2400 } 2401 2402 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2403 xmlRegisterNodeDefaultValue(cur); 2404 return(cur); 2405} 2406 2407#ifdef LIBXML_TREE_ENABLED 2408/** 2409 * xmlNewTextChild: 2410 * @parent: the parent node 2411 * @ns: a namespace if any 2412 * @name: the name of the child 2413 * @content: the text content of the child if any. 2414 * 2415 * Creation of a new child element, added at the end of @parent children list. 2416 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly 2417 * created element inherits the namespace of @parent. If @content is non NULL, 2418 * a child TEXT node will be created containing the string @content. 2419 * NOTE: Use xmlNewChild() if @content will contain entities that need to be 2420 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that 2421 * reserved XML chars that might appear in @content, such as the ampersand, 2422 * greater-than or less-than signs, are automatically replaced by their XML 2423 * escaped entity representations. 2424 * 2425 * Returns a pointer to the new node object. 2426 */ 2427xmlNodePtr 2428xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns, 2429 const xmlChar *name, const xmlChar *content) { 2430 xmlNodePtr cur, prev; 2431 2432 if (parent == NULL) { 2433#ifdef DEBUG_TREE 2434 xmlGenericError(xmlGenericErrorContext, 2435 "xmlNewTextChild : parent == NULL\n"); 2436#endif 2437 return(NULL); 2438 } 2439 2440 if (name == NULL) { 2441#ifdef DEBUG_TREE 2442 xmlGenericError(xmlGenericErrorContext, 2443 "xmlNewTextChild : name == NULL\n"); 2444#endif 2445 return(NULL); 2446 } 2447 2448 /* 2449 * Allocate a new node 2450 */ 2451 if (parent->type == XML_ELEMENT_NODE) { 2452 if (ns == NULL) 2453 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content); 2454 else 2455 cur = xmlNewDocRawNode(parent->doc, ns, name, content); 2456 } else if ((parent->type == XML_DOCUMENT_NODE) || 2457 (parent->type == XML_HTML_DOCUMENT_NODE)) { 2458 if (ns == NULL) 2459 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content); 2460 else 2461 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content); 2462 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { 2463 cur = xmlNewDocRawNode( parent->doc, ns, name, content); 2464 } else { 2465 return(NULL); 2466 } 2467 if (cur == NULL) return(NULL); 2468 2469 /* 2470 * add the new element at the end of the children list. 2471 */ 2472 cur->type = XML_ELEMENT_NODE; 2473 cur->parent = parent; 2474 cur->doc = parent->doc; 2475 if (parent->children == NULL) { 2476 parent->children = cur; 2477 parent->last = cur; 2478 } else { 2479 prev = parent->last; 2480 prev->next = cur; 2481 cur->prev = prev; 2482 parent->last = cur; 2483 } 2484 2485 return(cur); 2486} 2487#endif /* LIBXML_TREE_ENABLED */ 2488 2489/** 2490 * xmlNewCharRef: 2491 * @doc: the document 2492 * @name: the char ref string, starting with # or "&# ... ;" 2493 * 2494 * Creation of a new character reference node. 2495 * Returns a pointer to the new node object. 2496 */ 2497xmlNodePtr 2498xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) { 2499 xmlNodePtr cur; 2500 2501 if (name == NULL) 2502 return(NULL); 2503 2504 /* 2505 * Allocate a new node and fill the fields. 2506 */ 2507 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2508 if (cur == NULL) { 2509 xmlTreeErrMemory("building character reference"); 2510 return(NULL); 2511 } 2512 memset(cur, 0, sizeof(xmlNode)); 2513 cur->type = XML_ENTITY_REF_NODE; 2514 2515 cur->doc = doc; 2516 if (name[0] == '&') { 2517 int len; 2518 name++; 2519 len = xmlStrlen(name); 2520 if (name[len - 1] == ';') 2521 cur->name = xmlStrndup(name, len - 1); 2522 else 2523 cur->name = xmlStrndup(name, len); 2524 } else 2525 cur->name = xmlStrdup(name); 2526 2527 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2528 xmlRegisterNodeDefaultValue(cur); 2529 return(cur); 2530} 2531 2532/** 2533 * xmlNewReference: 2534 * @doc: the document 2535 * @name: the reference name, or the reference string with & and ; 2536 * 2537 * Creation of a new reference node. 2538 * Returns a pointer to the new node object. 2539 */ 2540xmlNodePtr 2541xmlNewReference(xmlDocPtr doc, const xmlChar *name) { 2542 xmlNodePtr cur; 2543 xmlEntityPtr ent; 2544 2545 if (name == NULL) 2546 return(NULL); 2547 2548 /* 2549 * Allocate a new node and fill the fields. 2550 */ 2551 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2552 if (cur == NULL) { 2553 xmlTreeErrMemory("building reference"); 2554 return(NULL); 2555 } 2556 memset(cur, 0, sizeof(xmlNode)); 2557 cur->type = XML_ENTITY_REF_NODE; 2558 2559 cur->doc = doc; 2560 if (name[0] == '&') { 2561 int len; 2562 name++; 2563 len = xmlStrlen(name); 2564 if (name[len - 1] == ';') 2565 cur->name = xmlStrndup(name, len - 1); 2566 else 2567 cur->name = xmlStrndup(name, len); 2568 } else 2569 cur->name = xmlStrdup(name); 2570 2571 ent = xmlGetDocEntity(doc, cur->name); 2572 if (ent != NULL) { 2573 cur->content = ent->content; 2574 /* 2575 * The parent pointer in entity is a DTD pointer and thus is NOT 2576 * updated. Not sure if this is 100% correct. 2577 * -George 2578 */ 2579 cur->children = (xmlNodePtr) ent; 2580 cur->last = (xmlNodePtr) ent; 2581 } 2582 2583 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2584 xmlRegisterNodeDefaultValue(cur); 2585 return(cur); 2586} 2587 2588/** 2589 * xmlNewDocText: 2590 * @doc: the document 2591 * @content: the text content 2592 * 2593 * Creation of a new text node within a document. 2594 * Returns a pointer to the new node object. 2595 */ 2596xmlNodePtr 2597xmlNewDocText(xmlDocPtr doc, const xmlChar *content) { 2598 xmlNodePtr cur; 2599 2600 cur = xmlNewText(content); 2601 if (cur != NULL) cur->doc = doc; 2602 return(cur); 2603} 2604 2605/** 2606 * xmlNewTextLen: 2607 * @content: the text content 2608 * @len: the text len. 2609 * 2610 * Creation of a new text node with an extra parameter for the content's length 2611 * Returns a pointer to the new node object. 2612 */ 2613xmlNodePtr 2614xmlNewTextLen(const xmlChar *content, int len) { 2615 xmlNodePtr cur; 2616 2617 /* 2618 * Allocate a new node and fill the fields. 2619 */ 2620 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2621 if (cur == NULL) { 2622 xmlTreeErrMemory("building text"); 2623 return(NULL); 2624 } 2625 memset(cur, 0, sizeof(xmlNode)); 2626 cur->type = XML_TEXT_NODE; 2627 2628 cur->name = xmlStringText; 2629 if (content != NULL) { 2630 cur->content = xmlStrndup(content, len); 2631 } 2632 2633 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2634 xmlRegisterNodeDefaultValue(cur); 2635 return(cur); 2636} 2637 2638/** 2639 * xmlNewDocTextLen: 2640 * @doc: the document 2641 * @content: the text content 2642 * @len: the text len. 2643 * 2644 * Creation of a new text node with an extra content length parameter. The 2645 * text node pertain to a given document. 2646 * Returns a pointer to the new node object. 2647 */ 2648xmlNodePtr 2649xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) { 2650 xmlNodePtr cur; 2651 2652 cur = xmlNewTextLen(content, len); 2653 if (cur != NULL) cur->doc = doc; 2654 return(cur); 2655} 2656 2657/** 2658 * xmlNewComment: 2659 * @content: the comment content 2660 * 2661 * Creation of a new node containing a comment. 2662 * Returns a pointer to the new node object. 2663 */ 2664xmlNodePtr 2665xmlNewComment(const xmlChar *content) { 2666 xmlNodePtr cur; 2667 2668 /* 2669 * Allocate a new node and fill the fields. 2670 */ 2671 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2672 if (cur == NULL) { 2673 xmlTreeErrMemory("building comment"); 2674 return(NULL); 2675 } 2676 memset(cur, 0, sizeof(xmlNode)); 2677 cur->type = XML_COMMENT_NODE; 2678 2679 cur->name = xmlStringComment; 2680 if (content != NULL) { 2681 cur->content = xmlStrdup(content); 2682 } 2683 2684 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2685 xmlRegisterNodeDefaultValue(cur); 2686 return(cur); 2687} 2688 2689/** 2690 * xmlNewCDataBlock: 2691 * @doc: the document 2692 * @content: the CDATA block content content 2693 * @len: the length of the block 2694 * 2695 * Creation of a new node containing a CDATA block. 2696 * Returns a pointer to the new node object. 2697 */ 2698xmlNodePtr 2699xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { 2700 xmlNodePtr cur; 2701 2702 /* 2703 * Allocate a new node and fill the fields. 2704 */ 2705 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 2706 if (cur == NULL) { 2707 xmlTreeErrMemory("building CDATA"); 2708 return(NULL); 2709 } 2710 memset(cur, 0, sizeof(xmlNode)); 2711 cur->type = XML_CDATA_SECTION_NODE; 2712 cur->doc = doc; 2713 2714 if (content != NULL) { 2715 cur->content = xmlStrndup(content, len); 2716 } 2717 2718 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 2719 xmlRegisterNodeDefaultValue(cur); 2720 return(cur); 2721} 2722 2723/** 2724 * xmlNewDocComment: 2725 * @doc: the document 2726 * @content: the comment content 2727 * 2728 * Creation of a new node containing a comment within a document. 2729 * Returns a pointer to the new node object. 2730 */ 2731xmlNodePtr 2732xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) { 2733 xmlNodePtr cur; 2734 2735 cur = xmlNewComment(content); 2736 if (cur != NULL) cur->doc = doc; 2737 return(cur); 2738} 2739 2740/** 2741 * xmlSetTreeDoc: 2742 * @tree: the top element 2743 * @doc: the document 2744 * 2745 * update all nodes under the tree to point to the right document 2746 */ 2747void 2748xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) { 2749 xmlAttrPtr prop; 2750 2751 if (tree == NULL) 2752 return; 2753 if (tree->doc != doc) { 2754 if(tree->type == XML_ELEMENT_NODE) { 2755 prop = tree->properties; 2756 while (prop != NULL) { 2757 prop->doc = doc; 2758 xmlSetListDoc(prop->children, doc); 2759 prop = prop->next; 2760 } 2761 } 2762 if (tree->children != NULL) 2763 xmlSetListDoc(tree->children, doc); 2764 tree->doc = doc; 2765 } 2766} 2767 2768/** 2769 * xmlSetListDoc: 2770 * @list: the first element 2771 * @doc: the document 2772 * 2773 * update all nodes in the list to point to the right document 2774 */ 2775void 2776xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) { 2777 xmlNodePtr cur; 2778 2779 if (list == NULL) 2780 return; 2781 cur = list; 2782 while (cur != NULL) { 2783 if (cur->doc != doc) 2784 xmlSetTreeDoc(cur, doc); 2785 cur = cur->next; 2786 } 2787} 2788 2789#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 2790/** 2791 * xmlNewChild: 2792 * @parent: the parent node 2793 * @ns: a namespace if any 2794 * @name: the name of the child 2795 * @content: the XML content of the child if any. 2796 * 2797 * Creation of a new child element, added at the end of @parent children list. 2798 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly 2799 * created element inherits the namespace of @parent. If @content is non NULL, 2800 * a child list containing the TEXTs and ENTITY_REFs node will be created. 2801 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity 2802 * references. XML special chars must be escaped first by using 2803 * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used. 2804 * 2805 * Returns a pointer to the new node object. 2806 */ 2807xmlNodePtr 2808xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, 2809 const xmlChar *name, const xmlChar *content) { 2810 xmlNodePtr cur, prev; 2811 2812 if (parent == NULL) { 2813#ifdef DEBUG_TREE 2814 xmlGenericError(xmlGenericErrorContext, 2815 "xmlNewChild : parent == NULL\n"); 2816#endif 2817 return(NULL); 2818 } 2819 2820 if (name == NULL) { 2821#ifdef DEBUG_TREE 2822 xmlGenericError(xmlGenericErrorContext, 2823 "xmlNewChild : name == NULL\n"); 2824#endif 2825 return(NULL); 2826 } 2827 2828 /* 2829 * Allocate a new node 2830 */ 2831 if (parent->type == XML_ELEMENT_NODE) { 2832 if (ns == NULL) 2833 cur = xmlNewDocNode(parent->doc, parent->ns, name, content); 2834 else 2835 cur = xmlNewDocNode(parent->doc, ns, name, content); 2836 } else if ((parent->type == XML_DOCUMENT_NODE) || 2837 (parent->type == XML_HTML_DOCUMENT_NODE)) { 2838 if (ns == NULL) 2839 cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content); 2840 else 2841 cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content); 2842 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { 2843 cur = xmlNewDocNode( parent->doc, ns, name, content); 2844 } else { 2845 return(NULL); 2846 } 2847 if (cur == NULL) return(NULL); 2848 2849 /* 2850 * add the new element at the end of the children list. 2851 */ 2852 cur->type = XML_ELEMENT_NODE; 2853 cur->parent = parent; 2854 cur->doc = parent->doc; 2855 if (parent->children == NULL) { 2856 parent->children = cur; 2857 parent->last = cur; 2858 } else { 2859 prev = parent->last; 2860 prev->next = cur; 2861 cur->prev = prev; 2862 parent->last = cur; 2863 } 2864 2865 return(cur); 2866} 2867#endif /* LIBXML_TREE_ENABLED */ 2868 2869/** 2870 * xmlAddPropSibling: 2871 * @prev: the attribute to which @prop is added after 2872 * @cur: the base attribute passed to calling function 2873 * @prop: the new attribute 2874 * 2875 * Add a new attribute after @prev using @cur as base attribute. 2876 * When inserting before @cur, @prev is passed as @cur->prev. 2877 * When inserting after @cur, @prev is passed as @cur. 2878 * If an existing attribute is found it is detroyed prior to adding @prop. 2879 * 2880 * Returns the attribute being inserted or NULL in case of error. 2881 */ 2882static xmlNodePtr 2883xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) { 2884 xmlAttrPtr attr; 2885 2886 if (cur->type != XML_ATTRIBUTE_NODE) 2887 return(NULL); 2888 2889 /* check if an attribute with the same name exists */ 2890 if (prop->ns == NULL) 2891 attr = xmlHasNsProp(cur->parent, prop->name, NULL); 2892 else 2893 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href); 2894 2895 if (prop->doc != cur->doc) { 2896 xmlSetTreeDoc(prop, cur->doc); 2897 } 2898 prop->parent = cur->parent; 2899 prop->prev = prev; 2900 if (prev != NULL) { 2901 prop->next = prev->next; 2902 prev->next = prop; 2903 if (prop->next) 2904 prop->next->prev = prop; 2905 } else { 2906 prop->next = cur; 2907 cur->prev = prop; 2908 } 2909 if (prop->prev == NULL && prop->parent != NULL) 2910 prop->parent->properties = (xmlAttrPtr) prop; 2911 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) { 2912 /* different instance, destroy it (attributes must be unique) */ 2913 xmlRemoveProp((xmlAttrPtr) attr); 2914 } 2915 return prop; 2916} 2917 2918/** 2919 * xmlAddNextSibling: 2920 * @cur: the child node 2921 * @elem: the new node 2922 * 2923 * Add a new node @elem as the next sibling of @cur 2924 * If the new node was already inserted in a document it is 2925 * first unlinked from its existing context. 2926 * As a result of text merging @elem may be freed. 2927 * If the new node is ATTRIBUTE, it is added into properties instead of children. 2928 * If there is an attribute with equal name, it is first destroyed. 2929 * 2930 * Returns the new node or NULL in case of error. 2931 */ 2932xmlNodePtr 2933xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) { 2934 if (cur == NULL) { 2935#ifdef DEBUG_TREE 2936 xmlGenericError(xmlGenericErrorContext, 2937 "xmlAddNextSibling : cur == NULL\n"); 2938#endif 2939 return(NULL); 2940 } 2941 if (elem == NULL) { 2942#ifdef DEBUG_TREE 2943 xmlGenericError(xmlGenericErrorContext, 2944 "xmlAddNextSibling : elem == NULL\n"); 2945#endif 2946 return(NULL); 2947 } 2948 2949 if (cur == elem) { 2950#ifdef DEBUG_TREE 2951 xmlGenericError(xmlGenericErrorContext, 2952 "xmlAddNextSibling : cur == elem\n"); 2953#endif 2954 return(NULL); 2955 } 2956 2957 xmlUnlinkNode(elem); 2958 2959 if (elem->type == XML_TEXT_NODE) { 2960 if (cur->type == XML_TEXT_NODE) { 2961 xmlNodeAddContent(cur, elem->content); 2962 xmlFreeNode(elem); 2963 return(cur); 2964 } 2965 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) && 2966 (cur->name == cur->next->name)) { 2967 xmlChar *tmp; 2968 2969 tmp = xmlStrdup(elem->content); 2970 tmp = xmlStrcat(tmp, cur->next->content); 2971 xmlNodeSetContent(cur->next, tmp); 2972 xmlFree(tmp); 2973 xmlFreeNode(elem); 2974 return(cur->next); 2975 } 2976 } else if (elem->type == XML_ATTRIBUTE_NODE) { 2977 return xmlAddPropSibling(cur, cur, elem); 2978 } 2979 2980 if (elem->doc != cur->doc) { 2981 xmlSetTreeDoc(elem, cur->doc); 2982 } 2983 elem->parent = cur->parent; 2984 elem->prev = cur; 2985 elem->next = cur->next; 2986 cur->next = elem; 2987 if (elem->next != NULL) 2988 elem->next->prev = elem; 2989 if ((elem->parent != NULL) && (elem->parent->last == cur)) 2990 elem->parent->last = elem; 2991 return(elem); 2992} 2993 2994#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ 2995 defined(LIBXML_SCHEMAS_ENABLED) 2996/** 2997 * xmlAddPrevSibling: 2998 * @cur: the child node 2999 * @elem: the new node 3000 * 3001 * Add a new node @elem as the previous sibling of @cur 3002 * merging adjacent TEXT nodes (@elem may be freed) 3003 * If the new node was already inserted in a document it is 3004 * first unlinked from its existing context. 3005 * If the new node is ATTRIBUTE, it is added into properties instead of children. 3006 * If there is an attribute with equal name, it is first destroyed. 3007 * 3008 * Returns the new node or NULL in case of error. 3009 */ 3010xmlNodePtr 3011xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) { 3012 if (cur == NULL) { 3013#ifdef DEBUG_TREE 3014 xmlGenericError(xmlGenericErrorContext, 3015 "xmlAddPrevSibling : cur == NULL\n"); 3016#endif 3017 return(NULL); 3018 } 3019 if (elem == NULL) { 3020#ifdef DEBUG_TREE 3021 xmlGenericError(xmlGenericErrorContext, 3022 "xmlAddPrevSibling : elem == NULL\n"); 3023#endif 3024 return(NULL); 3025 } 3026 3027 if (cur == elem) { 3028#ifdef DEBUG_TREE 3029 xmlGenericError(xmlGenericErrorContext, 3030 "xmlAddPrevSibling : cur == elem\n"); 3031#endif 3032 return(NULL); 3033 } 3034 3035 xmlUnlinkNode(elem); 3036 3037 if (elem->type == XML_TEXT_NODE) { 3038 if (cur->type == XML_TEXT_NODE) { 3039 xmlChar *tmp; 3040 3041 tmp = xmlStrdup(elem->content); 3042 tmp = xmlStrcat(tmp, cur->content); 3043 xmlNodeSetContent(cur, tmp); 3044 xmlFree(tmp); 3045 xmlFreeNode(elem); 3046 return(cur); 3047 } 3048 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) && 3049 (cur->name == cur->prev->name)) { 3050 xmlNodeAddContent(cur->prev, elem->content); 3051 xmlFreeNode(elem); 3052 return(cur->prev); 3053 } 3054 } else if (elem->type == XML_ATTRIBUTE_NODE) { 3055 return xmlAddPropSibling(cur->prev, cur, elem); 3056 } 3057 3058 if (elem->doc != cur->doc) { 3059 xmlSetTreeDoc(elem, cur->doc); 3060 } 3061 elem->parent = cur->parent; 3062 elem->next = cur; 3063 elem->prev = cur->prev; 3064 cur->prev = elem; 3065 if (elem->prev != NULL) 3066 elem->prev->next = elem; 3067 if ((elem->parent != NULL) && (elem->parent->children == cur)) { 3068 elem->parent->children = elem; 3069 } 3070 return(elem); 3071} 3072#endif /* LIBXML_TREE_ENABLED */ 3073 3074/** 3075 * xmlAddSibling: 3076 * @cur: the child node 3077 * @elem: the new node 3078 * 3079 * Add a new element @elem to the list of siblings of @cur 3080 * merging adjacent TEXT nodes (@elem may be freed) 3081 * If the new element was already inserted in a document it is 3082 * first unlinked from its existing context. 3083 * 3084 * Returns the new element or NULL in case of error. 3085 */ 3086xmlNodePtr 3087xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) { 3088 xmlNodePtr parent; 3089 3090 if (cur == NULL) { 3091#ifdef DEBUG_TREE 3092 xmlGenericError(xmlGenericErrorContext, 3093 "xmlAddSibling : cur == NULL\n"); 3094#endif 3095 return(NULL); 3096 } 3097 3098 if (elem == NULL) { 3099#ifdef DEBUG_TREE 3100 xmlGenericError(xmlGenericErrorContext, 3101 "xmlAddSibling : elem == NULL\n"); 3102#endif 3103 return(NULL); 3104 } 3105 3106 /* 3107 * Constant time is we can rely on the ->parent->last to find 3108 * the last sibling. 3109 */ 3110 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) && 3111 (cur->parent->children != NULL) && 3112 (cur->parent->last != NULL) && 3113 (cur->parent->last->next == NULL)) { 3114 cur = cur->parent->last; 3115 } else { 3116 while (cur->next != NULL) cur = cur->next; 3117 } 3118 3119 xmlUnlinkNode(elem); 3120 3121 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) && 3122 (cur->name == elem->name)) { 3123 xmlNodeAddContent(cur, elem->content); 3124 xmlFreeNode(elem); 3125 return(cur); 3126 } else if (elem->type == XML_ATTRIBUTE_NODE) { 3127 return xmlAddPropSibling(cur, cur, elem); 3128 } 3129 3130 if (elem->doc != cur->doc) { 3131 xmlSetTreeDoc(elem, cur->doc); 3132 } 3133 parent = cur->parent; 3134 elem->prev = cur; 3135 elem->next = NULL; 3136 elem->parent = parent; 3137 cur->next = elem; 3138 if (parent != NULL) 3139 parent->last = elem; 3140 3141 return(elem); 3142} 3143 3144/** 3145 * xmlAddChildList: 3146 * @parent: the parent node 3147 * @cur: the first node in the list 3148 * 3149 * Add a list of node at the end of the child list of the parent 3150 * merging adjacent TEXT nodes (@cur may be freed) 3151 * 3152 * Returns the last child or NULL in case of error. 3153 */ 3154xmlNodePtr 3155xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { 3156 xmlNodePtr prev; 3157 3158 if (parent == NULL) { 3159#ifdef DEBUG_TREE 3160 xmlGenericError(xmlGenericErrorContext, 3161 "xmlAddChildList : parent == NULL\n"); 3162#endif 3163 return(NULL); 3164 } 3165 3166 if (cur == NULL) { 3167#ifdef DEBUG_TREE 3168 xmlGenericError(xmlGenericErrorContext, 3169 "xmlAddChildList : child == NULL\n"); 3170#endif 3171 return(NULL); 3172 } 3173 3174 if ((cur->doc != NULL) && (parent->doc != NULL) && 3175 (cur->doc != parent->doc)) { 3176#ifdef DEBUG_TREE 3177 xmlGenericError(xmlGenericErrorContext, 3178 "Elements moved to a different document\n"); 3179#endif 3180 } 3181 3182 /* 3183 * add the first element at the end of the children list. 3184 */ 3185 3186 if (parent->children == NULL) { 3187 parent->children = cur; 3188 } else { 3189 /* 3190 * If cur and parent->last both are TEXT nodes, then merge them. 3191 */ 3192 if ((cur->type == XML_TEXT_NODE) && 3193 (parent->last->type == XML_TEXT_NODE) && 3194 (cur->name == parent->last->name)) { 3195 xmlNodeAddContent(parent->last, cur->content); 3196 /* 3197 * if it's the only child, nothing more to be done. 3198 */ 3199 if (cur->next == NULL) { 3200 xmlFreeNode(cur); 3201 return(parent->last); 3202 } 3203 prev = cur; 3204 cur = cur->next; 3205 xmlFreeNode(prev); 3206 } 3207 prev = parent->last; 3208 prev->next = cur; 3209 cur->prev = prev; 3210 } 3211 while (cur->next != NULL) { 3212 cur->parent = parent; 3213 if (cur->doc != parent->doc) { 3214 xmlSetTreeDoc(cur, parent->doc); 3215 } 3216 cur = cur->next; 3217 } 3218 cur->parent = parent; 3219 cur->doc = parent->doc; /* the parent may not be linked to a doc ! */ 3220 parent->last = cur; 3221 3222 return(cur); 3223} 3224 3225/** 3226 * xmlAddChild: 3227 * @parent: the parent node 3228 * @cur: the child node 3229 * 3230 * Add a new node to @parent, at the end of the child (or property) list 3231 * merging adjacent TEXT nodes (in which case @cur is freed) 3232 * If the new node is ATTRIBUTE, it is added into properties instead of children. 3233 * If there is an attribute with equal name, it is first destroyed. 3234 * 3235 * Returns the child or NULL in case of error. 3236 */ 3237xmlNodePtr 3238xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) { 3239 xmlNodePtr prev; 3240 3241 if (parent == NULL) { 3242#ifdef DEBUG_TREE 3243 xmlGenericError(xmlGenericErrorContext, 3244 "xmlAddChild : parent == NULL\n"); 3245#endif 3246 return(NULL); 3247 } 3248 3249 if (cur == NULL) { 3250#ifdef DEBUG_TREE 3251 xmlGenericError(xmlGenericErrorContext, 3252 "xmlAddChild : child == NULL\n"); 3253#endif 3254 return(NULL); 3255 } 3256 3257 if (parent == cur) { 3258#ifdef DEBUG_TREE 3259 xmlGenericError(xmlGenericErrorContext, 3260 "xmlAddChild : parent == cur\n"); 3261#endif 3262 return(NULL); 3263 } 3264 /* 3265 * If cur is a TEXT node, merge its content with adjacent TEXT nodes 3266 * cur is then freed. 3267 */ 3268 if (cur->type == XML_TEXT_NODE) { 3269 if ((parent->type == XML_TEXT_NODE) && 3270 (parent->content != NULL) && 3271 (parent->name == cur->name)) { 3272 xmlNodeAddContent(parent, cur->content); 3273 xmlFreeNode(cur); 3274 return(parent); 3275 } 3276 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) && 3277 (parent->last->name == cur->name) && 3278 (parent->last != cur)) { 3279 xmlNodeAddContent(parent->last, cur->content); 3280 xmlFreeNode(cur); 3281 return(parent->last); 3282 } 3283 } 3284 3285 /* 3286 * add the new element at the end of the children list. 3287 */ 3288 prev = cur->parent; 3289 cur->parent = parent; 3290 if (cur->doc != parent->doc) { 3291 xmlSetTreeDoc(cur, parent->doc); 3292 } 3293 /* this check prevents a loop on tree-traversions if a developer 3294 * tries to add a node to its parent multiple times 3295 */ 3296 if (prev == parent) 3297 return(cur); 3298 3299 /* 3300 * Coalescing 3301 */ 3302 if ((parent->type == XML_TEXT_NODE) && 3303 (parent->content != NULL) && 3304 (parent != cur)) { 3305 xmlNodeAddContent(parent, cur->content); 3306 xmlFreeNode(cur); 3307 return(parent); 3308 } 3309 if (cur->type == XML_ATTRIBUTE_NODE) { 3310 if (parent->type != XML_ELEMENT_NODE) 3311 return(NULL); 3312 if (parent->properties == NULL) { 3313 parent->properties = (xmlAttrPtr) cur; 3314 } else { 3315 /* check if an attribute with the same name exists */ 3316 xmlAttrPtr lastattr; 3317 3318 if (cur->ns == NULL) 3319 lastattr = xmlHasNsProp(parent, cur->name, NULL); 3320 else 3321 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href); 3322 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) { 3323 /* different instance, destroy it (attributes must be unique) */ 3324 xmlUnlinkNode((xmlNodePtr) lastattr); 3325 xmlFreeProp(lastattr); 3326 } 3327 if (lastattr == (xmlAttrPtr) cur) 3328 return(cur); 3329 /* find the end */ 3330 lastattr = parent->properties; 3331 while (lastattr->next != NULL) { 3332 lastattr = lastattr->next; 3333 } 3334 lastattr->next = (xmlAttrPtr) cur; 3335 ((xmlAttrPtr) cur)->prev = lastattr; 3336 } 3337 } else { 3338 if (parent->children == NULL) { 3339 parent->children = cur; 3340 parent->last = cur; 3341 } else { 3342 prev = parent->last; 3343 prev->next = cur; 3344 cur->prev = prev; 3345 parent->last = cur; 3346 } 3347 } 3348 return(cur); 3349} 3350 3351/** 3352 * xmlGetLastChild: 3353 * @parent: the parent node 3354 * 3355 * Search the last child of a node. 3356 * Returns the last child or NULL if none. 3357 */ 3358xmlNodePtr 3359xmlGetLastChild(xmlNodePtr parent) { 3360 if (parent == NULL) { 3361#ifdef DEBUG_TREE 3362 xmlGenericError(xmlGenericErrorContext, 3363 "xmlGetLastChild : parent == NULL\n"); 3364#endif 3365 return(NULL); 3366 } 3367 return(parent->last); 3368} 3369 3370/** 3371 * xmlFreeNodeList: 3372 * @cur: the first node in the list 3373 * 3374 * Free a node and all its siblings, this is a recursive behaviour, all 3375 * the children are freed too. 3376 */ 3377void 3378xmlFreeNodeList(xmlNodePtr cur) { 3379 xmlNodePtr next; 3380 xmlDictPtr dict = NULL; 3381 3382 if (cur == NULL) return; 3383 if (cur->type == XML_NAMESPACE_DECL) { 3384 xmlFreeNsList((xmlNsPtr) cur); 3385 return; 3386 } 3387 if ((cur->type == XML_DOCUMENT_NODE) || 3388#ifdef LIBXML_DOCB_ENABLED 3389 (cur->type == XML_DOCB_DOCUMENT_NODE) || 3390#endif 3391 (cur->type == XML_HTML_DOCUMENT_NODE)) { 3392 xmlFreeDoc((xmlDocPtr) cur); 3393 return; 3394 } 3395 if (cur->doc != NULL) dict = cur->doc->dict; 3396 while (cur != NULL) { 3397 next = cur->next; 3398 if (cur->type != XML_DTD_NODE) { 3399 3400 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 3401 xmlDeregisterNodeDefaultValue(cur); 3402 3403 if ((cur->children != NULL) && 3404 (cur->type != XML_ENTITY_REF_NODE)) 3405 xmlFreeNodeList(cur->children); 3406 if (((cur->type == XML_ELEMENT_NODE) || 3407 (cur->type == XML_XINCLUDE_START) || 3408 (cur->type == XML_XINCLUDE_END)) && 3409 (cur->properties != NULL)) 3410 xmlFreePropList(cur->properties); 3411 if ((cur->type != XML_ELEMENT_NODE) && 3412 (cur->type != XML_XINCLUDE_START) && 3413 (cur->type != XML_XINCLUDE_END) && 3414 (cur->type != XML_ENTITY_REF_NODE) && 3415 (cur->content != (xmlChar *) &(cur->properties))) { 3416 DICT_FREE(cur->content) 3417 } 3418 if (((cur->type == XML_ELEMENT_NODE) || 3419 (cur->type == XML_XINCLUDE_START) || 3420 (cur->type == XML_XINCLUDE_END)) && 3421 (cur->nsDef != NULL)) 3422 xmlFreeNsList(cur->nsDef); 3423 3424 /* 3425 * When a node is a text node or a comment, it uses a global static 3426 * variable for the name of the node. 3427 * Otherwise the node name might come from the document's 3428 * dictionnary 3429 */ 3430 if ((cur->name != NULL) && 3431 (cur->type != XML_TEXT_NODE) && 3432 (cur->type != XML_COMMENT_NODE)) 3433 DICT_FREE(cur->name) 3434 xmlFree(cur); 3435 } 3436 cur = next; 3437 } 3438} 3439 3440/** 3441 * xmlFreeNode: 3442 * @cur: the node 3443 * 3444 * Free a node, this is a recursive behaviour, all the children are freed too. 3445 * This doesn't unlink the child from the list, use xmlUnlinkNode() first. 3446 */ 3447void 3448xmlFreeNode(xmlNodePtr cur) { 3449 xmlDictPtr dict = NULL; 3450 3451 if (cur == NULL) return; 3452 3453 /* use xmlFreeDtd for DTD nodes */ 3454 if (cur->type == XML_DTD_NODE) { 3455 xmlFreeDtd((xmlDtdPtr) cur); 3456 return; 3457 } 3458 if (cur->type == XML_NAMESPACE_DECL) { 3459 xmlFreeNs((xmlNsPtr) cur); 3460 return; 3461 } 3462 if (cur->type == XML_ATTRIBUTE_NODE) { 3463 xmlFreeProp((xmlAttrPtr) cur); 3464 return; 3465 } 3466 3467 if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) 3468 xmlDeregisterNodeDefaultValue(cur); 3469 3470 if (cur->doc != NULL) dict = cur->doc->dict; 3471 3472 if (cur->type == XML_ENTITY_DECL) { 3473 xmlEntityPtr ent = (xmlEntityPtr) cur; 3474 DICT_FREE(ent->SystemID); 3475 DICT_FREE(ent->ExternalID); 3476 } 3477 if ((cur->children != NULL) && 3478 (cur->type != XML_ENTITY_REF_NODE)) 3479 xmlFreeNodeList(cur->children); 3480 if (((cur->type == XML_ELEMENT_NODE) || 3481 (cur->type == XML_XINCLUDE_START) || 3482 (cur->type == XML_XINCLUDE_END)) && 3483 (cur->properties != NULL)) 3484 xmlFreePropList(cur->properties); 3485 if ((cur->type != XML_ELEMENT_NODE) && 3486 (cur->content != NULL) && 3487 (cur->type != XML_ENTITY_REF_NODE) && 3488 (cur->type != XML_XINCLUDE_END) && 3489 (cur->type != XML_XINCLUDE_START) && 3490 (cur->content != (xmlChar *) &(cur->properties))) { 3491 DICT_FREE(cur->content) 3492 } 3493 3494 /* 3495 * When a node is a text node or a comment, it uses a global static 3496 * variable for the name of the node. 3497 * Otherwise the node name might come from the document's dictionnary 3498 */ 3499 if ((cur->name != NULL) && 3500 (cur->type != XML_TEXT_NODE) && 3501 (cur->type != XML_COMMENT_NODE)) 3502 DICT_FREE(cur->name) 3503 3504 if (((cur->type == XML_ELEMENT_NODE) || 3505 (cur->type == XML_XINCLUDE_START) || 3506 (cur->type == XML_XINCLUDE_END)) && 3507 (cur->nsDef != NULL)) 3508 xmlFreeNsList(cur->nsDef); 3509 xmlFree(cur); 3510} 3511 3512/** 3513 * xmlUnlinkNode: 3514 * @cur: the node 3515 * 3516 * Unlink a node from it's current context, the node is not freed 3517 */ 3518void 3519xmlUnlinkNode(xmlNodePtr cur) { 3520 if (cur == NULL) { 3521#ifdef DEBUG_TREE 3522 xmlGenericError(xmlGenericErrorContext, 3523 "xmlUnlinkNode : node == NULL\n"); 3524#endif 3525 return; 3526 } 3527 if (cur->type == XML_DTD_NODE) { 3528 xmlDocPtr doc; 3529 doc = cur->doc; 3530 if (doc != NULL) { 3531 if (doc->intSubset == (xmlDtdPtr) cur) 3532 doc->intSubset = NULL; 3533 if (doc->extSubset == (xmlDtdPtr) cur) 3534 doc->extSubset = NULL; 3535 } 3536 } 3537 if (cur->type == XML_ENTITY_DECL) { 3538 xmlDocPtr doc; 3539 doc = cur->doc; 3540 if (doc != NULL) { 3541 if (doc->intSubset != NULL) { 3542 if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur) 3543 xmlHashRemoveEntry(doc->intSubset->entities, cur->name, 3544 NULL); 3545 if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur) 3546 xmlHashRemoveEntry(doc->intSubset->pentities, cur->name, 3547 NULL); 3548 } 3549 if (doc->extSubset != NULL) { 3550 if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur) 3551 xmlHashRemoveEntry(doc->extSubset->entities, cur->name, 3552 NULL); 3553 if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur) 3554 xmlHashRemoveEntry(doc->extSubset->pentities, cur->name, 3555 NULL); 3556 } 3557 } 3558 } 3559 if (cur->parent != NULL) { 3560 xmlNodePtr parent; 3561 parent = cur->parent; 3562 if (cur->type == XML_ATTRIBUTE_NODE) { 3563 if (parent->properties == (xmlAttrPtr) cur) 3564 parent->properties = ((xmlAttrPtr) cur)->next; 3565 } else { 3566 if (parent->children == cur) 3567 parent->children = cur->next; 3568 if (parent->last == cur) 3569 parent->last = cur->prev; 3570 } 3571 cur->parent = NULL; 3572 } 3573 if (cur->next != NULL) 3574 cur->next->prev = cur->prev; 3575 if (cur->prev != NULL) 3576 cur->prev->next = cur->next; 3577 cur->next = cur->prev = NULL; 3578} 3579 3580#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) 3581/** 3582 * xmlReplaceNode: 3583 * @old: the old node 3584 * @cur: the node 3585 * 3586 * Unlink the old node from its current context, prune the new one 3587 * at the same place. If @cur was already inserted in a document it is 3588 * first unlinked from its existing context. 3589 * 3590 * Returns the @old node 3591 */ 3592xmlNodePtr 3593xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { 3594 if (old == cur) return(NULL); 3595 if ((old == NULL) || (old->parent == NULL)) { 3596#ifdef DEBUG_TREE 3597 xmlGenericError(xmlGenericErrorContext, 3598 "xmlReplaceNode : old == NULL or without parent\n"); 3599#endif 3600 return(NULL); 3601 } 3602 if (cur == NULL) { 3603 xmlUnlinkNode(old); 3604 return(old); 3605 } 3606 if (cur == old) { 3607 return(old); 3608 } 3609 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) { 3610#ifdef DEBUG_TREE 3611 xmlGenericError(xmlGenericErrorContext, 3612 "xmlReplaceNode : Trying to replace attribute node with other node type\n"); 3613#endif 3614 return(old); 3615 } 3616 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) { 3617#ifdef DEBUG_TREE 3618 xmlGenericError(xmlGenericErrorContext, 3619 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n"); 3620#endif 3621 return(old); 3622 } 3623 xmlUnlinkNode(cur); 3624 xmlSetTreeDoc(cur, old->doc); 3625 cur->parent = old->parent; 3626 cur->next = old->next; 3627 if (cur->next != NULL) 3628 cur->next->prev = cur; 3629 cur->prev = old->prev; 3630 if (cur->prev != NULL) 3631 cur->prev->next = cur; 3632 if (cur->parent != NULL) { 3633 if (cur->type == XML_ATTRIBUTE_NODE) { 3634 if (cur->parent->properties == (xmlAttrPtr)old) 3635 cur->parent->properties = ((xmlAttrPtr) cur); 3636 } else { 3637 if (cur->parent->children == old) 3638 cur->parent->children = cur; 3639 if (cur->parent->last == old) 3640 cur->parent->last = cur; 3641 } 3642 } 3643 old->next = old->prev = NULL; 3644 old->parent = NULL; 3645 return(old); 3646} 3647#endif /* LIBXML_TREE_ENABLED */ 3648 3649/************************************************************************ 3650 * * 3651 * Copy operations * 3652 * * 3653 ************************************************************************/ 3654 3655/** 3656 * xmlCopyNamespace: 3657 * @cur: the namespace 3658 * 3659 * Do a copy of the namespace. 3660 * 3661 * Returns: a new #xmlNsPtr, or NULL in case of error. 3662 */ 3663xmlNsPtr 3664xmlCopyNamespace(xmlNsPtr cur) { 3665 xmlNsPtr ret; 3666 3667 if (cur == NULL) return(NULL); 3668 switch (cur->type) { 3669 case XML_LOCAL_NAMESPACE: 3670 ret = xmlNewNs(NULL, cur->href, cur->prefix); 3671 break; 3672 default: 3673#ifdef DEBUG_TREE 3674 xmlGenericError(xmlGenericErrorContext, 3675 "xmlCopyNamespace: invalid type %d\n", cur->type); 3676#endif 3677 return(NULL); 3678 } 3679 return(ret); 3680} 3681 3682/** 3683 * xmlCopyNamespaceList: 3684 * @cur: the first namespace 3685 * 3686 * Do a copy of an namespace list. 3687 * 3688 * Returns: a new #xmlNsPtr, or NULL in case of error. 3689 */ 3690xmlNsPtr 3691xmlCopyNamespaceList(xmlNsPtr cur) { 3692 xmlNsPtr ret = NULL; 3693 xmlNsPtr p = NULL,q; 3694 3695 while (cur != NULL) { 3696 q = xmlCopyNamespace(cur); 3697 if (p == NULL) { 3698 ret = p = q; 3699 } else { 3700 p->next = q; 3701 p = q; 3702 } 3703 cur = cur->next; 3704 } 3705 return(ret); 3706} 3707 3708static xmlNodePtr 3709xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent); 3710 3711static xmlAttrPtr 3712xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { 3713 xmlAttrPtr ret; 3714 3715 if (cur == NULL) return(NULL); 3716 if (target != NULL) 3717 ret = xmlNewDocProp(target->doc, cur->name, NULL); 3718 else if (doc != NULL) 3719 ret = xmlNewDocProp(doc, cur->name, NULL); 3720 else if (cur->parent != NULL) 3721 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL); 3722 else if (cur->children != NULL) 3723 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL); 3724 else 3725 ret = xmlNewDocProp(NULL, cur->name, NULL); 3726 if (ret == NULL) return(NULL); 3727 ret->parent = target; 3728 3729 if ((cur->ns != NULL) && (target != NULL)) { 3730 xmlNsPtr ns; 3731 3732 ns = xmlSearchNs(target->doc, target, cur->ns->prefix); 3733 if (ns == NULL) { 3734 /* 3735 * Humm, we are copying an element whose namespace is defined 3736 * out of the new tree scope. Search it in the original tree 3737 * and add it at the top of the new tree 3738 */ 3739 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix); 3740 if (ns != NULL) { 3741 xmlNodePtr root = target; 3742 xmlNodePtr pred = NULL; 3743 3744 while (root->parent != NULL) { 3745 pred = root; 3746 root = root->parent; 3747 } 3748 if (root == (xmlNodePtr) target->doc) { 3749 /* correct possibly cycling above the document elt */ 3750 root = pred; 3751 } 3752 ret->ns = xmlNewNs(root, ns->href, ns->prefix); 3753 } 3754 } else { 3755 /* 3756 * we have to find something appropriate here since 3757 * we cant be sure, that the namespce we found is identified 3758 * by the prefix 3759 */ 3760 if (xmlStrEqual(ns->href, cur->ns->href)) { 3761 /* this is the nice case */ 3762 ret->ns = ns; 3763 } else { 3764 /* 3765 * we are in trouble: we need a new reconcilied namespace. 3766 * This is expensive 3767 */ 3768 ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns); 3769 } 3770 } 3771 3772 } else 3773 ret->ns = NULL; 3774 3775 if (cur->children != NULL) { 3776 xmlNodePtr tmp; 3777 3778 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret); 3779 ret->last = NULL; 3780 tmp = ret->children; 3781 while (tmp != NULL) { 3782 /* tmp->parent = (xmlNodePtr)ret; */ 3783 if (tmp->next == NULL) 3784 ret->last = tmp; 3785 tmp = tmp->next; 3786 } 3787 } 3788 /* 3789 * Try to handle IDs 3790 */ 3791 if ((target!= NULL) && (cur!= NULL) && 3792 (target->doc != NULL) && (cur->doc != NULL) && 3793 (cur->doc->ids != NULL) && (cur->parent != NULL)) { 3794 if (xmlIsID(cur->doc, cur->parent, cur)) { 3795 xmlChar *id; 3796 3797 id = xmlNodeListGetString(cur->doc, cur->children, 1); 3798 if (id != NULL) { 3799 xmlAddID(NULL, target->doc, id, ret); 3800 xmlFree(id); 3801 } 3802 } 3803 } 3804 return(ret); 3805} 3806 3807/** 3808 * xmlCopyProp: 3809 * @target: the element where the attribute will be grafted 3810 * @cur: the attribute 3811 * 3812 * Do a copy of the attribute. 3813 * 3814 * Returns: a new #xmlAttrPtr, or NULL in case of error. 3815 */ 3816xmlAttrPtr 3817xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { 3818 return xmlCopyPropInternal(NULL, target, cur); 3819} 3820 3821/** 3822 * xmlCopyPropList: 3823 * @target: the element where the attributes will be grafted 3824 * @cur: the first attribute 3825 * 3826 * Do a copy of an attribute list. 3827 * 3828 * Returns: a new #xmlAttrPtr, or NULL in case of error. 3829 */ 3830xmlAttrPtr 3831xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { 3832 xmlAttrPtr ret = NULL; 3833 xmlAttrPtr p = NULL,q; 3834 3835 while (cur != NULL) { 3836 q = xmlCopyProp(target, cur); 3837 if (q == NULL) 3838 return(NULL); 3839 if (p == NULL) { 3840 ret = p = q; 3841 } else { 3842 p->next = q; 3843 q->prev = p; 3844 p = q; 3845 } 3846 cur = cur->next; 3847 } 3848 return(ret); 3849} 3850 3851/* 3852 * NOTE about the CopyNode operations ! 3853 * 3854 * They are split into external and internal parts for one 3855 * tricky reason: namespaces. Doing a direct copy of a node 3856 * say RPM:Copyright without changing the namespace pointer to 3857 * something else can produce stale links. One way to do it is 3858 * to keep a reference counter but this doesn't work as soon 3859 * as one move the element or the subtree out of the scope of 3860 * the existing namespace. The actual solution seems to add 3861 * a copy of the namespace at the top of the copied tree if 3862 * not available in the subtree. 3863 * Hence two functions, the public front-end call the inner ones 3864 * The argument "recursive" normally indicates a recursive copy 3865 * of the node with values 0 (no) and 1 (yes). For XInclude, 3866 * however, we allow a value of 2 to indicate copy properties and 3867 * namespace info, but don't recurse on children. 3868 */ 3869 3870static xmlNodePtr 3871xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, 3872 int extended) { 3873 xmlNodePtr ret; 3874 3875 if (node == NULL) return(NULL); 3876 switch (node->type) { 3877 case XML_TEXT_NODE: 3878 case XML_CDATA_SECTION_NODE: 3879 case XML_ELEMENT_NODE: 3880 case XML_DOCUMENT_FRAG_NODE: 3881 case XML_ENTITY_REF_NODE: 3882 case XML_ENTITY_NODE: 3883 case XML_PI_NODE: 3884 case XML_COMMENT_NODE: 3885 case XML_XINCLUDE_START: 3886 case XML_XINCLUDE_END: 3887 break; 3888 case XML_ATTRIBUTE_NODE: 3889 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node)); 3890 case XML_NAMESPACE_DECL: 3891 return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node)); 3892 3893 case XML_DOCUMENT_NODE: 3894 case XML_HTML_DOCUMENT_NODE: 3895#ifdef LIBXML_DOCB_ENABLED 3896 case XML_DOCB_DOCUMENT_NODE: 3897#endif 3898#ifdef LIBXML_TREE_ENABLED 3899 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended)); 3900#endif /* LIBXML_TREE_ENABLED */ 3901 case XML_DOCUMENT_TYPE_NODE: 3902 case XML_NOTATION_NODE: 3903 case XML_DTD_NODE: 3904 case XML_ELEMENT_DECL: 3905 case XML_ATTRIBUTE_DECL: 3906 case XML_ENTITY_DECL: 3907 return(NULL); 3908 } 3909 3910 /* 3911 * Allocate a new node and fill the fields. 3912 */ 3913 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 3914 if (ret == NULL) { 3915 xmlTreeErrMemory("copying node"); 3916 return(NULL); 3917 } 3918 memset(ret, 0, sizeof(xmlNode)); 3919 ret->type = node->type; 3920 3921 ret->doc = doc; 3922 ret->parent = parent; 3923 if (node->name == xmlStringText) 3924 ret->name = xmlStringText; 3925 else if (node->name == xmlStringTextNoenc) 3926 ret->name = xmlStringTextNoenc; 3927 else if (node->name == xmlStringComment) 3928 ret->name = xmlStringComment; 3929 else if (node->name != NULL) { 3930 if ((doc != NULL) && (doc->dict != NULL)) 3931 ret->name = xmlDictLookup(doc->dict, node->name, -1); 3932 else 3933 ret->name = xmlStrdup(node->name); 3934 } 3935 if ((node->type != XML_ELEMENT_NODE) && 3936 (node->content != NULL) && 3937 (node->type != XML_ENTITY_REF_NODE) && 3938 (node->type != XML_XINCLUDE_END) && 3939 (node->type != XML_XINCLUDE_START)) { 3940 ret->content = xmlStrdup(node->content); 3941 }else{ 3942 if (node->type == XML_ELEMENT_NODE) 3943 ret->line = node->line; 3944 } 3945 if (parent != NULL) { 3946 xmlNodePtr tmp; 3947 3948 /* 3949 * this is a tricky part for the node register thing: 3950 * in case ret does get coalesced in xmlAddChild 3951 * the deregister-node callback is called; so we register ret now already 3952 */ 3953 if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) 3954 xmlRegisterNodeDefaultValue((xmlNodePtr)ret); 3955 3956 tmp = xmlAddChild(parent, ret); 3957 /* node could have coalesced */ 3958 if (tmp != ret) 3959 return(tmp); 3960 } 3961 3962 if (!extended) 3963 goto out; 3964 if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL)) 3965 ret->nsDef = xmlCopyNamespaceList(node->nsDef); 3966 3967 if (node->ns != NULL) { 3968 xmlNsPtr ns; 3969 3970 ns = xmlSearchNs(doc, ret, node->ns->prefix); 3971 if (ns == NULL) { 3972 /* 3973 * Humm, we are copying an element whose namespace is defined 3974 * out of the new tree scope. Search it in the original tree 3975 * and add it at the top of the new tree 3976 */ 3977 ns = xmlSearchNs(node->doc, node, node->ns->prefix); 3978 if (ns != NULL) { 3979 xmlNodePtr root = ret; 3980 3981 while (root->parent != NULL) root = root->parent; 3982 ret->ns = xmlNewNs(root, ns->href, ns->prefix); 3983 } 3984 } else { 3985 /* 3986 * reference the existing namespace definition in our own tree. 3987 */ 3988 ret->ns = ns; 3989 } 3990 } 3991 if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL)) 3992 ret->properties = xmlCopyPropList(ret, node->properties); 3993 if (node->type == XML_ENTITY_REF_NODE) { 3994 if ((doc == NULL) || (node->doc != doc)) { 3995 /* 3996 * The copied node will go into a separate document, so 3997 * to avoid dangling references to the ENTITY_DECL node 3998 * we cannot keep the reference. Try to find it in the 3999 * target document. 4000 */ 4001 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name); 4002 } else { 4003 ret->children = node->children; 4004 } 4005 ret->last = ret->children; 4006 } else if ((node->children != NULL) && (extended != 2)) { 4007 ret->children = xmlStaticCopyNodeList(node->children, doc, ret); 4008 UPDATE_LAST_CHILD_AND_PARENT(ret) 4009 } 4010 4011out: 4012 /* if parent != NULL we already registered the node above */ 4013 if ((parent == NULL) && 4014 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))) 4015 xmlRegisterNodeDefaultValue((xmlNodePtr)ret); 4016 return(ret); 4017} 4018 4019static xmlNodePtr 4020xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { 4021 xmlNodePtr ret = NULL; 4022 xmlNodePtr p = NULL,q; 4023 4024 while (node != NULL) { 4025#ifdef LIBXML_TREE_ENABLED 4026 if (node->type == XML_DTD_NODE ) { 4027 if (doc == NULL) { 4028 node = node->next; 4029 continue; 4030 } 4031 if (doc->intSubset == NULL) { 4032 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node ); 4033 q->doc = doc; 4034 q->parent = parent; 4035 doc->intSubset = (xmlDtdPtr) q; 4036 xmlAddChild(parent, q); 4037 } else { 4038 q = (xmlNodePtr) doc->intSubset; 4039 xmlAddChild(parent, q); 4040 } 4041 } else 4042#endif /* LIBXML_TREE_ENABLED */ 4043 q = xmlStaticCopyNode(node, doc, parent, 1); 4044 if (ret == NULL) { 4045 q->prev = NULL; 4046 ret = p = q; 4047 } else if (p != q) { 4048 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */ 4049 p->next = q; 4050 q->prev = p; 4051 p = q; 4052 } 4053 node = node->next; 4054 } 4055 return(ret); 4056} 4057 4058/** 4059 * xmlCopyNode: 4060 * @node: the node 4061 * @extended: if 1 do a recursive copy (properties, namespaces and children 4062 * when applicable) 4063 * if 2 copy properties and namespaces (when applicable) 4064 * 4065 * Do a copy of the node. 4066 * 4067 * Returns: a new #xmlNodePtr, or NULL in case of error. 4068 */ 4069xmlNodePtr 4070xmlCopyNode(const xmlNodePtr node, int extended) { 4071 xmlNodePtr ret; 4072 4073 ret = xmlStaticCopyNode(node, NULL, NULL, extended); 4074 return(ret); 4075} 4076 4077/** 4078 * xmlDocCopyNode: 4079 * @node: the node 4080 * @doc: the document 4081 * @extended: if 1 do a recursive copy (properties, namespaces and children 4082 * when applicable) 4083 * if 2 copy properties and namespaces (when applicable) 4084 * 4085 * Do a copy of the node to a given document. 4086 * 4087 * Returns: a new #xmlNodePtr, or NULL in case of error. 4088 */ 4089xmlNodePtr 4090xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) { 4091 xmlNodePtr ret; 4092 4093 ret = xmlStaticCopyNode(node, doc, NULL, extended); 4094 return(ret); 4095} 4096 4097/** 4098 * xmlDocCopyNodeList: 4099 * @doc: the target document 4100 * @node: the first node in the list. 4101 * 4102 * Do a recursive copy of the node list. 4103 * 4104 * Returns: a new #xmlNodePtr, or NULL in case of error. 4105 */ 4106xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) { 4107 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL); 4108 return(ret); 4109} 4110 4111/** 4112 * xmlCopyNodeList: 4113 * @node: the first node in the list. 4114 * 4115 * Do a recursive copy of the node list. 4116 * Use xmlDocCopyNodeList() if possible to ensure string interning. 4117 * 4118 * Returns: a new #xmlNodePtr, or NULL in case of error. 4119 */ 4120xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) { 4121 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL); 4122 return(ret); 4123} 4124 4125#if defined(LIBXML_TREE_ENABLED) 4126/** 4127 * xmlCopyDtd: 4128 * @dtd: the dtd 4129 * 4130 * Do a copy of the dtd. 4131 * 4132 * Returns: a new #xmlDtdPtr, or NULL in case of error. 4133 */ 4134xmlDtdPtr 4135xmlCopyDtd(xmlDtdPtr dtd) { 4136 xmlDtdPtr ret; 4137 xmlNodePtr cur, p = NULL, q; 4138 4139 if (dtd == NULL) return(NULL); 4140 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID); 4141 if (ret == NULL) return(NULL); 4142 if (dtd->entities != NULL) 4143 ret->entities = (void *) xmlCopyEntitiesTable( 4144 (xmlEntitiesTablePtr) dtd->entities); 4145 if (dtd->notations != NULL) 4146 ret->notations = (void *) xmlCopyNotationTable( 4147 (xmlNotationTablePtr) dtd->notations); 4148 if (dtd->elements != NULL) 4149 ret->elements = (void *) xmlCopyElementTable( 4150 (xmlElementTablePtr) dtd->elements); 4151 if (dtd->attributes != NULL) 4152 ret->attributes = (void *) xmlCopyAttributeTable( 4153 (xmlAttributeTablePtr) dtd->attributes); 4154 if (dtd->pentities != NULL) 4155 ret->pentities = (void *) xmlCopyEntitiesTable( 4156 (xmlEntitiesTablePtr) dtd->pentities); 4157 4158 cur = dtd->children; 4159 while (cur != NULL) { 4160 q = NULL; 4161 4162 if (cur->type == XML_ENTITY_DECL) { 4163 xmlEntityPtr tmp = (xmlEntityPtr) cur; 4164 switch (tmp->etype) { 4165 case XML_INTERNAL_GENERAL_ENTITY: 4166 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 4167 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 4168 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name); 4169 break; 4170 case XML_INTERNAL_PARAMETER_ENTITY: 4171 case XML_EXTERNAL_PARAMETER_ENTITY: 4172 q = (xmlNodePtr) 4173 xmlGetParameterEntityFromDtd(ret, tmp->name); 4174 break; 4175 case XML_INTERNAL_PREDEFINED_ENTITY: 4176 break; 4177 } 4178 } else if (cur->type == XML_ELEMENT_DECL) { 4179 xmlElementPtr tmp = (xmlElementPtr) cur; 4180 q = (xmlNodePtr) 4181 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix); 4182 } else if (cur->type == XML_ATTRIBUTE_DECL) { 4183 xmlAttributePtr tmp = (xmlAttributePtr) cur; 4184 q = (xmlNodePtr) 4185 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix); 4186 } else if (cur->type == XML_COMMENT_NODE) { 4187 q = xmlCopyNode(cur, 0); 4188 } 4189 4190 if (q == NULL) { 4191 cur = cur->next; 4192 continue; 4193 } 4194 4195 if (p == NULL) 4196 ret->children = q; 4197 else 4198 p->next = q; 4199 4200 q->prev = p; 4201 q->parent = (xmlNodePtr) ret; 4202 q->next = NULL; 4203 ret->last = q; 4204 p = q; 4205 cur = cur->next; 4206 } 4207 4208 return(ret); 4209} 4210#endif 4211 4212#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 4213/** 4214 * xmlCopyDoc: 4215 * @doc: the document 4216 * @recursive: if not zero do a recursive copy. 4217 * 4218 * Do a copy of the document info. If recursive, the content tree will 4219 * be copied too as well as DTD, namespaces and entities. 4220 * 4221 * Returns: a new #xmlDocPtr, or NULL in case of error. 4222 */ 4223xmlDocPtr 4224xmlCopyDoc(xmlDocPtr doc, int recursive) { 4225 xmlDocPtr ret; 4226 4227 if (doc == NULL) return(NULL); 4228 ret = xmlNewDoc(doc->version); 4229 if (ret == NULL) return(NULL); 4230 if (doc->name != NULL) 4231 ret->name = xmlMemStrdup(doc->name); 4232 if (doc->encoding != NULL) 4233 ret->encoding = xmlStrdup(doc->encoding); 4234 if (doc->URL != NULL) 4235 ret->URL = xmlStrdup(doc->URL); 4236 ret->charset = doc->charset; 4237 ret->compression = doc->compression; 4238 ret->standalone = doc->standalone; 4239 if (!recursive) return(ret); 4240 4241 ret->last = NULL; 4242 ret->children = NULL; 4243#ifdef LIBXML_TREE_ENABLED 4244 if (doc->intSubset != NULL) { 4245 ret->intSubset = xmlCopyDtd(doc->intSubset); 4246 xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret); 4247 ret->intSubset->parent = ret; 4248 } 4249#endif 4250 if (doc->oldNs != NULL) 4251 ret->oldNs = xmlCopyNamespaceList(doc->oldNs); 4252 if (doc->children != NULL) { 4253 xmlNodePtr tmp; 4254 4255 ret->children = xmlStaticCopyNodeList(doc->children, ret, 4256 (xmlNodePtr)ret); 4257 ret->last = NULL; 4258 tmp = ret->children; 4259 while (tmp != NULL) { 4260 if (tmp->next == NULL) 4261 ret->last = tmp; 4262 tmp = tmp->next; 4263 } 4264 } 4265 return(ret); 4266} 4267#endif /* LIBXML_TREE_ENABLED */ 4268 4269/************************************************************************ 4270 * * 4271 * Content access functions * 4272 * * 4273 ************************************************************************/ 4274 4275/** 4276 * xmlGetLineNo: 4277 * @node: valid node 4278 * 4279 * Get line number of @node. This requires activation of this option 4280 * before invoking the parser by calling xmlLineNumbersDefault(1) 4281 * 4282 * Returns the line number if successful, -1 otherwise 4283 */ 4284long 4285xmlGetLineNo(xmlNodePtr node) 4286{ 4287 long result = -1; 4288 4289 if (!node) 4290 return result; 4291 if ((node->type == XML_ELEMENT_NODE) || 4292 (node->type == XML_TEXT_NODE) || 4293 (node->type == XML_COMMENT_NODE) || 4294 (node->type == XML_PI_NODE)) 4295 result = (long) node->line; 4296 else if ((node->prev != NULL) && 4297 ((node->prev->type == XML_ELEMENT_NODE) || 4298 (node->prev->type == XML_TEXT_NODE) || 4299 (node->prev->type == XML_COMMENT_NODE) || 4300 (node->prev->type == XML_PI_NODE))) 4301 result = xmlGetLineNo(node->prev); 4302 else if ((node->parent != NULL) && 4303 (node->parent->type == XML_ELEMENT_NODE)) 4304 result = xmlGetLineNo(node->parent); 4305 4306 return result; 4307} 4308 4309#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) 4310/** 4311 * xmlGetNodePath: 4312 * @node: a node 4313 * 4314 * Build a structure based Path for the given node 4315 * 4316 * Returns the new path or NULL in case of error. The caller must free 4317 * the returned string 4318 */ 4319xmlChar * 4320xmlGetNodePath(xmlNodePtr node) 4321{ 4322 xmlNodePtr cur, tmp, next; 4323 xmlChar *buffer = NULL, *temp; 4324 size_t buf_len; 4325 xmlChar *buf; 4326 const char *sep; 4327 const char *name; 4328 char nametemp[100]; 4329 int occur = 0, generic; 4330 4331 if (node == NULL) 4332 return (NULL); 4333 4334 buf_len = 500; 4335 buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); 4336 if (buffer == NULL) { 4337 xmlTreeErrMemory("getting node path"); 4338 return (NULL); 4339 } 4340 buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); 4341 if (buf == NULL) { 4342 xmlTreeErrMemory("getting node path"); 4343 xmlFree(buffer); 4344 return (NULL); 4345 } 4346 4347 buffer[0] = 0; 4348 cur = node; 4349 do { 4350 name = ""; 4351 sep = "?"; 4352 occur = 0; 4353 if ((cur->type == XML_DOCUMENT_NODE) || 4354 (cur->type == XML_HTML_DOCUMENT_NODE)) { 4355 if (buffer[0] == '/') 4356 break; 4357 sep = "/"; 4358 next = NULL; 4359 } else if (cur->type == XML_ELEMENT_NODE) { 4360 generic = 0; 4361 sep = "/"; 4362 name = (const char *) cur->name; 4363 if (cur->ns) { 4364 if (cur->ns->prefix != NULL) { 4365 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", 4366 (char *)cur->ns->prefix, (char *)cur->name); 4367 nametemp[sizeof(nametemp) - 1] = 0; 4368 name = nametemp; 4369 } else { 4370 /* 4371 * We cannot express named elements in the default 4372 * namespace, so use "*". 4373 */ 4374 generic = 1; 4375 name = "*"; 4376 } 4377 } 4378 next = cur->parent; 4379 4380 /* 4381 * Thumbler index computation 4382 * TODO: the ocurence test seems bogus for namespaced names 4383 */ 4384 tmp = cur->prev; 4385 while (tmp != NULL) { 4386 if ((tmp->type == XML_ELEMENT_NODE) && 4387 (generic || 4388 (xmlStrEqual(cur->name, tmp->name) && 4389 ((tmp->ns == cur->ns) || 4390 ((tmp->ns != NULL) && (cur->ns != NULL) && 4391 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) 4392 occur++; 4393 tmp = tmp->prev; 4394 } 4395 if (occur == 0) { 4396 tmp = cur->next; 4397 while (tmp != NULL && occur == 0) { 4398 if ((tmp->type == XML_ELEMENT_NODE) && 4399 (generic || 4400 (xmlStrEqual(cur->name, tmp->name) && 4401 ((tmp->ns == cur->ns) || 4402 ((tmp->ns != NULL) && (cur->ns != NULL) && 4403 (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) 4404 occur++; 4405 tmp = tmp->next; 4406 } 4407 if (occur != 0) 4408 occur = 1; 4409 } else 4410 occur++; 4411 } else if (cur->type == XML_COMMENT_NODE) { 4412 sep = "/"; 4413 name = "comment()"; 4414 next = cur->parent; 4415 4416 /* 4417 * Thumbler index computation 4418 */ 4419 tmp = cur->prev; 4420 while (tmp != NULL) { 4421 if (tmp->type == XML_COMMENT_NODE) 4422 occur++; 4423 tmp = tmp->prev; 4424 } 4425 if (occur == 0) { 4426 tmp = cur->next; 4427 while (tmp != NULL && occur == 0) { 4428 if (tmp->type == XML_COMMENT_NODE) 4429 occur++; 4430 tmp = tmp->next; 4431 } 4432 if (occur != 0) 4433 occur = 1; 4434 } else 4435 occur++; 4436 } else if ((cur->type == XML_TEXT_NODE) || 4437 (cur->type == XML_CDATA_SECTION_NODE)) { 4438 sep = "/"; 4439 name = "text()"; 4440 next = cur->parent; 4441 4442 /* 4443 * Thumbler index computation 4444 */ 4445 tmp = cur->prev; 4446 while (tmp != NULL) { 4447 if ((tmp->type == XML_TEXT_NODE) || 4448 (tmp->type == XML_CDATA_SECTION_NODE)) 4449 occur++; 4450 tmp = tmp->prev; 4451 } 4452 /* 4453 * Evaluate if this is the only text- or CDATA-section-node; 4454 * if yes, then we'll get "text()", otherwise "text()[1]". 4455 */ 4456 if (occur == 0) { 4457 tmp = cur->next; 4458 while (tmp != NULL) { 4459 if ((tmp->type == XML_TEXT_NODE) || 4460 (tmp->type == XML_CDATA_SECTION_NODE)) 4461 { 4462 occur = 1; 4463 break; 4464 } 4465 tmp = tmp->next; 4466 } 4467 } else 4468 occur++; 4469 } else if (cur->type == XML_PI_NODE) { 4470 sep = "/"; 4471 snprintf(nametemp, sizeof(nametemp) - 1, 4472 "processing-instruction('%s')", (char *)cur->name); 4473 nametemp[sizeof(nametemp) - 1] = 0; 4474 name = nametemp; 4475 4476 next = cur->parent; 4477 4478 /* 4479 * Thumbler index computation 4480 */ 4481 tmp = cur->prev; 4482 while (tmp != NULL) { 4483 if ((tmp->type == XML_PI_NODE) && 4484 (xmlStrEqual(cur->name, tmp->name))) 4485 occur++; 4486 tmp = tmp->prev; 4487 } 4488 if (occur == 0) { 4489 tmp = cur->next; 4490 while (tmp != NULL && occur == 0) { 4491 if ((tmp->type == XML_PI_NODE) && 4492 (xmlStrEqual(cur->name, tmp->name))) 4493 occur++; 4494 tmp = tmp->next; 4495 } 4496 if (occur != 0) 4497 occur = 1; 4498 } else 4499 occur++; 4500 4501 } else if (cur->type == XML_ATTRIBUTE_NODE) { 4502 sep = "/@"; 4503 name = (const char *) (((xmlAttrPtr) cur)->name); 4504 if (cur->ns) { 4505 if (cur->ns->prefix != NULL) 4506 snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", 4507 (char *)cur->ns->prefix, (char *)cur->name); 4508 else 4509 snprintf(nametemp, sizeof(nametemp) - 1, "%s", 4510 (char *)cur->name); 4511 nametemp[sizeof(nametemp) - 1] = 0; 4512 name = nametemp; 4513 } 4514 next = ((xmlAttrPtr) cur)->parent; 4515 } else { 4516 next = cur->parent; 4517 } 4518 4519 /* 4520 * Make sure there is enough room 4521 */ 4522 if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) { 4523 buf_len = 4524 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20; 4525 temp = (xmlChar *) xmlRealloc(buffer, buf_len); 4526 if (temp == NULL) { 4527 xmlTreeErrMemory("getting node path"); 4528 xmlFree(buf); 4529 xmlFree(buffer); 4530 return (NULL); 4531 } 4532 buffer = temp; 4533 temp = (xmlChar *) xmlRealloc(buf, buf_len); 4534 if (temp == NULL) { 4535 xmlTreeErrMemory("getting node path"); 4536 xmlFree(buf); 4537 xmlFree(buffer); 4538 return (NULL); 4539 } 4540 buf = temp; 4541 } 4542 if (occur == 0) 4543 snprintf((char *) buf, buf_len, "%s%s%s", 4544 sep, name, (char *) buffer); 4545 else 4546 snprintf((char *) buf, buf_len, "%s%s[%d]%s", 4547 sep, name, occur, (char *) buffer); 4548 snprintf((char *) buffer, buf_len, "%s", (char *)buf); 4549 cur = next; 4550 } while (cur != NULL); 4551 xmlFree(buf); 4552 return (buffer); 4553} 4554#endif /* LIBXML_TREE_ENABLED */ 4555 4556/** 4557 * xmlDocGetRootElement: 4558 * @doc: the document 4559 * 4560 * Get the root element of the document (doc->children is a list 4561 * containing possibly comments, PIs, etc ...). 4562 * 4563 * Returns the #xmlNodePtr for the root or NULL 4564 */ 4565xmlNodePtr 4566xmlDocGetRootElement(xmlDocPtr doc) { 4567 xmlNodePtr ret; 4568 4569 if (doc == NULL) return(NULL); 4570 ret = doc->children; 4571 while (ret != NULL) { 4572 if (ret->type == XML_ELEMENT_NODE) 4573 return(ret); 4574 ret = ret->next; 4575 } 4576 return(ret); 4577} 4578 4579#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) 4580/** 4581 * xmlDocSetRootElement: 4582 * @doc: the document 4583 * @root: the new document root element, if root is NULL no action is taken, 4584 * to remove a node from a document use xmlUnlinkNode(root) instead. 4585 * 4586 * Set the root element of the document (doc->children is a list 4587 * containing possibly comments, PIs, etc ...). 4588 * 4589 * Returns the old root element if any was found, NULL if root was NULL 4590 */ 4591xmlNodePtr 4592xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { 4593 xmlNodePtr old = NULL; 4594 4595 if (doc == NULL) return(NULL); 4596 if (root == NULL) 4597 return(NULL); 4598 xmlUnlinkNode(root); 4599 xmlSetTreeDoc(root, doc); 4600 root->parent = (xmlNodePtr) doc; 4601 old = doc->children; 4602 while (old != NULL) { 4603 if (old->type == XML_ELEMENT_NODE) 4604 break; 4605 old = old->next; 4606 } 4607 if (old == NULL) { 4608 if (doc->children == NULL) { 4609 doc->children = root; 4610 doc->last = root; 4611 } else { 4612 xmlAddSibling(doc->children, root); 4613 } 4614 } else { 4615 xmlReplaceNode(old, root); 4616 } 4617 return(old); 4618} 4619#endif 4620 4621#if defined(LIBXML_TREE_ENABLED) 4622/** 4623 * xmlNodeSetLang: 4624 * @cur: the node being changed 4625 * @lang: the language description 4626 * 4627 * Set the language of a node, i.e. the values of the xml:lang 4628 * attribute. 4629 */ 4630void 4631xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { 4632 xmlNsPtr ns; 4633 4634 if (cur == NULL) return; 4635 switch(cur->type) { 4636 case XML_TEXT_NODE: 4637 case XML_CDATA_SECTION_NODE: 4638 case XML_COMMENT_NODE: 4639 case XML_DOCUMENT_NODE: 4640 case XML_DOCUMENT_TYPE_NODE: 4641 case XML_DOCUMENT_FRAG_NODE: 4642 case XML_NOTATION_NODE: 4643 case XML_HTML_DOCUMENT_NODE: 4644 case XML_DTD_NODE: 4645 case XML_ELEMENT_DECL: 4646 case XML_ATTRIBUTE_DECL: 4647 case XML_ENTITY_DECL: 4648 case XML_PI_NODE: 4649 case XML_ENTITY_REF_NODE: 4650 case XML_ENTITY_NODE: 4651 case XML_NAMESPACE_DECL: 4652#ifdef LIBXML_DOCB_ENABLED 4653 case XML_DOCB_DOCUMENT_NODE: 4654#endif 4655 case XML_XINCLUDE_START: 4656 case XML_XINCLUDE_END: 4657 return; 4658 case XML_ELEMENT_NODE: 4659 case XML_ATTRIBUTE_NODE: 4660 break; 4661 } 4662 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); 4663 if (ns == NULL) 4664 return; 4665 xmlSetNsProp(cur, ns, BAD_CAST "lang", lang); 4666} 4667#endif /* LIBXML_TREE_ENABLED */ 4668 4669/** 4670 * xmlNodeGetLang: 4671 * @cur: the node being checked 4672 * 4673 * Searches the language of a node, i.e. the values of the xml:lang 4674 * attribute or the one carried by the nearest ancestor. 4675 * 4676 * Returns a pointer to the lang value, or NULL if not found 4677 * It's up to the caller to free the memory with xmlFree(). 4678 */ 4679xmlChar * 4680xmlNodeGetLang(xmlNodePtr cur) { 4681 xmlChar *lang; 4682 4683 while (cur != NULL) { 4684 lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE); 4685 if (lang != NULL) 4686 return(lang); 4687 cur = cur->parent; 4688 } 4689 return(NULL); 4690} 4691 4692 4693#ifdef LIBXML_TREE_ENABLED 4694/** 4695 * xmlNodeSetSpacePreserve: 4696 * @cur: the node being changed 4697 * @val: the xml:space value ("0": default, 1: "preserve") 4698 * 4699 * Set (or reset) the space preserving behaviour of a node, i.e. the 4700 * value of the xml:space attribute. 4701 */ 4702void 4703xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { 4704 xmlNsPtr ns; 4705 4706 if (cur == NULL) return; 4707 switch(cur->type) { 4708 case XML_TEXT_NODE: 4709 case XML_CDATA_SECTION_NODE: 4710 case XML_COMMENT_NODE: 4711 case XML_DOCUMENT_NODE: 4712 case XML_DOCUMENT_TYPE_NODE: 4713 case XML_DOCUMENT_FRAG_NODE: 4714 case XML_NOTATION_NODE: 4715 case XML_HTML_DOCUMENT_NODE: 4716 case XML_DTD_NODE: 4717 case XML_ELEMENT_DECL: 4718 case XML_ATTRIBUTE_DECL: 4719 case XML_ENTITY_DECL: 4720 case XML_PI_NODE: 4721 case XML_ENTITY_REF_NODE: 4722 case XML_ENTITY_NODE: 4723 case XML_NAMESPACE_DECL: 4724 case XML_XINCLUDE_START: 4725 case XML_XINCLUDE_END: 4726#ifdef LIBXML_DOCB_ENABLED 4727 case XML_DOCB_DOCUMENT_NODE: 4728#endif 4729 return; 4730 case XML_ELEMENT_NODE: 4731 case XML_ATTRIBUTE_NODE: 4732 break; 4733 } 4734 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); 4735 if (ns == NULL) 4736 return; 4737 switch (val) { 4738 case 0: 4739 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default"); 4740 break; 4741 case 1: 4742 xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve"); 4743 break; 4744 } 4745} 4746#endif /* LIBXML_TREE_ENABLED */ 4747 4748/** 4749 * xmlNodeGetSpacePreserve: 4750 * @cur: the node being checked 4751 * 4752 * Searches the space preserving behaviour of a node, i.e. the values 4753 * of the xml:space attribute or the one carried by the nearest 4754 * ancestor. 4755 * 4756 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve" 4757 */ 4758int 4759xmlNodeGetSpacePreserve(xmlNodePtr cur) { 4760 xmlChar *space; 4761 4762 while (cur != NULL) { 4763 space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE); 4764 if (space != NULL) { 4765 if (xmlStrEqual(space, BAD_CAST "preserve")) { 4766 xmlFree(space); 4767 return(1); 4768 } 4769 if (xmlStrEqual(space, BAD_CAST "default")) { 4770 xmlFree(space); 4771 return(0); 4772 } 4773 xmlFree(space); 4774 } 4775 cur = cur->parent; 4776 } 4777 return(-1); 4778} 4779 4780#ifdef LIBXML_TREE_ENABLED 4781/** 4782 * xmlNodeSetName: 4783 * @cur: the node being changed 4784 * @name: the new tag name 4785 * 4786 * Set (or reset) the name of a node. 4787 */ 4788void 4789xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { 4790 xmlDocPtr doc; 4791 xmlDictPtr dict; 4792 4793 if (cur == NULL) return; 4794 if (name == NULL) return; 4795 switch(cur->type) { 4796 case XML_TEXT_NODE: 4797 case XML_CDATA_SECTION_NODE: 4798 case XML_COMMENT_NODE: 4799 case XML_DOCUMENT_TYPE_NODE: 4800 case XML_DOCUMENT_FRAG_NODE: 4801 case XML_NOTATION_NODE: 4802 case XML_HTML_DOCUMENT_NODE: 4803 case XML_NAMESPACE_DECL: 4804 case XML_XINCLUDE_START: 4805 case XML_XINCLUDE_END: 4806#ifdef LIBXML_DOCB_ENABLED 4807 case XML_DOCB_DOCUMENT_NODE: 4808#endif 4809 return; 4810 case XML_ELEMENT_NODE: 4811 case XML_ATTRIBUTE_NODE: 4812 case XML_PI_NODE: 4813 case XML_ENTITY_REF_NODE: 4814 case XML_ENTITY_NODE: 4815 case XML_DTD_NODE: 4816 case XML_DOCUMENT_NODE: 4817 case XML_ELEMENT_DECL: 4818 case XML_ATTRIBUTE_DECL: 4819 case XML_ENTITY_DECL: 4820 break; 4821 } 4822 doc = cur->doc; 4823 if (doc != NULL) 4824 dict = doc->dict; 4825 else 4826 dict = NULL; 4827 if (dict != NULL) { 4828 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) 4829 xmlFree((xmlChar *) cur->name); 4830 cur->name = xmlDictLookup(dict, name, -1); 4831 } else { 4832 if (cur->name != NULL) xmlFree((xmlChar *) cur->name); 4833 cur->name = xmlStrdup(name); 4834 } 4835} 4836#endif 4837 4838#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) 4839/** 4840 * xmlNodeSetBase: 4841 * @cur: the node being changed 4842 * @uri: the new base URI 4843 * 4844 * Set (or reset) the base URI of a node, i.e. the value of the 4845 * xml:base attribute. 4846 */ 4847void 4848xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { 4849 xmlNsPtr ns; 4850 const xmlChar* fixed; 4851 4852 if (cur == NULL) return; 4853 switch(cur->type) { 4854 case XML_TEXT_NODE: 4855 case XML_CDATA_SECTION_NODE: 4856 case XML_COMMENT_NODE: 4857 case XML_DOCUMENT_TYPE_NODE: 4858 case XML_DOCUMENT_FRAG_NODE: 4859 case XML_NOTATION_NODE: 4860 case XML_DTD_NODE: 4861 case XML_ELEMENT_DECL: 4862 case XML_ATTRIBUTE_DECL: 4863 case XML_ENTITY_DECL: 4864 case XML_PI_NODE: 4865 case XML_ENTITY_REF_NODE: 4866 case XML_ENTITY_NODE: 4867 case XML_NAMESPACE_DECL: 4868 case XML_XINCLUDE_START: 4869 case XML_XINCLUDE_END: 4870 return; 4871 case XML_ELEMENT_NODE: 4872 case XML_ATTRIBUTE_NODE: 4873 break; 4874 case XML_DOCUMENT_NODE: 4875#ifdef LIBXML_DOCB_ENABLED 4876 case XML_DOCB_DOCUMENT_NODE: 4877#endif 4878 case XML_HTML_DOCUMENT_NODE: { 4879 xmlDocPtr doc = (xmlDocPtr) cur; 4880 4881 if (doc->URL != NULL) 4882 xmlFree((xmlChar *) doc->URL); 4883 if (uri == NULL) 4884 doc->URL = NULL; 4885 else 4886 doc->URL = xmlPathToURI(uri); 4887 return; 4888 } 4889 } 4890 4891 ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); 4892 if (ns == NULL) 4893 return; 4894 fixed = xmlPathToURI(uri); 4895 if (fixed != NULL) { 4896 xmlSetNsProp(cur, ns, BAD_CAST "base", fixed); 4897 xmlFree((xmlChar *)fixed); 4898 } else { 4899 xmlSetNsProp(cur, ns, BAD_CAST "base", uri); 4900 } 4901} 4902#endif /* LIBXML_TREE_ENABLED */ 4903 4904/** 4905 * xmlNodeGetBase: 4906 * @doc: the document the node pertains to 4907 * @cur: the node being checked 4908 * 4909 * Searches for the BASE URL. The code should work on both XML 4910 * and HTML document even if base mechanisms are completely different. 4911 * It returns the base as defined in RFC 2396 sections 4912 * 5.1.1. Base URI within Document Content 4913 * and 4914 * 5.1.2. Base URI from the Encapsulating Entity 4915 * However it does not return the document base (5.1.3), use 4916 * xmlDocumentGetBase() for this 4917 * 4918 * Returns a pointer to the base URL, or NULL if not found 4919 * It's up to the caller to free the memory with xmlFree(). 4920 */ 4921xmlChar * 4922xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) { 4923 xmlChar *oldbase = NULL; 4924 xmlChar *base, *newbase; 4925 4926 if ((cur == NULL) && (doc == NULL)) 4927 return(NULL); 4928 if (doc == NULL) doc = cur->doc; 4929 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { 4930 cur = doc->children; 4931 while ((cur != NULL) && (cur->name != NULL)) { 4932 if (cur->type != XML_ELEMENT_NODE) { 4933 cur = cur->next; 4934 continue; 4935 } 4936 if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) { 4937 cur = cur->children; 4938 continue; 4939 } 4940 if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) { 4941 cur = cur->children; 4942 continue; 4943 } 4944 if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) { 4945 return(xmlGetProp(cur, BAD_CAST "href")); 4946 } 4947 cur = cur->next; 4948 } 4949 return(NULL); 4950 } 4951 while (cur != NULL) { 4952 if (cur->type == XML_ENTITY_DECL) { 4953 xmlEntityPtr ent = (xmlEntityPtr) cur; 4954 return(xmlStrdup(ent->URI)); 4955 } 4956 if (cur->type == XML_ELEMENT_NODE) { 4957 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); 4958 if (base != NULL) { 4959 if (oldbase != NULL) { 4960 newbase = xmlBuildURI(oldbase, base); 4961 if (newbase != NULL) { 4962 xmlFree(oldbase); 4963 xmlFree(base); 4964 oldbase = newbase; 4965 } else { 4966 xmlFree(oldbase); 4967 xmlFree(base); 4968 return(NULL); 4969 } 4970 } else { 4971 oldbase = base; 4972 } 4973 if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) || 4974 (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) || 4975 (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4))) 4976 return(oldbase); 4977 } 4978 } 4979 cur = cur->parent; 4980 } 4981 if ((doc != NULL) && (doc->URL != NULL)) { 4982 if (oldbase == NULL) 4983 return(xmlStrdup(doc->URL)); 4984 newbase = xmlBuildURI(oldbase, doc->URL); 4985 xmlFree(oldbase); 4986 return(newbase); 4987 } 4988 return(oldbase); 4989} 4990 4991/** 4992 * xmlNodeBufGetContent: 4993 * @buffer: a buffer 4994 * @cur: the node being read 4995 * 4996 * Read the value of a node @cur, this can be either the text carried 4997 * directly by this node if it's a TEXT node or the aggregate string 4998 * of the values carried by this node child's (TEXT and ENTITY_REF). 4999 * Entity references are substituted. 5000 * Fills up the buffer @buffer with this value 5001 * 5002 * Returns 0 in case of success and -1 in case of error. 5003 */ 5004int 5005xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur) 5006{ 5007 if ((cur == NULL) || (buffer == NULL)) return(-1); 5008 switch (cur->type) { 5009 case XML_CDATA_SECTION_NODE: 5010 case XML_TEXT_NODE: 5011 xmlBufferCat(buffer, cur->content); 5012 break; 5013 case XML_DOCUMENT_FRAG_NODE: 5014 case XML_ELEMENT_NODE:{ 5015 xmlNodePtr tmp = cur; 5016 5017 while (tmp != NULL) { 5018 switch (tmp->type) { 5019 case XML_CDATA_SECTION_NODE: 5020 case XML_TEXT_NODE: 5021 if (tmp->content != NULL) 5022 xmlBufferCat(buffer, tmp->content); 5023 break; 5024 case XML_ENTITY_REF_NODE: 5025 xmlNodeBufGetContent(buffer, tmp); 5026 break; 5027 default: 5028 break; 5029 } 5030 /* 5031 * Skip to next node 5032 */ 5033 if (tmp->children != NULL) { 5034 if (tmp->children->type != XML_ENTITY_DECL) { 5035 tmp = tmp->children; 5036 continue; 5037 } 5038 } 5039 if (tmp == cur) 5040 break; 5041 5042 if (tmp->next != NULL) { 5043 tmp = tmp->next; 5044 continue; 5045 } 5046 5047 do { 5048 tmp = tmp->parent; 5049 if (tmp == NULL) 5050 break; 5051 if (tmp == cur) { 5052 tmp = NULL; 5053 break; 5054 } 5055 if (tmp->next != NULL) { 5056 tmp = tmp->next; 5057 break; 5058 } 5059 } while (tmp != NULL); 5060 } 5061 break; 5062 } 5063 case XML_ATTRIBUTE_NODE:{ 5064 xmlAttrPtr attr = (xmlAttrPtr) cur; 5065 xmlNodePtr tmp = attr->children; 5066 5067 while (tmp != NULL) { 5068 if (tmp->type == XML_TEXT_NODE) 5069 xmlBufferCat(buffer, tmp->content); 5070 else 5071 xmlNodeBufGetContent(buffer, tmp); 5072 tmp = tmp->next; 5073 } 5074 break; 5075 } 5076 case XML_COMMENT_NODE: 5077 case XML_PI_NODE: 5078 xmlBufferCat(buffer, cur->content); 5079 break; 5080 case XML_ENTITY_REF_NODE:{ 5081 xmlEntityPtr ent; 5082 xmlNodePtr tmp; 5083 5084 /* lookup entity declaration */ 5085 ent = xmlGetDocEntity(cur->doc, cur->name); 5086 if (ent == NULL) 5087 return(-1); 5088 5089 /* an entity content can be any "well balanced chunk", 5090 * i.e. the result of the content [43] production: 5091 * http://www.w3.org/TR/REC-xml#NT-content 5092 * -> we iterate through child nodes and recursive call 5093 * xmlNodeGetContent() which handles all possible node types */ 5094 tmp = ent->children; 5095 while (tmp) { 5096 xmlNodeBufGetContent(buffer, tmp); 5097 tmp = tmp->next; 5098 } 5099 break; 5100 } 5101 case XML_ENTITY_NODE: 5102 case XML_DOCUMENT_TYPE_NODE: 5103 case XML_NOTATION_NODE: 5104 case XML_DTD_NODE: 5105 case XML_XINCLUDE_START: 5106 case XML_XINCLUDE_END: 5107 break; 5108 case XML_DOCUMENT_NODE: 5109#ifdef LIBXML_DOCB_ENABLED 5110 case XML_DOCB_DOCUMENT_NODE: 5111#endif 5112 case XML_HTML_DOCUMENT_NODE: 5113 cur = cur->children; 5114 while (cur!= NULL) { 5115 if ((cur->type == XML_ELEMENT_NODE) || 5116 (cur->type == XML_TEXT_NODE) || 5117 (cur->type == XML_CDATA_SECTION_NODE)) { 5118 xmlNodeBufGetContent(buffer, cur); 5119 } 5120 cur = cur->next; 5121 } 5122 break; 5123 case XML_NAMESPACE_DECL: 5124 xmlBufferCat(buffer, ((xmlNsPtr) cur)->href); 5125 break; 5126 case XML_ELEMENT_DECL: 5127 case XML_ATTRIBUTE_DECL: 5128 case XML_ENTITY_DECL: 5129 break; 5130 } 5131 return(0); 5132} 5133/** 5134 * xmlNodeGetContent: 5135 * @cur: the node being read 5136 * 5137 * Read the value of a node, this can be either the text carried 5138 * directly by this node if it's a TEXT node or the aggregate string 5139 * of the values carried by this node child's (TEXT and ENTITY_REF). 5140 * Entity references are substituted. 5141 * Returns a new #xmlChar * or NULL if no content is available. 5142 * It's up to the caller to free the memory with xmlFree(). 5143 */ 5144xmlChar * 5145xmlNodeGetContent(xmlNodePtr cur) 5146{ 5147 if (cur == NULL) 5148 return (NULL); 5149 switch (cur->type) { 5150 case XML_DOCUMENT_FRAG_NODE: 5151 case XML_ELEMENT_NODE:{ 5152 xmlBufferPtr buffer; 5153 xmlChar *ret; 5154 5155 buffer = xmlBufferCreateSize(64); 5156 if (buffer == NULL) 5157 return (NULL); 5158 xmlNodeBufGetContent(buffer, cur); 5159 ret = buffer->content; 5160 buffer->content = NULL; 5161 xmlBufferFree(buffer); 5162 return (ret); 5163 } 5164 case XML_ATTRIBUTE_NODE: 5165 return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur)); 5166 case XML_COMMENT_NODE: 5167 case XML_PI_NODE: 5168 if (cur->content != NULL) 5169 return (xmlStrdup(cur->content)); 5170 return (NULL); 5171 case XML_ENTITY_REF_NODE:{ 5172 xmlEntityPtr ent; 5173 xmlBufferPtr buffer; 5174 xmlChar *ret; 5175 5176 /* lookup entity declaration */ 5177 ent = xmlGetDocEntity(cur->doc, cur->name); 5178 if (ent == NULL) 5179 return (NULL); 5180 5181 buffer = xmlBufferCreate(); 5182 if (buffer == NULL) 5183 return (NULL); 5184 5185 xmlNodeBufGetContent(buffer, cur); 5186 5187 ret = buffer->content; 5188 buffer->content = NULL; 5189 xmlBufferFree(buffer); 5190 return (ret); 5191 } 5192 case XML_ENTITY_NODE: 5193 case XML_DOCUMENT_TYPE_NODE: 5194 case XML_NOTATION_NODE: 5195 case XML_DTD_NODE: 5196 case XML_XINCLUDE_START: 5197 case XML_XINCLUDE_END: 5198 return (NULL); 5199 case XML_DOCUMENT_NODE: 5200#ifdef LIBXML_DOCB_ENABLED 5201 case XML_DOCB_DOCUMENT_NODE: 5202#endif 5203 case XML_HTML_DOCUMENT_NODE: { 5204 xmlBufferPtr buffer; 5205 xmlChar *ret; 5206 5207 buffer = xmlBufferCreate(); 5208 if (buffer == NULL) 5209 return (NULL); 5210 5211 xmlNodeBufGetContent(buffer, (xmlNodePtr) cur); 5212 5213 ret = buffer->content; 5214 buffer->content = NULL; 5215 xmlBufferFree(buffer); 5216 return (ret); 5217 } 5218 case XML_NAMESPACE_DECL: { 5219 xmlChar *tmp; 5220 5221 tmp = xmlStrdup(((xmlNsPtr) cur)->href); 5222 return (tmp); 5223 } 5224 case XML_ELEMENT_DECL: 5225 /* TODO !!! */ 5226 return (NULL); 5227 case XML_ATTRIBUTE_DECL: 5228 /* TODO !!! */ 5229 return (NULL); 5230 case XML_ENTITY_DECL: 5231 /* TODO !!! */ 5232 return (NULL); 5233 case XML_CDATA_SECTION_NODE: 5234 case XML_TEXT_NODE: 5235 if (cur->content != NULL) 5236 return (xmlStrdup(cur->content)); 5237 return (NULL); 5238 } 5239 return (NULL); 5240} 5241 5242/** 5243 * xmlNodeSetContent: 5244 * @cur: the node being modified 5245 * @content: the new value of the content 5246 * 5247 * Replace the content of a node. 5248 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity 5249 * references, but XML special chars need to be escaped first by using 5250 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). 5251 */ 5252void 5253xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { 5254 if (cur == NULL) { 5255#ifdef DEBUG_TREE 5256 xmlGenericError(xmlGenericErrorContext, 5257 "xmlNodeSetContent : node == NULL\n"); 5258#endif 5259 return; 5260 } 5261 switch (cur->type) { 5262 case XML_DOCUMENT_FRAG_NODE: 5263 case XML_ELEMENT_NODE: 5264 case XML_ATTRIBUTE_NODE: 5265 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5266 cur->children = xmlStringGetNodeList(cur->doc, content); 5267 UPDATE_LAST_CHILD_AND_PARENT(cur) 5268 break; 5269 case XML_TEXT_NODE: 5270 case XML_CDATA_SECTION_NODE: 5271 case XML_ENTITY_REF_NODE: 5272 case XML_ENTITY_NODE: 5273 case XML_PI_NODE: 5274 case XML_COMMENT_NODE: 5275 if ((cur->content != NULL) && 5276 (cur->content != (xmlChar *) &(cur->properties))) { 5277 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && 5278 (xmlDictOwns(cur->doc->dict, cur->content)))) 5279 xmlFree(cur->content); 5280 } 5281 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5282 cur->last = cur->children = NULL; 5283 if (content != NULL) { 5284 cur->content = xmlStrdup(content); 5285 } else 5286 cur->content = NULL; 5287 cur->properties = NULL; 5288 cur->nsDef = NULL; 5289 break; 5290 case XML_DOCUMENT_NODE: 5291 case XML_HTML_DOCUMENT_NODE: 5292 case XML_DOCUMENT_TYPE_NODE: 5293 case XML_XINCLUDE_START: 5294 case XML_XINCLUDE_END: 5295#ifdef LIBXML_DOCB_ENABLED 5296 case XML_DOCB_DOCUMENT_NODE: 5297#endif 5298 break; 5299 case XML_NOTATION_NODE: 5300 break; 5301 case XML_DTD_NODE: 5302 break; 5303 case XML_NAMESPACE_DECL: 5304 break; 5305 case XML_ELEMENT_DECL: 5306 /* TODO !!! */ 5307 break; 5308 case XML_ATTRIBUTE_DECL: 5309 /* TODO !!! */ 5310 break; 5311 case XML_ENTITY_DECL: 5312 /* TODO !!! */ 5313 break; 5314 } 5315} 5316 5317#ifdef LIBXML_TREE_ENABLED 5318/** 5319 * xmlNodeSetContentLen: 5320 * @cur: the node being modified 5321 * @content: the new value of the content 5322 * @len: the size of @content 5323 * 5324 * Replace the content of a node. 5325 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity 5326 * references, but XML special chars need to be escaped first by using 5327 * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). 5328 */ 5329void 5330xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { 5331 if (cur == NULL) { 5332#ifdef DEBUG_TREE 5333 xmlGenericError(xmlGenericErrorContext, 5334 "xmlNodeSetContentLen : node == NULL\n"); 5335#endif 5336 return; 5337 } 5338 switch (cur->type) { 5339 case XML_DOCUMENT_FRAG_NODE: 5340 case XML_ELEMENT_NODE: 5341 case XML_ATTRIBUTE_NODE: 5342 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5343 cur->children = xmlStringLenGetNodeList(cur->doc, content, len); 5344 UPDATE_LAST_CHILD_AND_PARENT(cur) 5345 break; 5346 case XML_TEXT_NODE: 5347 case XML_CDATA_SECTION_NODE: 5348 case XML_ENTITY_REF_NODE: 5349 case XML_ENTITY_NODE: 5350 case XML_PI_NODE: 5351 case XML_COMMENT_NODE: 5352 case XML_NOTATION_NODE: 5353 if ((cur->content != NULL) && 5354 (cur->content != (xmlChar *) &(cur->properties))) { 5355 if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && 5356 (xmlDictOwns(cur->doc->dict, cur->content)))) 5357 xmlFree(cur->content); 5358 } 5359 if (cur->children != NULL) xmlFreeNodeList(cur->children); 5360 cur->children = cur->last = NULL; 5361 if (content != NULL) { 5362 cur->content = xmlStrndup(content, len); 5363 } else 5364 cur->content = NULL; 5365 cur->properties = NULL; 5366 cur->nsDef = NULL; 5367 break; 5368 case XML_DOCUMENT_NODE: 5369 case XML_DTD_NODE: 5370 case XML_HTML_DOCUMENT_NODE: 5371 case XML_DOCUMENT_TYPE_NODE: 5372 case XML_NAMESPACE_DECL: 5373 case XML_XINCLUDE_START: 5374 case XML_XINCLUDE_END: 5375#ifdef LIBXML_DOCB_ENABLED 5376 case XML_DOCB_DOCUMENT_NODE: 5377#endif 5378 break; 5379 case XML_ELEMENT_DECL: 5380 /* TODO !!! */ 5381 break; 5382 case XML_ATTRIBUTE_DECL: 5383 /* TODO !!! */ 5384 break; 5385 case XML_ENTITY_DECL: 5386 /* TODO !!! */ 5387 break; 5388 } 5389} 5390#endif /* LIBXML_TREE_ENABLED */ 5391 5392/** 5393 * xmlNodeAddContentLen: 5394 * @cur: the node being modified 5395 * @content: extra content 5396 * @len: the size of @content 5397 * 5398 * Append the extra substring to the node content. 5399 * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be 5400 * raw text, so unescaped XML special chars are allowed, entity 5401 * references are not supported. 5402 */ 5403void 5404xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { 5405 if (cur == NULL) { 5406#ifdef DEBUG_TREE 5407 xmlGenericError(xmlGenericErrorContext, 5408 "xmlNodeAddContentLen : node == NULL\n"); 5409#endif 5410 return; 5411 } 5412 if (len <= 0) return; 5413 switch (cur->type) { 5414 case XML_DOCUMENT_FRAG_NODE: 5415 case XML_ELEMENT_NODE: { 5416 xmlNodePtr last, newNode, tmp; 5417 5418 last = cur->last; 5419 newNode = xmlNewTextLen(content, len); 5420 if (newNode != NULL) { 5421 tmp = xmlAddChild(cur, newNode); 5422 if (tmp != newNode) 5423 return; 5424 if ((last != NULL) && (last->next == newNode)) { 5425 xmlTextMerge(last, newNode); 5426 } 5427 } 5428 break; 5429 } 5430 case XML_ATTRIBUTE_NODE: 5431 break; 5432 case XML_TEXT_NODE: 5433 case XML_CDATA_SECTION_NODE: 5434 case XML_ENTITY_REF_NODE: 5435 case XML_ENTITY_NODE: 5436 case XML_PI_NODE: 5437 case XML_COMMENT_NODE: 5438 case XML_NOTATION_NODE: 5439 if (content != NULL) { 5440 if ((cur->content == (xmlChar *) &(cur->properties)) || 5441 ((cur->doc != NULL) && (cur->doc->dict != NULL) && 5442 xmlDictOwns(cur->doc->dict, cur->content))) { 5443 cur->content = xmlStrncatNew(cur->content, content, len); 5444 cur->properties = NULL; 5445 cur->nsDef = NULL; 5446 break; 5447 } 5448 cur->content = xmlStrncat(cur->content, content, len); 5449 } 5450 case XML_DOCUMENT_NODE: 5451 case XML_DTD_NODE: 5452 case XML_HTML_DOCUMENT_NODE: 5453 case XML_DOCUMENT_TYPE_NODE: 5454 case XML_NAMESPACE_DECL: 5455 case XML_XINCLUDE_START: 5456 case XML_XINCLUDE_END: 5457#ifdef LIBXML_DOCB_ENABLED 5458 case XML_DOCB_DOCUMENT_NODE: 5459#endif 5460 break; 5461 case XML_ELEMENT_DECL: 5462 case XML_ATTRIBUTE_DECL: 5463 case XML_ENTITY_DECL: 5464 break; 5465 } 5466} 5467 5468/** 5469 * xmlNodeAddContent: 5470 * @cur: the node being modified 5471 * @content: extra content 5472 * 5473 * Append the extra substring to the node content. 5474 * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be 5475 * raw text, so unescaped XML special chars are allowed, entity 5476 * references are not supported. 5477 */ 5478void 5479xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { 5480 int len; 5481 5482 if (cur == NULL) { 5483#ifdef DEBUG_TREE 5484 xmlGenericError(xmlGenericErrorContext, 5485 "xmlNodeAddContent : node == NULL\n"); 5486#endif 5487 return; 5488 } 5489 if (content == NULL) return; 5490 len = xmlStrlen(content); 5491 xmlNodeAddContentLen(cur, content, len); 5492} 5493 5494/** 5495 * xmlTextMerge: 5496 * @first: the first text node 5497 * @second: the second text node being merged 5498 * 5499 * Merge two text nodes into one 5500 * Returns the first text node augmented 5501 */ 5502xmlNodePtr 5503xmlTextMerge(xmlNodePtr first, xmlNodePtr second) { 5504 if (first == NULL) return(second); 5505 if (second == NULL) return(first); 5506 if (first->type != XML_TEXT_NODE) return(first); 5507 if (second->type != XML_TEXT_NODE) return(first); 5508 if (second->name != first->name) 5509 return(first); 5510 xmlNodeAddContent(first, second->content); 5511 xmlUnlinkNode(second); 5512 xmlFreeNode(second); 5513 return(first); 5514} 5515 5516#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 5517/** 5518 * xmlGetNsList: 5519 * @doc: the document 5520 * @node: the current node 5521 * 5522 * Search all the namespace applying to a given element. 5523 * Returns an NULL terminated array of all the #xmlNsPtr found 5524 * that need to be freed by the caller or NULL if no 5525 * namespace if defined 5526 */ 5527xmlNsPtr * 5528xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node) 5529{ 5530 xmlNsPtr cur; 5531 xmlNsPtr *ret = NULL; 5532 int nbns = 0; 5533 int maxns = 10; 5534 int i; 5535 5536 while (node != NULL) { 5537 if (node->type == XML_ELEMENT_NODE) { 5538 cur = node->nsDef; 5539 while (cur != NULL) { 5540 if (ret == NULL) { 5541 ret = 5542 (xmlNsPtr *) xmlMalloc((maxns + 1) * 5543 sizeof(xmlNsPtr)); 5544 if (ret == NULL) { 5545 xmlTreeErrMemory("getting namespace list"); 5546 return (NULL); 5547 } 5548 ret[nbns] = NULL; 5549 } 5550 for (i = 0; i < nbns; i++) { 5551 if ((cur->prefix == ret[i]->prefix) || 5552 (xmlStrEqual(cur->prefix, ret[i]->prefix))) 5553 break; 5554 } 5555 if (i >= nbns) { 5556 if (nbns >= maxns) { 5557 maxns *= 2; 5558 ret = (xmlNsPtr *) xmlRealloc(ret, 5559 (maxns + 5560 1) * 5561 sizeof(xmlNsPtr)); 5562 if (ret == NULL) { 5563 xmlTreeErrMemory("getting namespace list"); 5564 return (NULL); 5565 } 5566 } 5567 ret[nbns++] = cur; 5568 ret[nbns] = NULL; 5569 } 5570 5571 cur = cur->next; 5572 } 5573 } 5574 node = node->parent; 5575 } 5576 return (ret); 5577} 5578#endif /* LIBXML_TREE_ENABLED */ 5579 5580/* 5581* xmlTreeEnsureXMLDecl: 5582* @doc: the doc 5583* 5584* Ensures that there is an XML namespace declaration on the doc. 5585* 5586* Returns the XML ns-struct or NULL on API and internal errors. 5587*/ 5588static xmlNsPtr 5589xmlTreeEnsureXMLDecl(xmlDocPtr doc) 5590{ 5591 if (doc == NULL) 5592 return (NULL); 5593 if (doc->oldNs != NULL) 5594 return (doc->oldNs); 5595 { 5596 xmlNsPtr ns; 5597 ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 5598 if (ns == NULL) { 5599 xmlTreeErrMemory( 5600 "allocating the XML namespace"); 5601 return (NULL); 5602 } 5603 memset(ns, 0, sizeof(xmlNs)); 5604 ns->type = XML_LOCAL_NAMESPACE; 5605 ns->href = xmlStrdup(XML_XML_NAMESPACE); 5606 ns->prefix = xmlStrdup((const xmlChar *)"xml"); 5607 doc->oldNs = ns; 5608 return (ns); 5609 } 5610} 5611 5612/** 5613 * xmlSearchNs: 5614 * @doc: the document 5615 * @node: the current node 5616 * @nameSpace: the namespace prefix 5617 * 5618 * Search a Ns registered under a given name space for a document. 5619 * recurse on the parents until it finds the defined namespace 5620 * or return NULL otherwise. 5621 * @nameSpace can be NULL, this is a search for the default namespace. 5622 * We don't allow to cross entities boundaries. If you don't declare 5623 * the namespace within those you will be in troubles !!! A warning 5624 * is generated to cover this case. 5625 * 5626 * Returns the namespace pointer or NULL. 5627 */ 5628xmlNsPtr 5629xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) { 5630 5631 xmlNsPtr cur; 5632 xmlNodePtr orig = node; 5633 5634 if (node == NULL) return(NULL); 5635 if ((nameSpace != NULL) && 5636 (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) { 5637 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { 5638 /* 5639 * The XML-1.0 namespace is normally held on the root 5640 * element. In this case exceptionally create it on the 5641 * node element. 5642 */ 5643 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 5644 if (cur == NULL) { 5645 xmlTreeErrMemory("searching namespace"); 5646 return(NULL); 5647 } 5648 memset(cur, 0, sizeof(xmlNs)); 5649 cur->type = XML_LOCAL_NAMESPACE; 5650 cur->href = xmlStrdup(XML_XML_NAMESPACE); 5651 cur->prefix = xmlStrdup((const xmlChar *)"xml"); 5652 cur->next = node->nsDef; 5653 node->nsDef = cur; 5654 return(cur); 5655 } 5656 if (doc == NULL) { 5657 doc = node->doc; 5658 if (doc == NULL) 5659 return(NULL); 5660 } 5661 /* 5662 * Return the XML namespace declaration held by the doc. 5663 */ 5664 if (doc->oldNs == NULL) 5665 return(xmlTreeEnsureXMLDecl(doc)); 5666 else 5667 return(doc->oldNs); 5668 } 5669 while (node != NULL) { 5670 if ((node->type == XML_ENTITY_REF_NODE) || 5671 (node->type == XML_ENTITY_NODE) || 5672 (node->type == XML_ENTITY_DECL)) 5673 return(NULL); 5674 if (node->type == XML_ELEMENT_NODE) { 5675 cur = node->nsDef; 5676 while (cur != NULL) { 5677 if ((cur->prefix == NULL) && (nameSpace == NULL) && 5678 (cur->href != NULL)) 5679 return(cur); 5680 if ((cur->prefix != NULL) && (nameSpace != NULL) && 5681 (cur->href != NULL) && 5682 (xmlStrEqual(cur->prefix, nameSpace))) 5683 return(cur); 5684 cur = cur->next; 5685 } 5686 if (orig != node) { 5687 cur = node->ns; 5688 if (cur != NULL) { 5689 if ((cur->prefix == NULL) && (nameSpace == NULL) && 5690 (cur->href != NULL)) 5691 return(cur); 5692 if ((cur->prefix != NULL) && (nameSpace != NULL) && 5693 (cur->href != NULL) && 5694 (xmlStrEqual(cur->prefix, nameSpace))) 5695 return(cur); 5696 } 5697 } 5698 } 5699 node = node->parent; 5700 } 5701 return(NULL); 5702} 5703 5704/** 5705 * xmlNsInScope: 5706 * @doc: the document 5707 * @node: the current node 5708 * @ancestor: the ancestor carrying the namespace 5709 * @prefix: the namespace prefix 5710 * 5711 * Verify that the given namespace held on @ancestor is still in scope 5712 * on node. 5713 * 5714 * Returns 1 if true, 0 if false and -1 in case of error. 5715 */ 5716static int 5717xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, 5718 xmlNodePtr ancestor, const xmlChar * prefix) 5719{ 5720 xmlNsPtr tst; 5721 5722 while ((node != NULL) && (node != ancestor)) { 5723 if ((node->type == XML_ENTITY_REF_NODE) || 5724 (node->type == XML_ENTITY_NODE) || 5725 (node->type == XML_ENTITY_DECL)) 5726 return (-1); 5727 if (node->type == XML_ELEMENT_NODE) { 5728 tst = node->nsDef; 5729 while (tst != NULL) { 5730 if ((tst->prefix == NULL) 5731 && (prefix == NULL)) 5732 return (0); 5733 if ((tst->prefix != NULL) 5734 && (prefix != NULL) 5735 && (xmlStrEqual(tst->prefix, prefix))) 5736 return (0); 5737 tst = tst->next; 5738 } 5739 } 5740 node = node->parent; 5741 } 5742 if (node != ancestor) 5743 return (-1); 5744 return (1); 5745} 5746 5747/** 5748 * xmlSearchNsByHref: 5749 * @doc: the document 5750 * @node: the current node 5751 * @href: the namespace value 5752 * 5753 * Search a Ns aliasing a given URI. Recurse on the parents until it finds 5754 * the defined namespace or return NULL otherwise. 5755 * Returns the namespace pointer or NULL. 5756 */ 5757xmlNsPtr 5758xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) 5759{ 5760 xmlNsPtr cur; 5761 xmlNodePtr orig = node; 5762 int is_attr; 5763 5764 if ((node == NULL) || (href == NULL)) 5765 return (NULL); 5766 if (xmlStrEqual(href, XML_XML_NAMESPACE)) { 5767 /* 5768 * Only the document can hold the XML spec namespace. 5769 */ 5770 if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { 5771 /* 5772 * The XML-1.0 namespace is normally held on the root 5773 * element. In this case exceptionally create it on the 5774 * node element. 5775 */ 5776 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 5777 if (cur == NULL) { 5778 xmlTreeErrMemory("searching namespace"); 5779 return (NULL); 5780 } 5781 memset(cur, 0, sizeof(xmlNs)); 5782 cur->type = XML_LOCAL_NAMESPACE; 5783 cur->href = xmlStrdup(XML_XML_NAMESPACE); 5784 cur->prefix = xmlStrdup((const xmlChar *) "xml"); 5785 cur->next = node->nsDef; 5786 node->nsDef = cur; 5787 return (cur); 5788 } 5789 if (doc == NULL) { 5790 doc = node->doc; 5791 if (doc == NULL) 5792 return(NULL); 5793 } 5794 /* 5795 * Return the XML namespace declaration held by the doc. 5796 */ 5797 if (doc->oldNs == NULL) 5798 return(xmlTreeEnsureXMLDecl(doc)); 5799 else 5800 return(doc->oldNs); 5801 } 5802 is_attr = (node->type == XML_ATTRIBUTE_NODE); 5803 while (node != NULL) { 5804 if ((node->type == XML_ENTITY_REF_NODE) || 5805 (node->type == XML_ENTITY_NODE) || 5806 (node->type == XML_ENTITY_DECL)) 5807 return (NULL); 5808 if (node->type == XML_ELEMENT_NODE) { 5809 cur = node->nsDef; 5810 while (cur != NULL) { 5811 if ((cur->href != NULL) && (href != NULL) && 5812 (xmlStrEqual(cur->href, href))) { 5813 if (((!is_attr) || (cur->prefix != NULL)) && 5814 (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) 5815 return (cur); 5816 } 5817 cur = cur->next; 5818 } 5819 if (orig != node) { 5820 cur = node->ns; 5821 if (cur != NULL) { 5822 if ((cur->href != NULL) && (href != NULL) && 5823 (xmlStrEqual(cur->href, href))) { 5824 if (((!is_attr) || (cur->prefix != NULL)) && 5825 (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) 5826 return (cur); 5827 } 5828 } 5829 } 5830 } 5831 node = node->parent; 5832 } 5833 return (NULL); 5834} 5835 5836/** 5837 * xmlNewReconciliedNs: 5838 * @doc: the document 5839 * @tree: a node expected to hold the new namespace 5840 * @ns: the original namespace 5841 * 5842 * This function tries to locate a namespace definition in a tree 5843 * ancestors, or create a new namespace definition node similar to 5844 * @ns trying to reuse the same prefix. However if the given prefix is 5845 * null (default namespace) or reused within the subtree defined by 5846 * @tree or on one of its ancestors then a new prefix is generated. 5847 * Returns the (new) namespace definition or NULL in case of error 5848 */ 5849xmlNsPtr 5850xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { 5851 xmlNsPtr def; 5852 xmlChar prefix[50]; 5853 int counter = 1; 5854 5855 if (tree == NULL) { 5856#ifdef DEBUG_TREE 5857 xmlGenericError(xmlGenericErrorContext, 5858 "xmlNewReconciliedNs : tree == NULL\n"); 5859#endif 5860 return(NULL); 5861 } 5862 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) { 5863#ifdef DEBUG_TREE 5864 xmlGenericError(xmlGenericErrorContext, 5865 "xmlNewReconciliedNs : ns == NULL\n"); 5866#endif 5867 return(NULL); 5868 } 5869 /* 5870 * Search an existing namespace definition inherited. 5871 */ 5872 def = xmlSearchNsByHref(doc, tree, ns->href); 5873 if (def != NULL) 5874 return(def); 5875 5876 /* 5877 * Find a close prefix which is not already in use. 5878 * Let's strip namespace prefixes longer than 20 chars ! 5879 */ 5880 if (ns->prefix == NULL) 5881 snprintf((char *) prefix, sizeof(prefix), "default"); 5882 else 5883 snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix); 5884 5885 def = xmlSearchNs(doc, tree, prefix); 5886 while (def != NULL) { 5887 if (counter > 1000) return(NULL); 5888 if (ns->prefix == NULL) 5889 snprintf((char *) prefix, sizeof(prefix), "default%d", counter++); 5890 else 5891 snprintf((char *) prefix, sizeof(prefix), "%.20s%d", 5892 (char *)ns->prefix, counter++); 5893 def = xmlSearchNs(doc, tree, prefix); 5894 } 5895 5896 /* 5897 * OK, now we are ready to create a new one. 5898 */ 5899 def = xmlNewNs(tree, ns->href, prefix); 5900 return(def); 5901} 5902 5903#ifdef LIBXML_TREE_ENABLED 5904/** 5905 * xmlReconciliateNs: 5906 * @doc: the document 5907 * @tree: a node defining the subtree to reconciliate 5908 * 5909 * This function checks that all the namespaces declared within the given 5910 * tree are properly declared. This is needed for example after Copy or Cut 5911 * and then paste operations. The subtree may still hold pointers to 5912 * namespace declarations outside the subtree or invalid/masked. As much 5913 * as possible the function try to reuse the existing namespaces found in 5914 * the new environment. If not possible the new namespaces are redeclared 5915 * on @tree at the top of the given subtree. 5916 * Returns the number of namespace declarations created or -1 in case of error. 5917 */ 5918int 5919xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { 5920 xmlNsPtr *oldNs = NULL; 5921 xmlNsPtr *newNs = NULL; 5922 int sizeCache = 0; 5923 int nbCache = 0; 5924 5925 xmlNsPtr n; 5926 xmlNodePtr node = tree; 5927 xmlAttrPtr attr; 5928 int ret = 0, i; 5929 5930 if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); 5931 if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1); 5932 if (node->doc != doc) return(-1); 5933 while (node != NULL) { 5934 /* 5935 * Reconciliate the node namespace 5936 */ 5937 if (node->ns != NULL) { 5938 /* 5939 * initialize the cache if needed 5940 */ 5941 if (sizeCache == 0) { 5942 sizeCache = 10; 5943 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * 5944 sizeof(xmlNsPtr)); 5945 if (oldNs == NULL) { 5946 xmlTreeErrMemory("fixing namespaces"); 5947 return(-1); 5948 } 5949 newNs = (xmlNsPtr *) xmlMalloc(sizeCache * 5950 sizeof(xmlNsPtr)); 5951 if (newNs == NULL) { 5952 xmlTreeErrMemory("fixing namespaces"); 5953 xmlFree(oldNs); 5954 return(-1); 5955 } 5956 } 5957 for (i = 0;i < nbCache;i++) { 5958 if (oldNs[i] == node->ns) { 5959 node->ns = newNs[i]; 5960 break; 5961 } 5962 } 5963 if (i == nbCache) { 5964 /* 5965 * OK we need to recreate a new namespace definition 5966 */ 5967 n = xmlNewReconciliedNs(doc, tree, node->ns); 5968 if (n != NULL) { /* :-( what if else ??? */ 5969 /* 5970 * check if we need to grow the cache buffers. 5971 */ 5972 if (sizeCache <= nbCache) { 5973 sizeCache *= 2; 5974 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache * 5975 sizeof(xmlNsPtr)); 5976 if (oldNs == NULL) { 5977 xmlTreeErrMemory("fixing namespaces"); 5978 xmlFree(newNs); 5979 return(-1); 5980 } 5981 newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache * 5982 sizeof(xmlNsPtr)); 5983 if (newNs == NULL) { 5984 xmlTreeErrMemory("fixing namespaces"); 5985 xmlFree(oldNs); 5986 return(-1); 5987 } 5988 } 5989 newNs[nbCache] = n; 5990 oldNs[nbCache++] = node->ns; 5991 node->ns = n; 5992 } 5993 } 5994 } 5995 /* 5996 * now check for namespace hold by attributes on the node. 5997 */ 5998 if (node->type == XML_ELEMENT_NODE) { 5999 attr = node->properties; 6000 while (attr != NULL) { 6001 if (attr->ns != NULL) { 6002 /* 6003 * initialize the cache if needed 6004 */ 6005 if (sizeCache == 0) { 6006 sizeCache = 10; 6007 oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * 6008 sizeof(xmlNsPtr)); 6009 if (oldNs == NULL) { 6010 xmlTreeErrMemory("fixing namespaces"); 6011 return(-1); 6012 } 6013 newNs = (xmlNsPtr *) xmlMalloc(sizeCache * 6014 sizeof(xmlNsPtr)); 6015 if (newNs == NULL) { 6016 xmlTreeErrMemory("fixing namespaces"); 6017 xmlFree(oldNs); 6018 return(-1); 6019 } 6020 } 6021 for (i = 0;i < nbCache;i++) { 6022 if (oldNs[i] == attr->ns) { 6023 attr->ns = newNs[i]; 6024 break; 6025 } 6026 } 6027 if (i == nbCache) { 6028 /* 6029 * OK we need to recreate a new namespace definition 6030 */ 6031 n = xmlNewReconciliedNs(doc, tree, attr->ns); 6032 if (n != NULL) { /* :-( what if else ??? */ 6033 /* 6034 * check if we need to grow the cache buffers. 6035 */ 6036 if (sizeCache <= nbCache) { 6037 sizeCache *= 2; 6038 oldNs = (xmlNsPtr *) xmlRealloc(oldNs, 6039 sizeCache * sizeof(xmlNsPtr)); 6040 if (oldNs == NULL) { 6041 xmlTreeErrMemory("fixing namespaces"); 6042 xmlFree(newNs); 6043 return(-1); 6044 } 6045 newNs = (xmlNsPtr *) xmlRealloc(newNs, 6046 sizeCache * sizeof(xmlNsPtr)); 6047 if (newNs == NULL) { 6048 xmlTreeErrMemory("fixing namespaces"); 6049 xmlFree(oldNs); 6050 return(-1); 6051 } 6052 } 6053 newNs[nbCache] = n; 6054 oldNs[nbCache++] = attr->ns; 6055 attr->ns = n; 6056 } 6057 } 6058 } 6059 attr = attr->next; 6060 } 6061 } 6062 6063 /* 6064 * Browse the full subtree, deep first 6065 */ 6066 if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { 6067 /* deep first */ 6068 node = node->children; 6069 } else if ((node != tree) && (node->next != NULL)) { 6070 /* then siblings */ 6071 node = node->next; 6072 } else if (node != tree) { 6073 /* go up to parents->next if needed */ 6074 while (node != tree) { 6075 if (node->parent != NULL) 6076 node = node->parent; 6077 if ((node != tree) && (node->next != NULL)) { 6078 node = node->next; 6079 break; 6080 } 6081 if (node->parent == NULL) { 6082 node = NULL; 6083 break; 6084 } 6085 } 6086 /* exit condition */ 6087 if (node == tree) 6088 node = NULL; 6089 } else 6090 break; 6091 } 6092 if (oldNs != NULL) 6093 xmlFree(oldNs); 6094 if (newNs != NULL) 6095 xmlFree(newNs); 6096 return(ret); 6097} 6098#endif /* LIBXML_TREE_ENABLED */ 6099 6100static xmlAttrPtr 6101xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name, 6102 const xmlChar *nsName, int useDTD) 6103{ 6104 xmlAttrPtr prop; 6105 6106 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) 6107 return(NULL); 6108 6109 if (node->properties != NULL) { 6110 prop = node->properties; 6111 if (nsName == NULL) { 6112 /* 6113 * We want the attr to be in no namespace. 6114 */ 6115 do { 6116 if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) { 6117 return(prop); 6118 } 6119 prop = prop->next; 6120 } while (prop != NULL); 6121 } else { 6122 /* 6123 * We want the attr to be in the specified namespace. 6124 */ 6125 do { 6126 if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) && 6127 ((prop->ns->href == nsName) || 6128 xmlStrEqual(prop->ns->href, nsName))) 6129 { 6130 return(prop); 6131 } 6132 prop = prop->next; 6133 } while (prop != NULL); 6134 } 6135 } 6136 6137#ifdef LIBXML_TREE_ENABLED 6138 if (! useDTD) 6139 return(NULL); 6140 /* 6141 * Check if there is a default/fixed attribute declaration in 6142 * the internal or external subset. 6143 */ 6144 if ((node->doc != NULL) && (node->doc->intSubset != NULL)) { 6145 xmlDocPtr doc = node->doc; 6146 xmlAttributePtr attrDecl = NULL; 6147 xmlChar *elemQName, *tmpstr = NULL; 6148 6149 /* 6150 * We need the QName of the element for the DTD-lookup. 6151 */ 6152 if ((node->ns != NULL) && (node->ns->prefix != NULL)) { 6153 tmpstr = xmlStrdup(node->ns->prefix); 6154 tmpstr = xmlStrcat(tmpstr, BAD_CAST ":"); 6155 tmpstr = xmlStrcat(tmpstr, node->name); 6156 if (tmpstr == NULL) 6157 return(NULL); 6158 elemQName = tmpstr; 6159 } else 6160 elemQName = (xmlChar *) node->name; 6161 if (nsName == NULL) { 6162 /* 6163 * The common and nice case: Attr in no namespace. 6164 */ 6165 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, 6166 elemQName, name, NULL); 6167 if ((attrDecl == NULL) && (doc->extSubset != NULL)) { 6168 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, 6169 elemQName, name, NULL); 6170 } 6171 } else { 6172 xmlNsPtr *nsList, *cur; 6173 6174 /* 6175 * The ugly case: Search using the prefixes of in-scope 6176 * ns-decls corresponding to @nsName. 6177 */ 6178 nsList = xmlGetNsList(node->doc, node); 6179 if (nsList == NULL) { 6180 if (tmpstr != NULL) 6181 xmlFree(tmpstr); 6182 return(NULL); 6183 } 6184 cur = nsList; 6185 while (*cur != NULL) { 6186 if (xmlStrEqual((*cur)->href, nsName)) { 6187 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName, 6188 name, (*cur)->prefix); 6189 if (attrDecl) 6190 break; 6191 if (doc->extSubset != NULL) { 6192 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName, 6193 name, (*cur)->prefix); 6194 if (attrDecl) 6195 break; 6196 } 6197 } 6198 cur++; 6199 } 6200 xmlFree(nsList); 6201 } 6202 if (tmpstr != NULL) 6203 xmlFree(tmpstr); 6204 /* 6205 * Only default/fixed attrs are relevant. 6206 */ 6207 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) 6208 return((xmlAttrPtr) attrDecl); 6209 } 6210#endif /* LIBXML_TREE_ENABLED */ 6211 return(NULL); 6212} 6213 6214static xmlChar* 6215xmlGetPropNodeValueInternal(xmlAttrPtr prop) 6216{ 6217 if (prop == NULL) 6218 return(NULL); 6219 if (prop->type == XML_ATTRIBUTE_NODE) { 6220 /* 6221 * Note that we return at least the empty string. 6222 * TODO: Do we really always want that? 6223 */ 6224 if (prop->children != NULL) { 6225 if ((prop->children->next == NULL) && 6226 ((prop->children->type == XML_TEXT_NODE) || 6227 (prop->children->type == XML_CDATA_SECTION_NODE))) 6228 { 6229 /* 6230 * Optimization for the common case: only 1 text node. 6231 */ 6232 return(xmlStrdup(prop->children->content)); 6233 } else { 6234 xmlChar *ret; 6235 6236 ret = xmlNodeListGetString(prop->doc, prop->children, 1); 6237 if (ret != NULL) 6238 return(ret); 6239 } 6240 } 6241 return(xmlStrdup((xmlChar *)"")); 6242 } else if (prop->type == XML_ATTRIBUTE_DECL) { 6243 return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue)); 6244 } 6245 return(NULL); 6246} 6247 6248/** 6249 * xmlHasProp: 6250 * @node: the node 6251 * @name: the attribute name 6252 * 6253 * Search an attribute associated to a node 6254 * This function also looks in DTD attribute declaration for #FIXED or 6255 * default declaration values unless DTD use has been turned off. 6256 * 6257 * Returns the attribute or the attribute declaration or NULL if 6258 * neither was found. 6259 */ 6260xmlAttrPtr 6261xmlHasProp(xmlNodePtr node, const xmlChar *name) { 6262 xmlAttrPtr prop; 6263 xmlDocPtr doc; 6264 6265 if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) 6266 return(NULL); 6267 /* 6268 * Check on the properties attached to the node 6269 */ 6270 prop = node->properties; 6271 while (prop != NULL) { 6272 if (xmlStrEqual(prop->name, name)) { 6273 return(prop); 6274 } 6275 prop = prop->next; 6276 } 6277 if (!xmlCheckDTD) return(NULL); 6278 6279 /* 6280 * Check if there is a default declaration in the internal 6281 * or external subsets 6282 */ 6283 doc = node->doc; 6284 if (doc != NULL) { 6285 xmlAttributePtr attrDecl; 6286 if (doc->intSubset != NULL) { 6287 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); 6288 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 6289 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); 6290 if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) 6291 /* return attribute declaration only if a default value is given 6292 (that includes #FIXED declarations) */ 6293 return((xmlAttrPtr) attrDecl); 6294 } 6295 } 6296 return(NULL); 6297} 6298 6299/** 6300 * xmlHasNsProp: 6301 * @node: the node 6302 * @name: the attribute name 6303 * @nameSpace: the URI of the namespace 6304 * 6305 * Search for an attribute associated to a node 6306 * This attribute has to be anchored in the namespace specified. 6307 * This does the entity substitution. 6308 * This function looks in DTD attribute declaration for #FIXED or 6309 * default declaration values unless DTD use has been turned off. 6310 * Note that a namespace of NULL indicates to use the default namespace. 6311 * 6312 * Returns the attribute or the attribute declaration or NULL 6313 * if neither was found. 6314 */ 6315xmlAttrPtr 6316xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { 6317 6318 return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD)); 6319} 6320 6321/** 6322 * xmlGetProp: 6323 * @node: the node 6324 * @name: the attribute name 6325 * 6326 * Search and get the value of an attribute associated to a node 6327 * This does the entity substitution. 6328 * This function looks in DTD attribute declaration for #FIXED or 6329 * default declaration values unless DTD use has been turned off. 6330 * NOTE: this function acts independently of namespaces associated 6331 * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp() 6332 * for namespace aware processing. 6333 * 6334 * Returns the attribute value or NULL if not found. 6335 * It's up to the caller to free the memory with xmlFree(). 6336 */ 6337xmlChar * 6338xmlGetProp(xmlNodePtr node, const xmlChar *name) { 6339 xmlAttrPtr prop; 6340 6341 prop = xmlHasProp(node, name); 6342 if (prop == NULL) 6343 return(NULL); 6344 return(xmlGetPropNodeValueInternal(prop)); 6345} 6346 6347/** 6348 * xmlGetNoNsProp: 6349 * @node: the node 6350 * @name: the attribute name 6351 * 6352 * Search and get the value of an attribute associated to a node 6353 * This does the entity substitution. 6354 * This function looks in DTD attribute declaration for #FIXED or 6355 * default declaration values unless DTD use has been turned off. 6356 * This function is similar to xmlGetProp except it will accept only 6357 * an attribute in no namespace. 6358 * 6359 * Returns the attribute value or NULL if not found. 6360 * It's up to the caller to free the memory with xmlFree(). 6361 */ 6362xmlChar * 6363xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) { 6364 xmlAttrPtr prop; 6365 6366 prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD); 6367 if (prop == NULL) 6368 return(NULL); 6369 return(xmlGetPropNodeValueInternal(prop)); 6370} 6371 6372/** 6373 * xmlGetNsProp: 6374 * @node: the node 6375 * @name: the attribute name 6376 * @nameSpace: the URI of the namespace 6377 * 6378 * Search and get the value of an attribute associated to a node 6379 * This attribute has to be anchored in the namespace specified. 6380 * This does the entity substitution. 6381 * This function looks in DTD attribute declaration for #FIXED or 6382 * default declaration values unless DTD use has been turned off. 6383 * 6384 * Returns the attribute value or NULL if not found. 6385 * It's up to the caller to free the memory with xmlFree(). 6386 */ 6387xmlChar * 6388xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { 6389 xmlAttrPtr prop; 6390 6391 prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD); 6392 if (prop == NULL) 6393 return(NULL); 6394 return(xmlGetPropNodeValueInternal(prop)); 6395} 6396 6397#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) 6398/** 6399 * xmlUnsetProp: 6400 * @node: the node 6401 * @name: the attribute name 6402 * 6403 * Remove an attribute carried by a node. 6404 * This handles only attributes in no namespace. 6405 * Returns 0 if successful, -1 if not found 6406 */ 6407int 6408xmlUnsetProp(xmlNodePtr node, const xmlChar *name) { 6409 xmlAttrPtr prop; 6410 6411 prop = xmlGetPropNodeInternal(node, name, NULL, 0); 6412 if (prop == NULL) 6413 return(-1); 6414 xmlUnlinkNode((xmlNodePtr) prop); 6415 xmlFreeProp(prop); 6416 return(0); 6417} 6418 6419/** 6420 * xmlUnsetNsProp: 6421 * @node: the node 6422 * @ns: the namespace definition 6423 * @name: the attribute name 6424 * 6425 * Remove an attribute carried by a node. 6426 * Returns 0 if successful, -1 if not found 6427 */ 6428int 6429xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { 6430 xmlAttrPtr prop; 6431 6432 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); 6433 if (prop == NULL) 6434 return(-1); 6435 xmlUnlinkNode((xmlNodePtr) prop); 6436 xmlFreeProp(prop); 6437 return(0); 6438} 6439#endif 6440 6441#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) 6442/** 6443 * xmlSetProp: 6444 * @node: the node 6445 * @name: the attribute name (a QName) 6446 * @value: the attribute value 6447 * 6448 * Set (or reset) an attribute carried by a node. 6449 * If @name has a prefix, then the corresponding 6450 * namespace-binding will be used, if in scope; it is an 6451 * error it there's no such ns-binding for the prefix in 6452 * scope. 6453 * Returns the attribute pointer. 6454 * 6455 */ 6456xmlAttrPtr 6457xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { 6458 int len; 6459 const xmlChar *nqname; 6460 6461 if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE)) 6462 return(NULL); 6463 6464 /* 6465 * handle QNames 6466 */ 6467 nqname = xmlSplitQName3(name, &len); 6468 if (nqname != NULL) { 6469 xmlNsPtr ns; 6470 xmlChar *prefix = xmlStrndup(name, len); 6471 ns = xmlSearchNs(node->doc, node, prefix); 6472 if (prefix != NULL) 6473 xmlFree(prefix); 6474 if (ns != NULL) 6475 return(xmlSetNsProp(node, ns, nqname, value)); 6476 } 6477 return(xmlSetNsProp(node, NULL, name, value)); 6478} 6479 6480/** 6481 * xmlSetNsProp: 6482 * @node: the node 6483 * @ns: the namespace definition 6484 * @name: the attribute name 6485 * @value: the attribute value 6486 * 6487 * Set (or reset) an attribute carried by a node. 6488 * The ns structure must be in scope, this is not checked 6489 * 6490 * Returns the attribute pointer. 6491 */ 6492xmlAttrPtr 6493xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, 6494 const xmlChar *value) 6495{ 6496 xmlAttrPtr prop; 6497 6498 if (ns && (ns->href == NULL)) 6499 return(NULL); 6500 prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); 6501 if (prop != NULL) { 6502 /* 6503 * Modify the attribute's value. 6504 */ 6505 if (prop->atype == XML_ATTRIBUTE_ID) { 6506 xmlRemoveID(node->doc, prop); 6507 prop->atype = XML_ATTRIBUTE_ID; 6508 } 6509 if (prop->children != NULL) 6510 xmlFreeNodeList(prop->children); 6511 prop->children = NULL; 6512 prop->last = NULL; 6513 prop->ns = ns; 6514 if (value != NULL) { 6515 xmlNodePtr tmp; 6516 6517 if(!xmlCheckUTF8(value)) { 6518 xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc, 6519 NULL); 6520 if (node->doc != NULL) 6521 node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); 6522 } 6523 prop->children = xmlNewDocText(node->doc, value); 6524 prop->last = NULL; 6525 tmp = prop->children; 6526 while (tmp != NULL) { 6527 tmp->parent = (xmlNodePtr) prop; 6528 if (tmp->next == NULL) 6529 prop->last = tmp; 6530 tmp = tmp->next; 6531 } 6532 } 6533 if (prop->atype == XML_ATTRIBUTE_ID) 6534 xmlAddID(NULL, node->doc, value, prop); 6535 return(prop); 6536 } 6537 /* 6538 * No equal attr found; create a new one. 6539 */ 6540 return(xmlNewPropInternal(node, ns, name, value, 0)); 6541} 6542 6543#endif /* LIBXML_TREE_ENABLED */ 6544 6545/** 6546 * xmlNodeIsText: 6547 * @node: the node 6548 * 6549 * Is this node a Text node ? 6550 * Returns 1 yes, 0 no 6551 */ 6552int 6553xmlNodeIsText(xmlNodePtr node) { 6554 if (node == NULL) return(0); 6555 6556 if (node->type == XML_TEXT_NODE) return(1); 6557 return(0); 6558} 6559 6560/** 6561 * xmlIsBlankNode: 6562 * @node: the node 6563 * 6564 * Checks whether this node is an empty or whitespace only 6565 * (and possibly ignorable) text-node. 6566 * 6567 * Returns 1 yes, 0 no 6568 */ 6569int 6570xmlIsBlankNode(xmlNodePtr node) { 6571 const xmlChar *cur; 6572 if (node == NULL) return(0); 6573 6574 if ((node->type != XML_TEXT_NODE) && 6575 (node->type != XML_CDATA_SECTION_NODE)) 6576 return(0); 6577 if (node->content == NULL) return(1); 6578 cur = node->content; 6579 while (*cur != 0) { 6580 if (!IS_BLANK_CH(*cur)) return(0); 6581 cur++; 6582 } 6583 6584 return(1); 6585} 6586 6587/** 6588 * xmlTextConcat: 6589 * @node: the node 6590 * @content: the content 6591 * @len: @content length 6592 * 6593 * Concat the given string at the end of the existing node content 6594 * 6595 * Returns -1 in case of error, 0 otherwise 6596 */ 6597 6598int 6599xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) { 6600 if (node == NULL) return(-1); 6601 6602 if ((node->type != XML_TEXT_NODE) && 6603 (node->type != XML_CDATA_SECTION_NODE) && 6604 (node->type != XML_COMMENT_NODE) && 6605 (node->type != XML_PI_NODE)) { 6606#ifdef DEBUG_TREE 6607 xmlGenericError(xmlGenericErrorContext, 6608 "xmlTextConcat: node is not text nor CDATA\n"); 6609#endif 6610 return(-1); 6611 } 6612 /* need to check if content is currently in the dictionary */ 6613 if ((node->content == (xmlChar *) &(node->properties)) || 6614 ((node->doc != NULL) && (node->doc->dict != NULL) && 6615 xmlDictOwns(node->doc->dict, node->content))) { 6616 node->content = xmlStrncatNew(node->content, content, len); 6617 } else { 6618 node->content = xmlStrncat(node->content, content, len); 6619 } 6620 node->properties = NULL; 6621 if (node->content == NULL) 6622 return(-1); 6623 return(0); 6624} 6625 6626/************************************************************************ 6627 * * 6628 * Output : to a FILE or in memory * 6629 * * 6630 ************************************************************************/ 6631 6632/** 6633 * xmlBufferCreate: 6634 * 6635 * routine to create an XML buffer. 6636 * returns the new structure. 6637 */ 6638xmlBufferPtr 6639xmlBufferCreate(void) { 6640 xmlBufferPtr ret; 6641 6642 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 6643 if (ret == NULL) { 6644 xmlTreeErrMemory("creating buffer"); 6645 return(NULL); 6646 } 6647 ret->use = 0; 6648 ret->size = xmlDefaultBufferSize; 6649 ret->alloc = xmlBufferAllocScheme; 6650 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); 6651 if (ret->content == NULL) { 6652 xmlTreeErrMemory("creating buffer"); 6653 xmlFree(ret); 6654 return(NULL); 6655 } 6656 ret->content[0] = 0; 6657 ret->contentIO = NULL; 6658 return(ret); 6659} 6660 6661/** 6662 * xmlBufferCreateSize: 6663 * @size: initial size of buffer 6664 * 6665 * routine to create an XML buffer. 6666 * returns the new structure. 6667 */ 6668xmlBufferPtr 6669xmlBufferCreateSize(size_t size) { 6670 xmlBufferPtr ret; 6671 6672 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 6673 if (ret == NULL) { 6674 xmlTreeErrMemory("creating buffer"); 6675 return(NULL); 6676 } 6677 ret->use = 0; 6678 ret->alloc = xmlBufferAllocScheme; 6679 ret->size = (size ? size+2 : 0); /* +1 for ending null */ 6680 if (ret->size){ 6681 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); 6682 if (ret->content == NULL) { 6683 xmlTreeErrMemory("creating buffer"); 6684 xmlFree(ret); 6685 return(NULL); 6686 } 6687 ret->content[0] = 0; 6688 } else 6689 ret->content = NULL; 6690 ret->contentIO = NULL; 6691 return(ret); 6692} 6693 6694/** 6695 * xmlBufferCreateStatic: 6696 * @mem: the memory area 6697 * @size: the size in byte 6698 * 6699 * routine to create an XML buffer from an immutable memory area. 6700 * The area won't be modified nor copied, and is expected to be 6701 * present until the end of the buffer lifetime. 6702 * 6703 * returns the new structure. 6704 */ 6705xmlBufferPtr 6706xmlBufferCreateStatic(void *mem, size_t size) { 6707 xmlBufferPtr ret; 6708 6709 if ((mem == NULL) || (size == 0)) 6710 return(NULL); 6711 6712 ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); 6713 if (ret == NULL) { 6714 xmlTreeErrMemory("creating buffer"); 6715 return(NULL); 6716 } 6717 ret->use = size; 6718 ret->size = size; 6719 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE; 6720 ret->content = (xmlChar *) mem; 6721 return(ret); 6722} 6723 6724/** 6725 * xmlBufferSetAllocationScheme: 6726 * @buf: the buffer to tune 6727 * @scheme: allocation scheme to use 6728 * 6729 * Sets the allocation scheme for this buffer 6730 */ 6731void 6732xmlBufferSetAllocationScheme(xmlBufferPtr buf, 6733 xmlBufferAllocationScheme scheme) { 6734 if (buf == NULL) { 6735#ifdef DEBUG_BUFFER 6736 xmlGenericError(xmlGenericErrorContext, 6737 "xmlBufferSetAllocationScheme: buf == NULL\n"); 6738#endif 6739 return; 6740 } 6741 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || 6742 (buf->alloc == XML_BUFFER_ALLOC_IO)) return; 6743 if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) || 6744 (scheme == XML_BUFFER_ALLOC_EXACT) || 6745 (scheme == XML_BUFFER_ALLOC_IMMUTABLE)) 6746 buf->alloc = scheme; 6747} 6748 6749/** 6750 * xmlBufferFree: 6751 * @buf: the buffer to free 6752 * 6753 * Frees an XML buffer. It frees both the content and the structure which 6754 * encapsulate it. 6755 */ 6756void 6757xmlBufferFree(xmlBufferPtr buf) { 6758 if (buf == NULL) { 6759#ifdef DEBUG_BUFFER 6760 xmlGenericError(xmlGenericErrorContext, 6761 "xmlBufferFree: buf == NULL\n"); 6762#endif 6763 return; 6764 } 6765 6766 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && 6767 (buf->contentIO != NULL)) { 6768 xmlFree(buf->contentIO); 6769 } else if ((buf->content != NULL) && 6770 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) { 6771 xmlFree(buf->content); 6772 } 6773 xmlFree(buf); 6774} 6775 6776/** 6777 * xmlBufferEmpty: 6778 * @buf: the buffer 6779 * 6780 * empty a buffer. 6781 */ 6782void 6783xmlBufferEmpty(xmlBufferPtr buf) { 6784 if (buf == NULL) return; 6785 if (buf->content == NULL) return; 6786 buf->use = 0; 6787 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) { 6788 buf->content = BAD_CAST ""; 6789 } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) && 6790 (buf->contentIO != NULL)) { 6791 size_t start_buf = buf->content - buf->contentIO; 6792 6793 buf->size += start_buf; 6794 buf->content = buf->contentIO; 6795 buf->content[0] = 0; 6796 } else { 6797 buf->content[0] = 0; 6798 } 6799} 6800 6801/** 6802 * xmlBufferShrink: 6803 * @buf: the buffer to dump 6804 * @len: the number of xmlChar to remove 6805 * 6806 * Remove the beginning of an XML buffer. 6807 * 6808 * Returns the number of #xmlChar removed, or -1 in case of failure. 6809 */ 6810int 6811xmlBufferShrink(xmlBufferPtr buf, unsigned int len) { 6812 if (buf == NULL) return(-1); 6813 if (len == 0) return(0); 6814 if (len > buf->use) return(-1); 6815 6816 buf->use -= len; 6817 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || 6818 ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) { 6819 /* 6820 * we just move the content pointer, but also make sure 6821 * the perceived buffer size has shrinked accordingly 6822 */ 6823 buf->content += len; 6824 buf->size -= len; 6825 6826 /* 6827 * sometimes though it maybe be better to really shrink 6828 * on IO buffers 6829 */ 6830 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 6831 size_t start_buf = buf->content - buf->contentIO; 6832 if (start_buf >= buf->size) { 6833 memmove(buf->contentIO, &buf->content[0], buf->use); 6834 buf->content = buf->contentIO; 6835 buf->content[buf->use] = 0; 6836 buf->size += start_buf; 6837 } 6838 } 6839 } else { 6840 memmove(buf->content, &buf->content[len], buf->use); 6841 buf->content[buf->use] = 0; 6842 } 6843 return(len); 6844} 6845 6846/** 6847 * xmlBufferGrow: 6848 * @buf: the buffer 6849 * @len: the minimum free size to allocate 6850 * 6851 * Grow the available space of an XML buffer. 6852 * 6853 * Returns the new available space or -1 in case of error 6854 */ 6855int 6856xmlBufferGrow(xmlBufferPtr buf, unsigned int len) { 6857 int size; 6858 xmlChar *newbuf; 6859 6860 if (buf == NULL) return(-1); 6861 6862 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); 6863 if (len + buf->use < buf->size) return(0); 6864 6865/* 6866 * Windows has a BIG problem on realloc timing, so we try to double 6867 * the buffer size (if that's enough) (bug 146697) 6868 */ 6869#ifdef WIN32 6870 if (buf->size > len) 6871 size = buf->size * 2; 6872 else 6873 size = buf->use + len + 100; 6874#else 6875 size = buf->use + len + 100; 6876#endif 6877 6878 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 6879 size_t start_buf = buf->content - buf->contentIO; 6880 6881 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size); 6882 if (newbuf == NULL) { 6883 xmlTreeErrMemory("growing buffer"); 6884 return(-1); 6885 } 6886 buf->contentIO = newbuf; 6887 buf->content = newbuf + start_buf; 6888 } else { 6889 newbuf = (xmlChar *) xmlRealloc(buf->content, size); 6890 if (newbuf == NULL) { 6891 xmlTreeErrMemory("growing buffer"); 6892 return(-1); 6893 } 6894 buf->content = newbuf; 6895 } 6896 buf->size = size; 6897 return(buf->size - buf->use); 6898} 6899 6900/** 6901 * xmlBufferDump: 6902 * @file: the file output 6903 * @buf: the buffer to dump 6904 * 6905 * Dumps an XML buffer to a FILE *. 6906 * Returns the number of #xmlChar written 6907 */ 6908int 6909xmlBufferDump(FILE *file, xmlBufferPtr buf) { 6910 int ret; 6911 6912 if (buf == NULL) { 6913#ifdef DEBUG_BUFFER 6914 xmlGenericError(xmlGenericErrorContext, 6915 "xmlBufferDump: buf == NULL\n"); 6916#endif 6917 return(0); 6918 } 6919 if (buf->content == NULL) { 6920#ifdef DEBUG_BUFFER 6921 xmlGenericError(xmlGenericErrorContext, 6922 "xmlBufferDump: buf->content == NULL\n"); 6923#endif 6924 return(0); 6925 } 6926 if (file == NULL) 6927 file = stdout; 6928 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file); 6929 return(ret); 6930} 6931 6932/** 6933 * xmlBufferContent: 6934 * @buf: the buffer 6935 * 6936 * Function to extract the content of a buffer 6937 * 6938 * Returns the internal content 6939 */ 6940 6941const xmlChar * 6942xmlBufferContent(const xmlBufferPtr buf) 6943{ 6944 if(!buf) 6945 return NULL; 6946 6947 return buf->content; 6948} 6949 6950/** 6951 * xmlBufferLength: 6952 * @buf: the buffer 6953 * 6954 * Function to get the length of a buffer 6955 * 6956 * Returns the length of data in the internal content 6957 */ 6958 6959int 6960xmlBufferLength(const xmlBufferPtr buf) 6961{ 6962 if(!buf) 6963 return 0; 6964 6965 return buf->use; 6966} 6967 6968/** 6969 * xmlBufferResize: 6970 * @buf: the buffer to resize 6971 * @size: the desired size 6972 * 6973 * Resize a buffer to accommodate minimum size of @size. 6974 * 6975 * Returns 0 in case of problems, 1 otherwise 6976 */ 6977int 6978xmlBufferResize(xmlBufferPtr buf, unsigned int size) 6979{ 6980 unsigned int newSize; 6981 xmlChar* rebuf = NULL; 6982 size_t start_buf; 6983 6984 if (buf == NULL) 6985 return(0); 6986 6987 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); 6988 6989 /* Don't resize if we don't have to */ 6990 if (size < buf->size) 6991 return 1; 6992 6993 /* figure out new size */ 6994 switch (buf->alloc){ 6995 case XML_BUFFER_ALLOC_IO: 6996 case XML_BUFFER_ALLOC_DOUBLEIT: 6997 /*take care of empty case*/ 6998 newSize = (buf->size ? buf->size*2 : size + 10); 6999 while (size > newSize) newSize *= 2; 7000 break; 7001 case XML_BUFFER_ALLOC_EXACT: 7002 newSize = size+10; 7003 break; 7004 default: 7005 newSize = size+10; 7006 break; 7007 } 7008 7009 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 7010 start_buf = buf->content - buf->contentIO; 7011 7012 if (start_buf > newSize) { 7013 /* move data back to start */ 7014 memmove(buf->contentIO, buf->content, buf->use); 7015 buf->content = buf->contentIO; 7016 buf->content[buf->use] = 0; 7017 buf->size += start_buf; 7018 } else { 7019 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize); 7020 if (rebuf == NULL) { 7021 xmlTreeErrMemory("growing buffer"); 7022 return 0; 7023 } 7024 buf->contentIO = rebuf; 7025 buf->content = rebuf + start_buf; 7026 } 7027 } else { 7028 if (buf->content == NULL) { 7029 rebuf = (xmlChar *) xmlMallocAtomic(newSize); 7030 } else if (buf->size - buf->use < 100) { 7031 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize); 7032 } else { 7033 /* 7034 * if we are reallocating a buffer far from being full, it's 7035 * better to make a new allocation and copy only the used range 7036 * and free the old one. 7037 */ 7038 rebuf = (xmlChar *) xmlMallocAtomic(newSize); 7039 if (rebuf != NULL) { 7040 memcpy(rebuf, buf->content, buf->use); 7041 xmlFree(buf->content); 7042 rebuf[buf->use] = 0; 7043 } 7044 } 7045 if (rebuf == NULL) { 7046 xmlTreeErrMemory("growing buffer"); 7047 return 0; 7048 } 7049 buf->content = rebuf; 7050 } 7051 buf->size = newSize; 7052 7053 return 1; 7054} 7055 7056/** 7057 * xmlBufferAdd: 7058 * @buf: the buffer to dump 7059 * @str: the #xmlChar string 7060 * @len: the number of #xmlChar to add 7061 * 7062 * Add a string range to an XML buffer. if len == -1, the length of 7063 * str is recomputed. 7064 * 7065 * Returns 0 successful, a positive error code number otherwise 7066 * and -1 in case of internal or API error. 7067 */ 7068int 7069xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) { 7070 unsigned int needSize; 7071 7072 if ((str == NULL) || (buf == NULL)) { 7073 return -1; 7074 } 7075 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7076 if (len < -1) { 7077#ifdef DEBUG_BUFFER 7078 xmlGenericError(xmlGenericErrorContext, 7079 "xmlBufferAdd: len < 0\n"); 7080#endif 7081 return -1; 7082 } 7083 if (len == 0) return 0; 7084 7085 if (len < 0) 7086 len = xmlStrlen(str); 7087 7088 if (len < 0) return -1; 7089 if (len == 0) return 0; 7090 7091 needSize = buf->use + len + 2; 7092 if (needSize > buf->size){ 7093 if (!xmlBufferResize(buf, needSize)){ 7094 xmlTreeErrMemory("growing buffer"); 7095 return XML_ERR_NO_MEMORY; 7096 } 7097 } 7098 7099 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar)); 7100 buf->use += len; 7101 buf->content[buf->use] = 0; 7102 return 0; 7103} 7104 7105/** 7106 * xmlBufferAddHead: 7107 * @buf: the buffer 7108 * @str: the #xmlChar string 7109 * @len: the number of #xmlChar to add 7110 * 7111 * Add a string range to the beginning of an XML buffer. 7112 * if len == -1, the length of @str is recomputed. 7113 * 7114 * Returns 0 successful, a positive error code number otherwise 7115 * and -1 in case of internal or API error. 7116 */ 7117int 7118xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) { 7119 unsigned int needSize; 7120 7121 if (buf == NULL) 7122 return(-1); 7123 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7124 if (str == NULL) { 7125#ifdef DEBUG_BUFFER 7126 xmlGenericError(xmlGenericErrorContext, 7127 "xmlBufferAddHead: str == NULL\n"); 7128#endif 7129 return -1; 7130 } 7131 if (len < -1) { 7132#ifdef DEBUG_BUFFER 7133 xmlGenericError(xmlGenericErrorContext, 7134 "xmlBufferAddHead: len < 0\n"); 7135#endif 7136 return -1; 7137 } 7138 if (len == 0) return 0; 7139 7140 if (len < 0) 7141 len = xmlStrlen(str); 7142 7143 if (len <= 0) return -1; 7144 7145 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { 7146 size_t start_buf = buf->content - buf->contentIO; 7147 7148 if (start_buf > (unsigned int) len) { 7149 /* 7150 * We can add it in the space previously shrinked 7151 */ 7152 buf->content -= len; 7153 memmove(&buf->content[0], str, len); 7154 buf->use += len; 7155 buf->size += len; 7156 return(0); 7157 } 7158 } 7159 needSize = buf->use + len + 2; 7160 if (needSize > buf->size){ 7161 if (!xmlBufferResize(buf, needSize)){ 7162 xmlTreeErrMemory("growing buffer"); 7163 return XML_ERR_NO_MEMORY; 7164 } 7165 } 7166 7167 memmove(&buf->content[len], &buf->content[0], buf->use); 7168 memmove(&buf->content[0], str, len); 7169 buf->use += len; 7170 buf->content[buf->use] = 0; 7171 return 0; 7172} 7173 7174/** 7175 * xmlBufferCat: 7176 * @buf: the buffer to add to 7177 * @str: the #xmlChar string 7178 * 7179 * Append a zero terminated string to an XML buffer. 7180 * 7181 * Returns 0 successful, a positive error code number otherwise 7182 * and -1 in case of internal or API error. 7183 */ 7184int 7185xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) { 7186 if (buf == NULL) 7187 return(-1); 7188 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7189 if (str == NULL) return -1; 7190 return xmlBufferAdd(buf, str, -1); 7191} 7192 7193/** 7194 * xmlBufferCCat: 7195 * @buf: the buffer to dump 7196 * @str: the C char string 7197 * 7198 * Append a zero terminated C string to an XML buffer. 7199 * 7200 * Returns 0 successful, a positive error code number otherwise 7201 * and -1 in case of internal or API error. 7202 */ 7203int 7204xmlBufferCCat(xmlBufferPtr buf, const char *str) { 7205 const char *cur; 7206 7207 if (buf == NULL) 7208 return(-1); 7209 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; 7210 if (str == NULL) { 7211#ifdef DEBUG_BUFFER 7212 xmlGenericError(xmlGenericErrorContext, 7213 "xmlBufferCCat: str == NULL\n"); 7214#endif 7215 return -1; 7216 } 7217 for (cur = str;*cur != 0;cur++) { 7218 if (buf->use + 10 >= buf->size) { 7219 if (!xmlBufferResize(buf, buf->use+10)){ 7220 xmlTreeErrMemory("growing buffer"); 7221 return XML_ERR_NO_MEMORY; 7222 } 7223 } 7224 buf->content[buf->use++] = *cur; 7225 } 7226 buf->content[buf->use] = 0; 7227 return 0; 7228} 7229 7230/** 7231 * xmlBufferWriteCHAR: 7232 * @buf: the XML buffer 7233 * @string: the string to add 7234 * 7235 * routine which manages and grows an output buffer. This one adds 7236 * xmlChars at the end of the buffer. 7237 */ 7238void 7239xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) { 7240 if (buf == NULL) 7241 return; 7242 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 7243 xmlBufferCat(buf, string); 7244} 7245 7246/** 7247 * xmlBufferWriteChar: 7248 * @buf: the XML buffer output 7249 * @string: the string to add 7250 * 7251 * routine which manage and grows an output buffer. This one add 7252 * C chars at the end of the array. 7253 */ 7254void 7255xmlBufferWriteChar(xmlBufferPtr buf, const char *string) { 7256 if (buf == NULL) 7257 return; 7258 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 7259 xmlBufferCCat(buf, string); 7260} 7261 7262 7263/** 7264 * xmlBufferWriteQuotedString: 7265 * @buf: the XML buffer output 7266 * @string: the string to add 7267 * 7268 * routine which manage and grows an output buffer. This one writes 7269 * a quoted or double quoted #xmlChar string, checking first if it holds 7270 * quote or double-quotes internally 7271 */ 7272void 7273xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) { 7274 const xmlChar *cur, *base; 7275 if (buf == NULL) 7276 return; 7277 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; 7278 if (xmlStrchr(string, '\"')) { 7279 if (xmlStrchr(string, '\'')) { 7280#ifdef DEBUG_BUFFER 7281 xmlGenericError(xmlGenericErrorContext, 7282 "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n"); 7283#endif 7284 xmlBufferCCat(buf, "\""); 7285 base = cur = string; 7286 while(*cur != 0){ 7287 if(*cur == '"'){ 7288 if (base != cur) 7289 xmlBufferAdd(buf, base, cur - base); 7290 xmlBufferAdd(buf, BAD_CAST """, 6); 7291 cur++; 7292 base = cur; 7293 } 7294 else { 7295 cur++; 7296 } 7297 } 7298 if (base != cur) 7299 xmlBufferAdd(buf, base, cur - base); 7300 xmlBufferCCat(buf, "\""); 7301 } 7302 else{ 7303 xmlBufferCCat(buf, "\'"); 7304 xmlBufferCat(buf, string); 7305 xmlBufferCCat(buf, "\'"); 7306 } 7307 } else { 7308 xmlBufferCCat(buf, "\""); 7309 xmlBufferCat(buf, string); 7310 xmlBufferCCat(buf, "\""); 7311 } 7312} 7313 7314 7315/** 7316 * xmlGetDocCompressMode: 7317 * @doc: the document 7318 * 7319 * get the compression ratio for a document, ZLIB based 7320 * Returns 0 (uncompressed) to 9 (max compression) 7321 */ 7322int 7323xmlGetDocCompressMode (xmlDocPtr doc) { 7324 if (doc == NULL) return(-1); 7325 return(doc->compression); 7326} 7327 7328/** 7329 * xmlSetDocCompressMode: 7330 * @doc: the document 7331 * @mode: the compression ratio 7332 * 7333 * set the compression ratio for a document, ZLIB based 7334 * Correct values: 0 (uncompressed) to 9 (max compression) 7335 */ 7336void 7337xmlSetDocCompressMode (xmlDocPtr doc, int mode) { 7338 if (doc == NULL) return; 7339 if (mode < 0) doc->compression = 0; 7340 else if (mode > 9) doc->compression = 9; 7341 else doc->compression = mode; 7342} 7343 7344/** 7345 * xmlGetCompressMode: 7346 * 7347 * get the default compression mode used, ZLIB based. 7348 * Returns 0 (uncompressed) to 9 (max compression) 7349 */ 7350int 7351xmlGetCompressMode(void) 7352{ 7353 return (xmlCompressMode); 7354} 7355 7356/** 7357 * xmlSetCompressMode: 7358 * @mode: the compression ratio 7359 * 7360 * set the default compression mode used, ZLIB based 7361 * Correct values: 0 (uncompressed) to 9 (max compression) 7362 */ 7363void 7364xmlSetCompressMode(int mode) { 7365 if (mode < 0) xmlCompressMode = 0; 7366 else if (mode > 9) xmlCompressMode = 9; 7367 else xmlCompressMode = mode; 7368} 7369 7370#define XML_TREE_NSMAP_PARENT -1 7371#define XML_TREE_NSMAP_XML -2 7372#define XML_TREE_NSMAP_DOC -3 7373#define XML_TREE_NSMAP_CUSTOM -4 7374 7375typedef struct xmlNsMapItem *xmlNsMapItemPtr; 7376struct xmlNsMapItem { 7377 xmlNsMapItemPtr next; 7378 xmlNsMapItemPtr prev; 7379 xmlNsPtr oldNs; /* old ns decl reference */ 7380 xmlNsPtr newNs; /* new ns decl reference */ 7381 int shadowDepth; /* Shadowed at this depth */ 7382 /* 7383 * depth: 7384 * >= 0 == @node's ns-decls 7385 * -1 == @parent's ns-decls 7386 * -2 == the doc->oldNs XML ns-decl 7387 * -3 == the doc->oldNs storage ns-decls 7388 * -4 == ns-decls provided via custom ns-handling 7389 */ 7390 int depth; 7391}; 7392 7393typedef struct xmlNsMap *xmlNsMapPtr; 7394struct xmlNsMap { 7395 xmlNsMapItemPtr first; 7396 xmlNsMapItemPtr last; 7397 xmlNsMapItemPtr pool; 7398}; 7399 7400#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL)) 7401#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next) 7402#define XML_NSMAP_POP(m, i) \ 7403 i = (m)->last; \ 7404 (m)->last = (i)->prev; \ 7405 if ((m)->last == NULL) \ 7406 (m)->first = NULL; \ 7407 else \ 7408 (m)->last->next = NULL; \ 7409 (i)->next = (m)->pool; \ 7410 (m)->pool = i; 7411 7412/* 7413* xmlDOMWrapNsMapFree: 7414* @map: the ns-map 7415* 7416* Frees the ns-map 7417*/ 7418static void 7419xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap) 7420{ 7421 xmlNsMapItemPtr cur, tmp; 7422 7423 if (nsmap == NULL) 7424 return; 7425 cur = nsmap->pool; 7426 while (cur != NULL) { 7427 tmp = cur; 7428 cur = cur->next; 7429 xmlFree(tmp); 7430 } 7431 cur = nsmap->first; 7432 while (cur != NULL) { 7433 tmp = cur; 7434 cur = cur->next; 7435 xmlFree(tmp); 7436 } 7437 xmlFree(nsmap); 7438} 7439 7440/* 7441* xmlDOMWrapNsMapAddItem: 7442* @map: the ns-map 7443* @oldNs: the old ns-struct 7444* @newNs: the new ns-struct 7445* @depth: depth and ns-kind information 7446* 7447* Adds an ns-mapping item. 7448*/ 7449static xmlNsMapItemPtr 7450xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, 7451 xmlNsPtr oldNs, xmlNsPtr newNs, int depth) 7452{ 7453 xmlNsMapItemPtr ret; 7454 xmlNsMapPtr map; 7455 7456 if (nsmap == NULL) 7457 return(NULL); 7458 if ((position != -1) && (position != 0)) 7459 return(NULL); 7460 map = *nsmap; 7461 7462 if (map == NULL) { 7463 /* 7464 * Create the ns-map. 7465 */ 7466 map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap)); 7467 if (map == NULL) { 7468 xmlTreeErrMemory("allocating namespace map"); 7469 return (NULL); 7470 } 7471 memset(map, 0, sizeof(struct xmlNsMap)); 7472 *nsmap = map; 7473 } 7474 7475 if (map->pool != NULL) { 7476 /* 7477 * Reuse an item from the pool. 7478 */ 7479 ret = map->pool; 7480 map->pool = ret->next; 7481 memset(ret, 0, sizeof(struct xmlNsMapItem)); 7482 } else { 7483 /* 7484 * Create a new item. 7485 */ 7486 ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem)); 7487 if (ret == NULL) { 7488 xmlTreeErrMemory("allocating namespace map item"); 7489 return (NULL); 7490 } 7491 memset(ret, 0, sizeof(struct xmlNsMapItem)); 7492 } 7493 7494 if (map->first == NULL) { 7495 /* 7496 * First ever. 7497 */ 7498 map->first = ret; 7499 map->last = ret; 7500 } else if (position == -1) { 7501 /* 7502 * Append. 7503 */ 7504 ret->prev = map->last; 7505 map->last->next = ret; 7506 map->last = ret; 7507 } else if (position == 0) { 7508 /* 7509 * Set on first position. 7510 */ 7511 map->first->prev = ret; 7512 ret->next = map->first; 7513 map->first = ret; 7514 } else 7515 return(NULL); 7516 7517 ret->oldNs = oldNs; 7518 ret->newNs = newNs; 7519 ret->shadowDepth = -1; 7520 ret->depth = depth; 7521 return (ret); 7522} 7523 7524/* 7525* xmlDOMWrapStoreNs: 7526* @doc: the doc 7527* @nsName: the namespace name 7528* @prefix: the prefix 7529* 7530* Creates or reuses an xmlNs struct on doc->oldNs with 7531* the given prefix and namespace name. 7532* 7533* Returns the aquired ns struct or NULL in case of an API 7534* or internal error. 7535*/ 7536static xmlNsPtr 7537xmlDOMWrapStoreNs(xmlDocPtr doc, 7538 const xmlChar *nsName, 7539 const xmlChar *prefix) 7540{ 7541 xmlNsPtr ns; 7542 7543 if (doc == NULL) 7544 return (NULL); 7545 ns = xmlTreeEnsureXMLDecl(doc); 7546 if (ns == NULL) 7547 return (NULL); 7548 if (ns->next != NULL) { 7549 /* Reuse. */ 7550 ns = ns->next; 7551 while (ns != NULL) { 7552 if (((ns->prefix == prefix) || 7553 xmlStrEqual(ns->prefix, prefix)) && 7554 xmlStrEqual(ns->href, nsName)) { 7555 return (ns); 7556 } 7557 if (ns->next == NULL) 7558 break; 7559 ns = ns->next; 7560 } 7561 } 7562 /* Create. */ 7563 ns->next = xmlNewNs(NULL, nsName, prefix); 7564 return (ns->next); 7565} 7566 7567/* 7568* xmlDOMWrapNewCtxt: 7569* 7570* Allocates and initializes a new DOM-wrapper context. 7571* 7572* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror. 7573*/ 7574xmlDOMWrapCtxtPtr 7575xmlDOMWrapNewCtxt(void) 7576{ 7577 xmlDOMWrapCtxtPtr ret; 7578 7579 ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); 7580 if (ret == NULL) { 7581 xmlTreeErrMemory("allocating DOM-wrapper context"); 7582 return (NULL); 7583 } 7584 memset(ret, 0, sizeof(xmlDOMWrapCtxt)); 7585 return (ret); 7586} 7587 7588/* 7589* xmlDOMWrapFreeCtxt: 7590* @ctxt: the DOM-wrapper context 7591* 7592* Frees the DOM-wrapper context. 7593*/ 7594void 7595xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt) 7596{ 7597 if (ctxt == NULL) 7598 return; 7599 if (ctxt->namespaceMap != NULL) 7600 xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap); 7601 /* 7602 * TODO: Store the namespace map in the context. 7603 */ 7604 xmlFree(ctxt); 7605} 7606 7607/* 7608* xmlTreeLookupNsListByPrefix: 7609* @nsList: a list of ns-structs 7610* @prefix: the searched prefix 7611* 7612* Searches for a ns-decl with the given prefix in @nsList. 7613* 7614* Returns the ns-decl if found, NULL if not found and on 7615* API errors. 7616*/ 7617static xmlNsPtr 7618xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix) 7619{ 7620 if (nsList == NULL) 7621 return (NULL); 7622 { 7623 xmlNsPtr ns; 7624 ns = nsList; 7625 do { 7626 if ((prefix == ns->prefix) || 7627 xmlStrEqual(prefix, ns->prefix)) { 7628 return (ns); 7629 } 7630 ns = ns->next; 7631 } while (ns != NULL); 7632 } 7633 return (NULL); 7634} 7635 7636/* 7637* 7638* xmlDOMWrapNSNormGatherInScopeNs: 7639* @map: the namespace map 7640* @node: the node to start with 7641* 7642* Puts in-scope namespaces into the ns-map. 7643* 7644* Returns 0 on success, -1 on API or internal errors. 7645*/ 7646static int 7647xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map, 7648 xmlNodePtr node) 7649{ 7650 xmlNodePtr cur; 7651 xmlNsPtr ns; 7652 xmlNsMapItemPtr mi; 7653 int shadowed; 7654 7655 if ((map == NULL) || (*map != NULL)) 7656 return (-1); 7657 /* 7658 * Get in-scope ns-decls of @parent. 7659 */ 7660 cur = node; 7661 while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) { 7662 if (cur->type == XML_ELEMENT_NODE) { 7663 if (cur->nsDef != NULL) { 7664 ns = cur->nsDef; 7665 do { 7666 shadowed = 0; 7667 if (XML_NSMAP_NOTEMPTY(*map)) { 7668 /* 7669 * Skip shadowed prefixes. 7670 */ 7671 XML_NSMAP_FOREACH(*map, mi) { 7672 if ((ns->prefix == mi->newNs->prefix) || 7673 xmlStrEqual(ns->prefix, mi->newNs->prefix)) { 7674 shadowed = 1; 7675 break; 7676 } 7677 } 7678 } 7679 /* 7680 * Insert mapping. 7681 */ 7682 mi = xmlDOMWrapNsMapAddItem(map, 0, NULL, 7683 ns, XML_TREE_NSMAP_PARENT); 7684 if (mi == NULL) 7685 return (-1); 7686 if (shadowed) 7687 mi->shadowDepth = 0; 7688 ns = ns->next; 7689 } while (ns != NULL); 7690 } 7691 } 7692 cur = cur->parent; 7693 } 7694 return (0); 7695} 7696 7697/* 7698* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict; 7699* otherwise copy it, when it was in the source-dict. 7700*/ 7701#define XML_TREE_ADOPT_STR(str) \ 7702 if (adoptStr && (str != NULL)) { \ 7703 if (destDoc->dict) { \ 7704 const xmlChar *old = str; \ 7705 str = xmlDictLookup(destDoc->dict, str, -1); \ 7706 if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \ 7707 (!xmlDictOwns(sourceDoc->dict, old))) \ 7708 xmlFree((char *)old); \ 7709 } else if ((sourceDoc) && (sourceDoc->dict) && \ 7710 xmlDictOwns(sourceDoc->dict, str)) { \ 7711 str = BAD_CAST xmlStrdup(str); \ 7712 } \ 7713 } 7714 7715/* 7716* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then 7717* put it in dest-dict or copy it. 7718*/ 7719#define XML_TREE_ADOPT_STR_2(str) \ 7720 if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \ 7721 (sourceDoc->dict != NULL) && \ 7722 xmlDictOwns(sourceDoc->dict, cur->content)) { \ 7723 if (destDoc->dict) \ 7724 cur->content = (xmlChar *) \ 7725 xmlDictLookup(destDoc->dict, cur->content, -1); \ 7726 else \ 7727 cur->content = xmlStrdup(BAD_CAST cur->content); \ 7728 } 7729 7730/* 7731* xmlDOMWrapNSNormAddNsMapItem2: 7732* 7733* For internal use. Adds a ns-decl mapping. 7734* 7735* Returns 0 on success, -1 on internal errors. 7736*/ 7737static int 7738xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number, 7739 xmlNsPtr oldNs, xmlNsPtr newNs) 7740{ 7741 if (*list == NULL) { 7742 *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr)); 7743 if (*list == NULL) { 7744 xmlTreeErrMemory("alloc ns map item"); 7745 return(-1); 7746 } 7747 *size = 3; 7748 *number = 0; 7749 } else if ((*number) >= (*size)) { 7750 *size *= 2; 7751 *list = (xmlNsPtr *) xmlRealloc(*list, 7752 (*size) * 2 * sizeof(xmlNsPtr)); 7753 if (*list == NULL) { 7754 xmlTreeErrMemory("realloc ns map item"); 7755 return(-1); 7756 } 7757 } 7758 (*list)[2 * (*number)] = oldNs; 7759 (*list)[2 * (*number) +1] = newNs; 7760 (*number)++; 7761 return (0); 7762} 7763 7764/* 7765* xmlDOMWrapRemoveNode: 7766* @ctxt: a DOM wrapper context 7767* @doc: the doc 7768* @node: the node to be removed. 7769* @options: set of options, unused at the moment 7770* 7771* Unlinks the given node from its owner. 7772* This will substitute ns-references to node->nsDef for 7773* ns-references to doc->oldNs, thus ensuring the removed 7774* branch to be autark wrt ns-references. 7775* 7776* NOTE: This function was not intensively tested. 7777* 7778* Returns 0 on success, 1 if the node is not supported, 7779* -1 on API and internal errors. 7780*/ 7781int 7782xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, 7783 xmlNodePtr node, int options ATTRIBUTE_UNUSED) 7784{ 7785 xmlNsPtr *list = NULL; 7786 int sizeList, nbList, i, j; 7787 xmlNsPtr ns; 7788 7789 if ((node == NULL) || (doc == NULL) || (node->doc != doc)) 7790 return (-1); 7791 7792 /* TODO: 0 or -1 ? */ 7793 if (node->parent == NULL) 7794 return (0); 7795 7796 switch (node->type) { 7797 case XML_TEXT_NODE: 7798 case XML_CDATA_SECTION_NODE: 7799 case XML_ENTITY_REF_NODE: 7800 case XML_PI_NODE: 7801 case XML_COMMENT_NODE: 7802 xmlUnlinkNode(node); 7803 return (0); 7804 case XML_ELEMENT_NODE: 7805 case XML_ATTRIBUTE_NODE: 7806 break; 7807 default: 7808 return (1); 7809 } 7810 xmlUnlinkNode(node); 7811 /* 7812 * Save out-of-scope ns-references in doc->oldNs. 7813 */ 7814 do { 7815 switch (node->type) { 7816 case XML_ELEMENT_NODE: 7817 if ((ctxt == NULL) && (node->nsDef != NULL)) { 7818 ns = node->nsDef; 7819 do { 7820 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, 7821 &nbList, ns, ns) == -1) 7822 goto internal_error; 7823 ns = ns->next; 7824 } while (ns != NULL); 7825 } 7826 /* No break on purpose. */ 7827 case XML_ATTRIBUTE_NODE: 7828 if (node->ns != NULL) { 7829 /* 7830 * Find a mapping. 7831 */ 7832 if (list != NULL) { 7833 for (i = 0, j = 0; i < nbList; i++, j += 2) { 7834 if (node->ns == list[j]) { 7835 node->ns = list[++j]; 7836 goto next_node; 7837 } 7838 } 7839 } 7840 ns = NULL; 7841 if (ctxt != NULL) { 7842 /* 7843 * User defined. 7844 */ 7845 } else { 7846 /* 7847 * Add to doc's oldNs. 7848 */ 7849 ns = xmlDOMWrapStoreNs(doc, node->ns->href, 7850 node->ns->prefix); 7851 if (ns == NULL) 7852 goto internal_error; 7853 } 7854 if (ns != NULL) { 7855 /* 7856 * Add mapping. 7857 */ 7858 if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, 7859 &nbList, node->ns, ns) == -1) 7860 goto internal_error; 7861 } 7862 node->ns = ns; 7863 } 7864 if ((node->type == XML_ELEMENT_NODE) && 7865 (node->properties != NULL)) { 7866 node = (xmlNodePtr) node->properties; 7867 continue; 7868 } 7869 break; 7870 default: 7871 goto next_sibling; 7872 } 7873next_node: 7874 if ((node->type == XML_ELEMENT_NODE) && 7875 (node->children != NULL)) { 7876 node = node->children; 7877 continue; 7878 } 7879next_sibling: 7880 if (node == NULL) 7881 break; 7882 if (node->next != NULL) 7883 node = node->next; 7884 else { 7885 node = node->parent; 7886 goto next_sibling; 7887 } 7888 } while (node != NULL); 7889 7890 if (list != NULL) 7891 xmlFree(list); 7892 return (0); 7893 7894internal_error: 7895 if (list != NULL) 7896 xmlFree(list); 7897 return (-1); 7898} 7899 7900/* 7901* xmlSearchNsByNamespaceStrict: 7902* @doc: the document 7903* @node: the start node 7904* @nsName: the searched namespace name 7905* @retNs: the resulting ns-decl 7906* @prefixed: if the found ns-decl must have a prefix (for attributes) 7907* 7908* Dynamically searches for a ns-declaration which matches 7909* the given @nsName in the ancestor-or-self axis of @node. 7910* 7911* Returns 1 if a ns-decl was found, 0 if not and -1 on API 7912* and internal errors. 7913*/ 7914static int 7915xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node, 7916 const xmlChar* nsName, 7917 xmlNsPtr *retNs, int prefixed) 7918{ 7919 xmlNodePtr cur, prev = NULL, out = NULL; 7920 xmlNsPtr ns, prevns; 7921 7922 if ((doc == NULL) || (nsName == NULL) || (retNs == NULL)) 7923 return (-1); 7924 7925 *retNs = NULL; 7926 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { 7927 *retNs = xmlTreeEnsureXMLDecl(doc); 7928 if (*retNs == NULL) 7929 return (-1); 7930 return (1); 7931 } 7932 cur = node; 7933 do { 7934 if (cur->type == XML_ELEMENT_NODE) { 7935 if (cur->nsDef != NULL) { 7936 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 7937 if (prefixed && (ns->prefix == NULL)) 7938 continue; 7939 if (prev != NULL) { 7940 /* 7941 * Check the last level of ns-decls for a 7942 * shadowing prefix. 7943 */ 7944 prevns = prev->nsDef; 7945 do { 7946 if ((prevns->prefix == ns->prefix) || 7947 ((prevns->prefix != NULL) && 7948 (ns->prefix != NULL) && 7949 xmlStrEqual(prevns->prefix, ns->prefix))) { 7950 /* 7951 * Shadowed. 7952 */ 7953 break; 7954 } 7955 prevns = prevns->next; 7956 } while (prevns != NULL); 7957 if (prevns != NULL) 7958 continue; 7959 } 7960 /* 7961 * Ns-name comparison. 7962 */ 7963 if ((nsName == ns->href) || 7964 xmlStrEqual(nsName, ns->href)) { 7965 /* 7966 * At this point the prefix can only be shadowed, 7967 * if we are the the (at least) 3rd level of 7968 * ns-decls. 7969 */ 7970 if (out) { 7971 int ret; 7972 7973 ret = xmlNsInScope(doc, node, prev, ns->prefix); 7974 if (ret < 0) 7975 return (-1); 7976 /* 7977 * TODO: Should we try to find a matching ns-name 7978 * only once? This here keeps on searching. 7979 * I think we should try further since, there might 7980 * be an other matching ns-decl with an unshadowed 7981 * prefix. 7982 */ 7983 if (! ret) 7984 continue; 7985 } 7986 *retNs = ns; 7987 return (1); 7988 } 7989 } 7990 out = prev; 7991 prev = cur; 7992 } 7993 } else if ((cur->type == XML_ENTITY_NODE) || 7994 (cur->type == XML_ENTITY_DECL)) 7995 return (0); 7996 cur = cur->parent; 7997 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); 7998 return (0); 7999} 8000 8001/* 8002* xmlSearchNsByPrefixStrict: 8003* @doc: the document 8004* @node: the start node 8005* @prefix: the searched namespace prefix 8006* @retNs: the resulting ns-decl 8007* 8008* Dynamically searches for a ns-declaration which matches 8009* the given @nsName in the ancestor-or-self axis of @node. 8010* 8011* Returns 1 if a ns-decl was found, 0 if not and -1 on API 8012* and internal errors. 8013*/ 8014static int 8015xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node, 8016 const xmlChar* prefix, 8017 xmlNsPtr *retNs) 8018{ 8019 xmlNodePtr cur; 8020 xmlNsPtr ns; 8021 8022 if ((doc == NULL) || (node == NULL)) 8023 return (-1); 8024 8025 if (retNs) 8026 *retNs = NULL; 8027 if (IS_STR_XML(prefix)) { 8028 if (retNs) { 8029 *retNs = xmlTreeEnsureXMLDecl(doc); 8030 if (*retNs == NULL) 8031 return (-1); 8032 } 8033 return (1); 8034 } 8035 cur = node; 8036 do { 8037 if (cur->type == XML_ELEMENT_NODE) { 8038 if (cur->nsDef != NULL) { 8039 ns = cur->nsDef; 8040 do { 8041 if ((prefix == ns->prefix) || 8042 xmlStrEqual(prefix, ns->prefix)) 8043 { 8044 /* 8045 * Disabled namespaces, e.g. xmlns:abc="". 8046 */ 8047 if (ns->href == NULL) 8048 return(0); 8049 if (retNs) 8050 *retNs = ns; 8051 return (1); 8052 } 8053 ns = ns->next; 8054 } while (ns != NULL); 8055 } 8056 } else if ((cur->type == XML_ENTITY_NODE) || 8057 (cur->type == XML_ENTITY_DECL)) 8058 return (0); 8059 cur = cur->parent; 8060 } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); 8061 return (0); 8062} 8063 8064/* 8065* xmlDOMWrapNSNormDeclareNsForced: 8066* @doc: the doc 8067* @elem: the element-node to declare on 8068* @nsName: the namespace-name of the ns-decl 8069* @prefix: the preferred prefix of the ns-decl 8070* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls 8071* 8072* Declares a new namespace on @elem. It tries to use the 8073* given @prefix; if a ns-decl with the given prefix is already existent 8074* on @elem, it will generate an other prefix. 8075* 8076* Returns 1 if a ns-decl was found, 0 if not and -1 on API 8077* and internal errors. 8078*/ 8079static xmlNsPtr 8080xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc, 8081 xmlNodePtr elem, 8082 const xmlChar *nsName, 8083 const xmlChar *prefix, 8084 int checkShadow) 8085{ 8086 8087 xmlNsPtr ret; 8088 char buf[50]; 8089 const xmlChar *pref; 8090 int counter = 0; 8091 /* 8092 * Create a ns-decl on @anchor. 8093 */ 8094 pref = prefix; 8095 while (1) { 8096 /* 8097 * Lookup whether the prefix is unused in elem's ns-decls. 8098 */ 8099 if ((elem->nsDef != NULL) && 8100 (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL)) 8101 goto ns_next_prefix; 8102 if (checkShadow && elem->parent && 8103 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 8104 /* 8105 * Does it shadow ancestor ns-decls? 8106 */ 8107 if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1) 8108 goto ns_next_prefix; 8109 } 8110 ret = xmlNewNs(NULL, nsName, pref); 8111 if (ret == NULL) 8112 return (NULL); 8113 if (elem->nsDef == NULL) 8114 elem->nsDef = ret; 8115 else { 8116 xmlNsPtr ns2 = elem->nsDef; 8117 while (ns2->next != NULL) 8118 ns2 = ns2->next; 8119 ns2->next = ret; 8120 } 8121 return (ret); 8122ns_next_prefix: 8123 counter++; 8124 if (counter > 1000) 8125 return (NULL); 8126 if (prefix == NULL) { 8127 snprintf((char *) buf, sizeof(buf), 8128 "ns_%d", counter); 8129 } else 8130 snprintf((char *) buf, sizeof(buf), 8131 "%.30s_%d", (char *)prefix, counter); 8132 pref = BAD_CAST buf; 8133 } 8134} 8135 8136/* 8137* xmlDOMWrapNSNormAquireNormalizedNs: 8138* @doc: the doc 8139* @elem: the element-node to declare namespaces on 8140* @ns: the ns-struct to use for the search 8141* @retNs: the found/created ns-struct 8142* @nsMap: the ns-map 8143* @depth: the current tree depth 8144* @ancestorsOnly: search in ancestor ns-decls only 8145* @prefixed: if the searched ns-decl must have a prefix (for attributes) 8146* 8147* Searches for a matching ns-name in the ns-decls of @nsMap, if not 8148* found it will either declare it on @elem, or store it in doc->oldNs. 8149* If a new ns-decl needs to be declared on @elem, it tries to use the 8150* @ns->prefix for it, if this prefix is already in use on @elem, it will 8151* change the prefix or the new ns-decl. 8152* 8153* Returns 0 if succeeded, -1 otherwise and on API/internal errors. 8154*/ 8155static int 8156xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc, 8157 xmlNodePtr elem, 8158 xmlNsPtr ns, 8159 xmlNsPtr *retNs, 8160 xmlNsMapPtr *nsMap, 8161 8162 int depth, 8163 int ancestorsOnly, 8164 int prefixed) 8165{ 8166 xmlNsMapItemPtr mi; 8167 8168 if ((doc == NULL) || (ns == NULL) || (retNs == NULL) || 8169 (nsMap == NULL)) 8170 return (-1); 8171 8172 *retNs = NULL; 8173 /* 8174 * Handle XML namespace. 8175 */ 8176 if (IS_STR_XML(ns->prefix)) { 8177 /* 8178 * Insert XML namespace mapping. 8179 */ 8180 *retNs = xmlTreeEnsureXMLDecl(doc); 8181 if (*retNs == NULL) 8182 return (-1); 8183 return (0); 8184 } 8185 /* 8186 * If the search should be done in ancestors only and no 8187 * @elem (the first ancestor) was specified, then skip the search. 8188 */ 8189 if ((XML_NSMAP_NOTEMPTY(*nsMap)) && 8190 (! (ancestorsOnly && (elem == NULL)))) 8191 { 8192 /* 8193 * Try to find an equal ns-name in in-scope ns-decls. 8194 */ 8195 XML_NSMAP_FOREACH(*nsMap, mi) { 8196 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8197 /* 8198 * ancestorsOnly: This should be turned on to gain speed, 8199 * if one knows that the branch itself was already 8200 * ns-wellformed and no stale references existed. 8201 * I.e. it searches in the ancestor axis only. 8202 */ 8203 ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) && 8204 /* Skip shadowed prefixes. */ 8205 (mi->shadowDepth == -1) && 8206 /* Skip xmlns="" or xmlns:foo="". */ 8207 ((mi->newNs->href != NULL) && 8208 (mi->newNs->href[0] != 0)) && 8209 /* Ensure a prefix if wanted. */ 8210 ((! prefixed) || (mi->newNs->prefix != NULL)) && 8211 /* Equal ns name */ 8212 ((mi->newNs->href == ns->href) || 8213 xmlStrEqual(mi->newNs->href, ns->href))) { 8214 /* Set the mapping. */ 8215 mi->oldNs = ns; 8216 *retNs = mi->newNs; 8217 return (0); 8218 } 8219 } 8220 } 8221 /* 8222 * No luck, the namespace is out of scope or shadowed. 8223 */ 8224 if (elem == NULL) { 8225 xmlNsPtr tmpns; 8226 8227 /* 8228 * Store ns-decls in "oldNs" of the document-node. 8229 */ 8230 tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix); 8231 if (tmpns == NULL) 8232 return (-1); 8233 /* 8234 * Insert mapping. 8235 */ 8236 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, 8237 tmpns, XML_TREE_NSMAP_DOC) == NULL) { 8238 xmlFreeNs(tmpns); 8239 return (-1); 8240 } 8241 *retNs = tmpns; 8242 } else { 8243 xmlNsPtr tmpns; 8244 8245 tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href, 8246 ns->prefix, 0); 8247 if (tmpns == NULL) 8248 return (-1); 8249 8250 if (*nsMap != NULL) { 8251 /* 8252 * Does it shadow ancestor ns-decls? 8253 */ 8254 XML_NSMAP_FOREACH(*nsMap, mi) { 8255 if ((mi->depth < depth) && 8256 (mi->shadowDepth == -1) && 8257 ((ns->prefix == mi->newNs->prefix) || 8258 xmlStrEqual(ns->prefix, mi->newNs->prefix))) { 8259 /* 8260 * Shadows. 8261 */ 8262 mi->shadowDepth = depth; 8263 break; 8264 } 8265 } 8266 } 8267 if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) { 8268 xmlFreeNs(tmpns); 8269 return (-1); 8270 } 8271 *retNs = tmpns; 8272 } 8273 return (0); 8274} 8275 8276typedef enum { 8277 XML_DOM_RECONNS_REMOVEREDUND = 1<<0 8278} xmlDOMReconcileNSOptions; 8279 8280/* 8281* xmlDOMWrapReconcileNamespaces: 8282* @ctxt: DOM wrapper context, unused at the moment 8283* @elem: the element-node 8284* @options: option flags 8285* 8286* Ensures that ns-references point to ns-decls hold on element-nodes. 8287* Ensures that the tree is namespace wellformed by creating additional 8288* ns-decls where needed. Note that, since prefixes of already existent 8289* ns-decls can be shadowed by this process, it could break QNames in 8290* attribute values or element content. 8291* 8292* NOTE: This function was not intensively tested. 8293* 8294* Returns 0 if succeeded, -1 otherwise and on API/internal errors. 8295*/ 8296 8297int 8298xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, 8299 xmlNodePtr elem, 8300 int options) 8301{ 8302 int depth = -1, adoptns = 0, parnsdone = 0; 8303 xmlNsPtr ns, prevns; 8304 xmlDocPtr doc; 8305 xmlNodePtr cur, curElem = NULL; 8306 xmlNsMapPtr nsMap = NULL; 8307 xmlNsMapItemPtr /* topmi = NULL, */ mi; 8308 /* @ancestorsOnly should be set by an option flag. */ 8309 int ancestorsOnly = 0; 8310 int optRemoveRedundantNS = 8311 ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0; 8312 xmlNsPtr *listRedund = NULL; 8313 int sizeRedund = 0, nbRedund = 0, ret, i, j; 8314 8315 if ((elem == NULL) || (elem->doc == NULL) || 8316 (elem->type != XML_ELEMENT_NODE)) 8317 return (-1); 8318 8319 doc = elem->doc; 8320 cur = elem; 8321 do { 8322 switch (cur->type) { 8323 case XML_ELEMENT_NODE: 8324 adoptns = 1; 8325 curElem = cur; 8326 depth++; 8327 /* 8328 * Namespace declarations. 8329 */ 8330 if (cur->nsDef != NULL) { 8331 prevns = NULL; 8332 ns = cur->nsDef; 8333 while (ns != NULL) { 8334 if (! parnsdone) { 8335 if ((elem->parent) && 8336 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 8337 /* 8338 * Gather ancestor in-scope ns-decls. 8339 */ 8340 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8341 elem->parent) == -1) 8342 goto internal_error; 8343 } 8344 parnsdone = 1; 8345 } 8346 8347 /* 8348 * Lookup the ns ancestor-axis for equal ns-decls in scope. 8349 */ 8350 if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) { 8351 XML_NSMAP_FOREACH(nsMap, mi) { 8352 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8353 (mi->shadowDepth == -1) && 8354 ((ns->prefix == mi->newNs->prefix) || 8355 xmlStrEqual(ns->prefix, mi->newNs->prefix)) && 8356 ((ns->href == mi->newNs->href) || 8357 xmlStrEqual(ns->href, mi->newNs->href))) 8358 { 8359 /* 8360 * A redundant ns-decl was found. 8361 * Add it to the list of redundant ns-decls. 8362 */ 8363 if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund, 8364 &sizeRedund, &nbRedund, ns, mi->newNs) == -1) 8365 goto internal_error; 8366 /* 8367 * Remove the ns-decl from the element-node. 8368 */ 8369 if (prevns) 8370 prevns->next = ns->next; 8371 else 8372 cur->nsDef = ns->next; 8373 goto next_ns_decl; 8374 } 8375 } 8376 } 8377 8378 /* 8379 * Skip ns-references handling if the referenced 8380 * ns-decl is declared on the same element. 8381 */ 8382 if ((cur->ns != NULL) && adoptns && (cur->ns == ns)) 8383 adoptns = 0; 8384 /* 8385 * Does it shadow any ns-decl? 8386 */ 8387 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8388 XML_NSMAP_FOREACH(nsMap, mi) { 8389 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8390 (mi->shadowDepth == -1) && 8391 ((ns->prefix == mi->newNs->prefix) || 8392 xmlStrEqual(ns->prefix, mi->newNs->prefix))) { 8393 8394 mi->shadowDepth = depth; 8395 } 8396 } 8397 } 8398 /* 8399 * Push mapping. 8400 */ 8401 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, 8402 depth) == NULL) 8403 goto internal_error; 8404 8405 prevns = ns; 8406next_ns_decl: 8407 ns = ns->next; 8408 } 8409 } 8410 if (! adoptns) 8411 goto ns_end; 8412 /* No break on purpose. */ 8413 case XML_ATTRIBUTE_NODE: 8414 /* No ns, no fun. */ 8415 if (cur->ns == NULL) 8416 goto ns_end; 8417 8418 if (! parnsdone) { 8419 if ((elem->parent) && 8420 ((xmlNodePtr) elem->parent->doc != elem->parent)) { 8421 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8422 elem->parent) == -1) 8423 goto internal_error; 8424 } 8425 parnsdone = 1; 8426 } 8427 /* 8428 * Adjust the reference if this was a redundant ns-decl. 8429 */ 8430 if (listRedund) { 8431 for (i = 0, j = 0; i < nbRedund; i++, j += 2) { 8432 if (cur->ns == listRedund[j]) { 8433 cur->ns = listRedund[++j]; 8434 break; 8435 } 8436 } 8437 } 8438 /* 8439 * Adopt ns-references. 8440 */ 8441 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8442 /* 8443 * Search for a mapping. 8444 */ 8445 XML_NSMAP_FOREACH(nsMap, mi) { 8446 if ((mi->shadowDepth == -1) && 8447 (cur->ns == mi->oldNs)) { 8448 8449 cur->ns = mi->newNs; 8450 goto ns_end; 8451 } 8452 } 8453 } 8454 /* 8455 * Aquire a normalized ns-decl and add it to the map. 8456 */ 8457 if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem, 8458 cur->ns, &ns, 8459 &nsMap, depth, 8460 ancestorsOnly, 8461 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 8462 goto internal_error; 8463 cur->ns = ns; 8464 8465ns_end: 8466 if ((cur->type == XML_ELEMENT_NODE) && 8467 (cur->properties != NULL)) { 8468 /* 8469 * Process attributes. 8470 */ 8471 cur = (xmlNodePtr) cur->properties; 8472 continue; 8473 } 8474 break; 8475 default: 8476 goto next_sibling; 8477 } 8478into_content: 8479 if ((cur->type == XML_ELEMENT_NODE) && 8480 (cur->children != NULL)) { 8481 /* 8482 * Process content of element-nodes only. 8483 */ 8484 cur = cur->children; 8485 continue; 8486 } 8487next_sibling: 8488 if (cur == elem) 8489 break; 8490 if (cur->type == XML_ELEMENT_NODE) { 8491 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8492 /* 8493 * Pop mappings. 8494 */ 8495 while ((nsMap->last != NULL) && 8496 (nsMap->last->depth >= depth)) 8497 { 8498 XML_NSMAP_POP(nsMap, mi) 8499 } 8500 /* 8501 * Unshadow. 8502 */ 8503 XML_NSMAP_FOREACH(nsMap, mi) { 8504 if (mi->shadowDepth >= depth) 8505 mi->shadowDepth = -1; 8506 } 8507 } 8508 depth--; 8509 } 8510 if (cur->next != NULL) 8511 cur = cur->next; 8512 else { 8513 if (cur->type == XML_ATTRIBUTE_NODE) { 8514 cur = cur->parent; 8515 goto into_content; 8516 } 8517 cur = cur->parent; 8518 goto next_sibling; 8519 } 8520 } while (cur != NULL); 8521 8522 ret = 0; 8523 goto exit; 8524internal_error: 8525 ret = -1; 8526exit: 8527 if (listRedund) { 8528 for (i = 0, j = 0; i < nbRedund; i++, j += 2) { 8529 xmlFreeNs(listRedund[j]); 8530 } 8531 xmlFree(listRedund); 8532 } 8533 if (nsMap != NULL) 8534 xmlDOMWrapNsMapFree(nsMap); 8535 return (ret); 8536} 8537 8538/* 8539* xmlDOMWrapAdoptBranch: 8540* @ctxt: the optional context for custom processing 8541* @sourceDoc: the optional sourceDoc 8542* @node: the element-node to start with 8543* @destDoc: the destination doc for adoption 8544* @destParent: the optional new parent of @node in @destDoc 8545* @options: option flags 8546* 8547* Ensures that ns-references point to @destDoc: either to 8548* elements->nsDef entries if @destParent is given, or to 8549* @destDoc->oldNs otherwise. 8550* If @destParent is given, it ensures that the tree is namespace 8551* wellformed by creating additional ns-decls where needed. 8552* Note that, since prefixes of already existent ns-decls can be 8553* shadowed by this process, it could break QNames in attribute 8554* values or element content. 8555* 8556* NOTE: This function was not intensively tested. 8557* 8558* Returns 0 if succeeded, -1 otherwise and on API/internal errors. 8559*/ 8560static int 8561xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, 8562 xmlDocPtr sourceDoc, 8563 xmlNodePtr node, 8564 xmlDocPtr destDoc, 8565 xmlNodePtr destParent, 8566 int options ATTRIBUTE_UNUSED) 8567{ 8568 int ret = 0; 8569 xmlNodePtr cur, curElem = NULL; 8570 xmlNsMapPtr nsMap = NULL; 8571 xmlNsMapItemPtr mi; 8572 xmlNsPtr ns = NULL; 8573 int depth = -1, adoptStr = 1; 8574 /* gather @parent's ns-decls. */ 8575 int parnsdone; 8576 /* @ancestorsOnly should be set per option. */ 8577 int ancestorsOnly = 0; 8578 8579 /* 8580 * Optimize string adoption for equal or none dicts. 8581 */ 8582 if ((sourceDoc != NULL) && 8583 (sourceDoc->dict == destDoc->dict)) 8584 adoptStr = 0; 8585 else 8586 adoptStr = 1; 8587 8588 /* 8589 * Get the ns-map from the context if available. 8590 */ 8591 if (ctxt) 8592 nsMap = (xmlNsMapPtr) ctxt->namespaceMap; 8593 /* 8594 * Disable search for ns-decls in the parent-axis of the 8595 * desination element, if: 8596 * 1) there's no destination parent 8597 * 2) custom ns-reference handling is used 8598 */ 8599 if ((destParent == NULL) || 8600 (ctxt && ctxt->getNsForNodeFunc)) 8601 { 8602 parnsdone = 1; 8603 } else 8604 parnsdone = 0; 8605 8606 cur = node; 8607 while (cur != NULL) { 8608 /* 8609 * Paranoid source-doc sanity check. 8610 */ 8611 if (cur->doc != sourceDoc) { 8612 /* 8613 * We'll assume XIncluded nodes if the doc differs. 8614 * TODO: Do we need to reconciliate XIncluded nodes? 8615 * This here skips XIncluded nodes and tries to handle 8616 * broken sequences. 8617 */ 8618 if (cur->next == NULL) 8619 goto leave_node; 8620 do { 8621 cur = cur->next; 8622 if ((cur->type == XML_XINCLUDE_END) || 8623 (cur->doc == node->doc)) 8624 break; 8625 } while (cur->next != NULL); 8626 8627 if (cur->doc != node->doc) 8628 goto leave_node; 8629 } 8630 cur->doc = destDoc; 8631 switch (cur->type) { 8632 case XML_XINCLUDE_START: 8633 case XML_XINCLUDE_END: 8634 /* 8635 * TODO 8636 */ 8637 return (-1); 8638 case XML_ELEMENT_NODE: 8639 curElem = cur; 8640 depth++; 8641 /* 8642 * Namespace declarations. 8643 * - ns->href and ns->prefix are never in the dict, so 8644 * we need not move the values over to the destination dict. 8645 * - Note that for custom handling of ns-references, 8646 * the ns-decls need not be stored in the ns-map, 8647 * since they won't be referenced by node->ns. 8648 */ 8649 if ((cur->nsDef) && 8650 ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL))) 8651 { 8652 if (! parnsdone) { 8653 /* 8654 * Gather @parent's in-scope ns-decls. 8655 */ 8656 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8657 destParent) == -1) 8658 goto internal_error; 8659 parnsdone = 1; 8660 } 8661 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 8662 /* 8663 * NOTE: ns->prefix and ns->href are never in the dict. 8664 * XML_TREE_ADOPT_STR(ns->prefix) 8665 * XML_TREE_ADOPT_STR(ns->href) 8666 */ 8667 /* 8668 * Does it shadow any ns-decl? 8669 */ 8670 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8671 XML_NSMAP_FOREACH(nsMap, mi) { 8672 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 8673 (mi->shadowDepth == -1) && 8674 ((ns->prefix == mi->newNs->prefix) || 8675 xmlStrEqual(ns->prefix, 8676 mi->newNs->prefix))) { 8677 8678 mi->shadowDepth = depth; 8679 } 8680 } 8681 } 8682 /* 8683 * Push mapping. 8684 */ 8685 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 8686 ns, ns, depth) == NULL) 8687 goto internal_error; 8688 } 8689 } 8690 /* No break on purpose. */ 8691 case XML_ATTRIBUTE_NODE: 8692 /* No namespace, no fun. */ 8693 if (cur->ns == NULL) 8694 goto ns_end; 8695 8696 if (! parnsdone) { 8697 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 8698 destParent) == -1) 8699 goto internal_error; 8700 parnsdone = 1; 8701 } 8702 /* 8703 * Adopt ns-references. 8704 */ 8705 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8706 /* 8707 * Search for a mapping. 8708 */ 8709 XML_NSMAP_FOREACH(nsMap, mi) { 8710 if ((mi->shadowDepth == -1) && 8711 (cur->ns == mi->oldNs)) { 8712 8713 cur->ns = mi->newNs; 8714 goto ns_end; 8715 } 8716 } 8717 } 8718 /* 8719 * No matching namespace in scope. We need a new one. 8720 */ 8721 if ((ctxt) && (ctxt->getNsForNodeFunc)) { 8722 /* 8723 * User-defined behaviour. 8724 */ 8725 ns = ctxt->getNsForNodeFunc(ctxt, cur, 8726 cur->ns->href, cur->ns->prefix); 8727 /* 8728 * Insert mapping if ns is available; it's the users fault 8729 * if not. 8730 */ 8731 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 8732 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) 8733 goto internal_error; 8734 cur->ns = ns; 8735 } else { 8736 /* 8737 * Aquire a normalized ns-decl and add it to the map. 8738 */ 8739 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, 8740 /* ns-decls on curElem or on destDoc->oldNs */ 8741 destParent ? curElem : NULL, 8742 cur->ns, &ns, 8743 &nsMap, depth, 8744 ancestorsOnly, 8745 /* ns-decls must be prefixed for attributes. */ 8746 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 8747 goto internal_error; 8748 cur->ns = ns; 8749 } 8750ns_end: 8751 /* 8752 * Further node properties. 8753 * TODO: Is this all? 8754 */ 8755 XML_TREE_ADOPT_STR(cur->name) 8756 if (cur->type == XML_ELEMENT_NODE) { 8757 cur->psvi = NULL; 8758 cur->line = 0; 8759 cur->extra = 0; 8760 /* 8761 * Walk attributes. 8762 */ 8763 if (cur->properties != NULL) { 8764 /* 8765 * Process first attribute node. 8766 */ 8767 cur = (xmlNodePtr) cur->properties; 8768 continue; 8769 } 8770 } else { 8771 /* 8772 * Attributes. 8773 */ 8774 if ((sourceDoc != NULL) && 8775 (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) 8776 { 8777 xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); 8778 } 8779 ((xmlAttrPtr) cur)->atype = 0; 8780 ((xmlAttrPtr) cur)->psvi = NULL; 8781 } 8782 break; 8783 case XML_TEXT_NODE: 8784 case XML_CDATA_SECTION_NODE: 8785 /* 8786 * This puts the content in the dest dict, only if 8787 * it was previously in the source dict. 8788 */ 8789 XML_TREE_ADOPT_STR_2(cur->content) 8790 goto leave_node; 8791 case XML_ENTITY_REF_NODE: 8792 /* 8793 * Remove reference to the entitity-node. 8794 */ 8795 cur->content = NULL; 8796 cur->children = NULL; 8797 cur->last = NULL; 8798 if ((destDoc->intSubset) || (destDoc->extSubset)) { 8799 xmlEntityPtr ent; 8800 /* 8801 * Assign new entity-node if available. 8802 */ 8803 ent = xmlGetDocEntity(destDoc, cur->name); 8804 if (ent != NULL) { 8805 cur->content = ent->content; 8806 cur->children = (xmlNodePtr) ent; 8807 cur->last = (xmlNodePtr) ent; 8808 } 8809 } 8810 goto leave_node; 8811 case XML_PI_NODE: 8812 XML_TREE_ADOPT_STR(cur->name) 8813 XML_TREE_ADOPT_STR_2(cur->content) 8814 break; 8815 case XML_COMMENT_NODE: 8816 break; 8817 default: 8818 goto internal_error; 8819 } 8820 /* 8821 * Walk the tree. 8822 */ 8823 if (cur->children != NULL) { 8824 cur = cur->children; 8825 continue; 8826 } 8827 8828leave_node: 8829 if (cur == node) 8830 break; 8831 if ((cur->type == XML_ELEMENT_NODE) || 8832 (cur->type == XML_XINCLUDE_START) || 8833 (cur->type == XML_XINCLUDE_END)) 8834 { 8835 /* 8836 * TODO: Do we expect nsDefs on XML_XINCLUDE_START? 8837 */ 8838 if (XML_NSMAP_NOTEMPTY(nsMap)) { 8839 /* 8840 * Pop mappings. 8841 */ 8842 while ((nsMap->last != NULL) && 8843 (nsMap->last->depth >= depth)) 8844 { 8845 XML_NSMAP_POP(nsMap, mi) 8846 } 8847 /* 8848 * Unshadow. 8849 */ 8850 XML_NSMAP_FOREACH(nsMap, mi) { 8851 if (mi->shadowDepth >= depth) 8852 mi->shadowDepth = -1; 8853 } 8854 } 8855 depth--; 8856 } 8857 if (cur->next != NULL) 8858 cur = cur->next; 8859 else if ((cur->type == XML_ATTRIBUTE_NODE) && 8860 (cur->parent->children != NULL)) 8861 { 8862 cur = cur->parent->children; 8863 } else { 8864 cur = cur->parent; 8865 goto leave_node; 8866 } 8867 } 8868 8869 goto exit; 8870 8871internal_error: 8872 ret = -1; 8873 8874exit: 8875 /* 8876 * Cleanup. 8877 */ 8878 if (nsMap != NULL) { 8879 if ((ctxt) && (ctxt->namespaceMap == nsMap)) { 8880 /* 8881 * Just cleanup the map but don't free. 8882 */ 8883 if (nsMap->first) { 8884 if (nsMap->pool) 8885 nsMap->last->next = nsMap->pool; 8886 nsMap->pool = nsMap->first; 8887 nsMap->first = NULL; 8888 } 8889 } else 8890 xmlDOMWrapNsMapFree(nsMap); 8891 } 8892 return(ret); 8893} 8894 8895/* 8896* xmlDOMWrapCloneNode: 8897* @ctxt: the optional context for custom processing 8898* @sourceDoc: the optional sourceDoc 8899* @node: the node to start with 8900* @resNode: the clone of the given @node 8901* @destDoc: the destination doc 8902* @destParent: the optional new parent of @node in @destDoc 8903* @deep: descend into child if set 8904* @options: option flags 8905* 8906* References of out-of scope ns-decls are remapped to point to @destDoc: 8907* 1) If @destParent is given, then nsDef entries on element-nodes are used 8908* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used. 8909* This is the case when you don't know already where the cloned branch 8910* will be added to. 8911* 8912* If @destParent is given, it ensures that the tree is namespace 8913* wellformed by creating additional ns-decls where needed. 8914* Note that, since prefixes of already existent ns-decls can be 8915* shadowed by this process, it could break QNames in attribute 8916* values or element content. 8917* TODO: 8918* 1) What to do with XInclude? Currently this returns an error for XInclude. 8919* 8920* Returns 0 if the operation succeeded, 8921* 1 if a node of unsupported (or not yet supported) type was given, 8922* -1 on API/internal errors. 8923*/ 8924 8925int 8926xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, 8927 xmlDocPtr sourceDoc, 8928 xmlNodePtr node, 8929 xmlNodePtr *resNode, 8930 xmlDocPtr destDoc, 8931 xmlNodePtr destParent, 8932 int deep, 8933 int options ATTRIBUTE_UNUSED) 8934{ 8935 int ret = 0; 8936 xmlNodePtr cur, curElem = NULL; 8937 xmlNsMapPtr nsMap = NULL; 8938 xmlNsMapItemPtr mi; 8939 xmlNsPtr ns; 8940 int depth = -1; 8941 /* int adoptStr = 1; */ 8942 /* gather @parent's ns-decls. */ 8943 int parnsdone = 0; 8944 /* 8945 * @ancestorsOnly: 8946 * TODO: @ancestorsOnly should be set per option. 8947 * 8948 */ 8949 int ancestorsOnly = 0; 8950 xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL; 8951 xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; 8952 xmlDictPtr dict; /* The destination dict */ 8953 8954 if ((node == NULL) || (resNode == NULL) || (destDoc == NULL)) 8955 return(-1); 8956 /* 8957 * TODO: Initially we support only element-nodes. 8958 */ 8959 if (node->type != XML_ELEMENT_NODE) 8960 return(1); 8961 /* 8962 * Check node->doc sanity. 8963 */ 8964 if ((node->doc != NULL) && (sourceDoc != NULL) && 8965 (node->doc != sourceDoc)) { 8966 /* 8967 * Might be an XIncluded node. 8968 */ 8969 return (-1); 8970 } 8971 if (sourceDoc == NULL) 8972 sourceDoc = node->doc; 8973 if (sourceDoc == NULL) 8974 return (-1); 8975 8976 dict = destDoc->dict; 8977 /* 8978 * Reuse the namespace map of the context. 8979 */ 8980 if (ctxt) 8981 nsMap = (xmlNsMapPtr) ctxt->namespaceMap; 8982 8983 *resNode = NULL; 8984 8985 cur = node; 8986 while (cur != NULL) { 8987 if (cur->doc != sourceDoc) { 8988 /* 8989 * We'll assume XIncluded nodes if the doc differs. 8990 * TODO: Do we need to reconciliate XIncluded nodes? 8991 * TODO: This here returns -1 in this case. 8992 */ 8993 goto internal_error; 8994 } 8995 /* 8996 * Create a new node. 8997 */ 8998 switch (cur->type) { 8999 case XML_XINCLUDE_START: 9000 case XML_XINCLUDE_END: 9001 /* 9002 * TODO: What to do with XInclude? 9003 */ 9004 goto internal_error; 9005 break; 9006 case XML_ELEMENT_NODE: 9007 case XML_TEXT_NODE: 9008 case XML_CDATA_SECTION_NODE: 9009 case XML_COMMENT_NODE: 9010 case XML_PI_NODE: 9011 case XML_DOCUMENT_FRAG_NODE: 9012 case XML_ENTITY_REF_NODE: 9013 case XML_ENTITY_NODE: 9014 /* 9015 * Nodes of xmlNode structure. 9016 */ 9017 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); 9018 if (clone == NULL) { 9019 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node"); 9020 goto internal_error; 9021 } 9022 memset(clone, 0, sizeof(xmlNode)); 9023 /* 9024 * Set hierachical links. 9025 */ 9026 if (resultClone != NULL) { 9027 clone->parent = parentClone; 9028 if (prevClone) { 9029 prevClone->next = clone; 9030 clone->prev = prevClone; 9031 } else 9032 parentClone->children = clone; 9033 } else 9034 resultClone = clone; 9035 9036 break; 9037 case XML_ATTRIBUTE_NODE: 9038 /* 9039 * Attributes (xmlAttr). 9040 */ 9041 clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr)); 9042 if (clone == NULL) { 9043 xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node"); 9044 goto internal_error; 9045 } 9046 memset(clone, 0, sizeof(xmlAttr)); 9047 /* 9048 * Set hierachical links. 9049 * TODO: Change this to add to the end of attributes. 9050 */ 9051 if (resultClone != NULL) { 9052 clone->parent = parentClone; 9053 if (prevClone) { 9054 prevClone->next = clone; 9055 clone->prev = prevClone; 9056 } else 9057 parentClone->properties = (xmlAttrPtr) clone; 9058 } else 9059 resultClone = clone; 9060 break; 9061 default: 9062 /* 9063 * TODO QUESTION: Any other nodes expected? 9064 */ 9065 goto internal_error; 9066 } 9067 9068 clone->type = cur->type; 9069 clone->doc = destDoc; 9070 9071 /* 9072 * Clone the name of the node if any. 9073 */ 9074 if (cur->name == xmlStringText) 9075 clone->name = xmlStringText; 9076 else if (cur->name == xmlStringTextNoenc) 9077 /* 9078 * NOTE: Although xmlStringTextNoenc is never assigned to a node 9079 * in tree.c, it might be set in Libxslt via 9080 * "xsl:disable-output-escaping". 9081 */ 9082 clone->name = xmlStringTextNoenc; 9083 else if (cur->name == xmlStringComment) 9084 clone->name = xmlStringComment; 9085 else if (cur->name != NULL) { 9086 DICT_CONST_COPY(cur->name, clone->name); 9087 } 9088 9089 switch (cur->type) { 9090 case XML_XINCLUDE_START: 9091 case XML_XINCLUDE_END: 9092 /* 9093 * TODO 9094 */ 9095 return (-1); 9096 case XML_ELEMENT_NODE: 9097 curElem = cur; 9098 depth++; 9099 /* 9100 * Namespace declarations. 9101 */ 9102 if (cur->nsDef != NULL) { 9103 if (! parnsdone) { 9104 if (destParent && (ctxt == NULL)) { 9105 /* 9106 * Gather @parent's in-scope ns-decls. 9107 */ 9108 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, 9109 destParent) == -1) 9110 goto internal_error; 9111 } 9112 parnsdone = 1; 9113 } 9114 /* 9115 * Clone namespace declarations. 9116 */ 9117 cloneNsDefSlot = &(clone->nsDef); 9118 for (ns = cur->nsDef; ns != NULL; ns = ns->next) { 9119 /* 9120 * Create a new xmlNs. 9121 */ 9122 cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 9123 if (cloneNs == NULL) { 9124 xmlTreeErrMemory("xmlDOMWrapCloneNode(): " 9125 "allocating namespace"); 9126 return(-1); 9127 } 9128 memset(cloneNs, 0, sizeof(xmlNs)); 9129 cloneNs->type = XML_LOCAL_NAMESPACE; 9130 9131 if (ns->href != NULL) 9132 cloneNs->href = xmlStrdup(ns->href); 9133 if (ns->prefix != NULL) 9134 cloneNs->prefix = xmlStrdup(ns->prefix); 9135 9136 *cloneNsDefSlot = cloneNs; 9137 cloneNsDefSlot = &(cloneNs->next); 9138 9139 /* 9140 * Note that for custom handling of ns-references, 9141 * the ns-decls need not be stored in the ns-map, 9142 * since they won't be referenced by node->ns. 9143 */ 9144 if ((ctxt == NULL) || 9145 (ctxt->getNsForNodeFunc == NULL)) 9146 { 9147 /* 9148 * Does it shadow any ns-decl? 9149 */ 9150 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9151 XML_NSMAP_FOREACH(nsMap, mi) { 9152 if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 9153 (mi->shadowDepth == -1) && 9154 ((ns->prefix == mi->newNs->prefix) || 9155 xmlStrEqual(ns->prefix, 9156 mi->newNs->prefix))) { 9157 /* 9158 * Mark as shadowed at the current 9159 * depth. 9160 */ 9161 mi->shadowDepth = depth; 9162 } 9163 } 9164 } 9165 /* 9166 * Push mapping. 9167 */ 9168 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 9169 ns, cloneNs, depth) == NULL) 9170 goto internal_error; 9171 } 9172 } 9173 } 9174 /* cur->ns will be processed further down. */ 9175 break; 9176 case XML_ATTRIBUTE_NODE: 9177 /* IDs will be processed further down. */ 9178 /* cur->ns will be processed further down. */ 9179 break; 9180 case XML_TEXT_NODE: 9181 case XML_CDATA_SECTION_NODE: 9182 /* 9183 * Note that this will also cover the values of attributes. 9184 */ 9185 DICT_COPY(cur->content, clone->content); 9186 goto leave_node; 9187 case XML_ENTITY_NODE: 9188 /* TODO: What to do here? */ 9189 goto leave_node; 9190 case XML_ENTITY_REF_NODE: 9191 if (sourceDoc != destDoc) { 9192 if ((destDoc->intSubset) || (destDoc->extSubset)) { 9193 xmlEntityPtr ent; 9194 /* 9195 * Different doc: Assign new entity-node if available. 9196 */ 9197 ent = xmlGetDocEntity(destDoc, cur->name); 9198 if (ent != NULL) { 9199 clone->content = ent->content; 9200 clone->children = (xmlNodePtr) ent; 9201 clone->last = (xmlNodePtr) ent; 9202 } 9203 } 9204 } else { 9205 /* 9206 * Same doc: Use the current node's entity declaration 9207 * and value. 9208 */ 9209 clone->content = cur->content; 9210 clone->children = cur->children; 9211 clone->last = cur->last; 9212 } 9213 goto leave_node; 9214 case XML_PI_NODE: 9215 DICT_COPY(cur->content, clone->content); 9216 goto leave_node; 9217 case XML_COMMENT_NODE: 9218 DICT_COPY(cur->content, clone->content); 9219 goto leave_node; 9220 default: 9221 goto internal_error; 9222 } 9223 9224 if (cur->ns == NULL) 9225 goto end_ns_reference; 9226 9227/* handle_ns_reference: */ 9228 /* 9229 ** The following will take care of references to ns-decls ******** 9230 ** and is intended only for element- and attribute-nodes. 9231 ** 9232 */ 9233 if (! parnsdone) { 9234 if (destParent && (ctxt == NULL)) { 9235 if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) 9236 goto internal_error; 9237 } 9238 parnsdone = 1; 9239 } 9240 /* 9241 * Adopt ns-references. 9242 */ 9243 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9244 /* 9245 * Search for a mapping. 9246 */ 9247 XML_NSMAP_FOREACH(nsMap, mi) { 9248 if ((mi->shadowDepth == -1) && 9249 (cur->ns == mi->oldNs)) { 9250 /* 9251 * This is the nice case: a mapping was found. 9252 */ 9253 clone->ns = mi->newNs; 9254 goto end_ns_reference; 9255 } 9256 } 9257 } 9258 /* 9259 * No matching namespace in scope. We need a new one. 9260 */ 9261 if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) { 9262 /* 9263 * User-defined behaviour. 9264 */ 9265 ns = ctxt->getNsForNodeFunc(ctxt, cur, 9266 cur->ns->href, cur->ns->prefix); 9267 /* 9268 * Add user's mapping. 9269 */ 9270 if (xmlDOMWrapNsMapAddItem(&nsMap, -1, 9271 cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) 9272 goto internal_error; 9273 clone->ns = ns; 9274 } else { 9275 /* 9276 * Aquire a normalized ns-decl and add it to the map. 9277 */ 9278 if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, 9279 /* ns-decls on curElem or on destDoc->oldNs */ 9280 destParent ? curElem : NULL, 9281 cur->ns, &ns, 9282 &nsMap, depth, 9283 /* if we need to search only in the ancestor-axis */ 9284 ancestorsOnly, 9285 /* ns-decls must be prefixed for attributes. */ 9286 (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) 9287 goto internal_error; 9288 clone->ns = ns; 9289 } 9290 9291end_ns_reference: 9292 9293 /* 9294 * Some post-processing. 9295 * 9296 * Handle ID attributes. 9297 */ 9298 if ((clone->type == XML_ATTRIBUTE_NODE) && 9299 (clone->parent != NULL)) 9300 { 9301 if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) { 9302 9303 xmlChar *idVal; 9304 9305 idVal = xmlNodeListGetString(cur->doc, cur->children, 1); 9306 if (idVal != NULL) { 9307 if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) { 9308 /* TODO: error message. */ 9309 xmlFree(idVal); 9310 goto internal_error; 9311 } 9312 xmlFree(idVal); 9313 } 9314 } 9315 } 9316 /* 9317 ** 9318 ** The following will traverse the tree ************************** 9319 ** 9320 * 9321 * Walk the element's attributes before descending into child-nodes. 9322 */ 9323 if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) { 9324 prevClone = NULL; 9325 parentClone = clone; 9326 cur = (xmlNodePtr) cur->properties; 9327 continue; 9328 } 9329into_content: 9330 /* 9331 * Descend into child-nodes. 9332 */ 9333 if (cur->children != NULL) { 9334 if (deep || (cur->type == XML_ATTRIBUTE_NODE)) { 9335 prevClone = NULL; 9336 parentClone = clone; 9337 cur = cur->children; 9338 continue; 9339 } 9340 } 9341 9342leave_node: 9343 /* 9344 * At this point we are done with the node, its content 9345 * and an element-nodes's attribute-nodes. 9346 */ 9347 if (cur == node) 9348 break; 9349 if ((cur->type == XML_ELEMENT_NODE) || 9350 (cur->type == XML_XINCLUDE_START) || 9351 (cur->type == XML_XINCLUDE_END)) { 9352 /* 9353 * TODO: Do we expect nsDefs on XML_XINCLUDE_START? 9354 */ 9355 if (XML_NSMAP_NOTEMPTY(nsMap)) { 9356 /* 9357 * Pop mappings. 9358 */ 9359 while ((nsMap->last != NULL) && 9360 (nsMap->last->depth >= depth)) 9361 { 9362 XML_NSMAP_POP(nsMap, mi) 9363 } 9364 /* 9365 * Unshadow. 9366 */ 9367 XML_NSMAP_FOREACH(nsMap, mi) { 9368 if (mi->shadowDepth >= depth) 9369 mi->shadowDepth = -1; 9370 } 9371 } 9372 depth--; 9373 } 9374 if (cur->next != NULL) { 9375 prevClone = clone; 9376 cur = cur->next; 9377 } else if (cur->type != XML_ATTRIBUTE_NODE) { 9378 /* 9379 * Set clone->last. 9380 */ 9381 if (clone->parent != NULL) 9382 clone->parent->last = clone; 9383 clone = clone->parent; 9384 parentClone = clone->parent; 9385 /* 9386 * Process parent --> next; 9387 */ 9388 cur = cur->parent; 9389 goto leave_node; 9390 } else { 9391 /* This is for attributes only. */ 9392 clone = clone->parent; 9393 parentClone = clone->parent; 9394 /* 9395 * Process parent-element --> children. 9396 */ 9397 cur = cur->parent; 9398 goto into_content; 9399 } 9400 } 9401 goto exit; 9402 9403internal_error: 9404 ret = -1; 9405 9406exit: 9407 /* 9408 * Cleanup. 9409 */ 9410 if (nsMap != NULL) { 9411 if ((ctxt) && (ctxt->namespaceMap == nsMap)) { 9412 /* 9413 * Just cleanup the map but don't free. 9414 */ 9415 if (nsMap->first) { 9416 if (nsMap->pool) 9417 nsMap->last->next = nsMap->pool; 9418 nsMap->pool = nsMap->first; 9419 nsMap->first = NULL; 9420 } 9421 } else 9422 xmlDOMWrapNsMapFree(nsMap); 9423 } 9424 /* 9425 * TODO: Should we try a cleanup of the cloned node in case of a 9426 * fatal error? 9427 */ 9428 *resNode = resultClone; 9429 return (ret); 9430} 9431 9432/* 9433* xmlDOMWrapAdoptAttr: 9434* @ctxt: the optional context for custom processing 9435* @sourceDoc: the optional source document of attr 9436* @attr: the attribute-node to be adopted 9437* @destDoc: the destination doc for adoption 9438* @destParent: the optional new parent of @attr in @destDoc 9439* @options: option flags 9440* 9441* @attr is adopted by @destDoc. 9442* Ensures that ns-references point to @destDoc: either to 9443* elements->nsDef entries if @destParent is given, or to 9444* @destDoc->oldNs otherwise. 9445* 9446* Returns 0 if succeeded, -1 otherwise and on API/internal errors. 9447*/ 9448static int 9449xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, 9450 xmlDocPtr sourceDoc, 9451 xmlAttrPtr attr, 9452 xmlDocPtr destDoc, 9453 xmlNodePtr destParent, 9454 int options ATTRIBUTE_UNUSED) 9455{ 9456 xmlNodePtr cur; 9457 int adoptStr = 1; 9458 9459 if ((attr == NULL) || (destDoc == NULL)) 9460 return (-1); 9461 9462 attr->doc = destDoc; 9463 if (attr->ns != NULL) { 9464 xmlNsPtr ns = NULL; 9465 9466 if (ctxt != NULL) { 9467 /* TODO: User defined. */ 9468 } 9469 /* XML Namespace. */ 9470 if (IS_STR_XML(attr->ns->prefix)) { 9471 ns = xmlTreeEnsureXMLDecl(destDoc); 9472 } else if (destParent == NULL) { 9473 /* 9474 * Store in @destDoc->oldNs. 9475 */ 9476 ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix); 9477 } else { 9478 /* 9479 * Declare on @destParent. 9480 */ 9481 if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href, 9482 &ns, 1) == -1) 9483 goto internal_error; 9484 if (ns == NULL) { 9485 ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent, 9486 attr->ns->href, attr->ns->prefix, 1); 9487 } 9488 } 9489 if (ns == NULL) 9490 goto internal_error; 9491 attr->ns = ns; 9492 } 9493 9494 XML_TREE_ADOPT_STR(attr->name); 9495 attr->atype = 0; 9496 attr->psvi = NULL; 9497 /* 9498 * Walk content. 9499 */ 9500 if (attr->children == NULL) 9501 return (0); 9502 cur = attr->children; 9503 while (cur != NULL) { 9504 cur->doc = destDoc; 9505 switch (cur->type) { 9506 case XML_TEXT_NODE: 9507 case XML_CDATA_SECTION_NODE: 9508 XML_TREE_ADOPT_STR_2(cur->content) 9509 break; 9510 case XML_ENTITY_REF_NODE: 9511 /* 9512 * Remove reference to the entitity-node. 9513 */ 9514 cur->content = NULL; 9515 cur->children = NULL; 9516 cur->last = NULL; 9517 if ((destDoc->intSubset) || (destDoc->extSubset)) { 9518 xmlEntityPtr ent; 9519 /* 9520 * Assign new entity-node if available. 9521 */ 9522 ent = xmlGetDocEntity(destDoc, cur->name); 9523 if (ent != NULL) { 9524 cur->content = ent->content; 9525 cur->children = (xmlNodePtr) ent; 9526 cur->last = (xmlNodePtr) ent; 9527 } 9528 } 9529 break; 9530 default: 9531 break; 9532 } 9533 if (cur->children != NULL) { 9534 cur = cur->children; 9535 continue; 9536 } 9537next_sibling: 9538 if (cur == (xmlNodePtr) attr) 9539 break; 9540 if (cur->next != NULL) 9541 cur = cur->next; 9542 else { 9543 cur = cur->parent; 9544 goto next_sibling; 9545 } 9546 } 9547 return (0); 9548internal_error: 9549 return (-1); 9550} 9551 9552/* 9553* xmlDOMWrapAdoptNode: 9554* @ctxt: the optional context for custom processing 9555* @sourceDoc: the optional sourceDoc 9556* @node: the node to start with 9557* @destDoc: the destination doc 9558* @destParent: the optional new parent of @node in @destDoc 9559* @options: option flags 9560* 9561* References of out-of scope ns-decls are remapped to point to @destDoc: 9562* 1) If @destParent is given, then nsDef entries on element-nodes are used 9563* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used 9564* This is the case when you have an unliked node and just want to move it 9565* to the context of 9566* 9567* If @destParent is given, it ensures that the tree is namespace 9568* wellformed by creating additional ns-decls where needed. 9569* Note that, since prefixes of already existent ns-decls can be 9570* shadowed by this process, it could break QNames in attribute 9571* values or element content. 9572* NOTE: This function was not intensively tested. 9573* 9574* Returns 0 if the operation succeeded, 9575* 1 if a node of unsupported type was given, 9576* 2 if a node of not yet supported type was given and 9577* -1 on API/internal errors. 9578*/ 9579int 9580xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, 9581 xmlDocPtr sourceDoc, 9582 xmlNodePtr node, 9583 xmlDocPtr destDoc, 9584 xmlNodePtr destParent, 9585 int options) 9586{ 9587 if ((node == NULL) || (destDoc == NULL) || 9588 ((destParent != NULL) && (destParent->doc != destDoc))) 9589 return(-1); 9590 /* 9591 * Check node->doc sanity. 9592 */ 9593 if ((node->doc != NULL) && (sourceDoc != NULL) && 9594 (node->doc != sourceDoc)) { 9595 /* 9596 * Might be an XIncluded node. 9597 */ 9598 return (-1); 9599 } 9600 if (sourceDoc == NULL) 9601 sourceDoc = node->doc; 9602 if (sourceDoc == destDoc) 9603 return (-1); 9604 switch (node->type) { 9605 case XML_ELEMENT_NODE: 9606 case XML_ATTRIBUTE_NODE: 9607 case XML_TEXT_NODE: 9608 case XML_CDATA_SECTION_NODE: 9609 case XML_ENTITY_REF_NODE: 9610 case XML_PI_NODE: 9611 case XML_COMMENT_NODE: 9612 break; 9613 case XML_DOCUMENT_FRAG_NODE: 9614 /* TODO: Support document-fragment-nodes. */ 9615 return (2); 9616 default: 9617 return (1); 9618 } 9619 /* 9620 * Unlink only if @node was not already added to @destParent. 9621 */ 9622 if ((node->parent != NULL) && (destParent != node->parent)) 9623 xmlUnlinkNode(node); 9624 9625 if (node->type == XML_ELEMENT_NODE) { 9626 return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node, 9627 destDoc, destParent, options)); 9628 } else if (node->type == XML_ATTRIBUTE_NODE) { 9629 return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc, 9630 (xmlAttrPtr) node, destDoc, destParent, options)); 9631 } else { 9632 xmlNodePtr cur = node; 9633 int adoptStr = 1; 9634 9635 cur->doc = destDoc; 9636 /* 9637 * Optimize string adoption. 9638 */ 9639 if ((sourceDoc != NULL) && 9640 (sourceDoc->dict == destDoc->dict)) 9641 adoptStr = 0; 9642 switch (node->type) { 9643 case XML_TEXT_NODE: 9644 case XML_CDATA_SECTION_NODE: 9645 XML_TREE_ADOPT_STR_2(node->content) 9646 break; 9647 case XML_ENTITY_REF_NODE: 9648 /* 9649 * Remove reference to the entitity-node. 9650 */ 9651 node->content = NULL; 9652 node->children = NULL; 9653 node->last = NULL; 9654 if ((destDoc->intSubset) || (destDoc->extSubset)) { 9655 xmlEntityPtr ent; 9656 /* 9657 * Assign new entity-node if available. 9658 */ 9659 ent = xmlGetDocEntity(destDoc, node->name); 9660 if (ent != NULL) { 9661 node->content = ent->content; 9662 node->children = (xmlNodePtr) ent; 9663 node->last = (xmlNodePtr) ent; 9664 } 9665 } 9666 XML_TREE_ADOPT_STR(node->name) 9667 break; 9668 case XML_PI_NODE: { 9669 XML_TREE_ADOPT_STR(node->name) 9670 XML_TREE_ADOPT_STR_2(node->content) 9671 break; 9672 } 9673 default: 9674 break; 9675 } 9676 } 9677 return (0); 9678} 9679 9680#define bottom_tree 9681#include "elfgcchack.h" 9682