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