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