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