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