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