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