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