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