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