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