ReactOS 0.4.15-dev-8614-gbc76250
tree.c
Go to the documentation of this file.
1/*
2 * tree.c : implementation of access function for an XML tree.
3 *
4 * References:
5 * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 *
11 */
12
13/* To avoid EBCDIC trouble when parsing on zOS */
14#if defined(__MVS__)
15#pragma convert("ISO8859-1")
16#endif
17
18#define IN_LIBXML
19#include "libxml.h"
20
21#include <string.h> /* for memset() only ! */
22#include <stddef.h>
23#include <limits.h>
24#include <ctype.h>
25#include <stdlib.h>
26
27#ifdef LIBXML_ZLIB_ENABLED
28#include <zlib.h>
29#endif
30
31#include <libxml/xmlmemory.h>
32#include <libxml/tree.h>
33#include <libxml/parser.h>
34#include <libxml/uri.h>
35#include <libxml/entities.h>
36#include <libxml/valid.h>
37#include <libxml/xmlerror.h>
39#include <libxml/globals.h>
40#ifdef LIBXML_HTML_ENABLED
41#include <libxml/HTMLtree.h>
42#endif
43#ifdef LIBXML_DEBUG_ENABLED
44#include <libxml/debugXML.h>
45#endif
46
47#include "buf.h"
48#include "save.h"
49
51
52/************************************************************************
53 * *
54 * Forward declarations *
55 * *
56 ************************************************************************/
57
58static xmlNsPtr
60
62
63/************************************************************************
64 * *
65 * Tree memory error handler *
66 * *
67 ************************************************************************/
74static void
76{
77 __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
78}
79
87static void
88xmlTreeErr(int code, xmlNodePtr node, const char *extra)
89{
90 const char *msg = NULL;
91
92 switch(code) {
94 msg = "invalid hexadecimal character value\n";
95 break;
97 msg = "invalid decimal character value\n";
98 break;
100 msg = "unterminated entity reference %15s\n";
101 break;
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 */
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/* #define DEBUG_BUFFER */
144/* #define DEBUG_TREE */
145
146/************************************************************************
147 * *
148 * Functions to move to entities.c once the *
149 * API freeze is smoothen and they can be made public. *
150 * *
151 ************************************************************************/
152#include <libxml/hash.h>
153
154#ifdef LIBXML_TREE_ENABLED
165static xmlEntityPtr
166xmlGetEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
168
169 if((dtd != NULL) && (dtd->entities != NULL)) {
172 /* return(xmlGetEntityFromTable(table, name)); */
173 }
174 return(NULL);
175}
186static xmlEntityPtr
187xmlGetParameterEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
189
190 if ((dtd != NULL) && (dtd->pentities != NULL)) {
193 /* return(xmlGetEntityFromTable(table, name)); */
194 }
195 return(NULL);
196}
197#endif /* LIBXML_TREE_ENABLED */
198
199/************************************************************************
200 * *
201 * QName handling helper *
202 * *
203 ************************************************************************/
204
219xmlChar *
220xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
221 xmlChar *memory, int len) {
222 int lenn, lenp;
223 xmlChar *ret;
224
225 if (ncname == NULL) return(NULL);
226 if (prefix == NULL) return((xmlChar *) ncname);
227
228 lenn = strlen((char *) ncname);
229 lenp = strlen((char *) prefix);
230
231 if ((memory == NULL) || (len < lenn + lenp + 2)) {
232 ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
233 if (ret == NULL) {
234 xmlTreeErrMemory("building QName");
235 return(NULL);
236 }
237 } else {
238 ret = memory;
239 }
240 memcpy(&ret[0], prefix, lenp);
241 ret[lenp] = ':';
242 memcpy(&ret[lenp + 1], ncname, lenn);
243 ret[lenn + lenp + 1] = 0;
244 return(ret);
245}
246
264xmlChar *
265xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
266 int len = 0;
267 xmlChar *ret = NULL;
268
269 if (prefix == NULL) return(NULL);
270 *prefix = NULL;
271 if (name == NULL) return(NULL);
272
273#ifndef XML_XML_NAMESPACE
274 /* xml: prefix is not really a namespace */
275 if ((name[0] == 'x') && (name[1] == 'm') &&
276 (name[2] == 'l') && (name[3] == ':'))
277 return(NULL);
278#endif
279
280 /* nasty but valid */
281 if (name[0] == ':')
282 return(NULL);
283
284 /*
285 * we are not trying to validate but just to cut, and yes it will
286 * work even if this is as set of UTF-8 encoded chars
287 */
288 while ((name[len] != 0) && (name[len] != ':'))
289 len++;
290
291 if (name[len] == 0)
292 return(NULL);
293
294 *prefix = xmlStrndup(name, len);
295 if (*prefix == NULL) {
296 xmlTreeErrMemory("QName split");
297 return(NULL);
298 }
299 ret = xmlStrdup(&name[len + 1]);
300 if (ret == NULL) {
301 xmlTreeErrMemory("QName split");
302 if (*prefix != NULL) {
303 xmlFree(*prefix);
304 *prefix = NULL;
305 }
306 return(NULL);
307 }
308
309 return(ret);
310}
311
324const xmlChar *
325xmlSplitQName3(const xmlChar *name, int *len) {
326 int l = 0;
327
328 if (name == NULL) return(NULL);
329 if (len == NULL) return(NULL);
330
331 /* nasty but valid */
332 if (name[0] == ':')
333 return(NULL);
334
335 /*
336 * we are not trying to validate but just to cut, and yes it will
337 * work even if this is as set of UTF-8 encoded chars
338 */
339 while ((name[l] != 0) && (name[l] != ':'))
340 l++;
341
342 if (name[l] == 0)
343 return(NULL);
344
345 *len = l;
346
347 return(&name[l+1]);
348}
349
350/************************************************************************
351 * *
352 * Check Name, NCName and QName strings *
353 * *
354 ************************************************************************/
355
356#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
357
358#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
369int
370xmlValidateNCName(const xmlChar *value, int space) {
371 const xmlChar *cur = value;
372 int c,l;
373
374 if (value == NULL)
375 return(-1);
376
377 /*
378 * First quick algorithm for ASCII range
379 */
380 if (space)
381 while (IS_BLANK_CH(*cur)) cur++;
382 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
383 (*cur == '_'))
384 cur++;
385 else
386 goto try_complex;
387 while (((*cur >= 'a') && (*cur <= 'z')) ||
388 ((*cur >= 'A') && (*cur <= 'Z')) ||
389 ((*cur >= '0') && (*cur <= '9')) ||
390 (*cur == '_') || (*cur == '-') || (*cur == '.'))
391 cur++;
392 if (space)
393 while (IS_BLANK_CH(*cur)) cur++;
394 if (*cur == 0)
395 return(0);
396
397try_complex:
398 /*
399 * Second check for chars outside the ASCII range
400 */
401 cur = value;
402 c = CUR_SCHAR(cur, l);
403 if (space) {
404 while (IS_BLANK(c)) {
405 cur += l;
406 c = CUR_SCHAR(cur, l);
407 }
408 }
409 if ((!IS_LETTER(c)) && (c != '_'))
410 return(1);
411 cur += l;
412 c = CUR_SCHAR(cur, l);
413 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
414 (c == '-') || (c == '_') || IS_COMBINING(c) ||
415 IS_EXTENDER(c)) {
416 cur += l;
417 c = CUR_SCHAR(cur, l);
418 }
419 if (space) {
420 while (IS_BLANK(c)) {
421 cur += l;
422 c = CUR_SCHAR(cur, l);
423 }
424 }
425 if (c != 0)
426 return(1);
427
428 return(0);
429}
430#endif
431
432#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
443int
444xmlValidateQName(const xmlChar *value, int space) {
445 const xmlChar *cur = value;
446 int c,l;
447
448 if (value == NULL)
449 return(-1);
450 /*
451 * First quick algorithm for ASCII range
452 */
453 if (space)
454 while (IS_BLANK_CH(*cur)) cur++;
455 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
456 (*cur == '_'))
457 cur++;
458 else
459 goto try_complex;
460 while (((*cur >= 'a') && (*cur <= 'z')) ||
461 ((*cur >= 'A') && (*cur <= 'Z')) ||
462 ((*cur >= '0') && (*cur <= '9')) ||
463 (*cur == '_') || (*cur == '-') || (*cur == '.'))
464 cur++;
465 if (*cur == ':') {
466 cur++;
467 if (((*cur >= 'a') && (*cur <= 'z')) ||
468 ((*cur >= 'A') && (*cur <= 'Z')) ||
469 (*cur == '_'))
470 cur++;
471 else
472 goto try_complex;
473 while (((*cur >= 'a') && (*cur <= 'z')) ||
474 ((*cur >= 'A') && (*cur <= 'Z')) ||
475 ((*cur >= '0') && (*cur <= '9')) ||
476 (*cur == '_') || (*cur == '-') || (*cur == '.'))
477 cur++;
478 }
479 if (space)
480 while (IS_BLANK_CH(*cur)) cur++;
481 if (*cur == 0)
482 return(0);
483
484try_complex:
485 /*
486 * Second check for chars outside the ASCII range
487 */
488 cur = value;
489 c = CUR_SCHAR(cur, l);
490 if (space) {
491 while (IS_BLANK(c)) {
492 cur += l;
493 c = CUR_SCHAR(cur, l);
494 }
495 }
496 if ((!IS_LETTER(c)) && (c != '_'))
497 return(1);
498 cur += l;
499 c = CUR_SCHAR(cur, l);
500 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
501 (c == '-') || (c == '_') || IS_COMBINING(c) ||
502 IS_EXTENDER(c)) {
503 cur += l;
504 c = CUR_SCHAR(cur, l);
505 }
506 if (c == ':') {
507 cur += l;
508 c = CUR_SCHAR(cur, l);
509 if ((!IS_LETTER(c)) && (c != '_'))
510 return(1);
511 cur += l;
512 c = CUR_SCHAR(cur, l);
513 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
514 (c == '-') || (c == '_') || IS_COMBINING(c) ||
515 IS_EXTENDER(c)) {
516 cur += l;
517 c = CUR_SCHAR(cur, l);
518 }
519 }
520 if (space) {
521 while (IS_BLANK(c)) {
522 cur += l;
523 c = CUR_SCHAR(cur, l);
524 }
525 }
526 if (c != 0)
527 return(1);
528 return(0);
529}
530
541int
542xmlValidateName(const xmlChar *value, int space) {
543 const xmlChar *cur = value;
544 int c,l;
545
546 if (value == NULL)
547 return(-1);
548 /*
549 * First quick algorithm for ASCII range
550 */
551 if (space)
552 while (IS_BLANK_CH(*cur)) cur++;
553 if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
554 (*cur == '_') || (*cur == ':'))
555 cur++;
556 else
557 goto try_complex;
558 while (((*cur >= 'a') && (*cur <= 'z')) ||
559 ((*cur >= 'A') && (*cur <= 'Z')) ||
560 ((*cur >= '0') && (*cur <= '9')) ||
561 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
562 cur++;
563 if (space)
564 while (IS_BLANK_CH(*cur)) cur++;
565 if (*cur == 0)
566 return(0);
567
568try_complex:
569 /*
570 * Second check for chars outside the ASCII range
571 */
572 cur = value;
573 c = CUR_SCHAR(cur, l);
574 if (space) {
575 while (IS_BLANK(c)) {
576 cur += l;
577 c = CUR_SCHAR(cur, l);
578 }
579 }
580 if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
581 return(1);
582 cur += l;
583 c = CUR_SCHAR(cur, l);
584 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
585 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
586 cur += l;
587 c = CUR_SCHAR(cur, l);
588 }
589 if (space) {
590 while (IS_BLANK(c)) {
591 cur += l;
592 c = CUR_SCHAR(cur, l);
593 }
594 }
595 if (c != 0)
596 return(1);
597 return(0);
598}
599
610int
611xmlValidateNMToken(const xmlChar *value, int space) {
612 const xmlChar *cur = value;
613 int c,l;
614
615 if (value == NULL)
616 return(-1);
617 /*
618 * First quick algorithm for ASCII range
619 */
620 if (space)
621 while (IS_BLANK_CH(*cur)) cur++;
622 if (((*cur >= 'a') && (*cur <= 'z')) ||
623 ((*cur >= 'A') && (*cur <= 'Z')) ||
624 ((*cur >= '0') && (*cur <= '9')) ||
625 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
626 cur++;
627 else
628 goto try_complex;
629 while (((*cur >= 'a') && (*cur <= 'z')) ||
630 ((*cur >= 'A') && (*cur <= 'Z')) ||
631 ((*cur >= '0') && (*cur <= '9')) ||
632 (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
633 cur++;
634 if (space)
635 while (IS_BLANK_CH(*cur)) cur++;
636 if (*cur == 0)
637 return(0);
638
639try_complex:
640 /*
641 * Second check for chars outside the ASCII range
642 */
643 cur = value;
644 c = CUR_SCHAR(cur, l);
645 if (space) {
646 while (IS_BLANK(c)) {
647 cur += l;
648 c = CUR_SCHAR(cur, l);
649 }
650 }
651 if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
652 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
653 return(1);
654 cur += l;
655 c = CUR_SCHAR(cur, l);
656 while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
657 (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
658 cur += l;
659 c = CUR_SCHAR(cur, l);
660 }
661 if (space) {
662 while (IS_BLANK(c)) {
663 cur += l;
664 c = CUR_SCHAR(cur, l);
665 }
666 }
667 if (c != 0)
668 return(1);
669 return(0);
670}
671#endif /* LIBXML_TREE_ENABLED */
672
673/************************************************************************
674 * *
675 * Allocation and deallocation of basic structures *
676 * *
677 ************************************************************************/
678
688void
694}
695
711 return(xmlBufferAllocScheme);
712}
713
731xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
733
734 if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
735 return(NULL);
736
737 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
738 /* xml namespace is predefined, no need to add it */
740 return(NULL);
741
742 /*
743 * Problem, this is an attempt to bind xml prefix to a wrong
744 * namespace, which breaks
745 * Namespace constraint: Reserved Prefixes and Namespace Names
746 * from XML namespace. But documents authors may not care in
747 * their context so let's proceed.
748 */
749 }
750
751 /*
752 * Allocate a new Namespace and fill the fields.
753 */
754 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
755 if (cur == NULL) {
756 xmlTreeErrMemory("building namespace");
757 return(NULL);
758 }
759 memset(cur, 0, sizeof(xmlNs));
760 cur->type = XML_LOCAL_NAMESPACE;
761
762 if (href != NULL)
763 cur->href = xmlStrdup(href);
764 if (prefix != NULL)
765 cur->prefix = xmlStrdup(prefix);
766
767 /*
768 * Add it at the end to preserve parsing order ...
769 * and checks for existing use of the prefix
770 */
771 if (node != NULL) {
772 if (node->nsDef == NULL) {
773 node->nsDef = cur;
774 } else {
775 xmlNsPtr prev = node->nsDef;
776
777 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
778 (xmlStrEqual(prev->prefix, cur->prefix))) {
779 xmlFreeNs(cur);
780 return(NULL);
781 }
782 while (prev->next != NULL) {
783 prev = prev->next;
784 if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
785 (xmlStrEqual(prev->prefix, cur->prefix))) {
786 xmlFreeNs(cur);
787 return(NULL);
788 }
789 }
790 prev->next = cur;
791 }
792 }
793 return(cur);
794}
795
803void
805 if (node == NULL) {
806#ifdef DEBUG_TREE
808 "xmlSetNs: node == NULL\n");
809#endif
810 return;
811 }
812 if ((node->type == XML_ELEMENT_NODE) ||
813 (node->type == XML_ATTRIBUTE_NODE))
814 node->ns = ns;
815}
816
823void
825 if (cur == NULL) {
826#ifdef DEBUG_TREE
828 "xmlFreeNs : ns == NULL\n");
829#endif
830 return;
831 }
832 if (cur->href != NULL) xmlFree((char *) cur->href);
833 if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
834 xmlFree(cur);
835}
836
843void
846 if (cur == NULL) {
847#ifdef DEBUG_TREE
849 "xmlFreeNsList : ns == NULL\n");
850#endif
851 return;
852 }
853 while (cur != NULL) {
854 next = cur->next;
855 xmlFreeNs(cur);
856 cur = next;
857 }
858}
859
873xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
874 const xmlChar *ExternalID, const xmlChar *SystemID) {
876
877 if ((doc != NULL) && (doc->extSubset != NULL)) {
878#ifdef DEBUG_TREE
880 "xmlNewDtd(%s): document %s already have a DTD %s\n",
881 /* !!! */ (char *) name, doc->name,
882 /* !!! */ (char *)doc->extSubset->name);
883#endif
884 return(NULL);
885 }
886
887 /*
888 * Allocate a new DTD and fill the fields.
889 */
890 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
891 if (cur == NULL) {
892 xmlTreeErrMemory("building DTD");
893 return(NULL);
894 }
895 memset(cur, 0 , sizeof(xmlDtd));
896 cur->type = XML_DTD_NODE;
897
898 if (name != NULL)
899 cur->name = xmlStrdup(name);
900 if (ExternalID != NULL)
901 cur->ExternalID = xmlStrdup(ExternalID);
902 if (SystemID != NULL)
903 cur->SystemID = xmlStrdup(SystemID);
904 if (doc != NULL)
905 doc->extSubset = cur;
906 cur->doc = doc;
907
910 return(cur);
911}
912
922xmlGetIntSubset(const xmlDoc *doc) {
924
925 if (doc == NULL)
926 return(NULL);
927 cur = doc->children;
928 while (cur != NULL) {
929 if (cur->type == XML_DTD_NODE)
930 return((xmlDtdPtr) cur);
931 cur = cur->next;
932 }
933 return((xmlDtdPtr) doc->intSubset);
934}
935
948 const xmlChar *ExternalID, const xmlChar *SystemID) {
950
951 if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
952#ifdef DEBUG_TREE
954
955 "xmlCreateIntSubset(): document %s already have an internal subset\n",
956 doc->name);
957#endif
958 return(NULL);
959 }
960
961 /*
962 * Allocate a new DTD and fill the fields.
963 */
964 cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
965 if (cur == NULL) {
966 xmlTreeErrMemory("building internal subset");
967 return(NULL);
968 }
969 memset(cur, 0, sizeof(xmlDtd));
970 cur->type = XML_DTD_NODE;
971
972 if (name != NULL) {
973 cur->name = xmlStrdup(name);
974 if (cur->name == NULL) {
975 xmlTreeErrMemory("building internal subset");
976 xmlFree(cur);
977 return(NULL);
978 }
979 }
980 if (ExternalID != NULL) {
981 cur->ExternalID = xmlStrdup(ExternalID);
982 if (cur->ExternalID == NULL) {
983 xmlTreeErrMemory("building internal subset");
984 if (cur->name != NULL)
985 xmlFree((char *)cur->name);
986 xmlFree(cur);
987 return(NULL);
988 }
989 }
990 if (SystemID != NULL) {
991 cur->SystemID = xmlStrdup(SystemID);
992 if (cur->SystemID == NULL) {
993 xmlTreeErrMemory("building internal subset");
994 if (cur->name != NULL)
995 xmlFree((char *)cur->name);
996 if (cur->ExternalID != NULL)
997 xmlFree((char *)cur->ExternalID);
998 xmlFree(cur);
999 return(NULL);
1000 }
1001 }
1002 if (doc != NULL) {
1003 doc->intSubset = cur;
1004 cur->parent = doc;
1005 cur->doc = doc;
1006 if (doc->children == NULL) {
1007 doc->children = (xmlNodePtr) cur;
1008 doc->last = (xmlNodePtr) cur;
1009 } else {
1010 if (doc->type == XML_HTML_DOCUMENT_NODE) {
1011 xmlNodePtr prev;
1012
1013 prev = doc->children;
1014 prev->prev = (xmlNodePtr) cur;
1015 cur->next = prev;
1016 doc->children = (xmlNodePtr) cur;
1017 } else {
1019
1020 next = doc->children;
1021 while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
1022 next = next->next;
1023 if (next == NULL) {
1024 cur->prev = doc->last;
1025 cur->prev->next = (xmlNodePtr) cur;
1026 cur->next = NULL;
1027 doc->last = (xmlNodePtr) cur;
1028 } else {
1029 cur->next = next;
1030 cur->prev = next->prev;
1031 if (cur->prev == NULL)
1032 doc->children = (xmlNodePtr) cur;
1033 else
1034 cur->prev->next = (xmlNodePtr) cur;
1035 next->prev = (xmlNodePtr) cur;
1036 }
1037 }
1038 }
1039 }
1040
1043 return(cur);
1044}
1045
1053#define DICT_FREE(str) \
1054 if ((str) && ((!dict) || \
1055 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1056 xmlFree((char *)(str));
1057
1058
1066#define DICT_COPY(str, cpy) \
1067 if (str) { \
1068 if (dict) { \
1069 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1070 cpy = (xmlChar *) (str); \
1071 else \
1072 cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1073 } else \
1074 cpy = xmlStrdup((const xmlChar *)(str)); }
1075
1083#define DICT_CONST_COPY(str, cpy) \
1084 if (str) { \
1085 if (dict) { \
1086 if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1087 cpy = (const xmlChar *) (str); \
1088 else \
1089 cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1090 } else \
1091 cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
1092
1093
1100void
1102 xmlDictPtr dict = NULL;
1103
1104 if (cur == NULL) {
1105 return;
1106 }
1107 if (cur->doc != NULL) dict = cur->doc->dict;
1108
1111
1112 if (cur->children != NULL) {
1113 xmlNodePtr next, c = cur->children;
1114
1115 /*
1116 * Cleanup all nodes which are not part of the specific lists
1117 * of notations, elements, attributes and entities.
1118 */
1119 while (c != NULL) {
1120 next = c->next;
1121 if ((c->type != XML_NOTATION_NODE) &&
1122 (c->type != XML_ELEMENT_DECL) &&
1123 (c->type != XML_ATTRIBUTE_DECL) &&
1124 (c->type != XML_ENTITY_DECL)) {
1126 xmlFreeNode(c);
1127 }
1128 c = next;
1129 }
1130 }
1131 DICT_FREE(cur->name)
1132 DICT_FREE(cur->SystemID)
1133 DICT_FREE(cur->ExternalID)
1134 /* TODO !!! */
1135 if (cur->notations != NULL)
1137
1138 if (cur->elements != NULL)
1140 if (cur->attributes != NULL)
1142 if (cur->entities != NULL)
1144 if (cur->pentities != NULL)
1146
1147 xmlFree(cur);
1148}
1149
1160 xmlDocPtr cur;
1161
1162 if (version == NULL)
1163 version = (const xmlChar *) "1.0";
1164
1165 /*
1166 * Allocate a new document and fill the fields.
1167 */
1168 cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1169 if (cur == NULL) {
1170 xmlTreeErrMemory("building doc");
1171 return(NULL);
1172 }
1173 memset(cur, 0, sizeof(xmlDoc));
1174 cur->type = XML_DOCUMENT_NODE;
1175
1176 cur->version = xmlStrdup(version);
1177 if (cur->version == NULL) {
1178 xmlTreeErrMemory("building doc");
1179 xmlFree(cur);
1180 return(NULL);
1181 }
1182 cur->standalone = -1;
1183 cur->compression = -1; /* not initialized */
1184 cur->doc = cur;
1185 cur->parseFlags = 0;
1186 cur->properties = XML_DOC_USERBUILT;
1187 /*
1188 * The in memory encoding is always UTF8
1189 * This field will never change and would
1190 * be obsolete if not for binary compatibility.
1191 */
1192 cur->charset = XML_CHAR_ENCODING_UTF8;
1193
1196 return(cur);
1197}
1198
1205void
1207 xmlDtdPtr extSubset, intSubset;
1208 xmlDictPtr dict = NULL;
1209
1210 if (cur == NULL) {
1211#ifdef DEBUG_TREE
1213 "xmlFreeDoc : document == NULL\n");
1214#endif
1215 return;
1216 }
1217#ifdef LIBXML_DEBUG_RUNTIME
1218#ifdef LIBXML_DEBUG_ENABLED
1219 xmlDebugCheckDocument(stderr, cur);
1220#endif
1221#endif
1222
1223 if (cur != NULL) dict = cur->dict;
1224
1227
1228 /*
1229 * Do this before freeing the children list to avoid ID lookups
1230 */
1231 if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1232 cur->ids = NULL;
1233 if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1234 cur->refs = NULL;
1235 extSubset = cur->extSubset;
1236 intSubset = cur->intSubset;
1237 if (intSubset == extSubset)
1238 extSubset = NULL;
1239 if (extSubset != NULL) {
1240 xmlUnlinkNode((xmlNodePtr) cur->extSubset);
1241 cur->extSubset = NULL;
1242 xmlFreeDtd(extSubset);
1243 }
1244 if (intSubset != NULL) {
1245 xmlUnlinkNode((xmlNodePtr) cur->intSubset);
1246 cur->intSubset = NULL;
1247 xmlFreeDtd(intSubset);
1248 }
1249
1250 if (cur->children != NULL) xmlFreeNodeList(cur->children);
1251 if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1252
1253 DICT_FREE(cur->version)
1256 DICT_FREE(cur->URL)
1257 xmlFree(cur);
1258 if (dict) xmlDictFree(dict);
1259}
1260
1275 xmlChar *val;
1276 const xmlChar *cur, *end;
1277 const xmlChar *q;
1278 xmlEntityPtr ent;
1279 xmlBufPtr buf;
1280
1281 if (value == NULL) return(NULL);
1282 cur = value;
1283 end = cur + len;
1284
1285 buf = xmlBufCreateSize(0);
1286 if (buf == NULL) return(NULL);
1288
1289 q = cur;
1290 while ((cur < end) && (*cur != 0)) {
1291 if (cur[0] == '&') {
1292 int charval = 0;
1293 xmlChar tmp;
1294
1295 /*
1296 * Save the current text.
1297 */
1298 if (cur != q) {
1299 if (xmlBufAdd(buf, q, cur - q))
1300 goto out;
1301 }
1302 q = cur;
1303 if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1304 cur += 3;
1305 if (cur < end)
1306 tmp = *cur;
1307 else
1308 tmp = 0;
1309 while (tmp != ';') { /* Non input consuming loop */
1310 /*
1311 * If you find an integer overflow here when fuzzing,
1312 * the bug is probably elsewhere. This function should
1313 * only receive entities that were already validated by
1314 * the parser, typically by xmlParseAttValueComplex
1315 * calling xmlStringDecodeEntities.
1316 *
1317 * So it's better *not* to check for overflow to
1318 * potentially discover new bugs.
1319 */
1320 if ((tmp >= '0') && (tmp <= '9'))
1321 charval = charval * 16 + (tmp - '0');
1322 else if ((tmp >= 'a') && (tmp <= 'f'))
1323 charval = charval * 16 + (tmp - 'a') + 10;
1324 else if ((tmp >= 'A') && (tmp <= 'F'))
1325 charval = charval * 16 + (tmp - 'A') + 10;
1326 else {
1327 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1328 NULL);
1329 charval = 0;
1330 break;
1331 }
1332 cur++;
1333 if (cur < end)
1334 tmp = *cur;
1335 else
1336 tmp = 0;
1337 }
1338 if (tmp == ';')
1339 cur++;
1340 q = cur;
1341 } else if ((cur + 1 < end) && (cur[1] == '#')) {
1342 cur += 2;
1343 if (cur < end)
1344 tmp = *cur;
1345 else
1346 tmp = 0;
1347 while (tmp != ';') { /* Non input consuming loops */
1348 /* Don't check for integer overflow, see above. */
1349 if ((tmp >= '0') && (tmp <= '9'))
1350 charval = charval * 10 + (tmp - '0');
1351 else {
1352 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1353 NULL);
1354 charval = 0;
1355 break;
1356 }
1357 cur++;
1358 if (cur < end)
1359 tmp = *cur;
1360 else
1361 tmp = 0;
1362 }
1363 if (tmp == ';')
1364 cur++;
1365 q = cur;
1366 } else {
1367 /*
1368 * Read the entity string
1369 */
1370 cur++;
1371 q = cur;
1372 while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1373 if ((cur >= end) || (*cur == 0)) {
1374 xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1375 (const char *) q);
1376 goto out;
1377 }
1378 if (cur != q) {
1379 /*
1380 * Predefined entities don't generate nodes
1381 */
1382 val = xmlStrndup(q, cur - q);
1383 ent = xmlGetDocEntity(doc, val);
1384 if ((ent != NULL) &&
1386
1387 if (xmlBufCat(buf, ent->content))
1388 goto out;
1389
1390 } else {
1391 /*
1392 * Flush buffer so far
1393 */
1394 if (!xmlBufIsEmpty(buf)) {
1395 node = xmlNewDocText(doc, NULL);
1396 if (node == NULL) {
1397 if (val != NULL) xmlFree(val);
1398 goto out;
1399 }
1400 node->content = xmlBufDetach(buf);
1401
1402 if (last == NULL) {
1403 last = ret = node;
1404 } else {
1406 }
1407 }
1408
1409 /*
1410 * Create a new REFERENCE_REF node
1411 */
1412 node = xmlNewReference(doc, val);
1413 if (node == NULL) {
1414 if (val != NULL) xmlFree(val);
1415 goto out;
1416 }
1417 else if ((ent != NULL) && (ent->children == NULL)) {
1419
1420 /* Set to non-NULL value to avoid recursion. */
1421 ent->children = (xmlNodePtr) -1;
1422 ent->children = xmlStringGetNodeList(doc,
1423 (const xmlChar*)node->content);
1424 ent->owner = 1;
1425 temp = ent->children;
1426 while (temp) {
1427 temp->parent = (xmlNodePtr)ent;
1428 ent->last = temp;
1429 temp = temp->next;
1430 }
1431 }
1432 if (last == NULL) {
1433 last = ret = node;
1434 } else {
1436 }
1437 }
1438 xmlFree(val);
1439 }
1440 cur++;
1441 q = cur;
1442 }
1443 if (charval != 0) {
1444 xmlChar buffer[10];
1445 int l;
1446
1447 l = xmlCopyCharMultiByte(buffer, charval);
1448 buffer[l] = 0;
1449
1450 if (xmlBufCat(buf, buffer))
1451 goto out;
1452 charval = 0;
1453 }
1454 } else
1455 cur++;
1456 }
1457
1458 if (cur != q) {
1459 /*
1460 * Handle the last piece of text.
1461 */
1462 if (xmlBufAdd(buf, q, cur - q))
1463 goto out;
1464 }
1465
1466 if (!xmlBufIsEmpty(buf)) {
1467 node = xmlNewDocText(doc, NULL);
1468 if (node == NULL) goto out;
1469 node->content = xmlBufDetach(buf);
1470
1471 if (last == NULL) {
1472 ret = node;
1473 } else {
1475 }
1476 } else if (ret == NULL) {
1477 ret = xmlNewDocText(doc, BAD_CAST "");
1478 }
1479
1480out:
1481 xmlBufFree(buf);
1482 return(ret);
1483}
1484
1495xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) {
1498 xmlChar *val;
1499 const xmlChar *cur = value;
1500 const xmlChar *q;
1501 xmlEntityPtr ent;
1502 xmlBufPtr buf;
1503
1504 if (value == NULL) return(NULL);
1505
1506 buf = xmlBufCreateSize(0);
1507 if (buf == NULL) return(NULL);
1509
1510 q = cur;
1511 while (*cur != 0) {
1512 if (cur[0] == '&') {
1513 int charval = 0;
1514 xmlChar tmp;
1515
1516 /*
1517 * Save the current text.
1518 */
1519 if (cur != q) {
1520 if (xmlBufAdd(buf, q, cur - q))
1521 goto out;
1522 }
1523 q = cur;
1524 if ((cur[1] == '#') && (cur[2] == 'x')) {
1525 cur += 3;
1526 tmp = *cur;
1527 while (tmp != ';') { /* Non input consuming loop */
1528 /* Don't check for integer overflow, see above. */
1529 if ((tmp >= '0') && (tmp <= '9'))
1530 charval = charval * 16 + (tmp - '0');
1531 else if ((tmp >= 'a') && (tmp <= 'f'))
1532 charval = charval * 16 + (tmp - 'a') + 10;
1533 else if ((tmp >= 'A') && (tmp <= 'F'))
1534 charval = charval * 16 + (tmp - 'A') + 10;
1535 else {
1536 xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1537 NULL);
1538 charval = 0;
1539 break;
1540 }
1541 cur++;
1542 tmp = *cur;
1543 }
1544 if (tmp == ';')
1545 cur++;
1546 q = cur;
1547 } else if (cur[1] == '#') {
1548 cur += 2;
1549 tmp = *cur;
1550 while (tmp != ';') { /* Non input consuming loops */
1551 /* Don't check for integer overflow, see above. */
1552 if ((tmp >= '0') && (tmp <= '9'))
1553 charval = charval * 10 + (tmp - '0');
1554 else {
1555 xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1556 NULL);
1557 charval = 0;
1558 break;
1559 }
1560 cur++;
1561 tmp = *cur;
1562 }
1563 if (tmp == ';')
1564 cur++;
1565 q = cur;
1566 } else {
1567 /*
1568 * Read the entity string
1569 */
1570 cur++;
1571 q = cur;
1572 while ((*cur != 0) && (*cur != ';')) cur++;
1573 if (*cur == 0) {
1575 (xmlNodePtr) doc, (const char *) q);
1576 goto out;
1577 }
1578 if (cur != q) {
1579 /*
1580 * Predefined entities don't generate nodes
1581 */
1582 val = xmlStrndup(q, cur - q);
1583 ent = xmlGetDocEntity(doc, val);
1584 if ((ent != NULL) &&
1586
1587 if (xmlBufCat(buf, ent->content))
1588 goto out;
1589
1590 } else {
1591 /*
1592 * Flush buffer so far
1593 */
1594 if (!xmlBufIsEmpty(buf)) {
1595 node = xmlNewDocText(doc, NULL);
1596 if (node == NULL) {
1597 if (val != NULL) xmlFree(val);
1598 goto out;
1599 }
1600 node->content = xmlBufDetach(buf);
1601
1602 if (last == NULL) {
1603 last = ret = node;
1604 } else {
1606 }
1607 }
1608
1609 /*
1610 * Create a new REFERENCE_REF node
1611 */
1612 node = xmlNewReference(doc, val);
1613 if (node == NULL) {
1614 if (val != NULL) xmlFree(val);
1615 goto out;
1616 }
1617 else if ((ent != NULL) && (ent->children == NULL)) {
1619
1620 /* Set to non-NULL value to avoid recursion. */
1621 ent->children = (xmlNodePtr) -1;
1622 ent->children = xmlStringGetNodeList(doc,
1623 (const xmlChar*)node->content);
1624 ent->owner = 1;
1625 temp = ent->children;
1626 while (temp) {
1627 temp->parent = (xmlNodePtr)ent;
1628 ent->last = temp;
1629 temp = temp->next;
1630 }
1631 }
1632 if (last == NULL) {
1633 last = ret = node;
1634 } else {
1636 }
1637 }
1638 xmlFree(val);
1639 }
1640 cur++;
1641 q = cur;
1642 }
1643 if (charval != 0) {
1644 xmlChar buffer[10];
1645 int len;
1646
1647 len = xmlCopyCharMultiByte(buffer, charval);
1648 buffer[len] = 0;
1649
1650 if (xmlBufCat(buf, buffer))
1651 goto out;
1652 charval = 0;
1653 }
1654 } else
1655 cur++;
1656 }
1657 if ((cur != q) || (ret == NULL)) {
1658 /*
1659 * Handle the last piece of text.
1660 */
1661 xmlBufAdd(buf, q, cur - q);
1662 }
1663
1664 if (!xmlBufIsEmpty(buf)) {
1665 node = xmlNewDocText(doc, NULL);
1666 if (node == NULL) {
1667 xmlBufFree(buf);
1668 return(NULL);
1669 }
1670 node->content = xmlBufDetach(buf);
1671
1672 if (last == NULL) {
1673 ret = node;
1674 } else {
1676 }
1677 }
1678
1679out:
1680 xmlBufFree(buf);
1681 return(ret);
1682}
1683
1695xmlChar *
1696xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
1697{
1698 const xmlNode *node = list;
1699 xmlChar *ret = NULL;
1700 xmlEntityPtr ent;
1701 int attr;
1702
1703 if (list == NULL)
1704 return (NULL);
1705 if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
1706 attr = 1;
1707 else
1708 attr = 0;
1709
1710 while (node != NULL) {
1711 if ((node->type == XML_TEXT_NODE) ||
1712 (node->type == XML_CDATA_SECTION_NODE)) {
1713 if (inLine) {
1714 ret = xmlStrcat(ret, node->content);
1715 } else {
1716 xmlChar *buffer;
1717
1718 if (attr)
1719 buffer = xmlEncodeAttributeEntities(doc, node->content);
1720 else
1721 buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1722 if (buffer != NULL) {
1723 ret = xmlStrcat(ret, buffer);
1724 xmlFree(buffer);
1725 }
1726 }
1727 } else if (node->type == XML_ENTITY_REF_NODE) {
1728 if (inLine) {
1729 ent = xmlGetDocEntity(doc, node->name);
1730 if (ent != NULL) {
1731 xmlChar *buffer;
1732
1733 /* an entity content can be any "well balanced chunk",
1734 * i.e. the result of the content [43] production:
1735 * http://www.w3.org/TR/REC-xml#NT-content.
1736 * So it can contain text, CDATA section or nested
1737 * entity reference nodes (among others).
1738 * -> we recursive call xmlNodeListGetString()
1739 * which handles these types */
1740 buffer = xmlNodeListGetString(doc, ent->children, 1);
1741 if (buffer != NULL) {
1742 ret = xmlStrcat(ret, buffer);
1743 xmlFree(buffer);
1744 }
1745 } else {
1746 ret = xmlStrcat(ret, node->content);
1747 }
1748 } else {
1749 xmlChar buf[2];
1750
1751 buf[0] = '&';
1752 buf[1] = 0;
1753 ret = xmlStrncat(ret, buf, 1);
1754 ret = xmlStrcat(ret, node->name);
1755 buf[0] = ';';
1756 buf[1] = 0;
1757 ret = xmlStrncat(ret, buf, 1);
1758 }
1759 }
1760#if 0
1761 else {
1763 "xmlGetNodeListString : invalid node type %d\n",
1764 node->type);
1765 }
1766#endif
1767 node = node->next;
1768 }
1769 return (ret);
1770}
1771
1772#ifdef LIBXML_TREE_ENABLED
1785xmlChar *
1786xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine)
1787{
1788 const xmlNode *node = list;
1789 xmlChar *ret = NULL;
1790 xmlEntityPtr ent;
1791
1792 if (list == NULL)
1793 return (NULL);
1794
1795 while (node != NULL) {
1796 if ((node->type == XML_TEXT_NODE) ||
1797 (node->type == XML_CDATA_SECTION_NODE)) {
1798 if (inLine) {
1799 ret = xmlStrcat(ret, node->content);
1800 } else {
1801 xmlChar *buffer;
1802
1803 buffer = xmlEncodeSpecialChars(doc, node->content);
1804 if (buffer != NULL) {
1805 ret = xmlStrcat(ret, buffer);
1806 xmlFree(buffer);
1807 }
1808 }
1809 } else if (node->type == XML_ENTITY_REF_NODE) {
1810 if (inLine) {
1811 ent = xmlGetDocEntity(doc, node->name);
1812 if (ent != NULL) {
1813 xmlChar *buffer;
1814
1815 /* an entity content can be any "well balanced chunk",
1816 * i.e. the result of the content [43] production:
1817 * http://www.w3.org/TR/REC-xml#NT-content.
1818 * So it can contain text, CDATA section or nested
1819 * entity reference nodes (among others).
1820 * -> we recursive call xmlNodeListGetRawString()
1821 * which handles these types */
1822 buffer =
1823 xmlNodeListGetRawString(doc, ent->children, 1);
1824 if (buffer != NULL) {
1825 ret = xmlStrcat(ret, buffer);
1826 xmlFree(buffer);
1827 }
1828 } else {
1829 ret = xmlStrcat(ret, node->content);
1830 }
1831 } else {
1832 xmlChar buf[2];
1833
1834 buf[0] = '&';
1835 buf[1] = 0;
1836 ret = xmlStrncat(ret, buf, 1);
1837 ret = xmlStrcat(ret, node->name);
1838 buf[0] = ';';
1839 buf[1] = 0;
1840 ret = xmlStrncat(ret, buf, 1);
1841 }
1842 }
1843#if 0
1844 else {
1846 "xmlGetNodeListString : invalid node type %d\n",
1847 node->type);
1848 }
1849#endif
1850 node = node->next;
1851 }
1852 return (ret);
1853}
1854#endif /* LIBXML_TREE_ENABLED */
1855
1856static xmlAttrPtr
1857xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1858 const xmlChar * name, const xmlChar * value,
1859 int eatname)
1860{
1862 xmlDocPtr doc = NULL;
1863
1864 if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1865 if ((eatname == 1) &&
1866 ((node->doc == NULL) ||
1867 (!(xmlDictOwns(node->doc->dict, name)))))
1868 xmlFree((xmlChar *) name);
1869 return (NULL);
1870 }
1871
1872 /*
1873 * Allocate a new property and fill the fields.
1874 */
1875 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1876 if (cur == NULL) {
1877 if ((eatname == 1) &&
1878 ((node == NULL) || (node->doc == NULL) ||
1879 (!(xmlDictOwns(node->doc->dict, name)))))
1880 xmlFree((xmlChar *) name);
1881 xmlTreeErrMemory("building attribute");
1882 return (NULL);
1883 }
1884 memset(cur, 0, sizeof(xmlAttr));
1885 cur->type = XML_ATTRIBUTE_NODE;
1886
1887 cur->parent = node;
1888 if (node != NULL) {
1889 doc = node->doc;
1890 cur->doc = doc;
1891 }
1892 cur->ns = ns;
1893
1894 if (eatname == 0) {
1895 if ((doc != NULL) && (doc->dict != NULL))
1896 cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1897 else
1898 cur->name = xmlStrdup(name);
1899 } else
1900 cur->name = name;
1901
1902 if (value != NULL) {
1903 xmlNodePtr tmp;
1904
1905 cur->children = xmlNewDocText(doc, value);
1906 cur->last = NULL;
1907 tmp = cur->children;
1908 while (tmp != NULL) {
1909 tmp->parent = (xmlNodePtr) cur;
1910 if (tmp->next == NULL)
1911 cur->last = tmp;
1912 tmp = tmp->next;
1913 }
1914 }
1915
1916 /*
1917 * Add it at the end to preserve parsing order ...
1918 */
1919 if (node != NULL) {
1920 if (node->properties == NULL) {
1921 node->properties = cur;
1922 } else {
1923 xmlAttrPtr prev = node->properties;
1924
1925 while (prev->next != NULL)
1926 prev = prev->next;
1927 prev->next = cur;
1928 cur->prev = prev;
1929 }
1930 }
1931
1932 if ((value != NULL) && (node != NULL) &&
1933 (xmlIsID(node->doc, node, cur) == 1))
1934 xmlAddID(NULL, node->doc, value, cur);
1935
1938 return (cur);
1939}
1940
1941#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1942 defined(LIBXML_SCHEMAS_ENABLED)
1953xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1954
1955 if (name == NULL) {
1956#ifdef DEBUG_TREE
1958 "xmlNewProp : name == NULL\n");
1959#endif
1960 return(NULL);
1961 }
1962
1963 return xmlNewPropInternal(node, NULL, name, value, 0);
1964}
1965#endif /* LIBXML_TREE_ENABLED */
1966
1979 const xmlChar *value) {
1980
1981 if (name == NULL) {
1982#ifdef DEBUG_TREE
1984 "xmlNewNsProp : name == NULL\n");
1985#endif
1986 return(NULL);
1987 }
1988
1989 return xmlNewPropInternal(node, ns, name, value, 0);
1990}
1991
2004 const xmlChar *value) {
2005
2006 if (name == NULL) {
2007#ifdef DEBUG_TREE
2009 "xmlNewNsPropEatName : name == NULL\n");
2010#endif
2011 return(NULL);
2012 }
2013
2014 return xmlNewPropInternal(node, ns, name, value, 1);
2015}
2016
2032xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
2034
2035 if (name == NULL) {
2036#ifdef DEBUG_TREE
2038 "xmlNewDocProp : name == NULL\n");
2039#endif
2040 return(NULL);
2041 }
2042
2043 /*
2044 * Allocate a new property and fill the fields.
2045 */
2046 cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
2047 if (cur == NULL) {
2048 xmlTreeErrMemory("building attribute");
2049 return(NULL);
2050 }
2051 memset(cur, 0, sizeof(xmlAttr));
2052 cur->type = XML_ATTRIBUTE_NODE;
2053
2054 if ((doc != NULL) && (doc->dict != NULL))
2055 cur->name = xmlDictLookup(doc->dict, name, -1);
2056 else
2057 cur->name = xmlStrdup(name);
2058 cur->doc = doc;
2059 if (value != NULL) {
2060 xmlNodePtr tmp;
2061
2062 cur->children = xmlStringGetNodeList(doc, value);
2063 cur->last = NULL;
2064
2065 tmp = cur->children;
2066 while (tmp != NULL) {
2067 tmp->parent = (xmlNodePtr) cur;
2068 if (tmp->next == NULL)
2069 cur->last = tmp;
2070 tmp = tmp->next;
2071 }
2072 }
2073
2076 return(cur);
2077}
2078
2085void
2088 if (cur == NULL) return;
2089 while (cur != NULL) {
2090 next = cur->next;
2092 cur = next;
2093 }
2094}
2095
2102void
2104 xmlDictPtr dict = NULL;
2105 if (cur == NULL) return;
2106
2107 if (cur->doc != NULL) dict = cur->doc->dict;
2108
2111
2112 /* Check for ID removal -> leading to invalid references ! */
2113 if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2114 xmlRemoveID(cur->doc, cur);
2115 }
2116 if (cur->children != NULL) xmlFreeNodeList(cur->children);
2117 DICT_FREE(cur->name)
2118 xmlFree(cur);
2119}
2120
2130int
2132 xmlAttrPtr tmp;
2133 if (cur == NULL) {
2134#ifdef DEBUG_TREE
2136 "xmlRemoveProp : cur == NULL\n");
2137#endif
2138 return(-1);
2139 }
2140 if (cur->parent == NULL) {
2141#ifdef DEBUG_TREE
2143 "xmlRemoveProp : cur->parent == NULL\n");
2144#endif
2145 return(-1);
2146 }
2147 tmp = cur->parent->properties;
2148 if (tmp == cur) {
2149 cur->parent->properties = cur->next;
2150 if (cur->next != NULL)
2151 cur->next->prev = NULL;
2153 return(0);
2154 }
2155 while (tmp != NULL) {
2156 if (tmp->next == cur) {
2157 tmp->next = cur->next;
2158 if (tmp->next != NULL)
2159 tmp->next->prev = tmp;
2161 return(0);
2162 }
2163 tmp = tmp->next;
2164 }
2165#ifdef DEBUG_TREE
2167 "xmlRemoveProp : attribute not owned by its node\n");
2168#endif
2169 return(-1);
2170}
2171
2182xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
2184
2185 if (name == NULL) {
2186#ifdef DEBUG_TREE
2188 "xmlNewPI : name == NULL\n");
2189#endif
2190 return(NULL);
2191 }
2192
2193 /*
2194 * Allocate a new node and fill the fields.
2195 */
2196 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2197 if (cur == NULL) {
2198 xmlTreeErrMemory("building PI");
2199 return(NULL);
2200 }
2201 memset(cur, 0, sizeof(xmlNode));
2202 cur->type = XML_PI_NODE;
2203
2204 if ((doc != NULL) && (doc->dict != NULL))
2205 cur->name = xmlDictLookup(doc->dict, name, -1);
2206 else
2207 cur->name = xmlStrdup(name);
2208 if (content != NULL) {
2209 cur->content = xmlStrdup(content);
2210 }
2211 cur->doc = doc;
2212
2215 return(cur);
2216}
2217
2230xmlNewPI(const xmlChar *name, const xmlChar *content) {
2231 return(xmlNewDocPI(NULL, name, content));
2232}
2233
2249
2250 if (name == NULL) {
2251#ifdef DEBUG_TREE
2253 "xmlNewNode : name == NULL\n");
2254#endif
2255 return(NULL);
2256 }
2257
2258 /*
2259 * Allocate a new node and fill the fields.
2260 */
2261 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2262 if (cur == NULL) {
2263 xmlTreeErrMemory("building node");
2264 return(NULL);
2265 }
2266 memset(cur, 0, sizeof(xmlNode));
2267 cur->type = XML_ELEMENT_NODE;
2268
2269 cur->name = xmlStrdup(name);
2270 cur->ns = ns;
2271
2274 return(cur);
2275}
2276
2293
2294 if (name == NULL) {
2295#ifdef DEBUG_TREE
2297 "xmlNewNode : name == NULL\n");
2298#endif
2299 return(NULL);
2300 }
2301
2302 /*
2303 * Allocate a new node and fill the fields.
2304 */
2305 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2306 if (cur == NULL) {
2307 xmlTreeErrMemory("building node");
2308 /* we can't check here that name comes from the doc dictionary */
2309 return(NULL);
2310 }
2311 memset(cur, 0, sizeof(xmlNode));
2312 cur->type = XML_ELEMENT_NODE;
2313
2314 cur->name = name;
2315 cur->ns = ns;
2316
2319 return(cur);
2320}
2321
2340 const xmlChar *name, const xmlChar *content) {
2342
2343 if ((doc != NULL) && (doc->dict != NULL))
2345 xmlDictLookup(doc->dict, name, -1));
2346 else
2347 cur = xmlNewNode(ns, name);
2348 if (cur != NULL) {
2349 cur->doc = doc;
2350 if (content != NULL) {
2351 cur->children = xmlStringGetNodeList(doc, content);
2353 }
2354 }
2355
2356 return(cur);
2357}
2358
2377 xmlChar *name, const xmlChar *content) {
2379
2381 if (cur != NULL) {
2382 cur->doc = doc;
2383 if (content != NULL) {
2384 cur->children = xmlStringGetNodeList(doc, content);
2386 }
2387 } else {
2388 /* if name don't come from the doc dictionary free it here */
2389 if ((name != NULL) && (doc != NULL) &&
2390 (!(xmlDictOwns(doc->dict, name))))
2391 xmlFree(name);
2392 }
2393 return(cur);
2394}
2395
2396#ifdef LIBXML_TREE_ENABLED
2410xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2411 const xmlChar *name, const xmlChar *content) {
2413
2414 cur = xmlNewDocNode(doc, ns, name, NULL);
2415 if (cur != NULL) {
2416 cur->doc = doc;
2417 if (content != NULL) {
2418 cur->children = xmlNewDocText(doc, content);
2420 }
2421 }
2422 return(cur);
2423}
2424
2433xmlNewDocFragment(xmlDocPtr doc) {
2435
2436 /*
2437 * Allocate a new DocumentFragment node and fill the fields.
2438 */
2439 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2440 if (cur == NULL) {
2441 xmlTreeErrMemory("building fragment");
2442 return(NULL);
2443 }
2444 memset(cur, 0, sizeof(xmlNode));
2446
2447 cur->doc = doc;
2448
2451 return(cur);
2452}
2453#endif /* LIBXML_TREE_ENABLED */
2454
2466xmlNewText(const xmlChar *content) {
2468
2469 /*
2470 * Allocate a new node and fill the fields.
2471 */
2472 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2473 if (cur == NULL) {
2474 xmlTreeErrMemory("building text");
2475 return(NULL);
2476 }
2477 memset(cur, 0, sizeof(xmlNode));
2478 cur->type = XML_TEXT_NODE;
2479
2480 cur->name = xmlStringText;
2481 if (content != NULL) {
2482 cur->content = xmlStrdup(content);
2483 }
2484
2487 return(cur);
2488}
2489
2490#ifdef LIBXML_TREE_ENABLED
2511xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2512 const xmlChar *name, const xmlChar *content) {
2513 xmlNodePtr cur, prev;
2514
2515 if (parent == NULL) {
2516#ifdef DEBUG_TREE
2518 "xmlNewTextChild : parent == NULL\n");
2519#endif
2520 return(NULL);
2521 }
2522
2523 if (name == NULL) {
2524#ifdef DEBUG_TREE
2526 "xmlNewTextChild : name == NULL\n");
2527#endif
2528 return(NULL);
2529 }
2530
2531 /*
2532 * Allocate a new node
2533 */
2534 if (parent->type == XML_ELEMENT_NODE) {
2535 if (ns == NULL)
2536 cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2537 else
2538 cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2539 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2540 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2541 if (ns == NULL)
2542 cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2543 else
2544 cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2545 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2546 cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2547 } else {
2548 return(NULL);
2549 }
2550 if (cur == NULL) return(NULL);
2551
2552 /*
2553 * add the new element at the end of the children list.
2554 */
2555 cur->type = XML_ELEMENT_NODE;
2556 cur->parent = parent;
2557 cur->doc = parent->doc;
2558 if (parent->children == NULL) {
2559 parent->children = cur;
2560 parent->last = cur;
2561 } else {
2562 prev = parent->last;
2563 prev->next = cur;
2564 cur->prev = prev;
2565 parent->last = cur;
2566 }
2567
2568 return(cur);
2569}
2570#endif /* LIBXML_TREE_ENABLED */
2571
2581xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2583
2584 if (name == NULL)
2585 return(NULL);
2586
2587 /*
2588 * Allocate a new node and fill the fields.
2589 */
2590 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2591 if (cur == NULL) {
2592 xmlTreeErrMemory("building character reference");
2593 return(NULL);
2594 }
2595 memset(cur, 0, sizeof(xmlNode));
2596 cur->type = XML_ENTITY_REF_NODE;
2597
2598 cur->doc = doc;
2599 if (name[0] == '&') {
2600 int len;
2601 name++;
2602 len = xmlStrlen(name);
2603 if (name[len - 1] == ';')
2604 cur->name = xmlStrndup(name, len - 1);
2605 else
2606 cur->name = xmlStrndup(name, len);
2607 } else
2608 cur->name = xmlStrdup(name);
2609
2612 return(cur);
2613}
2614
2624xmlNewReference(const xmlDoc *doc, const xmlChar *name) {
2626 xmlEntityPtr ent;
2627
2628 if (name == NULL)
2629 return(NULL);
2630
2631 /*
2632 * Allocate a new node and fill the fields.
2633 */
2634 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2635 if (cur == NULL) {
2636 xmlTreeErrMemory("building reference");
2637 return(NULL);
2638 }
2639 memset(cur, 0, sizeof(xmlNode));
2640 cur->type = XML_ENTITY_REF_NODE;
2641
2642 cur->doc = (xmlDoc *)doc;
2643 if (name[0] == '&') {
2644 int len;
2645 name++;
2646 len = xmlStrlen(name);
2647 if (name[len - 1] == ';')
2648 cur->name = xmlStrndup(name, len - 1);
2649 else
2650 cur->name = xmlStrndup(name, len);
2651 } else
2652 cur->name = xmlStrdup(name);
2653
2654 ent = xmlGetDocEntity(doc, cur->name);
2655 if (ent != NULL) {
2656 cur->content = ent->content;
2657 /*
2658 * The parent pointer in entity is a DTD pointer and thus is NOT
2659 * updated. Not sure if this is 100% correct.
2660 * -George
2661 */
2662 cur->children = (xmlNodePtr) ent;
2663 cur->last = (xmlNodePtr) ent;
2664 }
2665
2668 return(cur);
2669}
2670
2680xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
2682
2684 if (cur != NULL) cur->doc = (xmlDoc *)doc;
2685 return(cur);
2686}
2687
2699xmlNewTextLen(const xmlChar *content, int len) {
2701
2702 /*
2703 * Allocate a new node and fill the fields.
2704 */
2705 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2706 if (cur == NULL) {
2707 xmlTreeErrMemory("building text");
2708 return(NULL);
2709 }
2710 memset(cur, 0, sizeof(xmlNode));
2711 cur->type = XML_TEXT_NODE;
2712
2713 cur->name = xmlStringText;
2714 if (content != NULL) {
2715 cur->content = xmlStrndup(content, len);
2716 }
2717
2720 return(cur);
2721}
2722
2734xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2736
2738 if (cur != NULL) cur->doc = doc;
2739 return(cur);
2740}
2741
2754
2755 /*
2756 * Allocate a new node and fill the fields.
2757 */
2758 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2759 if (cur == NULL) {
2760 xmlTreeErrMemory("building comment");
2761 return(NULL);
2762 }
2763 memset(cur, 0, sizeof(xmlNode));
2764 cur->type = XML_COMMENT_NODE;
2765
2766 cur->name = xmlStringComment;
2767 if (content != NULL) {
2768 cur->content = xmlStrdup(content);
2769 }
2770
2773 return(cur);
2774}
2775
2786xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2788
2789 /*
2790 * Allocate a new node and fill the fields.
2791 */
2792 cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2793 if (cur == NULL) {
2794 xmlTreeErrMemory("building CDATA");
2795 return(NULL);
2796 }
2797 memset(cur, 0, sizeof(xmlNode));
2799 cur->doc = doc;
2800
2801 if (content != NULL) {
2802 cur->content = xmlStrndup(content, len);
2803 }
2804
2807 return(cur);
2808}
2809
2821
2823 if (cur != NULL) cur->doc = doc;
2824 return(cur);
2825}
2826
2827static const xmlChar *_copyStringForNewDictIfNeeded(xmlDictPtr oldDict, xmlDictPtr newDict, const xmlChar *oldValue) {
2828 const xmlChar *newValue = oldValue;
2829 if (oldValue) {
2830 int oldDictOwnsOldValue = oldDict && (xmlDictOwns(oldDict, oldValue) == 1);
2831 if (oldDictOwnsOldValue) {
2832 if (newDict)
2833 newValue = xmlDictLookup(newDict, oldValue, -1);
2834 else
2835 newValue = xmlStrdup(oldValue);
2836 }
2837 }
2838 return newValue;
2839}
2840
2848void
2850 xmlAttrPtr prop;
2851
2852 if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2853 return;
2854 if (tree->doc != doc) {
2855 xmlDictPtr oldTreeDict = tree->doc ? tree->doc->dict : NULL;
2856 xmlDictPtr newDict = doc ? doc->dict : NULL;
2857
2858 if(tree->type == XML_ELEMENT_NODE) {
2859 prop = tree->properties;
2860 while (prop != NULL) {
2861 if (prop->atype == XML_ATTRIBUTE_ID) {
2862 xmlRemoveID(tree->doc, prop);
2863 }
2864
2865 if (prop->doc != doc) {
2866 xmlDictPtr oldPropDict = prop->doc ? prop->doc->dict : NULL;
2867 prop->name = _copyStringForNewDictIfNeeded(oldPropDict, newDict, prop->name);
2868 prop->doc = doc;
2869 }
2870 xmlSetListDoc(prop->children, doc);
2871
2872 /*
2873 * TODO: ID attributes should be also added to the new
2874 * document, but this breaks things like xmlReplaceNode.
2875 * The underlying problem is that xmlRemoveID is only called
2876 * if a node is destroyed, not if it's unlinked.
2877 */
2878#if 0
2879 if (xmlIsID(doc, tree, prop)) {
2880 xmlChar *idVal = xmlNodeListGetString(doc, prop->children,
2881 1);
2882 xmlAddID(NULL, doc, idVal, prop);
2883 }
2884#endif
2885
2886 prop = prop->next;
2887 }
2888 }
2889 if (tree->type == XML_ENTITY_REF_NODE) {
2890 /*
2891 * Clear 'children' which points to the entity declaration
2892 * from the original document.
2893 */
2894 tree->children = NULL;
2895 } else if (tree->children != NULL) {
2896 xmlSetListDoc(tree->children, doc);
2897 }
2898
2899 tree->name = _copyStringForNewDictIfNeeded(oldTreeDict, newDict, tree->name);
2900 tree->content = (xmlChar *)_copyStringForNewDictIfNeeded(oldTreeDict, NULL, tree->content);
2901 /* FIXME: tree->ns should be updated as in xmlStaticCopyNode(). */
2902 tree->doc = doc;
2903 }
2904}
2905
2913void
2916
2917 if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
2918 return;
2919 cur = list;
2920 while (cur != NULL) {
2921 if (cur->doc != doc)
2922 xmlSetTreeDoc(cur, doc);
2923 cur = cur->next;
2924 }
2925}
2926
2927#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
2946xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2947 const xmlChar *name, const xmlChar *content) {
2948 xmlNodePtr cur, prev;
2949
2950 if (parent == NULL) {
2951#ifdef DEBUG_TREE
2953 "xmlNewChild : parent == NULL\n");
2954#endif
2955 return(NULL);
2956 }
2957
2958 if (name == NULL) {
2959#ifdef DEBUG_TREE
2961 "xmlNewChild : name == NULL\n");
2962#endif
2963 return(NULL);
2964 }
2965
2966 /*
2967 * Allocate a new node
2968 */
2969 if (parent->type == XML_ELEMENT_NODE) {
2970 if (ns == NULL)
2971 cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2972 else
2974 } else if ((parent->type == XML_DOCUMENT_NODE) ||
2975 (parent->type == XML_HTML_DOCUMENT_NODE)) {
2976 if (ns == NULL)
2978 else
2980 } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2981 cur = xmlNewDocNode( parent->doc, ns, name, content);
2982 } else {
2983 return(NULL);
2984 }
2985 if (cur == NULL) return(NULL);
2986
2987 /*
2988 * add the new element at the end of the children list.
2989 */
2990 cur->type = XML_ELEMENT_NODE;
2991 cur->parent = parent;
2992 cur->doc = parent->doc;
2993 if (parent->children == NULL) {
2994 parent->children = cur;
2995 parent->last = cur;
2996 } else {
2997 prev = parent->last;
2998 prev->next = cur;
2999 cur->prev = prev;
3000 parent->last = cur;
3001 }
3002
3003 return(cur);
3004}
3005#endif /* LIBXML_TREE_ENABLED */
3006
3022static xmlNodePtr
3023xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
3025
3026 if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) ||
3027 (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) ||
3028 ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)))
3029 return(NULL);
3030
3031 /* check if an attribute with the same name exists */
3032 if (prop->ns == NULL)
3033 attr = xmlHasNsProp(cur->parent, prop->name, NULL);
3034 else
3035 attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
3036
3037 if (prop->doc != cur->doc) {
3038 xmlSetTreeDoc(prop, cur->doc);
3039 }
3040 prop->parent = cur->parent;
3041 prop->prev = prev;
3042 if (prev != NULL) {
3043 prop->next = prev->next;
3044 prev->next = prop;
3045 if (prop->next)
3046 prop->next->prev = prop;
3047 } else {
3048 prop->next = cur;
3049 cur->prev = prop;
3050 }
3051 if (prop->prev == NULL && prop->parent != NULL)
3052 prop->parent->properties = (xmlAttrPtr) prop;
3053 if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
3054 /* different instance, destroy it (attributes must be unique) */
3056 }
3057 return prop;
3058}
3059
3078 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3079#ifdef DEBUG_TREE
3081 "xmlAddNextSibling : cur == NULL\n");
3082#endif
3083 return(NULL);
3084 }
3085 if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3086#ifdef DEBUG_TREE
3088 "xmlAddNextSibling : elem == NULL\n");
3089#endif
3090 return(NULL);
3091 }
3092
3093 if (cur == elem) {
3094#ifdef DEBUG_TREE
3096 "xmlAddNextSibling : cur == elem\n");
3097#endif
3098 return(NULL);
3099 }
3100
3102
3103 if (elem->type == XML_TEXT_NODE) {
3104 if (cur->type == XML_TEXT_NODE) {
3105 xmlNodeAddContent(cur, elem->content);
3107 return(cur);
3108 }
3109 if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
3110 (cur->name == cur->next->name)) {
3111 xmlChar *tmp;
3112
3113 tmp = xmlStrdup(elem->content);
3114 tmp = xmlStrcat(tmp, cur->next->content);
3115 xmlNodeSetContent(cur->next, tmp);
3116 xmlFree(tmp);
3118 return(cur->next);
3119 }
3120 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3121 return xmlAddPropSibling(cur, cur, elem);
3122 }
3123
3124 if (elem->doc != cur->doc) {
3125 xmlSetTreeDoc(elem, cur->doc);
3126 }
3127 elem->parent = cur->parent;
3128 elem->prev = cur;
3129 elem->next = cur->next;
3130 cur->next = elem;
3131 if (elem->next != NULL)
3132 elem->next->prev = elem;
3133 if ((elem->parent != NULL) && (elem->parent->last == cur))
3134 elem->parent->last = elem;
3135 return(elem);
3136}
3137
3138#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
3139 defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
3157xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
3158 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3159#ifdef DEBUG_TREE
3161 "xmlAddPrevSibling : cur == NULL\n");
3162#endif
3163 return(NULL);
3164 }
3165 if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3166#ifdef DEBUG_TREE
3168 "xmlAddPrevSibling : elem == NULL\n");
3169#endif
3170 return(NULL);
3171 }
3172
3173 if (cur == elem) {
3174#ifdef DEBUG_TREE
3176 "xmlAddPrevSibling : cur == elem\n");
3177#endif
3178 return(NULL);
3179 }
3180
3182
3183 if (elem->type == XML_TEXT_NODE) {
3184 if (cur->type == XML_TEXT_NODE) {
3185 xmlChar *tmp;
3186
3187 tmp = xmlStrdup(elem->content);
3188 tmp = xmlStrcat(tmp, cur->content);
3189 xmlNodeSetContent(cur, tmp);
3190 xmlFree(tmp);
3192 return(cur);
3193 }
3194 if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3195 (cur->name == cur->prev->name)) {
3196 xmlNodeAddContent(cur->prev, elem->content);
3198 return(cur->prev);
3199 }
3200 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3201 return xmlAddPropSibling(cur->prev, cur, elem);
3202 }
3203
3204 if (elem->doc != cur->doc) {
3205 xmlSetTreeDoc(elem, cur->doc);
3206 }
3207 elem->parent = cur->parent;
3208 elem->next = cur;
3209 elem->prev = cur->prev;
3210 cur->prev = elem;
3211 if (elem->prev != NULL)
3212 elem->prev->next = elem;
3213 if ((elem->parent != NULL) && (elem->parent->children == cur)) {
3214 elem->parent->children = elem;
3215 }
3216 return(elem);
3217}
3218#endif /* LIBXML_TREE_ENABLED */
3219
3237
3238 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3239#ifdef DEBUG_TREE
3241 "xmlAddSibling : cur == NULL\n");
3242#endif
3243 return(NULL);
3244 }
3245
3246 if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3247#ifdef DEBUG_TREE
3249 "xmlAddSibling : elem == NULL\n");
3250#endif
3251 return(NULL);
3252 }
3253
3254 if (cur == elem) {
3255#ifdef DEBUG_TREE
3257 "xmlAddSibling : cur == elem\n");
3258#endif
3259 return(NULL);
3260 }
3261
3262 /*
3263 * Constant time is we can rely on the ->parent->last to find
3264 * the last sibling.
3265 */
3266 if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
3267 (cur->parent->children != NULL) &&
3268 (cur->parent->last != NULL) &&
3269 (cur->parent->last->next == NULL)) {
3270 cur = cur->parent->last;
3271 } else {
3272 while (cur->next != NULL) cur = cur->next;
3273 }
3274
3276
3277 if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3278 (cur->name == elem->name)) {
3279 xmlNodeAddContent(cur, elem->content);
3281 return(cur);
3282 } else if (elem->type == XML_ATTRIBUTE_NODE) {
3283 return xmlAddPropSibling(cur, cur, elem);
3284 }
3285
3286 if (elem->doc != cur->doc) {
3287 xmlSetTreeDoc(elem, cur->doc);
3288 }
3289 parent = cur->parent;
3290 elem->prev = cur;
3291 elem->next = NULL;
3292 elem->parent = parent;
3293 cur->next = elem;
3294 if (parent != NULL)
3295 parent->last = elem;
3296
3297 return(elem);
3298}
3299
3314 xmlNodePtr prev;
3315
3316 if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3317#ifdef DEBUG_TREE
3319 "xmlAddChildList : parent == NULL\n");
3320#endif
3321 return(NULL);
3322 }
3323
3324 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3325#ifdef DEBUG_TREE
3327 "xmlAddChildList : child == NULL\n");
3328#endif
3329 return(NULL);
3330 }
3331
3332 if ((cur->doc != NULL) && (parent->doc != NULL) &&
3333 (cur->doc != parent->doc)) {
3334#ifdef DEBUG_TREE
3336 "Elements moved to a different document\n");
3337#endif
3338 }
3339
3340 /*
3341 * add the first element at the end of the children list.
3342 */
3343
3344 if (parent->children == NULL) {
3345 parent->children = cur;
3346 } else {
3347 /*
3348 * If cur and parent->last both are TEXT nodes, then merge them.
3349 */
3350 if ((cur->type == XML_TEXT_NODE) &&
3351 (parent->last->type == XML_TEXT_NODE) &&
3352 (cur->name == parent->last->name)) {
3353 xmlNodeAddContent(parent->last, cur->content);
3354 /*
3355 * if it's the only child, nothing more to be done.
3356 */
3357 if (cur->next == NULL) {
3359 return(parent->last);
3360 }
3361 prev = cur;
3362 cur = cur->next;
3363 xmlFreeNode(prev);
3364 }
3365 prev = parent->last;
3366 prev->next = cur;
3367 cur->prev = prev;
3368 }
3369 while (cur->next != NULL) {
3370 cur->parent = parent;
3371 if (cur->doc != parent->doc) {
3372 xmlSetTreeDoc(cur, parent->doc);
3373 }
3374 cur = cur->next;
3375 }
3376 cur->parent = parent;
3377 /* the parent may not be linked to a doc ! */
3378 if (cur->doc != parent->doc) {
3379 xmlSetTreeDoc(cur, parent->doc);
3380 }
3381 parent->last = cur;
3382
3383 return(cur);
3384}
3385
3406 xmlNodePtr prev;
3407
3408 if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3409#ifdef DEBUG_TREE
3411 "xmlAddChild : parent == NULL\n");
3412#endif
3413 return(NULL);
3414 }
3415
3416 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3417#ifdef DEBUG_TREE
3419 "xmlAddChild : child == NULL\n");
3420#endif
3421 return(NULL);
3422 }
3423
3424 if (parent == cur) {
3425#ifdef DEBUG_TREE
3427 "xmlAddChild : parent == cur\n");
3428#endif
3429 return(NULL);
3430 }
3431 /*
3432 * If cur is a TEXT node, merge its content with adjacent TEXT nodes
3433 * cur is then freed.
3434 */
3435 if (cur->type == XML_TEXT_NODE) {
3436 if ((parent->type == XML_TEXT_NODE) &&
3437 (parent->content != NULL) &&
3438 (parent->name == cur->name)) {
3439 xmlNodeAddContent(parent, cur->content);
3441 return(parent);
3442 }
3443 if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
3444 (parent->last->name == cur->name) &&
3445 (parent->last != cur)) {
3446 xmlNodeAddContent(parent->last, cur->content);
3448 return(parent->last);
3449 }
3450 }
3451
3452 /*
3453 * add the new element at the end of the children list.
3454 */
3455 prev = cur->parent;
3456 cur->parent = parent;
3457 if (cur->doc != parent->doc) {
3458 xmlSetTreeDoc(cur, parent->doc);
3459 }
3460 /* this check prevents a loop on tree-traversions if a developer
3461 * tries to add a node to its parent multiple times
3462 */
3463 if (prev == parent)
3464 return(cur);
3465
3466 /*
3467 * Coalescing
3468 */
3469 if ((parent->type == XML_TEXT_NODE) &&
3470 (parent->content != NULL) &&
3471 (parent != cur)) {
3472 xmlNodeAddContent(parent, cur->content);
3474 return(parent);
3475 }
3476 if (cur->type == XML_ATTRIBUTE_NODE) {
3477 if (parent->type != XML_ELEMENT_NODE)
3478 return(NULL);
3479 if (parent->properties != NULL) {
3480 /* check if an attribute with the same name exists */
3481 xmlAttrPtr lastattr;
3482
3483 if (cur->ns == NULL)
3484 lastattr = xmlHasNsProp(parent, cur->name, NULL);
3485 else
3486 lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3487 if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
3488 /* different instance, destroy it (attributes must be unique) */
3489 xmlUnlinkNode((xmlNodePtr) lastattr);
3490 xmlFreeProp(lastattr);
3491 }
3492 if (lastattr == (xmlAttrPtr) cur)
3493 return(cur);
3494
3495 }
3496 if (parent->properties == NULL) {
3497 parent->properties = (xmlAttrPtr) cur;
3498 } else {
3499 /* find the end */
3500 xmlAttrPtr lastattr = parent->properties;
3501 while (lastattr->next != NULL) {
3502 lastattr = lastattr->next;
3503 }
3504 lastattr->next = (xmlAttrPtr) cur;
3505 ((xmlAttrPtr) cur)->prev = lastattr;
3506 }
3507 } else {
3508 if (parent->children == NULL) {
3509 parent->children = cur;
3510 parent->last = cur;
3511 } else {
3512 prev = parent->last;
3513 prev->next = cur;
3514 cur->prev = prev;
3515 parent->last = cur;
3516 }
3517 }
3518 return(cur);
3519}
3520
3530 if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3531#ifdef DEBUG_TREE
3533 "xmlGetLastChild : parent == NULL\n");
3534#endif
3535 return(NULL);
3536 }
3537 return(parent->last);
3538}
3539
3540#ifdef LIBXML_TREE_ENABLED
3541/*
3542 * 5 interfaces from DOM ElementTraversal
3543 */
3544
3557unsigned long
3558xmlChildElementCount(xmlNodePtr parent) {
3559 unsigned long ret = 0;
3561
3562 if (parent == NULL)
3563 return(0);
3564 switch (parent->type) {
3565 case XML_ELEMENT_NODE:
3566 case XML_ENTITY_NODE:
3567 case XML_DOCUMENT_NODE:
3570 cur = parent->children;
3571 break;
3572 default:
3573 return(0);
3574 }
3575 while (cur != NULL) {
3576 if (cur->type == XML_ELEMENT_NODE)
3577 ret++;
3578 cur = cur->next;
3579 }
3580 return(ret);
3581}
3582
3595xmlFirstElementChild(xmlNodePtr parent) {
3597
3598 if (parent == NULL)
3599 return(NULL);
3600 switch (parent->type) {
3601 case XML_ELEMENT_NODE:
3602 case XML_ENTITY_NODE:
3603 case XML_DOCUMENT_NODE:
3606 cur = parent->children;
3607 break;
3608 default:
3609 return(NULL);
3610 }
3611 while (cur != NULL) {
3612 if (cur->type == XML_ELEMENT_NODE)
3613 return(cur);
3614 cur = cur->next;
3615 }
3616 return(NULL);
3617}
3618
3631xmlLastElementChild(xmlNodePtr parent) {
3633
3634 if (parent == NULL)
3635 return(NULL);
3636 switch (parent->type) {
3637 case XML_ELEMENT_NODE:
3638 case XML_ENTITY_NODE:
3639 case XML_DOCUMENT_NODE:
3642 cur = parent->last;
3643 break;
3644 default:
3645 return(NULL);
3646 }
3647 while (cur != NULL) {
3648 if (cur->type == XML_ELEMENT_NODE)
3649 return(cur);
3650 cur = cur->prev;
3651 }
3652 return(NULL);
3653}
3654
3668xmlPreviousElementSibling(xmlNodePtr node) {
3669 if (node == NULL)
3670 return(NULL);
3671 switch (node->type) {
3672 case XML_ELEMENT_NODE:
3673 case XML_TEXT_NODE:
3676 case XML_ENTITY_NODE:
3677 case XML_PI_NODE:
3678 case XML_COMMENT_NODE:
3679 case XML_XINCLUDE_START:
3680 case XML_XINCLUDE_END:
3681 node = node->prev;
3682 break;
3683 default:
3684 return(NULL);
3685 }
3686 while (node != NULL) {
3687 if (node->type == XML_ELEMENT_NODE)
3688 return(node);
3689 node = node->prev;
3690 }
3691 return(NULL);
3692}
3693
3707xmlNextElementSibling(xmlNodePtr node) {
3708 if (node == NULL)
3709 return(NULL);
3710 switch (node->type) {
3711 case XML_ELEMENT_NODE:
3712 case XML_TEXT_NODE:
3715 case XML_ENTITY_NODE:
3716 case XML_PI_NODE:
3717 case XML_COMMENT_NODE:
3718 case XML_DTD_NODE:
3719 case XML_XINCLUDE_START:
3720 case XML_XINCLUDE_END:
3721 node = node->next;
3722 break;
3723 default:
3724 return(NULL);
3725 }
3726 while (node != NULL) {
3727 if (node->type == XML_ELEMENT_NODE)
3728 return(node);
3729 node = node->next;
3730 }
3731 return(NULL);
3732}
3733
3734#endif /* LIBXML_TREE_ENABLED */
3735
3743void
3747 xmlDictPtr dict = NULL;
3748 size_t depth = 0;
3749
3750 if (cur == NULL) return;
3751 if (cur->type == XML_NAMESPACE_DECL) {
3753 return;
3754 }
3755 if (cur->doc != NULL) dict = cur->doc->dict;
3756 while (1) {
3757 while ((cur->children != NULL) &&
3758 (cur->type != XML_DOCUMENT_NODE) &&
3759 (cur->type != XML_HTML_DOCUMENT_NODE) &&
3760 (cur->type != XML_DTD_NODE) &&
3761 (cur->type != XML_ENTITY_REF_NODE)) {
3762 cur = cur->children;
3763 depth += 1;
3764 }
3765
3766 next = cur->next;
3767 parent = cur->parent;
3768 if ((cur->type == XML_DOCUMENT_NODE) ||
3769 (cur->type == XML_HTML_DOCUMENT_NODE)) {
3771 } else if (cur->type != XML_DTD_NODE) {
3772
3775
3776 if (((cur->type == XML_ELEMENT_NODE) ||
3777 (cur->type == XML_XINCLUDE_START) ||
3778 (cur->type == XML_XINCLUDE_END)) &&
3779 (cur->properties != NULL))
3780 xmlFreePropList(cur->properties);
3781 if ((cur->type != XML_ELEMENT_NODE) &&
3782 (cur->type != XML_XINCLUDE_START) &&
3783 (cur->type != XML_XINCLUDE_END) &&
3784 (cur->type != XML_ENTITY_REF_NODE) &&
3785 (cur->content != (xmlChar *) &(cur->properties))) {
3786 DICT_FREE(cur->content)
3787 }
3788 if (((cur->type == XML_ELEMENT_NODE) ||
3789 (cur->type == XML_XINCLUDE_START) ||
3790 (cur->type == XML_XINCLUDE_END)) &&
3791 (cur->nsDef != NULL))
3792 xmlFreeNsList(cur->nsDef);
3793
3794 /*
3795 * When a node is a text node or a comment, it uses a global static
3796 * variable for the name of the node.
3797 * Otherwise the node name might come from the document's
3798 * dictionary
3799 */
3800 if ((cur->name != NULL) &&
3801 (cur->type != XML_TEXT_NODE) &&
3802 (cur->type != XML_COMMENT_NODE))
3803 DICT_FREE(cur->name)
3804 xmlFree(cur);
3805 }
3806
3807 if (next != NULL) {
3808 cur = next;
3809 } else {
3810 if ((depth == 0) || (parent == NULL))
3811 break;
3812 depth -= 1;
3813 cur = parent;
3814 cur->children = NULL;
3815 }
3816 }
3817}
3818
3826void
3828 xmlDictPtr dict = NULL;
3829
3830 if (cur == NULL) return;
3831
3832 /* use xmlFreeDtd for DTD nodes */
3833 if (cur->type == XML_DTD_NODE) {
3835 return;
3836 }
3837 if (cur->type == XML_NAMESPACE_DECL) {
3839 return;
3840 }
3841 if (cur->type == XML_ATTRIBUTE_NODE) {
3843 return;
3844 }
3845
3848
3849 if (cur->doc != NULL) dict = cur->doc->dict;
3850
3851 if (cur->type == XML_ENTITY_DECL) {
3853 DICT_FREE(ent->SystemID);
3854 DICT_FREE(ent->ExternalID);
3855 }
3856 if ((cur->children != NULL) &&
3857 (cur->type != XML_ENTITY_REF_NODE))
3858 xmlFreeNodeList(cur->children);
3859
3860 if ((cur->type == XML_ELEMENT_NODE) ||
3861 (cur->type == XML_XINCLUDE_START) ||
3862 (cur->type == XML_XINCLUDE_END)) {
3863 if (cur->properties != NULL)
3864 xmlFreePropList(cur->properties);
3865 if (cur->nsDef != NULL)
3866 xmlFreeNsList(cur->nsDef);
3867 } else if ((cur->content != NULL) &&
3868 (cur->type != XML_ENTITY_REF_NODE) &&
3869 (cur->content != (xmlChar *) &(cur->properties))) {
3870 DICT_FREE(cur->content)
3871 }
3872
3873 /*
3874 * When a node is a text node or a comment, it uses a global static
3875 * variable for the name of the node.
3876 * Otherwise the node name might come from the document's dictionary
3877 */
3878 if ((cur->name != NULL) &&
3879 (cur->type != XML_TEXT_NODE) &&
3880 (cur->type != XML_COMMENT_NODE))
3881 DICT_FREE(cur->name)
3882
3883 xmlFree(cur);
3884}
3885
3896void
3898 if (cur == NULL) {
3899#ifdef DEBUG_TREE
3901 "xmlUnlinkNode : node == NULL\n");
3902#endif
3903 return;
3904 }
3905 if (cur->type == XML_NAMESPACE_DECL)
3906 return;
3907 if (cur->type == XML_DTD_NODE) {
3908 xmlDocPtr doc;
3909 doc = cur->doc;
3910 if (doc != NULL) {
3911 if (doc->intSubset == (xmlDtdPtr) cur)
3912 doc->intSubset = NULL;
3913 if (doc->extSubset == (xmlDtdPtr) cur)
3914 doc->extSubset = NULL;
3915 }
3916 }
3917 if (cur->type == XML_ENTITY_DECL) {
3918 xmlDocPtr doc;
3919 doc = cur->doc;
3920 if (doc != NULL) {
3921 if (doc->intSubset != NULL) {
3922 if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3923 xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3924 NULL);
3925 if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3926 xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3927 NULL);
3928 }
3929 if (doc->extSubset != NULL) {
3930 if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3931 xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3932 NULL);
3933 if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3934 xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3935 NULL);
3936 }
3937 }
3938 }
3939 if (cur->parent != NULL) {
3941 parent = cur->parent;
3942 if (cur->type == XML_ATTRIBUTE_NODE) {
3943 if (parent->properties == (xmlAttrPtr) cur)
3944 parent->properties = ((xmlAttrPtr) cur)->next;
3945 } else {
3946 if (parent->children == cur)
3947 parent->children = cur->next;
3948 if (parent->last == cur)
3949 parent->last = cur->prev;
3950 }
3951 cur->parent = NULL;
3952 }
3953 if (cur->next != NULL)
3954 cur->next->prev = cur->prev;
3955 if (cur->prev != NULL)
3956 cur->prev->next = cur->next;
3957 cur->next = cur->prev = NULL;
3958}
3959
3960#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
3975xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3976 if (old == cur) return(NULL);
3977 if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) ||
3978 (old->parent == NULL)) {
3979#ifdef DEBUG_TREE
3981 "xmlReplaceNode : old == NULL or without parent\n");
3982#endif
3983 return(NULL);
3984 }
3985 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3986 xmlUnlinkNode(old);
3987 return(old);
3988 }
3989 if (cur == old) {
3990 return(old);
3991 }
3992 if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3993#ifdef DEBUG_TREE
3995 "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3996#endif
3997 return(old);
3998 }
3999 if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
4000#ifdef DEBUG_TREE
4002 "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
4003#endif
4004 return(old);
4005 }
4007 xmlSetTreeDoc(cur, old->doc);
4008 cur->parent = old->parent;
4009 cur->next = old->next;
4010 if (cur->next != NULL)
4011 cur->next->prev = cur;
4012 cur->prev = old->prev;
4013 if (cur->prev != NULL)
4014 cur->prev->next = cur;
4015 if (cur->parent != NULL) {
4016 if (cur->type == XML_ATTRIBUTE_NODE) {
4017 if (cur->parent->properties == (xmlAttrPtr)old)
4018 cur->parent->properties = ((xmlAttrPtr) cur);
4019 } else {
4020 if (cur->parent->children == old)
4021 cur->parent->children = cur;
4022 if (cur->parent->last == old)
4023 cur->parent->last = cur;
4024 }
4025 }
4026 old->next = old->prev = NULL;
4027 old->parent = NULL;
4028 return(old);
4029}
4030#endif /* LIBXML_TREE_ENABLED */
4031
4032/************************************************************************
4033 * *
4034 * Copy operations *
4035 * *
4036 ************************************************************************/
4037
4048 xmlNsPtr ret;
4049
4050 if (cur == NULL) return(NULL);
4051 switch (cur->type) {
4053 ret = xmlNewNs(NULL, cur->href, cur->prefix);
4054 break;
4055 default:
4056#ifdef DEBUG_TREE
4058 "xmlCopyNamespace: invalid type %d\n", cur->type);
4059#endif
4060 return(NULL);
4061 }
4062 return(ret);
4063}
4064
4075 xmlNsPtr ret = NULL;
4076 xmlNsPtr p = NULL,q;
4077
4078 while (cur != NULL) {
4080 if (p == NULL) {
4081 ret = p = q;
4082 } else {
4083 p->next = q;
4084 p = q;
4085 }
4086 cur = cur->next;
4087 }
4088 return(ret);
4089}
4090
4091static xmlNodePtr
4092xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
4093
4094static xmlAttrPtr
4095xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
4097
4098 if (cur == NULL) return(NULL);
4099 if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4100 return(NULL);
4101 if (target != NULL)
4102 ret = xmlNewDocProp(target->doc, cur->name, NULL);
4103 else if (doc != NULL)
4104 ret = xmlNewDocProp(doc, cur->name, NULL);
4105 else if (cur->parent != NULL)
4106 ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
4107 else if (cur->children != NULL)
4108 ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
4109 else
4110 ret = xmlNewDocProp(NULL, cur->name, NULL);
4111 if (ret == NULL) return(NULL);
4112 ret->parent = target;
4113
4114 if ((cur->ns != NULL) && (target != NULL)) {
4115 xmlNsPtr ns;
4116
4117 ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
4118 if (ns == NULL) {
4119 /*
4120 * Humm, we are copying an element whose namespace is defined
4121 * out of the new tree scope. Search it in the original tree
4122 * and add it at the top of the new tree
4123 */
4124 ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
4125 if (ns != NULL) {
4127 xmlNodePtr pred = NULL;
4128
4129 while (root->parent != NULL) {
4130 pred = root;
4131 root = root->parent;
4132 }
4133 if (root == (xmlNodePtr) target->doc) {
4134 /* correct possibly cycling above the document elt */
4135 root = pred;
4136 }
4137 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4138 }
4139 } else {
4140 /*
4141 * we have to find something appropriate here since
4142 * we can't be sure, that the namespace we found is identified
4143 * by the prefix
4144 */
4145 if (xmlStrEqual(ns->href, cur->ns->href)) {
4146 /* this is the nice case */
4147 ret->ns = ns;
4148 } else {
4149 /*
4150 * we are in trouble: we need a new reconciled namespace.
4151 * This is expensive
4152 */
4153 ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns);
4154 }
4155 }
4156
4157 } else
4158 ret->ns = NULL;
4159
4160 if (cur->children != NULL) {
4161 xmlNodePtr tmp;
4162
4163 ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4164 ret->last = NULL;
4165 tmp = ret->children;
4166 while (tmp != NULL) {
4167 /* tmp->parent = (xmlNodePtr)ret; */
4168 if (tmp->next == NULL)
4169 ret->last = tmp;
4170 tmp = tmp->next;
4171 }
4172 }
4173 /*
4174 * Try to handle IDs
4175 */
4176 if ((target!= NULL) && (cur!= NULL) &&
4177 (target->doc != NULL) && (cur->doc != NULL) &&
4178 (cur->doc->ids != NULL) && (cur->parent != NULL)) {
4179 if (xmlIsID(cur->doc, cur->parent, cur)) {
4180 xmlChar *id;
4181
4182 id = xmlNodeListGetString(cur->doc, cur->children, 1);
4183 if (id != NULL) {
4184 xmlAddID(NULL, target->doc, id, ret);
4185 xmlFree(id);
4186 }
4187 }
4188 }
4189 return(ret);
4190}
4191
4203 return xmlCopyPropInternal(NULL, target, cur);
4204}
4205
4218 xmlAttrPtr p = NULL,q;
4219
4220 if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4221 return(NULL);
4222 while (cur != NULL) {
4223 q = xmlCopyProp(target, cur);
4224 if (q == NULL)
4225 return(NULL);
4226 if (p == NULL) {
4227 ret = p = q;
4228 } else {
4229 p->next = q;
4230 q->prev = p;
4231 p = q;
4232 }
4233 cur = cur->next;
4234 }
4235 return(ret);
4236}
4237
4238/*
4239 * NOTE about the CopyNode operations !
4240 *
4241 * They are split into external and internal parts for one
4242 * tricky reason: namespaces. Doing a direct copy of a node
4243 * say RPM:Copyright without changing the namespace pointer to
4244 * something else can produce stale links. One way to do it is
4245 * to keep a reference counter but this doesn't work as soon
4246 * as one moves the element or the subtree out of the scope of
4247 * the existing namespace. The actual solution seems to be to add
4248 * a copy of the namespace at the top of the copied tree if
4249 * not available in the subtree.
4250 * Hence two functions, the public front-end call the inner ones
4251 * The argument "recursive" normally indicates a recursive copy
4252 * of the node with values 0 (no) and 1 (yes). For XInclude,
4253 * however, we allow a value of 2 to indicate copy properties and
4254 * namespace info, but don't recurse on children.
4255 */
4256
4257static xmlNodePtr
4258xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
4259 int extended) {
4261
4262 if (node == NULL) return(NULL);
4263 switch (node->type) {
4264 case XML_TEXT_NODE:
4266 case XML_ELEMENT_NODE:
4269 case XML_ENTITY_NODE:
4270 case XML_PI_NODE:
4271 case XML_COMMENT_NODE:
4272 case XML_XINCLUDE_START:
4273 case XML_XINCLUDE_END:
4274 break;
4275 case XML_ATTRIBUTE_NODE:
4276 return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
4277 case XML_NAMESPACE_DECL:
4279
4280 case XML_DOCUMENT_NODE:
4282#ifdef LIBXML_TREE_ENABLED
4283 return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
4284#endif /* LIBXML_TREE_ENABLED */
4286 case XML_NOTATION_NODE:
4287 case XML_DTD_NODE:
4288 case XML_ELEMENT_DECL:
4289 case XML_ATTRIBUTE_DECL:
4290 case XML_ENTITY_DECL:
4291 return(NULL);
4292 }
4293
4294 /*
4295 * Allocate a new node and fill the fields.
4296 */
4297 ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4298 if (ret == NULL) {
4299 xmlTreeErrMemory("copying node");
4300 return(NULL);
4301 }
4302 memset(ret, 0, sizeof(xmlNode));
4303 ret->type = node->type;
4304
4305 ret->doc = doc;
4306 ret->parent = parent;
4307 if (node->name == xmlStringText)
4308 ret->name = xmlStringText;
4309 else if (node->name == xmlStringTextNoenc)
4310 ret->name = xmlStringTextNoenc;
4311 else if (node->name == xmlStringComment)
4312 ret->name = xmlStringComment;
4313 else if (node->name != NULL) {
4314 if ((doc != NULL) && (doc->dict != NULL))
4315 ret->name = xmlDictLookup(doc->dict, node->name, -1);
4316 else
4317 ret->name = xmlStrdup(node->name);
4318 }
4319 if ((node->type != XML_ELEMENT_NODE) &&
4320 (node->content != NULL) &&
4321 (node->type != XML_ENTITY_REF_NODE) &&
4322 (node->type != XML_XINCLUDE_END) &&
4323 (node->type != XML_XINCLUDE_START)) {
4324 ret->content = xmlStrdup(node->content);
4325 }else{
4326 if (node->type == XML_ELEMENT_NODE)
4327 ret->line = node->line;
4328 }
4329 if (parent != NULL) {
4330 xmlNodePtr tmp;
4331
4332 /*
4333 * this is a tricky part for the node register thing:
4334 * in case ret does get coalesced in xmlAddChild
4335 * the deregister-node callback is called; so we register ret now already
4336 */
4339
4340 /*
4341 * Note that since ret->parent is already set, xmlAddChild will
4342 * return early and not actually insert the node. It will only
4343 * coalesce text nodes and unnecessarily call xmlSetTreeDoc.
4344 * Assuming that the subtree to be copied always has its text
4345 * nodes coalesced, the somewhat confusing call to xmlAddChild
4346 * could be removed.
4347 */
4348 tmp = xmlAddChild(parent, ret);
4349 /* node could have coalesced */
4350 if (tmp != ret)
4351 return(tmp);
4352 }
4353
4354 if (!extended)
4355 goto out;
4356 if (((node->type == XML_ELEMENT_NODE) ||
4357 (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
4358 ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4359
4360 if (node->ns != NULL) {
4361 xmlNsPtr ns;
4362
4363 ns = xmlSearchNs(doc, ret, node->ns->prefix);
4364 if (ns == NULL) {
4365 /*
4366 * Humm, we are copying an element whose namespace is defined
4367 * out of the new tree scope. Search it in the original tree
4368 * and add it at the top of the new tree
4369 */
4370 ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4371 if (ns != NULL) {
4373
4374 while (root->parent != NULL) root = root->parent;
4375 ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4376 } else {
4377 ret->ns = xmlNewReconciledNs(doc, ret, node->ns);
4378 }
4379 } else {
4380 /*
4381 * reference the existing namespace definition in our own tree.
4382 */
4383 ret->ns = ns;
4384 }
4385 }
4386 if (((node->type == XML_ELEMENT_NODE) ||
4387 (node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
4388 ret->properties = xmlCopyPropList(ret, node->properties);
4389 if (node->type == XML_ENTITY_REF_NODE) {
4390 if ((doc == NULL) || (node->doc != doc)) {
4391 /*
4392 * The copied node will go into a separate document, so
4393 * to avoid dangling references to the ENTITY_DECL node
4394 * we cannot keep the reference. Try to find it in the
4395 * target document.
4396 */
4397 ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4398 } else {
4399 ret->children = node->children;
4400 }
4401 ret->last = ret->children;
4402 } else if ((node->children != NULL) && (extended != 2)) {
4404
4405 cur = node->children;
4406 insert = ret;
4407 while (cur != NULL) {
4408 xmlNodePtr copy = xmlStaticCopyNode(cur, doc, insert, 2);
4409 if (copy == NULL) {
4411 return(NULL);
4412 }
4413
4414 /* Check for coalesced text nodes */
4415 if (insert->last != copy) {
4416 if (insert->last == NULL) {
4417 insert->children = copy;
4418 } else {
4419 copy->prev = insert->last;
4420 insert->last->next = copy;
4421 }
4422 insert->last = copy;
4423 }
4424
4425 if ((cur->type != XML_ENTITY_REF_NODE) &&
4426 (cur->children != NULL)) {
4427 cur = cur->children;
4428 insert = copy;
4429 continue;
4430 }
4431
4432 while (1) {
4433 if (cur->next != NULL) {
4434 cur = cur->next;
4435 break;
4436 }
4437
4438 cur = cur->parent;
4439 insert = insert->parent;
4440 if (cur == node) {
4441 cur = NULL;
4442 break;
4443 }
4444 }
4445 }
4446 }
4447
4448out:
4449 /* if parent != NULL we already registered the node above */
4450 if ((parent == NULL) &&
4453 return(ret);
4454}
4455
4456static xmlNodePtr
4457xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4459 xmlNodePtr p = NULL,q;
4460
4461 while (node != NULL) {
4462#ifdef LIBXML_TREE_ENABLED
4463 if (node->type == XML_DTD_NODE ) {
4464 if (doc == NULL) {
4465 node = node->next;
4466 continue;
4467 }
4468 if (doc->intSubset == NULL) {
4469 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4470 if (q == NULL) return(NULL);
4471 q->doc = doc;
4472 q->parent = parent;
4473 doc->intSubset = (xmlDtdPtr) q;
4475 } else {
4476 q = (xmlNodePtr) doc->intSubset;
4478 }
4479 } else
4480#endif /* LIBXML_TREE_ENABLED */
4481 q = xmlStaticCopyNode(node, doc, parent, 1);
4482 if (q == NULL) return(NULL);
4483 if (ret == NULL) {
4484 q->prev = NULL;
4485 ret = p = q;
4486 } else if (p != q) {
4487 /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
4488 p->next = q;
4489 q->prev = p;
4490 p = q;
4491 }
4492 node = node->next;
4493 }
4494 return(ret);
4495}
4496
4509xmlCopyNode(xmlNodePtr node, int extended) {
4511
4512 ret = xmlStaticCopyNode(node, NULL, NULL, extended);
4513 return(ret);
4514}
4515
4529xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
4531
4532 ret = xmlStaticCopyNode(node, doc, NULL, extended);
4533 return(ret);
4534}
4535
4546 xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4547 return(ret);
4548}
4549
4560 xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4561 return(ret);
4562}
4563
4564#if defined(LIBXML_TREE_ENABLED)
4574xmlCopyDtd(xmlDtdPtr dtd) {
4575 xmlDtdPtr ret;
4576 xmlNodePtr cur, p = NULL, q;
4577
4578 if (dtd == NULL) return(NULL);
4579 ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4580 if (ret == NULL) return(NULL);
4581 if (dtd->entities != NULL)
4582 ret->entities = (void *) xmlCopyEntitiesTable(
4584 if (dtd->notations != NULL)
4585 ret->notations = (void *) xmlCopyNotationTable(
4587 if (dtd->elements != NULL)
4588 ret->elements = (void *) xmlCopyElementTable(
4590 if (dtd->attributes != NULL)
4591 ret->attributes = (void *) xmlCopyAttributeTable(
4593 if (dtd->pentities != NULL)
4594 ret->pentities = (void *) xmlCopyEntitiesTable(
4596
4597 cur = dtd->children;
4598 while (cur != NULL) {
4599 q = NULL;
4600
4601 if (cur->type == XML_ENTITY_DECL) {
4603 switch (tmp->etype) {
4607 q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4608 break;
4611 q = (xmlNodePtr)
4612 xmlGetParameterEntityFromDtd(ret, tmp->name);
4613 break;
4615 break;
4616 }
4617 } else if (cur->type == XML_ELEMENT_DECL) {
4619 q = (xmlNodePtr)
4620 xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4621 } else if (cur->type == XML_ATTRIBUTE_DECL) {
4623 q = (xmlNodePtr)
4624 xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4625 } else if (cur->type == XML_COMMENT_NODE) {
4626 q = xmlCopyNode(cur, 0);
4627 }
4628
4629 if (q == NULL) {
4630 cur = cur->next;
4631 continue;
4632 }
4633
4634 if (p == NULL)
4635 ret->children = q;
4636 else
4637 p->next = q;
4638
4639 q->prev = p;
4640 q->parent = (xmlNodePtr) ret;
4641 q->next = NULL;
4642 ret->last = q;
4643 p = q;
4644 cur = cur->next;
4645 }
4646
4647 return(ret);
4648}
4649#endif
4650
4651#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
4663xmlCopyDoc(xmlDocPtr doc, int recursive) {
4664 xmlDocPtr ret;
4665
4666 if (doc == NULL) return(NULL);
4667 ret = xmlNewDoc(doc->version);
4668 if (ret == NULL) return(NULL);
4669 ret->type = doc->type;
4670 if (doc->name != NULL)
4671 ret->name = xmlMemStrdup(doc->name);
4672 if (doc->encoding != NULL)
4673 ret->encoding = xmlStrdup(doc->encoding);
4674 if (doc->URL != NULL)
4675 ret->URL = xmlStrdup(doc->URL);
4676 ret->charset = doc->charset;
4677 ret->compression = doc->compression;