ReactOS  0.4.15-dev-3187-ge372f2b
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 #ifdef HAVE_CTYPE_H
25 #include <ctype.h>
26 #endif
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30 #ifdef LIBXML_ZLIB_ENABLED
31 #include <zlib.h>
32 #endif
33 
34 #include <libxml/xmlmemory.h>
35 #include <libxml/tree.h>
36 #include <libxml/parser.h>
37 #include <libxml/uri.h>
38 #include <libxml/entities.h>
39 #include <libxml/valid.h>
40 #include <libxml/xmlerror.h>
41 #include <libxml/parserInternals.h>
42 #include <libxml/globals.h>
43 #ifdef LIBXML_HTML_ENABLED
44 #include <libxml/HTMLtree.h>
45 #endif
46 #ifdef LIBXML_DEBUG_ENABLED
47 #include <libxml/debugXML.h>
48 #endif
49 
50 #include "buf.h"
51 #include "save.h"
52 
54 
55 /************************************************************************
56  * *
57  * Forward declarations *
58  * *
59  ************************************************************************/
60 
61 static xmlNsPtr
63 
64 static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
65 
66 /************************************************************************
67  * *
68  * Tree memory error handler *
69  * *
70  ************************************************************************/
77 static void
78 xmlTreeErrMemory(const char *extra)
79 {
80  __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
81 }
82 
90 static void
91 xmlTreeErr(int code, xmlNodePtr node, const char *extra)
92 {
93  const char *msg = NULL;
94 
95  switch(code) {
97  msg = "invalid hexadecimal character value\n";
98  break;
100  msg = "invalid decimal character value\n";
101  break;
103  msg = "unterminated entity reference %15s\n";
104  break;
105  case XML_TREE_NOT_UTF8:
106  msg = "string is not in UTF-8\n";
107  break;
108  default:
109  msg = "unexpected error number\n";
110  }
111  __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra);
112 }
113 
114 /************************************************************************
115  * *
116  * A few static variables and macros *
117  * *
118  ************************************************************************/
119 /* #undef xmlStringText */
120 const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
121 /* #undef xmlStringTextNoenc */
122 const xmlChar xmlStringTextNoenc[] =
123  { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
124 /* #undef xmlStringComment */
125 const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
126 
127 static int xmlCompressMode = 0;
128 static int xmlCheckDTD = 1;
129 
130 #define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \
131  xmlNodePtr ulccur = (n)->children; \
132  if (ulccur == NULL) { \
133  (n)->last = NULL; \
134  } else { \
135  while (ulccur->next != NULL) { \
136  ulccur->parent = (n); \
137  ulccur = ulccur->next; \
138  } \
139  ulccur->parent = (n); \
140  (n)->last = ulccur; \
141 }}
142 
143 #define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
144  (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
145 
146 /* #define DEBUG_BUFFER */
147 /* #define DEBUG_TREE */
148 
149 /************************************************************************
150  * *
151  * Functions to move to entities.c once the *
152  * API freeze is smoothen and they can be made public. *
153  * *
154  ************************************************************************/
155 #include <libxml/hash.h>
156 
157 #ifdef LIBXML_TREE_ENABLED
158 
168 static xmlEntityPtr
169 xmlGetEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
171 
172  if((dtd != NULL) && (dtd->entities != NULL)) {
174  return((xmlEntityPtr) xmlHashLookup(table, name));
175  /* return(xmlGetEntityFromTable(table, name)); */
176  }
177  return(NULL);
178 }
189 static xmlEntityPtr
190 xmlGetParameterEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
192 
193  if ((dtd != NULL) && (dtd->pentities != NULL)) {
195  return((xmlEntityPtr) xmlHashLookup(table, name));
196  /* return(xmlGetEntityFromTable(table, name)); */
197  }
198  return(NULL);
199 }
200 #endif /* LIBXML_TREE_ENABLED */
201 
202 /************************************************************************
203  * *
204  * QName handling helper *
205  * *
206  ************************************************************************/
207 
222 xmlChar *
223 xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
224  xmlChar *memory, int len) {
225  int lenn, lenp;
226  xmlChar *ret;
227 
228  if (ncname == NULL) return(NULL);
229  if (prefix == NULL) return((xmlChar *) ncname);
230 
231  lenn = strlen((char *) ncname);
232  lenp = strlen((char *) prefix);
233 
234  if ((memory == NULL) || (len < lenn + lenp + 2)) {
235  ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
236  if (ret == NULL) {
237  xmlTreeErrMemory("building QName");
238  return(NULL);
239  }
240  } else {
241  ret = memory;
242  }
243  memcpy(&ret[0], prefix, lenp);
244  ret[lenp] = ':';
245  memcpy(&ret[lenp + 1], ncname, lenn);
246  ret[lenn + lenp + 1] = 0;
247  return(ret);
248 }
249 
267 xmlChar *
268 xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
269  int len = 0;
270  xmlChar *ret = NULL;
271 
272  if (prefix == NULL) return(NULL);
273  *prefix = NULL;
274  if (name == NULL) return(NULL);
275 
276 #ifndef XML_XML_NAMESPACE
277  /* xml: prefix is not really a namespace */
278  if ((name[0] == 'x') && (name[1] == 'm') &&
279  (name[2] == 'l') && (name[3] == ':'))
280  return(NULL);
281 #endif
282 
283  /* nasty but valid */
284  if (name[0] == ':')
285  return(NULL);
286 
287  /*
288  * we are not trying to validate but just to cut, and yes it will
289  * work even if this is as set of UTF-8 encoded chars
290  */
291  while ((name[len] != 0) && (name[len] != ':'))
292  len++;
293 
294  if (name[len] == 0)
295  return(NULL);
296 
297  *prefix = xmlStrndup(name, len);
298  if (*prefix == NULL) {
299  xmlTreeErrMemory("QName split");
300  return(NULL);
301  }
302  ret = xmlStrdup(&name[len + 1]);
303  if (ret == NULL) {
304  xmlTreeErrMemory("QName split");
305  if (*prefix != NULL) {
306  xmlFree(*prefix);
307  *prefix = NULL;
308  }
309  return(NULL);
310  }
311 
312  return(ret);
313 }
314 
327 const xmlChar *
328 xmlSplitQName3(const xmlChar *name, int *len) {
329  int l = 0;
330 
331  if (name == NULL) return(NULL);
332  if (len == NULL) return(NULL);
333 
334  /* nasty but valid */
335  if (name[0] == ':')
336  return(NULL);
337 
338  /*
339  * we are not trying to validate but just to cut, and yes it will
340  * work even if this is as set of UTF-8 encoded chars
341  */
342  while ((name[l] != 0) && (name[l] != ':'))
343  l++;
344 
345  if (name[l] == 0)
346  return(NULL);
347 
348  *len = l;
349 
350  return(&name[l+1]);
351 }
352 
353 /************************************************************************
354  * *
355  * Check Name, NCName and QName strings *
356  * *
357  ************************************************************************/
358 
359 #define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
360 
361 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
362 
372 int
373 xmlValidateNCName(const xmlChar *value, int space) {
374  const xmlChar *cur = value;
375  int c,l;
376 
377  if (value == NULL)
378  return(-1);
379 
380  /*
381  * First quick algorithm for ASCII range
382  */
383  if (space)
384  while (IS_BLANK_CH(*cur)) cur++;
385  if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
386  (*cur == '_'))
387  cur++;
388  else
389  goto try_complex;
390  while (((*cur >= 'a') && (*cur <= 'z')) ||
391  ((*cur >= 'A') && (*cur <= 'Z')) ||
392  ((*cur >= '0') && (*cur <= '9')) ||
393  (*cur == '_') || (*cur == '-') || (*cur == '.'))
394  cur++;
395  if (space)
396  while (IS_BLANK_CH(*cur)) cur++;
397  if (*cur == 0)
398  return(0);
399 
400 try_complex:
401  /*
402  * Second check for chars outside the ASCII range
403  */
404  cur = value;
405  c = CUR_SCHAR(cur, l);
406  if (space) {
407  while (IS_BLANK(c)) {
408  cur += l;
409  c = CUR_SCHAR(cur, l);
410  }
411  }
412  if ((!IS_LETTER(c)) && (c != '_'))
413  return(1);
414  cur += l;
415  c = CUR_SCHAR(cur, l);
416  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
417  (c == '-') || (c == '_') || IS_COMBINING(c) ||
418  IS_EXTENDER(c)) {
419  cur += l;
420  c = CUR_SCHAR(cur, l);
421  }
422  if (space) {
423  while (IS_BLANK(c)) {
424  cur += l;
425  c = CUR_SCHAR(cur, l);
426  }
427  }
428  if (c != 0)
429  return(1);
430 
431  return(0);
432 }
433 #endif
434 
435 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
436 
446 int
447 xmlValidateQName(const xmlChar *value, int space) {
448  const xmlChar *cur = value;
449  int c,l;
450 
451  if (value == NULL)
452  return(-1);
453  /*
454  * First quick algorithm for ASCII range
455  */
456  if (space)
457  while (IS_BLANK_CH(*cur)) cur++;
458  if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
459  (*cur == '_'))
460  cur++;
461  else
462  goto try_complex;
463  while (((*cur >= 'a') && (*cur <= 'z')) ||
464  ((*cur >= 'A') && (*cur <= 'Z')) ||
465  ((*cur >= '0') && (*cur <= '9')) ||
466  (*cur == '_') || (*cur == '-') || (*cur == '.'))
467  cur++;
468  if (*cur == ':') {
469  cur++;
470  if (((*cur >= 'a') && (*cur <= 'z')) ||
471  ((*cur >= 'A') && (*cur <= 'Z')) ||
472  (*cur == '_'))
473  cur++;
474  else
475  goto try_complex;
476  while (((*cur >= 'a') && (*cur <= 'z')) ||
477  ((*cur >= 'A') && (*cur <= 'Z')) ||
478  ((*cur >= '0') && (*cur <= '9')) ||
479  (*cur == '_') || (*cur == '-') || (*cur == '.'))
480  cur++;
481  }
482  if (space)
483  while (IS_BLANK_CH(*cur)) cur++;
484  if (*cur == 0)
485  return(0);
486 
487 try_complex:
488  /*
489  * Second check for chars outside the ASCII range
490  */
491  cur = value;
492  c = CUR_SCHAR(cur, l);
493  if (space) {
494  while (IS_BLANK(c)) {
495  cur += l;
496  c = CUR_SCHAR(cur, l);
497  }
498  }
499  if ((!IS_LETTER(c)) && (c != '_'))
500  return(1);
501  cur += l;
502  c = CUR_SCHAR(cur, l);
503  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
504  (c == '-') || (c == '_') || IS_COMBINING(c) ||
505  IS_EXTENDER(c)) {
506  cur += l;
507  c = CUR_SCHAR(cur, l);
508  }
509  if (c == ':') {
510  cur += l;
511  c = CUR_SCHAR(cur, l);
512  if ((!IS_LETTER(c)) && (c != '_'))
513  return(1);
514  cur += l;
515  c = CUR_SCHAR(cur, l);
516  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
517  (c == '-') || (c == '_') || IS_COMBINING(c) ||
518  IS_EXTENDER(c)) {
519  cur += l;
520  c = CUR_SCHAR(cur, l);
521  }
522  }
523  if (space) {
524  while (IS_BLANK(c)) {
525  cur += l;
526  c = CUR_SCHAR(cur, l);
527  }
528  }
529  if (c != 0)
530  return(1);
531  return(0);
532 }
533 
544 int
545 xmlValidateName(const xmlChar *value, int space) {
546  const xmlChar *cur = value;
547  int c,l;
548 
549  if (value == NULL)
550  return(-1);
551  /*
552  * First quick algorithm for ASCII range
553  */
554  if (space)
555  while (IS_BLANK_CH(*cur)) cur++;
556  if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
557  (*cur == '_') || (*cur == ':'))
558  cur++;
559  else
560  goto try_complex;
561  while (((*cur >= 'a') && (*cur <= 'z')) ||
562  ((*cur >= 'A') && (*cur <= 'Z')) ||
563  ((*cur >= '0') && (*cur <= '9')) ||
564  (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
565  cur++;
566  if (space)
567  while (IS_BLANK_CH(*cur)) cur++;
568  if (*cur == 0)
569  return(0);
570 
571 try_complex:
572  /*
573  * Second check for chars outside the ASCII range
574  */
575  cur = value;
576  c = CUR_SCHAR(cur, l);
577  if (space) {
578  while (IS_BLANK(c)) {
579  cur += l;
580  c = CUR_SCHAR(cur, l);
581  }
582  }
583  if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
584  return(1);
585  cur += l;
586  c = CUR_SCHAR(cur, l);
587  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
588  (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
589  cur += l;
590  c = CUR_SCHAR(cur, l);
591  }
592  if (space) {
593  while (IS_BLANK(c)) {
594  cur += l;
595  c = CUR_SCHAR(cur, l);
596  }
597  }
598  if (c != 0)
599  return(1);
600  return(0);
601 }
602 
613 int
614 xmlValidateNMToken(const xmlChar *value, int space) {
615  const xmlChar *cur = value;
616  int c,l;
617 
618  if (value == NULL)
619  return(-1);
620  /*
621  * First quick algorithm for ASCII range
622  */
623  if (space)
624  while (IS_BLANK_CH(*cur)) cur++;
625  if (((*cur >= 'a') && (*cur <= 'z')) ||
626  ((*cur >= 'A') && (*cur <= 'Z')) ||
627  ((*cur >= '0') && (*cur <= '9')) ||
628  (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
629  cur++;
630  else
631  goto try_complex;
632  while (((*cur >= 'a') && (*cur <= 'z')) ||
633  ((*cur >= 'A') && (*cur <= 'Z')) ||
634  ((*cur >= '0') && (*cur <= '9')) ||
635  (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
636  cur++;
637  if (space)
638  while (IS_BLANK_CH(*cur)) cur++;
639  if (*cur == 0)
640  return(0);
641 
642 try_complex:
643  /*
644  * Second check for chars outside the ASCII range
645  */
646  cur = value;
647  c = CUR_SCHAR(cur, l);
648  if (space) {
649  while (IS_BLANK(c)) {
650  cur += l;
651  c = CUR_SCHAR(cur, l);
652  }
653  }
654  if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
655  (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
656  return(1);
657  cur += l;
658  c = CUR_SCHAR(cur, l);
659  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
660  (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
661  cur += l;
662  c = CUR_SCHAR(cur, l);
663  }
664  if (space) {
665  while (IS_BLANK(c)) {
666  cur += l;
667  c = CUR_SCHAR(cur, l);
668  }
669  }
670  if (c != 0)
671  return(1);
672  return(0);
673 }
674 #endif /* LIBXML_TREE_ENABLED */
675 
676 /************************************************************************
677  * *
678  * Allocation and deallocation of basic structures *
679  * *
680  ************************************************************************/
681 
691 void
693  if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
697 }
698 
714  return(xmlBufferAllocScheme);
715 }
716 
733 xmlNsPtr
734 xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
735  xmlNsPtr cur;
736 
737  if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
738  return(NULL);
739 
740  if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
741  /* xml namespace is predefined, no need to add it */
742  if (xmlStrEqual(href, XML_XML_NAMESPACE))
743  return(NULL);
744 
745  /*
746  * Problem, this is an attempt to bind xml prefix to a wrong
747  * namespace, which breaks
748  * Namespace constraint: Reserved Prefixes and Namespace Names
749  * from XML namespace. But documents authors may not care in
750  * their context so let's proceed.
751  */
752  }
753 
754  /*
755  * Allocate a new Namespace and fill the fields.
756  */
757  cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
758  if (cur == NULL) {
759  xmlTreeErrMemory("building namespace");
760  return(NULL);
761  }
762  memset(cur, 0, sizeof(xmlNs));
763  cur->type = XML_LOCAL_NAMESPACE;
764 
765  if (href != NULL)
766  cur->href = xmlStrdup(href);
767  if (prefix != NULL)
768  cur->prefix = xmlStrdup(prefix);
769 
770  /*
771  * Add it at the end to preserve parsing order ...
772  * and checks for existing use of the prefix
773  */
774  if (node != NULL) {
775  if (node->nsDef == NULL) {
776  node->nsDef = cur;
777  } else {
778  xmlNsPtr prev = node->nsDef;
779 
780  if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
781  (xmlStrEqual(prev->prefix, cur->prefix))) {
782  xmlFreeNs(cur);
783  return(NULL);
784  }
785  while (prev->next != NULL) {
786  prev = prev->next;
787  if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
788  (xmlStrEqual(prev->prefix, cur->prefix))) {
789  xmlFreeNs(cur);
790  return(NULL);
791  }
792  }
793  prev->next = cur;
794  }
795  }
796  return(cur);
797 }
798 
806 void
808  if (node == NULL) {
809 #ifdef DEBUG_TREE
811  "xmlSetNs: node == NULL\n");
812 #endif
813  return;
814  }
815  if ((node->type == XML_ELEMENT_NODE) ||
816  (node->type == XML_ATTRIBUTE_NODE))
817  node->ns = ns;
818 }
819 
826 void
828  if (cur == NULL) {
829 #ifdef DEBUG_TREE
831  "xmlFreeNs : ns == NULL\n");
832 #endif
833  return;
834  }
835  if (cur->href != NULL) xmlFree((char *) cur->href);
836  if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
837  xmlFree(cur);
838 }
839 
846 void
848  xmlNsPtr next;
849  if (cur == NULL) {
850 #ifdef DEBUG_TREE
852  "xmlFreeNsList : ns == NULL\n");
853 #endif
854  return;
855  }
856  while (cur != NULL) {
857  next = cur->next;
858  xmlFreeNs(cur);
859  cur = next;
860  }
861 }
862 
875 xmlDtdPtr
876 xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
877  const xmlChar *ExternalID, const xmlChar *SystemID) {
878  xmlDtdPtr cur;
879 
880  if ((doc != NULL) && (doc->extSubset != NULL)) {
881 #ifdef DEBUG_TREE
883  "xmlNewDtd(%s): document %s already have a DTD %s\n",
884  /* !!! */ (char *) name, doc->name,
885  /* !!! */ (char *)doc->extSubset->name);
886 #endif
887  return(NULL);
888  }
889 
890  /*
891  * Allocate a new DTD and fill the fields.
892  */
893  cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
894  if (cur == NULL) {
895  xmlTreeErrMemory("building DTD");
896  return(NULL);
897  }
898  memset(cur, 0 , sizeof(xmlDtd));
899  cur->type = XML_DTD_NODE;
900 
901  if (name != NULL)
902  cur->name = xmlStrdup(name);
903  if (ExternalID != NULL)
904  cur->ExternalID = xmlStrdup(ExternalID);
905  if (SystemID != NULL)
906  cur->SystemID = xmlStrdup(SystemID);
907  if (doc != NULL)
908  doc->extSubset = cur;
909  cur->doc = doc;
910 
913  return(cur);
914 }
915 
924 xmlDtdPtr
925 xmlGetIntSubset(const xmlDoc *doc) {
926  xmlNodePtr cur;
927 
928  if (doc == NULL)
929  return(NULL);
930  cur = doc->children;
931  while (cur != NULL) {
932  if (cur->type == XML_DTD_NODE)
933  return((xmlDtdPtr) cur);
934  cur = cur->next;
935  }
936  return((xmlDtdPtr) doc->intSubset);
937 }
938 
949 xmlDtdPtr
951  const xmlChar *ExternalID, const xmlChar *SystemID) {
952  xmlDtdPtr cur;
953 
954  if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
955 #ifdef DEBUG_TREE
957 
958  "xmlCreateIntSubset(): document %s already have an internal subset\n",
959  doc->name);
960 #endif
961  return(NULL);
962  }
963 
964  /*
965  * Allocate a new DTD and fill the fields.
966  */
967  cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
968  if (cur == NULL) {
969  xmlTreeErrMemory("building internal subset");
970  return(NULL);
971  }
972  memset(cur, 0, sizeof(xmlDtd));
973  cur->type = XML_DTD_NODE;
974 
975  if (name != NULL) {
976  cur->name = xmlStrdup(name);
977  if (cur->name == NULL) {
978  xmlTreeErrMemory("building internal subset");
979  xmlFree(cur);
980  return(NULL);
981  }
982  }
983  if (ExternalID != NULL) {
984  cur->ExternalID = xmlStrdup(ExternalID);
985  if (cur->ExternalID == NULL) {
986  xmlTreeErrMemory("building internal subset");
987  if (cur->name != NULL)
988  xmlFree((char *)cur->name);
989  xmlFree(cur);
990  return(NULL);
991  }
992  }
993  if (SystemID != NULL) {
994  cur->SystemID = xmlStrdup(SystemID);
995  if (cur->SystemID == NULL) {
996  xmlTreeErrMemory("building internal subset");
997  if (cur->name != NULL)
998  xmlFree((char *)cur->name);
999  if (cur->ExternalID != NULL)
1000  xmlFree((char *)cur->ExternalID);
1001  xmlFree(cur);
1002  return(NULL);
1003  }
1004  }
1005  if (doc != NULL) {
1006  doc->intSubset = cur;
1007  cur->parent = doc;
1008  cur->doc = doc;
1009  if (doc->children == NULL) {
1010  doc->children = (xmlNodePtr) cur;
1011  doc->last = (xmlNodePtr) cur;
1012  } else {
1013  if (doc->type == XML_HTML_DOCUMENT_NODE) {
1014  xmlNodePtr prev;
1015 
1016  prev = doc->children;
1017  prev->prev = (xmlNodePtr) cur;
1018  cur->next = prev;
1019  doc->children = (xmlNodePtr) cur;
1020  } else {
1021  xmlNodePtr next;
1022 
1023  next = doc->children;
1024  while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
1025  next = next->next;
1026  if (next == NULL) {
1027  cur->prev = doc->last;
1028  cur->prev->next = (xmlNodePtr) cur;
1029  cur->next = NULL;
1030  doc->last = (xmlNodePtr) cur;
1031  } else {
1032  cur->next = next;
1033  cur->prev = next->prev;
1034  if (cur->prev == NULL)
1035  doc->children = (xmlNodePtr) cur;
1036  else
1037  cur->prev->next = (xmlNodePtr) cur;
1038  next->prev = (xmlNodePtr) cur;
1039  }
1040  }
1041  }
1042  }
1043 
1046  return(cur);
1047 }
1048 
1056 #define DICT_FREE(str) \
1057  if ((str) && ((!dict) || \
1058  (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1059  xmlFree((char *)(str));
1060 
1061 
1069 #define DICT_COPY(str, cpy) \
1070  if (str) { \
1071  if (dict) { \
1072  if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1073  cpy = (xmlChar *) (str); \
1074  else \
1075  cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1076  } else \
1077  cpy = xmlStrdup((const xmlChar *)(str)); }
1078 
1086 #define DICT_CONST_COPY(str, cpy) \
1087  if (str) { \
1088  if (dict) { \
1089  if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1090  cpy = (const xmlChar *) (str); \
1091  else \
1092  cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1093  } else \
1094  cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
1095 
1096 
1103 void
1105  xmlDictPtr dict = NULL;
1106 
1107  if (cur == NULL) {
1108  return;
1109  }
1110  if (cur->doc != NULL) dict = cur->doc->dict;
1111 
1114 
1115  if (cur->children != NULL) {
1116  xmlNodePtr next, c = cur->children;
1117 
1118  /*
1119  * Cleanup all nodes which are not part of the specific lists
1120  * of notations, elements, attributes and entities.
1121  */
1122  while (c != NULL) {
1123  next = c->next;
1124  if ((c->type != XML_NOTATION_NODE) &&
1125  (c->type != XML_ELEMENT_DECL) &&
1126  (c->type != XML_ATTRIBUTE_DECL) &&
1127  (c->type != XML_ENTITY_DECL)) {
1128  xmlUnlinkNode(c);
1129  xmlFreeNode(c);
1130  }
1131  c = next;
1132  }
1133  }
1134  DICT_FREE(cur->name)
1135  DICT_FREE(cur->SystemID)
1136  DICT_FREE(cur->ExternalID)
1137  /* TODO !!! */
1138  if (cur->notations != NULL)
1140 
1141  if (cur->elements != NULL)
1143  if (cur->attributes != NULL)
1145  if (cur->entities != NULL)
1147  if (cur->pentities != NULL)
1149 
1150  xmlFree(cur);
1151 }
1152 
1161 xmlDocPtr
1163  xmlDocPtr cur;
1164 
1165  if (version == NULL)
1166  version = (const xmlChar *) "1.0";
1167 
1168  /*
1169  * Allocate a new document and fill the fields.
1170  */
1171  cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1172  if (cur == NULL) {
1173  xmlTreeErrMemory("building doc");
1174  return(NULL);
1175  }
1176  memset(cur, 0, sizeof(xmlDoc));
1177  cur->type = XML_DOCUMENT_NODE;
1178 
1179  cur->version = xmlStrdup(version);
1180  if (cur->version == NULL) {
1181  xmlTreeErrMemory("building doc");
1182  xmlFree(cur);
1183  return(NULL);
1184  }
1185  cur->standalone = -1;
1186  cur->compression = -1; /* not initialized */
1187  cur->doc = cur;
1188  cur->parseFlags = 0;
1189  cur->properties = XML_DOC_USERBUILT;
1190  /*
1191  * The in memory encoding is always UTF8
1192  * This field will never change and would
1193  * be obsolete if not for binary compatibility.
1194  */
1195  cur->charset = XML_CHAR_ENCODING_UTF8;
1196 
1199  return(cur);
1200 }
1201 
1208 void
1210  xmlDtdPtr extSubset, intSubset;
1211  xmlDictPtr dict = NULL;
1212 
1213  if (cur == NULL) {
1214 #ifdef DEBUG_TREE
1216  "xmlFreeDoc : document == NULL\n");
1217 #endif
1218  return;
1219  }
1220 #ifdef LIBXML_DEBUG_RUNTIME
1221 #ifdef LIBXML_DEBUG_ENABLED
1222  xmlDebugCheckDocument(stderr, cur);
1223 #endif
1224 #endif
1225 
1226  if (cur != NULL) dict = cur->dict;
1227 
1230 
1231  /*
1232  * Do this before freeing the children list to avoid ID lookups
1233  */
1234  if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1235  cur->ids = NULL;
1236  if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1237  cur->refs = NULL;
1238  extSubset = cur->extSubset;
1239  intSubset = cur->intSubset;
1240  if (intSubset == extSubset)
1241  extSubset = NULL;
1242  if (extSubset != NULL) {
1243  xmlUnlinkNode((xmlNodePtr) cur->extSubset);
1244  cur->extSubset = NULL;
1245  xmlFreeDtd(extSubset);
1246  }
1247  if (intSubset != NULL) {
1248  xmlUnlinkNode((xmlNodePtr) cur->intSubset);
1249  cur->intSubset = NULL;
1250  xmlFreeDtd(intSubset);
1251  }
1252 
1253  if (cur->children != NULL) xmlFreeNodeList(cur->children);
1254  if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1255 
1256  DICT_FREE(cur->version)
1257  DICT_FREE(cur->name)
1259  DICT_FREE(cur->URL)
1260  xmlFree(cur);
1261  if (dict) xmlDictFree(dict);
1262 }
1263 
1274 xmlNodePtr
1276  xmlNodePtr ret = NULL, last = NULL;
1277  xmlNodePtr node;
1278  xmlChar *val;
1279  const xmlChar *cur, *end;
1280  const xmlChar *q;
1281  xmlEntityPtr ent;
1282  xmlBufPtr buf;
1283 
1284  if (value == NULL) return(NULL);
1285  cur = value;
1286  end = cur + len;
1287 
1288  buf = xmlBufCreateSize(0);
1289  if (buf == NULL) return(NULL);
1291 
1292  q = cur;
1293  while ((cur < end) && (*cur != 0)) {
1294  if (cur[0] == '&') {
1295  int charval = 0;
1296  xmlChar tmp;
1297 
1298  /*
1299  * Save the current text.
1300  */
1301  if (cur != q) {
1302  if (xmlBufAdd(buf, q, cur - q))
1303  goto out;
1304  }
1305  q = cur;
1306  if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1307  cur += 3;
1308  if (cur < end)
1309  tmp = *cur;
1310  else
1311  tmp = 0;
1312  while (tmp != ';') { /* Non input consuming loop */
1313  /*
1314  * If you find an integer overflow here when fuzzing,
1315  * the bug is probably elsewhere. This function should
1316  * only receive entities that were already validated by
1317  * the parser, typically by xmlParseAttValueComplex
1318  * calling xmlStringDecodeEntities.
1319  *
1320  * So it's better *not* to check for overflow to
1321  * potentially discover new bugs.
1322  */
1323  if ((tmp >= '0') && (tmp <= '9'))
1324  charval = charval * 16 + (tmp - '0');
1325  else if ((tmp >= 'a') && (tmp <= 'f'))
1326  charval = charval * 16 + (tmp - 'a') + 10;
1327  else if ((tmp >= 'A') && (tmp <= 'F'))
1328  charval = charval * 16 + (tmp - 'A') + 10;
1329  else {
1330  xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1331  NULL);
1332  charval = 0;
1333  break;
1334  }
1335  cur++;
1336  if (cur < end)
1337  tmp = *cur;
1338  else
1339  tmp = 0;
1340  }
1341  if (tmp == ';')
1342  cur++;
1343  q = cur;
1344  } else if ((cur + 1 < end) && (cur[1] == '#')) {
1345  cur += 2;
1346  if (cur < end)
1347  tmp = *cur;
1348  else
1349  tmp = 0;
1350  while (tmp != ';') { /* Non input consuming loops */
1351  /* Don't check for integer overflow, see above. */
1352  if ((tmp >= '0') && (tmp <= '9'))
1353  charval = charval * 10 + (tmp - '0');
1354  else {
1355  xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1356  NULL);
1357  charval = 0;
1358  break;
1359  }
1360  cur++;
1361  if (cur < end)
1362  tmp = *cur;
1363  else
1364  tmp = 0;
1365  }
1366  if (tmp == ';')
1367  cur++;
1368  q = cur;
1369  } else {
1370  /*
1371  * Read the entity string
1372  */
1373  cur++;
1374  q = cur;
1375  while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1376  if ((cur >= end) || (*cur == 0)) {
1377  xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1378  (const char *) q);
1379  goto out;
1380  }
1381  if (cur != q) {
1382  /*
1383  * Predefined entities don't generate nodes
1384  */
1385  val = xmlStrndup(q, cur - q);
1386  ent = xmlGetDocEntity(doc, val);
1387  if ((ent != NULL) &&
1389 
1390  if (xmlBufCat(buf, ent->content))
1391  goto out;
1392 
1393  } else {
1394  /*
1395  * Flush buffer so far
1396  */
1397  if (!xmlBufIsEmpty(buf)) {
1398  node = xmlNewDocText(doc, NULL);
1399  if (node == NULL) {
1400  if (val != NULL) xmlFree(val);
1401  goto out;
1402  }
1403  node->content = xmlBufDetach(buf);
1404 
1405  if (last == NULL) {
1406  last = ret = node;
1407  } else {
1409  }
1410  }
1411 
1412  /*
1413  * Create a new REFERENCE_REF node
1414  */
1415  node = xmlNewReference(doc, val);
1416  if (node == NULL) {
1417  if (val != NULL) xmlFree(val);
1418  goto out;
1419  }
1420  else if ((ent != NULL) && (ent->children == NULL)) {
1421  xmlNodePtr temp;
1422 
1423  /* Set to non-NULL value to avoid recursion. */
1424  ent->children = (xmlNodePtr) -1;
1425  ent->children = xmlStringGetNodeList(doc,
1426  (const xmlChar*)node->content);
1427  ent->owner = 1;
1428  temp = ent->children;
1429  while (temp) {
1430  temp->parent = (xmlNodePtr)ent;
1431  ent->last = temp;
1432  temp = temp->next;
1433  }
1434  }
1435  if (last == NULL) {
1436  last = ret = node;
1437  } else {
1439  }
1440  }
1441  xmlFree(val);
1442  }
1443  cur++;
1444  q = cur;
1445  }
1446  if (charval != 0) {
1447  xmlChar buffer[10];
1448  int l;
1449 
1450  l = xmlCopyCharMultiByte(buffer, charval);
1451  buffer[l] = 0;
1452 
1453  if (xmlBufCat(buf, buffer))
1454  goto out;
1455  charval = 0;
1456  }
1457  } else
1458  cur++;
1459  }
1460 
1461  if (cur != q) {
1462  /*
1463  * Handle the last piece of text.
1464  */
1465  if (xmlBufAdd(buf, q, cur - q))
1466  goto out;
1467  }
1468 
1469  if (!xmlBufIsEmpty(buf)) {
1470  node = xmlNewDocText(doc, NULL);
1471  if (node == NULL) goto out;
1472  node->content = xmlBufDetach(buf);
1473 
1474  if (last == NULL) {
1475  ret = node;
1476  } else {
1478  }
1479  } else if (ret == NULL) {
1480  ret = xmlNewDocText(doc, BAD_CAST "");
1481  }
1482 
1483 out:
1484  xmlBufFree(buf);
1485  return(ret);
1486 }
1487 
1497 xmlNodePtr
1498 xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) {
1499  xmlNodePtr ret = NULL, last = NULL;
1500  xmlNodePtr node;
1501  xmlChar *val;
1502  const xmlChar *cur = value;
1503  const xmlChar *q;
1504  xmlEntityPtr ent;
1505  xmlBufPtr buf;
1506 
1507  if (value == NULL) return(NULL);
1508 
1509  buf = xmlBufCreateSize(0);
1510  if (buf == NULL) return(NULL);
1512 
1513  q = cur;
1514  while (*cur != 0) {
1515  if (cur[0] == '&') {
1516  int charval = 0;
1517  xmlChar tmp;
1518 
1519  /*
1520  * Save the current text.
1521  */
1522  if (cur != q) {
1523  if (xmlBufAdd(buf, q, cur - q))
1524  goto out;
1525  }
1526  q = cur;
1527  if ((cur[1] == '#') && (cur[2] == 'x')) {
1528  cur += 3;
1529  tmp = *cur;
1530  while (tmp != ';') { /* Non input consuming loop */
1531  /* Don't check for integer overflow, see above. */
1532  if ((tmp >= '0') && (tmp <= '9'))
1533  charval = charval * 16 + (tmp - '0');
1534  else if ((tmp >= 'a') && (tmp <= 'f'))
1535  charval = charval * 16 + (tmp - 'a') + 10;
1536  else if ((tmp >= 'A') && (tmp <= 'F'))
1537  charval = charval * 16 + (tmp - 'A') + 10;
1538  else {
1539  xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1540  NULL);
1541  charval = 0;
1542  break;
1543  }
1544  cur++;
1545  tmp = *cur;
1546  }
1547  if (tmp == ';')
1548  cur++;
1549  q = cur;
1550  } else if (cur[1] == '#') {
1551  cur += 2;
1552  tmp = *cur;
1553  while (tmp != ';') { /* Non input consuming loops */
1554  /* Don't check for integer overflow, see above. */
1555  if ((tmp >= '0') && (tmp <= '9'))
1556  charval = charval * 10 + (tmp - '0');
1557  else {
1558  xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1559  NULL);
1560  charval = 0;
1561  break;
1562  }
1563  cur++;
1564  tmp = *cur;
1565  }
1566  if (tmp == ';')
1567  cur++;
1568  q = cur;
1569  } else {
1570  /*
1571  * Read the entity string
1572  */
1573  cur++;
1574  q = cur;
1575  while ((*cur != 0) && (*cur != ';')) cur++;
1576  if (*cur == 0) {
1577  xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1578  (xmlNodePtr) doc, (const char *) q);
1579  goto out;
1580  }
1581  if (cur != q) {
1582  /*
1583  * Predefined entities don't generate nodes
1584  */
1585  val = xmlStrndup(q, cur - q);
1586  ent = xmlGetDocEntity(doc, val);
1587  if ((ent != NULL) &&
1589 
1590  if (xmlBufCat(buf, ent->content))
1591  goto out;
1592 
1593  } else {
1594  /*
1595  * Flush buffer so far
1596  */
1597  if (!xmlBufIsEmpty(buf)) {
1598  node = xmlNewDocText(doc, NULL);
1599  node->content = xmlBufDetach(buf);
1600 
1601  if (last == NULL) {
1602  last = ret = node;
1603  } else {
1605  }
1606  }
1607 
1608  /*
1609  * Create a new REFERENCE_REF node
1610  */
1611  node = xmlNewReference(doc, val);
1612  if (node == NULL) {
1613  if (val != NULL) xmlFree(val);
1614  goto out;
1615  }
1616  else if ((ent != NULL) && (ent->children == NULL)) {
1617  xmlNodePtr temp;
1618 
1619  /* Set to non-NULL value to avoid recursion. */
1620  ent->children = (xmlNodePtr) -1;
1621  ent->children = xmlStringGetNodeList(doc,
1622  (const xmlChar*)node->content);
1623  ent->owner = 1;
1624  temp = ent->children;
1625  while (temp) {
1626  temp->parent = (xmlNodePtr)ent;
1627  ent->last = temp;
1628  temp = temp->next;
1629  }
1630  }
1631  if (last == NULL) {
1632  last = ret = node;
1633  } else {
1635  }
1636  }
1637  xmlFree(val);
1638  }
1639  cur++;
1640  q = cur;
1641  }
1642  if (charval != 0) {
1643  xmlChar buffer[10];
1644  int len;
1645 
1646  len = xmlCopyCharMultiByte(buffer, charval);
1647  buffer[len] = 0;
1648 
1649  if (xmlBufCat(buf, buffer))
1650  goto out;
1651  charval = 0;
1652  }
1653  } else
1654  cur++;
1655  }
1656  if ((cur != q) || (ret == NULL)) {
1657  /*
1658  * Handle the last piece of text.
1659  */
1660  xmlBufAdd(buf, q, cur - q);
1661  }
1662 
1663  if (!xmlBufIsEmpty(buf)) {
1664  node = xmlNewDocText(doc, NULL);
1665  if (node == NULL) {
1666  xmlBufFree(buf);
1667  return(NULL);
1668  }
1669  node->content = xmlBufDetach(buf);
1670 
1671  if (last == NULL) {
1672  ret = node;
1673  } else {
1675  }
1676  }
1677 
1678 out:
1679  xmlBufFree(buf);
1680  return(ret);
1681 }
1682 
1694 xmlChar *
1695 xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
1696 {
1697  const xmlNode *node = list;
1698  xmlChar *ret = NULL;
1699  xmlEntityPtr ent;
1700  int attr;
1701 
1702  if (list == NULL)
1703  return (NULL);
1704  if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
1705  attr = 1;
1706  else
1707  attr = 0;
1708 
1709  while (node != NULL) {
1710  if ((node->type == XML_TEXT_NODE) ||
1711  (node->type == XML_CDATA_SECTION_NODE)) {
1712  if (inLine) {
1713  ret = xmlStrcat(ret, node->content);
1714  } else {
1715  xmlChar *buffer;
1716 
1717  if (attr)
1718  buffer = xmlEncodeAttributeEntities(doc, node->content);
1719  else
1720  buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1721  if (buffer != NULL) {
1722  ret = xmlStrcat(ret, buffer);
1723  xmlFree(buffer);
1724  }
1725  }
1726  } else if (node->type == XML_ENTITY_REF_NODE) {
1727  if (inLine) {
1728  ent = xmlGetDocEntity(doc, node->name);
1729  if (ent != NULL) {
1730  xmlChar *buffer;
1731 
1732  /* an entity content can be any "well balanced chunk",
1733  * i.e. the result of the content [43] production:
1734  * http://www.w3.org/TR/REC-xml#NT-content.
1735  * So it can contain text, CDATA section or nested
1736  * entity reference nodes (among others).
1737  * -> we recursive call xmlNodeListGetString()
1738  * which handles these types */
1739  buffer = xmlNodeListGetString(doc, ent->children, 1);
1740  if (buffer != NULL) {
1741  ret = xmlStrcat(ret, buffer);
1742  xmlFree(buffer);
1743  }
1744  } else {
1745  ret = xmlStrcat(ret, node->content);
1746  }
1747  } else {
1748  xmlChar buf[2];
1749 
1750  buf[0] = '&';
1751  buf[1] = 0;
1752  ret = xmlStrncat(ret, buf, 1);
1753  ret = xmlStrcat(ret, node->name);
1754  buf[0] = ';';
1755  buf[1] = 0;
1756  ret = xmlStrncat(ret, buf, 1);
1757  }
1758  }
1759 #if 0
1760  else {
1762  "xmlGetNodeListString : invalid node type %d\n",
1763  node->type);
1764  }
1765 #endif
1766  node = node->next;
1767  }
1768  return (ret);
1769 }
1770 
1771 #ifdef LIBXML_TREE_ENABLED
1772 
1784 xmlChar *
1785 xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine)
1786 {
1787  const xmlNode *node = list;
1788  xmlChar *ret = NULL;
1789  xmlEntityPtr ent;
1790 
1791  if (list == NULL)
1792  return (NULL);
1793 
1794  while (node != NULL) {
1795  if ((node->type == XML_TEXT_NODE) ||
1796  (node->type == XML_CDATA_SECTION_NODE)) {
1797  if (inLine) {
1798  ret = xmlStrcat(ret, node->content);
1799  } else {
1800  xmlChar *buffer;
1801 
1802  buffer = xmlEncodeSpecialChars(doc, node->content);
1803  if (buffer != NULL) {
1804  ret = xmlStrcat(ret, buffer);
1805  xmlFree(buffer);
1806  }
1807  }
1808  } else if (node->type == XML_ENTITY_REF_NODE) {
1809  if (inLine) {
1810  ent = xmlGetDocEntity(doc, node->name);
1811  if (ent != NULL) {
1812  xmlChar *buffer;
1813 
1814  /* an entity content can be any "well balanced chunk",
1815  * i.e. the result of the content [43] production:
1816  * http://www.w3.org/TR/REC-xml#NT-content.
1817  * So it can contain text, CDATA section or nested
1818  * entity reference nodes (among others).
1819  * -> we recursive call xmlNodeListGetRawString()
1820  * which handles these types */
1821  buffer =
1822  xmlNodeListGetRawString(doc, ent->children, 1);
1823  if (buffer != NULL) {
1824  ret = xmlStrcat(ret, buffer);
1825  xmlFree(buffer);
1826  }
1827  } else {
1828  ret = xmlStrcat(ret, node->content);
1829  }
1830  } else {
1831  xmlChar buf[2];
1832 
1833  buf[0] = '&';
1834  buf[1] = 0;
1835  ret = xmlStrncat(ret, buf, 1);
1836  ret = xmlStrcat(ret, node->name);
1837  buf[0] = ';';
1838  buf[1] = 0;
1839  ret = xmlStrncat(ret, buf, 1);
1840  }
1841  }
1842 #if 0
1843  else {
1845  "xmlGetNodeListString : invalid node type %d\n",
1846  node->type);
1847  }
1848 #endif
1849  node = node->next;
1850  }
1851  return (ret);
1852 }
1853 #endif /* LIBXML_TREE_ENABLED */
1854 
1855 static xmlAttrPtr
1856 xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1857  const xmlChar * name, const xmlChar * value,
1858  int eatname)
1859 {
1860  xmlAttrPtr cur;
1861  xmlDocPtr doc = NULL;
1862 
1863  if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1864  if ((eatname == 1) &&
1865  ((node->doc == NULL) ||
1866  (!(xmlDictOwns(node->doc->dict, name)))))
1867  xmlFree((xmlChar *) name);
1868  return (NULL);
1869  }
1870 
1871  /*
1872  * Allocate a new property and fill the fields.
1873  */
1874  cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1875  if (cur == NULL) {
1876  if ((eatname == 1) &&
1877  ((node == NULL) || (node->doc == NULL) ||
1878  (!(xmlDictOwns(node->doc->dict, name)))))
1879  xmlFree((xmlChar *) name);
1880  xmlTreeErrMemory("building attribute");
1881  return (NULL);
1882  }
1883  memset(cur, 0, sizeof(xmlAttr));
1884  cur->type = XML_ATTRIBUTE_NODE;
1885 
1886  cur->parent = node;
1887  if (node != NULL) {
1888  doc = node->doc;
1889  cur->doc = doc;
1890  }
1891  cur->ns = ns;
1892 
1893  if (eatname == 0) {
1894  if ((doc != NULL) && (doc->dict != NULL))
1895  cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1896  else
1897  cur->name = xmlStrdup(name);
1898  } else
1899  cur->name = name;
1900 
1901  if (value != NULL) {
1902  xmlNodePtr tmp;
1903 
1904  cur->children = xmlNewDocText(doc, value);
1905  cur->last = NULL;
1906  tmp = cur->children;
1907  while (tmp != NULL) {
1908  tmp->parent = (xmlNodePtr) cur;
1909  if (tmp->next == NULL)
1910  cur->last = tmp;
1911  tmp = tmp->next;
1912  }
1913  }
1914 
1915  /*
1916  * Add it at the end to preserve parsing order ...
1917  */
1918  if (node != NULL) {
1919  if (node->properties == NULL) {
1920  node->properties = cur;
1921  } else {
1922  xmlAttrPtr prev = node->properties;
1923 
1924  while (prev->next != NULL)
1925  prev = prev->next;
1926  prev->next = cur;
1927  cur->prev = prev;
1928  }
1929  }
1930 
1931  if ((value != NULL) && (node != NULL) &&
1932  (xmlIsID(node->doc, node, cur) == 1))
1933  xmlAddID(NULL, node->doc, value, cur);
1934 
1937  return (cur);
1938 }
1939 
1940 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1941  defined(LIBXML_SCHEMAS_ENABLED)
1942 
1951 xmlAttrPtr
1952 xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1953 
1954  if (name == NULL) {
1955 #ifdef DEBUG_TREE
1957  "xmlNewProp : name == NULL\n");
1958 #endif
1959  return(NULL);
1960  }
1961 
1962  return xmlNewPropInternal(node, NULL, name, value, 0);
1963 }
1964 #endif /* LIBXML_TREE_ENABLED */
1965 
1976 xmlAttrPtr
1978  const xmlChar *value) {
1979 
1980  if (name == NULL) {
1981 #ifdef DEBUG_TREE
1983  "xmlNewNsProp : name == NULL\n");
1984 #endif
1985  return(NULL);
1986  }
1987 
1988  return xmlNewPropInternal(node, ns, name, value, 0);
1989 }
1990 
2001 xmlAttrPtr
2003  const xmlChar *value) {
2004 
2005  if (name == NULL) {
2006 #ifdef DEBUG_TREE
2008  "xmlNewNsPropEatName : name == NULL\n");
2009 #endif
2010  return(NULL);
2011  }
2012 
2013  return xmlNewPropInternal(node, ns, name, value, 1);
2014 }
2015 
2030 xmlAttrPtr
2031 xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
2032  xmlAttrPtr cur;
2033 
2034  if (name == NULL) {
2035 #ifdef DEBUG_TREE
2037  "xmlNewDocProp : name == NULL\n");
2038 #endif
2039  return(NULL);
2040  }
2041 
2042  /*
2043  * Allocate a new property and fill the fields.
2044  */
2045  cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
2046  if (cur == NULL) {
2047  xmlTreeErrMemory("building attribute");
2048  return(NULL);
2049  }
2050  memset(cur, 0, sizeof(xmlAttr));
2051  cur->type = XML_ATTRIBUTE_NODE;
2052 
2053  if ((doc != NULL) && (doc->dict != NULL))
2054  cur->name = xmlDictLookup(doc->dict, name, -1);
2055  else
2056  cur->name = xmlStrdup(name);
2057  cur->doc = doc;
2058  if (value != NULL) {
2059  xmlNodePtr tmp;
2060 
2061  cur->children = xmlStringGetNodeList(doc, value);
2062  cur->last = NULL;
2063 
2064  tmp = cur->children;
2065  while (tmp != NULL) {
2066  tmp->parent = (xmlNodePtr) cur;
2067  if (tmp->next == NULL)
2068  cur->last = tmp;
2069  tmp = tmp->next;
2070  }
2071  }
2072 
2075  return(cur);
2076 }
2077 
2084 void
2086  xmlAttrPtr next;
2087  if (cur == NULL) return;
2088  while (cur != NULL) {
2089  next = cur->next;
2090  xmlFreeProp(cur);
2091  cur = next;
2092  }
2093 }
2094 
2101 void
2103  xmlDictPtr dict = NULL;
2104  if (cur == NULL) return;
2105 
2106  if (cur->doc != NULL) dict = cur->doc->dict;
2107 
2110 
2111  /* Check for ID removal -> leading to invalid references ! */
2112  if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2113  xmlRemoveID(cur->doc, cur);
2114  }
2115  if (cur->children != NULL) xmlFreeNodeList(cur->children);
2116  DICT_FREE(cur->name)
2117  xmlFree(cur);
2118 }
2119 
2129 int
2131  xmlAttrPtr tmp;
2132  if (cur == NULL) {
2133 #ifdef DEBUG_TREE
2135  "xmlRemoveProp : cur == NULL\n");
2136 #endif
2137  return(-1);
2138  }
2139  if (cur->parent == NULL) {
2140 #ifdef DEBUG_TREE
2142  "xmlRemoveProp : cur->parent == NULL\n");
2143 #endif
2144  return(-1);
2145  }
2146  tmp = cur->parent->properties;
2147  if (tmp == cur) {
2148  cur->parent->properties = cur->next;
2149  if (cur->next != NULL)
2150  cur->next->prev = NULL;
2151  xmlFreeProp(cur);
2152  return(0);
2153  }
2154  while (tmp != NULL) {
2155  if (tmp->next == cur) {
2156  tmp->next = cur->next;
2157  if (tmp->next != NULL)
2158  tmp->next->prev = tmp;
2159  xmlFreeProp(cur);
2160  return(0);
2161  }
2162  tmp = tmp->next;
2163  }
2164 #ifdef DEBUG_TREE
2166  "xmlRemoveProp : attribute not owned by its node\n");
2167 #endif
2168  return(-1);
2169 }
2170 
2180 xmlNodePtr
2181 xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
2182  xmlNodePtr cur;
2183 
2184  if (name == NULL) {
2185 #ifdef DEBUG_TREE
2187  "xmlNewPI : name == NULL\n");
2188 #endif
2189  return(NULL);
2190  }
2191 
2192  /*
2193  * Allocate a new node and fill the fields.
2194  */
2195  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2196  if (cur == NULL) {
2197  xmlTreeErrMemory("building PI");
2198  return(NULL);
2199  }
2200  memset(cur, 0, sizeof(xmlNode));
2201  cur->type = XML_PI_NODE;
2202 
2203  if ((doc != NULL) && (doc->dict != NULL))
2204  cur->name = xmlDictLookup(doc->dict, name, -1);
2205  else
2206  cur->name = xmlStrdup(name);
2207  if (content != NULL) {
2208  cur->content = xmlStrdup(content);
2209  }
2210  cur->doc = doc;
2211 
2214  return(cur);
2215 }
2216 
2227 xmlNodePtr
2228 xmlNewPI(const xmlChar *name, const xmlChar *content) {
2229  return(xmlNewDocPI(NULL, name, content));
2230 }
2231 
2242 xmlNodePtr
2243 xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2244  xmlNodePtr cur;
2245 
2246  if (name == NULL) {
2247 #ifdef DEBUG_TREE
2249  "xmlNewNode : name == NULL\n");
2250 #endif
2251  return(NULL);
2252  }
2253 
2254  /*
2255  * Allocate a new node and fill the fields.
2256  */
2257  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2258  if (cur == NULL) {
2259  xmlTreeErrMemory("building node");
2260  return(NULL);
2261  }
2262  memset(cur, 0, sizeof(xmlNode));
2263  cur->type = XML_ELEMENT_NODE;
2264 
2265  cur->name = xmlStrdup(name);
2266  cur->ns = ns;
2267 
2270  return(cur);
2271 }
2272 
2284 xmlNodePtr
2286  xmlNodePtr cur;
2287 
2288  if (name == NULL) {
2289 #ifdef DEBUG_TREE
2291  "xmlNewNode : name == NULL\n");
2292 #endif
2293  return(NULL);
2294  }
2295 
2296  /*
2297  * Allocate a new node and fill the fields.
2298  */
2299  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2300  if (cur == NULL) {
2301  xmlTreeErrMemory("building node");
2302  /* we can't check here that name comes from the doc dictionary */
2303  return(NULL);
2304  }
2305  memset(cur, 0, sizeof(xmlNode));
2306  cur->type = XML_ELEMENT_NODE;
2307 
2308  cur->name = name;
2309  cur->ns = ns;
2310 
2313  return(cur);
2314 }
2315 
2332 xmlNodePtr
2334  const xmlChar *name, const xmlChar *content) {
2335  xmlNodePtr cur;
2336 
2337  if ((doc != NULL) && (doc->dict != NULL))
2339  xmlDictLookup(doc->dict, name, -1));
2340  else
2341  cur = xmlNewNode(ns, name);
2342  if (cur != NULL) {
2343  cur->doc = doc;
2344  if (content != NULL) {
2345  cur->children = xmlStringGetNodeList(doc, content);
2347  }
2348  }
2349 
2350  return(cur);
2351 }
2352 
2369 xmlNodePtr
2371  xmlChar *name, const xmlChar *content) {
2372  xmlNodePtr cur;
2373 
2375  if (cur != NULL) {
2376  cur->doc = doc;
2377  if (content != NULL) {
2378  cur->children = xmlStringGetNodeList(doc, content);
2380  }
2381  } else {
2382  /* if name don't come from the doc dictionary free it here */
2383  if ((name != NULL) && (doc != NULL) &&
2384  (!(xmlDictOwns(doc->dict, name))))
2385  xmlFree(name);
2386  }
2387  return(cur);
2388 }
2389 
2390 #ifdef LIBXML_TREE_ENABLED
2391 
2403 xmlNodePtr
2404 xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2405  const xmlChar *name, const xmlChar *content) {
2406  xmlNodePtr cur;
2407 
2408  cur = xmlNewDocNode(doc, ns, name, NULL);
2409  if (cur != NULL) {
2410  cur->doc = doc;
2411  if (content != NULL) {
2412  cur->children = xmlNewDocText(doc, content);
2414  }
2415  }
2416  return(cur);
2417 }
2418 
2426 xmlNodePtr
2427 xmlNewDocFragment(xmlDocPtr doc) {
2428  xmlNodePtr cur;
2429 
2430  /*
2431  * Allocate a new DocumentFragment node and fill the fields.
2432  */
2433  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2434  if (cur == NULL) {
2435  xmlTreeErrMemory("building fragment");
2436  return(NULL);
2437  }
2438  memset(cur, 0, sizeof(xmlNode));
2439  cur->type = XML_DOCUMENT_FRAG_NODE;
2440 
2441  cur->doc = doc;
2442 
2445  return(cur);
2446 }
2447 #endif /* LIBXML_TREE_ENABLED */
2448 
2456 xmlNodePtr
2457 xmlNewText(const xmlChar *content) {
2458  xmlNodePtr cur;
2459 
2460  /*
2461  * Allocate a new node and fill the fields.
2462  */
2463  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2464  if (cur == NULL) {
2465  xmlTreeErrMemory("building text");
2466  return(NULL);
2467  }
2468  memset(cur, 0, sizeof(xmlNode));
2469  cur->type = XML_TEXT_NODE;
2470 
2471  cur->name = xmlStringText;
2472  if (content != NULL) {
2473  cur->content = xmlStrdup(content);
2474  }
2475 
2478  return(cur);
2479 }
2480 
2481 #ifdef LIBXML_TREE_ENABLED
2482 
2501 xmlNodePtr
2502 xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2503  const xmlChar *name, const xmlChar *content) {
2504  xmlNodePtr cur, prev;
2505 
2506  if (parent == NULL) {
2507 #ifdef DEBUG_TREE
2509  "xmlNewTextChild : parent == NULL\n");
2510 #endif
2511  return(NULL);
2512  }
2513 
2514  if (name == NULL) {
2515 #ifdef DEBUG_TREE
2517  "xmlNewTextChild : name == NULL\n");
2518 #endif
2519  return(NULL);
2520  }
2521 
2522  /*
2523  * Allocate a new node
2524  */
2525  if (parent->type == XML_ELEMENT_NODE) {
2526  if (ns == NULL)
2527  cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2528  else
2529  cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2530  } else if ((parent->type == XML_DOCUMENT_NODE) ||
2531  (parent->type == XML_HTML_DOCUMENT_NODE)) {
2532  if (ns == NULL)
2533  cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2534  else
2535  cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2536  } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2537  cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2538  } else {
2539  return(NULL);
2540  }
2541  if (cur == NULL) return(NULL);
2542 
2543  /*
2544  * add the new element at the end of the children list.
2545  */
2546  cur->type = XML_ELEMENT_NODE;
2547  cur->parent = parent;
2548  cur->doc = parent->doc;
2549  if (parent->children == NULL) {
2550  parent->children = cur;
2551  parent->last = cur;
2552  } else {
2553  prev = parent->last;
2554  prev->next = cur;
2555  cur->prev = prev;
2556  parent->last = cur;
2557  }
2558 
2559  return(cur);
2560 }
2561 #endif /* LIBXML_TREE_ENABLED */
2562 
2571 xmlNodePtr
2572 xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2573  xmlNodePtr cur;
2574 
2575  if (name == NULL)
2576  return(NULL);
2577 
2578  /*
2579  * Allocate a new node and fill the fields.
2580  */
2581  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2582  if (cur == NULL) {
2583  xmlTreeErrMemory("building character reference");
2584  return(NULL);
2585  }
2586  memset(cur, 0, sizeof(xmlNode));
2587  cur->type = XML_ENTITY_REF_NODE;
2588 
2589  cur->doc = doc;
2590  if (name[0] == '&') {
2591  int len;
2592  name++;
2593  len = xmlStrlen(name);
2594  if (name[len - 1] == ';')
2595  cur->name = xmlStrndup(name, len - 1);
2596  else
2597  cur->name = xmlStrndup(name, len);
2598  } else
2599  cur->name = xmlStrdup(name);
2600 
2603  return(cur);
2604 }
2605 
2614 xmlNodePtr
2615 xmlNewReference(const xmlDoc *doc, const xmlChar *name) {
2616  xmlNodePtr cur;
2617  xmlEntityPtr ent;
2618 
2619  if (name == NULL)
2620  return(NULL);
2621 
2622  /*
2623  * Allocate a new node and fill the fields.
2624  */
2625  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2626  if (cur == NULL) {
2627  xmlTreeErrMemory("building reference");
2628  return(NULL);
2629  }
2630  memset(cur, 0, sizeof(xmlNode));
2631  cur->type = XML_ENTITY_REF_NODE;
2632 
2633  cur->doc = (xmlDoc *)doc;
2634  if (name[0] == '&') {
2635  int len;
2636  name++;
2637  len = xmlStrlen(name);
2638  if (name[len - 1] == ';')
2639  cur->name = xmlStrndup(name, len - 1);
2640  else
2641  cur->name = xmlStrndup(name, len);
2642  } else
2643  cur->name = xmlStrdup(name);
2644 
2645  ent = xmlGetDocEntity(doc, cur->name);
2646  if (ent != NULL) {
2647  cur->content = ent->content;
2648  /*
2649  * The parent pointer in entity is a DTD pointer and thus is NOT
2650  * updated. Not sure if this is 100% correct.
2651  * -George
2652  */
2653  cur->children = (xmlNodePtr) ent;
2654  cur->last = (xmlNodePtr) ent;
2655  }
2656 
2659  return(cur);
2660 }
2661 
2670 xmlNodePtr
2671 xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
2672  xmlNodePtr cur;
2673 
2674  cur = xmlNewText(content);
2675  if (cur != NULL) cur->doc = (xmlDoc *)doc;
2676  return(cur);
2677 }
2678 
2687 xmlNodePtr
2688 xmlNewTextLen(const xmlChar *content, int len) {
2689  xmlNodePtr cur;
2690 
2691  /*
2692  * Allocate a new node and fill the fields.
2693  */
2694  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2695  if (cur == NULL) {
2696  xmlTreeErrMemory("building text");
2697  return(NULL);
2698  }
2699  memset(cur, 0, sizeof(xmlNode));
2700  cur->type = XML_TEXT_NODE;
2701 
2702  cur->name = xmlStringText;
2703  if (content != NULL) {
2704  cur->content = xmlStrndup(content, len);
2705  }
2706 
2709  return(cur);
2710 }
2711 
2722 xmlNodePtr
2723 xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2724  xmlNodePtr cur;
2725 
2727  if (cur != NULL) cur->doc = doc;
2728  return(cur);
2729 }
2730 
2738 xmlNodePtr
2739 xmlNewComment(const xmlChar *content) {
2740  xmlNodePtr cur;
2741 
2742  /*
2743  * Allocate a new node and fill the fields.
2744  */
2745  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2746  if (cur == NULL) {
2747  xmlTreeErrMemory("building comment");
2748  return(NULL);
2749  }
2750  memset(cur, 0, sizeof(xmlNode));
2751  cur->type = XML_COMMENT_NODE;
2752 
2753  cur->name = xmlStringComment;
2754  if (content != NULL) {
2755  cur->content = xmlStrdup(content);
2756  }
2757 
2760  return(cur);
2761 }
2762 
2772 xmlNodePtr
2773 xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2774  xmlNodePtr cur;
2775 
2776  /*
2777  * Allocate a new node and fill the fields.
2778  */
2779  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2780  if (cur == NULL) {
2781  xmlTreeErrMemory("building CDATA");
2782  return(NULL);
2783  }
2784  memset(cur, 0, sizeof(xmlNode));
2785  cur->type = XML_CDATA_SECTION_NODE;
2786  cur->doc = doc;
2787 
2788  if (content != NULL) {
2789  cur->content = xmlStrndup(content, len);
2790  }
2791 
2794  return(cur);
2795 }
2796 
2805 xmlNodePtr
2807  xmlNodePtr cur;
2808 
2810  if (cur != NULL) cur->doc = doc;
2811  return(cur);
2812 }
2813 
2821 void
2823  xmlAttrPtr prop;
2824 
2825  if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2826  return;
2827  if (tree->doc != doc) {
2828  if(tree->type == XML_ELEMENT_NODE) {
2829  prop = tree->properties;
2830  while (prop != NULL) {
2831  if (prop->atype == XML_ATTRIBUTE_ID) {
2832  xmlRemoveID(tree->doc, prop);
2833  }
2834 
2835  prop->doc = doc;
2836  xmlSetListDoc(prop->children, doc);
2837 
2838  /*
2839  * TODO: ID attributes should be also added to the new
2840  * document, but this breaks things like xmlReplaceNode.
2841  * The underlying problem is that xmlRemoveID is only called
2842  * if a node is destroyed, not if it's unlinked.
2843  */
2844 #if 0
2845  if (xmlIsID(doc, tree, prop)) {
2846  xmlChar *idVal = xmlNodeListGetString(doc, prop->children,
2847  1);
2848  xmlAddID(NULL, doc, idVal, prop);
2849  }
2850 #endif
2851 
2852  prop = prop->next;
2853  }
2854  }
2855  if (tree->children != NULL)
2856  xmlSetListDoc(tree->children, doc);
2857  tree->doc = doc;
2858  }
2859 }
2860 
2868 void
2870  xmlNodePtr cur;
2871 
2872  if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
2873  return;
2874  cur = list;
2875  while (cur != NULL) {
2876  if (cur->doc != doc)
2877  xmlSetTreeDoc(cur, doc);
2878  cur = cur->next;
2879  }
2880 }
2881 
2882 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
2883 
2900 xmlNodePtr
2901 xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2902  const xmlChar *name, const xmlChar *content) {
2903  xmlNodePtr cur, prev;
2904 
2905  if (parent == NULL) {
2906 #ifdef DEBUG_TREE
2908  "xmlNewChild : parent == NULL\n");
2909 #endif
2910  return(NULL);
2911  }
2912 
2913  if (name == NULL) {
2914 #ifdef DEBUG_TREE
2916  "xmlNewChild : name == NULL\n");
2917 #endif
2918  return(NULL);
2919  }
2920 
2921  /*
2922  * Allocate a new node
2923  */
2924  if (parent->type == XML_ELEMENT_NODE) {
2925  if (ns == NULL)
2926  cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2927  else
2928  cur = xmlNewDocNode(parent->doc, ns, name, content);
2929  } else if ((parent->type == XML_DOCUMENT_NODE) ||
2930  (parent->type == XML_HTML_DOCUMENT_NODE)) {
2931  if (ns == NULL)
2933  else
2935  } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2936  cur = xmlNewDocNode( parent->doc, ns, name, content);
2937  } else {
2938  return(NULL);
2939  }
2940  if (cur == NULL) return(NULL);
2941 
2942  /*
2943  * add the new element at the end of the children list.
2944  */
2945  cur->type = XML_ELEMENT_NODE;
2946  cur->parent = parent;
2947  cur->doc = parent->doc;
2948  if (parent->children == NULL) {
2949  parent->children = cur;
2950  parent->last = cur;
2951  } else {
2952  prev = parent->last;
2953  prev->next = cur;
2954  cur->prev = prev;
2955  parent->last = cur;
2956  }
2957 
2958  return(cur);
2959 }
2960 #endif /* LIBXML_TREE_ENABLED */
2961 
2975 static xmlNodePtr
2976 xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2977  xmlAttrPtr attr;
2978 
2979  if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) ||
2980  (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) ||
2981  ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)))
2982  return(NULL);
2983 
2984  /* check if an attribute with the same name exists */
2985  if (prop->ns == NULL)
2986  attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2987  else
2988  attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2989 
2990  if (prop->doc != cur->doc) {
2991  xmlSetTreeDoc(prop, cur->doc);
2992  }
2993  prop->parent = cur->parent;
2994  prop->prev = prev;
2995  if (prev != NULL) {
2996  prop->next = prev->next;
2997  prev->next = prop;
2998  if (prop->next)
2999  prop->next->prev = prop;
3000  } else {
3001  prop->next = cur;
3002  cur->prev = prop;
3003  }
3004  if (prop->prev == NULL && prop->parent != NULL)
3005  prop->parent->properties = (xmlAttrPtr) prop;
3006  if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
3007  /* different instance, destroy it (attributes must be unique) */
3009  }
3010  return prop;
3011 }
3012 
3027 xmlNodePtr
3029  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3030 #ifdef DEBUG_TREE
3032  "xmlAddNextSibling : cur == NULL\n");
3033 #endif
3034  return(NULL);
3035  }
3036  if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3037 #ifdef DEBUG_TREE
3039  "xmlAddNextSibling : elem == NULL\n");
3040 #endif
3041  return(NULL);
3042  }
3043 
3044  if (cur == elem) {
3045 #ifdef DEBUG_TREE
3047  "xmlAddNextSibling : cur == elem\n");
3048 #endif
3049  return(NULL);
3050  }
3051 
3053 
3054  if (elem->type == XML_TEXT_NODE) {
3055  if (cur->type == XML_TEXT_NODE) {
3056  xmlNodeAddContent(cur, elem->content);
3057  xmlFreeNode(elem);
3058  return(cur);
3059  }
3060  if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
3061  (cur->name == cur->next->name)) {
3062  xmlChar *tmp;
3063 
3064  tmp = xmlStrdup(elem->content);
3065  tmp = xmlStrcat(tmp, cur->next->content);
3066  xmlNodeSetContent(cur->next, tmp);
3067  xmlFree(tmp);
3068  xmlFreeNode(elem);
3069  return(cur->next);
3070  }
3071  } else if (elem->type == XML_ATTRIBUTE_NODE) {
3072  return xmlAddPropSibling(cur, cur, elem);
3073  }
3074 
3075  if (elem->doc != cur->doc) {
3076  xmlSetTreeDoc(elem, cur->doc);
3077  }
3078  elem->parent = cur->parent;
3079  elem->prev = cur;
3080  elem->next = cur->next;
3081  cur->next = elem;
3082  if (elem->next != NULL)
3083  elem->next->prev = elem;
3084  if ((elem->parent != NULL) && (elem->parent->last == cur))
3085  elem->parent->last = elem;
3086  return(elem);
3087 }
3088 
3089 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
3090  defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
3091 
3105 xmlNodePtr
3106 xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
3107  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3108 #ifdef DEBUG_TREE
3110  "xmlAddPrevSibling : cur == NULL\n");
3111 #endif
3112  return(NULL);
3113  }
3114  if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3115 #ifdef DEBUG_TREE
3117  "xmlAddPrevSibling : elem == NULL\n");
3118 #endif
3119  return(NULL);
3120  }
3121 
3122  if (cur == elem) {
3123 #ifdef DEBUG_TREE
3125  "xmlAddPrevSibling : cur == elem\n");
3126 #endif
3127  return(NULL);
3128  }
3129 
3131 
3132  if (elem->type == XML_TEXT_NODE) {
3133  if (cur->type == XML_TEXT_NODE) {
3134  xmlChar *tmp;
3135 
3136  tmp = xmlStrdup(elem->content);
3137  tmp = xmlStrcat(tmp, cur->content);
3138  xmlNodeSetContent(cur, tmp);
3139  xmlFree(tmp);
3140  xmlFreeNode(elem);
3141  return(cur);
3142  }
3143  if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3144  (cur->name == cur->prev->name)) {
3145  xmlNodeAddContent(cur->prev, elem->content);
3146  xmlFreeNode(elem);
3147  return(cur->prev);
3148  }
3149  } else if (elem->type == XML_ATTRIBUTE_NODE) {
3150  return xmlAddPropSibling(cur->prev, cur, elem);
3151  }
3152 
3153  if (elem->doc != cur->doc) {
3154  xmlSetTreeDoc(elem, cur->doc);
3155  }
3156  elem->parent = cur->parent;
3157  elem->next = cur;
3158  elem->prev = cur->prev;
3159  cur->prev = elem;
3160  if (elem->prev != NULL)
3161  elem->prev->next = elem;
3162  if ((elem->parent != NULL) && (elem->parent->children == cur)) {
3163  elem->parent->children = elem;
3164  }
3165  return(elem);
3166 }
3167 #endif /* LIBXML_TREE_ENABLED */
3168 
3181 xmlNodePtr
3184 
3185  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3186 #ifdef DEBUG_TREE
3188  "xmlAddSibling : cur == NULL\n");
3189 #endif
3190  return(NULL);
3191  }
3192 
3193  if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3194 #ifdef DEBUG_TREE
3196  "xmlAddSibling : elem == NULL\n");
3197 #endif
3198  return(NULL);
3199  }
3200 
3201  if (cur == elem) {
3202 #ifdef DEBUG_TREE
3204  "xmlAddSibling : cur == elem\n");
3205 #endif
3206  return(NULL);
3207  }
3208 
3209  /*
3210  * Constant time is we can rely on the ->parent->last to find
3211  * the last sibling.
3212  */
3213  if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
3214  (cur->parent->children != NULL) &&
3215  (cur->parent->last != NULL) &&
3216  (cur->parent->last->next == NULL)) {
3217  cur = cur->parent->last;
3218  } else {
3219  while (cur->next != NULL) cur = cur->next;
3220  }
3221 
3223 
3224  if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3225  (cur->name == elem->name)) {
3226  xmlNodeAddContent(cur, elem->content);
3227  xmlFreeNode(elem);
3228  return(cur);
3229  } else if (elem->type == XML_ATTRIBUTE_NODE) {
3230  return xmlAddPropSibling(cur, cur, elem);
3231  }
3232 
3233  if (elem->doc != cur->doc) {
3234  xmlSetTreeDoc(elem, cur->doc);
3235  }
3236  parent = cur->parent;
3237  elem->prev = cur;
3238  elem->next = NULL;
3239  elem->parent = parent;
3240  cur->next = elem;
3241  if (parent != NULL)
3242  parent->last = elem;
3243 
3244  return(elem);
3245 }
3246 
3257 xmlNodePtr
3259  xmlNodePtr prev;
3260 
3261  if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3262 #ifdef DEBUG_TREE
3264  "xmlAddChildList : parent == NULL\n");
3265 #endif
3266  return(NULL);
3267  }
3268 
3269  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3270 #ifdef DEBUG_TREE
3272  "xmlAddChildList : child == NULL\n");
3273 #endif
3274  return(NULL);
3275  }
3276 
3277  if ((cur->doc != NULL) && (parent->doc != NULL) &&
3278  (cur->doc != parent->doc)) {
3279 #ifdef DEBUG_TREE
3281  "Elements moved to a different document\n");
3282 #endif
3283  }
3284 
3285  /*
3286  * add the first element at the end of the children list.
3287  */
3288 
3289  if (parent->children == NULL) {
3290  parent->children = cur;
3291  } else {
3292  /*
3293  * If cur and parent->last both are TEXT nodes, then merge them.
3294  */
3295  if ((cur->type == XML_TEXT_NODE) &&
3296  (parent->last->type == XML_TEXT_NODE) &&
3297  (cur->name == parent->last->name)) {
3298  xmlNodeAddContent(parent->last, cur->content);
3299  /*
3300  * if it's the only child, nothing more to be done.
3301  */
3302  if (cur->next == NULL) {
3303  xmlFreeNode(cur);
3304  return(parent->last);
3305  }
3306  prev = cur;
3307  cur = cur->next;
3308  xmlFreeNode(prev);
3309  }
3310  prev = parent->last;
3311  prev->next = cur;
3312  cur->prev = prev;
3313  }
3314  while (cur->next != NULL) {
3315  cur->parent = parent;
3316  if (cur->doc != parent->doc) {
3317  xmlSetTreeDoc(cur, parent->doc);
3318  }
3319  cur = cur->next;
3320  }
3321  cur->parent = parent;
3322  /* the parent may not be linked to a doc ! */
3323  if (cur->doc != parent->doc) {
3324  xmlSetTreeDoc(cur, parent->doc);
3325  }
3326  parent->last = cur;
3327 
3328  return(cur);
3329 }
3330 
3343 xmlNodePtr
3345  xmlNodePtr prev;
3346 
3347  if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3348 #ifdef DEBUG_TREE
3350  "xmlAddChild : parent == NULL\n");
3351 #endif
3352  return(NULL);
3353  }
3354 
3355  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3356 #ifdef DEBUG_TREE
3358  "xmlAddChild : child == NULL\n");
3359 #endif
3360  return(NULL);
3361  }
3362 
3363  if (parent == cur) {
3364 #ifdef DEBUG_TREE
3366  "xmlAddChild : parent == cur\n");
3367 #endif
3368  return(NULL);
3369  }
3370  /*
3371  * If cur is a TEXT node, merge its content with adjacent TEXT nodes
3372  * cur is then freed.
3373  */
3374  if (cur->type == XML_TEXT_NODE) {
3375  if ((parent->type == XML_TEXT_NODE) &&
3376  (parent->content != NULL) &&
3377  (parent->name == cur->name)) {
3378  xmlNodeAddContent(parent, cur->content);
3379  xmlFreeNode(cur);
3380  return(parent);
3381  }
3382  if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
3383  (parent->last->name == cur->name) &&
3384  (parent->last != cur)) {
3385  xmlNodeAddContent(parent->last, cur->content);
3386  xmlFreeNode(cur);
3387  return(parent->last);
3388  }
3389  }
3390 
3391  /*
3392  * add the new element at the end of the children list.
3393  */
3394  prev = cur->parent;
3395  cur->parent = parent;
3396  if (cur->doc != parent->doc) {
3397  xmlSetTreeDoc(cur, parent->doc);
3398  }
3399  /* this check prevents a loop on tree-traversions if a developer
3400  * tries to add a node to its parent multiple times
3401  */
3402  if (prev == parent)
3403  return(cur);
3404 
3405  /*
3406  * Coalescing
3407  */
3408  if ((parent->type == XML_TEXT_NODE) &&
3409  (parent->content != NULL) &&
3410  (parent != cur)) {
3411  xmlNodeAddContent(parent, cur->content);
3412  xmlFreeNode(cur);
3413  return(parent);
3414  }
3415  if (cur->type == XML_ATTRIBUTE_NODE) {
3416  if (parent->type != XML_ELEMENT_NODE)
3417  return(NULL);
3418  if (parent->properties != NULL) {
3419  /* check if an attribute with the same name exists */
3420  xmlAttrPtr lastattr;
3421 
3422  if (cur->ns == NULL)
3423  lastattr = xmlHasNsProp(parent, cur->name, NULL);
3424  else
3425  lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3426  if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
3427  /* different instance, destroy it (attributes must be unique) */
3428  xmlUnlinkNode((xmlNodePtr) lastattr);
3429  xmlFreeProp(lastattr);
3430  }
3431  if (lastattr == (xmlAttrPtr) cur)
3432  return(cur);
3433 
3434  }
3435  if (parent->properties == NULL) {
3436  parent->properties = (xmlAttrPtr) cur;
3437  } else {
3438  /* find the end */
3439  xmlAttrPtr lastattr = parent->properties;
3440  while (lastattr->next != NULL) {
3441  lastattr = lastattr->next;
3442  }
3443  lastattr->next = (xmlAttrPtr) cur;
3444  ((xmlAttrPtr) cur)->prev = lastattr;
3445  }
3446  } else {
3447  if (parent->children == NULL) {
3448  parent->children = cur;
3449  parent->last = cur;
3450  } else {
3451  prev = parent->last;
3452  prev->next = cur;
3453  cur->prev = prev;
3454  parent->last = cur;
3455  }
3456  }
3457  return(cur);
3458 }
3459 
3467 xmlNodePtr
3468 xmlGetLastChild(const xmlNode *parent) {
3469  if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3470 #ifdef DEBUG_TREE
3472  "xmlGetLastChild : parent == NULL\n");
3473 #endif
3474  return(NULL);
3475  }
3476  return(parent->last);
3477 }
3478 
3479 #ifdef LIBXML_TREE_ENABLED
3480 /*
3481  * 5 interfaces from DOM ElementTraversal
3482  */
3483 
3496 unsigned long
3497 xmlChildElementCount(xmlNodePtr parent) {
3498  unsigned long ret = 0;
3499  xmlNodePtr cur = NULL;
3500 
3501  if (parent == NULL)
3502  return(0);
3503  switch (parent->type) {
3504  case XML_ELEMENT_NODE:
3505  case XML_ENTITY_NODE:
3506  case XML_DOCUMENT_NODE:
3509  cur = parent->children;
3510  break;
3511  default:
3512  return(0);
3513  }
3514  while (cur != NULL) {
3515  if (cur->type == XML_ELEMENT_NODE)
3516  ret++;
3517  cur = cur->next;
3518  }
3519  return(ret);
3520 }
3521 
3533 xmlNodePtr
3534 xmlFirstElementChild(xmlNodePtr parent) {
3535  xmlNodePtr cur = NULL;
3536 
3537  if (parent == NULL)
3538  return(NULL);
3539  switch (parent->type) {
3540  case XML_ELEMENT_NODE:
3541  case XML_ENTITY_NODE:
3542  case XML_DOCUMENT_NODE:
3545  cur = parent->children;
3546  break;
3547  default:
3548  return(NULL);
3549  }
3550  while (cur != NULL) {
3551  if (cur->type == XML_ELEMENT_NODE)
3552  return(cur);
3553  cur = cur->next;
3554  }
3555  return(NULL);
3556 }
3557 
3569 xmlNodePtr
3570 xmlLastElementChild(xmlNodePtr parent) {
3571  xmlNodePtr cur = NULL;
3572 
3573  if (parent == NULL)
3574  return(NULL);
3575  switch (parent->type) {
3576  case XML_ELEMENT_NODE:
3577  case XML_ENTITY_NODE:
3578  case XML_DOCUMENT_NODE:
3581  cur = parent->last;
3582  break;
3583  default:
3584  return(NULL);
3585  }
3586  while (cur != NULL) {
3587  if (cur->type == XML_ELEMENT_NODE)
3588  return(cur);
3589  cur = cur->prev;
3590  }
3591  return(NULL);
3592 }
3593 
3606 xmlNodePtr
3607 xmlPreviousElementSibling(xmlNodePtr node) {
3608  if (node == NULL)
3609  return(NULL);
3610  switch (node->type) {
3611  case XML_ELEMENT_NODE:
3612  case XML_TEXT_NODE:
3614  case XML_ENTITY_REF_NODE:
3615  case XML_ENTITY_NODE:
3616  case XML_PI_NODE:
3617  case XML_COMMENT_NODE:
3618  case XML_XINCLUDE_START:
3619  case XML_XINCLUDE_END:
3620  node = node->prev;
3621  break;
3622  default:
3623  return(NULL);
3624  }
3625  while (node != NULL) {
3626  if (node->type == XML_ELEMENT_NODE)
3627  return(node);
3628  node = node->prev;
3629  }
3630  return(NULL);
3631 }
3632 
3645 xmlNodePtr
3646 xmlNextElementSibling(xmlNodePtr node) {
3647  if (node == NULL)
3648  return(NULL);
3649  switch (node->type) {
3650  case XML_ELEMENT_NODE:
3651  case XML_TEXT_NODE:
3653  case XML_ENTITY_REF_NODE:
3654  case XML_ENTITY_NODE:
3655  case XML_PI_NODE:
3656  case XML_COMMENT_NODE:
3657  case XML_DTD_NODE:
3658  case XML_XINCLUDE_START:
3659  case XML_XINCLUDE_END:
3660  node = node->next;
3661  break;
3662  default:
3663  return(NULL);
3664  }
3665  while (node != NULL) {
3666  if (node->type == XML_ELEMENT_NODE)
3667  return(node);
3668  node = node->next;
3669  }
3670  return(NULL);
3671 }
3672 
3673 #endif /* LIBXML_TREE_ENABLED */
3674 
3682 void
3684  xmlNodePtr next;
3686  xmlDictPtr dict = NULL;
3687  size_t depth = 0;
3688 
3689  if (cur == NULL) return;
3690  if (cur->type == XML_NAMESPACE_DECL) {
3692  return;
3693  }
3694  if ((cur->type == XML_DOCUMENT_NODE) ||
3695 #ifdef LIBXML_DOCB_ENABLED
3696  (cur->type == XML_DOCB_DOCUMENT_NODE) ||
3697 #endif
3698  (cur->type == XML_HTML_DOCUMENT_NODE)) {
3700  return;
3701  }
3702  if (cur->doc != NULL) dict = cur->doc->dict;
3703  while (1) {
3704  while ((cur->children != NULL) &&
3705  (cur->type != XML_DTD_NODE) &&
3706  (cur->type != XML_ENTITY_REF_NODE)) {
3707  cur = cur->children;
3708  depth += 1;
3709  }
3710 
3711  next = cur->next;
3712  parent = cur->parent;
3713  if (cur->type != XML_DTD_NODE) {
3714 
3717 
3718  if (((cur->type == XML_ELEMENT_NODE) ||
3719  (cur->type == XML_XINCLUDE_START) ||
3720  (cur->type == XML_XINCLUDE_END)) &&
3721  (cur->properties != NULL))
3722  xmlFreePropList(cur->properties);
3723  if ((cur->type != XML_ELEMENT_NODE) &&
3724  (cur->type != XML_XINCLUDE_START) &&
3725  (cur->type != XML_XINCLUDE_END) &&
3726  (cur->type != XML_ENTITY_REF_NODE) &&
3727  (cur->type != XML_DOCUMENT_NODE) &&
3728 #ifdef LIBXML_DOCB_ENABLED
3729  (cur->type != XML_DOCB_DOCUMENT_NODE) &&
3730 #endif
3731  (cur->type != XML_HTML_DOCUMENT_NODE) &&
3732  (cur->content != (xmlChar *) &(cur->properties))) {
3733  DICT_FREE(cur->content)
3734  }
3735  if (((cur->type == XML_ELEMENT_NODE) ||
3736  (cur->type == XML_XINCLUDE_START) ||
3737  (cur->type == XML_XINCLUDE_END)) &&
3738  (cur->nsDef != NULL))
3739  xmlFreeNsList(cur->nsDef);
3740 
3741  /*
3742  * When a node is a text node or a comment, it uses a global static
3743  * variable for the name of the node.
3744  * Otherwise the node name might come from the document's
3745  * dictionary
3746  */
3747  if ((cur->name != NULL) &&
3748  (cur->type != XML_TEXT_NODE) &&
3749  (cur->type != XML_COMMENT_NODE))
3750  DICT_FREE(cur->name)
3751  xmlFree(cur);
3752  }
3753 
3754  if (next != NULL) {
3755  cur = next;
3756  } else {
3757  if ((depth == 0) || (parent == NULL))
3758  break;
3759  depth -= 1;
3760  cur = parent;
3761  cur->children = NULL;
3762  }
3763  }
3764 }
3765 
3773 void
3775  xmlDictPtr dict = NULL;
3776 
3777  if (cur == NULL) return;
3778 
3779  /* use xmlFreeDtd for DTD nodes */
3780  if (cur->type == XML_DTD_NODE) {
3782  return;
3783  }
3784  if (cur->type == XML_NAMESPACE_DECL) {
3785  xmlFreeNs((xmlNsPtr) cur);
3786  return;
3787  }
3788  if (cur->type == XML_ATTRIBUTE_NODE) {
3790  return;
3791  }
3792 
3795 
3796  if (cur->doc != NULL) dict = cur->doc->dict;
3797 
3798  if (cur->type == XML_ENTITY_DECL) {
3799  xmlEntityPtr ent = (xmlEntityPtr) cur;
3800  DICT_FREE(ent->SystemID);
3801  DICT_FREE(ent->ExternalID);
3802  }
3803  if ((cur->children != NULL) &&
3804  (cur->type != XML_ENTITY_REF_NODE))
3805  xmlFreeNodeList(cur->children);
3806  if (((cur->type == XML_ELEMENT_NODE) ||
3807  (cur->type == XML_XINCLUDE_START) ||
3808  (cur->type == XML_XINCLUDE_END)) &&
3809  (cur->properties != NULL))
3810  xmlFreePropList(cur->properties);
3811  if ((cur->type != XML_ELEMENT_NODE) &&
3812  (cur->content != NULL) &&
3813  (cur->type != XML_ENTITY_REF_NODE) &&
3814  (cur->type != XML_XINCLUDE_END) &&
3815  (cur->type != XML_XINCLUDE_START) &&
3816  (cur->content != (xmlChar *) &(cur->properties))) {
3817  DICT_FREE(cur->content)
3818  }
3819 
3820  /*
3821  * When a node is a text node or a comment, it uses a global static
3822  * variable for the name of the node.
3823  * Otherwise the node name might come from the document's dictionary
3824  */
3825  if ((cur->name != NULL) &&
3826  (cur->type != XML_TEXT_NODE) &&
3827  (cur->type != XML_COMMENT_NODE))
3828  DICT_FREE(cur->name)
3829 
3830  if (((cur->type == XML_ELEMENT_NODE) ||
3831  (cur->type == XML_XINCLUDE_START) ||
3832  (cur->type == XML_XINCLUDE_END)) &&
3833  (cur->nsDef != NULL))
3834  xmlFreeNsList(cur->nsDef);
3835  xmlFree(cur);
3836 }
3837 
3848 void
3850  if (cur == NULL) {
3851 #ifdef DEBUG_TREE
3853  "xmlUnlinkNode : node == NULL\n");
3854 #endif
3855  return;
3856  }
3857  if (cur->type == XML_NAMESPACE_DECL)
3858  return;
3859  if (cur->type == XML_DTD_NODE) {
3860  xmlDocPtr doc;
3861  doc = cur->doc;
3862  if (doc != NULL) {
3863  if (doc->intSubset == (xmlDtdPtr) cur)
3864  doc->intSubset = NULL;
3865  if (doc->extSubset == (xmlDtdPtr) cur)
3866  doc->extSubset = NULL;
3867  }
3868  }
3869  if (cur->type == XML_ENTITY_DECL) {
3870  xmlDocPtr doc;
3871  doc = cur->doc;
3872  if (doc != NULL) {
3873  if (doc->intSubset != NULL) {
3874  if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3875  xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3876  NULL);
3877  if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3878  xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3879  NULL);
3880  }
3881  if (doc->extSubset != NULL) {
3882  if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3883  xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3884  NULL);
3885  if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3886  xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3887  NULL);
3888  }
3889  }
3890  }
3891  if (cur->parent != NULL) {
3893  parent = cur->parent;
3894  if (cur->type == XML_ATTRIBUTE_NODE) {
3895  if (parent->properties == (xmlAttrPtr) cur)
3896  parent->properties = ((xmlAttrPtr) cur)->next;
3897  } else {
3898  if (parent->children == cur)
3899  parent->children = cur->next;
3900  if (parent->last == cur)
3901  parent->last = cur->prev;
3902  }
3903  cur->parent = NULL;
3904  }
3905  if (cur->next != NULL)
3906  cur->next->prev = cur->prev;
3907  if (cur->prev != NULL)
3908  cur->prev->next = cur->next;
3909  cur->next = cur->prev = NULL;
3910 }
3911 
3912 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
3913 
3924 xmlNodePtr
3925 xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3926  if (old == cur) return(NULL);
3927  if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) ||
3928  (old->parent == NULL)) {
3929 #ifdef DEBUG_TREE
3931  "xmlReplaceNode : old == NULL or without parent\n");
3932 #endif
3933  return(NULL);
3934  }
3935  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3936  xmlUnlinkNode(old);
3937  return(old);
3938  }
3939  if (cur == old) {
3940  return(old);
3941  }
3942  if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3943 #ifdef DEBUG_TREE
3945  "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3946 #endif
3947  return(old);
3948  }
3949  if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3950 #ifdef DEBUG_TREE
3952  "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3953 #endif
3954  return(old);
3955  }
3956  xmlUnlinkNode(cur);
3957  xmlSetTreeDoc(cur, old->doc);
3958  cur->parent = old->parent;
3959  cur->next = old->next;
3960  if (cur->next != NULL)
3961  cur->next->prev = cur;
3962  cur->prev = old->prev;
3963  if (cur->prev != NULL)
3964  cur->prev->next = cur;
3965  if (cur->parent != NULL) {
3966  if (cur->type == XML_ATTRIBUTE_NODE) {
3967  if (cur->parent->properties == (xmlAttrPtr)old)
3968  cur->parent->properties = ((xmlAttrPtr) cur);
3969  } else {
3970  if (cur->parent->children == old)
3971  cur->parent->children = cur;
3972  if (cur->parent->last == old)
3973  cur->parent->last = cur;
3974  }
3975  }
3976  old->next = old->prev = NULL;
3977  old->parent = NULL;
3978  return(old);
3979 }
3980 #endif /* LIBXML_TREE_ENABLED */
3981 
3982 /************************************************************************
3983  * *
3984  * Copy operations *
3985  * *
3986  ************************************************************************/
3987 
3996 xmlNsPtr
3998  xmlNsPtr ret;
3999 
4000  if (cur == NULL) return(NULL);
4001  switch (cur->type) {
4002  case XML_LOCAL_NAMESPACE:
4003  ret = xmlNewNs(NULL, cur->href, cur->prefix);
4004  break;
4005  default:
4006 #ifdef DEBUG_TREE
4008  "xmlCopyNamespace: invalid type %d\n", cur->type);
4009 #endif
4010  return(NULL);
4011  }
4012  return(ret);
4013 }
4014 
4023 xmlNsPtr
4025  xmlNsPtr ret = NULL;
4026  xmlNsPtr p = NULL,q;
4027 
4028  while (cur != NULL) {
4029  q = xmlCopyNamespace(cur);
4030  if (p == NULL) {
4031  ret = p = q;
4032  } else {
4033  p->next = q;
4034  p = q;
4035  }
4036  cur = cur->next;
4037  }
4038  return(ret);
4039 }
4040 
4041 static xmlNodePtr
4042 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
4043 
4044 static xmlAttrPtr
4045 xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
4046  xmlAttrPtr ret;
4047 
4048  if (cur == NULL) return(NULL);
4049  if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4050  return(NULL);
4051  if (target != NULL)
4052  ret = xmlNewDocProp(target->doc, cur->name, NULL);
4053  else if (doc != NULL)
4054  ret = xmlNewDocProp(doc, cur->name, NULL);
4055  else if (cur->parent != NULL)
4056  ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
4057  else if (cur->children != NULL)
4058  ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
4059  else
4060  ret = xmlNewDocProp(NULL, cur->name, NULL);
4061  if (ret == NULL) return(NULL);
4062  ret->parent = target;
4063 
4064  if ((cur->ns != NULL) && (target != NULL)) {
4065  xmlNsPtr ns;
4066 
4067  ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
4068  if (ns == NULL) {
4069  /*
4070  * Humm, we are copying an element whose namespace is defined
4071  * out of the new tree scope. Search it in the original tree
4072  * and add it at the top of the new tree
4073  */
4074  ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
4075  if (ns != NULL) {
4077  xmlNodePtr pred = NULL;
4078 
4079  while (root->parent != NULL) {
4080  pred = root;
4081  root = root->parent;
4082  }
4083  if (root == (xmlNodePtr) target->doc) {
4084  /* correct possibly cycling above the document elt */
4085  root = pred;
4086  }
4087  ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4088  }
4089  } else {
4090  /*
4091  * we have to find something appropriate here since
4092  * we can't be sure, that the namespace we found is identified
4093  * by the prefix
4094  */
4095  if (xmlStrEqual(ns->href, cur->ns->href)) {
4096  /* this is the nice case */
4097  ret->ns = ns;
4098  } else {
4099  /*
4100  * we are in trouble: we need a new reconciled namespace.
4101  * This is expensive
4102  */
4103  ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns);
4104  }
4105  }
4106 
4107  } else
4108  ret->ns = NULL;
4109 
4110  if (cur->children != NULL) {
4111  xmlNodePtr tmp;
4112 
4113  ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4114  ret->last = NULL;
4115  tmp = ret->children;
4116  while (tmp != NULL) {
4117  /* tmp->parent = (xmlNodePtr)ret; */
4118  if (tmp->next == NULL)
4119  ret->last = tmp;
4120  tmp = tmp->next;
4121  }
4122  }
4123  /*
4124  * Try to handle IDs
4125  */
4126  if ((target!= NULL) && (cur!= NULL) &&
4127  (target->doc != NULL) && (cur->doc != NULL) &&
4128  (cur->doc->ids != NULL) && (cur->parent != NULL)) {
4129  if (xmlIsID(cur->doc, cur->parent, cur)) {
4130  xmlChar *id;
4131 
4132  id = xmlNodeListGetString(cur->doc, cur->children, 1);
4133  if (id != NULL) {
4134  xmlAddID(NULL, target->doc, id, ret);
4135  xmlFree(id);
4136  }
4137  }
4138  }
4139  return(ret);
4140 }
4141 
4151 xmlAttrPtr
4153  return xmlCopyPropInternal(NULL, target, cur);
4154 }
4155 
4165 xmlAttrPtr
4167  xmlAttrPtr ret = NULL;
4168  xmlAttrPtr p = NULL,q;
4169 
4170  if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4171  return(NULL);
4172  while (cur != NULL) {
4173  q = xmlCopyProp(target, cur);
4174  if (q == NULL)
4175  return(NULL);
4176  if (p == NULL) {
4177  ret = p = q;
4178  } else {
4179  p->next = q;
4180  q->prev = p;
4181  p = q;
4182  }
4183  cur = cur->next;
4184  }
4185  return(ret);
4186 }
4187 
4188 /*
4189  * NOTE about the CopyNode operations !
4190  *
4191  * They are split into external and internal parts for one
4192  * tricky reason: namespaces. Doing a direct copy of a node
4193  * say RPM:Copyright without changing the namespace pointer to
4194  * something else can produce stale links. One way to do it is
4195  * to keep a reference counter but this doesn't work as soon
4196  * as one moves the element or the subtree out of the scope of
4197  * the existing namespace. The actual solution seems to be to add
4198  * a copy of the namespace at the top of the copied tree if
4199  * not available in the subtree.
4200  * Hence two functions, the public front-end call the inner ones
4201  * The argument "recursive" normally indicates a recursive copy
4202  * of the node with values 0 (no) and 1 (yes). For XInclude,
4203  * however, we allow a value of 2 to indicate copy properties and
4204  * namespace info, but don't recurse on children.
4205  */
4206 
4207 static xmlNodePtr
4208 xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
4209  int extended) {
4210  xmlNodePtr ret;
4211 
4212  if (node == NULL) return(NULL);
4213  switch (node->type) {
4214  case XML_TEXT_NODE:
4216  case XML_ELEMENT_NODE:
4218  case XML_ENTITY_REF_NODE:
4219  case XML_ENTITY_NODE:
4220  case XML_PI_NODE:
4221  case XML_COMMENT_NODE:
4222  case XML_XINCLUDE_START:
4223  case XML_XINCLUDE_END:
4224  break;
4225  case XML_ATTRIBUTE_NODE:
4226  return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
4227  case XML_NAMESPACE_DECL:
4229 
4230  case XML_DOCUMENT_NODE:
4232 #ifdef LIBXML_DOCB_ENABLED
4233  case XML_DOCB_DOCUMENT_NODE:
4234 #endif
4235 #ifdef LIBXML_TREE_ENABLED
4236  return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
4237 #endif /* LIBXML_TREE_ENABLED */
4239  case XML_NOTATION_NODE:
4240  case XML_DTD_NODE:
4241  case XML_ELEMENT_DECL:
4242  case XML_ATTRIBUTE_DECL:
4243  case XML_ENTITY_DECL:
4244  return(NULL);
4245  }
4246 
4247  /*
4248  * Allocate a new node and fill the fields.
4249  */
4250  ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4251  if (ret == NULL) {
4252  xmlTreeErrMemory("copying node");
4253  return(NULL);
4254  }
4255  memset(ret, 0, sizeof(xmlNode));
4256  ret->type = node->type;
4257 
4258  ret->doc = doc;
4259  ret->parent = parent;
4260  if (node->name == xmlStringText)
4261  ret->name = xmlStringText;
4262  else if (node->name == xmlStringTextNoenc)
4263  ret->name = xmlStringTextNoenc;
4264  else if (node->name == xmlStringComment)
4265  ret->name = xmlStringComment;
4266  else if (node->name != NULL) {
4267  if ((doc != NULL) && (doc->dict != NULL))
4268  ret->name = xmlDictLookup(doc->dict, node->name, -1);
4269  else
4270  ret->name = xmlStrdup(node->name);
4271  }
4272  if ((node->type != XML_ELEMENT_NODE) &&
4273  (node->content != NULL) &&
4274  (node->type != XML_ENTITY_REF_NODE) &&
4275  (node->type != XML_XINCLUDE_END) &&
4276  (node->type != XML_XINCLUDE_START)) {
4277  ret->content = xmlStrdup(node->content);
4278  }else{
4279  if (node->type == XML_ELEMENT_NODE)
4280  ret->line = node->line;
4281  }
4282  if (parent != NULL) {
4283  xmlNodePtr tmp;
4284 
4285  /*
4286  * this is a tricky part for the node register thing:
4287  * in case ret does get coalesced in xmlAddChild
4288  * the deregister-node callback is called; so we register ret now already
4289  */
4292 
4293  tmp = xmlAddChild(parent, ret);
4294  /* node could have coalesced */
4295  if (tmp != ret)
4296  return(tmp);
4297  }
4298 
4299  if (!extended)
4300  goto out;
4301  if (((node->type == XML_ELEMENT_NODE) ||
4302  (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
4303  ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4304 
4305  if (node->ns != NULL) {
4306  xmlNsPtr ns;
4307 
4308  ns = xmlSearchNs(doc, ret, node->ns->prefix);
4309  if (ns == NULL) {
4310  /*
4311  * Humm, we are copying an element whose namespace is defined
4312  * out of the new tree scope. Search it in the original tree
4313  * and add it at the top of the new tree
4314  */
4315  ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4316  if (ns != NULL) {
4317  xmlNodePtr root = ret;
4318 
4319  while (root->parent != NULL) root = root->parent;
4320  ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4321  } else {
4322  ret->ns = xmlNewReconciledNs(doc, ret, node->ns);
4323  }
4324  } else {
4325  /*
4326  * reference the existing namespace definition in our own tree.
4327  */
4328  ret->ns = ns;
4329  }
4330  }
4331  if (((node->type == XML_ELEMENT_NODE) ||
4332  (node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
4333  ret->properties = xmlCopyPropList(ret, node->properties);
4334  if (node->type == XML_ENTITY_REF_NODE) {
4335  if ((doc == NULL) || (node->doc != doc)) {
4336  /*
4337  * The copied node will go into a separate document, so
4338  * to avoid dangling references to the ENTITY_DECL node
4339  * we cannot keep the reference. Try to find it in the
4340  * target document.
4341  */
4342  ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4343  } else {
4344  ret->children = node->children;
4345  }
4346  ret->last = ret->children;
4347  } else if ((node->children != NULL) && (extended != 2)) {
4348  ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
4350  }
4351 
4352 out:
4353  /* if parent != NULL we already registered the node above */
4354  if ((parent == NULL) &&
4357  return(ret);
4358 }
4359 
4360 static xmlNodePtr
4361 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4362  xmlNodePtr ret = NULL;
4363  xmlNodePtr p = NULL,q;
4364 
4365  while (node != NULL) {
4366 #ifdef LIBXML_TREE_ENABLED
4367  if (node->type == XML_DTD_NODE ) {
4368  if (doc == NULL) {
4369  node = node->next;
4370  continue;
4371  }
4372  if (doc->intSubset == NULL) {
4373  q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4374  if (q == NULL) return(NULL);
4375  q->doc = doc;
4376  q->parent = parent;
4377  doc->intSubset = (xmlDtdPtr) q;
4378  xmlAddChild(parent, q);
4379  } else {
4380  q = (xmlNodePtr) doc->intSubset;
4381  xmlAddChild(parent, q);
4382  }
4383  } else
4384 #endif /* LIBXML_TREE_ENABLED */
4385  q = xmlStaticCopyNode(node, doc, parent, 1);
4386  if (q == NULL) return(NULL);
4387  if (ret == NULL) {
4388  q->prev = NULL;
4389  ret = p = q;
4390  } else if (p != q) {
4391  /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
4392  p->next = q;
4393  q->prev = p;
4394  p = q;
4395  }
4396  node = node->next;
4397  }
4398  return(ret);
4399 }
4400 
4412 xmlNodePtr
4413 xmlCopyNode(xmlNodePtr node, int extended) {
4414  xmlNodePtr ret;
4415 
4416  ret = xmlStaticCopyNode(node, NULL, NULL, extended);
4417  return(ret);
4418 }
4419 
4432 xmlNodePtr
4433 xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
4434  xmlNodePtr ret;
4435 
4436  ret = xmlStaticCopyNode(node, doc, NULL, extended);
4437  return(ret);
4438 }
4439 
4450  xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4451  return(ret);
4452 }
4453 
4464  xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4465  return(ret);
4466 }
4467 
4468 #if defined(LIBXML_TREE_ENABLED)
4469 
4477 xmlDtdPtr
4478 xmlCopyDtd(xmlDtdPtr dtd) {
4479  xmlDtdPtr ret;
4480  xmlNodePtr cur, p = NULL, q;
4481 
4482  if (dtd == NULL) return(NULL);
4483  ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4484  if (ret == NULL) return(NULL);
4485  if (dtd->entities != NULL)
4486  ret->entities = (void *) xmlCopyEntitiesTable(
4487  (xmlEntitiesTablePtr) dtd->entities);
4488  if (dtd->notations != NULL)
4489  ret->notations = (void *) xmlCopyNotationTable(
4491  if (dtd->elements != NULL)
4492  ret->elements = (void *) xmlCopyElementTable(
4493  (xmlElementTablePtr) dtd->elements);
4494  if (dtd->attributes != NULL)
4495  ret->attributes = (void *) xmlCopyAttributeTable(
4497  if (dtd->pentities != NULL)
4498  ret->pentities = (void *) xmlCopyEntitiesTable(
4500 
4501  cur = dtd->children;
4502  while (cur != NULL) {
4503  q = NULL;
4504 
4505  if (cur->type == XML_ENTITY_DECL) {
4506  xmlEntityPtr tmp = (xmlEntityPtr) cur;
4507  switch (tmp->etype) {
4511  q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4512  break;
4515  q = (xmlNodePtr)
4516  xmlGetParameterEntityFromDtd(ret, tmp->name);
4517  break;
4519  break;
4520  }
4521  } else if (cur->type == XML_ELEMENT_DECL) {
4523  q = (xmlNodePtr)
4524  xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4525  } else if (cur->type == XML_ATTRIBUTE_DECL) {
4527  q = (xmlNodePtr)
4528  xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4529  } else if (cur->type == XML_COMMENT_NODE) {
4530  q = xmlCopyNode(cur, 0);
4531  }
4532 
4533  if (q == NULL) {
4534  cur = cur->next;
4535  continue;
4536  }
4537 
4538  if (p == NULL)
4539  ret->children = q;
4540  else
4541  p->next = q;
4542 
4543  q->prev = p;
4544  q->parent = (xmlNodePtr) ret;
4545  q->next = NULL;
4546  ret->last = q;
4547  p = q;
4548  cur = cur->next;
4549  }
4550 
4551  return(ret);
4552 }
4553 #endif
4554 
4555 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
4556 
4566 xmlDocPtr
4567 xmlCopyDoc(xmlDocPtr doc, int recursive) {
4568  xmlDocPtr ret;
4569 
4570  if (doc == NULL) return(NULL);
4571  ret = xmlNewDoc(doc->version);
4572  if (ret == NULL) return(NULL);
4573  ret->type = doc->type;
4574  if (doc->name != NULL)
4575  ret->name = xmlMemStrdup(doc->name);
4576  if (doc->encoding != NULL)
4577  ret->encoding = xmlStrdup(doc->encoding);
4578  if (doc->URL != NULL)
4579  ret->URL = xmlStrdup(doc->URL);
4580  ret->charset = doc->charset;
4581  ret->compression = doc->compression;
4582  ret->standalone = doc->standalone;
4583  if (!recursive) return(ret);
4584 
4585  ret->last = NULL;
4586  ret->children = NULL;
4587 #ifdef LIBXML_TREE_ENABLED
4588  if (doc->intSubset != NULL) {
4589  ret->intSubset = xmlCopyDtd(doc->intSubset);
4590  if (ret->intSubset == NULL) {
4591  xmlFreeDoc(ret);
4592  return(NULL);
4593  }
4594  xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
4595  ret->intSubset->parent = ret;
4596  }
4597 #endif
4598  if (doc->oldNs != NULL)
4599  ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4600  if (doc->children != NULL) {
4601  xmlNodePtr tmp;
4602 
4603  ret->children = xmlStaticCopyNodeList(doc->children, ret,
4604  (xmlNodePtr)ret);
4605  ret->last = NULL;
4606  tmp = ret->children;
4607  while (tmp != NULL) {
4608  if (tmp->next == NULL)
4609  ret->last = tmp;
4610  tmp = tmp->next;
4611  }
4612  }
4613  return(ret);
4614 }
4615 #endif /* LIBXML_TREE_ENABLED */
4616 
4617 /************************************************************************
4618  * *
4619  * Content access functions *
4620  * *
4621  ************************************************************************/
4622 
4633 static long
4634 xmlGetLineNoInternal(const xmlNode *node, int depth)
4635 {
4636  long result = -1;
4637 
4638  if (depth >= 5)
4639  return(-1);
4640 
4641  if (!node)
4642  return result;
4643  if ((node->type == XML_ELEMENT_NODE) ||
4644  (node->type == XML_TEXT_NODE) ||
4645  (node->type == XML_COMMENT_NODE) ||
4646  (node->type == XML_PI_NODE)) {
4647  if (node->line == 65535) {
4648  if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL))
4649  result = (long) (ptrdiff_t) node->psvi;
4650  else if ((node->type == XML_ELEMENT_NODE) &&
4651  (node->children != NULL))
4652  result = xmlGetLineNoInternal(node->children, depth + 1);
4653  else if (node->next != NULL)
4654  result = xmlGetLineNoInternal(node->next, depth + 1);
4655  else if (node->prev != NULL)
4656  result = xmlGetLineNoInternal(node->prev, depth + 1);
4657  }
4658  if ((result == -1) || (result == 65535))
4659  result = (long) node->line;
4660  } else if ((node->prev != NULL) &&
4661  ((node->prev->type == XML_ELEMENT_NODE) ||
4662  (node->prev->type == XML_TEXT_NODE) ||
4663  (node->prev->type == XML_COMMENT_NODE) ||
4664  (node->prev->type == XML_PI_NODE)))
4665  result = xmlGetLineNoInternal(node->prev, depth + 1);
4666  else if ((node->parent != NULL) &&
4667  (node->parent->type == XML_ELEMENT_NODE))
4668  result = xmlGetLineNoInternal(node->parent, depth + 1);
4669 
4670  return result;
4671 }
4672 
4683 long
4684 xmlGetLineNo(const xmlNode *node)
4685 {
4686  return(xmlGetLineNoInternal(node, 0));
4687 }
4688 
4689 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
4690 
4699 xmlChar *
4700 xmlGetNodePath(const xmlNode *node)
4701 {
4702  const xmlNode *cur, *tmp, *next;
4703  xmlChar *buffer = NULL, *temp;
4704  size_t buf_len;
4705  xmlChar *buf;
4706  const char *sep;
4707  const char *name;
4708  char nametemp[100];
4709  int occur = 0, generic;
4710 
4711  if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
4712  return (NULL);
4713 
4714  buf_len = 500;
4715  buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4716  if (buffer == NULL) {
4717  xmlTreeErrMemory("getting node path");
4718  return (NULL);
4719  }
4720  buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4721  if (buf == NULL) {
4722  xmlTreeErrMemory("getting node path");
4723  xmlFree(buffer);
4724  return (NULL);
4725  }
4726 
4727  buffer[0] = 0;
4728  cur = node;
4729  do {
4730  name = "";
4731  sep = "?";
4732  occur = 0;
4733  if ((cur->type == XML_DOCUMENT_NODE) ||
4734  (cur->type == XML_HTML_DOCUMENT_NODE)) {
4735  if (buffer[0] == '/')
4736  break;
4737  sep = "/";
4738  next = NULL;
4739  } else if (cur->type == XML_ELEMENT_NODE) {
4740  generic = 0;
4741  sep = "/";
4742  name = (const char *) cur->name;
4743  if (cur->ns) {
4744  if (cur->ns->prefix != NULL) {
4745  snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4746  (char *)cur->ns->prefix, (char *)cur->name);
4747  nametemp[sizeof(nametemp) - 1] = 0;
4748  name = nametemp;
4749  } else {
4750  /*
4751  * We cannot express named elements in the default
4752  * namespace, so use "*".
4753  */
4754  generic = 1;
4755  name = "*";
4756  }
4757  }
4758  next = cur->parent;
4759 
4760  /*
4761  * Thumbler index computation
4762  * TODO: the occurrence test seems bogus for namespaced names
4763  */
4764  tmp = cur->prev;
4765  while (tmp != NULL) {
4766  if ((tmp->type == XML_ELEMENT_NODE) &&
4767  (generic ||
4768  (xmlStrEqual(cur->name, tmp->name) &&
4769  ((tmp->ns == cur->ns) ||
4770  ((tmp->ns != NULL) && (cur->ns != NULL) &&
4771  (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4772  occur++;
4773  tmp = tmp->prev;
4774  }
4775  if (occur == 0) {
4776  tmp = cur->next;
4777  while (tmp != NULL && occur == 0) {
4778  if ((tmp->type == XML_ELEMENT_NODE) &&
4779  (generic ||
4780  (xmlStrEqual(cur->name, tmp->name) &&
4781  ((tmp->ns == cur->ns) ||
4782  ((tmp->ns != NULL) && (cur->ns != NULL) &&
4783  (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4784  occur++;
4785  tmp = tmp->next;
4786  }
4787  if (occur != 0)
4788  occur = 1;
4789  } else
4790  occur++;
4791  } else if (cur->type == XML_COMMENT_NODE) {
4792  sep = "/";
4793  name = "comment()";
4794  next = cur->parent;
4795 
4796  /*
4797  * Thumbler index computation
4798  */
4799  tmp = cur->prev;
4800  while (tmp != NULL) {
4801  if (tmp->type == XML_COMMENT_NODE)
4802  occur++;
4803  tmp = tmp->prev;
4804  }
4805  if (occur == 0) {
4806  tmp = cur->next;
4807  while (tmp != NULL && occur == 0) {
4808  if (tmp->type == XML_COMMENT_NODE)
4809  occur++;
4810  tmp = tmp->next;
4811  }
4812  if (occur != 0)
4813  occur = 1;
4814  } else
4815  occur++;
4816  } else if ((cur->type == XML_TEXT_NODE) ||
4817  (cur->type == XML_CDATA_SECTION_NODE)) {
4818  sep = "/";
4819  name = "text()";
4820  next = cur->parent;
4821 
4822  /*
4823  * Thumbler index computation
4824  */
4825  tmp = cur->prev;
4826  while (tmp != NULL) {
4827  if ((tmp->type == XML_TEXT_NODE) ||
4828  (tmp->type == XML_CDATA_SECTION_NODE))
4829  occur++;
4830  tmp = tmp->prev;
4831  }
4832  /*
4833  * Evaluate if this is the only text- or CDATA-section-node;
4834  * if yes, then we'll get "text()", otherwise "text()[1]".
4835  */
4836  if (occur == 0) {
4837  tmp = cur->next;
4838  while (tmp != NULL) {
4839  if ((tmp->type == XML_TEXT_NODE) ||
4840  (tmp->type == XML_CDATA_SECTION_NODE))
4841  {
4842  occur = 1;
4843  break;
4844  }
4845  tmp = tmp->next;
4846  }
4847  } else
4848  occur++;
4849  } else if (cur->type == XML_PI_NODE) {
4850  sep = "/";
4851  snprintf(nametemp, sizeof(nametemp) - 1,
4852  "processing-instruction('%s')", (char *)cur->name);
4853  nametemp[sizeof(nametemp) - 1] = 0;
4854  name = nametemp;
4855 
4856  next = cur->parent;
4857 
4858  /*
4859  * Thumbler index computation
4860  */
4861  tmp = cur->prev;
4862  while (tmp != NULL) {
4863  if ((tmp->type == XML_PI_NODE) &&
4864  (xmlStrEqual(cur->name, tmp->name)))
4865  occur++;
4866  tmp = tmp->prev;
4867  }
4868  if (occur == 0) {
4869  tmp = cur->next;
4870  while (tmp != NULL && occur == 0) {
4871  if ((tmp->type == XML_PI_NODE) &&
4872  (xmlStrEqual(cur->name, tmp->name)))
4873  occur++;
4874  tmp = tmp->next;
4875  }
4876  if (occur != 0)
4877  occur = 1;
4878  } else
4879  occur++;
4880 
4881  } else if (cur->type == XML_ATTRIBUTE_NODE) {
4882  sep = "/@";
4883  name = (const char *) (((xmlAttrPtr) cur)->name);
4884  if (cur->ns) {
4885  if (cur->ns->prefix != NULL)
4886  snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4887  (char *)cur->ns->prefix, (char *)cur->name);
4888  else
4889  snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4890  (char *)cur->name);
4891  nametemp[sizeof(nametemp) - 1] = 0;
4892  name = nametemp;
4893  }
4894  next = ((xmlAttrPtr) cur)->parent;
4895  } else {
4896  xmlFree(buf);
4897  xmlFree(buffer);
4898  return (NULL);
4899  }
4900 
4901  /*
4902  * Make sure there is enough room
4903  */
4904  if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4905  buf_len =
4906  2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4907  temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4908  if (temp == NULL) {
4909  xmlTreeErrMemory("getting node path");
4910  xmlFree(buf);
4911  xmlFree(buffer);
4912  return (NULL);
4913  }
4914  buffer = temp;
4915  temp = (xmlChar *) xmlRealloc(buf, buf_len);
4916  if (temp == NULL) {
4917  xmlTreeErrMemory("getting node path");
4918  xmlFree(buf);
4919  xmlFree(buffer);
4920  return (NULL);
4921  }
4922  buf = temp;
4923  }
4924  if (occur == 0)
4925  snprintf((char *) buf, buf_len, "%s%s%s",
4926  sep, name, (char *) buffer);
4927  else
4928  snprintf((char *) buf, buf_len, "%s%s[%d]%s",
4929  sep, name, occur, (char *) buffer);
4930  snprintf((char *) buffer, buf_len, "%s", (char *)buf);
4931  cur = next;
4932  } while (cur != NULL);
4933  xmlFree(buf);
4934  return (buffer);
4935 }
4936 #endif /* LIBXML_TREE_ENABLED */
4937 
4947 xmlNodePtr
4948 xmlDocGetRootElement(const xmlDoc *doc) {
4949  xmlNodePtr ret;
4950 
4951  if (doc == NULL) return(NULL);
4952  ret = doc->children;
4953  while (ret != NULL) {
4954  if (ret->type == XML_ELEMENT_NODE)
4955  return(ret);
4956  ret = ret->next;
4957  }
4958  return(ret);
4959 }
4960 
4961 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
4962 
4973 xmlNodePtr
4974 xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4975  xmlNodePtr old = NULL;
4976 
4977  if (doc == NULL) return(NULL);
4978  if ((root == NULL) || (root->type == XML_NAMESPACE_DECL))
4979  return(NULL);
4981  xmlSetTreeDoc(root, doc);
4982  root->parent = (xmlNodePtr) doc;
4983  old = doc->children;
4984  while (old != NULL) {
4985  if (old->type == XML_ELEMENT_NODE)
4986  break;
4987  old = old->next;
4988  }
4989  if (old == NULL) {
4990  if (doc->children == NULL) {
4991  doc->children = root;
4992  doc->last = root;
4993  } else {
4994  xmlAddSibling(doc->children, root);
4995  }
4996  } else {
4997  xmlReplaceNode(old, root);
4998  }
4999  return(old);
5000 }
5001 #endif
5002 
5003 #if defined(LIBXML_TREE_ENABLED)
5004 
5012 void
5013 xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
5014  xmlNsPtr ns;
5015 
5016  if (cur == NULL) return;
5017  switch(cur->type) {
5018  case XML_TEXT_NODE:
5020  case XML_COMMENT_NODE:
5021  case