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