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