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