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