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