ReactOS  0.4.15-dev-1068-g467feb9
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
827 xmlFreeNs(xmlNsPtr cur) {
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
847 xmlFreeNsList(xmlNsPtr cur) {
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
1104 xmlFreeDtd(xmlDtdPtr cur) {
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)
1139  xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1140 
1141  if (cur->elements != NULL)
1142  xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1143  if (cur->attributes != NULL)
1144  xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1145  if (cur->entities != NULL)
1147  if (cur->pentities != NULL)
1148  xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
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;
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  */
1196 
1199  return(cur);
1200 }
1201 
1208 void
1209 xmlFreeDoc(xmlDocPtr cur) {
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) {
1244  cur->extSubset = NULL;
1245  xmlFreeDtd(extSubset);
1246  }
1247  if (intSubset != NULL) {
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)
1258  DICT_FREE(cur->encoding)
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 = value, *end = cur + len;
1280  const xmlChar *q;
1281  xmlEntityPtr ent;
1282  xmlBufPtr buf;
1283 
1284  if (value == NULL) return(NULL);
1285 
1286  buf = xmlBufCreateSize(0);
1287  if (buf == NULL) return(NULL);
1289 
1290  q = cur;
1291  while ((cur < end) && (*cur != 0)) {
1292  if (cur[0] == '&') {
1293  int charval = 0;
1294  xmlChar tmp;
1295 
1296  /*
1297  * Save the current text.
1298  */
1299  if (cur != q) {
1300  if (xmlBufAdd(buf, q, cur - q))
1301  goto out;
1302  }
1303  q = cur;
1304  if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1305  cur += 3;
1306  if (cur < end)
1307  tmp = *cur;
1308  else
1309  tmp = 0;
1310  while (tmp != ';') { /* Non input consuming loop */
1311  if ((tmp >= '0') && (tmp <= '9'))
1312  charval = charval * 16 + (tmp - '0');
1313  else if ((tmp >= 'a') && (tmp <= 'f'))
1314  charval = charval * 16 + (tmp - 'a') + 10;
1315  else if ((tmp >= 'A') && (tmp <= 'F'))
1316  charval = charval * 16 + (tmp - 'A') + 10;
1317  else {
1318  xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1319  NULL);
1320  charval = 0;
1321  break;
1322  }
1323  cur++;
1324  if (cur < end)
1325  tmp = *cur;
1326  else
1327  tmp = 0;
1328  }
1329  if (tmp == ';')
1330  cur++;
1331  q = cur;
1332  } else if ((cur + 1 < end) && (cur[1] == '#')) {
1333  cur += 2;
1334  if (cur < end)
1335  tmp = *cur;
1336  else
1337  tmp = 0;
1338  while (tmp != ';') { /* Non input consuming loops */
1339  if ((tmp >= '0') && (tmp <= '9'))
1340  charval = charval * 10 + (tmp - '0');
1341  else {
1342  xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1343  NULL);
1344  charval = 0;
1345  break;
1346  }
1347  cur++;
1348  if (cur < end)
1349  tmp = *cur;
1350  else
1351  tmp = 0;
1352  }
1353  if (tmp == ';')
1354  cur++;
1355  q = cur;
1356  } else {
1357  /*
1358  * Read the entity string
1359  */
1360  cur++;
1361  q = cur;
1362  while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1363  if ((cur >= end) || (*cur == 0)) {
1364  xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc,
1365  (const char *) q);
1366  goto out;
1367  }
1368  if (cur != q) {
1369  /*
1370  * Predefined entities don't generate nodes
1371  */
1372  val = xmlStrndup(q, cur - q);
1373  ent = xmlGetDocEntity(doc, val);
1374  if ((ent != NULL) &&
1376 
1377  if (xmlBufCat(buf, ent->content))
1378  goto out;
1379 
1380  } else {
1381  /*
1382  * Flush buffer so far
1383  */
1384  if (!xmlBufIsEmpty(buf)) {
1385  node = xmlNewDocText(doc, NULL);
1386  if (node == NULL) {
1387  if (val != NULL) xmlFree(val);
1388  goto out;
1389  }
1390  node->content = xmlBufDetach(buf);
1391 
1392  if (last == NULL) {
1393  last = ret = node;
1394  } else {
1396  }
1397  }
1398 
1399  /*
1400  * Create a new REFERENCE_REF node
1401  */
1402  node = xmlNewReference(doc, val);
1403  if (node == NULL) {
1404  if (val != NULL) xmlFree(val);
1405  goto out;
1406  }
1407  else if ((ent != NULL) && (ent->children == NULL)) {
1408  xmlNodePtr temp;
1409 
1410  /* Set to non-NULL value to avoid recursion. */
1411  ent->children = (xmlNodePtr) -1;
1412  ent->children = xmlStringGetNodeList(doc,
1413  (const xmlChar*)node->content);
1414  ent->owner = 1;
1415  temp = ent->children;
1416  while (temp) {
1417  temp->parent = (xmlNodePtr)ent;
1418  ent->last = temp;
1419  temp = temp->next;
1420  }
1421  }
1422  if (last == NULL) {
1423  last = ret = node;
1424  } else {
1426  }
1427  }
1428  xmlFree(val);
1429  }
1430  cur++;
1431  q = cur;
1432  }
1433  if (charval != 0) {
1434  xmlChar buffer[10];
1435  int l;
1436 
1437  l = xmlCopyCharMultiByte(buffer, charval);
1438  buffer[l] = 0;
1439 
1440  if (xmlBufCat(buf, buffer))
1441  goto out;
1442  charval = 0;
1443  }
1444  } else
1445  cur++;
1446  }
1447 
1448  if (cur != q) {
1449  /*
1450  * Handle the last piece of text.
1451  */
1452  if (xmlBufAdd(buf, q, cur - q))
1453  goto out;
1454  }
1455 
1456  if (!xmlBufIsEmpty(buf)) {
1457  node = xmlNewDocText(doc, NULL);
1458  if (node == NULL) goto out;
1459  node->content = xmlBufDetach(buf);
1460 
1461  if (last == NULL) {
1462  ret = node;
1463  } else {
1465  }
1466  } else if (ret == NULL) {
1467  ret = xmlNewDocText(doc, BAD_CAST "");
1468  }
1469 
1470 out:
1471  xmlBufFree(buf);
1472  return(ret);
1473 }
1474 
1484 xmlNodePtr
1485 xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) {
1486  xmlNodePtr ret = NULL, last = NULL;
1487  xmlNodePtr node;
1488  xmlChar *val;
1489  const xmlChar *cur = value;
1490  const xmlChar *q;
1491  xmlEntityPtr ent;
1492  xmlBufPtr buf;
1493 
1494  if (value == NULL) return(NULL);
1495 
1496  buf = xmlBufCreateSize(0);
1497  if (buf == NULL) return(NULL);
1499 
1500  q = cur;
1501  while (*cur != 0) {
1502  if (cur[0] == '&') {
1503  int charval = 0;
1504  xmlChar tmp;
1505 
1506  /*
1507  * Save the current text.
1508  */
1509  if (cur != q) {
1510  if (xmlBufAdd(buf, q, cur - q))
1511  goto out;
1512  }
1513  q = cur;
1514  if ((cur[1] == '#') && (cur[2] == 'x')) {
1515  cur += 3;
1516  tmp = *cur;
1517  while (tmp != ';') { /* Non input consuming loop */
1518  if ((tmp >= '0') && (tmp <= '9'))
1519  charval = charval * 16 + (tmp - '0');
1520  else if ((tmp >= 'a') && (tmp <= 'f'))
1521  charval = charval * 16 + (tmp - 'a') + 10;
1522  else if ((tmp >= 'A') && (tmp <= 'F'))
1523  charval = charval * 16 + (tmp - 'A') + 10;
1524  else {
1525  xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc,
1526  NULL);
1527  charval = 0;
1528  break;
1529  }
1530  cur++;
1531  tmp = *cur;
1532  }
1533  if (tmp == ';')
1534  cur++;
1535  q = cur;
1536  } else if (cur[1] == '#') {
1537  cur += 2;
1538  tmp = *cur;
1539  while (tmp != ';') { /* Non input consuming loops */
1540  if ((tmp >= '0') && (tmp <= '9'))
1541  charval = charval * 10 + (tmp - '0');
1542  else {
1543  xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc,
1544  NULL);
1545  charval = 0;
1546  break;
1547  }
1548  cur++;
1549  tmp = *cur;
1550  }
1551  if (tmp == ';')
1552  cur++;
1553  q = cur;
1554  } else {
1555  /*
1556  * Read the entity string
1557  */
1558  cur++;
1559  q = cur;
1560  while ((*cur != 0) && (*cur != ';')) cur++;
1561  if (*cur == 0) {
1562  xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY,
1563  (xmlNodePtr) doc, (const char *) q);
1564  goto out;
1565  }
1566  if (cur != q) {
1567  /*
1568  * Predefined entities don't generate nodes
1569  */
1570  val = xmlStrndup(q, cur - q);
1571  ent = xmlGetDocEntity(doc, val);
1572  if ((ent != NULL) &&
1574 
1575  if (xmlBufCat(buf, ent->content))
1576  goto out;
1577 
1578  } else {
1579  /*
1580  * Flush buffer so far
1581  */
1582  if (!xmlBufIsEmpty(buf)) {
1583  node = xmlNewDocText(doc, NULL);
1584  node->content = xmlBufDetach(buf);
1585 
1586  if (last == NULL) {
1587  last = ret = node;
1588  } else {
1590  }
1591  }
1592 
1593  /*
1594  * Create a new REFERENCE_REF node
1595  */
1596  node = xmlNewReference(doc, val);
1597  if (node == NULL) {
1598  if (val != NULL) xmlFree(val);
1599  goto out;
1600  }
1601  else if ((ent != NULL) && (ent->children == NULL)) {
1602  xmlNodePtr temp;
1603 
1604  /* Set to non-NULL value to avoid recursion. */
1605  ent->children = (xmlNodePtr) -1;
1606  ent->children = xmlStringGetNodeList(doc,
1607  (const xmlChar*)node->content);
1608  ent->owner = 1;
1609  temp = ent->children;
1610  while (temp) {
1611  temp->parent = (xmlNodePtr)ent;
1612  ent->last = temp;
1613  temp = temp->next;
1614  }
1615  }
1616  if (last == NULL) {
1617  last = ret = node;
1618  } else {
1620  }
1621  }
1622  xmlFree(val);
1623  }
1624  cur++;
1625  q = cur;
1626  }
1627  if (charval != 0) {
1628  xmlChar buffer[10];
1629  int len;
1630 
1631  len = xmlCopyCharMultiByte(buffer, charval);
1632  buffer[len] = 0;
1633 
1634  if (xmlBufCat(buf, buffer))
1635  goto out;
1636  charval = 0;
1637  }
1638  } else
1639  cur++;
1640  }
1641  if ((cur != q) || (ret == NULL)) {
1642  /*
1643  * Handle the last piece of text.
1644  */
1645  xmlBufAdd(buf, q, cur - q);
1646  }
1647 
1648  if (!xmlBufIsEmpty(buf)) {
1649  node = xmlNewDocText(doc, NULL);
1650  node->content = xmlBufDetach(buf);
1651 
1652  if (last == NULL) {
1653  ret = node;
1654  } else {
1656  }
1657  }
1658 
1659 out:
1660  xmlBufFree(buf);
1661  return(ret);
1662 }
1663 
1675 xmlChar *
1676 xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
1677 {
1678  const xmlNode *node = list;
1679  xmlChar *ret = NULL;
1680  xmlEntityPtr ent;
1681  int attr;
1682 
1683  if (list == NULL)
1684  return (NULL);
1685  if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
1686  attr = 1;
1687  else
1688  attr = 0;
1689 
1690  while (node != NULL) {
1691  if ((node->type == XML_TEXT_NODE) ||
1692  (node->type == XML_CDATA_SECTION_NODE)) {
1693  if (inLine) {
1694  ret = xmlStrcat(ret, node->content);
1695  } else {
1696  xmlChar *buffer;
1697 
1698  if (attr)
1699  buffer = xmlEncodeAttributeEntities(doc, node->content);
1700  else
1701  buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1702  if (buffer != NULL) {
1703  ret = xmlStrcat(ret, buffer);
1704  xmlFree(buffer);
1705  }
1706  }
1707  } else if (node->type == XML_ENTITY_REF_NODE) {
1708  if (inLine) {
1709  ent = xmlGetDocEntity(doc, node->name);
1710  if (ent != NULL) {
1711  xmlChar *buffer;
1712 
1713  /* an entity content can be any "well balanced chunk",
1714  * i.e. the result of the content [43] production:
1715  * http://www.w3.org/TR/REC-xml#NT-content.
1716  * So it can contain text, CDATA section or nested
1717  * entity reference nodes (among others).
1718  * -> we recursive call xmlNodeListGetString()
1719  * which handles these types */
1720  buffer = xmlNodeListGetString(doc, ent->children, 1);
1721  if (buffer != NULL) {
1722  ret = xmlStrcat(ret, buffer);
1723  xmlFree(buffer);
1724  }
1725  } else {
1726  ret = xmlStrcat(ret, node->content);
1727  }
1728  } else {
1729  xmlChar buf[2];
1730 
1731  buf[0] = '&';
1732  buf[1] = 0;
1733  ret = xmlStrncat(ret, buf, 1);
1734  ret = xmlStrcat(ret, node->name);
1735  buf[0] = ';';
1736  buf[1] = 0;
1737  ret = xmlStrncat(ret, buf, 1);
1738  }
1739  }
1740 #if 0
1741  else {
1743  "xmlGetNodeListString : invalid node type %d\n",
1744  node->type);
1745  }
1746 #endif
1747  node = node->next;
1748  }
1749  return (ret);
1750 }
1751 
1752 #ifdef LIBXML_TREE_ENABLED
1753 
1765 xmlChar *
1766 xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine)
1767 {
1768  const xmlNode *node = list;
1769  xmlChar *ret = NULL;
1770  xmlEntityPtr ent;
1771 
1772  if (list == NULL)
1773  return (NULL);
1774 
1775  while (node != NULL) {
1776  if ((node->type == XML_TEXT_NODE) ||
1777  (node->type == XML_CDATA_SECTION_NODE)) {
1778  if (inLine) {
1779  ret = xmlStrcat(ret, node->content);
1780  } else {
1781  xmlChar *buffer;
1782 
1783  buffer = xmlEncodeSpecialChars(doc, node->content);
1784  if (buffer != NULL) {
1785  ret = xmlStrcat(ret, buffer);
1786  xmlFree(buffer);
1787  }
1788  }
1789  } else if (node->type == XML_ENTITY_REF_NODE) {
1790  if (inLine) {
1791  ent = xmlGetDocEntity(doc, node->name);
1792  if (ent != NULL) {
1793  xmlChar *buffer;
1794 
1795  /* an entity content can be any "well balanced chunk",
1796  * i.e. the result of the content [43] production:
1797  * http://www.w3.org/TR/REC-xml#NT-content.
1798  * So it can contain text, CDATA section or nested
1799  * entity reference nodes (among others).
1800  * -> we recursive call xmlNodeListGetRawString()
1801  * which handles these types */
1802  buffer =
1803  xmlNodeListGetRawString(doc, ent->children, 1);
1804  if (buffer != NULL) {
1805  ret = xmlStrcat(ret, buffer);
1806  xmlFree(buffer);
1807  }
1808  } else {
1809  ret = xmlStrcat(ret, node->content);
1810  }
1811  } else {
1812  xmlChar buf[2];
1813 
1814  buf[0] = '&';
1815  buf[1] = 0;
1816  ret = xmlStrncat(ret, buf, 1);
1817  ret = xmlStrcat(ret, node->name);
1818  buf[0] = ';';
1819  buf[1] = 0;
1820  ret = xmlStrncat(ret, buf, 1);
1821  }
1822  }
1823 #if 0
1824  else {
1826  "xmlGetNodeListString : invalid node type %d\n",
1827  node->type);
1828  }
1829 #endif
1830  node = node->next;
1831  }
1832  return (ret);
1833 }
1834 #endif /* LIBXML_TREE_ENABLED */
1835 
1836 static xmlAttrPtr
1837 xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1838  const xmlChar * name, const xmlChar * value,
1839  int eatname)
1840 {
1841  xmlAttrPtr cur;
1842  xmlDocPtr doc = NULL;
1843 
1844  if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1845  if ((eatname == 1) &&
1846  ((node->doc == NULL) ||
1847  (!(xmlDictOwns(node->doc->dict, name)))))
1848  xmlFree((xmlChar *) name);
1849  return (NULL);
1850  }
1851 
1852  /*
1853  * Allocate a new property and fill the fields.
1854  */
1855  cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1856  if (cur == NULL) {
1857  if ((eatname == 1) &&
1858  ((node == NULL) || (node->doc == NULL) ||
1859  (!(xmlDictOwns(node->doc->dict, name)))))
1860  xmlFree((xmlChar *) name);
1861  xmlTreeErrMemory("building attribute");
1862  return (NULL);
1863  }
1864  memset(cur, 0, sizeof(xmlAttr));
1865  cur->type = XML_ATTRIBUTE_NODE;
1866 
1867  cur->parent = node;
1868  if (node != NULL) {
1869  doc = node->doc;
1870  cur->doc = doc;
1871  }
1872  cur->ns = ns;
1873 
1874  if (eatname == 0) {
1875  if ((doc != NULL) && (doc->dict != NULL))
1876  cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1877  else
1878  cur->name = xmlStrdup(name);
1879  } else
1880  cur->name = name;
1881 
1882  if (value != NULL) {
1883  xmlNodePtr tmp;
1884 
1885  if(!xmlCheckUTF8(value)) {
1886  xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) doc,
1887  NULL);
1888  if (doc != NULL)
1889  doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
1890  }
1891  cur->children = xmlNewDocText(doc, value);
1892  cur->last = NULL;
1893  tmp = cur->children;
1894  while (tmp != NULL) {
1895  tmp->parent = (xmlNodePtr) cur;
1896  if (tmp->next == NULL)
1897  cur->last = tmp;
1898  tmp = tmp->next;
1899  }
1900  }
1901 
1902  /*
1903  * Add it at the end to preserve parsing order ...
1904  */
1905  if (node != NULL) {
1906  if (node->properties == NULL) {
1907  node->properties = cur;
1908  } else {
1909  xmlAttrPtr prev = node->properties;
1910 
1911  while (prev->next != NULL)
1912  prev = prev->next;
1913  prev->next = cur;
1914  cur->prev = prev;
1915  }
1916  }
1917 
1918  if ((value != NULL) && (node != NULL) &&
1919  (xmlIsID(node->doc, node, cur) == 1))
1920  xmlAddID(NULL, node->doc, value, cur);
1921 
1924  return (cur);
1925 }
1926 
1927 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1928  defined(LIBXML_SCHEMAS_ENABLED)
1929 
1938 xmlAttrPtr
1939 xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1940 
1941  if (name == NULL) {
1942 #ifdef DEBUG_TREE
1944  "xmlNewProp : name == NULL\n");
1945 #endif
1946  return(NULL);
1947  }
1948 
1949  return xmlNewPropInternal(node, NULL, name, value, 0);
1950 }
1951 #endif /* LIBXML_TREE_ENABLED */
1952 
1963 xmlAttrPtr
1965  const xmlChar *value) {
1966 
1967  if (name == NULL) {
1968 #ifdef DEBUG_TREE
1970  "xmlNewNsProp : name == NULL\n");
1971 #endif
1972  return(NULL);
1973  }
1974 
1975  return xmlNewPropInternal(node, ns, name, value, 0);
1976 }
1977 
1988 xmlAttrPtr
1990  const xmlChar *value) {
1991 
1992  if (name == NULL) {
1993 #ifdef DEBUG_TREE
1995  "xmlNewNsPropEatName : name == NULL\n");
1996 #endif
1997  return(NULL);
1998  }
1999 
2000  return xmlNewPropInternal(node, ns, name, value, 1);
2001 }
2002 
2012 xmlAttrPtr
2013 xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
2014  xmlAttrPtr cur;
2015 
2016  if (name == NULL) {
2017 #ifdef DEBUG_TREE
2019  "xmlNewDocProp : name == NULL\n");
2020 #endif
2021  return(NULL);
2022  }
2023 
2024  /*
2025  * Allocate a new property and fill the fields.
2026  */
2027  cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
2028  if (cur == NULL) {
2029  xmlTreeErrMemory("building attribute");
2030  return(NULL);
2031  }
2032  memset(cur, 0, sizeof(xmlAttr));
2033  cur->type = XML_ATTRIBUTE_NODE;
2034 
2035  if ((doc != NULL) && (doc->dict != NULL))
2036  cur->name = xmlDictLookup(doc->dict, name, -1);
2037  else
2038  cur->name = xmlStrdup(name);
2039  cur->doc = doc;
2040  if (value != NULL) {
2041  xmlNodePtr tmp;
2042 
2043  cur->children = xmlStringGetNodeList(doc, value);
2044  cur->last = NULL;
2045 
2046  tmp = cur->children;
2047  while (tmp != NULL) {
2048  tmp->parent = (xmlNodePtr) cur;
2049  if (tmp->next == NULL)
2050  cur->last = tmp;
2051  tmp = tmp->next;
2052  }
2053  }
2054 
2057  return(cur);
2058 }
2059 
2066 void
2068  xmlAttrPtr next;
2069  if (cur == NULL) return;
2070  while (cur != NULL) {
2071  next = cur->next;
2072  xmlFreeProp(cur);
2073  cur = next;
2074  }
2075 }
2076 
2083 void
2084 xmlFreeProp(xmlAttrPtr cur) {
2085  xmlDictPtr dict = NULL;
2086  if (cur == NULL) return;
2087 
2088  if (cur->doc != NULL) dict = cur->doc->dict;
2089 
2092 
2093  /* Check for ID removal -> leading to invalid references ! */
2094  if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2095  xmlRemoveID(cur->doc, cur);
2096  }
2097  if (cur->children != NULL) xmlFreeNodeList(cur->children);
2098  DICT_FREE(cur->name)
2099  xmlFree(cur);
2100 }
2101 
2111 int
2113  xmlAttrPtr tmp;
2114  if (cur == NULL) {
2115 #ifdef DEBUG_TREE
2117  "xmlRemoveProp : cur == NULL\n");
2118 #endif
2119  return(-1);
2120  }
2121  if (cur->parent == NULL) {
2122 #ifdef DEBUG_TREE
2124  "xmlRemoveProp : cur->parent == NULL\n");
2125 #endif
2126  return(-1);
2127  }
2128  tmp = cur->parent->properties;
2129  if (tmp == cur) {
2130  cur->parent->properties = cur->next;
2131  if (cur->next != NULL)
2132  cur->next->prev = NULL;
2133  xmlFreeProp(cur);
2134  return(0);
2135  }
2136  while (tmp != NULL) {
2137  if (tmp->next == cur) {
2138  tmp->next = cur->next;
2139  if (tmp->next != NULL)
2140  tmp->next->prev = tmp;
2141  xmlFreeProp(cur);
2142  return(0);
2143  }
2144  tmp = tmp->next;
2145  }
2146 #ifdef DEBUG_TREE
2148  "xmlRemoveProp : attribute not owned by its node\n");
2149 #endif
2150  return(-1);
2151 }
2152 
2162 xmlNodePtr
2163 xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
2164  xmlNodePtr cur;
2165 
2166  if (name == NULL) {
2167 #ifdef DEBUG_TREE
2169  "xmlNewPI : name == NULL\n");
2170 #endif
2171  return(NULL);
2172  }
2173 
2174  /*
2175  * Allocate a new node and fill the fields.
2176  */
2177  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2178  if (cur == NULL) {
2179  xmlTreeErrMemory("building PI");
2180  return(NULL);
2181  }
2182  memset(cur, 0, sizeof(xmlNode));
2183  cur->type = XML_PI_NODE;
2184 
2185  if ((doc != NULL) && (doc->dict != NULL))
2186  cur->name = xmlDictLookup(doc->dict, name, -1);
2187  else
2188  cur->name = xmlStrdup(name);
2189  if (content != NULL) {
2190  cur->content = xmlStrdup(content);
2191  }
2192  cur->doc = doc;
2193 
2196  return(cur);
2197 }
2198 
2209 xmlNodePtr
2210 xmlNewPI(const xmlChar *name, const xmlChar *content) {
2211  return(xmlNewDocPI(NULL, name, content));
2212 }
2213 
2224 xmlNodePtr
2225 xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2226  xmlNodePtr cur;
2227 
2228  if (name == NULL) {
2229 #ifdef DEBUG_TREE
2231  "xmlNewNode : name == NULL\n");
2232 #endif
2233  return(NULL);
2234  }
2235 
2236  /*
2237  * Allocate a new node and fill the fields.
2238  */
2239  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2240  if (cur == NULL) {
2241  xmlTreeErrMemory("building node");
2242  return(NULL);
2243  }
2244  memset(cur, 0, sizeof(xmlNode));
2245  cur->type = XML_ELEMENT_NODE;
2246 
2247  cur->name = xmlStrdup(name);
2248  cur->ns = ns;
2249 
2252  return(cur);
2253 }
2254 
2266 xmlNodePtr
2268  xmlNodePtr cur;
2269 
2270  if (name == NULL) {
2271 #ifdef DEBUG_TREE
2273  "xmlNewNode : name == NULL\n");
2274 #endif
2275  return(NULL);
2276  }
2277 
2278  /*
2279  * Allocate a new node and fill the fields.
2280  */
2281  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2282  if (cur == NULL) {
2283  xmlTreeErrMemory("building node");
2284  /* we can't check here that name comes from the doc dictionary */
2285  return(NULL);
2286  }
2287  memset(cur, 0, sizeof(xmlNode));
2288  cur->type = XML_ELEMENT_NODE;
2289 
2290  cur->name = name;
2291  cur->ns = ns;
2292 
2295  return(cur);
2296 }
2297 
2314 xmlNodePtr
2316  const xmlChar *name, const xmlChar *content) {
2317  xmlNodePtr cur;
2318 
2319  if ((doc != NULL) && (doc->dict != NULL))
2320  cur = xmlNewNodeEatName(ns, (xmlChar *)
2321  xmlDictLookup(doc->dict, name, -1));
2322  else
2323  cur = xmlNewNode(ns, name);
2324  if (cur != NULL) {
2325  cur->doc = doc;
2326  if (content != NULL) {
2327  cur->children = xmlStringGetNodeList(doc, content);
2329  }
2330  }
2331 
2332  return(cur);
2333 }
2334 
2351 xmlNodePtr
2353  xmlChar *name, const xmlChar *content) {
2354  xmlNodePtr cur;
2355 
2356  cur = xmlNewNodeEatName(ns, name);
2357  if (cur != NULL) {
2358  cur->doc = doc;
2359  if (content != NULL) {
2360  cur->children = xmlStringGetNodeList(doc, content);
2362  }
2363  } else {
2364  /* if name don't come from the doc dictionary free it here */
2365  if ((name != NULL) && (doc != NULL) &&
2366  (!(xmlDictOwns(doc->dict, name))))
2367  xmlFree(name);
2368  }
2369  return(cur);
2370 }
2371 
2372 #ifdef LIBXML_TREE_ENABLED
2373 
2385 xmlNodePtr
2386 xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2387  const xmlChar *name, const xmlChar *content) {
2388  xmlNodePtr cur;
2389 
2390  cur = xmlNewDocNode(doc, ns, name, NULL);
2391  if (cur != NULL) {
2392  cur->doc = doc;
2393  if (content != NULL) {
2394  cur->children = xmlNewDocText(doc, content);
2396  }
2397  }
2398  return(cur);
2399 }
2400 
2408 xmlNodePtr
2409 xmlNewDocFragment(xmlDocPtr doc) {
2410  xmlNodePtr cur;
2411 
2412  /*
2413  * Allocate a new DocumentFragment node and fill the fields.
2414  */
2415  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2416  if (cur == NULL) {
2417  xmlTreeErrMemory("building fragment");
2418  return(NULL);
2419  }
2420  memset(cur, 0, sizeof(xmlNode));
2422 
2423  cur->doc = doc;
2424 
2427  return(cur);
2428 }
2429 #endif /* LIBXML_TREE_ENABLED */
2430 
2438 xmlNodePtr
2439 xmlNewText(const xmlChar *content) {
2440  xmlNodePtr cur;
2441 
2442  /*
2443  * Allocate a new node and fill the fields.
2444  */
2445  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2446  if (cur == NULL) {
2447  xmlTreeErrMemory("building text");
2448  return(NULL);
2449  }
2450  memset(cur, 0, sizeof(xmlNode));
2451  cur->type = XML_TEXT_NODE;
2452 
2453  cur->name = xmlStringText;
2454  if (content != NULL) {
2455  cur->content = xmlStrdup(content);
2456  }
2457 
2460  return(cur);
2461 }
2462 
2463 #ifdef LIBXML_TREE_ENABLED
2464 
2483 xmlNodePtr
2484 xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2485  const xmlChar *name, const xmlChar *content) {
2486  xmlNodePtr cur, prev;
2487 
2488  if (parent == NULL) {
2489 #ifdef DEBUG_TREE
2491  "xmlNewTextChild : parent == NULL\n");
2492 #endif
2493  return(NULL);
2494  }
2495 
2496  if (name == NULL) {
2497 #ifdef DEBUG_TREE
2499  "xmlNewTextChild : name == NULL\n");
2500 #endif
2501  return(NULL);
2502  }
2503 
2504  /*
2505  * Allocate a new node
2506  */
2507  if (parent->type == XML_ELEMENT_NODE) {
2508  if (ns == NULL)
2509  cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2510  else
2511  cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2512  } else if ((parent->type == XML_DOCUMENT_NODE) ||
2513  (parent->type == XML_HTML_DOCUMENT_NODE)) {
2514  if (ns == NULL)
2515  cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2516  else
2517  cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2518  } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2519  cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2520  } else {
2521  return(NULL);
2522  }
2523  if (cur == NULL) return(NULL);
2524 
2525  /*
2526  * add the new element at the end of the children list.
2527  */
2528  cur->type = XML_ELEMENT_NODE;
2529  cur->parent = parent;
2530  cur->doc = parent->doc;
2531  if (parent->children == NULL) {
2532  parent->children = cur;
2533  parent->last = cur;
2534  } else {
2535  prev = parent->last;
2536  prev->next = cur;
2537  cur->prev = prev;
2538  parent->last = cur;
2539  }
2540 
2541  return(cur);
2542 }
2543 #endif /* LIBXML_TREE_ENABLED */
2544 
2553 xmlNodePtr
2554 xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2555  xmlNodePtr cur;
2556 
2557  if (name == NULL)
2558  return(NULL);
2559 
2560  /*
2561  * Allocate a new node and fill the fields.
2562  */
2563  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2564  if (cur == NULL) {
2565  xmlTreeErrMemory("building character reference");
2566  return(NULL);
2567  }
2568  memset(cur, 0, sizeof(xmlNode));
2569  cur->type = XML_ENTITY_REF_NODE;
2570 
2571  cur->doc = doc;
2572  if (name[0] == '&') {
2573  int len;
2574  name++;
2575  len = xmlStrlen(name);
2576  if (name[len - 1] == ';')
2577  cur->name = xmlStrndup(name, len - 1);
2578  else
2579  cur->name = xmlStrndup(name, len);
2580  } else
2581  cur->name = xmlStrdup(name);
2582 
2585  return(cur);
2586 }
2587 
2596 xmlNodePtr
2597 xmlNewReference(const xmlDoc *doc, const xmlChar *name) {
2598  xmlNodePtr cur;
2599  xmlEntityPtr ent;
2600 
2601  if (name == NULL)
2602  return(NULL);
2603 
2604  /*
2605  * Allocate a new node and fill the fields.
2606  */
2607  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2608  if (cur == NULL) {
2609  xmlTreeErrMemory("building reference");
2610  return(NULL);
2611  }
2612  memset(cur, 0, sizeof(xmlNode));
2613  cur->type = XML_ENTITY_REF_NODE;
2614 
2615  cur->doc = (xmlDoc *)doc;
2616  if (name[0] == '&') {
2617  int len;
2618  name++;
2619  len = xmlStrlen(name);
2620  if (name[len - 1] == ';')
2621  cur->name = xmlStrndup(name, len - 1);
2622  else
2623  cur->name = xmlStrndup(name, len);
2624  } else
2625  cur->name = xmlStrdup(name);
2626 
2627  ent = xmlGetDocEntity(doc, cur->name);
2628  if (ent != NULL) {
2629  cur->content = ent->content;
2630  /*
2631  * The parent pointer in entity is a DTD pointer and thus is NOT
2632  * updated. Not sure if this is 100% correct.
2633  * -George
2634  */
2635  cur->children = (xmlNodePtr) ent;
2636  cur->last = (xmlNodePtr) ent;
2637  }
2638 
2641  return(cur);
2642 }
2643 
2652 xmlNodePtr
2653 xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
2654  xmlNodePtr cur;
2655 
2656  cur = xmlNewText(content);
2657  if (cur != NULL) cur->doc = (xmlDoc *)doc;
2658  return(cur);
2659 }
2660 
2669 xmlNodePtr
2670 xmlNewTextLen(const xmlChar *content, int len) {
2671  xmlNodePtr cur;
2672 
2673  /*
2674  * Allocate a new node and fill the fields.
2675  */
2676  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2677  if (cur == NULL) {
2678  xmlTreeErrMemory("building text");
2679  return(NULL);
2680  }
2681  memset(cur, 0, sizeof(xmlNode));
2682  cur->type = XML_TEXT_NODE;
2683 
2684  cur->name = xmlStringText;
2685  if (content != NULL) {
2686  cur->content = xmlStrndup(content, len);
2687  }
2688 
2691  return(cur);
2692 }
2693 
2704 xmlNodePtr
2705 xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2706  xmlNodePtr cur;
2707 
2708  cur = xmlNewTextLen(content, len);
2709  if (cur != NULL) cur->doc = doc;
2710  return(cur);
2711 }
2712 
2720 xmlNodePtr
2721 xmlNewComment(const xmlChar *content) {
2722  xmlNodePtr cur;
2723 
2724  /*
2725  * Allocate a new node and fill the fields.
2726  */
2727  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2728  if (cur == NULL) {
2729  xmlTreeErrMemory("building comment");
2730  return(NULL);
2731  }
2732  memset(cur, 0, sizeof(xmlNode));
2733  cur->type = XML_COMMENT_NODE;
2734 
2735  cur->name = xmlStringComment;
2736  if (content != NULL) {
2737  cur->content = xmlStrdup(content);
2738  }
2739 
2742  return(cur);
2743 }
2744 
2754 xmlNodePtr
2755 xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2756  xmlNodePtr cur;
2757 
2758  /*
2759  * Allocate a new node and fill the fields.
2760  */
2761  cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2762  if (cur == NULL) {
2763  xmlTreeErrMemory("building CDATA");
2764  return(NULL);
2765  }
2766  memset(cur, 0, sizeof(xmlNode));
2768  cur->doc = doc;
2769 
2770  if (content != NULL) {
2771  cur->content = xmlStrndup(content, len);
2772  }
2773 
2776  return(cur);
2777 }
2778 
2787 xmlNodePtr
2789  xmlNodePtr cur;
2790 
2791  cur = xmlNewComment(content);
2792  if (cur != NULL) cur->doc = doc;
2793  return(cur);
2794 }
2795 
2803 void
2805  xmlAttrPtr prop;
2806 
2807  if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2808  return;
2809  if (tree->doc != doc) {
2810  if(tree->type == XML_ELEMENT_NODE) {
2811  prop = tree->properties;
2812  while (prop != NULL) {
2813  if (prop->atype == XML_ATTRIBUTE_ID) {
2814  xmlRemoveID(tree->doc, prop);
2815  }
2816 
2817  prop->doc = doc;
2818  xmlSetListDoc(prop->children, doc);
2819 
2820  /*
2821  * TODO: ID attributes should be also added to the new
2822  * document, but this breaks things like xmlReplaceNode.
2823  * The underlying problem is that xmlRemoveID is only called
2824  * if a node is destroyed, not if it's unlinked.
2825  */
2826 #if 0
2827  if (xmlIsID(doc, tree, prop)) {
2828  xmlChar *idVal = xmlNodeListGetString(doc, prop->children,
2829  1);
2830  xmlAddID(NULL, doc, idVal, prop);
2831  }
2832 #endif
2833 
2834  prop = prop->next;
2835  }
2836  }
2837  if (tree->children != NULL)
2838  xmlSetListDoc(tree->children, doc);
2839  tree->doc = doc;
2840  }
2841 }
2842 
2850 void
2852  xmlNodePtr cur;
2853 
2854  if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
2855  return;
2856  cur = list;
2857  while (cur != NULL) {
2858  if (cur->doc != doc)
2859  xmlSetTreeDoc(cur, doc);
2860  cur = cur->next;
2861  }
2862 }
2863 
2864 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
2865 
2882 xmlNodePtr
2883 xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
2884  const xmlChar *name, const xmlChar *content) {
2885  xmlNodePtr cur, prev;
2886 
2887  if (parent == NULL) {
2888 #ifdef DEBUG_TREE
2890  "xmlNewChild : parent == NULL\n");
2891 #endif
2892  return(NULL);
2893  }
2894 
2895  if (name == NULL) {
2896 #ifdef DEBUG_TREE
2898  "xmlNewChild : name == NULL\n");
2899 #endif
2900  return(NULL);
2901  }
2902 
2903  /*
2904  * Allocate a new node
2905  */
2906  if (parent->type == XML_ELEMENT_NODE) {
2907  if (ns == NULL)
2908  cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2909  else
2910  cur = xmlNewDocNode(parent->doc, ns, name, content);
2911  } else if ((parent->type == XML_DOCUMENT_NODE) ||
2912  (parent->type == XML_HTML_DOCUMENT_NODE)) {
2913  if (ns == NULL)
2915  else
2917  } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2918  cur = xmlNewDocNode( parent->doc, ns, name, content);
2919  } else {
2920  return(NULL);
2921  }
2922  if (cur == NULL) return(NULL);
2923 
2924  /*
2925  * add the new element at the end of the children list.
2926  */
2927  cur->type = XML_ELEMENT_NODE;
2928  cur->parent = parent;
2929  cur->doc = parent->doc;
2930  if (parent->children == NULL) {
2931  parent->children = cur;
2932  parent->last = cur;
2933  } else {
2934  prev = parent->last;
2935  prev->next = cur;
2936  cur->prev = prev;
2937  parent->last = cur;
2938  }
2939 
2940  return(cur);
2941 }
2942 #endif /* LIBXML_TREE_ENABLED */
2943 
2957 static xmlNodePtr
2958 xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2959  xmlAttrPtr attr;
2960 
2961  if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) ||
2962  (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) ||
2963  ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)))
2964  return(NULL);
2965 
2966  /* check if an attribute with the same name exists */
2967  if (prop->ns == NULL)
2968  attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2969  else
2970  attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2971 
2972  if (prop->doc != cur->doc) {
2973  xmlSetTreeDoc(prop, cur->doc);
2974  }
2975  prop->parent = cur->parent;
2976  prop->prev = prev;
2977  if (prev != NULL) {
2978  prop->next = prev->next;
2979  prev->next = prop;
2980  if (prop->next)
2981  prop->next->prev = prop;
2982  } else {
2983  prop->next = cur;
2984  cur->prev = prop;
2985  }
2986  if (prop->prev == NULL && prop->parent != NULL)
2987  prop->parent->properties = (xmlAttrPtr) prop;
2988  if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
2989  /* different instance, destroy it (attributes must be unique) */
2991  }
2992  return prop;
2993 }
2994 
3009 xmlNodePtr
3011  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3012 #ifdef DEBUG_TREE
3014  "xmlAddNextSibling : cur == NULL\n");
3015 #endif
3016  return(NULL);
3017  }
3018  if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3019 #ifdef DEBUG_TREE
3021  "xmlAddNextSibling : elem == NULL\n");
3022 #endif
3023  return(NULL);
3024  }
3025 
3026  if (cur == elem) {
3027 #ifdef DEBUG_TREE
3029  "xmlAddNextSibling : cur == elem\n");
3030 #endif
3031  return(NULL);
3032  }
3033 
3035 
3036  if (elem->type == XML_TEXT_NODE) {
3037  if (cur->type == XML_TEXT_NODE) {
3038  xmlNodeAddContent(cur, elem->content);
3039  xmlFreeNode(elem);
3040  return(cur);
3041  }
3042  if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
3043  (cur->name == cur->next->name)) {
3044  xmlChar *tmp;
3045 
3046  tmp = xmlStrdup(elem->content);
3047  tmp = xmlStrcat(tmp, cur->next->content);
3048  xmlNodeSetContent(cur->next, tmp);
3049  xmlFree(tmp);
3050  xmlFreeNode(elem);
3051  return(cur->next);
3052  }
3053  } else if (elem->type == XML_ATTRIBUTE_NODE) {
3054  return xmlAddPropSibling(cur, cur, elem);
3055  }
3056 
3057  if (elem->doc != cur->doc) {
3058  xmlSetTreeDoc(elem, cur->doc);
3059  }
3060  elem->parent = cur->parent;
3061  elem->prev = cur;
3062  elem->next = cur->next;
3063  cur->next = elem;
3064  if (elem->next != NULL)
3065  elem->next->prev = elem;
3066  if ((elem->parent != NULL) && (elem->parent->last == cur))
3067  elem->parent->last = elem;
3068  return(elem);
3069 }
3070 
3071 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
3072  defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
3073 
3087 xmlNodePtr
3088 xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
3089  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3090 #ifdef DEBUG_TREE
3092  "xmlAddPrevSibling : cur == NULL\n");
3093 #endif
3094  return(NULL);
3095  }
3096  if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3097 #ifdef DEBUG_TREE
3099  "xmlAddPrevSibling : elem == NULL\n");
3100 #endif
3101  return(NULL);
3102  }
3103 
3104  if (cur == elem) {
3105 #ifdef DEBUG_TREE
3107  "xmlAddPrevSibling : cur == elem\n");
3108 #endif
3109  return(NULL);
3110  }
3111 
3113 
3114  if (elem->type == XML_TEXT_NODE) {
3115  if (cur->type == XML_TEXT_NODE) {
3116  xmlChar *tmp;
3117 
3118  tmp = xmlStrdup(elem->content);
3119  tmp = xmlStrcat(tmp, cur->content);
3120  xmlNodeSetContent(cur, tmp);
3121  xmlFree(tmp);
3122  xmlFreeNode(elem);
3123  return(cur);
3124  }
3125  if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3126  (cur->name == cur->prev->name)) {
3127  xmlNodeAddContent(cur->prev, elem->content);
3128  xmlFreeNode(elem);
3129  return(cur->prev);
3130  }
3131  } else if (elem->type == XML_ATTRIBUTE_NODE) {
3132  return xmlAddPropSibling(cur->prev, cur, elem);
3133  }
3134 
3135  if (elem->doc != cur->doc) {
3136  xmlSetTreeDoc(elem, cur->doc);
3137  }
3138  elem->parent = cur->parent;
3139  elem->next = cur;
3140  elem->prev = cur->prev;
3141  cur->prev = elem;
3142  if (elem->prev != NULL)
3143  elem->prev->next = elem;
3144  if ((elem->parent != NULL) && (elem->parent->children == cur)) {
3145  elem->parent->children = elem;
3146  }
3147  return(elem);
3148 }
3149 #endif /* LIBXML_TREE_ENABLED */
3150 
3163 xmlNodePtr
3166 
3167  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3168 #ifdef DEBUG_TREE
3170  "xmlAddSibling : cur == NULL\n");
3171 #endif
3172  return(NULL);
3173  }
3174 
3175  if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3176 #ifdef DEBUG_TREE
3178  "xmlAddSibling : elem == NULL\n");
3179 #endif
3180  return(NULL);
3181  }
3182 
3183  if (cur == elem) {
3184 #ifdef DEBUG_TREE
3186  "xmlAddSibling : cur == elem\n");
3187 #endif
3188  return(NULL);
3189  }
3190 
3191  /*
3192  * Constant time is we can rely on the ->parent->last to find
3193  * the last sibling.
3194  */
3195  if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
3196  (cur->parent->children != NULL) &&
3197  (cur->parent->last != NULL) &&
3198  (cur->parent->last->next == NULL)) {
3199  cur = cur->parent->last;
3200  } else {
3201  while (cur->next != NULL) cur = cur->next;
3202  }
3203 
3205 
3206  if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3207  (cur->name == elem->name)) {
3208  xmlNodeAddContent(cur, elem->content);
3209  xmlFreeNode(elem);
3210  return(cur);
3211  } else if (elem->type == XML_ATTRIBUTE_NODE) {
3212  return xmlAddPropSibling(cur, cur, elem);
3213  }
3214 
3215  if (elem->doc != cur->doc) {
3216  xmlSetTreeDoc(elem, cur->doc);
3217  }
3218  parent = cur->parent;
3219  elem->prev = cur;
3220  elem->next = NULL;
3221  elem->parent = parent;
3222  cur->next = elem;
3223  if (parent != NULL)
3224  parent->last = elem;
3225 
3226  return(elem);
3227 }
3228 
3239 xmlNodePtr
3241  xmlNodePtr prev;
3242 
3243  if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3244 #ifdef DEBUG_TREE
3246  "xmlAddChildList : parent == NULL\n");
3247 #endif
3248  return(NULL);
3249  }
3250 
3251  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3252 #ifdef DEBUG_TREE
3254  "xmlAddChildList : child == NULL\n");
3255 #endif
3256  return(NULL);
3257  }
3258 
3259  if ((cur->doc != NULL) && (parent->doc != NULL) &&
3260  (cur->doc != parent->doc)) {
3261 #ifdef DEBUG_TREE
3263  "Elements moved to a different document\n");
3264 #endif
3265  }
3266 
3267  /*
3268  * add the first element at the end of the children list.
3269  */
3270 
3271  if (parent->children == NULL) {
3272  parent->children = cur;
3273  } else {
3274  /*
3275  * If cur and parent->last both are TEXT nodes, then merge them.
3276  */
3277  if ((cur->type == XML_TEXT_NODE) &&
3278  (parent->last->type == XML_TEXT_NODE) &&
3279  (cur->name == parent->last->name)) {
3280  xmlNodeAddContent(parent->last, cur->content);
3281  /*
3282  * if it's the only child, nothing more to be done.
3283  */
3284  if (cur->next == NULL) {
3285  xmlFreeNode(cur);
3286  return(parent->last);
3287  }
3288  prev = cur;
3289  cur = cur->next;
3290  xmlFreeNode(prev);
3291  }
3292  prev = parent->last;
3293  prev->next = cur;
3294  cur->prev = prev;
3295  }
3296  while (cur->next != NULL) {
3297  cur->parent = parent;
3298  if (cur->doc != parent->doc) {
3299  xmlSetTreeDoc(cur, parent->doc);
3300  }
3301  cur = cur->next;
3302  }
3303  cur->parent = parent;
3304  /* the parent may not be linked to a doc ! */
3305  if (cur->doc != parent->doc) {
3306  xmlSetTreeDoc(cur, parent->doc);
3307  }
3308  parent->last = cur;
3309 
3310  return(cur);
3311 }
3312 
3325 xmlNodePtr
3327  xmlNodePtr prev;
3328 
3329  if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3330 #ifdef DEBUG_TREE
3332  "xmlAddChild : parent == NULL\n");
3333 #endif
3334  return(NULL);
3335  }
3336 
3337  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3338 #ifdef DEBUG_TREE
3340  "xmlAddChild : child == NULL\n");
3341 #endif
3342  return(NULL);
3343  }
3344 
3345  if (parent == cur) {
3346 #ifdef DEBUG_TREE
3348  "xmlAddChild : parent == cur\n");
3349 #endif
3350  return(NULL);
3351  }
3352  /*
3353  * If cur is a TEXT node, merge its content with adjacent TEXT nodes
3354  * cur is then freed.
3355  */
3356  if (cur->type == XML_TEXT_NODE) {
3357  if ((parent->type == XML_TEXT_NODE) &&
3358  (parent->content != NULL) &&
3359  (parent->name == cur->name)) {
3361  xmlFreeNode(cur);
3362  return(parent);
3363  }
3364  if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
3365  (parent->last->name == cur->name) &&
3366  (parent->last != cur)) {
3367  xmlNodeAddContent(parent->last, cur->content);
3368  xmlFreeNode(cur);
3369  return(parent->last);
3370  }
3371  }
3372 
3373  /*
3374  * add the new element at the end of the children list.
3375  */
3376  prev = cur->parent;
3377  cur->parent = parent;
3378  if (cur->doc != parent->doc) {
3379  xmlSetTreeDoc(cur, parent->doc);
3380  }
3381  /* this check prevents a loop on tree-traversions if a developer
3382  * tries to add a node to its parent multiple times
3383  */
3384  if (prev == parent)
3385  return(cur);
3386 
3387  /*
3388  * Coalescing
3389  */
3390  if ((parent->type == XML_TEXT_NODE) &&
3391  (parent->content != NULL) &&
3392  (parent != cur)) {
3394  xmlFreeNode(cur);
3395  return(parent);
3396  }
3397  if (cur->type == XML_ATTRIBUTE_NODE) {
3398  if (parent->type != XML_ELEMENT_NODE)
3399  return(NULL);
3400  if (parent->properties != NULL) {
3401  /* check if an attribute with the same name exists */
3402  xmlAttrPtr lastattr;
3403 
3404  if (cur->ns == NULL)
3405  lastattr = xmlHasNsProp(parent, cur->name, NULL);
3406  else
3407  lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3408  if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
3409  /* different instance, destroy it (attributes must be unique) */
3410  xmlUnlinkNode((xmlNodePtr) lastattr);
3411  xmlFreeProp(lastattr);
3412  }
3413  if (lastattr == (xmlAttrPtr) cur)
3414  return(cur);
3415 
3416  }
3417  if (parent->properties == NULL) {
3418  parent->properties = (xmlAttrPtr) cur;
3419  } else {
3420  /* find the end */
3421  xmlAttrPtr lastattr = parent->properties;
3422  while (lastattr->next != NULL) {
3423  lastattr = lastattr->next;
3424  }
3425  lastattr->next = (xmlAttrPtr) cur;
3426  ((xmlAttrPtr) cur)->prev = lastattr;
3427  }
3428  } else {
3429  if (parent->children == NULL) {
3430  parent->children = cur;
3431  parent->last = cur;
3432  } else {
3433  prev = parent->last;
3434  prev->next = cur;
3435  cur->prev = prev;
3436  parent->last = cur;
3437  }
3438  }
3439  return(cur);
3440 }
3441 
3449 xmlNodePtr
3450 xmlGetLastChild(const xmlNode *parent) {
3451  if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3452 #ifdef DEBUG_TREE
3454  "xmlGetLastChild : parent == NULL\n");
3455 #endif
3456  return(NULL);
3457  }
3458  return(parent->last);
3459 }
3460 
3461 #ifdef LIBXML_TREE_ENABLED
3462 /*
3463  * 5 interfaces from DOM ElementTraversal
3464  */
3465 
3478 unsigned long
3479 xmlChildElementCount(xmlNodePtr parent) {
3480  unsigned long ret = 0;
3481  xmlNodePtr cur = NULL;
3482 
3483  if (parent == NULL)
3484  return(0);
3485  switch (parent->type) {
3486  case XML_ELEMENT_NODE:
3487  case XML_ENTITY_NODE:
3488  case XML_DOCUMENT_NODE:
3491  cur = parent->children;
3492  break;
3493  default:
3494  return(0);
3495  }
3496  while (cur != NULL) {
3497  if (cur->type == XML_ELEMENT_NODE)
3498  ret++;
3499  cur = cur->next;
3500  }
3501  return(ret);
3502 }
3503 
3515 xmlNodePtr
3516 xmlFirstElementChild(xmlNodePtr parent) {
3517  xmlNodePtr cur = NULL;
3518 
3519  if (parent == NULL)
3520  return(NULL);
3521  switch (parent->type) {
3522  case XML_ELEMENT_NODE:
3523  case XML_ENTITY_NODE:
3524  case XML_DOCUMENT_NODE:
3527  cur = parent->children;
3528  break;
3529  default:
3530  return(NULL);
3531  }
3532  while (cur != NULL) {
3533  if (cur->type == XML_ELEMENT_NODE)
3534  return(cur);
3535  cur = cur->next;
3536  }
3537  return(NULL);
3538 }
3539 
3551 xmlNodePtr
3552 xmlLastElementChild(xmlNodePtr parent) {
3553  xmlNodePtr cur = NULL;
3554 
3555  if (parent == NULL)
3556  return(NULL);
3557  switch (parent->type) {
3558  case XML_ELEMENT_NODE:
3559  case XML_ENTITY_NODE:
3560  case XML_DOCUMENT_NODE:
3563  cur = parent->last;
3564  break;
3565  default:
3566  return(NULL);
3567  }
3568  while (cur != NULL) {
3569  if (cur->type == XML_ELEMENT_NODE)
3570  return(cur);
3571  cur = cur->prev;
3572  }
3573  return(NULL);
3574 }
3575 
3588 xmlNodePtr
3589 xmlPreviousElementSibling(xmlNodePtr node) {
3590  if (node == NULL)
3591  return(NULL);
3592  switch (node->type) {
3593  case XML_ELEMENT_NODE:
3594  case XML_TEXT_NODE:
3596  case XML_ENTITY_REF_NODE:
3597  case XML_ENTITY_NODE:
3598  case XML_PI_NODE:
3599  case XML_COMMENT_NODE:
3600  case XML_XINCLUDE_START:
3601  case XML_XINCLUDE_END:
3602  node = node->prev;
3603  break;
3604  default:
3605  return(NULL);
3606  }
3607  while (node != NULL) {
3608  if (node->type == XML_ELEMENT_NODE)
3609  return(node);
3610  node = node->prev;
3611  }
3612  return(NULL);
3613 }
3614 
3627 xmlNodePtr
3628 xmlNextElementSibling(xmlNodePtr node) {
3629  if (node == NULL)
3630  return(NULL);
3631  switch (node->type) {
3632  case XML_ELEMENT_NODE:
3633  case XML_TEXT_NODE:
3635  case XML_ENTITY_REF_NODE:
3636  case XML_ENTITY_NODE:
3637  case XML_PI_NODE:
3638  case XML_COMMENT_NODE:
3639  case XML_DTD_NODE:
3640  case XML_XINCLUDE_START:
3641  case XML_XINCLUDE_END:
3642  node = node->next;
3643  break;
3644  default:
3645  return(NULL);
3646  }
3647  while (node != NULL) {
3648  if (node->type == XML_ELEMENT_NODE)
3649  return(node);
3650  node = node->next;
3651  }
3652  return(NULL);
3653 }
3654 
3655 #endif /* LIBXML_TREE_ENABLED */
3656 
3664 void
3666  xmlNodePtr next;
3668  xmlDictPtr dict = NULL;
3669  size_t depth = 0;
3670 
3671  if (cur == NULL) return;
3672  if (cur->type == XML_NAMESPACE_DECL) {
3673  xmlFreeNsList((xmlNsPtr) cur);
3674  return;
3675  }
3676  if ((cur->type == XML_DOCUMENT_NODE) ||
3677 #ifdef LIBXML_DOCB_ENABLED
3678  (cur->type == XML_DOCB_DOCUMENT_NODE) ||
3679 #endif
3680  (cur->type == XML_HTML_DOCUMENT_NODE)) {
3681  xmlFreeDoc((xmlDocPtr) cur);
3682  return;
3683  }
3684  if (cur->doc != NULL) dict = cur->doc->dict;
3685  while (1) {
3686  while ((cur->children != NULL) &&
3687  (cur->type != XML_DTD_NODE) &&
3688  (cur->type != XML_ENTITY_REF_NODE)) {
3689  cur = cur->children;
3690  depth += 1;
3691  }
3692 
3693  next = cur->next;
3694  parent = cur->parent;
3695  if (cur->type != XML_DTD_NODE) {
3696 
3699 
3700  if (((cur->type == XML_ELEMENT_NODE) ||
3701  (cur->type == XML_XINCLUDE_START) ||
3702  (cur->type == XML_XINCLUDE_END)) &&
3703  (cur->properties != NULL))
3705  if ((cur->type != XML_ELEMENT_NODE) &&
3706  (cur->type != XML_XINCLUDE_START) &&
3707  (cur->type != XML_XINCLUDE_END) &&
3708  (cur->type != XML_ENTITY_REF_NODE) &&
3709  (cur->content != (xmlChar *) &(cur->properties))) {
3710  DICT_FREE(cur->content)
3711  }
3712  if (((cur->type == XML_ELEMENT_NODE) ||
3713  (cur->type == XML_XINCLUDE_START) ||
3714  (cur->type == XML_XINCLUDE_END)) &&
3715  (cur->nsDef != NULL))
3716  xmlFreeNsList(cur->nsDef);
3717 
3718  /*
3719  * When a node is a text node or a comment, it uses a global static
3720  * variable for the name of the node.
3721  * Otherwise the node name might come from the document's
3722  * dictionary
3723  */
3724  if ((cur->name != NULL) &&
3725  (cur->type != XML_TEXT_NODE) &&
3726  (cur->type != XML_COMMENT_NODE))
3727  DICT_FREE(cur->name)
3728  xmlFree(cur);
3729  }
3730 
3731  if (next != NULL) {
3732  cur = next;
3733  } else {
3734  if ((depth == 0) || (parent == NULL))
3735  break;
3736  depth -= 1;
3737  cur = parent;
3738  cur->children = NULL;
3739  }
3740  }
3741 }
3742 
3750 void
3751 xmlFreeNode(xmlNodePtr cur) {
3752  xmlDictPtr dict = NULL;
3753 
3754  if (cur == NULL) return;
3755 
3756  /* use xmlFreeDtd for DTD nodes */
3757  if (cur->type == XML_DTD_NODE) {
3758  xmlFreeDtd((xmlDtdPtr) cur);
3759  return;
3760  }
3761  if (cur->type == XML_NAMESPACE_DECL) {
3762  xmlFreeNs((xmlNsPtr) cur);
3763  return;
3764  }
3765  if (cur->type == XML_ATTRIBUTE_NODE) {
3766  xmlFreeProp((xmlAttrPtr) cur);
3767  return;
3768  }
3769 
3772 
3773  if (cur->doc != NULL) dict = cur->doc->dict;
3774 
3775  if (cur->type == XML_ENTITY_DECL) {
3776  xmlEntityPtr ent = (xmlEntityPtr) cur;
3777  DICT_FREE(ent->SystemID);
3778  DICT_FREE(ent->ExternalID);
3779  }
3780  if ((cur->children != NULL) &&
3781  (cur->type != XML_ENTITY_REF_NODE))
3782  xmlFreeNodeList(cur->children);
3783  if (((cur->type == XML_ELEMENT_NODE) ||
3784  (cur->type == XML_XINCLUDE_START) ||
3785  (cur->type == XML_XINCLUDE_END)) &&
3786  (cur->properties != NULL))
3788  if ((cur->type != XML_ELEMENT_NODE) &&
3789  (cur->content != NULL) &&
3790  (cur->type != XML_ENTITY_REF_NODE) &&
3791  (cur->type != XML_XINCLUDE_END) &&
3792  (cur->type != XML_XINCLUDE_START) &&
3793  (cur->content != (xmlChar *) &(cur->properties))) {
3794  DICT_FREE(cur->content)
3795  }
3796 
3797  /*
3798  * When a node is a text node or a comment, it uses a global static
3799  * variable for the name of the node.
3800  * Otherwise the node name might come from the document's dictionary
3801  */
3802  if ((cur->name != NULL) &&
3803  (cur->type != XML_TEXT_NODE) &&
3804  (cur->type != XML_COMMENT_NODE))
3805  DICT_FREE(cur->name)
3806 
3807  if (((cur->type == XML_ELEMENT_NODE) ||
3808  (cur->type == XML_XINCLUDE_START) ||
3809  (cur->type == XML_XINCLUDE_END)) &&
3810  (cur->nsDef != NULL))
3811  xmlFreeNsList(cur->nsDef);
3812  xmlFree(cur);
3813 }
3814 
3825 void
3827  if (cur == NULL) {
3828 #ifdef DEBUG_TREE
3830  "xmlUnlinkNode : node == NULL\n");
3831 #endif
3832  return;
3833  }
3834  if (cur->type == XML_NAMESPACE_DECL)
3835  return;
3836  if (cur->type == XML_DTD_NODE) {
3837  xmlDocPtr doc;
3838  doc = cur->doc;
3839  if (doc != NULL) {
3840  if (doc->intSubset == (xmlDtdPtr) cur)
3841  doc->intSubset = NULL;
3842  if (doc->extSubset == (xmlDtdPtr) cur)
3843  doc->extSubset = NULL;
3844  }
3845  }
3846  if (cur->type == XML_ENTITY_DECL) {
3847  xmlDocPtr doc;
3848  doc = cur->doc;
3849  if (doc != NULL) {
3850  if (doc->intSubset != NULL) {
3851  if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3852  xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3853  NULL);
3854  if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3855  xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3856  NULL);
3857  }
3858  if (doc->extSubset != NULL) {
3859  if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3860  xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3861  NULL);
3862  if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3863  xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3864  NULL);
3865  }
3866  }
3867  }
3868  if (cur->parent != NULL) {
3870  parent = cur->parent;
3871  if (cur->type == XML_ATTRIBUTE_NODE) {
3872  if (parent->properties == (xmlAttrPtr) cur)
3873  parent->properties = ((xmlAttrPtr) cur)->next;
3874  } else {
3875  if (parent->children == cur)
3876  parent->children = cur->next;
3877  if (parent->last == cur)
3878  parent->last = cur->prev;
3879  }
3880  cur->parent = NULL;
3881  }
3882  if (cur->next != NULL)
3883  cur->next->prev = cur->prev;
3884  if (cur->prev != NULL)
3885  cur->prev->next = cur->next;
3886  cur->next = cur->prev = NULL;
3887 }
3888 
3889 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
3890 
3901 xmlNodePtr
3902 xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3903  if (old == cur) return(NULL);
3904  if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) ||
3905  (old->parent == NULL)) {
3906 #ifdef DEBUG_TREE
3908  "xmlReplaceNode : old == NULL or without parent\n");
3909 #endif
3910  return(NULL);
3911  }
3912  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3913  xmlUnlinkNode(old);
3914  return(old);
3915  }
3916  if (cur == old) {
3917  return(old);
3918  }
3919  if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3920 #ifdef DEBUG_TREE
3922  "xmlReplaceNode : Trying to replace attribute node with other node type\n");
3923 #endif
3924  return(old);
3925  }
3926  if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3927 #ifdef DEBUG_TREE
3929  "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3930 #endif
3931  return(old);
3932  }
3933  xmlUnlinkNode(cur);
3934  xmlSetTreeDoc(cur, old->doc);
3935  cur->parent = old->parent;
3936  cur->next = old->next;
3937  if (cur->next != NULL)
3938  cur->next->prev = cur;
3939  cur->prev = old->prev;
3940  if (cur->prev != NULL)
3941  cur->prev->next = cur;
3942  if (cur->parent != NULL) {
3943  if (cur->type == XML_ATTRIBUTE_NODE) {
3944  if (cur->parent->properties == (xmlAttrPtr)old)
3945  cur->parent->properties = ((xmlAttrPtr) cur);
3946  } else {
3947  if (cur->parent->children == old)
3948  cur->parent->children = cur;
3949  if (cur->parent->last == old)
3950  cur->parent->last = cur;
3951  }
3952  }
3953  old->next = old->prev = NULL;
3954  old->parent = NULL;
3955  return(old);
3956 }
3957 #endif /* LIBXML_TREE_ENABLED */
3958 
3959 /************************************************************************
3960  * *
3961  * Copy operations *
3962  * *
3963  ************************************************************************/
3964 
3973 xmlNsPtr
3975  xmlNsPtr ret;
3976 
3977  if (cur == NULL) return(NULL);
3978  switch (cur->type) {
3979  case XML_LOCAL_NAMESPACE:
3980  ret = xmlNewNs(NULL, cur->href, cur->prefix);
3981  break;
3982  default:
3983 #ifdef DEBUG_TREE
3985  "xmlCopyNamespace: invalid type %d\n", cur->type);
3986 #endif
3987  return(NULL);
3988  }
3989  return(ret);
3990 }
3991 
4000 xmlNsPtr
4002  xmlNsPtr ret = NULL;
4003  xmlNsPtr p = NULL,q;
4004 
4005  while (cur != NULL) {
4006  q = xmlCopyNamespace(cur);
4007  if (p == NULL) {
4008  ret = p = q;
4009  } else {
4010  p->next = q;
4011  p = q;
4012  }
4013  cur = cur->next;
4014  }
4015  return(ret);
4016 }
4017 
4018 static xmlNodePtr
4019 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
4020 
4021 static xmlAttrPtr
4022 xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
4023  xmlAttrPtr ret;
4024 
4025  if (cur == NULL) return(NULL);
4026  if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4027  return(NULL);
4028  if (target != NULL)
4029  ret = xmlNewDocProp(target->doc, cur->name, NULL);
4030  else if (doc != NULL)
4031  ret = xmlNewDocProp(doc, cur->name, NULL);
4032  else if (cur->parent != NULL)
4033  ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
4034  else if (cur->children != NULL)
4035  ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
4036  else
4037  ret = xmlNewDocProp(NULL, cur->name, NULL);
4038  if (ret == NULL) return(NULL);
4039  ret->parent = target;
4040 
4041  if ((cur->ns != NULL) && (target != NULL)) {
4042  xmlNsPtr ns;
4043 
4044  ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
4045  if (ns == NULL) {
4046  /*
4047  * Humm, we are copying an element whose namespace is defined
4048  * out of the new tree scope. Search it in the original tree
4049  * and add it at the top of the new tree
4050  */
4051  ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
4052  if (ns != NULL) {
4054  xmlNodePtr pred = NULL;
4055 
4056  while (root->parent != NULL) {
4057  pred = root;
4058  root = root->parent;
4059  }
4060  if (root == (xmlNodePtr) target->doc) {
4061  /* correct possibly cycling above the document elt */
4062  root = pred;
4063  }
4064  ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4065  }
4066  } else {
4067  /*
4068  * we have to find something appropriate here since
4069  * we cant be sure, that the namespace we found is identified
4070  * by the prefix
4071  */
4072  if (xmlStrEqual(ns->href, cur->ns->href)) {
4073  /* this is the nice case */
4074  ret->ns = ns;
4075  } else {
4076  /*
4077  * we are in trouble: we need a new reconciled namespace.
4078  * This is expensive
4079  */
4080  ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns);
4081  }
4082  }
4083 
4084  } else
4085  ret->ns = NULL;
4086 
4087  if (cur->children != NULL) {
4088  xmlNodePtr tmp;
4089 
4090  ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4091  ret->last = NULL;
4092  tmp = ret->children;
4093  while (tmp != NULL) {
4094  /* tmp->parent = (xmlNodePtr)ret; */
4095  if (tmp->next == NULL)
4096  ret->last = tmp;
4097  tmp = tmp->next;
4098  }
4099  }
4100  /*
4101  * Try to handle IDs
4102  */
4103  if ((target!= NULL) && (cur!= NULL) &&
4104  (target->doc != NULL) && (cur->doc != NULL) &&
4105  (cur->doc->ids != NULL) && (cur->parent != NULL)) {
4106  if (xmlIsID(cur->doc, cur->parent, cur)) {
4107  xmlChar *id;
4108 
4109  id = xmlNodeListGetString(cur->doc, cur->children, 1);
4110  if (id != NULL) {
4111  xmlAddID(NULL, target->doc, id, ret);
4112  xmlFree(id);
4113  }
4114  }
4115  }
4116  return(ret);
4117 }
4118 
4128 xmlAttrPtr
4130  return xmlCopyPropInternal(NULL, target, cur);
4131 }
4132 
4142 xmlAttrPtr
4144  xmlAttrPtr ret = NULL;
4145  xmlAttrPtr p = NULL,q;
4146 
4147  if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4148  return(NULL);
4149  while (cur != NULL) {
4150  q = xmlCopyProp(target, cur);
4151  if (q == NULL)
4152  return(NULL);
4153  if (p == NULL) {
4154  ret = p = q;
4155  } else {
4156  p->next = q;
4157  q->prev = p;
4158  p = q;
4159  }
4160  cur = cur->next;
4161  }
4162  return(ret);
4163 }
4164 
4165 /*
4166  * NOTE about the CopyNode operations !
4167  *
4168  * They are split into external and internal parts for one
4169  * tricky reason: namespaces. Doing a direct copy of a node
4170  * say RPM:Copyright without changing the namespace pointer to
4171  * something else can produce stale links. One way to do it is
4172  * to keep a reference counter but this doesn't work as soon
4173  * as one moves the element or the subtree out of the scope of
4174  * the existing namespace. The actual solution seems to be to add
4175  * a copy of the namespace at the top of the copied tree if
4176  * not available in the subtree.
4177  * Hence two functions, the public front-end call the inner ones
4178  * The argument "recursive" normally indicates a recursive copy
4179  * of the node with values 0 (no) and 1 (yes). For XInclude,
4180  * however, we allow a value of 2 to indicate copy properties and
4181  * namespace info, but don't recurse on children.
4182  */
4183 
4184 static xmlNodePtr
4185 xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
4186  int extended) {
4187  xmlNodePtr ret;
4188 
4189  if (node == NULL) return(NULL);
4190  switch (node->type) {
4191  case XML_TEXT_NODE:
4193  case XML_ELEMENT_NODE:
4195  case XML_ENTITY_REF_NODE:
4196  case XML_ENTITY_NODE:
4197  case XML_PI_NODE:
4198  case XML_COMMENT_NODE:
4199  case XML_XINCLUDE_START:
4200  case XML_XINCLUDE_END:
4201  break;
4202  case XML_ATTRIBUTE_NODE:
4203  return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
4204  case XML_NAMESPACE_DECL:
4206 
4207  case XML_DOCUMENT_NODE:
4209 #ifdef LIBXML_DOCB_ENABLED
4210  case XML_DOCB_DOCUMENT_NODE:
4211 #endif
4212 #ifdef LIBXML_TREE_ENABLED
4213  return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
4214 #endif /* LIBXML_TREE_ENABLED */
4216  case XML_NOTATION_NODE:
4217  case XML_DTD_NODE:
4218  case XML_ELEMENT_DECL:
4219  case XML_ATTRIBUTE_DECL:
4220  case XML_ENTITY_DECL:
4221  return(NULL);
4222  }
4223 
4224  /*
4225  * Allocate a new node and fill the fields.
4226  */
4227  ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4228  if (ret == NULL) {
4229  xmlTreeErrMemory("copying node");
4230  return(NULL);
4231  }
4232  memset(ret, 0, sizeof(xmlNode));
4233  ret->type = node->type;
4234 
4235  ret->doc = doc;
4236  ret->parent = parent;
4237  if (node->name == xmlStringText)
4238  ret->name = xmlStringText;
4239  else if (node->name == xmlStringTextNoenc)
4240  ret->name = xmlStringTextNoenc;
4241  else if (node->name == xmlStringComment)
4242  ret->name = xmlStringComment;
4243  else if (node->name != NULL) {
4244  if ((doc != NULL) && (doc->dict != NULL))
4245  ret->name = xmlDictLookup(doc->dict, node->name, -1);
4246  else
4247  ret->name = xmlStrdup(node->name);
4248  }
4249  if ((node->type != XML_ELEMENT_NODE) &&
4250  (node->content != NULL) &&
4251  (node->type != XML_ENTITY_REF_NODE) &&
4252  (node->type != XML_XINCLUDE_END) &&
4253  (node->type != XML_XINCLUDE_START)) {
4254  ret->content = xmlStrdup(node->content);
4255  }else{
4256  if (node->type == XML_ELEMENT_NODE)
4257  ret->line = node->line;
4258  }
4259  if (parent != NULL) {
4260  xmlNodePtr tmp;
4261 
4262  /*
4263  * this is a tricky part for the node register thing:
4264  * in case ret does get coalesced in xmlAddChild
4265  * the deregister-node callback is called; so we register ret now already
4266  */
4269 
4270  tmp = xmlAddChild(parent, ret);
4271  /* node could have coalesced */
4272  if (tmp != ret)
4273  return(tmp);
4274  }
4275 
4276  if (!extended)
4277  goto out;
4278  if (((node->type == XML_ELEMENT_NODE) ||
4279  (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
4280  ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4281 
4282  if (node->ns != NULL) {
4283  xmlNsPtr ns;
4284 
4285  ns = xmlSearchNs(doc, ret, node->ns->prefix);
4286  if (ns == NULL) {
4287  /*
4288  * Humm, we are copying an element whose namespace is defined
4289  * out of the new tree scope. Search it in the original tree
4290  * and add it at the top of the new tree
4291  */
4292  ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4293  if (ns != NULL) {
4294  xmlNodePtr root = ret;
4295 
4296  while (root->parent != NULL) root = root->parent;
4297  ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4298  } else {
4299  ret->ns = xmlNewReconciledNs(doc, ret, node->ns);
4300  }
4301  } else {
4302  /*
4303  * reference the existing namespace definition in our own tree.
4304  */
4305  ret->ns = ns;
4306  }
4307  }
4308  if (((node->type == XML_ELEMENT_NODE) ||
4309  (node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
4310  ret->properties = xmlCopyPropList(ret, node->properties);
4311  if (node->type == XML_ENTITY_REF_NODE) {
4312  if ((doc == NULL) || (node->doc != doc)) {
4313  /*
4314  * The copied node will go into a separate document, so
4315  * to avoid dangling references to the ENTITY_DECL node
4316  * we cannot keep the reference. Try to find it in the
4317  * target document.
4318  */
4319  ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4320  } else {
4321  ret->children = node->children;
4322  }
4323  ret->last = ret->children;
4324  } else if ((node->children != NULL) && (extended != 2)) {
4325  ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
4327  }
4328 
4329 out:
4330  /* if parent != NULL we already registered the node above */
4331  if ((parent == NULL) &&
4334  return(ret);
4335 }
4336 
4337 static xmlNodePtr
4338 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4339  xmlNodePtr ret = NULL;
4340  xmlNodePtr p = NULL,q;
4341 
4342  while (node != NULL) {
4343 #ifdef LIBXML_TREE_ENABLED
4344  if (node->type == XML_DTD_NODE ) {
4345  if (doc == NULL) {
4346  node = node->next;
4347  continue;
4348  }
4349  if (doc->intSubset == NULL) {
4350  q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4351  if (q == NULL) return(NULL);
4352  q->doc = doc;
4353  q->parent = parent;
4354  doc->intSubset = (xmlDtdPtr) q;
4355  xmlAddChild(parent, q);
4356  } else {
4357  q = (xmlNodePtr) doc->intSubset;
4358  xmlAddChild(parent, q);
4359  }
4360  } else
4361 #endif /* LIBXML_TREE_ENABLED */
4362  q = xmlStaticCopyNode(node, doc, parent, 1);
4363  if (q == NULL) return(NULL);
4364  if (ret == NULL) {
4365  q->prev = NULL;
4366  ret = p = q;
4367  } else if (p != q) {
4368  /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
4369  p->next = q;
4370  q->prev = p;
4371  p = q;
4372  }
4373  node = node->next;
4374  }
4375  return(ret);
4376 }
4377 
4389 xmlNodePtr
4390 xmlCopyNode(xmlNodePtr node, int extended) {
4391  xmlNodePtr ret;
4392 
4393  ret = xmlStaticCopyNode(node, NULL, NULL, extended);
4394  return(ret);
4395 }
4396 
4409 xmlNodePtr
4410 xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
4411  xmlNodePtr ret;
4412 
4413  ret = xmlStaticCopyNode(node, doc, NULL, extended);
4414  return(ret);
4415 }
4416 
4427  xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4428  return(ret);
4429 }
4430 
4441  xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4442  return(ret);
4443 }
4444 
4445 #if defined(LIBXML_TREE_ENABLED)
4446 
4454 xmlDtdPtr
4455 xmlCopyDtd(xmlDtdPtr dtd) {
4456  xmlDtdPtr ret;
4457  xmlNodePtr cur, p = NULL, q;
4458 
4459  if (dtd == NULL) return(NULL);
4460  ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4461  if (ret == NULL) return(NULL);
4462  if (dtd->entities != NULL)
4463  ret->entities = (void *) xmlCopyEntitiesTable(
4464  (xmlEntitiesTablePtr) dtd->entities);
4465  if (dtd->notations != NULL)
4466  ret->notations = (void *) xmlCopyNotationTable(
4468  if (dtd->elements != NULL)
4469  ret->elements = (void *) xmlCopyElementTable(
4470  (xmlElementTablePtr) dtd->elements);
4471  if (dtd->attributes != NULL)
4472  ret->attributes = (void *) xmlCopyAttributeTable(
4474  if (dtd->pentities != NULL)
4475  ret->pentities = (void *) xmlCopyEntitiesTable(
4477 
4478  cur = dtd->children;
4479  while (cur != NULL) {
4480  q = NULL;
4481 
4482  if (cur->type == XML_ENTITY_DECL) {
4483  xmlEntityPtr tmp = (xmlEntityPtr) cur;
4484  switch (tmp->etype) {
4488  q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4489  break;
4492  q = (xmlNodePtr)
4493  xmlGetParameterEntityFromDtd(ret, tmp->name);
4494  break;
4496  break;
4497  }
4498  } else if (cur->type == XML_ELEMENT_DECL) {
4499  xmlElementPtr tmp = (xmlElementPtr) cur;
4500  q = (xmlNodePtr)
4501  xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4502  } else if (cur->type == XML_ATTRIBUTE_DECL) {
4503  xmlAttributePtr tmp = (xmlAttributePtr) cur;
4504  q = (xmlNodePtr)
4505  xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4506  } else if (cur->type == XML_COMMENT_NODE) {
4507  q = xmlCopyNode(cur, 0);
4508  }
4509 
4510  if (q == NULL) {
4511  cur = cur->next;
4512  continue;
4513  }
4514 
4515  if (p == NULL)
4516  ret->children = q;
4517  else
4518  p->next = q;
4519 
4520  q->prev = p;
4521  q->parent = (xmlNodePtr) ret;
4522  q->next = NULL;
4523  ret->last = q;
4524  p = q;
4525  cur = cur->next;
4526  }
4527 
4528  return(ret);
4529 }
4530 #endif
4531 
4532 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
4533 
4543 xmlDocPtr
4544 xmlCopyDoc(xmlDocPtr doc, int recursive) {
4545  xmlDocPtr ret;
4546 
4547  if (doc == NULL) return(NULL);
4548  ret = xmlNewDoc(doc->version);
4549  if (ret == NULL) return(NULL);
4550  if (doc->name != NULL)
4551  ret->name = xmlMemStrdup(doc->name);
4552  if (doc->encoding != NULL)
4553  ret->encoding = xmlStrdup(doc->encoding);
4554  if (doc->URL != NULL)
4555  ret->URL = xmlStrdup(doc->URL);
4556  ret->charset = doc->charset;
4557  ret->compression = doc->compression;
4558  ret->standalone = doc->standalone;
4559  if (!recursive) return(ret);
4560 
4561  ret->last = NULL;
4562  ret->children = NULL;
4563 #ifdef LIBXML_TREE_ENABLED
4564  if (doc->intSubset != NULL) {
4565  ret->intSubset = xmlCopyDtd(doc->intSubset);
4566  if (ret->intSubset == NULL) {
4567  xmlFreeDoc(ret);
4568  return(NULL);
4569  }
4570  xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
4571  ret->intSubset->parent = ret;
4572  }
4573 #endif
4574  if (doc->oldNs != NULL)
4575  ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4576  if (doc->children != NULL) {
4577  xmlNodePtr tmp;
4578 
4579  ret->children = xmlStaticCopyNodeList(doc->children, ret,
4580  (xmlNodePtr)ret);
4581  ret->last = NULL;
4582  tmp = ret->children;
4583  while (tmp != NULL) {
4584  if (tmp->next == NULL)
4585  ret->last = tmp;
4586  tmp = tmp->next;
4587  }
4588  }
4589  return(ret);
4590 }
4591 #endif /* LIBXML_TREE_ENABLED */
4592 
4593 /************************************************************************
4594  * *
4595  * Content access functions *
4596  * *
4597  ************************************************************************/
4598 
4609 static long
4610 xmlGetLineNoInternal(const xmlNode *node, int depth)
4611 {
4612  long result = -1;
4613 
4614  if (depth >= 5)
4615  return(-1);
4616 
4617  if (!node)
4618  return result;
4619  if ((node->type == XML_ELEMENT_NODE) ||
4620  (node->type == XML_TEXT_NODE) ||
4621  (node->type == XML_COMMENT_NODE) ||
4622  (node->type == XML_PI_NODE)) {
4623  if (node->line == 65535) {
4624  if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL))
4625  result = (long) (ptrdiff_t) node->psvi;
4626  else if ((node->type == XML_ELEMENT_NODE) &&
4627  (node->children != NULL))
4628  result = xmlGetLineNoInternal(node->children, depth + 1);
4629  else if (node->next != NULL)
4630  result = xmlGetLineNoInternal(node->next, depth + 1);
4631  else if (node->prev != NULL)
4632  result = xmlGetLineNoInternal(node->prev, depth + 1);
4633  }
4634  if ((result == -1) || (result == 65535))
4635  result = (long) node->line;
4636  } else if ((node->prev != NULL) &&
4637  ((node->prev->type == XML_ELEMENT_NODE) ||
4638  (node->prev->type == XML_TEXT_NODE) ||
4639  (node->prev->type == XML_COMMENT_NODE) ||
4640  (node->prev->type == XML_PI_NODE)))
4641  result = xmlGetLineNoInternal(node->prev, depth + 1);
4642  else if ((node->parent != NULL) &&
4643  (node->parent->type == XML_ELEMENT_NODE))
4644  result = xmlGetLineNoInternal(node->parent, depth + 1);
4645 
4646  return result;
4647 }
4648 
4659 long
4660 xmlGetLineNo(const xmlNode *node)
4661 {
4662  return(xmlGetLineNoInternal(node, 0));
4663 }
4664 
4665 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
4666 
4675 xmlChar *
4676 xmlGetNodePath(const xmlNode *node)
4677 {
4678  const xmlNode *cur, *tmp, *next;
4679  xmlChar *buffer = NULL, *temp;
4680  size_t buf_len;
4681  xmlChar *buf;
4682  const char *sep;
4683  const char *name;
4684  char nametemp[100];
4685  int occur = 0, generic;
4686 
4687  if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
4688  return (NULL);
4689 
4690  buf_len = 500;
4691  buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4692  if (buffer == NULL) {
4693  xmlTreeErrMemory("getting node path");
4694  return (NULL);
4695  }
4696  buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4697  if (buf == NULL) {
4698  xmlTreeErrMemory("getting node path");
4699  xmlFree(buffer);
4700  return (NULL);
4701  }
4702 
4703  buffer[0] = 0;
4704  cur = node;
4705  do {
4706  name = "";
4707  sep = "?";
4708  occur = 0;
4709  if ((cur->type == XML_DOCUMENT_NODE) ||
4710  (cur->type == XML_HTML_DOCUMENT_NODE)) {
4711  if (buffer[0] == '/')
4712  break;
4713  sep = "/";
4714  next = NULL;
4715  } else if (cur->type == XML_ELEMENT_NODE) {
4716  generic = 0;
4717  sep = "/";
4718  name = (const char *) cur->name;
4719  if (cur->ns) {
4720  if (cur->ns->prefix != NULL) {
4721  snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4722  (char *)cur->ns->prefix, (char *)cur->name);
4723  nametemp[sizeof(nametemp) - 1] = 0;
4724  name = nametemp;
4725  } else {
4726  /*
4727  * We cannot express named elements in the default
4728  * namespace, so use "*".
4729  */
4730  generic = 1;
4731  name = "*";
4732  }
4733  }
4734  next = cur->parent;
4735 
4736  /*
4737  * Thumbler index computation
4738  * TODO: the occurrence test seems bogus for namespaced names
4739  */
4740  tmp = cur->prev;
4741  while (tmp != NULL) {
4742  if ((tmp->type == XML_ELEMENT_NODE) &&
4743  (generic ||
4744  (xmlStrEqual(cur->name, tmp->name) &&
4745  ((tmp->ns == cur->ns) ||
4746  ((tmp->ns != NULL) && (cur->ns != NULL) &&
4747  (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4748  occur++;
4749  tmp = tmp->prev;
4750  }
4751  if (occur == 0) {
4752  tmp = cur->next;
4753  while (tmp != NULL && occur == 0) {
4754  if ((tmp->type == XML_ELEMENT_NODE) &&
4755  (generic ||
4756  (xmlStrEqual(cur->name, tmp->name) &&
4757  ((tmp->ns == cur->ns) ||
4758  ((tmp->ns != NULL) && (cur->ns != NULL) &&
4759  (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4760  occur++;
4761  tmp = tmp->next;
4762  }
4763  if (occur != 0)
4764  occur = 1;
4765  } else
4766  occur++;
4767  } else if (cur->type == XML_COMMENT_NODE) {
4768  sep = "/";
4769  name = "comment()";
4770  next = cur->parent;
4771 
4772  /*
4773  * Thumbler index computation
4774  */
4775  tmp = cur->prev;
4776  while (tmp != NULL) {
4777  if (tmp->type == XML_COMMENT_NODE)
4778  occur++;
4779  tmp = tmp->prev;
4780  }
4781  if (occur == 0) {
4782  tmp = cur->next;
4783  while (tmp != NULL && occur == 0) {
4784  if (tmp->type == XML_COMMENT_NODE)
4785  occur++;
4786  tmp = tmp->next;
4787  }
4788  if (occur != 0)
4789  occur = 1;
4790  } else
4791  occur++;
4792  } else if ((cur->type == XML_TEXT_NODE) ||
4793  (cur->type == XML_CDATA_SECTION_NODE)) {
4794  sep = "/";
4795  name = "text()";
4796  next = cur->parent;
4797 
4798  /*
4799  * Thumbler index computation
4800  */
4801  tmp = cur->prev;
4802  while (tmp != NULL) {
4803  if ((tmp->type == XML_TEXT_NODE) ||
4804  (tmp->type == XML_CDATA_SECTION_NODE))
4805  occur++;
4806  tmp = tmp->prev;
4807  }
4808  /*
4809  * Evaluate if this is the only text- or CDATA-section-node;
4810  * if yes, then we'll get "text()", otherwise "text()[1]".
4811  */
4812  if (occur == 0) {
4813  tmp = cur->next;
4814  while (tmp != NULL) {
4815  if ((tmp->type == XML_TEXT_NODE) ||
4816  (tmp->type == XML_CDATA_SECTION_NODE))
4817  {
4818  occur = 1;
4819  break;
4820  }
4821  tmp = tmp->next;
4822  }
4823  } else
4824  occur++;
4825  } else if (cur->type == XML_PI_NODE) {
4826  sep = "/";
4827  snprintf(nametemp, sizeof(nametemp) - 1,
4828  "processing-instruction('%s')", (char *)cur->name);
4829  nametemp[sizeof(nametemp) - 1] = 0;
4830  name = nametemp;
4831 
4832  next = cur->parent;
4833 
4834  /*
4835  * Thumbler index computation
4836  */
4837  tmp = cur->prev;
4838  while (tmp != NULL) {
4839  if ((tmp->type == XML_PI_NODE) &&
4840  (xmlStrEqual(cur->name, tmp->name)))
4841  occur++;
4842  tmp = tmp->prev;
4843  }
4844  if (occur == 0) {
4845  tmp = cur->next;
4846  while (tmp != NULL && occur == 0) {
4847  if ((tmp->type == XML_PI_NODE) &&
4848  (xmlStrEqual(cur->name, tmp->name)))
4849  occur++;
4850  tmp = tmp->next;
4851  }
4852  if (occur != 0)
4853  occur = 1;
4854  } else
4855  occur++;
4856 
4857  } else if (cur->type == XML_ATTRIBUTE_NODE) {
4858  sep = "/@";
4859  name = (const char *) (((xmlAttrPtr) cur)->name);
4860  if (cur->ns) {
4861  if (cur->ns->prefix != NULL)
4862  snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4863  (char *)cur->ns->prefix, (char *)cur->name);
4864  else
4865  snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4866  (char *)cur->name);
4867  nametemp[sizeof(nametemp) - 1] = 0;
4868  name = nametemp;
4869  }
4870  next = ((xmlAttrPtr) cur)->parent;
4871  } else {
4872  next = cur->parent;
4873  }
4874 
4875  /*
4876  * Make sure there is enough room
4877  */
4878  if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4879  buf_len =
4880  2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4881  temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4882  if (temp == NULL) {
4883  xmlTreeErrMemory("getting node path");
4884  xmlFree(buf);
4885  xmlFree(buffer);
4886  return (NULL);
4887  }
4888  buffer = temp;
4889  temp = (xmlChar *) xmlRealloc(buf, buf_len);
4890  if (temp == NULL) {
4891  xmlTreeErrMemory("getting node path");
4892  xmlFree(buf);
4893  xmlFree(buffer);
4894  return (NULL);
4895  }
4896  buf = temp;
4897  }
4898  if (occur == 0)
4899  snprintf((char *) buf, buf_len, "%s%s%s",
4900  sep, name, (char *) buffer);
4901  else
4902  snprintf((char *) buf, buf_len, "%s%s[%d]%s",
4903  sep, name, occur, (char *) buffer);
4904  snprintf((char *) buffer, buf_len, "%s", (char *)buf);
4905  cur = next;
4906  } while (cur != NULL);
4907  xmlFree(buf);
4908  return (buffer);
4909 }
4910 #endif /* LIBXML_TREE_ENABLED */
4911 
4921 xmlNodePtr
4922 xmlDocGetRootElement(const xmlDoc *doc) {
4923  xmlNodePtr ret;
4924 
4925  if (doc == NULL) return(NULL);
4926  ret = doc->children;
4927  while (ret != NULL) {
4928  if (ret->type == XML_ELEMENT_NODE)
4929  return(ret);
4930  ret = ret->next;
4931  }
4932  return(ret);
4933 }
4934 
4935 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
4936 
4947 xmlNodePtr
4948 xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4949  xmlNodePtr old = NULL;
4950 
4951  if (doc == NULL) return(NULL);
4952  if ((root == NULL) || (root->type == XML_NAMESPACE_DECL))
4953  return(NULL);
4955  xmlSetTreeDoc(root, doc);
4956  root->parent = (xmlNodePtr) doc;
4957  old = doc->children;
4958  while (old != NULL) {
4959  if (old->type == XML_ELEMENT_NODE)
4960  break;
4961  old = old->next;
4962  }
4963  if (old == NULL) {
4964  if (doc->children == NULL) {
4965  doc->children = root;
4966  doc->last = root;
4967  } else {
4968  xmlAddSibling(doc->children, root);
4969  }
4970  } else {
4971  xmlReplaceNode(old, root);
4972  }
4973  return(old);
4974 }
4975 #endif
4976 
4977 #if defined(LIBXML_TREE_ENABLED)
4978 
4986 void
4987 xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
4988  xmlNsPtr ns;
4989 
4990  if (cur == NULL) return;
4991  switch(cur->type) {
4992  case XML_TEXT_NODE:
4994  case XML_COMMENT_NODE:
4995  case XML_DOCUMENT_NODE:
4998  case XML_NOTATION_NODE:
5000  case XML_DTD_NODE:
5001  case XML_ELEMENT_DECL:
5002  case XML_ATTRIBUTE_DECL:
5003  case XML_ENTITY_DECL:
5004  case XML_PI_NODE:
5005  case XML_ENTITY_REF_NODE:
5006  case XML_ENTITY_NODE:
5007  case XML_NAMESPACE_DECL:
5008 #ifdef LIBXML_DOCB_ENABLED
5009  case XML_DOCB_DOCUMENT_NODE:
5010 #endif
5011  case XML_XINCLUDE_START:
5012  case XML_XINCLUDE_END:
5013  return;
5014  case XML_ELEMENT_NODE:
5015  case XML_ATTRIBUTE_NODE:
5016  break;
5017  }
5018  ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5019  if (ns == NULL)
5020  return;
5021  xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
5022 }
5023 #endif /* LIBXML_TREE_ENABLED */
5024 
5035 xmlChar *
5036 xmlNodeGetLang(const xmlNode *cur) {
5037  xmlChar *lang;
5038 
5039  if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
5040  return(NULL);
5041  while (cur != NULL) {
5042  lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
5043  if (lang != NULL)
5044  return(lang);
5045  cur = cur->parent;
5046  }
5047  return(NULL);
5048 }
5049 
5050 
5051 #ifdef LIBXML_TREE_ENABLED
5052 
5060 void
5061 xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
5062  xmlNsPtr ns;
5063 
5064  if (cur == NULL) return;
5065  switch(cur->type) {
5066  case XML_TEXT_NODE:
5068  case XML_COMMENT_NODE:
5069  case XML_DOCUMENT_NODE:
5072  case XML_NOTATION_NODE:
5074  case XML_DTD_NODE:
5075  case XML_ELEMENT_DECL:
5076  case XML_ATTRIBUTE_DECL:
5077  case XML_ENTITY_DECL:
5078  case XML_PI_NODE:
5079  case XML_ENTITY_REF_NODE:
5080  case XML_ENTITY_NODE:
5081  case XML_NAMESPACE_DECL:
5082  case XML_XINCLUDE_START:
5083  case XML_XINCLUDE_END:
5084 #ifdef LIBXML_DOCB_ENABLED
5085  case XML_DOCB_DOCUMENT_NODE:
5086 #endif
5087  return;
5088  case XML_ELEMENT_NODE:
5089  case XML_ATTRIBUTE_NODE:
5090  break;
5091  }
5092  ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5093  if (ns == NULL)
5094  return;
5095  switch (val) {
5096  case 0:
5097  xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
5098  break;
5099  case 1:
5100  xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
5101  break;
5102  }
5103 }
5104 #endif /* LIBXML_TREE_ENABLED */
5105 
5116 int
5117 xmlNodeGetSpacePreserve(const xmlNode *cur) {
5118  xmlChar *space;
5119 
5120  if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
5121  return(-1);
5122  while (cur != NULL) {
5123  space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
5124  if (space != NULL) {
5125  if (xmlStrEqual(space, BAD_CAST "preserve")) {
5126  xmlFree(space);
5127  return(1);
5128  }
5129  if (xmlStrEqual(space, BAD_CAST "default")) {
5130  xmlFree(space);
5131  return(0);
5132  }
5133  xmlFree(space);
5134  }
5135  cur = cur->parent;
5136  }
5137  return(-1);
5138 }
5139 
5140 #ifdef LIBXML_TREE_ENABLED
5141 
5148 void
5149 xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
5150  xmlDocPtr doc;
5151  xmlDictPtr dict;
5152  const xmlChar *freeme = NULL;
5153 
5154  if (cur == NULL) return;
5155  if (name == NULL) return;
5156  switch(cur->type) {
5157  case XML_TEXT_NODE:
5159  case XML_COMMENT_NODE:
5162  case XML_NOTATION_NODE:
5164  case XML_NAMESPACE_DECL:
5165  case XML_XINCLUDE_START:
5166  case XML_XINCLUDE_END:
5167 #ifdef LIBXML_DOCB_ENABLED
5168  case XML_DOCB_DOCUMENT_NODE:
5169 #endif
5170  return;
5171  case XML_ELEMENT_NODE:
5172  case XML_ATTRIBUTE_NODE:
5173  case XML_PI_NODE:
5174  case XML_ENTITY_REF_NODE:
5175  case XML_ENTITY_NODE:
5176  case XML_DTD_NODE:
5177  case XML_DOCUMENT_NODE:
5178  case XML_ELEMENT_DECL:
5179  case XML_ATTRIBUTE_DECL:
5180  case XML_ENTITY_DECL:
5181  break;
5182  }
5183  doc = cur->doc;
5184  if (doc != NULL)
5185  dict = doc->dict;
5186  else
5187  dict = NULL;
5188  if (dict != NULL) {
5189  if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
5190  freeme = cur->name;
5191  cur->name = xmlDictLookup(dict, name, -1);
5192  } else {
5193  if (cur->name != NULL)
5194  freeme = cur->name;
5195  cur->name = xmlStrdup(name);
5196  }
5197 
5198  if (freeme)
5199  xmlFree((xmlChar *) freeme);
5200 }
5201 #endif
5202 
5203 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
5204 
5212 void
5213 xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
5214  xmlNsPtr ns;
5215  xmlChar* fixed;
5216 
5217  if (cur == NULL) return;
5218  switch(cur->type) {
5219  case XML_TEXT_NODE:
5221  case XML_COMMENT_NODE:
5224  case XML_NOTATION_NODE:
5225  case XML_DTD_NODE:
5226  case XML_ELEMENT_DECL:
5227  case XML_ATTRIBUTE_DECL:
5228  case XML_ENTITY_DECL:
5229  case XML_PI_NODE:
5230  case XML_ENTITY_REF_NODE:
5231  case XML_ENTITY_NODE:
5232  case XML_NAMESPACE_DECL:
5233  case XML_XINCLUDE_START:
5234  case XML_XINCLUDE_END:
5235  return;
5236  case XML_ELEMENT_NODE:
5237  case XML_ATTRIBUTE_NODE:
5238  break;
5239  case XML_DOCUMENT_NODE:
5240 #ifdef LIBXML_DOCB_ENABLED
5241  case XML_DOCB_DOCUMENT_NODE:
5242 #endif
5243  case XML_HTML_DOCUMENT_NODE: {
5244  xmlDocPtr doc = (xmlDocPtr) cur;
5245 
5246  if (doc->URL != NULL)
5247  xmlFree((xmlChar *) doc->URL);
5248  if (uri == NULL)
5249  doc->URL = NULL;
5250  else
5251  doc->URL = xmlPathToURI(uri);
5252  return;
5253  }
5254  }
5255 
5256  ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5257  if (ns == NULL)
5258  return;
5259  fixed = xmlPathToURI(uri);
5260  if (fixed != NULL) {
5261  xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
5262  xmlFree(fixed);
5263  } else {
5264  xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
5265  }
5266 }
5267 #endif /* LIBXML_TREE_ENABLED */
5268 
5286 xmlChar *
5287 xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) {
5288  xmlChar *oldbase = NULL;
5289  xmlChar *base, *newbase;
5290 
5291  if ((cur == NULL) && (doc == NULL))
5292  return(NULL);
5293  if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
5294  return(NULL);
5295  if (doc == NULL) doc = cur->doc;
5296  if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
5297  cur = doc->children;
5298  while ((cur != NULL) && (cur->name != NULL)) {
5299  if (cur->type != XML_ELEMENT_NODE) {
5300  cur = cur->next;
5301  continue;
5302  }
5303  if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
5304  cur = cur->children;
5305  continue;
5306  }
5307  if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
5308  cur = cur->children;
5309  continue;
5310  }
5311  if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
5312  return(xmlGetProp(cur, BAD_CAST "href"));
5313  }
5314  cur = cur->next;
5315  }
5316  return(NULL);
5317  }
5318  while (cur != NULL) {
5319  if (cur->type == XML_ENTITY_DECL) {
5320  xmlEntityPtr ent = (xmlEntityPtr) cur;
5321  return(xmlStrdup(ent->URI));
5322  }
5323  if (cur->type == XML_ELEMENT_NODE) {
5324  base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
5325  if (base != NULL) {
5326  if (oldbase != NULL) {
5327  newbase = xmlBuildURI(oldbase, base);
5328  if (newbase != NULL) {
5329  xmlFree(oldbase);
5330  xmlFree(base);
5331  oldbase = newbase;
5332  } else {
5333  xmlFree(oldbase);
5334  xmlFree(base);
5335  return(NULL);
5336  }
5337  } else {
5338  oldbase = base;
5339  }
5340  if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
5341  (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
5342  (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
5343  return(oldbase);
5344  }
5345  }
5346  cur = cur->parent;
5347  }
5348  if ((doc != NULL) && (doc->URL != NULL)) {
5349  if (oldbase == NULL)
5350  return(xmlStrdup(doc->URL));
5351  newbase = xmlBuildURI(oldbase, doc->URL);
5352  xmlFree(oldbase);
5353  return(newbase);
5354  }
5355  return(oldbase);
5356 }
5357 
5371 int
5373 {
5374  xmlBufPtr buf;
5375  int ret;
5376 
5377  if ((cur == NULL) || (buffer == NULL)) return(-1);
5379  ret = xmlBufGetNodeContent(buf, cur);
5381  if ((ret < 0) || (buffer == NULL))
5382  return(-1);
5383  return(0);
5384 }
5385 
5399 int
5401 {
5402  if ((cur == NULL) || (buf == NULL)) return(-1);
5403  switch (cur->type) {
5405  case XML_TEXT_NODE:
5406  xmlBufCat(buf, cur->content);
5407  break;
5409  case XML_ELEMENT_NODE:{
5410  const xmlNode *tmp = cur;
5411 
5412  while (tmp != NULL) {
5413  switch (tmp->type) {
5415  case XML_TEXT_NODE:
5416  if (tmp->content != NULL)
5417  xmlBufCat(buf, tmp->content);
5418  break;
5419  case XML_ENTITY_REF_NODE:
5420  xmlBufGetNodeContent(buf, tmp);
5421  break;
5422  default:
5423  break;
5424  }
5425  /*
5426  * Skip to next node
5427  */
5428  if (tmp->children != NULL) {
5429  if (tmp->children->type != XML_ENTITY_DECL) {
5430  tmp = tmp->children;
5431  continue;
5432  }
5433  }
5434  if (tmp == cur)
5435  break;
5436 
5437  if (tmp->next != NULL) {
5438  tmp = tmp->next;
5439  continue;
5440  }
5441 
5442  do {
5443  tmp = tmp->parent;
5444  if (tmp == NULL)
5445  break;
5446  if (tmp == cur) {
5447  tmp = NULL;
5448  break;
5449  }
5450