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