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