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