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