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