• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     if (size >= UINT_MAX)
7099         return(NULL);
7100     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
7101     if (ret == NULL) {
7102 	xmlTreeErrMemory("creating buffer");
7103         return(NULL);
7104     }
7105     ret->use = 0;
7106     ret->alloc = xmlBufferAllocScheme;
7107     ret->size = (size ? size+1 : 0);         /* +1 for ending null */
7108     if (ret->size){
7109         ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
7110         if (ret->content == NULL) {
7111 	    xmlTreeErrMemory("creating buffer");
7112             xmlFree(ret);
7113             return(NULL);
7114         }
7115         ret->content[0] = 0;
7116     } else
7117 	ret->content = NULL;
7118     ret->contentIO = NULL;
7119     return(ret);
7120 }
7121 
7122 /**
7123  * xmlBufferDetach:
7124  * @buf:  the buffer
7125  *
7126  * Remove the string contained in a buffer and gie it back to the
7127  * caller. The buffer is reset to an empty content.
7128  * This doesn't work with immutable buffers as they can't be reset.
7129  *
7130  * Returns the previous string contained by the buffer.
7131  */
7132 xmlChar *
xmlBufferDetach(xmlBufferPtr buf)7133 xmlBufferDetach(xmlBufferPtr buf) {
7134     xmlChar *ret;
7135 
7136     if (buf == NULL)
7137         return(NULL);
7138     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
7139         return(NULL);
7140 
7141     ret = buf->content;
7142     buf->content = NULL;
7143     buf->size = 0;
7144     buf->use = 0;
7145 
7146     return ret;
7147 }
7148 
7149 
7150 /**
7151  * xmlBufferCreateStatic:
7152  * @mem: the memory area
7153  * @size:  the size in byte
7154  *
7155  * routine to create an XML buffer from an immutable memory area.
7156  * The area won't be modified nor copied, and is expected to be
7157  * present until the end of the buffer lifetime.
7158  *
7159  * returns the new structure.
7160  */
7161 xmlBufferPtr
xmlBufferCreateStatic(void * mem,size_t size)7162 xmlBufferCreateStatic(void *mem, size_t size) {
7163     xmlBufferPtr ret;
7164 
7165     if ((mem == NULL) || (size == 0))
7166         return(NULL);
7167     if (size > UINT_MAX)
7168         return(NULL);
7169 
7170     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
7171     if (ret == NULL) {
7172 	xmlTreeErrMemory("creating buffer");
7173         return(NULL);
7174     }
7175     ret->use = size;
7176     ret->size = size;
7177     ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
7178     ret->content = (xmlChar *) mem;
7179     return(ret);
7180 }
7181 
7182 /**
7183  * xmlBufferSetAllocationScheme:
7184  * @buf:  the buffer to tune
7185  * @scheme:  allocation scheme to use
7186  *
7187  * Sets the allocation scheme for this buffer
7188  */
7189 void
xmlBufferSetAllocationScheme(xmlBufferPtr buf,xmlBufferAllocationScheme scheme)7190 xmlBufferSetAllocationScheme(xmlBufferPtr buf,
7191                              xmlBufferAllocationScheme scheme) {
7192     if (buf == NULL) {
7193 #ifdef DEBUG_BUFFER
7194         xmlGenericError(xmlGenericErrorContext,
7195 		"xmlBufferSetAllocationScheme: buf == NULL\n");
7196 #endif
7197         return;
7198     }
7199     if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
7200         (buf->alloc == XML_BUFFER_ALLOC_IO)) return;
7201     if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
7202         (scheme == XML_BUFFER_ALLOC_EXACT) ||
7203         (scheme == XML_BUFFER_ALLOC_HYBRID) ||
7204         (scheme == XML_BUFFER_ALLOC_IMMUTABLE))
7205 	buf->alloc = scheme;
7206 }
7207 
7208 /**
7209  * xmlBufferFree:
7210  * @buf:  the buffer to free
7211  *
7212  * Frees an XML buffer. It frees both the content and the structure which
7213  * encapsulate it.
7214  */
7215 void
xmlBufferFree(xmlBufferPtr buf)7216 xmlBufferFree(xmlBufferPtr buf) {
7217     if (buf == NULL) {
7218 #ifdef DEBUG_BUFFER
7219         xmlGenericError(xmlGenericErrorContext,
7220 		"xmlBufferFree: buf == NULL\n");
7221 #endif
7222 	return;
7223     }
7224 
7225     if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7226         (buf->contentIO != NULL)) {
7227         xmlFree(buf->contentIO);
7228     } else if ((buf->content != NULL) &&
7229         (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
7230         xmlFree(buf->content);
7231     }
7232     xmlFree(buf);
7233 }
7234 
7235 /**
7236  * xmlBufferEmpty:
7237  * @buf:  the buffer
7238  *
7239  * empty a buffer.
7240  */
7241 void
xmlBufferEmpty(xmlBufferPtr buf)7242 xmlBufferEmpty(xmlBufferPtr buf) {
7243     if (buf == NULL) return;
7244     if (buf->content == NULL) return;
7245     buf->use = 0;
7246     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
7247         buf->content = BAD_CAST "";
7248     } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7249                (buf->contentIO != NULL)) {
7250         size_t start_buf = buf->content - buf->contentIO;
7251 
7252 	buf->size += start_buf;
7253         buf->content = buf->contentIO;
7254         buf->content[0] = 0;
7255     } else {
7256         buf->content[0] = 0;
7257     }
7258 }
7259 
7260 /**
7261  * xmlBufferShrink:
7262  * @buf:  the buffer to dump
7263  * @len:  the number of xmlChar to remove
7264  *
7265  * Remove the beginning of an XML buffer.
7266  *
7267  * Returns the number of #xmlChar removed, or -1 in case of failure.
7268  */
7269 int
xmlBufferShrink(xmlBufferPtr buf,unsigned int len)7270 xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
7271     if (buf == NULL) return(-1);
7272     if (len == 0) return(0);
7273     if (len > buf->use) return(-1);
7274 
7275     buf->use -= len;
7276     if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
7277         ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
7278 	/*
7279 	 * we just move the content pointer, but also make sure
7280 	 * the perceived buffer size has shrunk accordingly
7281 	 */
7282         buf->content += len;
7283 	buf->size -= len;
7284 
7285         /*
7286 	 * sometimes though it maybe be better to really shrink
7287 	 * on IO buffers
7288 	 */
7289 	if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7290 	    size_t start_buf = buf->content - buf->contentIO;
7291 	    if (start_buf >= buf->size) {
7292 		memmove(buf->contentIO, &buf->content[0], buf->use);
7293 		buf->content = buf->contentIO;
7294 		buf->content[buf->use] = 0;
7295 		buf->size += start_buf;
7296 	    }
7297 	}
7298     } else {
7299 	memmove(buf->content, &buf->content[len], buf->use);
7300 	buf->content[buf->use] = 0;
7301     }
7302     return(len);
7303 }
7304 
7305 /**
7306  * xmlBufferGrow:
7307  * @buf:  the buffer
7308  * @len:  the minimum free size to allocate
7309  *
7310  * Grow the available space of an XML buffer.
7311  *
7312  * Returns the new available space or -1 in case of error
7313  */
7314 int
xmlBufferGrow(xmlBufferPtr buf,unsigned int len)7315 xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
7316     unsigned int size;
7317     xmlChar *newbuf;
7318 
7319     if (buf == NULL) return(-1);
7320 
7321     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
7322     if (len < buf->size - buf->use)
7323         return(0);
7324     if (len > UINT_MAX - buf->use)
7325         return(-1);
7326 
7327     if (buf->size > (size_t) len) {
7328         size = buf->size > UINT_MAX / 2 ? UINT_MAX : buf->size * 2;
7329     } else {
7330         size = buf->use + len;
7331         size = size > UINT_MAX - 100 ? UINT_MAX : size + 100;
7332     }
7333 
7334     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7335         size_t start_buf = buf->content - buf->contentIO;
7336 
7337 	newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
7338 	if (newbuf == NULL) {
7339 	    xmlTreeErrMemory("growing buffer");
7340 	    return(-1);
7341 	}
7342 	buf->contentIO = newbuf;
7343 	buf->content = newbuf + start_buf;
7344     } else {
7345 	newbuf = (xmlChar *) xmlRealloc(buf->content, size);
7346 	if (newbuf == NULL) {
7347 	    xmlTreeErrMemory("growing buffer");
7348 	    return(-1);
7349 	}
7350 	buf->content = newbuf;
7351     }
7352     buf->size = size;
7353     return(buf->size - buf->use);
7354 }
7355 
7356 /**
7357  * xmlBufferDump:
7358  * @file:  the file output
7359  * @buf:  the buffer to dump
7360  *
7361  * Dumps an XML buffer to  a FILE *.
7362  * Returns the number of #xmlChar written
7363  */
7364 int
xmlBufferDump(FILE * file,xmlBufferPtr buf)7365 xmlBufferDump(FILE *file, xmlBufferPtr buf) {
7366     int ret;
7367 
7368     if (buf == NULL) {
7369 #ifdef DEBUG_BUFFER
7370         xmlGenericError(xmlGenericErrorContext,
7371 		"xmlBufferDump: buf == NULL\n");
7372 #endif
7373 	return(0);
7374     }
7375     if (buf->content == NULL) {
7376 #ifdef DEBUG_BUFFER
7377         xmlGenericError(xmlGenericErrorContext,
7378 		"xmlBufferDump: buf->content == NULL\n");
7379 #endif
7380 	return(0);
7381     }
7382     if (file == NULL)
7383 	file = stdout;
7384     ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
7385     return(ret);
7386 }
7387 
7388 /**
7389  * xmlBufferContent:
7390  * @buf:  the buffer
7391  *
7392  * Function to extract the content of a buffer
7393  *
7394  * Returns the internal content
7395  */
7396 
7397 const xmlChar *
xmlBufferContent(const xmlBuffer * buf)7398 xmlBufferContent(const xmlBuffer *buf)
7399 {
7400     if(!buf)
7401         return NULL;
7402 
7403     return buf->content;
7404 }
7405 
7406 /**
7407  * xmlBufferLength:
7408  * @buf:  the buffer
7409  *
7410  * Function to get the length of a buffer
7411  *
7412  * Returns the length of data in the internal content
7413  */
7414 
7415 int
xmlBufferLength(const xmlBuffer * buf)7416 xmlBufferLength(const xmlBuffer *buf)
7417 {
7418     if(!buf)
7419         return 0;
7420 
7421     return buf->use;
7422 }
7423 
7424 /**
7425  * xmlBufferResize:
7426  * @buf:  the buffer to resize
7427  * @size:  the desired size
7428  *
7429  * Resize a buffer to accommodate minimum size of @size.
7430  *
7431  * Returns  0 in case of problems, 1 otherwise
7432  */
7433 int
xmlBufferResize(xmlBufferPtr buf,unsigned int size)7434 xmlBufferResize(xmlBufferPtr buf, unsigned int size)
7435 {
7436     unsigned int newSize;
7437     xmlChar* rebuf = NULL;
7438     size_t start_buf;
7439 
7440     if (buf == NULL)
7441         return(0);
7442 
7443     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
7444 
7445     /* Don't resize if we don't have to */
7446     if (size < buf->size)
7447         return 1;
7448 
7449     if (size > UINT_MAX - 10) {
7450         xmlTreeErrMemory("growing buffer");
7451         return 0;
7452     }
7453 
7454     /* figure out new size */
7455     switch (buf->alloc){
7456 	case XML_BUFFER_ALLOC_IO:
7457 	case XML_BUFFER_ALLOC_DOUBLEIT:
7458 	    /*take care of empty case*/
7459             if (buf->size == 0)
7460                 newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
7461             else
7462                 newSize = buf->size;
7463 	    while (size > newSize) {
7464 	        if (newSize > UINT_MAX / 2) {
7465 	            xmlTreeErrMemory("growing buffer");
7466 	            return 0;
7467 	        }
7468 	        newSize *= 2;
7469 	    }
7470 	    break;
7471 	case XML_BUFFER_ALLOC_EXACT:
7472 	    newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
7473 	    break;
7474         case XML_BUFFER_ALLOC_HYBRID:
7475             if (buf->use < BASE_BUFFER_SIZE)
7476                 newSize = size;
7477             else {
7478                 newSize = buf->size;
7479                 while (size > newSize) {
7480                     if (newSize > UINT_MAX / 2) {
7481                         xmlTreeErrMemory("growing buffer");
7482                         return 0;
7483                     }
7484                     newSize *= 2;
7485                 }
7486             }
7487             break;
7488 
7489 	default:
7490 	    newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
7491 	    break;
7492     }
7493 
7494     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7495         start_buf = buf->content - buf->contentIO;
7496 
7497         if (start_buf > newSize) {
7498 	    /* move data back to start */
7499 	    memmove(buf->contentIO, buf->content, buf->use);
7500 	    buf->content = buf->contentIO;
7501 	    buf->content[buf->use] = 0;
7502 	    buf->size += start_buf;
7503 	} else {
7504 	    rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
7505 	    if (rebuf == NULL) {
7506 		xmlTreeErrMemory("growing buffer");
7507 		return 0;
7508 	    }
7509 	    buf->contentIO = rebuf;
7510 	    buf->content = rebuf + start_buf;
7511 	}
7512     } else {
7513 	if (buf->content == NULL) {
7514 	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7515 	} else if (buf->size - buf->use < 100) {
7516 	    rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
7517         } else {
7518 	    /*
7519 	     * if we are reallocating a buffer far from being full, it's
7520 	     * better to make a new allocation and copy only the used range
7521 	     * and free the old one.
7522 	     */
7523 	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7524 	    if (rebuf != NULL) {
7525 		memcpy(rebuf, buf->content, buf->use);
7526 		xmlFree(buf->content);
7527 		rebuf[buf->use] = 0;
7528 	    }
7529 	}
7530 	if (rebuf == NULL) {
7531 	    xmlTreeErrMemory("growing buffer");
7532 	    return 0;
7533 	}
7534 	buf->content = rebuf;
7535     }
7536     buf->size = newSize;
7537 
7538     return 1;
7539 }
7540 
7541 /**
7542  * xmlBufferAdd:
7543  * @buf:  the buffer to dump
7544  * @str:  the #xmlChar string
7545  * @len:  the number of #xmlChar to add
7546  *
7547  * Add a string range to an XML buffer. if len == -1, the length of
7548  * str is recomputed.
7549  *
7550  * Returns 0 successful, a positive error code number otherwise
7551  *         and -1 in case of internal or API error.
7552  */
7553 int
xmlBufferAdd(xmlBufferPtr buf,const xmlChar * str,int len)7554 xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
7555     unsigned int needSize;
7556 
7557     if ((str == NULL) || (buf == NULL)) {
7558 	return -1;
7559     }
7560     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7561     if (len < -1) {
7562 #ifdef DEBUG_BUFFER
7563         xmlGenericError(xmlGenericErrorContext,
7564 		"xmlBufferAdd: len < 0\n");
7565 #endif
7566 	return -1;
7567     }
7568     if (len == 0) return 0;
7569 
7570     if (len < 0)
7571         len = xmlStrlen(str);
7572 
7573     if (len < 0) return -1;
7574     if (len == 0) return 0;
7575 
7576     if ((unsigned) len >= buf->size - buf->use) {
7577         if ((unsigned) len >= UINT_MAX - buf->use)
7578             return XML_ERR_NO_MEMORY;
7579         needSize = buf->use + len + 1;
7580         if (!xmlBufferResize(buf, needSize)){
7581 	    xmlTreeErrMemory("growing buffer");
7582             return XML_ERR_NO_MEMORY;
7583         }
7584     }
7585 
7586     memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
7587     buf->use += len;
7588     buf->content[buf->use] = 0;
7589     return 0;
7590 }
7591 
7592 /**
7593  * xmlBufferAddHead:
7594  * @buf:  the buffer
7595  * @str:  the #xmlChar string
7596  * @len:  the number of #xmlChar to add
7597  *
7598  * Add a string range to the beginning of an XML buffer.
7599  * if len == -1, the length of @str is recomputed.
7600  *
7601  * Returns 0 successful, a positive error code number otherwise
7602  *         and -1 in case of internal or API error.
7603  */
7604 int
xmlBufferAddHead(xmlBufferPtr buf,const xmlChar * str,int len)7605 xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
7606     unsigned int needSize;
7607 
7608     if (buf == NULL)
7609         return(-1);
7610     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7611     if (str == NULL) {
7612 #ifdef DEBUG_BUFFER
7613         xmlGenericError(xmlGenericErrorContext,
7614 		"xmlBufferAddHead: str == NULL\n");
7615 #endif
7616 	return -1;
7617     }
7618     if (len < -1) {
7619 #ifdef DEBUG_BUFFER
7620         xmlGenericError(xmlGenericErrorContext,
7621 		"xmlBufferAddHead: len < 0\n");
7622 #endif
7623 	return -1;
7624     }
7625     if (len == 0) return 0;
7626 
7627     if (len < 0)
7628         len = xmlStrlen(str);
7629 
7630     if (len <= 0) return -1;
7631 
7632     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7633         size_t start_buf = buf->content - buf->contentIO;
7634 
7635 	if (start_buf > (unsigned int) len) {
7636 	    /*
7637 	     * We can add it in the space previously shrunk
7638 	     */
7639 	    buf->content -= len;
7640             memmove(&buf->content[0], str, len);
7641 	    buf->use += len;
7642 	    buf->size += len;
7643 	    return(0);
7644 	}
7645     }
7646     needSize = buf->use + len + 2;
7647     if (needSize > buf->size){
7648         if (!xmlBufferResize(buf, needSize)){
7649 	    xmlTreeErrMemory("growing buffer");
7650             return XML_ERR_NO_MEMORY;
7651         }
7652     }
7653 
7654     memmove(&buf->content[len], &buf->content[0], buf->use);
7655     memmove(&buf->content[0], str, len);
7656     buf->use += len;
7657     buf->content[buf->use] = 0;
7658     return 0;
7659 }
7660 
7661 /**
7662  * xmlBufferCat:
7663  * @buf:  the buffer to add to
7664  * @str:  the #xmlChar string
7665  *
7666  * Append a zero terminated string to an XML buffer.
7667  *
7668  * Returns 0 successful, a positive error code number otherwise
7669  *         and -1 in case of internal or API error.
7670  */
7671 int
xmlBufferCat(xmlBufferPtr buf,const xmlChar * str)7672 xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
7673     if (buf == NULL)
7674         return(-1);
7675     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7676     if (str == NULL) return -1;
7677     return xmlBufferAdd(buf, str, -1);
7678 }
7679 
7680 /**
7681  * xmlBufferCCat:
7682  * @buf:  the buffer to dump
7683  * @str:  the C char string
7684  *
7685  * Append a zero terminated C string to an XML buffer.
7686  *
7687  * Returns 0 successful, a positive error code number otherwise
7688  *         and -1 in case of internal or API error.
7689  */
7690 int
xmlBufferCCat(xmlBufferPtr buf,const char * str)7691 xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7692     return xmlBufferCat(buf, (const xmlChar *) str);
7693 }
7694 
7695 /**
7696  * xmlBufferWriteCHAR:
7697  * @buf:  the XML buffer
7698  * @string:  the string to add
7699  *
7700  * routine which manages and grows an output buffer. This one adds
7701  * xmlChars at the end of the buffer.
7702  */
7703 void
xmlBufferWriteCHAR(xmlBufferPtr buf,const xmlChar * string)7704 xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
7705     if (buf == NULL)
7706         return;
7707     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
7708     xmlBufferCat(buf, string);
7709 }
7710 
7711 /**
7712  * xmlBufferWriteChar:
7713  * @buf:  the XML buffer output
7714  * @string:  the string to add
7715  *
7716  * routine which manage and grows an output buffer. This one add
7717  * C chars at the end of the array.
7718  */
7719 void
xmlBufferWriteChar(xmlBufferPtr buf,const char * string)7720 xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
7721     if (buf == NULL)
7722         return;
7723     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
7724     xmlBufferCCat(buf, string);
7725 }
7726 
7727 
7728 /**
7729  * xmlBufferWriteQuotedString:
7730  * @buf:  the XML buffer output
7731  * @string:  the string to add
7732  *
7733  * routine which manage and grows an output buffer. This one writes
7734  * a quoted or double quoted #xmlChar string, checking first if it holds
7735  * quote or double-quotes internally
7736  */
7737 void
xmlBufferWriteQuotedString(xmlBufferPtr buf,const xmlChar * string)7738 xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
7739     const xmlChar *cur, *base;
7740     if (buf == NULL)
7741         return;
7742     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
7743     if (xmlStrchr(string, '\"')) {
7744         if (xmlStrchr(string, '\'')) {
7745 #ifdef DEBUG_BUFFER
7746 	    xmlGenericError(xmlGenericErrorContext,
7747  "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7748 #endif
7749 	    xmlBufferCCat(buf, "\"");
7750             base = cur = string;
7751             while(*cur != 0){
7752                 if(*cur == '"'){
7753                     if (base != cur)
7754                         xmlBufferAdd(buf, base, cur - base);
7755                     xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7756                     cur++;
7757                     base = cur;
7758                 }
7759                 else {
7760                     cur++;
7761                 }
7762             }
7763             if (base != cur)
7764                 xmlBufferAdd(buf, base, cur - base);
7765 	    xmlBufferCCat(buf, "\"");
7766 	}
7767         else{
7768 	    xmlBufferCCat(buf, "\'");
7769             xmlBufferCat(buf, string);
7770 	    xmlBufferCCat(buf, "\'");
7771         }
7772     } else {
7773         xmlBufferCCat(buf, "\"");
7774         xmlBufferCat(buf, string);
7775         xmlBufferCCat(buf, "\"");
7776     }
7777 }
7778 
7779 
7780 /**
7781  * xmlGetDocCompressMode:
7782  * @doc:  the document
7783  *
7784  * get the compression ratio for a document, ZLIB based
7785  * Returns 0 (uncompressed) to 9 (max compression)
7786  */
7787 int
xmlGetDocCompressMode(const xmlDoc * doc)7788 xmlGetDocCompressMode (const xmlDoc *doc) {
7789     if (doc == NULL) return(-1);
7790     return(doc->compression);
7791 }
7792 
7793 /**
7794  * xmlSetDocCompressMode:
7795  * @doc:  the document
7796  * @mode:  the compression ratio
7797  *
7798  * set the compression ratio for a document, ZLIB based
7799  * Correct values: 0 (uncompressed) to 9 (max compression)
7800  */
7801 void
xmlSetDocCompressMode(xmlDocPtr doc,int mode)7802 xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7803     if (doc == NULL) return;
7804     if (mode < 0) doc->compression = 0;
7805     else if (mode > 9) doc->compression = 9;
7806     else doc->compression = mode;
7807 }
7808 
7809 /**
7810  * xmlGetCompressMode:
7811  *
7812  * get the default compression mode used, ZLIB based.
7813  * Returns 0 (uncompressed) to 9 (max compression)
7814  */
7815 int
xmlGetCompressMode(void)7816 xmlGetCompressMode(void)
7817 {
7818     return (xmlCompressMode);
7819 }
7820 
7821 /**
7822  * xmlSetCompressMode:
7823  * @mode:  the compression ratio
7824  *
7825  * set the default compression mode used, ZLIB based
7826  * Correct values: 0 (uncompressed) to 9 (max compression)
7827  */
7828 void
xmlSetCompressMode(int mode)7829 xmlSetCompressMode(int mode) {
7830     if (mode < 0) xmlCompressMode = 0;
7831     else if (mode > 9) xmlCompressMode = 9;
7832     else xmlCompressMode = mode;
7833 }
7834 
7835 #define XML_TREE_NSMAP_PARENT -1
7836 #define XML_TREE_NSMAP_XML -2
7837 #define XML_TREE_NSMAP_DOC -3
7838 #define XML_TREE_NSMAP_CUSTOM -4
7839 
7840 typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7841 struct xmlNsMapItem {
7842     xmlNsMapItemPtr next;
7843     xmlNsMapItemPtr prev;
7844     xmlNsPtr oldNs; /* old ns decl reference */
7845     xmlNsPtr newNs; /* new ns decl reference */
7846     int shadowDepth; /* Shadowed at this depth */
7847     /*
7848     * depth:
7849     * >= 0 == @node's ns-decls
7850     * -1   == @parent's ns-decls
7851     * -2   == the doc->oldNs XML ns-decl
7852     * -3   == the doc->oldNs storage ns-decls
7853     * -4   == ns-decls provided via custom ns-handling
7854     */
7855     int depth;
7856 };
7857 
7858 typedef struct xmlNsMap *xmlNsMapPtr;
7859 struct xmlNsMap {
7860     xmlNsMapItemPtr first;
7861     xmlNsMapItemPtr last;
7862     xmlNsMapItemPtr pool;
7863 };
7864 
7865 #define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7866 #define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7867 #define XML_NSMAP_POP(m, i) \
7868     i = (m)->last; \
7869     (m)->last = (i)->prev; \
7870     if ((m)->last == NULL) \
7871 	(m)->first = NULL; \
7872     else \
7873 	(m)->last->next = NULL; \
7874     (i)->next = (m)->pool; \
7875     (m)->pool = i;
7876 
7877 /*
7878 * xmlDOMWrapNsMapFree:
7879 * @map: the ns-map
7880 *
7881 * Frees the ns-map
7882 */
7883 static void
xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)7884 xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7885 {
7886     xmlNsMapItemPtr cur, tmp;
7887 
7888     if (nsmap == NULL)
7889 	return;
7890     cur = nsmap->pool;
7891     while (cur != NULL) {
7892 	tmp = cur;
7893 	cur = cur->next;
7894 	xmlFree(tmp);
7895     }
7896     cur = nsmap->first;
7897     while (cur != NULL) {
7898 	tmp = cur;
7899 	cur = cur->next;
7900 	xmlFree(tmp);
7901     }
7902     xmlFree(nsmap);
7903 }
7904 
7905 /*
7906 * xmlDOMWrapNsMapAddItem:
7907 * @map: the ns-map
7908 * @oldNs: the old ns-struct
7909 * @newNs: the new ns-struct
7910 * @depth: depth and ns-kind information
7911 *
7912 * Adds an ns-mapping item.
7913 */
7914 static xmlNsMapItemPtr
xmlDOMWrapNsMapAddItem(xmlNsMapPtr * nsmap,int position,xmlNsPtr oldNs,xmlNsPtr newNs,int depth)7915 xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position,
7916 		       xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
7917 {
7918     xmlNsMapItemPtr ret;
7919     xmlNsMapPtr map;
7920 
7921     if (nsmap == NULL)
7922 	return(NULL);
7923     if ((position != -1) && (position != 0))
7924 	return(NULL);
7925     map = *nsmap;
7926 
7927     if (map == NULL) {
7928 	/*
7929 	* Create the ns-map.
7930 	*/
7931 	map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7932 	if (map == NULL) {
7933 	    xmlTreeErrMemory("allocating namespace map");
7934 	    return (NULL);
7935 	}
7936 	memset(map, 0, sizeof(struct xmlNsMap));
7937 	*nsmap = map;
7938     }
7939 
7940     if (map->pool != NULL) {
7941 	/*
7942 	* Reuse an item from the pool.
7943 	*/
7944 	ret = map->pool;
7945 	map->pool = ret->next;
7946 	memset(ret, 0, sizeof(struct xmlNsMapItem));
7947     } else {
7948 	/*
7949 	* Create a new item.
7950 	*/
7951 	ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7952 	if (ret == NULL) {
7953 	    xmlTreeErrMemory("allocating namespace map item");
7954 	    return (NULL);
7955 	}
7956 	memset(ret, 0, sizeof(struct xmlNsMapItem));
7957     }
7958 
7959     if (map->first == NULL) {
7960 	/*
7961 	* First ever.
7962 	*/
7963 	map->first = ret;
7964 	map->last = ret;
7965     } else if (position == -1) {
7966 	/*
7967 	* Append.
7968 	*/
7969 	ret->prev = map->last;
7970 	map->last->next = ret;
7971 	map->last = ret;
7972     } else if (position == 0) {
7973 	/*
7974 	* Set on first position.
7975 	*/
7976 	map->first->prev = ret;
7977 	ret->next = map->first;
7978 	map->first = ret;
7979     }
7980 
7981     ret->oldNs = oldNs;
7982     ret->newNs = newNs;
7983     ret->shadowDepth = -1;
7984     ret->depth = depth;
7985     return (ret);
7986 }
7987 
7988 /*
7989 * xmlDOMWrapStoreNs:
7990 * @doc: the doc
7991 * @nsName: the namespace name
7992 * @prefix: the prefix
7993 *
7994 * Creates or reuses an xmlNs struct on doc->oldNs with
7995 * the given prefix and namespace name.
7996 *
7997 * Returns the acquired ns struct or NULL in case of an API
7998 *         or internal error.
7999 */
8000 static xmlNsPtr
xmlDOMWrapStoreNs(xmlDocPtr doc,const xmlChar * nsName,const xmlChar * prefix)8001 xmlDOMWrapStoreNs(xmlDocPtr doc,
8002 		   const xmlChar *nsName,
8003 		   const xmlChar *prefix)
8004 {
8005     xmlNsPtr ns;
8006 
8007     if (doc == NULL)
8008 	return (NULL);
8009     ns = xmlTreeEnsureXMLDecl(doc);
8010     if (ns == NULL)
8011 	return (NULL);
8012     if (ns->next != NULL) {
8013 	/* Reuse. */
8014 	ns = ns->next;
8015 	while (ns != NULL) {
8016 	    if (((ns->prefix == prefix) ||
8017 		xmlStrEqual(ns->prefix, prefix)) &&
8018 		xmlStrEqual(ns->href, nsName)) {
8019 		return (ns);
8020 	    }
8021 	    if (ns->next == NULL)
8022 		break;
8023 	    ns = ns->next;
8024 	}
8025     }
8026     /* Create. */
8027     if (ns != NULL) {
8028         ns->next = xmlNewNs(NULL, nsName, prefix);
8029         return (ns->next);
8030     }
8031     return(NULL);
8032 }
8033 
8034 /*
8035 * xmlDOMWrapNewCtxt:
8036 *
8037 * Allocates and initializes a new DOM-wrapper context.
8038 *
8039 * Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal error.
8040 */
8041 xmlDOMWrapCtxtPtr
xmlDOMWrapNewCtxt(void)8042 xmlDOMWrapNewCtxt(void)
8043 {
8044     xmlDOMWrapCtxtPtr ret;
8045 
8046     ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
8047     if (ret == NULL) {
8048 	xmlTreeErrMemory("allocating DOM-wrapper context");
8049 	return (NULL);
8050     }
8051     memset(ret, 0, sizeof(xmlDOMWrapCtxt));
8052     return (ret);
8053 }
8054 
8055 /*
8056 * xmlDOMWrapFreeCtxt:
8057 * @ctxt: the DOM-wrapper context
8058 *
8059 * Frees the DOM-wrapper context.
8060 */
8061 void
xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)8062 xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
8063 {
8064     if (ctxt == NULL)
8065 	return;
8066     if (ctxt->namespaceMap != NULL)
8067 	xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap);
8068     /*
8069     * TODO: Store the namespace map in the context.
8070     */
8071     xmlFree(ctxt);
8072 }
8073 
8074 /*
8075 * xmlTreeLookupNsListByPrefix:
8076 * @nsList: a list of ns-structs
8077 * @prefix: the searched prefix
8078 *
8079 * Searches for a ns-decl with the given prefix in @nsList.
8080 *
8081 * Returns the ns-decl if found, NULL if not found and on
8082 *         API errors.
8083 */
8084 static xmlNsPtr
xmlTreeNSListLookupByPrefix(xmlNsPtr nsList,const xmlChar * prefix)8085 xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
8086 {
8087     if (nsList == NULL)
8088 	return (NULL);
8089     {
8090 	xmlNsPtr ns;
8091 	ns = nsList;
8092 	do {
8093 	    if ((prefix == ns->prefix) ||
8094 		xmlStrEqual(prefix, ns->prefix)) {
8095 		return (ns);
8096 	    }
8097 	    ns = ns->next;
8098 	} while (ns != NULL);
8099     }
8100     return (NULL);
8101 }
8102 
8103 /*
8104 *
8105 * xmlDOMWrapNSNormGatherInScopeNs:
8106 * @map: the namespace map
8107 * @node: the node to start with
8108 *
8109 * Puts in-scope namespaces into the ns-map.
8110 *
8111 * Returns 0 on success, -1 on API or internal errors.
8112 */
8113 static int
xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr * map,xmlNodePtr node)8114 xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
8115 				xmlNodePtr node)
8116 {
8117     xmlNodePtr cur;
8118     xmlNsPtr ns;
8119     xmlNsMapItemPtr mi;
8120     int shadowed;
8121 
8122     if ((map == NULL) || (*map != NULL))
8123 	return (-1);
8124     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
8125         return (-1);
8126     /*
8127     * Get in-scope ns-decls of @parent.
8128     */
8129     cur = node;
8130     while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
8131 	if (cur->type == XML_ELEMENT_NODE) {
8132 	    if (cur->nsDef != NULL) {
8133 		ns = cur->nsDef;
8134 		do {
8135 		    shadowed = 0;
8136 		    if (XML_NSMAP_NOTEMPTY(*map)) {
8137 			/*
8138 			* Skip shadowed prefixes.
8139 			*/
8140 			XML_NSMAP_FOREACH(*map, mi) {
8141 			    if ((ns->prefix == mi->newNs->prefix) ||
8142 				xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
8143 				shadowed = 1;
8144 				break;
8145 			    }
8146 			}
8147 		    }
8148 		    /*
8149 		    * Insert mapping.
8150 		    */
8151 		    mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
8152 			ns, XML_TREE_NSMAP_PARENT);
8153 		    if (mi == NULL)
8154 			return (-1);
8155 		    if (shadowed)
8156 			mi->shadowDepth = 0;
8157 		    ns = ns->next;
8158 		} while (ns != NULL);
8159 	    }
8160 	}
8161 	cur = cur->parent;
8162     }
8163     return (0);
8164 }
8165 
8166 /*
8167 * XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
8168 * otherwise copy it, when it was in the source-dict.
8169 */
8170 #define XML_TREE_ADOPT_STR(str) \
8171     if (adoptStr && (str != NULL)) { \
8172 	if (destDoc->dict) { \
8173 	    const xmlChar *old = str;	\
8174 	    str = xmlDictLookup(destDoc->dict, str, -1); \
8175 	    if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
8176 	        (!xmlDictOwns(sourceDoc->dict, old))) \
8177 		xmlFree((char *)old); \
8178 	} else if ((sourceDoc) && (sourceDoc->dict) && \
8179 	    xmlDictOwns(sourceDoc->dict, str)) { \
8180 	    str = BAD_CAST xmlStrdup(str); \
8181 	} \
8182     }
8183 
8184 /*
8185 * XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
8186 * put it in dest-dict or copy it.
8187 */
8188 #define XML_TREE_ADOPT_STR_2(str) \
8189     if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
8190 	(sourceDoc->dict != NULL) && \
8191 	xmlDictOwns(sourceDoc->dict, cur->content)) { \
8192 	if (destDoc->dict) \
8193 	    cur->content = (xmlChar *) \
8194 		xmlDictLookup(destDoc->dict, cur->content, -1); \
8195 	else \
8196 	    cur->content = xmlStrdup(BAD_CAST cur->content); \
8197     }
8198 
8199 /*
8200 * xmlDOMWrapNSNormAddNsMapItem2:
8201 *
8202 * For internal use. Adds a ns-decl mapping.
8203 *
8204 * Returns 0 on success, -1 on internal errors.
8205 */
8206 static int
xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr ** list,int * size,int * number,xmlNsPtr oldNs,xmlNsPtr newNs)8207 xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
8208 			xmlNsPtr oldNs, xmlNsPtr newNs)
8209 {
8210     if (*list == NULL) {
8211 	*list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
8212 	if (*list == NULL) {
8213 	    xmlTreeErrMemory("alloc ns map item");
8214 	    return(-1);
8215 	}
8216 	*size = 3;
8217 	*number = 0;
8218     } else if ((*number) >= (*size)) {
8219 	*size *= 2;
8220 	*list = (xmlNsPtr *) xmlRealloc(*list,
8221 	    (*size) * 2 * sizeof(xmlNsPtr));
8222 	if (*list == NULL) {
8223 	    xmlTreeErrMemory("realloc ns map item");
8224 	    return(-1);
8225 	}
8226     }
8227     (*list)[2 * (*number)] = oldNs;
8228     (*list)[2 * (*number) +1] = newNs;
8229     (*number)++;
8230     return (0);
8231 }
8232 
8233 /*
8234 * xmlDOMWrapRemoveNode:
8235 * @ctxt: a DOM wrapper context
8236 * @doc: the doc
8237 * @node: the node to be removed.
8238 * @options: set of options, unused at the moment
8239 *
8240 * Unlinks the given node from its owner.
8241 * This will substitute ns-references to node->nsDef for
8242 * ns-references to doc->oldNs, thus ensuring the removed
8243 * branch to be autark wrt ns-references.
8244 *
8245 * NOTE: This function was not intensively tested.
8246 *
8247 * Returns 0 on success, 1 if the node is not supported,
8248 *         -1 on API and internal errors.
8249 */
8250 int
xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr node,int options ATTRIBUTE_UNUSED)8251 xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
8252 		     xmlNodePtr node, int options ATTRIBUTE_UNUSED)
8253 {
8254     xmlNsPtr *list = NULL;
8255     int sizeList, nbList, i, j;
8256     xmlNsPtr ns;
8257 
8258     if ((node == NULL) || (doc == NULL) || (node->doc != doc))
8259 	return (-1);
8260 
8261     /* TODO: 0 or -1 ? */
8262     if (node->parent == NULL)
8263 	return (0);
8264 
8265     switch (node->type) {
8266 	case XML_TEXT_NODE:
8267 	case XML_CDATA_SECTION_NODE:
8268 	case XML_ENTITY_REF_NODE:
8269 	case XML_PI_NODE:
8270 	case XML_COMMENT_NODE:
8271 	    xmlUnlinkNode(node);
8272 	    return (0);
8273 	case XML_ELEMENT_NODE:
8274 	case XML_ATTRIBUTE_NODE:
8275 	    break;
8276 	default:
8277 	    return (1);
8278     }
8279     xmlUnlinkNode(node);
8280     /*
8281     * Save out-of-scope ns-references in doc->oldNs.
8282     */
8283     do {
8284 	switch (node->type) {
8285 	    case XML_ELEMENT_NODE:
8286 		if ((ctxt == NULL) && (node->nsDef != NULL)) {
8287 		    ns = node->nsDef;
8288 		    do {
8289 			if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8290 			    &nbList, ns, ns) == -1)
8291 			    goto internal_error;
8292 			ns = ns->next;
8293 		    } while (ns != NULL);
8294 		}
8295                 /* Falls through. */
8296 	    case XML_ATTRIBUTE_NODE:
8297 		if (node->ns != NULL) {
8298 		    /*
8299 		    * Find a mapping.
8300 		    */
8301 		    if (list != NULL) {
8302 			for (i = 0, j = 0; i < nbList; i++, j += 2) {
8303 			    if (node->ns == list[j]) {
8304 				node->ns = list[++j];
8305 				goto next_node;
8306 			    }
8307 			}
8308 		    }
8309 		    ns = NULL;
8310 		    if (ctxt != NULL) {
8311 			/*
8312 			* User defined.
8313 			*/
8314 		    } else {
8315 			/*
8316 			* Add to doc's oldNs.
8317 			*/
8318 			ns = xmlDOMWrapStoreNs(doc, node->ns->href,
8319 			    node->ns->prefix);
8320 			if (ns == NULL)
8321 			    goto internal_error;
8322 		    }
8323 		    if (ns != NULL) {
8324 			/*
8325 			* Add mapping.
8326 			*/
8327 			if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8328 			    &nbList, node->ns, ns) == -1)
8329 			    goto internal_error;
8330 		    }
8331 		    node->ns = ns;
8332 		}
8333 		if ((node->type == XML_ELEMENT_NODE) &&
8334 		    (node->properties != NULL)) {
8335 		    node = (xmlNodePtr) node->properties;
8336 		    continue;
8337 		}
8338 		break;
8339 	    default:
8340 		goto next_sibling;
8341 	}
8342 next_node:
8343 	if ((node->type == XML_ELEMENT_NODE) &&
8344 	    (node->children != NULL)) {
8345 	    node = node->children;
8346 	    continue;
8347 	}
8348 next_sibling:
8349 	if (node == NULL)
8350 	    break;
8351 	if (node->next != NULL)
8352 	    node = node->next;
8353 	else {
8354 	    node = node->parent;
8355 	    goto next_sibling;
8356 	}
8357     } while (node != NULL);
8358 
8359     if (list != NULL)
8360 	xmlFree(list);
8361     return (0);
8362 
8363 internal_error:
8364     if (list != NULL)
8365 	xmlFree(list);
8366     return (-1);
8367 }
8368 
8369 /*
8370 * xmlSearchNsByNamespaceStrict:
8371 * @doc: the document
8372 * @node: the start node
8373 * @nsName: the searched namespace name
8374 * @retNs: the resulting ns-decl
8375 * @prefixed: if the found ns-decl must have a prefix (for attributes)
8376 *
8377 * Dynamically searches for a ns-declaration which matches
8378 * the given @nsName in the ancestor-or-self axis of @node.
8379 *
8380 * Returns 1 if a ns-decl was found, 0 if not and -1 on API
8381 *         and internal errors.
8382 */
8383 static int
xmlSearchNsByNamespaceStrict(xmlDocPtr doc,xmlNodePtr node,const xmlChar * nsName,xmlNsPtr * retNs,int prefixed)8384 xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
8385 			     const xmlChar* nsName,
8386 			     xmlNsPtr *retNs, int prefixed)
8387 {
8388     xmlNodePtr cur, prev = NULL, out = NULL;
8389     xmlNsPtr ns, prevns;
8390 
8391     if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
8392 	return (-1);
8393     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
8394         return(-1);
8395 
8396     *retNs = NULL;
8397     if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
8398 	*retNs = xmlTreeEnsureXMLDecl(doc);
8399 	if (*retNs == NULL)
8400 	    return (-1);
8401 	return (1);
8402     }
8403     cur = node;
8404     do {
8405 	if (cur->type == XML_ELEMENT_NODE) {
8406 	    if (cur->nsDef != NULL) {
8407 		for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8408 		    if (prefixed && (ns->prefix == NULL))
8409 			continue;
8410 		    if (prev != NULL) {
8411 			/*
8412 			* Check the last level of ns-decls for a
8413 			* shadowing prefix.
8414 			*/
8415 			prevns = prev->nsDef;
8416 			do {
8417 			    if ((prevns->prefix == ns->prefix) ||
8418 				((prevns->prefix != NULL) &&
8419 				(ns->prefix != NULL) &&
8420 				xmlStrEqual(prevns->prefix, ns->prefix))) {
8421 				/*
8422 				* Shadowed.
8423 				*/
8424 				break;
8425 			    }
8426 			    prevns = prevns->next;
8427 			} while (prevns != NULL);
8428 			if (prevns != NULL)
8429 			    continue;
8430 		    }
8431 		    /*
8432 		    * Ns-name comparison.
8433 		    */
8434 		    if ((nsName == ns->href) ||
8435 			xmlStrEqual(nsName, ns->href)) {
8436 			/*
8437 			* At this point the prefix can only be shadowed,
8438 			* if we are the the (at least) 3rd level of
8439 			* ns-decls.
8440 			*/
8441 			if (out) {
8442 			    int ret;
8443 
8444 			    ret = xmlNsInScope(doc, node, prev, ns->prefix);
8445 			    if (ret < 0)
8446 				return (-1);
8447 			    /*
8448 			    * TODO: Should we try to find a matching ns-name
8449 			    * only once? This here keeps on searching.
8450 			    * I think we should try further since, there might
8451 			    * be an other matching ns-decl with an unshadowed
8452 			    * prefix.
8453 			    */
8454 			    if (! ret)
8455 				continue;
8456 			}
8457 			*retNs = ns;
8458 			return (1);
8459 		    }
8460 		}
8461 		out = prev;
8462 		prev = cur;
8463 	    }
8464 	} else if ((cur->type == XML_ENTITY_NODE) ||
8465             (cur->type == XML_ENTITY_DECL))
8466 	    return (0);
8467 	cur = cur->parent;
8468     } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8469     return (0);
8470 }
8471 
8472 /*
8473 * xmlSearchNsByPrefixStrict:
8474 * @doc: the document
8475 * @node: the start node
8476 * @prefix: the searched namespace prefix
8477 * @retNs: the resulting ns-decl
8478 *
8479 * Dynamically searches for a ns-declaration which matches
8480 * the given @nsName in the ancestor-or-self axis of @node.
8481 *
8482 * Returns 1 if a ns-decl was found, 0 if not and -1 on API
8483 *         and internal errors.
8484 */
8485 static int
xmlSearchNsByPrefixStrict(xmlDocPtr doc,xmlNodePtr node,const xmlChar * prefix,xmlNsPtr * retNs)8486 xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
8487 			  const xmlChar* prefix,
8488 			  xmlNsPtr *retNs)
8489 {
8490     xmlNodePtr cur;
8491     xmlNsPtr ns;
8492 
8493     if ((doc == NULL) || (node == NULL) || (node->type == XML_NAMESPACE_DECL))
8494         return(-1);
8495 
8496     if (retNs)
8497 	*retNs = NULL;
8498     if (IS_STR_XML(prefix)) {
8499 	if (retNs) {
8500 	    *retNs = xmlTreeEnsureXMLDecl(doc);
8501 	    if (*retNs == NULL)
8502 		return (-1);
8503 	}
8504 	return (1);
8505     }
8506     cur = node;
8507     do {
8508 	if (cur->type == XML_ELEMENT_NODE) {
8509 	    if (cur->nsDef != NULL) {
8510 		ns = cur->nsDef;
8511 		do {
8512 		    if ((prefix == ns->prefix) ||
8513 			xmlStrEqual(prefix, ns->prefix))
8514 		    {
8515 			/*
8516 			* Disabled namespaces, e.g. xmlns:abc="".
8517 			*/
8518 			if (ns->href == NULL)
8519 			    return(0);
8520 			if (retNs)
8521 			    *retNs = ns;
8522 			return (1);
8523 		    }
8524 		    ns = ns->next;
8525 		} while (ns != NULL);
8526 	    }
8527 	} else if ((cur->type == XML_ENTITY_NODE) ||
8528             (cur->type == XML_ENTITY_DECL))
8529 	    return (0);
8530 	cur = cur->parent;
8531     } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8532     return (0);
8533 }
8534 
8535 /*
8536 * xmlDOMWrapNSNormDeclareNsForced:
8537 * @doc: the doc
8538 * @elem: the element-node to declare on
8539 * @nsName: the namespace-name of the ns-decl
8540 * @prefix: the preferred prefix of the ns-decl
8541 * @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
8542 *
8543 * Declares a new namespace on @elem. It tries to use the
8544 * given @prefix; if a ns-decl with the given prefix is already existent
8545 * on @elem, it will generate an other prefix.
8546 *
8547 * Returns 1 if a ns-decl was found, 0 if not and -1 on API
8548 *         and internal errors.
8549 */
8550 static xmlNsPtr
xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,xmlNodePtr elem,const xmlChar * nsName,const xmlChar * prefix,int checkShadow)8551 xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
8552 				xmlNodePtr elem,
8553 				const xmlChar *nsName,
8554 				const xmlChar *prefix,
8555 				int checkShadow)
8556 {
8557 
8558     xmlNsPtr ret;
8559     char buf[50];
8560     const xmlChar *pref;
8561     int counter = 0;
8562 
8563     if ((doc == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE))
8564         return(NULL);
8565     /*
8566     * Create a ns-decl on @anchor.
8567     */
8568     pref = prefix;
8569     while (1) {
8570 	/*
8571 	* Lookup whether the prefix is unused in elem's ns-decls.
8572 	*/
8573 	if ((elem->nsDef != NULL) &&
8574 	    (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
8575 	    goto ns_next_prefix;
8576 	if (checkShadow && elem->parent &&
8577 	    ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8578 	    /*
8579 	    * Does it shadow ancestor ns-decls?
8580 	    */
8581 	    if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
8582 		goto ns_next_prefix;
8583 	}
8584 	ret = xmlNewNs(NULL, nsName, pref);
8585 	if (ret == NULL)
8586 	    return (NULL);
8587 	if (elem->nsDef == NULL)
8588 	    elem->nsDef = ret;
8589 	else {
8590 	    xmlNsPtr ns2 = elem->nsDef;
8591 	    while (ns2->next != NULL)
8592 		ns2 = ns2->next;
8593 	    ns2->next = ret;
8594 	}
8595 	return (ret);
8596 ns_next_prefix:
8597 	counter++;
8598 	if (counter > 1000)
8599 	    return (NULL);
8600 	if (prefix == NULL) {
8601 	    snprintf((char *) buf, sizeof(buf),
8602 		"ns_%d", counter);
8603 	} else
8604 	    snprintf((char *) buf, sizeof(buf),
8605 	    "%.30s_%d", (char *)prefix, counter);
8606 	pref = BAD_CAST buf;
8607     }
8608 }
8609 
8610 /*
8611 * xmlDOMWrapNSNormAcquireNormalizedNs:
8612 * @doc: the doc
8613 * @elem: the element-node to declare namespaces on
8614 * @ns: the ns-struct to use for the search
8615 * @retNs: the found/created ns-struct
8616 * @nsMap: the ns-map
8617 * @depth: the current tree depth
8618 * @ancestorsOnly: search in ancestor ns-decls only
8619 * @prefixed: if the searched ns-decl must have a prefix (for attributes)
8620 *
8621 * Searches for a matching ns-name in the ns-decls of @nsMap, if not
8622 * found it will either declare it on @elem, or store it in doc->oldNs.
8623 * If a new ns-decl needs to be declared on @elem, it tries to use the
8624 * @ns->prefix for it, if this prefix is already in use on @elem, it will
8625 * change the prefix or the new ns-decl.
8626 *
8627 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8628 */
8629 static int
xmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc,xmlNodePtr elem,xmlNsPtr ns,xmlNsPtr * retNs,xmlNsMapPtr * nsMap,int depth,int ancestorsOnly,int prefixed)8630 xmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc,
8631 				   xmlNodePtr elem,
8632 				   xmlNsPtr ns,
8633 				   xmlNsPtr *retNs,
8634 				   xmlNsMapPtr *nsMap,
8635 
8636 				   int depth,
8637 				   int ancestorsOnly,
8638 				   int prefixed)
8639 {
8640     xmlNsMapItemPtr mi;
8641 
8642     if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
8643 	(nsMap == NULL))
8644 	return (-1);
8645 
8646     *retNs = NULL;
8647     /*
8648     * Handle XML namespace.
8649     */
8650     if (IS_STR_XML(ns->prefix)) {
8651 	/*
8652 	* Insert XML namespace mapping.
8653 	*/
8654 	*retNs = xmlTreeEnsureXMLDecl(doc);
8655 	if (*retNs == NULL)
8656 	    return (-1);
8657 	return (0);
8658     }
8659     /*
8660     * If the search should be done in ancestors only and no
8661     * @elem (the first ancestor) was specified, then skip the search.
8662     */
8663     if ((XML_NSMAP_NOTEMPTY(*nsMap)) &&
8664 	(! (ancestorsOnly && (elem == NULL))))
8665     {
8666 	/*
8667 	* Try to find an equal ns-name in in-scope ns-decls.
8668 	*/
8669 	XML_NSMAP_FOREACH(*nsMap, mi) {
8670 	    if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8671 		/*
8672 		* ancestorsOnly: This should be turned on to gain speed,
8673 		* if one knows that the branch itself was already
8674 		* ns-wellformed and no stale references existed.
8675 		* I.e. it searches in the ancestor axis only.
8676 		*/
8677 		((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8678 		/* Skip shadowed prefixes. */
8679 		(mi->shadowDepth == -1) &&
8680 		/* Skip xmlns="" or xmlns:foo="". */
8681 		((mi->newNs->href != NULL) &&
8682 		(mi->newNs->href[0] != 0)) &&
8683 		/* Ensure a prefix if wanted. */
8684 		((! prefixed) || (mi->newNs->prefix != NULL)) &&
8685 		/* Equal ns name */
8686 		((mi->newNs->href == ns->href) ||
8687 		xmlStrEqual(mi->newNs->href, ns->href))) {
8688 		/* Set the mapping. */
8689 		mi->oldNs = ns;
8690 		*retNs = mi->newNs;
8691 		return (0);
8692 	    }
8693 	}
8694     }
8695     /*
8696     * No luck, the namespace is out of scope or shadowed.
8697     */
8698     if (elem == NULL) {
8699 	xmlNsPtr tmpns;
8700 
8701 	/*
8702 	* Store ns-decls in "oldNs" of the document-node.
8703 	*/
8704 	tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8705 	if (tmpns == NULL)
8706 	    return (-1);
8707 	/*
8708 	* Insert mapping.
8709 	*/
8710 	if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
8711 		tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8712 	    xmlFreeNs(tmpns);
8713 	    return (-1);
8714 	}
8715 	*retNs = tmpns;
8716     } else {
8717 	xmlNsPtr tmpns;
8718 
8719 	tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8720 	    ns->prefix, 0);
8721 	if (tmpns == NULL)
8722 	    return (-1);
8723 
8724 	if (*nsMap != NULL) {
8725 	    /*
8726 	    * Does it shadow ancestor ns-decls?
8727 	    */
8728 	    XML_NSMAP_FOREACH(*nsMap, mi) {
8729 		if ((mi->depth < depth) &&
8730 		    (mi->shadowDepth == -1) &&
8731 		    ((ns->prefix == mi->newNs->prefix) ||
8732 		    xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8733 		    /*
8734 		    * Shadows.
8735 		    */
8736 		    mi->shadowDepth = depth;
8737 		    break;
8738 		}
8739 	    }
8740 	}
8741 	if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
8742 	    xmlFreeNs(tmpns);
8743 	    return (-1);
8744 	}
8745 	*retNs = tmpns;
8746     }
8747     return (0);
8748 }
8749 
8750 typedef enum {
8751     XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8752 } xmlDOMReconcileNSOptions;
8753 
8754 /*
8755 * xmlDOMWrapReconcileNamespaces:
8756 * @ctxt: DOM wrapper context, unused at the moment
8757 * @elem: the element-node
8758 * @options: option flags
8759 *
8760 * Ensures that ns-references point to ns-decls hold on element-nodes.
8761 * Ensures that the tree is namespace wellformed by creating additional
8762 * ns-decls where needed. Note that, since prefixes of already existent
8763 * ns-decls can be shadowed by this process, it could break QNames in
8764 * attribute values or element content.
8765 *
8766 * NOTE: This function was not intensively tested.
8767 *
8768 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8769 */
8770 
8771 int
xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,xmlNodePtr elem,int options)8772 xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8773 			      xmlNodePtr elem,
8774 			      int options)
8775 {
8776     int depth = -1, adoptns = 0, parnsdone = 0;
8777     xmlNsPtr ns, prevns;
8778     xmlDocPtr doc;
8779     xmlNodePtr cur, curElem = NULL;
8780     xmlNsMapPtr nsMap = NULL;
8781     xmlNsMapItemPtr /* topmi = NULL, */ mi;
8782     /* @ancestorsOnly should be set by an option flag. */
8783     int ancestorsOnly = 0;
8784     int optRemoveRedundantNS =
8785 	((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8786     xmlNsPtr *listRedund = NULL;
8787     int sizeRedund = 0, nbRedund = 0, ret, i, j;
8788 
8789     if ((elem == NULL) || (elem->doc == NULL) ||
8790 	(elem->type != XML_ELEMENT_NODE))
8791 	return (-1);
8792 
8793     doc = elem->doc;
8794     cur = elem;
8795     do {
8796 	switch (cur->type) {
8797 	    case XML_ELEMENT_NODE:
8798 		adoptns = 1;
8799 		curElem = cur;
8800 		depth++;
8801 		/*
8802 		* Namespace declarations.
8803 		*/
8804 		if (cur->nsDef != NULL) {
8805 		    prevns = NULL;
8806 		    ns = cur->nsDef;
8807 		    while (ns != NULL) {
8808 			if (! parnsdone) {
8809 			    if ((elem->parent) &&
8810 				((xmlNodePtr) elem->parent->doc != elem->parent)) {
8811 				/*
8812 				* Gather ancestor in-scope ns-decls.
8813 				*/
8814 				if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8815 				    elem->parent) == -1)
8816 				    goto internal_error;
8817 			    }
8818 			    parnsdone = 1;
8819 			}
8820 
8821 			/*
8822 			* Lookup the ns ancestor-axis for equal ns-decls in scope.
8823 			*/
8824 			if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
8825 			    XML_NSMAP_FOREACH(nsMap, mi) {
8826 				if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8827 				    (mi->shadowDepth == -1) &&
8828 				    ((ns->prefix == mi->newNs->prefix) ||
8829 				      xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8830 				    ((ns->href == mi->newNs->href) ||
8831 				      xmlStrEqual(ns->href, mi->newNs->href)))
8832 				{
8833 				    /*
8834 				    * A redundant ns-decl was found.
8835 				    * Add it to the list of redundant ns-decls.
8836 				    */
8837 				    if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8838 					&sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8839 					goto internal_error;
8840 				    /*
8841 				    * Remove the ns-decl from the element-node.
8842 				    */
8843 				    if (prevns)
8844 					prevns->next = ns->next;
8845 				    else
8846 					cur->nsDef = ns->next;
8847 				    goto next_ns_decl;
8848 				}
8849 			    }
8850 			}
8851 
8852 			/*
8853 			* Skip ns-references handling if the referenced
8854 			* ns-decl is declared on the same element.
8855 			*/
8856 			if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8857 			    adoptns = 0;
8858 			/*
8859 			* Does it shadow any ns-decl?
8860 			*/
8861 			if (XML_NSMAP_NOTEMPTY(nsMap)) {
8862 			    XML_NSMAP_FOREACH(nsMap, mi) {
8863 				if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8864 				    (mi->shadowDepth == -1) &&
8865 				    ((ns->prefix == mi->newNs->prefix) ||
8866 				    xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8867 
8868 				    mi->shadowDepth = depth;
8869 				}
8870 			    }
8871 			}
8872 			/*
8873 			* Push mapping.
8874 			*/
8875 			if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
8876 			    depth) == NULL)
8877 			    goto internal_error;
8878 
8879 			prevns = ns;
8880 next_ns_decl:
8881 			ns = ns->next;
8882 		    }
8883 		}
8884 		if (! adoptns)
8885 		    goto ns_end;
8886                 /* Falls through. */
8887 	    case XML_ATTRIBUTE_NODE:
8888 		/* No ns, no fun. */
8889 		if (cur->ns == NULL)
8890 		    goto ns_end;
8891 
8892 		if (! parnsdone) {
8893 		    if ((elem->parent) &&
8894 			((xmlNodePtr) elem->parent->doc != elem->parent)) {
8895 			if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8896 				elem->parent) == -1)
8897 			    goto internal_error;
8898 		    }
8899 		    parnsdone = 1;
8900 		}
8901 		/*
8902 		* Adjust the reference if this was a redundant ns-decl.
8903 		*/
8904 		if (listRedund) {
8905 		   for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8906 		       if (cur->ns == listRedund[j]) {
8907 			   cur->ns = listRedund[++j];
8908 			   break;
8909 		       }
8910 		   }
8911 		}
8912 		/*
8913 		* Adopt ns-references.
8914 		*/
8915 		if (XML_NSMAP_NOTEMPTY(nsMap)) {
8916 		    /*
8917 		    * Search for a mapping.
8918 		    */
8919 		    XML_NSMAP_FOREACH(nsMap, mi) {
8920 			if ((mi->shadowDepth == -1) &&
8921 			    (cur->ns == mi->oldNs)) {
8922 
8923 			    cur->ns = mi->newNs;
8924 			    goto ns_end;
8925 			}
8926 		    }
8927 		}
8928 		/*
8929 		* Acquire a normalized ns-decl and add it to the map.
8930 		*/
8931 		if (xmlDOMWrapNSNormAcquireNormalizedNs(doc, curElem,
8932 			cur->ns, &ns,
8933 			&nsMap, depth,
8934 			ancestorsOnly,
8935 			(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8936 		    goto internal_error;
8937 		cur->ns = ns;
8938 
8939 ns_end:
8940 		if ((cur->type == XML_ELEMENT_NODE) &&
8941 		    (cur->properties != NULL)) {
8942 		    /*
8943 		    * Process attributes.
8944 		    */
8945 		    cur = (xmlNodePtr) cur->properties;
8946 		    continue;
8947 		}
8948 		break;
8949 	    default:
8950 		goto next_sibling;
8951 	}
8952 into_content:
8953 	if ((cur->type == XML_ELEMENT_NODE) &&
8954 	    (cur->children != NULL)) {
8955 	    /*
8956 	    * Process content of element-nodes only.
8957 	    */
8958 	    cur = cur->children;
8959 	    continue;
8960 	}
8961 next_sibling:
8962 	if (cur == elem)
8963 	    break;
8964 	if (cur->type == XML_ELEMENT_NODE) {
8965 	    if (XML_NSMAP_NOTEMPTY(nsMap)) {
8966 		/*
8967 		* Pop mappings.
8968 		*/
8969 		while ((nsMap->last != NULL) &&
8970 		    (nsMap->last->depth >= depth))
8971 		{
8972 		    XML_NSMAP_POP(nsMap, mi)
8973 		}
8974 		/*
8975 		* Unshadow.
8976 		*/
8977 		XML_NSMAP_FOREACH(nsMap, mi) {
8978 		    if (mi->shadowDepth >= depth)
8979 			mi->shadowDepth = -1;
8980 		}
8981 	    }
8982 	    depth--;
8983 	}
8984 	if (cur->next != NULL)
8985 	    cur = cur->next;
8986 	else {
8987 	    if (cur->type == XML_ATTRIBUTE_NODE) {
8988 		cur = cur->parent;
8989 		goto into_content;
8990 	    }
8991 	    cur = cur->parent;
8992 	    goto next_sibling;
8993 	}
8994     } while (cur != NULL);
8995 
8996     ret = 0;
8997     goto exit;
8998 internal_error:
8999     ret = -1;
9000 exit:
9001     if (listRedund) {
9002 	for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
9003 	    xmlFreeNs(listRedund[j]);
9004 	}
9005 	xmlFree(listRedund);
9006     }
9007     if (nsMap != NULL)
9008 	xmlDOMWrapNsMapFree(nsMap);
9009     return (ret);
9010 }
9011 
9012 /*
9013 * xmlDOMWrapAdoptBranch:
9014 * @ctxt: the optional context for custom processing
9015 * @sourceDoc: the optional sourceDoc
9016 * @node: the element-node to start with
9017 * @destDoc: the destination doc for adoption
9018 * @destParent: the optional new parent of @node in @destDoc
9019 * @options: option flags
9020 *
9021 * Ensures that ns-references point to @destDoc: either to
9022 * elements->nsDef entries if @destParent is given, or to
9023 * @destDoc->oldNs otherwise.
9024 * If @destParent is given, it ensures that the tree is namespace
9025 * wellformed by creating additional ns-decls where needed.
9026 * Note that, since prefixes of already existent ns-decls can be
9027 * shadowed by this process, it could break QNames in attribute
9028 * values or element content.
9029 *
9030 * NOTE: This function was not intensively tested.
9031 *
9032 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9033 */
9034 static int
xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr sourceDoc,xmlNodePtr node,xmlDocPtr destDoc,xmlNodePtr destParent,int options ATTRIBUTE_UNUSED)9035 xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
9036 		      xmlDocPtr sourceDoc,
9037 		      xmlNodePtr node,
9038 		      xmlDocPtr destDoc,
9039 		      xmlNodePtr destParent,
9040 		      int options ATTRIBUTE_UNUSED)
9041 {
9042     int ret = 0;
9043     xmlNodePtr cur, curElem = NULL;
9044     xmlNsMapPtr nsMap = NULL;
9045     xmlNsMapItemPtr mi;
9046     xmlNsPtr ns = NULL;
9047     int depth = -1, adoptStr = 1;
9048     /* gather @parent's ns-decls. */
9049     int parnsdone;
9050     /* @ancestorsOnly should be set per option. */
9051     int ancestorsOnly = 0;
9052 
9053     /*
9054     * Optimize string adoption for equal or none dicts.
9055     */
9056     if ((sourceDoc != NULL) &&
9057 	(sourceDoc->dict == destDoc->dict))
9058 	adoptStr = 0;
9059     else
9060 	adoptStr = 1;
9061 
9062     /*
9063     * Get the ns-map from the context if available.
9064     */
9065     if (ctxt)
9066 	nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
9067     /*
9068     * Disable search for ns-decls in the parent-axis of the
9069     * destination element, if:
9070     * 1) there's no destination parent
9071     * 2) custom ns-reference handling is used
9072     */
9073     if ((destParent == NULL) ||
9074 	(ctxt && ctxt->getNsForNodeFunc))
9075     {
9076 	parnsdone = 1;
9077     } else
9078 	parnsdone = 0;
9079 
9080     cur = node;
9081     if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9082 	goto internal_error;
9083 
9084     while (cur != NULL) {
9085 	/*
9086 	* Paranoid source-doc sanity check.
9087 	*/
9088 	if (cur->doc != sourceDoc) {
9089 	    /*
9090 	    * We'll assume XIncluded nodes if the doc differs.
9091 	    * TODO: Do we need to reconciliate XIncluded nodes?
9092 	    * This here skips XIncluded nodes and tries to handle
9093 	    * broken sequences.
9094 	    */
9095 	    if (cur->next == NULL)
9096 		goto leave_node;
9097 	    do {
9098 		cur = cur->next;
9099 		if ((cur->type == XML_XINCLUDE_END) ||
9100 		    (cur->doc == node->doc))
9101 		    break;
9102 	    } while (cur->next != NULL);
9103 
9104 	    if (cur->doc != node->doc)
9105 		goto leave_node;
9106 	}
9107 	cur->doc = destDoc;
9108 	switch (cur->type) {
9109 	    case XML_XINCLUDE_START:
9110 	    case XML_XINCLUDE_END:
9111 		/*
9112 		* TODO
9113 		*/
9114 		return (-1);
9115 	    case XML_ELEMENT_NODE:
9116 		curElem = cur;
9117 		depth++;
9118 		/*
9119 		* Namespace declarations.
9120 		* - ns->href and ns->prefix are never in the dict, so
9121 		*   we need not move the values over to the destination dict.
9122 		* - Note that for custom handling of ns-references,
9123 		*   the ns-decls need not be stored in the ns-map,
9124 		*   since they won't be referenced by node->ns.
9125 		*/
9126 		if ((cur->nsDef) &&
9127 		    ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)))
9128 		{
9129 		    if (! parnsdone) {
9130 			/*
9131 			* Gather @parent's in-scope ns-decls.
9132 			*/
9133 			if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9134 			    destParent) == -1)
9135 			    goto internal_error;
9136 			parnsdone = 1;
9137 		    }
9138 		    for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
9139 			/*
9140 			* NOTE: ns->prefix and ns->href are never in the dict.
9141 			* XML_TREE_ADOPT_STR(ns->prefix)
9142 			* XML_TREE_ADOPT_STR(ns->href)
9143 			*/
9144 			/*
9145 			* Does it shadow any ns-decl?
9146 			*/
9147 			if (XML_NSMAP_NOTEMPTY(nsMap)) {
9148 			    XML_NSMAP_FOREACH(nsMap, mi) {
9149 				if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9150 				    (mi->shadowDepth == -1) &&
9151 				    ((ns->prefix == mi->newNs->prefix) ||
9152 				    xmlStrEqual(ns->prefix,
9153 				    mi->newNs->prefix))) {
9154 
9155 				    mi->shadowDepth = depth;
9156 				}
9157 			    }
9158 			}
9159 			/*
9160 			* Push mapping.
9161 			*/
9162 			if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9163 			    ns, ns, depth) == NULL)
9164 			    goto internal_error;
9165 		    }
9166 		}
9167                 /* Falls through. */
9168 	    case XML_ATTRIBUTE_NODE:
9169 		/* No namespace, no fun. */
9170 		if (cur->ns == NULL)
9171 		    goto ns_end;
9172 
9173 		if (! parnsdone) {
9174 		    if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9175 			destParent) == -1)
9176 			goto internal_error;
9177 		    parnsdone = 1;
9178 		}
9179 		/*
9180 		* Adopt ns-references.
9181 		*/
9182 		if (XML_NSMAP_NOTEMPTY(nsMap)) {
9183 		    /*
9184 		    * Search for a mapping.
9185 		    */
9186 		    XML_NSMAP_FOREACH(nsMap, mi) {
9187 			if ((mi->shadowDepth == -1) &&
9188 			    (cur->ns == mi->oldNs)) {
9189 
9190 			    cur->ns = mi->newNs;
9191 			    goto ns_end;
9192 			}
9193 		    }
9194 		}
9195 		/*
9196 		* No matching namespace in scope. We need a new one.
9197 		*/
9198 		if ((ctxt) && (ctxt->getNsForNodeFunc)) {
9199 		    /*
9200 		    * User-defined behaviour.
9201 		    */
9202 		    ns = ctxt->getNsForNodeFunc(ctxt, cur,
9203 			cur->ns->href, cur->ns->prefix);
9204 		    /*
9205 		    * Insert mapping if ns is available; it's the users fault
9206 		    * if not.
9207 		    */
9208 		    if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9209 			    cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9210 			goto internal_error;
9211 		    cur->ns = ns;
9212 		} else {
9213 		    /*
9214 		    * Acquire a normalized ns-decl and add it to the map.
9215 		    */
9216 		    if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc,
9217 			/* ns-decls on curElem or on destDoc->oldNs */
9218 			destParent ? curElem : NULL,
9219 			cur->ns, &ns,
9220 			&nsMap, depth,
9221 			ancestorsOnly,
9222 			/* ns-decls must be prefixed for attributes. */
9223 			(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9224 			goto internal_error;
9225 		    cur->ns = ns;
9226 		}
9227 ns_end:
9228 		/*
9229 		* Further node properties.
9230 		* TODO: Is this all?
9231 		*/
9232 		XML_TREE_ADOPT_STR(cur->name)
9233 		if (cur->type == XML_ELEMENT_NODE) {
9234 		    cur->psvi = NULL;
9235 		    cur->line = 0;
9236 		    cur->extra = 0;
9237 		    /*
9238 		    * Walk attributes.
9239 		    */
9240 		    if (cur->properties != NULL) {
9241 			/*
9242 			* Process first attribute node.
9243 			*/
9244 			cur = (xmlNodePtr) cur->properties;
9245 			continue;
9246 		    }
9247 		} else {
9248 		    /*
9249 		    * Attributes.
9250 		    */
9251 		    if ((sourceDoc != NULL) &&
9252 			(((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
9253 		    {
9254 			xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
9255 		    }
9256 		    ((xmlAttrPtr) cur)->atype = 0;
9257 		    ((xmlAttrPtr) cur)->psvi = NULL;
9258 		}
9259 		break;
9260 	    case XML_TEXT_NODE:
9261 	    case XML_CDATA_SECTION_NODE:
9262 		/*
9263 		* This puts the content in the dest dict, only if
9264 		* it was previously in the source dict.
9265 		*/
9266 		XML_TREE_ADOPT_STR_2(cur->content)
9267 		goto leave_node;
9268 	    case XML_ENTITY_REF_NODE:
9269 		/*
9270 		* Remove reference to the entity-node.
9271 		*/
9272 		cur->content = NULL;
9273 		cur->children = NULL;
9274 		cur->last = NULL;
9275 		if ((destDoc->intSubset) || (destDoc->extSubset)) {
9276 		    xmlEntityPtr ent;
9277 		    /*
9278 		    * Assign new entity-node if available.
9279 		    */
9280 		    ent = xmlGetDocEntity(destDoc, cur->name);
9281 		    if (ent != NULL) {
9282 			cur->content = ent->content;
9283 			cur->children = (xmlNodePtr) ent;
9284 			cur->last = (xmlNodePtr) ent;
9285 		    }
9286 		}
9287 		goto leave_node;
9288 	    case XML_PI_NODE:
9289 		XML_TREE_ADOPT_STR(cur->name)
9290 		XML_TREE_ADOPT_STR_2(cur->content)
9291 		break;
9292 	    case XML_COMMENT_NODE:
9293 		break;
9294 	    default:
9295 		goto internal_error;
9296 	}
9297 	/*
9298 	* Walk the tree.
9299 	*/
9300 	if (cur->children != NULL) {
9301 	    cur = cur->children;
9302 	    continue;
9303 	}
9304 
9305 leave_node:
9306 	if (cur == node)
9307 	    break;
9308 	if ((cur->type == XML_ELEMENT_NODE) ||
9309 	    (cur->type == XML_XINCLUDE_START) ||
9310 	    (cur->type == XML_XINCLUDE_END))
9311 	{
9312 	    /*
9313 	    * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9314 	    */
9315 	    if (XML_NSMAP_NOTEMPTY(nsMap)) {
9316 		/*
9317 		* Pop mappings.
9318 		*/
9319 		while ((nsMap->last != NULL) &&
9320 		    (nsMap->last->depth >= depth))
9321 		{
9322 		    XML_NSMAP_POP(nsMap, mi)
9323 		}
9324 		/*
9325 		* Unshadow.
9326 		*/
9327 		XML_NSMAP_FOREACH(nsMap, mi) {
9328 		    if (mi->shadowDepth >= depth)
9329 			mi->shadowDepth = -1;
9330 		}
9331 	    }
9332 	    depth--;
9333 	}
9334 	if (cur->next != NULL)
9335 	    cur = cur->next;
9336 	else if ((cur->type == XML_ATTRIBUTE_NODE) &&
9337 	    (cur->parent->children != NULL))
9338 	{
9339 	    cur = cur->parent->children;
9340 	} else {
9341 	    cur = cur->parent;
9342 	    goto leave_node;
9343 	}
9344     }
9345 
9346     goto exit;
9347 
9348 internal_error:
9349     ret = -1;
9350 
9351 exit:
9352     /*
9353     * Cleanup.
9354     */
9355     if (nsMap != NULL) {
9356 	if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9357 	    /*
9358 	    * Just cleanup the map but don't free.
9359 	    */
9360 	    if (nsMap->first) {
9361 		if (nsMap->pool)
9362 		    nsMap->last->next = nsMap->pool;
9363 		nsMap->pool = nsMap->first;
9364 		nsMap->first = NULL;
9365 	    }
9366 	} else
9367 	    xmlDOMWrapNsMapFree(nsMap);
9368     }
9369     return(ret);
9370 }
9371 
9372 /*
9373 * xmlDOMWrapCloneNode:
9374 * @ctxt: the optional context for custom processing
9375 * @sourceDoc: the optional sourceDoc
9376 * @node: the node to start with
9377 * @resNode: the clone of the given @node
9378 * @destDoc: the destination doc
9379 * @destParent: the optional new parent of @node in @destDoc
9380 * @deep: descend into child if set
9381 * @options: option flags
9382 *
9383 * References of out-of scope ns-decls are remapped to point to @destDoc:
9384 * 1) If @destParent is given, then nsDef entries on element-nodes are used
9385 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.
9386 *    This is the case when you don't know already where the cloned branch
9387 *    will be added to.
9388 *
9389 * If @destParent is given, it ensures that the tree is namespace
9390 * wellformed by creating additional ns-decls where needed.
9391 * Note that, since prefixes of already existent ns-decls can be
9392 * shadowed by this process, it could break QNames in attribute
9393 * values or element content.
9394 * TODO:
9395 *   1) What to do with XInclude? Currently this returns an error for XInclude.
9396 *
9397 * Returns 0 if the operation succeeded,
9398 *         1 if a node of unsupported (or not yet supported) type was given,
9399 *         -1 on API/internal errors.
9400 */
9401 
9402 int
xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr sourceDoc,xmlNodePtr node,xmlNodePtr * resNode,xmlDocPtr destDoc,xmlNodePtr destParent,int deep,int options ATTRIBUTE_UNUSED)9403 xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
9404 		      xmlDocPtr sourceDoc,
9405 		      xmlNodePtr node,
9406 		      xmlNodePtr *resNode,
9407 		      xmlDocPtr destDoc,
9408 		      xmlNodePtr destParent,
9409 		      int deep,
9410 		      int options ATTRIBUTE_UNUSED)
9411 {
9412     int ret = 0;
9413     xmlNodePtr cur, curElem = NULL;
9414     xmlNsMapPtr nsMap = NULL;
9415     xmlNsMapItemPtr mi;
9416     xmlNsPtr ns;
9417     int depth = -1;
9418     /* int adoptStr = 1; */
9419     /* gather @parent's ns-decls. */
9420     int parnsdone = 0;
9421     /*
9422     * @ancestorsOnly:
9423     * TODO: @ancestorsOnly should be set per option.
9424     *
9425     */
9426     int ancestorsOnly = 0;
9427     xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
9428     xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
9429     xmlDictPtr dict; /* The destination dict */
9430 
9431     if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
9432 	return(-1);
9433     /*
9434     * TODO: Initially we support only element-nodes.
9435     */
9436     if (node->type != XML_ELEMENT_NODE)
9437 	return(1);
9438     /*
9439     * Check node->doc sanity.
9440     */
9441     if ((node->doc != NULL) && (sourceDoc != NULL) &&
9442 	(node->doc != sourceDoc)) {
9443 	/*
9444 	* Might be an XIncluded node.
9445 	*/
9446 	return (-1);
9447     }
9448     if (sourceDoc == NULL)
9449 	sourceDoc = node->doc;
9450     if (sourceDoc == NULL)
9451         return (-1);
9452 
9453     dict = destDoc->dict;
9454     /*
9455     * Reuse the namespace map of the context.
9456     */
9457     if (ctxt)
9458 	nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
9459 
9460     *resNode = NULL;
9461 
9462     cur = node;
9463     if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9464         return(-1);
9465 
9466     while (cur != NULL) {
9467 	if (cur->doc != sourceDoc) {
9468 	    /*
9469 	    * We'll assume XIncluded nodes if the doc differs.
9470 	    * TODO: Do we need to reconciliate XIncluded nodes?
9471 	    * TODO: This here returns -1 in this case.
9472 	    */
9473 	    goto internal_error;
9474 	}
9475 	/*
9476 	* Create a new node.
9477 	*/
9478 	switch (cur->type) {
9479 	    case XML_XINCLUDE_START:
9480 	    case XML_XINCLUDE_END:
9481 		/*
9482 		* TODO: What to do with XInclude?
9483 		*/
9484 		goto internal_error;
9485 		break;
9486 	    case XML_ELEMENT_NODE:
9487 	    case XML_TEXT_NODE:
9488 	    case XML_CDATA_SECTION_NODE:
9489 	    case XML_COMMENT_NODE:
9490 	    case XML_PI_NODE:
9491 	    case XML_DOCUMENT_FRAG_NODE:
9492 	    case XML_ENTITY_REF_NODE:
9493 	    case XML_ENTITY_NODE:
9494 		/*
9495 		* Nodes of xmlNode structure.
9496 		*/
9497 		clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
9498 		if (clone == NULL) {
9499 		    xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node");
9500 		    goto internal_error;
9501 		}
9502 		memset(clone, 0, sizeof(xmlNode));
9503 		/*
9504 		* Set hierarchical links.
9505 		*/
9506 		if (resultClone != NULL) {
9507 		    clone->parent = parentClone;
9508 		    if (prevClone) {
9509 			prevClone->next = clone;
9510 			clone->prev = prevClone;
9511 		    } else
9512 			parentClone->children = clone;
9513 		} else
9514 		    resultClone = clone;
9515 
9516 		break;
9517 	    case XML_ATTRIBUTE_NODE:
9518 		/*
9519 		* Attributes (xmlAttr).
9520 		*/
9521 		clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
9522 		if (clone == NULL) {
9523 		    xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node");
9524 		    goto internal_error;
9525 		}
9526 		memset(clone, 0, sizeof(xmlAttr));
9527 		/*
9528 		* Set hierarchical links.
9529 		* TODO: Change this to add to the end of attributes.
9530 		*/
9531 		if (resultClone != NULL) {
9532 		    clone->parent = parentClone;
9533 		    if (prevClone) {
9534 			prevClone->next = clone;
9535 			clone->prev = prevClone;
9536 		    } else
9537 			parentClone->properties = (xmlAttrPtr) clone;
9538 		} else
9539 		    resultClone = clone;
9540 		break;
9541 	    default:
9542 		/*
9543 		* TODO QUESTION: Any other nodes expected?
9544 		*/
9545 		goto internal_error;
9546 	}
9547 
9548 	clone->type = cur->type;
9549 	clone->doc = destDoc;
9550 
9551 	/*
9552 	* Clone the name of the node if any.
9553 	*/
9554 	if (cur->name == xmlStringText)
9555 	    clone->name = xmlStringText;
9556 	else if (cur->name == xmlStringTextNoenc)
9557 	    /*
9558 	    * NOTE: Although xmlStringTextNoenc is never assigned to a node
9559 	    *   in tree.c, it might be set in Libxslt via
9560 	    *   "xsl:disable-output-escaping".
9561 	    */
9562 	    clone->name = xmlStringTextNoenc;
9563 	else if (cur->name == xmlStringComment)
9564 	    clone->name = xmlStringComment;
9565 	else if (cur->name != NULL) {
9566 	    DICT_CONST_COPY(cur->name, clone->name);
9567 	}
9568 
9569 	switch (cur->type) {
9570 	    case XML_XINCLUDE_START:
9571 	    case XML_XINCLUDE_END:
9572 		/*
9573 		* TODO
9574 		*/
9575 		return (-1);
9576 	    case XML_ELEMENT_NODE:
9577 		curElem = cur;
9578 		depth++;
9579 		/*
9580 		* Namespace declarations.
9581 		*/
9582 		if (cur->nsDef != NULL) {
9583 		    if (! parnsdone) {
9584 			if (destParent && (ctxt == NULL)) {
9585 			    /*
9586 			    * Gather @parent's in-scope ns-decls.
9587 			    */
9588 			    if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9589 				destParent) == -1)
9590 				goto internal_error;
9591 			}
9592 			parnsdone = 1;
9593 		    }
9594 		    /*
9595 		    * Clone namespace declarations.
9596 		    */
9597 		    cloneNsDefSlot = &(clone->nsDef);
9598 		    for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
9599 			/*
9600 			* Create a new xmlNs.
9601 			*/
9602 			cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
9603 			if (cloneNs == NULL) {
9604 			    xmlTreeErrMemory("xmlDOMWrapCloneNode(): "
9605 				"allocating namespace");
9606 			    return(-1);
9607 			}
9608 			memset(cloneNs, 0, sizeof(xmlNs));
9609 			cloneNs->type = XML_LOCAL_NAMESPACE;
9610 
9611 			if (ns->href != NULL)
9612 			    cloneNs->href = xmlStrdup(ns->href);
9613 			if (ns->prefix != NULL)
9614 			    cloneNs->prefix = xmlStrdup(ns->prefix);
9615 
9616 			*cloneNsDefSlot = cloneNs;
9617 			cloneNsDefSlot = &(cloneNs->next);
9618 
9619 			/*
9620 			* Note that for custom handling of ns-references,
9621 			* the ns-decls need not be stored in the ns-map,
9622 			* since they won't be referenced by node->ns.
9623 			*/
9624 			if ((ctxt == NULL) ||
9625 			    (ctxt->getNsForNodeFunc == NULL))
9626 			{
9627 			    /*
9628 			    * Does it shadow any ns-decl?
9629 			    */
9630 			    if (XML_NSMAP_NOTEMPTY(nsMap)) {
9631 				XML_NSMAP_FOREACH(nsMap, mi) {
9632 				    if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9633 					(mi->shadowDepth == -1) &&
9634 					((ns->prefix == mi->newNs->prefix) ||
9635 					xmlStrEqual(ns->prefix,
9636 					mi->newNs->prefix))) {
9637 					/*
9638 					* Mark as shadowed at the current
9639 					* depth.
9640 					*/
9641 					mi->shadowDepth = depth;
9642 				    }
9643 				}
9644 			    }
9645 			    /*
9646 			    * Push mapping.
9647 			    */
9648 			    if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9649 				ns, cloneNs, depth) == NULL)
9650 				goto internal_error;
9651 			}
9652 		    }
9653 		}
9654 		/* cur->ns will be processed further down. */
9655 		break;
9656 	    case XML_ATTRIBUTE_NODE:
9657 		/* IDs will be processed further down. */
9658 		/* cur->ns will be processed further down. */
9659 		break;
9660 	    case XML_TEXT_NODE:
9661 	    case XML_CDATA_SECTION_NODE:
9662 		/*
9663 		* Note that this will also cover the values of attributes.
9664 		*/
9665 		DICT_COPY(cur->content, clone->content);
9666 		goto leave_node;
9667 	    case XML_ENTITY_NODE:
9668 		/* TODO: What to do here? */
9669 		goto leave_node;
9670 	    case XML_ENTITY_REF_NODE:
9671 		if (sourceDoc != destDoc) {
9672 		    if ((destDoc->intSubset) || (destDoc->extSubset)) {
9673 			xmlEntityPtr ent;
9674 			/*
9675 			* Different doc: Assign new entity-node if available.
9676 			*/
9677 			ent = xmlGetDocEntity(destDoc, cur->name);
9678 			if (ent != NULL) {
9679 			    clone->content = ent->content;
9680 			    clone->children = (xmlNodePtr) ent;
9681 			    clone->last = (xmlNodePtr) ent;
9682 			}
9683 		    }
9684 		} else {
9685 		    /*
9686 		    * Same doc: Use the current node's entity declaration
9687 		    * and value.
9688 		    */
9689 		    clone->content = cur->content;
9690 		    clone->children = cur->children;
9691 		    clone->last = cur->last;
9692 		}
9693 		goto leave_node;
9694 	    case XML_PI_NODE:
9695 		DICT_COPY(cur->content, clone->content);
9696 		goto leave_node;
9697 	    case XML_COMMENT_NODE:
9698 		DICT_COPY(cur->content, clone->content);
9699 		goto leave_node;
9700 	    default:
9701 		goto internal_error;
9702 	}
9703 
9704 	if (cur->ns == NULL)
9705 	    goto end_ns_reference;
9706 
9707 /* handle_ns_reference: */
9708 	/*
9709 	** The following will take care of references to ns-decls ********
9710 	** and is intended only for element- and attribute-nodes.
9711 	**
9712 	*/
9713 	if (! parnsdone) {
9714 	    if (destParent && (ctxt == NULL)) {
9715 		if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
9716 		    goto internal_error;
9717 	    }
9718 	    parnsdone = 1;
9719 	}
9720 	/*
9721 	* Adopt ns-references.
9722 	*/
9723 	if (XML_NSMAP_NOTEMPTY(nsMap)) {
9724 	    /*
9725 	    * Search for a mapping.
9726 	    */
9727 	    XML_NSMAP_FOREACH(nsMap, mi) {
9728 		if ((mi->shadowDepth == -1) &&
9729 		    (cur->ns == mi->oldNs)) {
9730 		    /*
9731 		    * This is the nice case: a mapping was found.
9732 		    */
9733 		    clone->ns = mi->newNs;
9734 		    goto end_ns_reference;
9735 		}
9736 	    }
9737 	}
9738 	/*
9739 	* No matching namespace in scope. We need a new one.
9740 	*/
9741 	if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) {
9742 	    /*
9743 	    * User-defined behaviour.
9744 	    */
9745 	    ns = ctxt->getNsForNodeFunc(ctxt, cur,
9746 		cur->ns->href, cur->ns->prefix);
9747 	    /*
9748 	    * Add user's mapping.
9749 	    */
9750 	    if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9751 		cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9752 		goto internal_error;
9753 	    clone->ns = ns;
9754 	} else {
9755 	    /*
9756 	    * Acquire a normalized ns-decl and add it to the map.
9757 	    */
9758 	    if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc,
9759 		/* ns-decls on curElem or on destDoc->oldNs */
9760 		destParent ? curElem : NULL,
9761 		cur->ns, &ns,
9762 		&nsMap, depth,
9763 		/* if we need to search only in the ancestor-axis */
9764 		ancestorsOnly,
9765 		/* ns-decls must be prefixed for attributes. */
9766 		(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9767 		goto internal_error;
9768 	    clone->ns = ns;
9769 	}
9770 
9771 end_ns_reference:
9772 
9773 	/*
9774 	* Some post-processing.
9775 	*
9776 	* Handle ID attributes.
9777 	*/
9778 	if ((clone->type == XML_ATTRIBUTE_NODE) &&
9779 	    (clone->parent != NULL))
9780 	{
9781 	    if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
9782 
9783 		xmlChar *idVal;
9784 
9785 		idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9786 		if (idVal != NULL) {
9787 		    if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9788 			/* TODO: error message. */
9789 			xmlFree(idVal);
9790 			goto internal_error;
9791 		    }
9792 		    xmlFree(idVal);
9793 		}
9794 	    }
9795 	}
9796 	/*
9797 	**
9798 	** The following will traverse the tree **************************
9799 	**
9800 	*
9801 	* Walk the element's attributes before descending into child-nodes.
9802 	*/
9803 	if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9804 	    prevClone = NULL;
9805 	    parentClone = clone;
9806 	    cur = (xmlNodePtr) cur->properties;
9807 	    continue;
9808 	}
9809 into_content:
9810 	/*
9811 	* Descend into child-nodes.
9812 	*/
9813 	if (cur->children != NULL) {
9814 	    if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9815 		prevClone = NULL;
9816 		parentClone = clone;
9817 		cur = cur->children;
9818 		continue;
9819 	    }
9820 	}
9821 
9822 leave_node:
9823 	/*
9824 	* At this point we are done with the node, its content
9825 	* and an element-nodes's attribute-nodes.
9826 	*/
9827 	if (cur == node)
9828 	    break;
9829 	if ((cur->type == XML_ELEMENT_NODE) ||
9830 	    (cur->type == XML_XINCLUDE_START) ||
9831 	    (cur->type == XML_XINCLUDE_END)) {
9832 	    /*
9833 	    * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9834 	    */
9835 	    if (XML_NSMAP_NOTEMPTY(nsMap)) {
9836 		/*
9837 		* Pop mappings.
9838 		*/
9839 		while ((nsMap->last != NULL) &&
9840 		    (nsMap->last->depth >= depth))
9841 		{
9842 		    XML_NSMAP_POP(nsMap, mi)
9843 		}
9844 		/*
9845 		* Unshadow.
9846 		*/
9847 		XML_NSMAP_FOREACH(nsMap, mi) {
9848 		    if (mi->shadowDepth >= depth)
9849 			mi->shadowDepth = -1;
9850 		}
9851 	    }
9852 	    depth--;
9853 	}
9854 	if (cur->next != NULL) {
9855 	    prevClone = clone;
9856 	    cur = cur->next;
9857 	} else if (cur->type != XML_ATTRIBUTE_NODE) {
9858 	    /*
9859 	    * Set clone->last.
9860 	    */
9861 	    if (clone->parent != NULL)
9862 		clone->parent->last = clone;
9863 	    clone = clone->parent;
9864 	    if (clone != NULL)
9865 		parentClone = clone->parent;
9866 	    /*
9867 	    * Process parent --> next;
9868 	    */
9869 	    cur = cur->parent;
9870 	    goto leave_node;
9871 	} else {
9872 	    /* This is for attributes only. */
9873 	    clone = clone->parent;
9874 	    parentClone = clone->parent;
9875 	    /*
9876 	    * Process parent-element --> children.
9877 	    */
9878 	    cur = cur->parent;
9879 	    goto into_content;
9880 	}
9881     }
9882     goto exit;
9883 
9884 internal_error:
9885     ret = -1;
9886 
9887 exit:
9888     /*
9889     * Cleanup.
9890     */
9891     if (nsMap != NULL) {
9892 	if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9893 	    /*
9894 	    * Just cleanup the map but don't free.
9895 	    */
9896 	    if (nsMap->first) {
9897 		if (nsMap->pool)
9898 		    nsMap->last->next = nsMap->pool;
9899 		nsMap->pool = nsMap->first;
9900 		nsMap->first = NULL;
9901 	    }
9902 	} else
9903 	    xmlDOMWrapNsMapFree(nsMap);
9904     }
9905     /*
9906     * TODO: Should we try a cleanup of the cloned node in case of a
9907     * fatal error?
9908     */
9909     *resNode = resultClone;
9910     return (ret);
9911 }
9912 
9913 /*
9914 * xmlDOMWrapAdoptAttr:
9915 * @ctxt: the optional context for custom processing
9916 * @sourceDoc: the optional source document of attr
9917 * @attr: the attribute-node to be adopted
9918 * @destDoc: the destination doc for adoption
9919 * @destParent: the optional new parent of @attr in @destDoc
9920 * @options: option flags
9921 *
9922 * @attr is adopted by @destDoc.
9923 * Ensures that ns-references point to @destDoc: either to
9924 * elements->nsDef entries if @destParent is given, or to
9925 * @destDoc->oldNs otherwise.
9926 *
9927 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9928 */
9929 static int
xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr sourceDoc,xmlAttrPtr attr,xmlDocPtr destDoc,xmlNodePtr destParent,int options ATTRIBUTE_UNUSED)9930 xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9931 		    xmlDocPtr sourceDoc,
9932 		    xmlAttrPtr attr,
9933 		    xmlDocPtr destDoc,
9934 		    xmlNodePtr destParent,
9935 		    int options ATTRIBUTE_UNUSED)
9936 {
9937     xmlNodePtr cur;
9938     int adoptStr = 1;
9939 
9940     if ((attr == NULL) || (destDoc == NULL))
9941 	return (-1);
9942 
9943     attr->doc = destDoc;
9944     if (attr->ns != NULL) {
9945 	xmlNsPtr ns = NULL;
9946 
9947 	if (ctxt != NULL) {
9948 	    /* TODO: User defined. */
9949 	}
9950 	/* XML Namespace. */
9951 	if (IS_STR_XML(attr->ns->prefix)) {
9952 	    ns = xmlTreeEnsureXMLDecl(destDoc);
9953 	} else if (destParent == NULL) {
9954 	    /*
9955 	    * Store in @destDoc->oldNs.
9956 	    */
9957 	    ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9958 	} else {
9959 	    /*
9960 	    * Declare on @destParent.
9961 	    */
9962 	    if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
9963 		&ns, 1) == -1)
9964 		goto internal_error;
9965 	    if (ns == NULL) {
9966 		ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9967 		    attr->ns->href, attr->ns->prefix, 1);
9968 	    }
9969 	}
9970 	if (ns == NULL)
9971 	    goto internal_error;
9972 	attr->ns = ns;
9973     }
9974 
9975     XML_TREE_ADOPT_STR(attr->name);
9976     attr->atype = 0;
9977     attr->psvi = NULL;
9978     /*
9979     * Walk content.
9980     */
9981     if (attr->children == NULL)
9982 	return (0);
9983     cur = attr->children;
9984     if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9985         goto internal_error;
9986     while (cur != NULL) {
9987 	cur->doc = destDoc;
9988 	switch (cur->type) {
9989 	    case XML_TEXT_NODE:
9990 	    case XML_CDATA_SECTION_NODE:
9991 		XML_TREE_ADOPT_STR_2(cur->content)
9992 		break;
9993 	    case XML_ENTITY_REF_NODE:
9994 		/*
9995 		* Remove reference to the entity-node.
9996 		*/
9997 		cur->content = NULL;
9998 		cur->children = NULL;
9999 		cur->last = NULL;
10000 		if ((destDoc->intSubset) || (destDoc->extSubset)) {
10001 		    xmlEntityPtr ent;
10002 		    /*
10003 		    * Assign new entity-node if available.
10004 		    */
10005 		    ent = xmlGetDocEntity(destDoc, cur->name);
10006 		    if (ent != NULL) {
10007 			cur->content = ent->content;
10008 			cur->children = (xmlNodePtr) ent;
10009 			cur->last = (xmlNodePtr) ent;
10010 		    }
10011 		}
10012 		break;
10013 	    default:
10014 		break;
10015 	}
10016 	if (cur->children != NULL) {
10017 	    cur = cur->children;
10018 	    continue;
10019 	}
10020 next_sibling:
10021 	if (cur == (xmlNodePtr) attr)
10022 	    break;
10023 	if (cur->next != NULL)
10024 	    cur = cur->next;
10025 	else {
10026 	    cur = cur->parent;
10027 	    goto next_sibling;
10028 	}
10029     }
10030     return (0);
10031 internal_error:
10032     return (-1);
10033 }
10034 
10035 /*
10036 * xmlDOMWrapAdoptNode:
10037 * @ctxt: the optional context for custom processing
10038 * @sourceDoc: the optional sourceDoc
10039 * @node: the node to start with
10040 * @destDoc: the destination doc
10041 * @destParent: the optional new parent of @node in @destDoc
10042 * @options: option flags
10043 *
10044 * References of out-of scope ns-decls are remapped to point to @destDoc:
10045 * 1) If @destParent is given, then nsDef entries on element-nodes are used
10046 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
10047 *    This is the case when you have an unlinked node and just want to move it
10048 *    to the context of
10049 *
10050 * If @destParent is given, it ensures that the tree is namespace
10051 * wellformed by creating additional ns-decls where needed.
10052 * Note that, since prefixes of already existent ns-decls can be
10053 * shadowed by this process, it could break QNames in attribute
10054 * values or element content.
10055 * NOTE: This function was not intensively tested.
10056 *
10057 * Returns 0 if the operation succeeded,
10058 *         1 if a node of unsupported type was given,
10059 *         2 if a node of not yet supported type was given and
10060 *         -1 on API/internal errors.
10061 */
10062 int
xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr sourceDoc,xmlNodePtr node,xmlDocPtr destDoc,xmlNodePtr destParent,int options)10063 xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
10064 		    xmlDocPtr sourceDoc,
10065 		    xmlNodePtr node,
10066 		    xmlDocPtr destDoc,
10067 		    xmlNodePtr destParent,
10068 		    int options)
10069 {
10070     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
10071         (destDoc == NULL) ||
10072 	((destParent != NULL) && (destParent->doc != destDoc)))
10073 	return(-1);
10074     /*
10075     * Check node->doc sanity.
10076     */
10077     if ((node->doc != NULL) && (sourceDoc != NULL) &&
10078 	(node->doc != sourceDoc)) {
10079 	/*
10080 	* Might be an XIncluded node.
10081 	*/
10082 	return (-1);
10083     }
10084     if (sourceDoc == NULL)
10085 	sourceDoc = node->doc;
10086     if (sourceDoc == destDoc)
10087 	return (-1);
10088     switch (node->type) {
10089 	case XML_ELEMENT_NODE:
10090 	case XML_ATTRIBUTE_NODE:
10091 	case XML_TEXT_NODE:
10092 	case XML_CDATA_SECTION_NODE:
10093 	case XML_ENTITY_REF_NODE:
10094 	case XML_PI_NODE:
10095 	case XML_COMMENT_NODE:
10096 	    break;
10097 	case XML_DOCUMENT_FRAG_NODE:
10098 	    /* TODO: Support document-fragment-nodes. */
10099 	    return (2);
10100 	default:
10101 	    return (1);
10102     }
10103     /*
10104     * Unlink only if @node was not already added to @destParent.
10105     */
10106     if ((node->parent != NULL) && (destParent != node->parent))
10107 	xmlUnlinkNode(node);
10108 
10109     if (node->type == XML_ELEMENT_NODE) {
10110 	    return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
10111 		    destDoc, destParent, options));
10112     } else if (node->type == XML_ATTRIBUTE_NODE) {
10113 	    return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
10114 		(xmlAttrPtr) node, destDoc, destParent, options));
10115     } else {
10116 	xmlNodePtr cur = node;
10117 	int adoptStr = 1;
10118 
10119 	cur->doc = destDoc;
10120 	/*
10121 	* Optimize string adoption.
10122 	*/
10123 	if ((sourceDoc != NULL) &&
10124 	    (sourceDoc->dict == destDoc->dict))
10125 		adoptStr = 0;
10126 	switch (node->type) {
10127 	    case XML_TEXT_NODE:
10128 	    case XML_CDATA_SECTION_NODE:
10129 		XML_TREE_ADOPT_STR_2(node->content)
10130 		    break;
10131 	    case XML_ENTITY_REF_NODE:
10132 		/*
10133 		* Remove reference to the entity-node.
10134 		*/
10135 		node->content = NULL;
10136 		node->children = NULL;
10137 		node->last = NULL;
10138 		if ((destDoc->intSubset) || (destDoc->extSubset)) {
10139 		    xmlEntityPtr ent;
10140 		    /*
10141 		    * Assign new entity-node if available.
10142 		    */
10143 		    ent = xmlGetDocEntity(destDoc, node->name);
10144 		    if (ent != NULL) {
10145 			node->content = ent->content;
10146 			node->children = (xmlNodePtr) ent;
10147 			node->last = (xmlNodePtr) ent;
10148 		    }
10149 		}
10150 		XML_TREE_ADOPT_STR(node->name)
10151 		break;
10152 	    case XML_PI_NODE: {
10153 		XML_TREE_ADOPT_STR(node->name)
10154 		XML_TREE_ADOPT_STR_2(node->content)
10155 		break;
10156 	    }
10157 	    default:
10158 		break;
10159 	}
10160     }
10161     return (0);
10162 }
10163 
10164 #define bottom_tree
10165 #include "elfgcchack.h"
10166