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