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