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