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