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