• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * tree.c : implementation of access function for an XML tree.
3  *
4  * References:
5  *   XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
6  *
7  * See Copyright for the status of this software.
8  *
9  * daniel@veillard.com
10  *
11  */
12 
13 /* To avoid EBCDIC trouble when parsing on zOS */
14 #if defined(__MVS__)
15 #pragma convert("ISO8859-1")
16 #endif
17 
18 #define IN_LIBXML
19 #include "libxml.h"
20 
21 #include <string.h> /* for memset() only ! */
22 #include <stddef.h>
23 #include <limits.h>
24 #ifdef HAVE_CTYPE_H
25 #include <ctype.h>
26 #endif
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30 #ifdef LIBXML_ZLIB_ENABLED
31 #include <zlib.h>
32 #endif
33 
34 #include <libxml/xmlmemory.h>
35 #include <libxml/tree.h>
36 #include <libxml/parser.h>
37 #include <libxml/uri.h>
38 #include <libxml/entities.h>
39 #include <libxml/valid.h>
40 #include <libxml/xmlerror.h>
41 #include <libxml/parserInternals.h>
42 #include <libxml/globals.h>
43 #ifdef LIBXML_HTML_ENABLED
44 #include <libxml/HTMLtree.h>
45 #endif
46 #ifdef LIBXML_DEBUG_ENABLED
47 #include <libxml/debugXML.h>
48 #endif
49 
50 #include "buf.h"
51 #include "save.h"
52 
53 int __xmlRegisterCallbacks = 0;
54 
55 /************************************************************************
56  *									*
57  *		Forward declarations					*
58  *									*
59  ************************************************************************/
60 
61 static xmlNsPtr
62 xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
63 
64 static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
65 
66 /************************************************************************
67  *									*
68  *		Tree memory error handler				*
69  *									*
70  ************************************************************************/
71 /**
72  * xmlTreeErrMemory:
73  * @extra:  extra 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 parameter entity hash table and
185  * return the corresponding entity, if found.
186  *
187  * Returns A pointer to the entity structure or NULL if not found.
188  */
189 static xmlEntityPtr
xmlGetParameterEntityFromDtd(const xmlDtd * dtd,const xmlChar * name)190 xmlGetParameterEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
191     xmlEntitiesTablePtr table;
192 
193     if ((dtd != NULL) && (dtd->pentities != NULL)) {
194 	table = (xmlEntitiesTablePtr) dtd->pentities;
195 	return((xmlEntityPtr) xmlHashLookup(table, name));
196 	/* return(xmlGetEntityFromTable(table, name)); */
197     }
198     return(NULL);
199 }
200 #endif /* LIBXML_TREE_ENABLED */
201 
202 /************************************************************************
203  *									*
204  *			QName handling helper				*
205  *									*
206  ************************************************************************/
207 
208 /**
209  * xmlBuildQName:
210  * @ncname:  the Name
211  * @prefix:  the prefix
212  * @memory:  preallocated memory
213  * @len:  preallocated memory length
214  *
215  * Builds the QName @prefix:@ncname in @memory if there is enough space
216  * and prefix is not NULL nor empty, otherwise allocate a new string.
217  * If prefix is NULL or empty it returns ncname.
218  *
219  * Returns the new string which must be freed by the caller if different from
220  *         @memory and @ncname or NULL in case of error
221  */
222 xmlChar *
xmlBuildQName(const xmlChar * ncname,const xmlChar * prefix,xmlChar * memory,int len)223 xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
224 	      xmlChar *memory, int len) {
225     int lenn, lenp;
226     xmlChar *ret;
227 
228     if (ncname == NULL) return(NULL);
229     if (prefix == NULL) return((xmlChar *) ncname);
230 
231     lenn = strlen((char *) ncname);
232     lenp = strlen((char *) prefix);
233 
234     if ((memory == NULL) || (len < lenn + lenp + 2)) {
235 	ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
236 	if (ret == NULL) {
237 	    xmlTreeErrMemory("building QName");
238 	    return(NULL);
239 	}
240     } else {
241 	ret = memory;
242     }
243     memcpy(&ret[0], prefix, lenp);
244     ret[lenp] = ':';
245     memcpy(&ret[lenp + 1], ncname, lenn);
246     ret[lenn + lenp + 1] = 0;
247     return(ret);
248 }
249 
250 /**
251  * xmlSplitQName2:
252  * @name:  the full QName
253  * @prefix:  a xmlChar **
254  *
255  * parse an XML qualified name string
256  *
257  * [NS 5] QName ::= (Prefix ':')? LocalPart
258  *
259  * [NS 6] Prefix ::= NCName
260  *
261  * [NS 7] LocalPart ::= NCName
262  *
263  * Returns NULL if the name doesn't have a prefix. Otherwise, returns the
264  * local part, and prefix is updated to get the Prefix. Both the return value
265  * and the prefix must be freed by the caller.
266  */
267 xmlChar *
xmlSplitQName2(const xmlChar * name,xmlChar ** prefix)268 xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
269     int len = 0;
270     xmlChar *ret = NULL;
271 
272     if (prefix == NULL) return(NULL);
273     *prefix = NULL;
274     if (name == NULL) return(NULL);
275 
276 #ifndef XML_XML_NAMESPACE
277     /* xml: prefix is not really a namespace */
278     if ((name[0] == 'x') && (name[1] == 'm') &&
279         (name[2] == 'l') && (name[3] == ':'))
280 	return(NULL);
281 #endif
282 
283     /* nasty but valid */
284     if (name[0] == ':')
285 	return(NULL);
286 
287     /*
288      * we are not trying to validate but just to cut, and yes it will
289      * work even if this is as set of UTF-8 encoded chars
290      */
291     while ((name[len] != 0) && (name[len] != ':'))
292 	len++;
293 
294     if (name[len] == 0)
295 	return(NULL);
296 
297     *prefix = xmlStrndup(name, len);
298     if (*prefix == NULL) {
299 	xmlTreeErrMemory("QName split");
300 	return(NULL);
301     }
302     ret = xmlStrdup(&name[len + 1]);
303     if (ret == NULL) {
304 	xmlTreeErrMemory("QName split");
305 	if (*prefix != NULL) {
306 	    xmlFree(*prefix);
307 	    *prefix = NULL;
308 	}
309 	return(NULL);
310     }
311 
312     return(ret);
313 }
314 
315 /**
316  * xmlSplitQName3:
317  * @name:  the full QName
318  * @len: an int *
319  *
320  * parse an XML qualified name string,i
321  *
322  * returns NULL if it is not a Qualified Name, otherwise, update len
323  *         with the length in byte of the prefix and return a pointer
324  *         to the start of the name without the prefix
325  */
326 
327 const xmlChar *
xmlSplitQName3(const xmlChar * name,int * len)328 xmlSplitQName3(const xmlChar *name, int *len) {
329     int l = 0;
330 
331     if (name == NULL) return(NULL);
332     if (len == NULL) return(NULL);
333 
334     /* nasty but valid */
335     if (name[0] == ':')
336 	return(NULL);
337 
338     /*
339      * we are not trying to validate but just to cut, and yes it will
340      * work even if this is as set of UTF-8 encoded chars
341      */
342     while ((name[l] != 0) && (name[l] != ':'))
343 	l++;
344 
345     if (name[l] == 0)
346 	return(NULL);
347 
348     *len = l;
349 
350     return(&name[l+1]);
351 }
352 
353 /************************************************************************
354  *									*
355  *		Check Name, NCName and QName strings			*
356  *									*
357  ************************************************************************/
358 
359 #define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
360 
361 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
362 /**
363  * xmlValidateNCName:
364  * @value: the value to check
365  * @space: allow spaces in front and end of the string
366  *
367  * Check that a value conforms to the lexical space of NCName
368  *
369  * Returns 0 if this validates, a positive error code number otherwise
370  *         and -1 in case of internal or API error.
371  */
372 int
xmlValidateNCName(const xmlChar * value,int space)373 xmlValidateNCName(const xmlChar *value, int space) {
374     const xmlChar *cur = value;
375     int c,l;
376 
377     if (value == NULL)
378         return(-1);
379 
380     /*
381      * First quick algorithm for ASCII range
382      */
383     if (space)
384 	while (IS_BLANK_CH(*cur)) cur++;
385     if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
386 	(*cur == '_'))
387 	cur++;
388     else
389 	goto try_complex;
390     while (((*cur >= 'a') && (*cur <= 'z')) ||
391 	   ((*cur >= 'A') && (*cur <= 'Z')) ||
392 	   ((*cur >= '0') && (*cur <= '9')) ||
393 	   (*cur == '_') || (*cur == '-') || (*cur == '.'))
394 	cur++;
395     if (space)
396 	while (IS_BLANK_CH(*cur)) cur++;
397     if (*cur == 0)
398 	return(0);
399 
400 try_complex:
401     /*
402      * Second check for chars outside the ASCII range
403      */
404     cur = value;
405     c = CUR_SCHAR(cur, l);
406     if (space) {
407 	while (IS_BLANK(c)) {
408 	    cur += l;
409 	    c = CUR_SCHAR(cur, l);
410 	}
411     }
412     if ((!IS_LETTER(c)) && (c != '_'))
413 	return(1);
414     cur += l;
415     c = CUR_SCHAR(cur, l);
416     while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
417 	   (c == '-') || (c == '_') || IS_COMBINING(c) ||
418 	   IS_EXTENDER(c)) {
419 	cur += l;
420 	c = CUR_SCHAR(cur, l);
421     }
422     if (space) {
423 	while (IS_BLANK(c)) {
424 	    cur += l;
425 	    c = CUR_SCHAR(cur, l);
426 	}
427     }
428     if (c != 0)
429 	return(1);
430 
431     return(0);
432 }
433 #endif
434 
435 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
436 /**
437  * xmlValidateQName:
438  * @value: the value to check
439  * @space: allow spaces in front and end of the string
440  *
441  * Check that a value conforms to the lexical space of QName
442  *
443  * Returns 0 if this validates, a positive error code number otherwise
444  *         and -1 in case of internal or API error.
445  */
446 int
xmlValidateQName(const xmlChar * value,int space)447 xmlValidateQName(const xmlChar *value, int space) {
448     const xmlChar *cur = value;
449     int c,l;
450 
451     if (value == NULL)
452         return(-1);
453     /*
454      * First quick algorithm for ASCII range
455      */
456     if (space)
457 	while (IS_BLANK_CH(*cur)) cur++;
458     if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
459 	(*cur == '_'))
460 	cur++;
461     else
462 	goto try_complex;
463     while (((*cur >= 'a') && (*cur <= 'z')) ||
464 	   ((*cur >= 'A') && (*cur <= 'Z')) ||
465 	   ((*cur >= '0') && (*cur <= '9')) ||
466 	   (*cur == '_') || (*cur == '-') || (*cur == '.'))
467 	cur++;
468     if (*cur == ':') {
469 	cur++;
470 	if (((*cur >= 'a') && (*cur <= 'z')) ||
471 	    ((*cur >= 'A') && (*cur <= 'Z')) ||
472 	    (*cur == '_'))
473 	    cur++;
474 	else
475 	    goto try_complex;
476 	while (((*cur >= 'a') && (*cur <= 'z')) ||
477 	       ((*cur >= 'A') && (*cur <= 'Z')) ||
478 	       ((*cur >= '0') && (*cur <= '9')) ||
479 	       (*cur == '_') || (*cur == '-') || (*cur == '.'))
480 	    cur++;
481     }
482     if (space)
483 	while (IS_BLANK_CH(*cur)) cur++;
484     if (*cur == 0)
485 	return(0);
486 
487 try_complex:
488     /*
489      * Second check for chars outside the ASCII range
490      */
491     cur = value;
492     c = CUR_SCHAR(cur, l);
493     if (space) {
494 	while (IS_BLANK(c)) {
495 	    cur += l;
496 	    c = CUR_SCHAR(cur, l);
497 	}
498     }
499     if ((!IS_LETTER(c)) && (c != '_'))
500 	return(1);
501     cur += l;
502     c = CUR_SCHAR(cur, l);
503     while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
504 	   (c == '-') || (c == '_') || IS_COMBINING(c) ||
505 	   IS_EXTENDER(c)) {
506 	cur += l;
507 	c = CUR_SCHAR(cur, l);
508     }
509     if (c == ':') {
510 	cur += l;
511 	c = CUR_SCHAR(cur, l);
512 	if ((!IS_LETTER(c)) && (c != '_'))
513 	    return(1);
514 	cur += l;
515 	c = CUR_SCHAR(cur, l);
516 	while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
517 	       (c == '-') || (c == '_') || IS_COMBINING(c) ||
518 	       IS_EXTENDER(c)) {
519 	    cur += l;
520 	    c = CUR_SCHAR(cur, l);
521 	}
522     }
523     if (space) {
524 	while (IS_BLANK(c)) {
525 	    cur += l;
526 	    c = CUR_SCHAR(cur, l);
527 	}
528     }
529     if (c != 0)
530 	return(1);
531     return(0);
532 }
533 
534 /**
535  * xmlValidateName:
536  * @value: the value to check
537  * @space: allow spaces in front and end of the string
538  *
539  * Check that a value conforms to the lexical space of Name
540  *
541  * Returns 0 if this validates, a positive error code number otherwise
542  *         and -1 in case of internal or API error.
543  */
544 int
xmlValidateName(const xmlChar * value,int space)545 xmlValidateName(const xmlChar *value, int space) {
546     const xmlChar *cur = value;
547     int c,l;
548 
549     if (value == NULL)
550         return(-1);
551     /*
552      * First quick algorithm for ASCII range
553      */
554     if (space)
555 	while (IS_BLANK_CH(*cur)) cur++;
556     if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
557 	(*cur == '_') || (*cur == ':'))
558 	cur++;
559     else
560 	goto try_complex;
561     while (((*cur >= 'a') && (*cur <= 'z')) ||
562 	   ((*cur >= 'A') && (*cur <= 'Z')) ||
563 	   ((*cur >= '0') && (*cur <= '9')) ||
564 	   (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
565 	cur++;
566     if (space)
567 	while (IS_BLANK_CH(*cur)) cur++;
568     if (*cur == 0)
569 	return(0);
570 
571 try_complex:
572     /*
573      * Second check for chars outside the ASCII range
574      */
575     cur = value;
576     c = CUR_SCHAR(cur, l);
577     if (space) {
578 	while (IS_BLANK(c)) {
579 	    cur += l;
580 	    c = CUR_SCHAR(cur, l);
581 	}
582     }
583     if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
584 	return(1);
585     cur += l;
586     c = CUR_SCHAR(cur, l);
587     while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
588 	   (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
589 	cur += l;
590 	c = CUR_SCHAR(cur, l);
591     }
592     if (space) {
593 	while (IS_BLANK(c)) {
594 	    cur += l;
595 	    c = CUR_SCHAR(cur, l);
596 	}
597     }
598     if (c != 0)
599 	return(1);
600     return(0);
601 }
602 
603 /**
604  * xmlValidateNMToken:
605  * @value: the value to check
606  * @space: allow spaces in front and end of the string
607  *
608  * Check that a value conforms to the lexical space of NMToken
609  *
610  * Returns 0 if this validates, a positive error code number otherwise
611  *         and -1 in case of internal or API error.
612  */
613 int
xmlValidateNMToken(const xmlChar * value,int space)614 xmlValidateNMToken(const xmlChar *value, int space) {
615     const xmlChar *cur = value;
616     int c,l;
617 
618     if (value == NULL)
619         return(-1);
620     /*
621      * First quick algorithm for ASCII range
622      */
623     if (space)
624 	while (IS_BLANK_CH(*cur)) cur++;
625     if (((*cur >= 'a') && (*cur <= 'z')) ||
626         ((*cur >= 'A') && (*cur <= 'Z')) ||
627         ((*cur >= '0') && (*cur <= '9')) ||
628         (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
629 	cur++;
630     else
631 	goto try_complex;
632     while (((*cur >= 'a') && (*cur <= 'z')) ||
633 	   ((*cur >= 'A') && (*cur <= 'Z')) ||
634 	   ((*cur >= '0') && (*cur <= '9')) ||
635 	   (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
636 	cur++;
637     if (space)
638 	while (IS_BLANK_CH(*cur)) cur++;
639     if (*cur == 0)
640 	return(0);
641 
642 try_complex:
643     /*
644      * Second check for chars outside the ASCII range
645      */
646     cur = value;
647     c = CUR_SCHAR(cur, l);
648     if (space) {
649 	while (IS_BLANK(c)) {
650 	    cur += l;
651 	    c = CUR_SCHAR(cur, l);
652 	}
653     }
654     if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
655         (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
656 	return(1);
657     cur += l;
658     c = CUR_SCHAR(cur, l);
659     while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
660 	   (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
661 	cur += l;
662 	c = CUR_SCHAR(cur, l);
663     }
664     if (space) {
665 	while (IS_BLANK(c)) {
666 	    cur += l;
667 	    c = CUR_SCHAR(cur, l);
668 	}
669     }
670     if (c != 0)
671 	return(1);
672     return(0);
673 }
674 #endif /* LIBXML_TREE_ENABLED */
675 
676 /************************************************************************
677  *									*
678  *		Allocation and deallocation of basic structures		*
679  *									*
680  ************************************************************************/
681 
682 /**
683  * xmlSetBufferAllocationScheme:
684  * @scheme:  allocation method to use
685  *
686  * Set the buffer allocation method.  Types are
687  * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
688  * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
689  *                             improves performance
690  */
691 void
xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme)692 xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
693     if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
694         (scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
695         (scheme == XML_BUFFER_ALLOC_HYBRID))
696 	xmlBufferAllocScheme = scheme;
697 }
698 
699 /**
700  * xmlGetBufferAllocationScheme:
701  *
702  * Types are
703  * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
704  * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
705  *                             improves performance
706  * XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight
707  *                            in normal usage, and doubleit on large strings to avoid
708  *                            pathological performance.
709  *
710  * Returns the current allocation scheme
711  */
712 xmlBufferAllocationScheme
xmlGetBufferAllocationScheme(void)713 xmlGetBufferAllocationScheme(void) {
714     return(xmlBufferAllocScheme);
715 }
716 
717 /**
718  * xmlNewNs:
719  * @node:  the element carrying the namespace
720  * @href:  the URI associated
721  * @prefix:  the prefix for the namespace
722  *
723  * Creation of a new Namespace. This function will refuse to create
724  * a namespace with a similar prefix than an existing one present on this
725  * node.
726  * Note that for a default namespace, @prefix should be NULL.
727  *
728  * We use href==NULL in the case of an element creation where the namespace
729  * was not defined.
730  *
731  * Returns a new namespace pointer or NULL
732  */
733 xmlNsPtr
xmlNewNs(xmlNodePtr node,const xmlChar * href,const xmlChar * prefix)734 xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
735     xmlNsPtr cur;
736 
737     if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
738 	return(NULL);
739 
740     if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
741         /* xml namespace is predefined, no need to add it */
742         if (xmlStrEqual(href, XML_XML_NAMESPACE))
743             return(NULL);
744 
745         /*
746          * Problem, this is an attempt to bind xml prefix to a wrong
747          * namespace, which breaks
748          * Namespace constraint: Reserved Prefixes and Namespace Names
749          * from XML namespace. But documents authors may not care in
750          * their context so let's proceed.
751          */
752     }
753 
754     /*
755      * Allocate a new Namespace and fill the fields.
756      */
757     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
758     if (cur == NULL) {
759 	xmlTreeErrMemory("building namespace");
760 	return(NULL);
761     }
762     memset(cur, 0, sizeof(xmlNs));
763     cur->type = XML_LOCAL_NAMESPACE;
764 
765     if (href != NULL)
766 	cur->href = xmlStrdup(href);
767     if (prefix != NULL)
768 	cur->prefix = xmlStrdup(prefix);
769 
770     /*
771      * Add it at the end to preserve parsing order ...
772      * and checks for existing use of the prefix
773      */
774     if (node != NULL) {
775 	if (node->nsDef == NULL) {
776 	    node->nsDef = cur;
777 	} else {
778 	    xmlNsPtr prev = node->nsDef;
779 
780 	    if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
781 		(xmlStrEqual(prev->prefix, cur->prefix))) {
782 		xmlFreeNs(cur);
783 		return(NULL);
784 	    }
785 	    while (prev->next != NULL) {
786 	        prev = prev->next;
787 		if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
788 		    (xmlStrEqual(prev->prefix, cur->prefix))) {
789 		    xmlFreeNs(cur);
790 		    return(NULL);
791 		}
792 	    }
793 	    prev->next = cur;
794 	}
795     }
796     return(cur);
797 }
798 
799 /**
800  * xmlSetNs:
801  * @node:  a node in the document
802  * @ns:  a namespace pointer
803  *
804  * Associate a namespace to a node, a posteriori.
805  */
806 void
xmlSetNs(xmlNodePtr node,xmlNsPtr ns)807 xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
808     if (node == NULL) {
809 #ifdef DEBUG_TREE
810         xmlGenericError(xmlGenericErrorContext,
811 		"xmlSetNs: node == NULL\n");
812 #endif
813 	return;
814     }
815     if ((node->type == XML_ELEMENT_NODE) ||
816         (node->type == XML_ATTRIBUTE_NODE))
817 	node->ns = ns;
818 }
819 
820 /**
821  * xmlFreeNs:
822  * @cur:  the namespace pointer
823  *
824  * Free up the structures associated to a namespace
825  */
826 void
xmlFreeNs(xmlNsPtr cur)827 xmlFreeNs(xmlNsPtr cur) {
828     if (cur == NULL) {
829 #ifdef DEBUG_TREE
830         xmlGenericError(xmlGenericErrorContext,
831 		"xmlFreeNs : ns == NULL\n");
832 #endif
833 	return;
834     }
835     if (cur->href != NULL) xmlFree((char *) cur->href);
836     if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
837     xmlFree(cur);
838 }
839 
840 /**
841  * xmlFreeNsList:
842  * @cur:  the first namespace pointer
843  *
844  * Free up all the structures associated to the chained namespaces.
845  */
846 void
xmlFreeNsList(xmlNsPtr cur)847 xmlFreeNsList(xmlNsPtr cur) {
848     xmlNsPtr next;
849     if (cur == NULL) {
850 #ifdef DEBUG_TREE
851         xmlGenericError(xmlGenericErrorContext,
852 		"xmlFreeNsList : ns == NULL\n");
853 #endif
854 	return;
855     }
856     while (cur != NULL) {
857         next = cur->next;
858         xmlFreeNs(cur);
859 	cur = next;
860     }
861 }
862 
863 /**
864  * xmlNewDtd:
865  * @doc:  the document pointer
866  * @name:  the DTD name
867  * @ExternalID:  the external ID
868  * @SystemID:  the system ID
869  *
870  * Creation of a new DTD for the external subset. To create an
871  * internal subset, use xmlCreateIntSubset().
872  *
873  * Returns a pointer to the new DTD structure
874  */
875 xmlDtdPtr
xmlNewDtd(xmlDocPtr doc,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)876 xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
877                     const xmlChar *ExternalID, const xmlChar *SystemID) {
878     xmlDtdPtr cur;
879 
880     if ((doc != NULL) && (doc->extSubset != NULL)) {
881 #ifdef DEBUG_TREE
882         xmlGenericError(xmlGenericErrorContext,
883 		"xmlNewDtd(%s): document %s already have a DTD %s\n",
884 	    /* !!! */ (char *) name, doc->name,
885 	    /* !!! */ (char *)doc->extSubset->name);
886 #endif
887 	return(NULL);
888     }
889 
890     /*
891      * Allocate a new DTD and fill the fields.
892      */
893     cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
894     if (cur == NULL) {
895 	xmlTreeErrMemory("building DTD");
896 	return(NULL);
897     }
898     memset(cur, 0 , sizeof(xmlDtd));
899     cur->type = XML_DTD_NODE;
900 
901     if (name != NULL)
902 	cur->name = xmlStrdup(name);
903     if (ExternalID != NULL)
904 	cur->ExternalID = xmlStrdup(ExternalID);
905     if (SystemID != NULL)
906 	cur->SystemID = xmlStrdup(SystemID);
907     if (doc != NULL)
908 	doc->extSubset = cur;
909     cur->doc = doc;
910 
911     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
912 	xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
913     return(cur);
914 }
915 
916 /**
917  * xmlGetIntSubset:
918  * @doc:  the document pointer
919  *
920  * Get the internal subset of a document
921  * Returns a pointer to the DTD structure or NULL if not found
922  */
923 
924 xmlDtdPtr
xmlGetIntSubset(const xmlDoc * doc)925 xmlGetIntSubset(const xmlDoc *doc) {
926     xmlNodePtr cur;
927 
928     if (doc == NULL)
929 	return(NULL);
930     cur = doc->children;
931     while (cur != NULL) {
932 	if (cur->type == XML_DTD_NODE)
933 	    return((xmlDtdPtr) cur);
934 	cur = cur->next;
935     }
936     return((xmlDtdPtr) doc->intSubset);
937 }
938 
939 /**
940  * xmlCreateIntSubset:
941  * @doc:  the document pointer
942  * @name:  the DTD name
943  * @ExternalID:  the external (PUBLIC) ID
944  * @SystemID:  the system ID
945  *
946  * Create the internal subset of a document
947  * Returns a pointer to the new DTD structure
948  */
949 xmlDtdPtr
xmlCreateIntSubset(xmlDocPtr doc,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)950 xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
951                    const xmlChar *ExternalID, const xmlChar *SystemID) {
952     xmlDtdPtr cur;
953 
954     if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
955 #ifdef DEBUG_TREE
956         xmlGenericError(xmlGenericErrorContext,
957 
958      "xmlCreateIntSubset(): document %s already have an internal subset\n",
959 	    doc->name);
960 #endif
961 	return(NULL);
962     }
963 
964     /*
965      * Allocate a new DTD and fill the fields.
966      */
967     cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
968     if (cur == NULL) {
969 	xmlTreeErrMemory("building internal subset");
970 	return(NULL);
971     }
972     memset(cur, 0, sizeof(xmlDtd));
973     cur->type = XML_DTD_NODE;
974 
975     if (name != NULL) {
976 	cur->name = xmlStrdup(name);
977 	if (cur->name == NULL) {
978 	    xmlTreeErrMemory("building internal subset");
979 	    xmlFree(cur);
980 	    return(NULL);
981 	}
982     }
983     if (ExternalID != NULL) {
984 	cur->ExternalID = xmlStrdup(ExternalID);
985 	if (cur->ExternalID  == NULL) {
986 	    xmlTreeErrMemory("building internal subset");
987 	    if (cur->name != NULL)
988 	        xmlFree((char *)cur->name);
989 	    xmlFree(cur);
990 	    return(NULL);
991 	}
992     }
993     if (SystemID != NULL) {
994 	cur->SystemID = xmlStrdup(SystemID);
995 	if (cur->SystemID == NULL) {
996 	    xmlTreeErrMemory("building internal subset");
997 	    if (cur->name != NULL)
998 	        xmlFree((char *)cur->name);
999 	    if (cur->ExternalID != NULL)
1000 	        xmlFree((char *)cur->ExternalID);
1001 	    xmlFree(cur);
1002 	    return(NULL);
1003 	}
1004     }
1005     if (doc != NULL) {
1006 	doc->intSubset = cur;
1007 	cur->parent = doc;
1008 	cur->doc = doc;
1009 	if (doc->children == NULL) {
1010 	    doc->children = (xmlNodePtr) cur;
1011 	    doc->last = (xmlNodePtr) cur;
1012 	} else {
1013 	    if (doc->type == XML_HTML_DOCUMENT_NODE) {
1014 		xmlNodePtr prev;
1015 
1016 		prev = doc->children;
1017 		prev->prev = (xmlNodePtr) cur;
1018 		cur->next = prev;
1019 		doc->children = (xmlNodePtr) cur;
1020 	    } else {
1021 		xmlNodePtr next;
1022 
1023 		next = doc->children;
1024 		while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
1025 		    next = next->next;
1026 		if (next == NULL) {
1027 		    cur->prev = doc->last;
1028 		    cur->prev->next = (xmlNodePtr) cur;
1029 		    cur->next = NULL;
1030 		    doc->last = (xmlNodePtr) cur;
1031 		} else {
1032 		    cur->next = next;
1033 		    cur->prev = next->prev;
1034 		    if (cur->prev == NULL)
1035 			doc->children = (xmlNodePtr) cur;
1036 		    else
1037 			cur->prev->next = (xmlNodePtr) cur;
1038 		    next->prev = (xmlNodePtr) cur;
1039 		}
1040 	    }
1041 	}
1042     }
1043 
1044     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1045 	xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
1046     return(cur);
1047 }
1048 
1049 /**
1050  * DICT_FREE:
1051  * @str:  a string
1052  *
1053  * Free a string if it is not owned by the "dict" dictionary in the
1054  * current scope
1055  */
1056 #define DICT_FREE(str)						\
1057 	if ((str) && ((!dict) ||				\
1058 	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
1059 	    xmlFree((char *)(str));
1060 
1061 
1062 /**
1063  * DICT_COPY:
1064  * @str:  a string
1065  *
1066  * Copy a string using a "dict" dictionary in the current scope,
1067  * if 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 destroyed 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     xmlNodePtr parent;
3668     xmlDictPtr dict = NULL;
3669     size_t depth = 0;
3670 
3671     if (cur == NULL) return;
3672     if (cur->type == XML_NAMESPACE_DECL) {
3673 	xmlFreeNsList((xmlNsPtr) cur);
3674 	return;
3675     }
3676     if ((cur->type == XML_DOCUMENT_NODE) ||
3677 #ifdef LIBXML_DOCB_ENABLED
3678 	(cur->type == XML_DOCB_DOCUMENT_NODE) ||
3679 #endif
3680 	(cur->type == XML_HTML_DOCUMENT_NODE)) {
3681 	xmlFreeDoc((xmlDocPtr) cur);
3682 	return;
3683     }
3684     if (cur->doc != NULL) dict = cur->doc->dict;
3685     while (1) {
3686         while ((cur->children != NULL) &&
3687                (cur->type != XML_DTD_NODE) &&
3688                (cur->type != XML_ENTITY_REF_NODE)) {
3689             cur = cur->children;
3690             depth += 1;
3691         }
3692 
3693         next = cur->next;
3694         parent = cur->parent;
3695 	if (cur->type != XML_DTD_NODE) {
3696 
3697 	    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3698 		xmlDeregisterNodeDefaultValue(cur);
3699 
3700 	    if (((cur->type == XML_ELEMENT_NODE) ||
3701 		 (cur->type == XML_XINCLUDE_START) ||
3702 		 (cur->type == XML_XINCLUDE_END)) &&
3703 		(cur->properties != NULL))
3704 		xmlFreePropList(cur->properties);
3705 	    if ((cur->type != XML_ELEMENT_NODE) &&
3706 		(cur->type != XML_XINCLUDE_START) &&
3707 		(cur->type != XML_XINCLUDE_END) &&
3708 		(cur->type != XML_ENTITY_REF_NODE) &&
3709 		(cur->content != (xmlChar *) &(cur->properties))) {
3710 		DICT_FREE(cur->content)
3711 	    }
3712 	    if (((cur->type == XML_ELEMENT_NODE) ||
3713 	         (cur->type == XML_XINCLUDE_START) ||
3714 		 (cur->type == XML_XINCLUDE_END)) &&
3715 		(cur->nsDef != NULL))
3716 		xmlFreeNsList(cur->nsDef);
3717 
3718 	    /*
3719 	     * When a node is a text node or a comment, it uses a global static
3720 	     * variable for the name of the node.
3721 	     * Otherwise the node name might come from the document's
3722 	     * dictionary
3723 	     */
3724 	    if ((cur->name != NULL) &&
3725 		(cur->type != XML_TEXT_NODE) &&
3726 		(cur->type != XML_COMMENT_NODE))
3727 		DICT_FREE(cur->name)
3728 	    xmlFree(cur);
3729 	}
3730 
3731         if (next != NULL) {
3732 	    cur = next;
3733         } else {
3734             if ((depth == 0) || (parent == NULL))
3735                 break;
3736             depth -= 1;
3737             cur = parent;
3738             cur->children = NULL;
3739         }
3740     }
3741 }
3742 
3743 /**
3744  * xmlFreeNode:
3745  * @cur:  the node
3746  *
3747  * Free a node, this is a recursive behaviour, all the children are freed too.
3748  * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3749  */
3750 void
xmlFreeNode(xmlNodePtr cur)3751 xmlFreeNode(xmlNodePtr cur) {
3752     xmlDictPtr dict = NULL;
3753 
3754     if (cur == NULL) return;
3755 
3756     /* use xmlFreeDtd for DTD nodes */
3757     if (cur->type == XML_DTD_NODE) {
3758 	xmlFreeDtd((xmlDtdPtr) cur);
3759 	return;
3760     }
3761     if (cur->type == XML_NAMESPACE_DECL) {
3762 	xmlFreeNs((xmlNsPtr) cur);
3763         return;
3764     }
3765     if (cur->type == XML_ATTRIBUTE_NODE) {
3766 	xmlFreeProp((xmlAttrPtr) cur);
3767 	return;
3768     }
3769 
3770     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3771 	xmlDeregisterNodeDefaultValue(cur);
3772 
3773     if (cur->doc != NULL) dict = cur->doc->dict;
3774 
3775     if (cur->type == XML_ENTITY_DECL) {
3776         xmlEntityPtr ent = (xmlEntityPtr) cur;
3777 	DICT_FREE(ent->SystemID);
3778 	DICT_FREE(ent->ExternalID);
3779     }
3780     if ((cur->children != NULL) &&
3781 	(cur->type != XML_ENTITY_REF_NODE))
3782 	xmlFreeNodeList(cur->children);
3783     if (((cur->type == XML_ELEMENT_NODE) ||
3784 	 (cur->type == XML_XINCLUDE_START) ||
3785 	 (cur->type == XML_XINCLUDE_END)) &&
3786 	(cur->properties != NULL))
3787 	xmlFreePropList(cur->properties);
3788     if ((cur->type != XML_ELEMENT_NODE) &&
3789 	(cur->content != NULL) &&
3790 	(cur->type != XML_ENTITY_REF_NODE) &&
3791 	(cur->type != XML_XINCLUDE_END) &&
3792 	(cur->type != XML_XINCLUDE_START) &&
3793 	(cur->content != (xmlChar *) &(cur->properties))) {
3794 	DICT_FREE(cur->content)
3795     }
3796 
3797     /*
3798      * When a node is a text node or a comment, it uses a global static
3799      * variable for the name of the node.
3800      * Otherwise the node name might come from the document's dictionary
3801      */
3802     if ((cur->name != NULL) &&
3803         (cur->type != XML_TEXT_NODE) &&
3804         (cur->type != XML_COMMENT_NODE))
3805 	DICT_FREE(cur->name)
3806 
3807     if (((cur->type == XML_ELEMENT_NODE) ||
3808 	 (cur->type == XML_XINCLUDE_START) ||
3809 	 (cur->type == XML_XINCLUDE_END)) &&
3810 	(cur->nsDef != NULL))
3811 	xmlFreeNsList(cur->nsDef);
3812     xmlFree(cur);
3813 }
3814 
3815 /**
3816  * xmlUnlinkNode:
3817  * @cur:  the node
3818  *
3819  * Unlink a node from it's current context, the node is not freed
3820  * If one need to free the node, use xmlFreeNode() routine after the
3821  * unlink to discard it.
3822  * Note that namespace nodes can't be unlinked as they do not have
3823  * pointer to their parent.
3824  */
3825 void
xmlUnlinkNode(xmlNodePtr cur)3826 xmlUnlinkNode(xmlNodePtr cur) {
3827     if (cur == NULL) {
3828 #ifdef DEBUG_TREE
3829         xmlGenericError(xmlGenericErrorContext,
3830 		"xmlUnlinkNode : node == NULL\n");
3831 #endif
3832 	return;
3833     }
3834     if (cur->type == XML_NAMESPACE_DECL)
3835         return;
3836     if (cur->type == XML_DTD_NODE) {
3837 	xmlDocPtr doc;
3838 	doc = cur->doc;
3839 	if (doc != NULL) {
3840 	    if (doc->intSubset == (xmlDtdPtr) cur)
3841 		doc->intSubset = NULL;
3842 	    if (doc->extSubset == (xmlDtdPtr) cur)
3843 		doc->extSubset = NULL;
3844 	}
3845     }
3846     if (cur->type == XML_ENTITY_DECL) {
3847         xmlDocPtr doc;
3848 	doc = cur->doc;
3849 	if (doc != NULL) {
3850 	    if (doc->intSubset != NULL) {
3851 	        if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3852 		    xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3853 		                       NULL);
3854 	        if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3855 		    xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3856 		                       NULL);
3857 	    }
3858 	    if (doc->extSubset != NULL) {
3859 	        if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3860 		    xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3861 		                       NULL);
3862 	        if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3863 		    xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3864 		                       NULL);
3865 	    }
3866 	}
3867     }
3868     if (cur->parent != NULL) {
3869 	xmlNodePtr parent;
3870 	parent = cur->parent;
3871 	if (cur->type == XML_ATTRIBUTE_NODE) {
3872 	    if (parent->properties == (xmlAttrPtr) cur)
3873 		parent->properties = ((xmlAttrPtr) cur)->next;
3874 	} else {
3875 	    if (parent->children == cur)
3876 		parent->children = cur->next;
3877 	    if (parent->last == cur)
3878 		parent->last = cur->prev;
3879 	}
3880 	cur->parent = NULL;
3881     }
3882     if (cur->next != NULL)
3883         cur->next->prev = cur->prev;
3884     if (cur->prev != NULL)
3885         cur->prev->next = cur->next;
3886     cur->next = cur->prev = NULL;
3887 }
3888 
3889 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
3890 /**
3891  * xmlReplaceNode:
3892  * @old:  the old node
3893  * @cur:  the node
3894  *
3895  * Unlink the old node from its current context, prune the new one
3896  * at the same place. If @cur was already inserted in a document it is
3897  * first unlinked from its existing context.
3898  *
3899  * Returns the @old node
3900  */
3901 xmlNodePtr
xmlReplaceNode(xmlNodePtr old,xmlNodePtr cur)3902 xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3903     if (old == cur) return(NULL);
3904     if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) ||
3905         (old->parent == NULL)) {
3906 #ifdef DEBUG_TREE
3907         xmlGenericError(xmlGenericErrorContext,
3908 		"xmlReplaceNode : old == NULL or without parent\n");
3909 #endif
3910 	return(NULL);
3911     }
3912     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3913 	xmlUnlinkNode(old);
3914 	return(old);
3915     }
3916     if (cur == old) {
3917 	return(old);
3918     }
3919     if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3920 #ifdef DEBUG_TREE
3921         xmlGenericError(xmlGenericErrorContext,
3922 		"xmlReplaceNode : Trying to replace attribute node with other node type\n");
3923 #endif
3924 	return(old);
3925     }
3926     if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3927 #ifdef DEBUG_TREE
3928         xmlGenericError(xmlGenericErrorContext,
3929 		"xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n");
3930 #endif
3931 	return(old);
3932     }
3933     xmlUnlinkNode(cur);
3934     xmlSetTreeDoc(cur, old->doc);
3935     cur->parent = old->parent;
3936     cur->next = old->next;
3937     if (cur->next != NULL)
3938 	cur->next->prev = cur;
3939     cur->prev = old->prev;
3940     if (cur->prev != NULL)
3941 	cur->prev->next = cur;
3942     if (cur->parent != NULL) {
3943 	if (cur->type == XML_ATTRIBUTE_NODE) {
3944 	    if (cur->parent->properties == (xmlAttrPtr)old)
3945 		cur->parent->properties = ((xmlAttrPtr) cur);
3946 	} else {
3947 	    if (cur->parent->children == old)
3948 		cur->parent->children = cur;
3949 	    if (cur->parent->last == old)
3950 		cur->parent->last = cur;
3951 	}
3952     }
3953     old->next = old->prev = NULL;
3954     old->parent = NULL;
3955     return(old);
3956 }
3957 #endif /* LIBXML_TREE_ENABLED */
3958 
3959 /************************************************************************
3960  *									*
3961  *		Copy operations						*
3962  *									*
3963  ************************************************************************/
3964 
3965 /**
3966  * xmlCopyNamespace:
3967  * @cur:  the namespace
3968  *
3969  * Do a copy of the namespace.
3970  *
3971  * Returns: a new #xmlNsPtr, or NULL in case of error.
3972  */
3973 xmlNsPtr
xmlCopyNamespace(xmlNsPtr cur)3974 xmlCopyNamespace(xmlNsPtr cur) {
3975     xmlNsPtr ret;
3976 
3977     if (cur == NULL) return(NULL);
3978     switch (cur->type) {
3979 	case XML_LOCAL_NAMESPACE:
3980 	    ret = xmlNewNs(NULL, cur->href, cur->prefix);
3981 	    break;
3982 	default:
3983 #ifdef DEBUG_TREE
3984 	    xmlGenericError(xmlGenericErrorContext,
3985 		    "xmlCopyNamespace: invalid type %d\n", cur->type);
3986 #endif
3987 	    return(NULL);
3988     }
3989     return(ret);
3990 }
3991 
3992 /**
3993  * xmlCopyNamespaceList:
3994  * @cur:  the first namespace
3995  *
3996  * Do a copy of an namespace list.
3997  *
3998  * Returns: a new #xmlNsPtr, or NULL in case of error.
3999  */
4000 xmlNsPtr
xmlCopyNamespaceList(xmlNsPtr cur)4001 xmlCopyNamespaceList(xmlNsPtr cur) {
4002     xmlNsPtr ret = NULL;
4003     xmlNsPtr p = NULL,q;
4004 
4005     while (cur != NULL) {
4006         q = xmlCopyNamespace(cur);
4007 	if (p == NULL) {
4008 	    ret = p = q;
4009 	} else {
4010 	    p->next = q;
4011 	    p = q;
4012 	}
4013 	cur = cur->next;
4014     }
4015     return(ret);
4016 }
4017 
4018 static xmlNodePtr
4019 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
4020 
4021 static xmlAttrPtr
xmlCopyPropInternal(xmlDocPtr doc,xmlNodePtr target,xmlAttrPtr cur)4022 xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
4023     xmlAttrPtr ret;
4024 
4025     if (cur == NULL) return(NULL);
4026     if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4027         return(NULL);
4028     if (target != NULL)
4029 	ret = xmlNewDocProp(target->doc, cur->name, NULL);
4030     else if (doc != NULL)
4031 	ret = xmlNewDocProp(doc, cur->name, NULL);
4032     else if (cur->parent != NULL)
4033 	ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
4034     else if (cur->children != NULL)
4035 	ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
4036     else
4037 	ret = xmlNewDocProp(NULL, cur->name, NULL);
4038     if (ret == NULL) return(NULL);
4039     ret->parent = target;
4040 
4041     if ((cur->ns != NULL) && (target != NULL)) {
4042       xmlNsPtr ns;
4043 
4044       ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
4045       if (ns == NULL) {
4046         /*
4047          * Humm, we are copying an element whose namespace is defined
4048          * out of the new tree scope. Search it in the original tree
4049          * and add it at the top of the new tree
4050          */
4051         ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
4052         if (ns != NULL) {
4053           xmlNodePtr root = target;
4054           xmlNodePtr pred = NULL;
4055 
4056           while (root->parent != NULL) {
4057             pred = root;
4058             root = root->parent;
4059           }
4060           if (root == (xmlNodePtr) target->doc) {
4061             /* correct possibly cycling above the document elt */
4062             root = pred;
4063           }
4064           ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4065         }
4066       } else {
4067         /*
4068          * we have to find something appropriate here since
4069          * we cant be sure, that the namespace we found is identified
4070          * by the prefix
4071          */
4072         if (xmlStrEqual(ns->href, cur->ns->href)) {
4073           /* this is the nice case */
4074           ret->ns = ns;
4075         } else {
4076           /*
4077            * we are in trouble: we need a new reconciled namespace.
4078            * This is expensive
4079            */
4080           ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns);
4081         }
4082       }
4083 
4084     } else
4085         ret->ns = NULL;
4086 
4087     if (cur->children != NULL) {
4088 	xmlNodePtr tmp;
4089 
4090 	ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4091 	ret->last = NULL;
4092 	tmp = ret->children;
4093 	while (tmp != NULL) {
4094 	    /* tmp->parent = (xmlNodePtr)ret; */
4095 	    if (tmp->next == NULL)
4096 	        ret->last = tmp;
4097 	    tmp = tmp->next;
4098 	}
4099     }
4100     /*
4101      * Try to handle IDs
4102      */
4103     if ((target!= NULL) && (cur!= NULL) &&
4104 	(target->doc != NULL) && (cur->doc != NULL) &&
4105 	(cur->doc->ids != NULL) && (cur->parent != NULL)) {
4106 	if (xmlIsID(cur->doc, cur->parent, cur)) {
4107 	    xmlChar *id;
4108 
4109 	    id = xmlNodeListGetString(cur->doc, cur->children, 1);
4110 	    if (id != NULL) {
4111 		xmlAddID(NULL, target->doc, id, ret);
4112 		xmlFree(id);
4113 	    }
4114 	}
4115     }
4116     return(ret);
4117 }
4118 
4119 /**
4120  * xmlCopyProp:
4121  * @target:  the element where the attribute will be grafted
4122  * @cur:  the attribute
4123  *
4124  * Do a copy of the attribute.
4125  *
4126  * Returns: a new #xmlAttrPtr, or NULL in case of error.
4127  */
4128 xmlAttrPtr
xmlCopyProp(xmlNodePtr target,xmlAttrPtr cur)4129 xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
4130 	return xmlCopyPropInternal(NULL, target, cur);
4131 }
4132 
4133 /**
4134  * xmlCopyPropList:
4135  * @target:  the element where the attributes will be grafted
4136  * @cur:  the first attribute
4137  *
4138  * Do a copy of an attribute list.
4139  *
4140  * Returns: a new #xmlAttrPtr, or NULL in case of error.
4141  */
4142 xmlAttrPtr
xmlCopyPropList(xmlNodePtr target,xmlAttrPtr cur)4143 xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
4144     xmlAttrPtr ret = NULL;
4145     xmlAttrPtr p = NULL,q;
4146 
4147     if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4148         return(NULL);
4149     while (cur != NULL) {
4150         q = xmlCopyProp(target, cur);
4151 	if (q == NULL)
4152 	    return(NULL);
4153 	if (p == NULL) {
4154 	    ret = p = q;
4155 	} else {
4156 	    p->next = q;
4157 	    q->prev = p;
4158 	    p = q;
4159 	}
4160 	cur = cur->next;
4161     }
4162     return(ret);
4163 }
4164 
4165 /*
4166  * NOTE about the CopyNode operations !
4167  *
4168  * They are split into external and internal parts for one
4169  * tricky reason: namespaces. Doing a direct copy of a node
4170  * say RPM:Copyright without changing the namespace pointer to
4171  * something else can produce stale links. One way to do it is
4172  * to keep a reference counter but this doesn't work as soon
4173  * as one moves the element or the subtree out of the scope of
4174  * the existing namespace. The actual solution seems to be to add
4175  * a copy of the namespace at the top of the copied tree if
4176  * not available in the subtree.
4177  * Hence two functions, the public front-end call the inner ones
4178  * The argument "recursive" normally indicates a recursive copy
4179  * of the node with values 0 (no) and 1 (yes).  For XInclude,
4180  * however, we allow a value of 2 to indicate copy properties and
4181  * namespace info, but don't recurse on children.
4182  */
4183 
4184 static xmlNodePtr
xmlStaticCopyNode(xmlNodePtr node,xmlDocPtr doc,xmlNodePtr parent,int extended)4185 xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
4186                   int extended) {
4187     xmlNodePtr ret;
4188 
4189     if (node == NULL) return(NULL);
4190     switch (node->type) {
4191         case XML_TEXT_NODE:
4192         case XML_CDATA_SECTION_NODE:
4193         case XML_ELEMENT_NODE:
4194         case XML_DOCUMENT_FRAG_NODE:
4195         case XML_ENTITY_REF_NODE:
4196         case XML_ENTITY_NODE:
4197         case XML_PI_NODE:
4198         case XML_COMMENT_NODE:
4199         case XML_XINCLUDE_START:
4200         case XML_XINCLUDE_END:
4201 	    break;
4202         case XML_ATTRIBUTE_NODE:
4203 		return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
4204         case XML_NAMESPACE_DECL:
4205 	    return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
4206 
4207         case XML_DOCUMENT_NODE:
4208         case XML_HTML_DOCUMENT_NODE:
4209 #ifdef LIBXML_DOCB_ENABLED
4210         case XML_DOCB_DOCUMENT_NODE:
4211 #endif
4212 #ifdef LIBXML_TREE_ENABLED
4213 	    return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
4214 #endif /* LIBXML_TREE_ENABLED */
4215         case XML_DOCUMENT_TYPE_NODE:
4216         case XML_NOTATION_NODE:
4217         case XML_DTD_NODE:
4218         case XML_ELEMENT_DECL:
4219         case XML_ATTRIBUTE_DECL:
4220         case XML_ENTITY_DECL:
4221             return(NULL);
4222     }
4223 
4224     /*
4225      * Allocate a new node and fill the fields.
4226      */
4227     ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4228     if (ret == NULL) {
4229 	xmlTreeErrMemory("copying node");
4230 	return(NULL);
4231     }
4232     memset(ret, 0, sizeof(xmlNode));
4233     ret->type = node->type;
4234 
4235     ret->doc = doc;
4236     ret->parent = parent;
4237     if (node->name == xmlStringText)
4238 	ret->name = xmlStringText;
4239     else if (node->name == xmlStringTextNoenc)
4240 	ret->name = xmlStringTextNoenc;
4241     else if (node->name == xmlStringComment)
4242 	ret->name = xmlStringComment;
4243     else if (node->name != NULL) {
4244         if ((doc != NULL) && (doc->dict != NULL))
4245 	    ret->name = xmlDictLookup(doc->dict, node->name, -1);
4246 	else
4247 	    ret->name = xmlStrdup(node->name);
4248     }
4249     if ((node->type != XML_ELEMENT_NODE) &&
4250 	(node->content != NULL) &&
4251 	(node->type != XML_ENTITY_REF_NODE) &&
4252 	(node->type != XML_XINCLUDE_END) &&
4253 	(node->type != XML_XINCLUDE_START)) {
4254 	ret->content = xmlStrdup(node->content);
4255     }else{
4256       if (node->type == XML_ELEMENT_NODE)
4257         ret->line = node->line;
4258     }
4259     if (parent != NULL) {
4260 	xmlNodePtr tmp;
4261 
4262 	/*
4263 	 * this is a tricky part for the node register thing:
4264 	 * in case ret does get coalesced in xmlAddChild
4265 	 * the deregister-node callback is called; so we register ret now already
4266 	 */
4267 	if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
4268 	    xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4269 
4270         tmp = xmlAddChild(parent, ret);
4271 	/* node could have coalesced */
4272 	if (tmp != ret)
4273 	    return(tmp);
4274     }
4275 
4276     if (!extended)
4277 	goto out;
4278     if (((node->type == XML_ELEMENT_NODE) ||
4279          (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL))
4280         ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4281 
4282     if (node->ns != NULL) {
4283         xmlNsPtr ns;
4284 
4285 	ns = xmlSearchNs(doc, ret, node->ns->prefix);
4286 	if (ns == NULL) {
4287 	    /*
4288 	     * Humm, we are copying an element whose namespace is defined
4289 	     * out of the new tree scope. Search it in the original tree
4290 	     * and add it at the top of the new tree
4291 	     */
4292 	    ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4293 	    if (ns != NULL) {
4294 	        xmlNodePtr root = ret;
4295 
4296 		while (root->parent != NULL) root = root->parent;
4297 		ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4298 		} else {
4299 			ret->ns = xmlNewReconciledNs(doc, ret, node->ns);
4300 	    }
4301 	} else {
4302 	    /*
4303 	     * reference the existing namespace definition in our own tree.
4304 	     */
4305 	    ret->ns = ns;
4306 	}
4307     }
4308     if (((node->type == XML_ELEMENT_NODE) ||
4309          (node->type == XML_XINCLUDE_START)) && (node->properties != NULL))
4310         ret->properties = xmlCopyPropList(ret, node->properties);
4311     if (node->type == XML_ENTITY_REF_NODE) {
4312 	if ((doc == NULL) || (node->doc != doc)) {
4313 	    /*
4314 	     * The copied node will go into a separate document, so
4315 	     * to avoid dangling references to the ENTITY_DECL node
4316 	     * we cannot keep the reference. Try to find it in the
4317 	     * target document.
4318 	     */
4319 	    ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4320 	} else {
4321             ret->children = node->children;
4322 	}
4323 	ret->last = ret->children;
4324     } else if ((node->children != NULL) && (extended != 2)) {
4325         ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
4326 	UPDATE_LAST_CHILD_AND_PARENT(ret)
4327     }
4328 
4329 out:
4330     /* if parent != NULL we already registered the node above */
4331     if ((parent == NULL) &&
4332         ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
4333 	xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4334     return(ret);
4335 }
4336 
4337 static xmlNodePtr
xmlStaticCopyNodeList(xmlNodePtr node,xmlDocPtr doc,xmlNodePtr parent)4338 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4339     xmlNodePtr ret = NULL;
4340     xmlNodePtr p = NULL,q;
4341 
4342     while (node != NULL) {
4343 #ifdef LIBXML_TREE_ENABLED
4344 	if (node->type == XML_DTD_NODE ) {
4345 	    if (doc == NULL) {
4346 		node = node->next;
4347 		continue;
4348 	    }
4349 	    if (doc->intSubset == NULL) {
4350 		q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4351 		if (q == NULL) return(NULL);
4352 		q->doc = doc;
4353 		q->parent = parent;
4354 		doc->intSubset = (xmlDtdPtr) q;
4355 		xmlAddChild(parent, q);
4356 	    } else {
4357 		q = (xmlNodePtr) doc->intSubset;
4358 		xmlAddChild(parent, q);
4359 	    }
4360 	} else
4361 #endif /* LIBXML_TREE_ENABLED */
4362 	    q = xmlStaticCopyNode(node, doc, parent, 1);
4363 	if (q == NULL) return(NULL);
4364 	if (ret == NULL) {
4365 	    q->prev = NULL;
4366 	    ret = p = q;
4367 	} else if (p != q) {
4368 	/* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
4369 	    p->next = q;
4370 	    q->prev = p;
4371 	    p = q;
4372 	}
4373 	node = node->next;
4374     }
4375     return(ret);
4376 }
4377 
4378 /**
4379  * xmlCopyNode:
4380  * @node:  the node
4381  * @extended:   if 1 do a recursive copy (properties, namespaces and children
4382  *			when applicable)
4383  *		if 2 copy properties and namespaces (when applicable)
4384  *
4385  * Do a copy of the node.
4386  *
4387  * Returns: a new #xmlNodePtr, or NULL in case of error.
4388  */
4389 xmlNodePtr
xmlCopyNode(xmlNodePtr node,int extended)4390 xmlCopyNode(xmlNodePtr node, int extended) {
4391     xmlNodePtr ret;
4392 
4393     ret = xmlStaticCopyNode(node, NULL, NULL, extended);
4394     return(ret);
4395 }
4396 
4397 /**
4398  * xmlDocCopyNode:
4399  * @node:  the node
4400  * @doc:  the document
4401  * @extended:   if 1 do a recursive copy (properties, namespaces and children
4402  *			when applicable)
4403  *		if 2 copy properties and namespaces (when applicable)
4404  *
4405  * Do a copy of the node to a given document.
4406  *
4407  * Returns: a new #xmlNodePtr, or NULL in case of error.
4408  */
4409 xmlNodePtr
xmlDocCopyNode(xmlNodePtr node,xmlDocPtr doc,int extended)4410 xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
4411     xmlNodePtr ret;
4412 
4413     ret = xmlStaticCopyNode(node, doc, NULL, extended);
4414     return(ret);
4415 }
4416 
4417 /**
4418  * xmlDocCopyNodeList:
4419  * @doc: the target document
4420  * @node:  the first node in the list.
4421  *
4422  * Do a recursive copy of the node list.
4423  *
4424  * Returns: a new #xmlNodePtr, or NULL in case of error.
4425  */
xmlDocCopyNodeList(xmlDocPtr doc,xmlNodePtr node)4426 xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) {
4427     xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4428     return(ret);
4429 }
4430 
4431 /**
4432  * xmlCopyNodeList:
4433  * @node:  the first node in the list.
4434  *
4435  * Do a recursive copy of the node list.
4436  * Use xmlDocCopyNodeList() if possible to ensure string interning.
4437  *
4438  * Returns: a new #xmlNodePtr, or NULL in case of error.
4439  */
xmlCopyNodeList(xmlNodePtr node)4440 xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
4441     xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4442     return(ret);
4443 }
4444 
4445 #if defined(LIBXML_TREE_ENABLED)
4446 /**
4447  * xmlCopyDtd:
4448  * @dtd:  the dtd
4449  *
4450  * Do a copy of the dtd.
4451  *
4452  * Returns: a new #xmlDtdPtr, or NULL in case of error.
4453  */
4454 xmlDtdPtr
xmlCopyDtd(xmlDtdPtr dtd)4455 xmlCopyDtd(xmlDtdPtr dtd) {
4456     xmlDtdPtr ret;
4457     xmlNodePtr cur, p = NULL, q;
4458 
4459     if (dtd == NULL) return(NULL);
4460     ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4461     if (ret == NULL) return(NULL);
4462     if (dtd->entities != NULL)
4463         ret->entities = (void *) xmlCopyEntitiesTable(
4464 	                    (xmlEntitiesTablePtr) dtd->entities);
4465     if (dtd->notations != NULL)
4466         ret->notations = (void *) xmlCopyNotationTable(
4467 	                    (xmlNotationTablePtr) dtd->notations);
4468     if (dtd->elements != NULL)
4469         ret->elements = (void *) xmlCopyElementTable(
4470 	                    (xmlElementTablePtr) dtd->elements);
4471     if (dtd->attributes != NULL)
4472         ret->attributes = (void *) xmlCopyAttributeTable(
4473 	                    (xmlAttributeTablePtr) dtd->attributes);
4474     if (dtd->pentities != NULL)
4475 	ret->pentities = (void *) xmlCopyEntitiesTable(
4476 			    (xmlEntitiesTablePtr) dtd->pentities);
4477 
4478     cur = dtd->children;
4479     while (cur != NULL) {
4480 	q = NULL;
4481 
4482 	if (cur->type == XML_ENTITY_DECL) {
4483 	    xmlEntityPtr tmp = (xmlEntityPtr) cur;
4484 	    switch (tmp->etype) {
4485 		case XML_INTERNAL_GENERAL_ENTITY:
4486 		case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4487 		case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4488 		    q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4489 		    break;
4490 		case XML_INTERNAL_PARAMETER_ENTITY:
4491 		case XML_EXTERNAL_PARAMETER_ENTITY:
4492 		    q = (xmlNodePtr)
4493 			xmlGetParameterEntityFromDtd(ret, tmp->name);
4494 		    break;
4495 		case XML_INTERNAL_PREDEFINED_ENTITY:
4496 		    break;
4497 	    }
4498 	} else if (cur->type == XML_ELEMENT_DECL) {
4499 	    xmlElementPtr tmp = (xmlElementPtr) cur;
4500 	    q = (xmlNodePtr)
4501 		xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4502 	} else if (cur->type == XML_ATTRIBUTE_DECL) {
4503 	    xmlAttributePtr tmp = (xmlAttributePtr) cur;
4504 	    q = (xmlNodePtr)
4505 		xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4506 	} else if (cur->type == XML_COMMENT_NODE) {
4507 	    q = xmlCopyNode(cur, 0);
4508 	}
4509 
4510 	if (q == NULL) {
4511 	    cur = cur->next;
4512 	    continue;
4513 	}
4514 
4515 	if (p == NULL)
4516 	    ret->children = q;
4517 	else
4518 	    p->next = q;
4519 
4520 	q->prev = p;
4521 	q->parent = (xmlNodePtr) ret;
4522 	q->next = NULL;
4523 	ret->last = q;
4524 	p = q;
4525 	cur = cur->next;
4526     }
4527 
4528     return(ret);
4529 }
4530 #endif
4531 
4532 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
4533 /**
4534  * xmlCopyDoc:
4535  * @doc:  the document
4536  * @recursive:  if not zero do a recursive copy.
4537  *
4538  * Do a copy of the document info. If recursive, the content tree will
4539  * be copied too as well as DTD, namespaces and entities.
4540  *
4541  * Returns: a new #xmlDocPtr, or NULL in case of error.
4542  */
4543 xmlDocPtr
xmlCopyDoc(xmlDocPtr doc,int recursive)4544 xmlCopyDoc(xmlDocPtr doc, int recursive) {
4545     xmlDocPtr ret;
4546 
4547     if (doc == NULL) return(NULL);
4548     ret = xmlNewDoc(doc->version);
4549     if (ret == NULL) return(NULL);
4550     if (doc->name != NULL)
4551         ret->name = xmlMemStrdup(doc->name);
4552     if (doc->encoding != NULL)
4553         ret->encoding = xmlStrdup(doc->encoding);
4554     if (doc->URL != NULL)
4555         ret->URL = xmlStrdup(doc->URL);
4556     ret->charset = doc->charset;
4557     ret->compression = doc->compression;
4558     ret->standalone = doc->standalone;
4559     if (!recursive) return(ret);
4560 
4561     ret->last = NULL;
4562     ret->children = NULL;
4563 #ifdef LIBXML_TREE_ENABLED
4564     if (doc->intSubset != NULL) {
4565         ret->intSubset = xmlCopyDtd(doc->intSubset);
4566 	if (ret->intSubset == NULL) {
4567 	    xmlFreeDoc(ret);
4568 	    return(NULL);
4569 	}
4570 	xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
4571 	ret->intSubset->parent = ret;
4572     }
4573 #endif
4574     if (doc->oldNs != NULL)
4575         ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4576     if (doc->children != NULL) {
4577 	xmlNodePtr tmp;
4578 
4579 	ret->children = xmlStaticCopyNodeList(doc->children, ret,
4580 		                               (xmlNodePtr)ret);
4581 	ret->last = NULL;
4582 	tmp = ret->children;
4583 	while (tmp != NULL) {
4584 	    if (tmp->next == NULL)
4585 	        ret->last = tmp;
4586 	    tmp = tmp->next;
4587 	}
4588     }
4589     return(ret);
4590 }
4591 #endif /* LIBXML_TREE_ENABLED */
4592 
4593 /************************************************************************
4594  *									*
4595  *		Content access functions				*
4596  *									*
4597  ************************************************************************/
4598 
4599 /**
4600  * xmlGetLineNoInternal:
4601  * @node: valid node
4602  * @depth: used to limit any risk of recursion
4603  *
4604  * Get line number of @node.
4605  * Try to override the limitation of lines being store in 16 bits ints
4606  *
4607  * Returns the line number if successful, -1 otherwise
4608  */
4609 static long
xmlGetLineNoInternal(const xmlNode * node,int depth)4610 xmlGetLineNoInternal(const xmlNode *node, int depth)
4611 {
4612     long result = -1;
4613 
4614     if (depth >= 5)
4615         return(-1);
4616 
4617     if (!node)
4618         return result;
4619     if ((node->type == XML_ELEMENT_NODE) ||
4620         (node->type == XML_TEXT_NODE) ||
4621 	(node->type == XML_COMMENT_NODE) ||
4622 	(node->type == XML_PI_NODE)) {
4623 	if (node->line == 65535) {
4624 	    if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL))
4625 	        result = (long) (ptrdiff_t) node->psvi;
4626 	    else if ((node->type == XML_ELEMENT_NODE) &&
4627 	             (node->children != NULL))
4628 	        result = xmlGetLineNoInternal(node->children, depth + 1);
4629 	    else if (node->next != NULL)
4630 	        result = xmlGetLineNoInternal(node->next, depth + 1);
4631 	    else if (node->prev != NULL)
4632 	        result = xmlGetLineNoInternal(node->prev, depth + 1);
4633 	}
4634 	if ((result == -1) || (result == 65535))
4635 	    result = (long) node->line;
4636     } else if ((node->prev != NULL) &&
4637              ((node->prev->type == XML_ELEMENT_NODE) ||
4638 	      (node->prev->type == XML_TEXT_NODE) ||
4639 	      (node->prev->type == XML_COMMENT_NODE) ||
4640 	      (node->prev->type == XML_PI_NODE)))
4641         result = xmlGetLineNoInternal(node->prev, depth + 1);
4642     else if ((node->parent != NULL) &&
4643              (node->parent->type == XML_ELEMENT_NODE))
4644         result = xmlGetLineNoInternal(node->parent, depth + 1);
4645 
4646     return result;
4647 }
4648 
4649 /**
4650  * xmlGetLineNo:
4651  * @node: valid node
4652  *
4653  * Get line number of @node.
4654  * Try to override the limitation of lines being store in 16 bits ints
4655  * if XML_PARSE_BIG_LINES parser option was used
4656  *
4657  * Returns the line number if successful, -1 otherwise
4658  */
4659 long
xmlGetLineNo(const xmlNode * node)4660 xmlGetLineNo(const xmlNode *node)
4661 {
4662     return(xmlGetLineNoInternal(node, 0));
4663 }
4664 
4665 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
4666 /**
4667  * xmlGetNodePath:
4668  * @node: a node
4669  *
4670  * Build a structure based Path for the given node
4671  *
4672  * Returns the new path or NULL in case of error. The caller must free
4673  *     the returned string
4674  */
4675 xmlChar *
xmlGetNodePath(const xmlNode * node)4676 xmlGetNodePath(const xmlNode *node)
4677 {
4678     const xmlNode *cur, *tmp, *next;
4679     xmlChar *buffer = NULL, *temp;
4680     size_t buf_len;
4681     xmlChar *buf;
4682     const char *sep;
4683     const char *name;
4684     char nametemp[100];
4685     int occur = 0, generic;
4686 
4687     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
4688         return (NULL);
4689 
4690     buf_len = 500;
4691     buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4692     if (buffer == NULL) {
4693 	xmlTreeErrMemory("getting node path");
4694         return (NULL);
4695     }
4696     buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar));
4697     if (buf == NULL) {
4698 	xmlTreeErrMemory("getting node path");
4699         xmlFree(buffer);
4700         return (NULL);
4701     }
4702 
4703     buffer[0] = 0;
4704     cur = node;
4705     do {
4706         name = "";
4707         sep = "?";
4708         occur = 0;
4709         if ((cur->type == XML_DOCUMENT_NODE) ||
4710             (cur->type == XML_HTML_DOCUMENT_NODE)) {
4711             if (buffer[0] == '/')
4712                 break;
4713             sep = "/";
4714             next = NULL;
4715         } else if (cur->type == XML_ELEMENT_NODE) {
4716 	    generic = 0;
4717             sep = "/";
4718             name = (const char *) cur->name;
4719             if (cur->ns) {
4720 		if (cur->ns->prefix != NULL) {
4721                     snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4722 			(char *)cur->ns->prefix, (char *)cur->name);
4723 		    nametemp[sizeof(nametemp) - 1] = 0;
4724 		    name = nametemp;
4725 		} else {
4726 		    /*
4727 		    * We cannot express named elements in the default
4728 		    * namespace, so use "*".
4729 		    */
4730 		    generic = 1;
4731 		    name = "*";
4732 		}
4733             }
4734             next = cur->parent;
4735 
4736             /*
4737              * Thumbler index computation
4738 	     * TODO: the occurrence test seems bogus for namespaced names
4739              */
4740             tmp = cur->prev;
4741             while (tmp != NULL) {
4742                 if ((tmp->type == XML_ELEMENT_NODE) &&
4743 		    (generic ||
4744 		     (xmlStrEqual(cur->name, tmp->name) &&
4745 		     ((tmp->ns == cur->ns) ||
4746 		      ((tmp->ns != NULL) && (cur->ns != NULL) &&
4747 		       (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4748                     occur++;
4749                 tmp = tmp->prev;
4750             }
4751             if (occur == 0) {
4752                 tmp = cur->next;
4753                 while (tmp != NULL && occur == 0) {
4754                     if ((tmp->type == XML_ELEMENT_NODE) &&
4755 			(generic ||
4756 			 (xmlStrEqual(cur->name, tmp->name) &&
4757 			 ((tmp->ns == cur->ns) ||
4758 			  ((tmp->ns != NULL) && (cur->ns != NULL) &&
4759 			   (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4760                         occur++;
4761                     tmp = tmp->next;
4762                 }
4763                 if (occur != 0)
4764                     occur = 1;
4765             } else
4766                 occur++;
4767         } else if (cur->type == XML_COMMENT_NODE) {
4768             sep = "/";
4769 	    name = "comment()";
4770             next = cur->parent;
4771 
4772             /*
4773              * Thumbler index computation
4774              */
4775             tmp = cur->prev;
4776             while (tmp != NULL) {
4777                 if (tmp->type == XML_COMMENT_NODE)
4778 		    occur++;
4779                 tmp = tmp->prev;
4780             }
4781             if (occur == 0) {
4782                 tmp = cur->next;
4783                 while (tmp != NULL && occur == 0) {
4784 		    if (tmp->type == XML_COMMENT_NODE)
4785 		        occur++;
4786                     tmp = tmp->next;
4787                 }
4788                 if (occur != 0)
4789                     occur = 1;
4790             } else
4791                 occur++;
4792         } else if ((cur->type == XML_TEXT_NODE) ||
4793                    (cur->type == XML_CDATA_SECTION_NODE)) {
4794             sep = "/";
4795 	    name = "text()";
4796             next = cur->parent;
4797 
4798             /*
4799              * Thumbler index computation
4800              */
4801             tmp = cur->prev;
4802             while (tmp != NULL) {
4803                 if ((tmp->type == XML_TEXT_NODE) ||
4804 		    (tmp->type == XML_CDATA_SECTION_NODE))
4805 		    occur++;
4806                 tmp = tmp->prev;
4807             }
4808 	    /*
4809 	    * Evaluate if this is the only text- or CDATA-section-node;
4810 	    * if yes, then we'll get "text()", otherwise "text()[1]".
4811 	    */
4812             if (occur == 0) {
4813                 tmp = cur->next;
4814                 while (tmp != NULL) {
4815 		    if ((tmp->type == XML_TEXT_NODE) ||
4816 			(tmp->type == XML_CDATA_SECTION_NODE))
4817 		    {
4818 			occur = 1;
4819 			break;
4820 		    }
4821 		    tmp = tmp->next;
4822 		}
4823             } else
4824                 occur++;
4825         } else if (cur->type == XML_PI_NODE) {
4826             sep = "/";
4827 	    snprintf(nametemp, sizeof(nametemp) - 1,
4828 		     "processing-instruction('%s')", (char *)cur->name);
4829             nametemp[sizeof(nametemp) - 1] = 0;
4830             name = nametemp;
4831 
4832 	    next = cur->parent;
4833 
4834             /*
4835              * Thumbler index computation
4836              */
4837             tmp = cur->prev;
4838             while (tmp != NULL) {
4839                 if ((tmp->type == XML_PI_NODE) &&
4840 		    (xmlStrEqual(cur->name, tmp->name)))
4841                     occur++;
4842                 tmp = tmp->prev;
4843             }
4844             if (occur == 0) {
4845                 tmp = cur->next;
4846                 while (tmp != NULL && occur == 0) {
4847                     if ((tmp->type == XML_PI_NODE) &&
4848 			(xmlStrEqual(cur->name, tmp->name)))
4849                         occur++;
4850                     tmp = tmp->next;
4851                 }
4852                 if (occur != 0)
4853                     occur = 1;
4854             } else
4855                 occur++;
4856 
4857         } else if (cur->type == XML_ATTRIBUTE_NODE) {
4858             sep = "/@";
4859             name = (const char *) (((xmlAttrPtr) cur)->name);
4860             if (cur->ns) {
4861 	        if (cur->ns->prefix != NULL)
4862                     snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4863 			(char *)cur->ns->prefix, (char *)cur->name);
4864 		else
4865 		    snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4866 			(char *)cur->name);
4867                 nametemp[sizeof(nametemp) - 1] = 0;
4868                 name = nametemp;
4869             }
4870             next = ((xmlAttrPtr) cur)->parent;
4871         } else {
4872             next = cur->parent;
4873         }
4874 
4875         /*
4876          * Make sure there is enough room
4877          */
4878         if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4879             buf_len =
4880                 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4881             temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4882             if (temp == NULL) {
4883 		xmlTreeErrMemory("getting node path");
4884                 xmlFree(buf);
4885                 xmlFree(buffer);
4886                 return (NULL);
4887             }
4888             buffer = temp;
4889             temp = (xmlChar *) xmlRealloc(buf, buf_len);
4890             if (temp == NULL) {
4891 		xmlTreeErrMemory("getting node path");
4892                 xmlFree(buf);
4893                 xmlFree(buffer);
4894                 return (NULL);
4895             }
4896             buf = temp;
4897         }
4898         if (occur == 0)
4899             snprintf((char *) buf, buf_len, "%s%s%s",
4900                      sep, name, (char *) buffer);
4901         else
4902             snprintf((char *) buf, buf_len, "%s%s[%d]%s",
4903                      sep, name, occur, (char *) buffer);
4904         snprintf((char *) buffer, buf_len, "%s", (char *)buf);
4905         cur = next;
4906     } while (cur != NULL);
4907     xmlFree(buf);
4908     return (buffer);
4909 }
4910 #endif /* LIBXML_TREE_ENABLED */
4911 
4912 /**
4913  * xmlDocGetRootElement:
4914  * @doc:  the document
4915  *
4916  * Get the root element of the document (doc->children is a list
4917  * containing possibly comments, PIs, etc ...).
4918  *
4919  * Returns the #xmlNodePtr for the root or NULL
4920  */
4921 xmlNodePtr
xmlDocGetRootElement(const xmlDoc * doc)4922 xmlDocGetRootElement(const xmlDoc *doc) {
4923     xmlNodePtr ret;
4924 
4925     if (doc == NULL) return(NULL);
4926     ret = doc->children;
4927     while (ret != NULL) {
4928 	if (ret->type == XML_ELEMENT_NODE)
4929 	    return(ret);
4930         ret = ret->next;
4931     }
4932     return(ret);
4933 }
4934 
4935 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
4936 /**
4937  * xmlDocSetRootElement:
4938  * @doc:  the document
4939  * @root:  the new document root element, if root is NULL no action is taken,
4940  *         to remove a node from a document use xmlUnlinkNode(root) instead.
4941  *
4942  * Set the root element of the document (doc->children is a list
4943  * containing possibly comments, PIs, etc ...).
4944  *
4945  * Returns the old root element if any was found, NULL if root was NULL
4946  */
4947 xmlNodePtr
xmlDocSetRootElement(xmlDocPtr doc,xmlNodePtr root)4948 xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
4949     xmlNodePtr old = NULL;
4950 
4951     if (doc == NULL) return(NULL);
4952     if ((root == NULL) || (root->type == XML_NAMESPACE_DECL))
4953 	return(NULL);
4954     xmlUnlinkNode(root);
4955     xmlSetTreeDoc(root, doc);
4956     root->parent = (xmlNodePtr) doc;
4957     old = doc->children;
4958     while (old != NULL) {
4959 	if (old->type == XML_ELEMENT_NODE)
4960 	    break;
4961         old = old->next;
4962     }
4963     if (old == NULL) {
4964 	if (doc->children == NULL) {
4965 	    doc->children = root;
4966 	    doc->last = root;
4967 	} else {
4968 	    xmlAddSibling(doc->children, root);
4969 	}
4970     } else {
4971 	xmlReplaceNode(old, root);
4972     }
4973     return(old);
4974 }
4975 #endif
4976 
4977 #if defined(LIBXML_TREE_ENABLED)
4978 /**
4979  * xmlNodeSetLang:
4980  * @cur:  the node being changed
4981  * @lang:  the language description
4982  *
4983  * Set the language of a node, i.e. the values of the xml:lang
4984  * attribute.
4985  */
4986 void
xmlNodeSetLang(xmlNodePtr cur,const xmlChar * lang)4987 xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
4988     xmlNsPtr ns;
4989 
4990     if (cur == NULL) return;
4991     switch(cur->type) {
4992         case XML_TEXT_NODE:
4993         case XML_CDATA_SECTION_NODE:
4994         case XML_COMMENT_NODE:
4995         case XML_DOCUMENT_NODE:
4996         case XML_DOCUMENT_TYPE_NODE:
4997         case XML_DOCUMENT_FRAG_NODE:
4998         case XML_NOTATION_NODE:
4999         case XML_HTML_DOCUMENT_NODE:
5000         case XML_DTD_NODE:
5001         case XML_ELEMENT_DECL:
5002         case XML_ATTRIBUTE_DECL:
5003         case XML_ENTITY_DECL:
5004         case XML_PI_NODE:
5005         case XML_ENTITY_REF_NODE:
5006         case XML_ENTITY_NODE:
5007 	case XML_NAMESPACE_DECL:
5008 #ifdef LIBXML_DOCB_ENABLED
5009 	case XML_DOCB_DOCUMENT_NODE:
5010 #endif
5011 	case XML_XINCLUDE_START:
5012 	case XML_XINCLUDE_END:
5013 	    return;
5014         case XML_ELEMENT_NODE:
5015         case XML_ATTRIBUTE_NODE:
5016 	    break;
5017     }
5018     ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5019     if (ns == NULL)
5020 	return;
5021     xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
5022 }
5023 #endif /* LIBXML_TREE_ENABLED */
5024 
5025 /**
5026  * xmlNodeGetLang:
5027  * @cur:  the node being checked
5028  *
5029  * Searches the language of a node, i.e. the values of the xml:lang
5030  * attribute or the one carried by the nearest ancestor.
5031  *
5032  * Returns a pointer to the lang value, or NULL if not found
5033  *     It's up to the caller to free the memory with xmlFree().
5034  */
5035 xmlChar *
xmlNodeGetLang(const xmlNode * cur)5036 xmlNodeGetLang(const xmlNode *cur) {
5037     xmlChar *lang;
5038 
5039     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
5040         return(NULL);
5041     while (cur != NULL) {
5042         lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
5043 	if (lang != NULL)
5044 	    return(lang);
5045 	cur = cur->parent;
5046     }
5047     return(NULL);
5048 }
5049 
5050 
5051 #ifdef LIBXML_TREE_ENABLED
5052 /**
5053  * xmlNodeSetSpacePreserve:
5054  * @cur:  the node being changed
5055  * @val:  the xml:space value ("0": default, 1: "preserve")
5056  *
5057  * Set (or reset) the space preserving behaviour of a node, i.e. the
5058  * value of the xml:space attribute.
5059  */
5060 void
xmlNodeSetSpacePreserve(xmlNodePtr cur,int val)5061 xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
5062     xmlNsPtr ns;
5063 
5064     if (cur == NULL) return;
5065     switch(cur->type) {
5066         case XML_TEXT_NODE:
5067         case XML_CDATA_SECTION_NODE:
5068         case XML_COMMENT_NODE:
5069         case XML_DOCUMENT_NODE:
5070         case XML_DOCUMENT_TYPE_NODE:
5071         case XML_DOCUMENT_FRAG_NODE:
5072         case XML_NOTATION_NODE:
5073         case XML_HTML_DOCUMENT_NODE:
5074         case XML_DTD_NODE:
5075         case XML_ELEMENT_DECL:
5076         case XML_ATTRIBUTE_DECL:
5077         case XML_ENTITY_DECL:
5078         case XML_PI_NODE:
5079         case XML_ENTITY_REF_NODE:
5080         case XML_ENTITY_NODE:
5081 	case XML_NAMESPACE_DECL:
5082 	case XML_XINCLUDE_START:
5083 	case XML_XINCLUDE_END:
5084 #ifdef LIBXML_DOCB_ENABLED
5085 	case XML_DOCB_DOCUMENT_NODE:
5086 #endif
5087 	    return;
5088         case XML_ELEMENT_NODE:
5089         case XML_ATTRIBUTE_NODE:
5090 	    break;
5091     }
5092     ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5093     if (ns == NULL)
5094 	return;
5095     switch (val) {
5096     case 0:
5097 	xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
5098 	break;
5099     case 1:
5100 	xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
5101 	break;
5102     }
5103 }
5104 #endif /* LIBXML_TREE_ENABLED */
5105 
5106 /**
5107  * xmlNodeGetSpacePreserve:
5108  * @cur:  the node being checked
5109  *
5110  * Searches the space preserving behaviour of a node, i.e. the values
5111  * of the xml:space attribute or the one carried by the nearest
5112  * ancestor.
5113  *
5114  * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
5115  */
5116 int
xmlNodeGetSpacePreserve(const xmlNode * cur)5117 xmlNodeGetSpacePreserve(const xmlNode *cur) {
5118     xmlChar *space;
5119 
5120     if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
5121         return(-1);
5122     while (cur != NULL) {
5123 	space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
5124 	if (space != NULL) {
5125 	    if (xmlStrEqual(space, BAD_CAST "preserve")) {
5126 		xmlFree(space);
5127 		return(1);
5128 	    }
5129 	    if (xmlStrEqual(space, BAD_CAST "default")) {
5130 		xmlFree(space);
5131 		return(0);
5132 	    }
5133 	    xmlFree(space);
5134 	}
5135 	cur = cur->parent;
5136     }
5137     return(-1);
5138 }
5139 
5140 #ifdef LIBXML_TREE_ENABLED
5141 /**
5142  * xmlNodeSetName:
5143  * @cur:  the node being changed
5144  * @name:  the new tag name
5145  *
5146  * Set (or reset) the name of a node.
5147  */
5148 void
xmlNodeSetName(xmlNodePtr cur,const xmlChar * name)5149 xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
5150     xmlDocPtr doc;
5151     xmlDictPtr dict;
5152     const xmlChar *freeme = NULL;
5153 
5154     if (cur == NULL) return;
5155     if (name == NULL) return;
5156     switch(cur->type) {
5157         case XML_TEXT_NODE:
5158         case XML_CDATA_SECTION_NODE:
5159         case XML_COMMENT_NODE:
5160         case XML_DOCUMENT_TYPE_NODE:
5161         case XML_DOCUMENT_FRAG_NODE:
5162         case XML_NOTATION_NODE:
5163         case XML_HTML_DOCUMENT_NODE:
5164 	case XML_NAMESPACE_DECL:
5165 	case XML_XINCLUDE_START:
5166 	case XML_XINCLUDE_END:
5167 #ifdef LIBXML_DOCB_ENABLED
5168 	case XML_DOCB_DOCUMENT_NODE:
5169 #endif
5170 	    return;
5171         case XML_ELEMENT_NODE:
5172         case XML_ATTRIBUTE_NODE:
5173         case XML_PI_NODE:
5174         case XML_ENTITY_REF_NODE:
5175         case XML_ENTITY_NODE:
5176         case XML_DTD_NODE:
5177         case XML_DOCUMENT_NODE:
5178         case XML_ELEMENT_DECL:
5179         case XML_ATTRIBUTE_DECL:
5180         case XML_ENTITY_DECL:
5181 	    break;
5182     }
5183     doc = cur->doc;
5184     if (doc != NULL)
5185 	dict = doc->dict;
5186     else
5187         dict = NULL;
5188     if (dict != NULL) {
5189         if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
5190 	    freeme = cur->name;
5191 	cur->name = xmlDictLookup(dict, name, -1);
5192     } else {
5193 	if (cur->name != NULL)
5194 	    freeme = cur->name;
5195 	cur->name = xmlStrdup(name);
5196     }
5197 
5198     if (freeme)
5199         xmlFree((xmlChar *) freeme);
5200 }
5201 #endif
5202 
5203 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
5204 /**
5205  * xmlNodeSetBase:
5206  * @cur:  the node being changed
5207  * @uri:  the new base URI
5208  *
5209  * Set (or reset) the base URI of a node, i.e. the value of the
5210  * xml:base attribute.
5211  */
5212 void
xmlNodeSetBase(xmlNodePtr cur,const xmlChar * uri)5213 xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
5214     xmlNsPtr ns;
5215     xmlChar* fixed;
5216 
5217     if (cur == NULL) return;
5218     switch(cur->type) {
5219         case XML_TEXT_NODE:
5220         case XML_CDATA_SECTION_NODE:
5221         case XML_COMMENT_NODE:
5222         case XML_DOCUMENT_TYPE_NODE:
5223         case XML_DOCUMENT_FRAG_NODE:
5224         case XML_NOTATION_NODE:
5225         case XML_DTD_NODE:
5226         case XML_ELEMENT_DECL:
5227         case XML_ATTRIBUTE_DECL:
5228         case XML_ENTITY_DECL:
5229         case XML_PI_NODE:
5230         case XML_ENTITY_REF_NODE:
5231         case XML_ENTITY_NODE:
5232 	case XML_NAMESPACE_DECL:
5233 	case XML_XINCLUDE_START:
5234 	case XML_XINCLUDE_END:
5235 	    return;
5236         case XML_ELEMENT_NODE:
5237         case XML_ATTRIBUTE_NODE:
5238 	    break;
5239         case XML_DOCUMENT_NODE:
5240 #ifdef LIBXML_DOCB_ENABLED
5241 	case XML_DOCB_DOCUMENT_NODE:
5242 #endif
5243         case XML_HTML_DOCUMENT_NODE: {
5244 	    xmlDocPtr doc = (xmlDocPtr) cur;
5245 
5246 	    if (doc->URL != NULL)
5247 		xmlFree((xmlChar *) doc->URL);
5248 	    if (uri == NULL)
5249 		doc->URL = NULL;
5250 	    else
5251 		doc->URL = xmlPathToURI(uri);
5252 	    return;
5253 	}
5254     }
5255 
5256     ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5257     if (ns == NULL)
5258 	return;
5259     fixed = xmlPathToURI(uri);
5260     if (fixed != NULL) {
5261 	xmlSetNsProp(cur, ns, BAD_CAST "base", fixed);
5262 	xmlFree(fixed);
5263     } else {
5264 	xmlSetNsProp(cur, ns, BAD_CAST "base", uri);
5265     }
5266 }
5267 #endif /* LIBXML_TREE_ENABLED */
5268 
5269 /**
5270  * xmlNodeGetBase:
5271  * @doc:  the document the node pertains to
5272  * @cur:  the node being checked
5273  *
5274  * Searches for the BASE URL. The code should work on both XML
5275  * and HTML document even if base mechanisms are completely different.
5276  * It returns the base as defined in RFC 2396 sections
5277  * 5.1.1. Base URI within Document Content
5278  * and
5279  * 5.1.2. Base URI from the Encapsulating Entity
5280  * However it does not return the document base (5.1.3), use
5281  * doc->URL in this case
5282  *
5283  * Returns a pointer to the base URL, or NULL if not found
5284  *     It's up to the caller to free the memory with xmlFree().
5285  */
5286 xmlChar *
xmlNodeGetBase(const xmlDoc * doc,const xmlNode * cur)5287 xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) {
5288     xmlChar *oldbase = NULL;
5289     xmlChar *base, *newbase;
5290 
5291     if ((cur == NULL) && (doc == NULL))
5292         return(NULL);
5293     if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
5294         return(NULL);
5295     if (doc == NULL) doc = cur->doc;
5296     if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
5297         cur = doc->children;
5298 	while ((cur != NULL) && (cur->name != NULL)) {
5299 	    if (cur->type != XML_ELEMENT_NODE) {
5300 	        cur = cur->next;
5301 		continue;
5302 	    }
5303 	    if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
5304 	        cur = cur->children;
5305 		continue;
5306 	    }
5307 	    if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
5308 	        cur = cur->children;
5309 		continue;
5310 	    }
5311 	    if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
5312                 return(xmlGetProp(cur, BAD_CAST "href"));
5313 	    }
5314 	    cur = cur->next;
5315 	}
5316 	return(NULL);
5317     }
5318     while (cur != NULL) {
5319 	if (cur->type == XML_ENTITY_DECL) {
5320 	    xmlEntityPtr ent = (xmlEntityPtr) cur;
5321 	    return(xmlStrdup(ent->URI));
5322 	}
5323 	if (cur->type == XML_ELEMENT_NODE) {
5324 	    base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
5325 	    if (base != NULL) {
5326 		if (oldbase != NULL) {
5327 		    newbase = xmlBuildURI(oldbase, base);
5328 		    if (newbase != NULL) {
5329 			xmlFree(oldbase);
5330 			xmlFree(base);
5331 			oldbase = newbase;
5332 		    } else {
5333 			xmlFree(oldbase);
5334 			xmlFree(base);
5335 			return(NULL);
5336 		    }
5337 		} else {
5338 		    oldbase = base;
5339 		}
5340 		if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) ||
5341 		    (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) ||
5342 		    (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4)))
5343 		    return(oldbase);
5344 	    }
5345 	}
5346 	cur = cur->parent;
5347     }
5348     if ((doc != NULL) && (doc->URL != NULL)) {
5349 	if (oldbase == NULL)
5350 	    return(xmlStrdup(doc->URL));
5351 	newbase = xmlBuildURI(oldbase, doc->URL);
5352 	xmlFree(oldbase);
5353 	return(newbase);
5354     }
5355     return(oldbase);
5356 }
5357 
5358 /**
5359  * xmlNodeBufGetContent:
5360  * @buffer:  a buffer
5361  * @cur:  the node being read
5362  *
5363  * Read the value of a node @cur, this can be either the text carried
5364  * directly by this node if it's a TEXT node or the aggregate string
5365  * of the values carried by this node child's (TEXT and ENTITY_REF).
5366  * Entity references are substituted.
5367  * Fills up the buffer @buffer with this value
5368  *
5369  * Returns 0 in case of success and -1 in case of error.
5370  */
5371 int
xmlNodeBufGetContent(xmlBufferPtr buffer,const xmlNode * cur)5372 xmlNodeBufGetContent(xmlBufferPtr buffer, const xmlNode *cur)
5373 {
5374     xmlBufPtr buf;
5375     int ret;
5376 
5377     if ((cur == NULL) || (buffer == NULL)) return(-1);
5378     buf = xmlBufFromBuffer(buffer);
5379     ret = xmlBufGetNodeContent(buf, cur);
5380     buffer = xmlBufBackToBuffer(buf);
5381     if ((ret < 0) || (buffer == NULL))
5382         return(-1);
5383     return(0);
5384 }
5385 
5386 /**
5387  * xmlBufGetNodeContent:
5388  * @buf:  a buffer xmlBufPtr
5389  * @cur:  the node being read
5390  *
5391  * Read the value of a node @cur, this can be either the text carried
5392  * directly by this node if it's a TEXT node or the aggregate string
5393  * of the values carried by this node child's (TEXT and ENTITY_REF).
5394  * Entity references are substituted.
5395  * Fills up the buffer @buf with this value
5396  *
5397  * Returns 0 in case of success and -1 in case of error.
5398  */
5399 int
xmlBufGetNodeContent(xmlBufPtr buf,const xmlNode * cur)5400 xmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur)
5401 {
5402     if ((cur == NULL) || (buf == NULL)) return(-1);
5403     switch (cur->type) {
5404         case XML_CDATA_SECTION_NODE:
5405         case XML_TEXT_NODE:
5406 	    xmlBufCat(buf, cur->content);
5407             break;
5408         case XML_DOCUMENT_FRAG_NODE:
5409         case XML_ELEMENT_NODE:{
5410                 const xmlNode *tmp = cur;
5411 
5412                 while (tmp != NULL) {
5413                     switch (tmp->type) {
5414                         case XML_CDATA_SECTION_NODE:
5415                         case XML_TEXT_NODE:
5416                             if (tmp->content != NULL)
5417                                 xmlBufCat(buf, tmp->content);
5418                             break;
5419                         case XML_ENTITY_REF_NODE:
5420                             xmlBufGetNodeContent(buf, tmp);
5421                             break;
5422                         default:
5423                             break;
5424                     }
5425                     /*
5426                      * Skip to next node
5427                      */
5428                     if (tmp->children != NULL) {
5429                         if (tmp->children->type != XML_ENTITY_DECL) {
5430                             tmp = tmp->children;
5431                             continue;
5432                         }
5433                     }
5434                     if (tmp == cur)
5435                         break;
5436 
5437                     if (tmp->next != NULL) {
5438                         tmp = tmp->next;
5439                         continue;
5440                     }
5441 
5442                     do {
5443                         tmp = tmp->parent;
5444                         if (tmp == NULL)
5445                             break;
5446                         if (tmp == cur) {
5447                             tmp = NULL;
5448                             break;
5449                         }
5450                         if (tmp->next != NULL) {
5451                             tmp = tmp->next;
5452                             break;
5453                         }
5454                     } while (tmp != NULL);
5455                 }
5456 		break;
5457             }
5458         case XML_ATTRIBUTE_NODE:{
5459                 xmlAttrPtr attr = (xmlAttrPtr) cur;
5460 		xmlNodePtr tmp = attr->children;
5461 
5462 		while (tmp != NULL) {
5463 		    if (tmp->type == XML_TEXT_NODE)
5464 		        xmlBufCat(buf, tmp->content);
5465 		    else
5466 		        xmlBufGetNodeContent(buf, tmp);
5467 		    tmp = tmp->next;
5468 		}
5469                 break;
5470             }
5471         case XML_COMMENT_NODE:
5472         case XML_PI_NODE:
5473 	    xmlBufCat(buf, cur->content);
5474             break;
5475         case XML_ENTITY_REF_NODE:{
5476                 xmlEntityPtr ent;
5477                 xmlNodePtr tmp;
5478 
5479                 /* lookup entity declaration */
5480                 ent = xmlGetDocEntity(cur->doc, cur->name);
5481                 if (ent == NULL)
5482                     return(-1);
5483 
5484                 /* an entity content can be any "well balanced chunk",
5485                  * i.e. the result of the content [43] production:
5486                  * http://www.w3.org/TR/REC-xml#NT-content
5487                  * -> we iterate through child nodes and recursive call
5488                  * xmlNodeGetContent() which handles all possible node types */
5489                 tmp = ent->children;
5490                 while (tmp) {
5491 		    xmlBufGetNodeContent(buf, tmp);
5492                     tmp = tmp->next;
5493                 }
5494 		break;
5495             }
5496         case XML_ENTITY_NODE:
5497         case XML_DOCUMENT_TYPE_NODE:
5498         case XML_NOTATION_NODE:
5499         case XML_DTD_NODE:
5500         case XML_XINCLUDE_START:
5501         case XML_XINCLUDE_END:
5502             break;
5503         case XML_DOCUMENT_NODE:
5504 #ifdef LIBXML_DOCB_ENABLED
5505         case XML_DOCB_DOCUMENT_NODE:
5506 #endif
5507         case XML_HTML_DOCUMENT_NODE:
5508 	    cur = cur->children;
5509 	    while (cur!= NULL) {
5510 		if ((cur->type == XML_ELEMENT_NODE) ||
5511 		    (cur->type == XML_TEXT_NODE) ||
5512 		    (cur->type == XML_CDATA_SECTION_NODE)) {
5513 		    xmlBufGetNodeContent(buf, cur);
5514 		}
5515 		cur = cur->next;
5516 	    }
5517 	    break;
5518         case XML_NAMESPACE_DECL:
5519 	    xmlBufCat(buf, ((xmlNsPtr) cur)->href);
5520 	    break;
5521         case XML_ELEMENT_DECL:
5522         case XML_ATTRIBUTE_DECL:
5523         case XML_ENTITY_DECL:
5524             break;
5525     }
5526     return(0);
5527 }
5528 
5529 /**
5530  * xmlNodeGetContent:
5531  * @cur:  the node being read
5532  *
5533  * Read the value of a node, this can be either the text carried
5534  * directly by this node if it's a TEXT node or the aggregate string
5535  * of the values carried by this node child's (TEXT and ENTITY_REF).
5536  * Entity references are substituted.
5537  * Returns a new #xmlChar * or NULL if no content is available.
5538  *     It's up to the caller to free the memory with xmlFree().
5539  */
5540 xmlChar *
xmlNodeGetContent(const xmlNode * cur)5541 xmlNodeGetContent(const xmlNode *cur)
5542 {
5543     if (cur == NULL)
5544         return (NULL);
5545     switch (cur->type) {
5546         case XML_DOCUMENT_FRAG_NODE:
5547         case XML_ELEMENT_NODE:{
5548                 xmlBufPtr buf;
5549                 xmlChar *ret;
5550 
5551                 buf = xmlBufCreateSize(64);
5552                 if (buf == NULL)
5553                     return (NULL);
5554 		xmlBufGetNodeContent(buf, cur);
5555                 ret = xmlBufDetach(buf);
5556                 xmlBufFree(buf);
5557                 return (ret);
5558             }
5559         case XML_ATTRIBUTE_NODE:
5560 	    return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
5561         case XML_COMMENT_NODE:
5562         case XML_PI_NODE:
5563             if (cur->content != NULL)
5564                 return (xmlStrdup(cur->content));
5565             return (NULL);
5566         case XML_ENTITY_REF_NODE:{
5567                 xmlEntityPtr ent;
5568                 xmlBufPtr buf;
5569                 xmlChar *ret;
5570 
5571                 /* lookup entity declaration */
5572                 ent = xmlGetDocEntity(cur->doc, cur->name);
5573                 if (ent == NULL)
5574                     return (NULL);
5575 
5576                 buf = xmlBufCreate();
5577                 if (buf == NULL)
5578                     return (NULL);
5579 
5580                 xmlBufGetNodeContent(buf, cur);
5581 
5582                 ret = xmlBufDetach(buf);
5583                 xmlBufFree(buf);
5584                 return (ret);
5585             }
5586         case XML_ENTITY_NODE:
5587         case XML_DOCUMENT_TYPE_NODE:
5588         case XML_NOTATION_NODE:
5589         case XML_DTD_NODE:
5590         case XML_XINCLUDE_START:
5591         case XML_XINCLUDE_END:
5592             return (NULL);
5593         case XML_DOCUMENT_NODE:
5594 #ifdef LIBXML_DOCB_ENABLED
5595         case XML_DOCB_DOCUMENT_NODE:
5596 #endif
5597         case XML_HTML_DOCUMENT_NODE: {
5598 	    xmlBufPtr buf;
5599 	    xmlChar *ret;
5600 
5601 	    buf = xmlBufCreate();
5602 	    if (buf == NULL)
5603 		return (NULL);
5604 
5605 	    xmlBufGetNodeContent(buf, (xmlNodePtr) cur);
5606 
5607 	    ret = xmlBufDetach(buf);
5608 	    xmlBufFree(buf);
5609 	    return (ret);
5610 	}
5611         case XML_NAMESPACE_DECL: {
5612 	    xmlChar *tmp;
5613 
5614 	    tmp = xmlStrdup(((xmlNsPtr) cur)->href);
5615             return (tmp);
5616 	}
5617         case XML_ELEMENT_DECL:
5618             /* TODO !!! */
5619             return (NULL);
5620         case XML_ATTRIBUTE_DECL:
5621             /* TODO !!! */
5622             return (NULL);
5623         case XML_ENTITY_DECL:
5624             /* TODO !!! */
5625             return (NULL);
5626         case XML_CDATA_SECTION_NODE:
5627         case XML_TEXT_NODE:
5628             if (cur->content != NULL)
5629                 return (xmlStrdup(cur->content));
5630             return (NULL);
5631     }
5632     return (NULL);
5633 }
5634 
5635 /**
5636  * xmlNodeSetContent:
5637  * @cur:  the node being modified
5638  * @content:  the new value of the content
5639  *
5640  * Replace the content of a node.
5641  * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5642  *       references, but XML special chars need to be escaped first by using
5643  *       xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
5644  */
5645 void
xmlNodeSetContent(xmlNodePtr cur,const xmlChar * content)5646 xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
5647     if (cur == NULL) {
5648 #ifdef DEBUG_TREE
5649         xmlGenericError(xmlGenericErrorContext,
5650 		"xmlNodeSetContent : node == NULL\n");
5651 #endif
5652 	return;
5653     }
5654     switch (cur->type) {
5655         case XML_DOCUMENT_FRAG_NODE:
5656         case XML_ELEMENT_NODE:
5657         case XML_ATTRIBUTE_NODE:
5658 	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
5659 	    cur->children = xmlStringGetNodeList(cur->doc, content);
5660 	    UPDATE_LAST_CHILD_AND_PARENT(cur)
5661 	    break;
5662         case XML_TEXT_NODE:
5663         case XML_CDATA_SECTION_NODE:
5664         case XML_ENTITY_REF_NODE:
5665         case XML_ENTITY_NODE:
5666         case XML_PI_NODE:
5667         case XML_COMMENT_NODE:
5668 	    if ((cur->content != NULL) &&
5669 	        (cur->content != (xmlChar *) &(cur->properties))) {
5670 	        if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5671 		    (xmlDictOwns(cur->doc->dict, cur->content))))
5672 		    xmlFree(cur->content);
5673 	    }
5674 	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
5675 	    cur->last = cur->children = NULL;
5676 	    if (content != NULL) {
5677 		cur->content = xmlStrdup(content);
5678 	    } else
5679 		cur->content = NULL;
5680 	    cur->properties = NULL;
5681 	    cur->nsDef = NULL;
5682 	    break;
5683         case XML_DOCUMENT_NODE:
5684         case XML_HTML_DOCUMENT_NODE:
5685         case XML_DOCUMENT_TYPE_NODE:
5686 	case XML_XINCLUDE_START:
5687 	case XML_XINCLUDE_END:
5688 #ifdef LIBXML_DOCB_ENABLED
5689 	case XML_DOCB_DOCUMENT_NODE:
5690 #endif
5691 	    break;
5692         case XML_NOTATION_NODE:
5693 	    break;
5694         case XML_DTD_NODE:
5695 	    break;
5696 	case XML_NAMESPACE_DECL:
5697 	    break;
5698         case XML_ELEMENT_DECL:
5699 	    /* TODO !!! */
5700 	    break;
5701         case XML_ATTRIBUTE_DECL:
5702 	    /* TODO !!! */
5703 	    break;
5704         case XML_ENTITY_DECL:
5705 	    /* TODO !!! */
5706 	    break;
5707     }
5708 }
5709 
5710 #ifdef LIBXML_TREE_ENABLED
5711 /**
5712  * xmlNodeSetContentLen:
5713  * @cur:  the node being modified
5714  * @content:  the new value of the content
5715  * @len:  the size of @content
5716  *
5717  * Replace the content of a node.
5718  * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
5719  *       references, but XML special chars need to be escaped first by using
5720  *       xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
5721  */
5722 void
xmlNodeSetContentLen(xmlNodePtr cur,const xmlChar * content,int len)5723 xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5724     if (cur == NULL) {
5725 #ifdef DEBUG_TREE
5726         xmlGenericError(xmlGenericErrorContext,
5727 		"xmlNodeSetContentLen : node == NULL\n");
5728 #endif
5729 	return;
5730     }
5731     switch (cur->type) {
5732         case XML_DOCUMENT_FRAG_NODE:
5733         case XML_ELEMENT_NODE:
5734         case XML_ATTRIBUTE_NODE:
5735 	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
5736 	    cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
5737 	    UPDATE_LAST_CHILD_AND_PARENT(cur)
5738 	    break;
5739         case XML_TEXT_NODE:
5740         case XML_CDATA_SECTION_NODE:
5741         case XML_ENTITY_REF_NODE:
5742         case XML_ENTITY_NODE:
5743         case XML_PI_NODE:
5744         case XML_COMMENT_NODE:
5745         case XML_NOTATION_NODE:
5746 	    if ((cur->content != NULL) &&
5747 	        (cur->content != (xmlChar *) &(cur->properties))) {
5748 	        if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5749 		    (xmlDictOwns(cur->doc->dict, cur->content))))
5750 		    xmlFree(cur->content);
5751 	    }
5752 	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
5753 	    cur->children = cur->last = NULL;
5754 	    if (content != NULL) {
5755 		cur->content = xmlStrndup(content, len);
5756 	    } else
5757 		cur->content = NULL;
5758 	    cur->properties = NULL;
5759 	    cur->nsDef = NULL;
5760 	    break;
5761         case XML_DOCUMENT_NODE:
5762         case XML_DTD_NODE:
5763         case XML_HTML_DOCUMENT_NODE:
5764         case XML_DOCUMENT_TYPE_NODE:
5765 	case XML_NAMESPACE_DECL:
5766 	case XML_XINCLUDE_START:
5767 	case XML_XINCLUDE_END:
5768 #ifdef LIBXML_DOCB_ENABLED
5769 	case XML_DOCB_DOCUMENT_NODE:
5770 #endif
5771 	    break;
5772         case XML_ELEMENT_DECL:
5773 	    /* TODO !!! */
5774 	    break;
5775         case XML_ATTRIBUTE_DECL:
5776 	    /* TODO !!! */
5777 	    break;
5778         case XML_ENTITY_DECL:
5779 	    /* TODO !!! */
5780 	    break;
5781     }
5782 }
5783 #endif /* LIBXML_TREE_ENABLED */
5784 
5785 /**
5786  * xmlNodeAddContentLen:
5787  * @cur:  the node being modified
5788  * @content:  extra content
5789  * @len:  the size of @content
5790  *
5791  * Append the extra substring to the node content.
5792  * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be
5793  *       raw text, so unescaped XML special chars are allowed, entity
5794  *       references are not supported.
5795  */
5796 void
xmlNodeAddContentLen(xmlNodePtr cur,const xmlChar * content,int len)5797 xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
5798     if (cur == NULL) {
5799 #ifdef DEBUG_TREE
5800         xmlGenericError(xmlGenericErrorContext,
5801 		"xmlNodeAddContentLen : node == NULL\n");
5802 #endif
5803 	return;
5804     }
5805     if (len <= 0) return;
5806     switch (cur->type) {
5807         case XML_DOCUMENT_FRAG_NODE:
5808         case XML_ELEMENT_NODE: {
5809 	    xmlNodePtr last, newNode, tmp;
5810 
5811 	    last = cur->last;
5812 	    newNode = xmlNewTextLen(content, len);
5813 	    if (newNode != NULL) {
5814 		tmp = xmlAddChild(cur, newNode);
5815 		if (tmp != newNode)
5816 		    return;
5817 	        if ((last != NULL) && (last->next == newNode)) {
5818 		    xmlTextMerge(last, newNode);
5819 		}
5820 	    }
5821 	    break;
5822 	}
5823         case XML_ATTRIBUTE_NODE:
5824 	    break;
5825         case XML_TEXT_NODE:
5826         case XML_CDATA_SECTION_NODE:
5827         case XML_ENTITY_REF_NODE:
5828         case XML_ENTITY_NODE:
5829         case XML_PI_NODE:
5830         case XML_COMMENT_NODE:
5831         case XML_NOTATION_NODE:
5832 	    if (content != NULL) {
5833 	        if ((cur->content == (xmlChar *) &(cur->properties)) ||
5834 		    ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
5835 			    xmlDictOwns(cur->doc->dict, cur->content))) {
5836 		    cur->content = xmlStrncatNew(cur->content, content, len);
5837 		    cur->properties = NULL;
5838 		    cur->nsDef = NULL;
5839 		    break;
5840 		}
5841 		cur->content = xmlStrncat(cur->content, content, len);
5842             }
5843         case XML_DOCUMENT_NODE:
5844         case XML_DTD_NODE:
5845         case XML_HTML_DOCUMENT_NODE:
5846         case XML_DOCUMENT_TYPE_NODE:
5847 	case XML_NAMESPACE_DECL:
5848 	case XML_XINCLUDE_START:
5849 	case XML_XINCLUDE_END:
5850 #ifdef LIBXML_DOCB_ENABLED
5851 	case XML_DOCB_DOCUMENT_NODE:
5852 #endif
5853 	    break;
5854         case XML_ELEMENT_DECL:
5855         case XML_ATTRIBUTE_DECL:
5856         case XML_ENTITY_DECL:
5857 	    break;
5858     }
5859 }
5860 
5861 /**
5862  * xmlNodeAddContent:
5863  * @cur:  the node being modified
5864  * @content:  extra content
5865  *
5866  * Append the extra substring to the node content.
5867  * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be
5868  *       raw text, so unescaped XML special chars are allowed, entity
5869  *       references are not supported.
5870  */
5871 void
xmlNodeAddContent(xmlNodePtr cur,const xmlChar * content)5872 xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
5873     int len;
5874 
5875     if (cur == NULL) {
5876 #ifdef DEBUG_TREE
5877         xmlGenericError(xmlGenericErrorContext,
5878 		"xmlNodeAddContent : node == NULL\n");
5879 #endif
5880 	return;
5881     }
5882     if (content == NULL) return;
5883     len = xmlStrlen(content);
5884     xmlNodeAddContentLen(cur, content, len);
5885 }
5886 
5887 /**
5888  * xmlTextMerge:
5889  * @first:  the first text node
5890  * @second:  the second text node being merged
5891  *
5892  * Merge two text nodes into one
5893  * Returns the first text node augmented
5894  */
5895 xmlNodePtr
xmlTextMerge(xmlNodePtr first,xmlNodePtr second)5896 xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
5897     if (first == NULL) return(second);
5898     if (second == NULL) return(first);
5899     if (first->type != XML_TEXT_NODE) return(first);
5900     if (second->type != XML_TEXT_NODE) return(first);
5901     if (second->name != first->name)
5902 	return(first);
5903     xmlNodeAddContent(first, second->content);
5904     xmlUnlinkNode(second);
5905     xmlFreeNode(second);
5906     return(first);
5907 }
5908 
5909 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
5910 /**
5911  * xmlGetNsList:
5912  * @doc:  the document
5913  * @node:  the current node
5914  *
5915  * Search all the namespace applying to a given element.
5916  * Returns an NULL terminated array of all the #xmlNsPtr found
5917  *         that need to be freed by the caller or NULL if no
5918  *         namespace if defined
5919  */
5920 xmlNsPtr *
xmlGetNsList(const xmlDoc * doc ATTRIBUTE_UNUSED,const xmlNode * node)5921 xmlGetNsList(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node)
5922 {
5923     xmlNsPtr cur;
5924     xmlNsPtr *ret = NULL;
5925     int nbns = 0;
5926     int maxns = 10;
5927     int i;
5928 
5929     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
5930         return(NULL);
5931 
5932     while (node != NULL) {
5933         if (node->type == XML_ELEMENT_NODE) {
5934             cur = node->nsDef;
5935             while (cur != NULL) {
5936                 if (ret == NULL) {
5937                     ret =
5938                         (xmlNsPtr *) xmlMalloc((maxns + 1) *
5939                                                sizeof(xmlNsPtr));
5940                     if (ret == NULL) {
5941 			xmlTreeErrMemory("getting namespace list");
5942                         return (NULL);
5943                     }
5944                     ret[nbns] = NULL;
5945                 }
5946                 for (i = 0; i < nbns; i++) {
5947                     if ((cur->prefix == ret[i]->prefix) ||
5948                         (xmlStrEqual(cur->prefix, ret[i]->prefix)))
5949                         break;
5950                 }
5951                 if (i >= nbns) {
5952                     if (nbns >= maxns) {
5953                         maxns *= 2;
5954                         ret = (xmlNsPtr *) xmlRealloc(ret,
5955                                                       (maxns +
5956                                                        1) *
5957                                                       sizeof(xmlNsPtr));
5958                         if (ret == NULL) {
5959 			    xmlTreeErrMemory("getting namespace list");
5960                             return (NULL);
5961                         }
5962                     }
5963                     ret[nbns++] = cur;
5964                     ret[nbns] = NULL;
5965                 }
5966 
5967                 cur = cur->next;
5968             }
5969         }
5970         node = node->parent;
5971     }
5972     return (ret);
5973 }
5974 #endif /* LIBXML_TREE_ENABLED */
5975 
5976 /*
5977 * xmlTreeEnsureXMLDecl:
5978 * @doc: the doc
5979 *
5980 * Ensures that there is an XML namespace declaration on the doc.
5981 *
5982 * Returns the XML ns-struct or NULL on API and internal errors.
5983 */
5984 static xmlNsPtr
xmlTreeEnsureXMLDecl(xmlDocPtr doc)5985 xmlTreeEnsureXMLDecl(xmlDocPtr doc)
5986 {
5987     if (doc == NULL)
5988 	return (NULL);
5989     if (doc->oldNs != NULL)
5990 	return (doc->oldNs);
5991     {
5992 	xmlNsPtr ns;
5993 	ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
5994 	if (ns == NULL) {
5995 	    xmlTreeErrMemory(
5996 		"allocating the XML namespace");
5997 	    return (NULL);
5998 	}
5999 	memset(ns, 0, sizeof(xmlNs));
6000 	ns->type = XML_LOCAL_NAMESPACE;
6001 	ns->href = xmlStrdup(XML_XML_NAMESPACE);
6002 	ns->prefix = xmlStrdup((const xmlChar *)"xml");
6003 	doc->oldNs = ns;
6004 	return (ns);
6005     }
6006 }
6007 
6008 /**
6009  * xmlSearchNs:
6010  * @doc:  the document
6011  * @node:  the current node
6012  * @nameSpace:  the namespace prefix
6013  *
6014  * Search a Ns registered under a given name space for a document.
6015  * recurse on the parents until it finds the defined namespace
6016  * or return NULL otherwise.
6017  * @nameSpace can be NULL, this is a search for the default namespace.
6018  * We don't allow to cross entities boundaries. If you don't declare
6019  * the namespace within those you will be in troubles !!! A warning
6020  * is generated to cover this case.
6021  *
6022  * Returns the namespace pointer or NULL.
6023  */
6024 xmlNsPtr
xmlSearchNs(xmlDocPtr doc,xmlNodePtr node,const xmlChar * nameSpace)6025 xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
6026 
6027     xmlNsPtr cur;
6028     const xmlNode *orig = node;
6029 
6030     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL);
6031     if ((nameSpace != NULL) &&
6032 	(xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
6033 	if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
6034 	    /*
6035 	     * The XML-1.0 namespace is normally held on the root
6036 	     * element. In this case exceptionally create it on the
6037 	     * node element.
6038 	     */
6039 	    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
6040 	    if (cur == NULL) {
6041 		xmlTreeErrMemory("searching namespace");
6042 		return(NULL);
6043 	    }
6044 	    memset(cur, 0, sizeof(xmlNs));
6045 	    cur->type = XML_LOCAL_NAMESPACE;
6046 	    cur->href = xmlStrdup(XML_XML_NAMESPACE);
6047 	    cur->prefix = xmlStrdup((const xmlChar *)"xml");
6048 	    cur->next = node->nsDef;
6049 	    node->nsDef = cur;
6050 	    return(cur);
6051 	}
6052 	if (doc == NULL) {
6053 	    doc = node->doc;
6054 	    if (doc == NULL)
6055 		return(NULL);
6056 	}
6057 	/*
6058 	* Return the XML namespace declaration held by the doc.
6059 	*/
6060 	if (doc->oldNs == NULL)
6061 	    return(xmlTreeEnsureXMLDecl(doc));
6062 	else
6063 	    return(doc->oldNs);
6064     }
6065     while (node != NULL) {
6066 	if ((node->type == XML_ENTITY_REF_NODE) ||
6067 	    (node->type == XML_ENTITY_NODE) ||
6068 	    (node->type == XML_ENTITY_DECL))
6069 	    return(NULL);
6070 	if (node->type == XML_ELEMENT_NODE) {
6071 	    cur = node->nsDef;
6072 	    while (cur != NULL) {
6073 		if ((cur->prefix == NULL) && (nameSpace == NULL) &&
6074 		    (cur->href != NULL))
6075 		    return(cur);
6076 		if ((cur->prefix != NULL) && (nameSpace != NULL) &&
6077 		    (cur->href != NULL) &&
6078 		    (xmlStrEqual(cur->prefix, nameSpace)))
6079 		    return(cur);
6080 		cur = cur->next;
6081 	    }
6082 	    if (orig != node) {
6083 	        cur = node->ns;
6084 	        if (cur != NULL) {
6085 		    if ((cur->prefix == NULL) && (nameSpace == NULL) &&
6086 		        (cur->href != NULL))
6087 		        return(cur);
6088 		    if ((cur->prefix != NULL) && (nameSpace != NULL) &&
6089 		        (cur->href != NULL) &&
6090 		        (xmlStrEqual(cur->prefix, nameSpace)))
6091 		        return(cur);
6092 	        }
6093 	    }
6094 	}
6095 	node = node->parent;
6096     }
6097     return(NULL);
6098 }
6099 
6100 /**
6101  * xmlNsInScope:
6102  * @doc:  the document
6103  * @node:  the current node
6104  * @ancestor:  the ancestor carrying the namespace
6105  * @prefix:  the namespace prefix
6106  *
6107  * Verify that the given namespace held on @ancestor is still in scope
6108  * on node.
6109  *
6110  * Returns 1 if true, 0 if false and -1 in case of error.
6111  */
6112 static int
xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED,xmlNodePtr node,xmlNodePtr ancestor,const xmlChar * prefix)6113 xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
6114              xmlNodePtr ancestor, const xmlChar * prefix)
6115 {
6116     xmlNsPtr tst;
6117 
6118     while ((node != NULL) && (node != ancestor)) {
6119         if ((node->type == XML_ENTITY_REF_NODE) ||
6120             (node->type == XML_ENTITY_NODE) ||
6121             (node->type == XML_ENTITY_DECL))
6122             return (-1);
6123         if (node->type == XML_ELEMENT_NODE) {
6124             tst = node->nsDef;
6125             while (tst != NULL) {
6126                 if ((tst->prefix == NULL)
6127                     && (prefix == NULL))
6128                     return (0);
6129                 if ((tst->prefix != NULL)
6130                     && (prefix != NULL)
6131                     && (xmlStrEqual(tst->prefix, prefix)))
6132                     return (0);
6133                 tst = tst->next;
6134             }
6135         }
6136         node = node->parent;
6137     }
6138     if (node != ancestor)
6139         return (-1);
6140     return (1);
6141 }
6142 
6143 /**
6144  * xmlSearchNsByHref:
6145  * @doc:  the document
6146  * @node:  the current node
6147  * @href:  the namespace value
6148  *
6149  * Search a Ns aliasing a given URI. Recurse on the parents until it finds
6150  * the defined namespace or return NULL otherwise.
6151  * Returns the namespace pointer or NULL.
6152  */
6153 xmlNsPtr
xmlSearchNsByHref(xmlDocPtr doc,xmlNodePtr node,const xmlChar * href)6154 xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
6155 {
6156     xmlNsPtr cur;
6157     xmlNodePtr orig = node;
6158     int is_attr;
6159 
6160     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (href == NULL))
6161         return (NULL);
6162     if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
6163         /*
6164          * Only the document can hold the XML spec namespace.
6165          */
6166         if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
6167             /*
6168              * The XML-1.0 namespace is normally held on the root
6169              * element. In this case exceptionally create it on the
6170              * node element.
6171              */
6172             cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
6173             if (cur == NULL) {
6174 		xmlTreeErrMemory("searching namespace");
6175                 return (NULL);
6176             }
6177             memset(cur, 0, sizeof(xmlNs));
6178             cur->type = XML_LOCAL_NAMESPACE;
6179             cur->href = xmlStrdup(XML_XML_NAMESPACE);
6180             cur->prefix = xmlStrdup((const xmlChar *) "xml");
6181             cur->next = node->nsDef;
6182             node->nsDef = cur;
6183             return (cur);
6184         }
6185 	if (doc == NULL) {
6186 	    doc = node->doc;
6187 	    if (doc == NULL)
6188 		return(NULL);
6189 	}
6190 	/*
6191 	* Return the XML namespace declaration held by the doc.
6192 	*/
6193 	if (doc->oldNs == NULL)
6194 	    return(xmlTreeEnsureXMLDecl(doc));
6195 	else
6196 	    return(doc->oldNs);
6197     }
6198     is_attr = (node->type == XML_ATTRIBUTE_NODE);
6199     while (node != NULL) {
6200         if ((node->type == XML_ENTITY_REF_NODE) ||
6201             (node->type == XML_ENTITY_NODE) ||
6202             (node->type == XML_ENTITY_DECL))
6203             return (NULL);
6204         if (node->type == XML_ELEMENT_NODE) {
6205             cur = node->nsDef;
6206             while (cur != NULL) {
6207                 if ((cur->href != NULL) && (href != NULL) &&
6208                     (xmlStrEqual(cur->href, href))) {
6209 		    if (((!is_attr) || (cur->prefix != NULL)) &&
6210 		        (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
6211 			return (cur);
6212                 }
6213                 cur = cur->next;
6214             }
6215             if (orig != node) {
6216                 cur = node->ns;
6217                 if (cur != NULL) {
6218                     if ((cur->href != NULL) && (href != NULL) &&
6219                         (xmlStrEqual(cur->href, href))) {
6220 			if (((!is_attr) || (cur->prefix != NULL)) &&
6221 		            (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
6222 			    return (cur);
6223                     }
6224                 }
6225             }
6226         }
6227         node = node->parent;
6228     }
6229     return (NULL);
6230 }
6231 
6232 /**
6233  * xmlNewReconciledNs:
6234  * @doc:  the document
6235  * @tree:  a node expected to hold the new namespace
6236  * @ns:  the original namespace
6237  *
6238  * This function tries to locate a namespace definition in a tree
6239  * ancestors, or create a new namespace definition node similar to
6240  * @ns trying to reuse the same prefix. However if the given prefix is
6241  * null (default namespace) or reused within the subtree defined by
6242  * @tree or on one of its ancestors then a new prefix is generated.
6243  * Returns the (new) namespace definition or NULL in case of error
6244  */
6245 static xmlNsPtr
xmlNewReconciledNs(xmlDocPtr doc,xmlNodePtr tree,xmlNsPtr ns)6246 xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
6247     xmlNsPtr def;
6248     xmlChar prefix[50];
6249     int counter = 1;
6250 
6251     if ((tree == NULL) || (tree->type != XML_ELEMENT_NODE)) {
6252 #ifdef DEBUG_TREE
6253         xmlGenericError(xmlGenericErrorContext,
6254 		"xmlNewReconciledNs : tree == NULL\n");
6255 #endif
6256 	return(NULL);
6257     }
6258     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) {
6259 #ifdef DEBUG_TREE
6260         xmlGenericError(xmlGenericErrorContext,
6261 		"xmlNewReconciledNs : ns == NULL\n");
6262 #endif
6263 	return(NULL);
6264     }
6265     /*
6266      * Search an existing namespace definition inherited.
6267      */
6268     def = xmlSearchNsByHref(doc, tree, ns->href);
6269     if (def != NULL)
6270         return(def);
6271 
6272     /*
6273      * Find a close prefix which is not already in use.
6274      * Let's strip namespace prefixes longer than 20 chars !
6275      */
6276     if (ns->prefix == NULL)
6277 	snprintf((char *) prefix, sizeof(prefix), "default");
6278     else
6279 	snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
6280 
6281     def = xmlSearchNs(doc, tree, prefix);
6282     while (def != NULL) {
6283         if (counter > 1000) return(NULL);
6284 	if (ns->prefix == NULL)
6285 	    snprintf((char *) prefix, sizeof(prefix), "default%d", counter++);
6286 	else
6287 	    snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
6288 		(char *)ns->prefix, counter++);
6289 	def = xmlSearchNs(doc, tree, prefix);
6290     }
6291 
6292     /*
6293      * OK, now we are ready to create a new one.
6294      */
6295     def = xmlNewNs(tree, ns->href, prefix);
6296     return(def);
6297 }
6298 
6299 #ifdef LIBXML_TREE_ENABLED
6300 /**
6301  * xmlReconciliateNs:
6302  * @doc:  the document
6303  * @tree:  a node defining the subtree to reconciliate
6304  *
6305  * This function checks that all the namespaces declared within the given
6306  * tree are properly declared. This is needed for example after Copy or Cut
6307  * and then paste operations. The subtree may still hold pointers to
6308  * namespace declarations outside the subtree or invalid/masked. As much
6309  * as possible the function try to reuse the existing namespaces found in
6310  * the new environment. If not possible the new namespaces are redeclared
6311  * on @tree at the top of the given subtree.
6312  * Returns the number of namespace declarations created or -1 in case of error.
6313  */
6314 int
xmlReconciliateNs(xmlDocPtr doc,xmlNodePtr tree)6315 xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
6316     xmlNsPtr *oldNs = NULL;
6317     xmlNsPtr *newNs = NULL;
6318     int sizeCache = 0;
6319     int nbCache = 0;
6320 
6321     xmlNsPtr n;
6322     xmlNodePtr node = tree;
6323     xmlAttrPtr attr;
6324     int ret = 0, i;
6325 
6326     if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
6327     if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
6328     if (node->doc != doc) return(-1);
6329     while (node != NULL) {
6330         /*
6331 	 * Reconciliate the node namespace
6332 	 */
6333 	if (node->ns != NULL) {
6334 	    /*
6335 	     * initialize the cache if needed
6336 	     */
6337 	    if (sizeCache == 0) {
6338 		sizeCache = 10;
6339 		oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6340 					       sizeof(xmlNsPtr));
6341 		if (oldNs == NULL) {
6342 		    xmlTreeErrMemory("fixing namespaces");
6343 		    return(-1);
6344 		}
6345 		newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6346 					       sizeof(xmlNsPtr));
6347 		if (newNs == NULL) {
6348 		    xmlTreeErrMemory("fixing namespaces");
6349 		    xmlFree(oldNs);
6350 		    return(-1);
6351 		}
6352 	    }
6353 	    for (i = 0;i < nbCache;i++) {
6354 	        if (oldNs[i] == node->ns) {
6355 		    node->ns = newNs[i];
6356 		    break;
6357 		}
6358 	    }
6359 	    if (i == nbCache) {
6360 	        /*
6361 		 * OK we need to recreate a new namespace definition
6362 		 */
6363 		n = xmlNewReconciledNs(doc, tree, node->ns);
6364 		if (n != NULL) { /* :-( what if else ??? */
6365 		    /*
6366 		     * check if we need to grow the cache buffers.
6367 		     */
6368 		    if (sizeCache <= nbCache) {
6369 		        sizeCache *= 2;
6370 			oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
6371 			                               sizeof(xmlNsPtr));
6372 		        if (oldNs == NULL) {
6373 			    xmlTreeErrMemory("fixing namespaces");
6374 			    xmlFree(newNs);
6375 			    return(-1);
6376 			}
6377 			newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
6378 			                               sizeof(xmlNsPtr));
6379 		        if (newNs == NULL) {
6380 			    xmlTreeErrMemory("fixing namespaces");
6381 			    xmlFree(oldNs);
6382 			    return(-1);
6383 			}
6384 		    }
6385 		    newNs[nbCache] = n;
6386 		    oldNs[nbCache++] = node->ns;
6387 		    node->ns = n;
6388                 }
6389 	    }
6390 	}
6391 	/*
6392 	 * now check for namespace held by attributes on the node.
6393 	 */
6394 	if (node->type == XML_ELEMENT_NODE) {
6395 	    attr = node->properties;
6396 	    while (attr != NULL) {
6397 		if (attr->ns != NULL) {
6398 		    /*
6399 		     * initialize the cache if needed
6400 		     */
6401 		    if (sizeCache == 0) {
6402 			sizeCache = 10;
6403 			oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6404 						       sizeof(xmlNsPtr));
6405 			if (oldNs == NULL) {
6406 			    xmlTreeErrMemory("fixing namespaces");
6407 			    return(-1);
6408 			}
6409 			newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
6410 						       sizeof(xmlNsPtr));
6411 			if (newNs == NULL) {
6412 			    xmlTreeErrMemory("fixing namespaces");
6413 			    xmlFree(oldNs);
6414 			    return(-1);
6415 			}
6416 		    }
6417 		    for (i = 0;i < nbCache;i++) {
6418 			if (oldNs[i] == attr->ns) {
6419 			    attr->ns = newNs[i];
6420 			    break;
6421 			}
6422 		    }
6423 		    if (i == nbCache) {
6424 			/*
6425 			 * OK we need to recreate a new namespace definition
6426 			 */
6427 			n = xmlNewReconciledNs(doc, tree, attr->ns);
6428 			if (n != NULL) { /* :-( what if else ??? */
6429 			    /*
6430 			     * check if we need to grow the cache buffers.
6431 			     */
6432 			    if (sizeCache <= nbCache) {
6433 				sizeCache *= 2;
6434 				oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
6435 				           sizeCache * sizeof(xmlNsPtr));
6436 				if (oldNs == NULL) {
6437 				    xmlTreeErrMemory("fixing namespaces");
6438 				    xmlFree(newNs);
6439 				    return(-1);
6440 				}
6441 				newNs = (xmlNsPtr *) xmlRealloc(newNs,
6442 				           sizeCache * sizeof(xmlNsPtr));
6443 				if (newNs == NULL) {
6444 				    xmlTreeErrMemory("fixing namespaces");
6445 				    xmlFree(oldNs);
6446 				    return(-1);
6447 				}
6448 			    }
6449 			    newNs[nbCache] = n;
6450 			    oldNs[nbCache++] = attr->ns;
6451 			    attr->ns = n;
6452 			}
6453 		    }
6454 		}
6455 		attr = attr->next;
6456 	    }
6457 	}
6458 
6459 	/*
6460 	 * Browse the full subtree, deep first
6461 	 */
6462         if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
6463 	    /* deep first */
6464 	    node = node->children;
6465 	} else if ((node != tree) && (node->next != NULL)) {
6466 	    /* then siblings */
6467 	    node = node->next;
6468 	} else if (node != tree) {
6469 	    /* go up to parents->next if needed */
6470 	    while (node != tree) {
6471 	        if (node->parent != NULL)
6472 		    node = node->parent;
6473 		if ((node != tree) && (node->next != NULL)) {
6474 		    node = node->next;
6475 		    break;
6476 		}
6477 		if (node->parent == NULL) {
6478 		    node = NULL;
6479 		    break;
6480 		}
6481 	    }
6482 	    /* exit condition */
6483 	    if (node == tree)
6484 	        node = NULL;
6485 	} else
6486 	    break;
6487     }
6488     if (oldNs != NULL)
6489 	xmlFree(oldNs);
6490     if (newNs != NULL)
6491 	xmlFree(newNs);
6492     return(ret);
6493 }
6494 #endif /* LIBXML_TREE_ENABLED */
6495 
6496 static xmlAttrPtr
xmlGetPropNodeInternal(const xmlNode * node,const xmlChar * name,const xmlChar * nsName,int useDTD)6497 xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name,
6498 		       const xmlChar *nsName, int useDTD)
6499 {
6500     xmlAttrPtr prop;
6501 
6502     if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6503 	return(NULL);
6504 
6505     if (node->properties != NULL) {
6506 	prop = node->properties;
6507 	if (nsName == NULL) {
6508 	    /*
6509 	    * We want the attr to be in no namespace.
6510 	    */
6511 	    do {
6512 		if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) {
6513 		    return(prop);
6514 		}
6515 		prop = prop->next;
6516 	    } while (prop != NULL);
6517 	} else {
6518 	    /*
6519 	    * We want the attr to be in the specified namespace.
6520 	    */
6521 	    do {
6522 		if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) &&
6523 		    ((prop->ns->href == nsName) ||
6524 		     xmlStrEqual(prop->ns->href, nsName)))
6525 		{
6526 		    return(prop);
6527 		}
6528 		prop = prop->next;
6529 	    } while (prop != NULL);
6530 	}
6531     }
6532 
6533 #ifdef LIBXML_TREE_ENABLED
6534     if (! useDTD)
6535 	return(NULL);
6536     /*
6537      * Check if there is a default/fixed attribute declaration in
6538      * the internal or external subset.
6539      */
6540     if ((node->doc != NULL) && (node->doc->intSubset != NULL)) {
6541 	xmlDocPtr doc = node->doc;
6542 	xmlAttributePtr attrDecl = NULL;
6543 	xmlChar *elemQName, *tmpstr = NULL;
6544 
6545 	/*
6546 	* We need the QName of the element for the DTD-lookup.
6547 	*/
6548 	if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
6549 	    tmpstr = xmlStrdup(node->ns->prefix);
6550 	    tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
6551 	    tmpstr = xmlStrcat(tmpstr, node->name);
6552 	    if (tmpstr == NULL)
6553 		return(NULL);
6554 	    elemQName = tmpstr;
6555 	} else
6556 	    elemQName = (xmlChar *) node->name;
6557 	if (nsName == NULL) {
6558 	    /*
6559 	    * The common and nice case: Attr in no namespace.
6560 	    */
6561 	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
6562 		elemQName, name, NULL);
6563 	    if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
6564 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
6565 		    elemQName, name, NULL);
6566 	    }
6567 	} else {
6568 	    xmlNsPtr *nsList, *cur;
6569 
6570 	    /*
6571 	    * The ugly case: Search using the prefixes of in-scope
6572 	    * ns-decls corresponding to @nsName.
6573 	    */
6574 	    nsList = xmlGetNsList(node->doc, node);
6575 	    if (nsList == NULL) {
6576 		if (tmpstr != NULL)
6577 		    xmlFree(tmpstr);
6578 		return(NULL);
6579 	    }
6580 	    cur = nsList;
6581 	    while (*cur != NULL) {
6582 		if (xmlStrEqual((*cur)->href, nsName)) {
6583 		    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName,
6584 			name, (*cur)->prefix);
6585 		    if (attrDecl)
6586 			break;
6587 		    if (doc->extSubset != NULL) {
6588 			attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName,
6589 			    name, (*cur)->prefix);
6590 			if (attrDecl)
6591 			    break;
6592 		    }
6593 		}
6594 		cur++;
6595 	    }
6596 	    xmlFree(nsList);
6597 	}
6598 	if (tmpstr != NULL)
6599 	    xmlFree(tmpstr);
6600 	/*
6601 	* Only default/fixed attrs are relevant.
6602 	*/
6603 	if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6604 	    return((xmlAttrPtr) attrDecl);
6605     }
6606 #endif /* LIBXML_TREE_ENABLED */
6607     return(NULL);
6608 }
6609 
6610 static xmlChar*
xmlGetPropNodeValueInternal(const xmlAttr * prop)6611 xmlGetPropNodeValueInternal(const xmlAttr *prop)
6612 {
6613     if (prop == NULL)
6614 	return(NULL);
6615     if (prop->type == XML_ATTRIBUTE_NODE) {
6616 	/*
6617 	* Note that we return at least the empty string.
6618 	*   TODO: Do we really always want that?
6619 	*/
6620 	if (prop->children != NULL) {
6621 	    if ((prop->children->next == NULL) &&
6622 		((prop->children->type == XML_TEXT_NODE) ||
6623 		(prop->children->type == XML_CDATA_SECTION_NODE)))
6624 	    {
6625 		/*
6626 		* Optimization for the common case: only 1 text node.
6627 		*/
6628 		return(xmlStrdup(prop->children->content));
6629 	    } else {
6630 		xmlChar *ret;
6631 
6632 		ret = xmlNodeListGetString(prop->doc, prop->children, 1);
6633 		if (ret != NULL)
6634 		    return(ret);
6635 	    }
6636 	}
6637 	return(xmlStrdup((xmlChar *)""));
6638     } else if (prop->type == XML_ATTRIBUTE_DECL) {
6639 	return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
6640     }
6641     return(NULL);
6642 }
6643 
6644 /**
6645  * xmlHasProp:
6646  * @node:  the node
6647  * @name:  the attribute name
6648  *
6649  * Search an attribute associated to a node
6650  * This function also looks in DTD attribute declaration for #FIXED or
6651  * default declaration values unless DTD use has been turned off.
6652  *
6653  * Returns the attribute or the attribute declaration or NULL if
6654  *         neither was found.
6655  */
6656 xmlAttrPtr
xmlHasProp(const xmlNode * node,const xmlChar * name)6657 xmlHasProp(const xmlNode *node, const xmlChar *name) {
6658     xmlAttrPtr prop;
6659     xmlDocPtr doc;
6660 
6661     if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL))
6662         return(NULL);
6663     /*
6664      * Check on the properties attached to the node
6665      */
6666     prop = node->properties;
6667     while (prop != NULL) {
6668         if (xmlStrEqual(prop->name, name))  {
6669 	    return(prop);
6670         }
6671 	prop = prop->next;
6672     }
6673     if (!xmlCheckDTD) return(NULL);
6674 
6675     /*
6676      * Check if there is a default declaration in the internal
6677      * or external subsets
6678      */
6679     doc =  node->doc;
6680     if (doc != NULL) {
6681         xmlAttributePtr attrDecl;
6682         if (doc->intSubset != NULL) {
6683 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
6684 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
6685 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
6686             if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL))
6687               /* return attribute declaration only if a default value is given
6688                  (that includes #FIXED declarations) */
6689 		return((xmlAttrPtr) attrDecl);
6690 	}
6691     }
6692     return(NULL);
6693 }
6694 
6695 /**
6696  * xmlHasNsProp:
6697  * @node:  the node
6698  * @name:  the attribute name
6699  * @nameSpace:  the URI of the namespace
6700  *
6701  * Search for an attribute associated to a node
6702  * This attribute has to be anchored in the namespace specified.
6703  * This does the entity substitution.
6704  * This function looks in DTD attribute declaration for #FIXED or
6705  * default declaration values unless DTD use has been turned off.
6706  * Note that a namespace of NULL indicates to use the default namespace.
6707  *
6708  * Returns the attribute or the attribute declaration or NULL
6709  *     if neither was found.
6710  */
6711 xmlAttrPtr
xmlHasNsProp(const xmlNode * node,const xmlChar * name,const xmlChar * nameSpace)6712 xmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) {
6713 
6714     return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD));
6715 }
6716 
6717 /**
6718  * xmlGetProp:
6719  * @node:  the node
6720  * @name:  the attribute name
6721  *
6722  * Search and get the value of an attribute associated to a node
6723  * This does the entity substitution.
6724  * This function looks in DTD attribute declaration for #FIXED or
6725  * default declaration values unless DTD use has been turned off.
6726  * NOTE: this function acts independently of namespaces associated
6727  *       to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp()
6728  *       for namespace aware processing.
6729  *
6730  * Returns the attribute value or NULL if not found.
6731  *     It's up to the caller to free the memory with xmlFree().
6732  */
6733 xmlChar *
xmlGetProp(const xmlNode * node,const xmlChar * name)6734 xmlGetProp(const xmlNode *node, const xmlChar *name) {
6735     xmlAttrPtr prop;
6736 
6737     prop = xmlHasProp(node, name);
6738     if (prop == NULL)
6739 	return(NULL);
6740     return(xmlGetPropNodeValueInternal(prop));
6741 }
6742 
6743 /**
6744  * xmlGetNoNsProp:
6745  * @node:  the node
6746  * @name:  the attribute name
6747  *
6748  * Search and get the value of an attribute associated to a node
6749  * This does the entity substitution.
6750  * This function looks in DTD attribute declaration for #FIXED or
6751  * default declaration values unless DTD use has been turned off.
6752  * This function is similar to xmlGetProp except it will accept only
6753  * an attribute in no namespace.
6754  *
6755  * Returns the attribute value or NULL if not found.
6756  *     It's up to the caller to free the memory with xmlFree().
6757  */
6758 xmlChar *
xmlGetNoNsProp(const xmlNode * node,const xmlChar * name)6759 xmlGetNoNsProp(const xmlNode *node, const xmlChar *name) {
6760     xmlAttrPtr prop;
6761 
6762     prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD);
6763     if (prop == NULL)
6764 	return(NULL);
6765     return(xmlGetPropNodeValueInternal(prop));
6766 }
6767 
6768 /**
6769  * xmlGetNsProp:
6770  * @node:  the node
6771  * @name:  the attribute name
6772  * @nameSpace:  the URI of the namespace
6773  *
6774  * Search and get the value of an attribute associated to a node
6775  * This attribute has to be anchored in the namespace specified.
6776  * This does the entity substitution.
6777  * This function looks in DTD attribute declaration for #FIXED or
6778  * default declaration values unless DTD use has been turned off.
6779  *
6780  * Returns the attribute value or NULL if not found.
6781  *     It's up to the caller to free the memory with xmlFree().
6782  */
6783 xmlChar *
xmlGetNsProp(const xmlNode * node,const xmlChar * name,const xmlChar * nameSpace)6784 xmlGetNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) {
6785     xmlAttrPtr prop;
6786 
6787     prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD);
6788     if (prop == NULL)
6789 	return(NULL);
6790     return(xmlGetPropNodeValueInternal(prop));
6791 }
6792 
6793 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
6794 /**
6795  * xmlUnsetProp:
6796  * @node:  the node
6797  * @name:  the attribute name
6798  *
6799  * Remove an attribute carried by a node.
6800  * This handles only attributes in no namespace.
6801  * Returns 0 if successful, -1 if not found
6802  */
6803 int
xmlUnsetProp(xmlNodePtr node,const xmlChar * name)6804 xmlUnsetProp(xmlNodePtr node, const xmlChar *name) {
6805     xmlAttrPtr prop;
6806 
6807     prop = xmlGetPropNodeInternal(node, name, NULL, 0);
6808     if (prop == NULL)
6809 	return(-1);
6810     xmlUnlinkNode((xmlNodePtr) prop);
6811     xmlFreeProp(prop);
6812     return(0);
6813 }
6814 
6815 /**
6816  * xmlUnsetNsProp:
6817  * @node:  the node
6818  * @ns:  the namespace definition
6819  * @name:  the attribute name
6820  *
6821  * Remove an attribute carried by a node.
6822  * Returns 0 if successful, -1 if not found
6823  */
6824 int
xmlUnsetNsProp(xmlNodePtr node,xmlNsPtr ns,const xmlChar * name)6825 xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) {
6826     xmlAttrPtr prop;
6827 
6828     prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6829     if (prop == NULL)
6830 	return(-1);
6831     xmlUnlinkNode((xmlNodePtr) prop);
6832     xmlFreeProp(prop);
6833     return(0);
6834 }
6835 #endif
6836 
6837 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED)
6838 /**
6839  * xmlSetProp:
6840  * @node:  the node
6841  * @name:  the attribute name (a QName)
6842  * @value:  the attribute value
6843  *
6844  * Set (or reset) an attribute carried by a node.
6845  * If @name has a prefix, then the corresponding
6846  * namespace-binding will be used, if in scope; it is an
6847  * error it there's no such ns-binding for the prefix in
6848  * scope.
6849  * Returns the attribute pointer.
6850  *
6851  */
6852 xmlAttrPtr
xmlSetProp(xmlNodePtr node,const xmlChar * name,const xmlChar * value)6853 xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
6854     int len;
6855     const xmlChar *nqname;
6856 
6857     if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
6858 	return(NULL);
6859 
6860     /*
6861      * handle QNames
6862      */
6863     nqname = xmlSplitQName3(name, &len);
6864     if (nqname != NULL) {
6865         xmlNsPtr ns;
6866 	xmlChar *prefix = xmlStrndup(name, len);
6867 	ns = xmlSearchNs(node->doc, node, prefix);
6868 	if (prefix != NULL)
6869 	    xmlFree(prefix);
6870 	if (ns != NULL)
6871 	    return(xmlSetNsProp(node, ns, nqname, value));
6872     }
6873     return(xmlSetNsProp(node, NULL, name, value));
6874 }
6875 
6876 /**
6877  * xmlSetNsProp:
6878  * @node:  the node
6879  * @ns:  the namespace definition
6880  * @name:  the attribute name
6881  * @value:  the attribute value
6882  *
6883  * Set (or reset) an attribute carried by a node.
6884  * The ns structure must be in scope, this is not checked
6885  *
6886  * Returns the attribute pointer.
6887  */
6888 xmlAttrPtr
xmlSetNsProp(xmlNodePtr node,xmlNsPtr ns,const xmlChar * name,const xmlChar * value)6889 xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
6890 	     const xmlChar *value)
6891 {
6892     xmlAttrPtr prop;
6893 
6894     if (ns && (ns->href == NULL))
6895 	return(NULL);
6896     prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
6897     if (prop != NULL) {
6898 	/*
6899 	* Modify the attribute's value.
6900 	*/
6901 	if (prop->atype == XML_ATTRIBUTE_ID) {
6902 	    xmlRemoveID(node->doc, prop);
6903 	    prop->atype = XML_ATTRIBUTE_ID;
6904 	}
6905 	if (prop->children != NULL)
6906 	    xmlFreeNodeList(prop->children);
6907 	prop->children = NULL;
6908 	prop->last = NULL;
6909 	prop->ns = ns;
6910 	if (value != NULL) {
6911 	    xmlNodePtr tmp;
6912 
6913 	    if(!xmlCheckUTF8(value)) {
6914 	        xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc,
6915 	                   NULL);
6916                 if (node->doc != NULL)
6917                     node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
6918 	    }
6919 	    prop->children = xmlNewDocText(node->doc, value);
6920 	    prop->last = NULL;
6921 	    tmp = prop->children;
6922 	    while (tmp != NULL) {
6923 		tmp->parent = (xmlNodePtr) prop;
6924 		if (tmp->next == NULL)
6925 		    prop->last = tmp;
6926 		tmp = tmp->next;
6927 	    }
6928 	}
6929 	if (prop->atype == XML_ATTRIBUTE_ID)
6930 	    xmlAddID(NULL, node->doc, value, prop);
6931 	return(prop);
6932     }
6933     /*
6934     * No equal attr found; create a new one.
6935     */
6936     return(xmlNewPropInternal(node, ns, name, value, 0));
6937 }
6938 
6939 #endif /* LIBXML_TREE_ENABLED */
6940 
6941 /**
6942  * xmlNodeIsText:
6943  * @node:  the node
6944  *
6945  * Is this node a Text node ?
6946  * Returns 1 yes, 0 no
6947  */
6948 int
xmlNodeIsText(const xmlNode * node)6949 xmlNodeIsText(const xmlNode *node) {
6950     if (node == NULL) return(0);
6951 
6952     if (node->type == XML_TEXT_NODE) return(1);
6953     return(0);
6954 }
6955 
6956 /**
6957  * xmlIsBlankNode:
6958  * @node:  the node
6959  *
6960  * Checks whether this node is an empty or whitespace only
6961  * (and possibly ignorable) text-node.
6962  *
6963  * Returns 1 yes, 0 no
6964  */
6965 int
xmlIsBlankNode(const xmlNode * node)6966 xmlIsBlankNode(const xmlNode *node) {
6967     const xmlChar *cur;
6968     if (node == NULL) return(0);
6969 
6970     if ((node->type != XML_TEXT_NODE) &&
6971         (node->type != XML_CDATA_SECTION_NODE))
6972 	return(0);
6973     if (node->content == NULL) return(1);
6974     cur = node->content;
6975     while (*cur != 0) {
6976 	if (!IS_BLANK_CH(*cur)) return(0);
6977 	cur++;
6978     }
6979 
6980     return(1);
6981 }
6982 
6983 /**
6984  * xmlTextConcat:
6985  * @node:  the node
6986  * @content:  the content
6987  * @len:  @content length
6988  *
6989  * Concat the given string at the end of the existing node content
6990  *
6991  * Returns -1 in case of error, 0 otherwise
6992  */
6993 
6994 int
xmlTextConcat(xmlNodePtr node,const xmlChar * content,int len)6995 xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
6996     if (node == NULL) return(-1);
6997 
6998     if ((node->type != XML_TEXT_NODE) &&
6999         (node->type != XML_CDATA_SECTION_NODE) &&
7000 	(node->type != XML_COMMENT_NODE) &&
7001 	(node->type != XML_PI_NODE)) {
7002 #ifdef DEBUG_TREE
7003 	xmlGenericError(xmlGenericErrorContext,
7004 		"xmlTextConcat: node is not text nor CDATA\n");
7005 #endif
7006         return(-1);
7007     }
7008     /* need to check if content is currently in the dictionary */
7009     if ((node->content == (xmlChar *) &(node->properties)) ||
7010         ((node->doc != NULL) && (node->doc->dict != NULL) &&
7011 		xmlDictOwns(node->doc->dict, node->content))) {
7012 	node->content = xmlStrncatNew(node->content, content, len);
7013     } else {
7014         node->content = xmlStrncat(node->content, content, len);
7015     }
7016     node->properties = NULL;
7017     if (node->content == NULL)
7018         return(-1);
7019     return(0);
7020 }
7021 
7022 /************************************************************************
7023  *									*
7024  *			Output : to a FILE or in memory			*
7025  *									*
7026  ************************************************************************/
7027 
7028 /**
7029  * xmlBufferCreate:
7030  *
7031  * routine to create an XML buffer.
7032  * returns the new structure.
7033  */
7034 xmlBufferPtr
xmlBufferCreate(void)7035 xmlBufferCreate(void) {
7036     xmlBufferPtr ret;
7037 
7038     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
7039     if (ret == NULL) {
7040 	xmlTreeErrMemory("creating buffer");
7041         return(NULL);
7042     }
7043     ret->use = 0;
7044     ret->size = xmlDefaultBufferSize;
7045     ret->alloc = xmlBufferAllocScheme;
7046     ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
7047     if (ret->content == NULL) {
7048 	xmlTreeErrMemory("creating buffer");
7049 	xmlFree(ret);
7050         return(NULL);
7051     }
7052     ret->content[0] = 0;
7053     ret->contentIO = NULL;
7054     return(ret);
7055 }
7056 
7057 /**
7058  * xmlBufferCreateSize:
7059  * @size: initial size of buffer
7060  *
7061  * routine to create an XML buffer.
7062  * returns the new structure.
7063  */
7064 xmlBufferPtr
xmlBufferCreateSize(size_t size)7065 xmlBufferCreateSize(size_t size) {
7066     xmlBufferPtr ret;
7067 
7068     if (size >= UINT_MAX)
7069         return(NULL);
7070     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
7071     if (ret == NULL) {
7072 	xmlTreeErrMemory("creating buffer");
7073         return(NULL);
7074     }
7075     ret->use = 0;
7076     ret->alloc = xmlBufferAllocScheme;
7077     ret->size = (size ? size+1 : 0);         /* +1 for ending null */
7078     if (ret->size){
7079         ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
7080         if (ret->content == NULL) {
7081 	    xmlTreeErrMemory("creating buffer");
7082             xmlFree(ret);
7083             return(NULL);
7084         }
7085         ret->content[0] = 0;
7086     } else
7087 	ret->content = NULL;
7088     ret->contentIO = NULL;
7089     return(ret);
7090 }
7091 
7092 /**
7093  * xmlBufferDetach:
7094  * @buf:  the buffer
7095  *
7096  * Remove the string contained in a buffer and gie it back to the
7097  * caller. The buffer is reset to an empty content.
7098  * This doesn't work with immutable buffers as they can't be reset.
7099  *
7100  * Returns the previous string contained by the buffer.
7101  */
7102 xmlChar *
xmlBufferDetach(xmlBufferPtr buf)7103 xmlBufferDetach(xmlBufferPtr buf) {
7104     xmlChar *ret;
7105 
7106     if (buf == NULL)
7107         return(NULL);
7108     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
7109         return(NULL);
7110 
7111     ret = buf->content;
7112     buf->content = NULL;
7113     buf->size = 0;
7114     buf->use = 0;
7115 
7116     return ret;
7117 }
7118 
7119 
7120 /**
7121  * xmlBufferCreateStatic:
7122  * @mem: the memory area
7123  * @size:  the size in byte
7124  *
7125  * routine to create an XML buffer from an immutable memory area.
7126  * The area won't be modified nor copied, and is expected to be
7127  * present until the end of the buffer lifetime.
7128  *
7129  * returns the new structure.
7130  */
7131 xmlBufferPtr
xmlBufferCreateStatic(void * mem,size_t size)7132 xmlBufferCreateStatic(void *mem, size_t size) {
7133     xmlBufferPtr ret;
7134 
7135     if ((mem == NULL) || (size == 0))
7136         return(NULL);
7137     if (size > UINT_MAX)
7138         return(NULL);
7139 
7140     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
7141     if (ret == NULL) {
7142 	xmlTreeErrMemory("creating buffer");
7143         return(NULL);
7144     }
7145     ret->use = size;
7146     ret->size = size;
7147     ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
7148     ret->content = (xmlChar *) mem;
7149     return(ret);
7150 }
7151 
7152 /**
7153  * xmlBufferSetAllocationScheme:
7154  * @buf:  the buffer to tune
7155  * @scheme:  allocation scheme to use
7156  *
7157  * Sets the allocation scheme for this buffer
7158  */
7159 void
xmlBufferSetAllocationScheme(xmlBufferPtr buf,xmlBufferAllocationScheme scheme)7160 xmlBufferSetAllocationScheme(xmlBufferPtr buf,
7161                              xmlBufferAllocationScheme scheme) {
7162     if (buf == NULL) {
7163 #ifdef DEBUG_BUFFER
7164         xmlGenericError(xmlGenericErrorContext,
7165 		"xmlBufferSetAllocationScheme: buf == NULL\n");
7166 #endif
7167         return;
7168     }
7169     if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
7170         (buf->alloc == XML_BUFFER_ALLOC_IO)) return;
7171     if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
7172         (scheme == XML_BUFFER_ALLOC_EXACT) ||
7173         (scheme == XML_BUFFER_ALLOC_HYBRID) ||
7174         (scheme == XML_BUFFER_ALLOC_IMMUTABLE))
7175 	buf->alloc = scheme;
7176 }
7177 
7178 /**
7179  * xmlBufferFree:
7180  * @buf:  the buffer to free
7181  *
7182  * Frees an XML buffer. It frees both the content and the structure which
7183  * encapsulate it.
7184  */
7185 void
xmlBufferFree(xmlBufferPtr buf)7186 xmlBufferFree(xmlBufferPtr buf) {
7187     if (buf == NULL) {
7188 #ifdef DEBUG_BUFFER
7189         xmlGenericError(xmlGenericErrorContext,
7190 		"xmlBufferFree: buf == NULL\n");
7191 #endif
7192 	return;
7193     }
7194 
7195     if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7196         (buf->contentIO != NULL)) {
7197         xmlFree(buf->contentIO);
7198     } else if ((buf->content != NULL) &&
7199         (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
7200         xmlFree(buf->content);
7201     }
7202     xmlFree(buf);
7203 }
7204 
7205 /**
7206  * xmlBufferEmpty:
7207  * @buf:  the buffer
7208  *
7209  * empty a buffer.
7210  */
7211 void
xmlBufferEmpty(xmlBufferPtr buf)7212 xmlBufferEmpty(xmlBufferPtr buf) {
7213     if (buf == NULL) return;
7214     if (buf->content == NULL) return;
7215     buf->use = 0;
7216     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
7217         buf->content = BAD_CAST "";
7218     } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
7219                (buf->contentIO != NULL)) {
7220         size_t start_buf = buf->content - buf->contentIO;
7221 
7222 	buf->size += start_buf;
7223         buf->content = buf->contentIO;
7224         buf->content[0] = 0;
7225     } else {
7226         buf->content[0] = 0;
7227     }
7228 }
7229 
7230 /**
7231  * xmlBufferShrink:
7232  * @buf:  the buffer to dump
7233  * @len:  the number of xmlChar to remove
7234  *
7235  * Remove the beginning of an XML buffer.
7236  *
7237  * Returns the number of #xmlChar removed, or -1 in case of failure.
7238  */
7239 int
xmlBufferShrink(xmlBufferPtr buf,unsigned int len)7240 xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
7241     if (buf == NULL) return(-1);
7242     if (len == 0) return(0);
7243     if (len > buf->use) return(-1);
7244 
7245     buf->use -= len;
7246     if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
7247         ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
7248 	/*
7249 	 * we just move the content pointer, but also make sure
7250 	 * the perceived buffer size has shrinked accordingly
7251 	 */
7252         buf->content += len;
7253 	buf->size -= len;
7254 
7255         /*
7256 	 * sometimes though it maybe be better to really shrink
7257 	 * on IO buffers
7258 	 */
7259 	if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7260 	    size_t start_buf = buf->content - buf->contentIO;
7261 	    if (start_buf >= buf->size) {
7262 		memmove(buf->contentIO, &buf->content[0], buf->use);
7263 		buf->content = buf->contentIO;
7264 		buf->content[buf->use] = 0;
7265 		buf->size += start_buf;
7266 	    }
7267 	}
7268     } else {
7269 	memmove(buf->content, &buf->content[len], buf->use);
7270 	buf->content[buf->use] = 0;
7271     }
7272     return(len);
7273 }
7274 
7275 /**
7276  * xmlBufferGrow:
7277  * @buf:  the buffer
7278  * @len:  the minimum free size to allocate
7279  *
7280  * Grow the available space of an XML buffer.
7281  *
7282  * Returns the new available space or -1 in case of error
7283  */
7284 int
xmlBufferGrow(xmlBufferPtr buf,unsigned int len)7285 xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
7286     unsigned int size;
7287     xmlChar *newbuf;
7288 
7289     if (buf == NULL) return(-1);
7290 
7291     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
7292     if (len < buf->size - buf->use)
7293         return(0);
7294     if (len > UINT_MAX - buf->use)
7295         return(-1);
7296 
7297     if (buf->size > (size_t) len) {
7298         size = buf->size > UINT_MAX / 2 ? UINT_MAX : buf->size * 2;
7299     } else {
7300         size = buf->use + len;
7301         size = size > UINT_MAX - 100 ? UINT_MAX : size + 100;
7302     }
7303 
7304     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7305         size_t start_buf = buf->content - buf->contentIO;
7306 
7307 	newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
7308 	if (newbuf == NULL) {
7309 	    xmlTreeErrMemory("growing buffer");
7310 	    return(-1);
7311 	}
7312 	buf->contentIO = newbuf;
7313 	buf->content = newbuf + start_buf;
7314     } else {
7315 	newbuf = (xmlChar *) xmlRealloc(buf->content, size);
7316 	if (newbuf == NULL) {
7317 	    xmlTreeErrMemory("growing buffer");
7318 	    return(-1);
7319 	}
7320 	buf->content = newbuf;
7321     }
7322     buf->size = size;
7323     return(buf->size - buf->use);
7324 }
7325 
7326 /**
7327  * xmlBufferDump:
7328  * @file:  the file output
7329  * @buf:  the buffer to dump
7330  *
7331  * Dumps an XML buffer to  a FILE *.
7332  * Returns the number of #xmlChar written
7333  */
7334 int
xmlBufferDump(FILE * file,xmlBufferPtr buf)7335 xmlBufferDump(FILE *file, xmlBufferPtr buf) {
7336     int ret;
7337 
7338     if (buf == NULL) {
7339 #ifdef DEBUG_BUFFER
7340         xmlGenericError(xmlGenericErrorContext,
7341 		"xmlBufferDump: buf == NULL\n");
7342 #endif
7343 	return(0);
7344     }
7345     if (buf->content == NULL) {
7346 #ifdef DEBUG_BUFFER
7347         xmlGenericError(xmlGenericErrorContext,
7348 		"xmlBufferDump: buf->content == NULL\n");
7349 #endif
7350 	return(0);
7351     }
7352     if (file == NULL)
7353 	file = stdout;
7354     ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
7355     return(ret);
7356 }
7357 
7358 /**
7359  * xmlBufferContent:
7360  * @buf:  the buffer
7361  *
7362  * Function to extract the content of a buffer
7363  *
7364  * Returns the internal content
7365  */
7366 
7367 const xmlChar *
xmlBufferContent(const xmlBuffer * buf)7368 xmlBufferContent(const xmlBuffer *buf)
7369 {
7370     if(!buf)
7371         return NULL;
7372 
7373     return buf->content;
7374 }
7375 
7376 /**
7377  * xmlBufferLength:
7378  * @buf:  the buffer
7379  *
7380  * Function to get the length of a buffer
7381  *
7382  * Returns the length of data in the internal content
7383  */
7384 
7385 int
xmlBufferLength(const xmlBuffer * buf)7386 xmlBufferLength(const xmlBuffer *buf)
7387 {
7388     if(!buf)
7389         return 0;
7390 
7391     return buf->use;
7392 }
7393 
7394 /**
7395  * xmlBufferResize:
7396  * @buf:  the buffer to resize
7397  * @size:  the desired size
7398  *
7399  * Resize a buffer to accommodate minimum size of @size.
7400  *
7401  * Returns  0 in case of problems, 1 otherwise
7402  */
7403 int
xmlBufferResize(xmlBufferPtr buf,unsigned int size)7404 xmlBufferResize(xmlBufferPtr buf, unsigned int size)
7405 {
7406     unsigned int newSize;
7407     xmlChar* rebuf = NULL;
7408     size_t start_buf;
7409 
7410     if (buf == NULL)
7411         return(0);
7412 
7413     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
7414 
7415     /* Don't resize if we don't have to */
7416     if (size < buf->size)
7417         return 1;
7418 
7419     /* figure out new size */
7420     switch (buf->alloc){
7421 	case XML_BUFFER_ALLOC_IO:
7422 	case XML_BUFFER_ALLOC_DOUBLEIT:
7423 	    /*take care of empty case*/
7424             if (buf->size == 0)
7425                 newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
7426             else
7427                 newSize = buf->size;
7428 	    while (size > newSize) {
7429 	        if (newSize > UINT_MAX / 2) {
7430 	            xmlTreeErrMemory("growing buffer");
7431 	            return 0;
7432 	        }
7433 	        newSize *= 2;
7434 	    }
7435 	    break;
7436 	case XML_BUFFER_ALLOC_EXACT:
7437 	    newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
7438 	    break;
7439         case XML_BUFFER_ALLOC_HYBRID:
7440             if (buf->use < BASE_BUFFER_SIZE)
7441                 newSize = size;
7442             else {
7443                 newSize = buf->size * 2;
7444                 while (size > newSize) {
7445                     if (newSize > UINT_MAX / 2) {
7446                         xmlTreeErrMemory("growing buffer");
7447                         return 0;
7448                     }
7449                     newSize *= 2;
7450                 }
7451             }
7452             break;
7453 
7454 	default:
7455 	    newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
7456 	    break;
7457     }
7458 
7459     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7460         start_buf = buf->content - buf->contentIO;
7461 
7462         if (start_buf > newSize) {
7463 	    /* move data back to start */
7464 	    memmove(buf->contentIO, buf->content, buf->use);
7465 	    buf->content = buf->contentIO;
7466 	    buf->content[buf->use] = 0;
7467 	    buf->size += start_buf;
7468 	} else {
7469 	    rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
7470 	    if (rebuf == NULL) {
7471 		xmlTreeErrMemory("growing buffer");
7472 		return 0;
7473 	    }
7474 	    buf->contentIO = rebuf;
7475 	    buf->content = rebuf + start_buf;
7476 	}
7477     } else {
7478 	if (buf->content == NULL) {
7479 	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7480 	} else if (buf->size - buf->use < 100) {
7481 	    rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
7482         } else {
7483 	    /*
7484 	     * if we are reallocating a buffer far from being full, it's
7485 	     * better to make a new allocation and copy only the used range
7486 	     * and free the old one.
7487 	     */
7488 	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
7489 	    if (rebuf != NULL) {
7490 		memcpy(rebuf, buf->content, buf->use);
7491 		xmlFree(buf->content);
7492 		rebuf[buf->use] = 0;
7493 	    }
7494 	}
7495 	if (rebuf == NULL) {
7496 	    xmlTreeErrMemory("growing buffer");
7497 	    return 0;
7498 	}
7499 	buf->content = rebuf;
7500     }
7501     buf->size = newSize;
7502 
7503     return 1;
7504 }
7505 
7506 /**
7507  * xmlBufferAdd:
7508  * @buf:  the buffer to dump
7509  * @str:  the #xmlChar string
7510  * @len:  the number of #xmlChar to add
7511  *
7512  * Add a string range to an XML buffer. if len == -1, the length of
7513  * str is recomputed.
7514  *
7515  * Returns 0 successful, a positive error code number otherwise
7516  *         and -1 in case of internal or API error.
7517  */
7518 int
xmlBufferAdd(xmlBufferPtr buf,const xmlChar * str,int len)7519 xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
7520     unsigned int needSize;
7521 
7522     if ((str == NULL) || (buf == NULL)) {
7523 	return -1;
7524     }
7525     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7526     if (len < -1) {
7527 #ifdef DEBUG_BUFFER
7528         xmlGenericError(xmlGenericErrorContext,
7529 		"xmlBufferAdd: len < 0\n");
7530 #endif
7531 	return -1;
7532     }
7533     if (len == 0) return 0;
7534 
7535     if (len < 0)
7536         len = xmlStrlen(str);
7537 
7538     if (len < 0) return -1;
7539     if (len == 0) return 0;
7540 
7541     if ((unsigned) len >= buf->size - buf->use) {
7542         if ((unsigned) len >= UINT_MAX - buf->use)
7543             return XML_ERR_NO_MEMORY;
7544         needSize = buf->use + len + 1;
7545         if (!xmlBufferResize(buf, needSize)){
7546 	    xmlTreeErrMemory("growing buffer");
7547             return XML_ERR_NO_MEMORY;
7548         }
7549     }
7550 
7551     memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
7552     buf->use += len;
7553     buf->content[buf->use] = 0;
7554     return 0;
7555 }
7556 
7557 /**
7558  * xmlBufferAddHead:
7559  * @buf:  the buffer
7560  * @str:  the #xmlChar string
7561  * @len:  the number of #xmlChar to add
7562  *
7563  * Add a string range to the beginning of an XML buffer.
7564  * if len == -1, the length of @str is recomputed.
7565  *
7566  * Returns 0 successful, a positive error code number otherwise
7567  *         and -1 in case of internal or API error.
7568  */
7569 int
xmlBufferAddHead(xmlBufferPtr buf,const xmlChar * str,int len)7570 xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
7571     unsigned int needSize;
7572 
7573     if (buf == NULL)
7574         return(-1);
7575     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7576     if (str == NULL) {
7577 #ifdef DEBUG_BUFFER
7578         xmlGenericError(xmlGenericErrorContext,
7579 		"xmlBufferAddHead: str == NULL\n");
7580 #endif
7581 	return -1;
7582     }
7583     if (len < -1) {
7584 #ifdef DEBUG_BUFFER
7585         xmlGenericError(xmlGenericErrorContext,
7586 		"xmlBufferAddHead: len < 0\n");
7587 #endif
7588 	return -1;
7589     }
7590     if (len == 0) return 0;
7591 
7592     if (len < 0)
7593         len = xmlStrlen(str);
7594 
7595     if (len <= 0) return -1;
7596 
7597     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
7598         size_t start_buf = buf->content - buf->contentIO;
7599 
7600 	if (start_buf > (unsigned int) len) {
7601 	    /*
7602 	     * We can add it in the space previously shrinked
7603 	     */
7604 	    buf->content -= len;
7605             memmove(&buf->content[0], str, len);
7606 	    buf->use += len;
7607 	    buf->size += len;
7608 	    return(0);
7609 	}
7610     }
7611     needSize = buf->use + len + 2;
7612     if (needSize > buf->size){
7613         if (!xmlBufferResize(buf, needSize)){
7614 	    xmlTreeErrMemory("growing buffer");
7615             return XML_ERR_NO_MEMORY;
7616         }
7617     }
7618 
7619     memmove(&buf->content[len], &buf->content[0], buf->use);
7620     memmove(&buf->content[0], str, len);
7621     buf->use += len;
7622     buf->content[buf->use] = 0;
7623     return 0;
7624 }
7625 
7626 /**
7627  * xmlBufferCat:
7628  * @buf:  the buffer to add to
7629  * @str:  the #xmlChar string
7630  *
7631  * Append a zero terminated string to an XML buffer.
7632  *
7633  * Returns 0 successful, a positive error code number otherwise
7634  *         and -1 in case of internal or API error.
7635  */
7636 int
xmlBufferCat(xmlBufferPtr buf,const xmlChar * str)7637 xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
7638     if (buf == NULL)
7639         return(-1);
7640     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
7641     if (str == NULL) return -1;
7642     return xmlBufferAdd(buf, str, -1);
7643 }
7644 
7645 /**
7646  * xmlBufferCCat:
7647  * @buf:  the buffer to dump
7648  * @str:  the C char string
7649  *
7650  * Append a zero terminated C string to an XML buffer.
7651  *
7652  * Returns 0 successful, a positive error code number otherwise
7653  *         and -1 in case of internal or API error.
7654  */
7655 int
xmlBufferCCat(xmlBufferPtr buf,const char * str)7656 xmlBufferCCat(xmlBufferPtr buf, const char *str) {
7657     return xmlBufferCat(buf, (const xmlChar *) str);
7658 }
7659 
7660 /**
7661  * xmlBufferWriteCHAR:
7662  * @buf:  the XML buffer
7663  * @string:  the string to add
7664  *
7665  * routine which manages and grows an output buffer. This one adds
7666  * xmlChars at the end of the buffer.
7667  */
7668 void
xmlBufferWriteCHAR(xmlBufferPtr buf,const xmlChar * string)7669 xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
7670     if (buf == NULL)
7671         return;
7672     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
7673     xmlBufferCat(buf, string);
7674 }
7675 
7676 /**
7677  * xmlBufferWriteChar:
7678  * @buf:  the XML buffer output
7679  * @string:  the string to add
7680  *
7681  * routine which manage and grows an output buffer. This one add
7682  * C chars at the end of the array.
7683  */
7684 void
xmlBufferWriteChar(xmlBufferPtr buf,const char * string)7685 xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
7686     if (buf == NULL)
7687         return;
7688     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
7689     xmlBufferCCat(buf, string);
7690 }
7691 
7692 
7693 /**
7694  * xmlBufferWriteQuotedString:
7695  * @buf:  the XML buffer output
7696  * @string:  the string to add
7697  *
7698  * routine which manage and grows an output buffer. This one writes
7699  * a quoted or double quoted #xmlChar string, checking first if it holds
7700  * quote or double-quotes internally
7701  */
7702 void
xmlBufferWriteQuotedString(xmlBufferPtr buf,const xmlChar * string)7703 xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
7704     const xmlChar *cur, *base;
7705     if (buf == NULL)
7706         return;
7707     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
7708     if (xmlStrchr(string, '\"')) {
7709         if (xmlStrchr(string, '\'')) {
7710 #ifdef DEBUG_BUFFER
7711 	    xmlGenericError(xmlGenericErrorContext,
7712  "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
7713 #endif
7714 	    xmlBufferCCat(buf, "\"");
7715             base = cur = string;
7716             while(*cur != 0){
7717                 if(*cur == '"'){
7718                     if (base != cur)
7719                         xmlBufferAdd(buf, base, cur - base);
7720                     xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
7721                     cur++;
7722                     base = cur;
7723                 }
7724                 else {
7725                     cur++;
7726                 }
7727             }
7728             if (base != cur)
7729                 xmlBufferAdd(buf, base, cur - base);
7730 	    xmlBufferCCat(buf, "\"");
7731 	}
7732         else{
7733 	    xmlBufferCCat(buf, "\'");
7734             xmlBufferCat(buf, string);
7735 	    xmlBufferCCat(buf, "\'");
7736         }
7737     } else {
7738         xmlBufferCCat(buf, "\"");
7739         xmlBufferCat(buf, string);
7740         xmlBufferCCat(buf, "\"");
7741     }
7742 }
7743 
7744 
7745 /**
7746  * xmlGetDocCompressMode:
7747  * @doc:  the document
7748  *
7749  * get the compression ratio for a document, ZLIB based
7750  * Returns 0 (uncompressed) to 9 (max compression)
7751  */
7752 int
xmlGetDocCompressMode(const xmlDoc * doc)7753 xmlGetDocCompressMode (const xmlDoc *doc) {
7754     if (doc == NULL) return(-1);
7755     return(doc->compression);
7756 }
7757 
7758 /**
7759  * xmlSetDocCompressMode:
7760  * @doc:  the document
7761  * @mode:  the compression ratio
7762  *
7763  * set the compression ratio for a document, ZLIB based
7764  * Correct values: 0 (uncompressed) to 9 (max compression)
7765  */
7766 void
xmlSetDocCompressMode(xmlDocPtr doc,int mode)7767 xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
7768     if (doc == NULL) return;
7769     if (mode < 0) doc->compression = 0;
7770     else if (mode > 9) doc->compression = 9;
7771     else doc->compression = mode;
7772 }
7773 
7774 /**
7775  * xmlGetCompressMode:
7776  *
7777  * get the default compression mode used, ZLIB based.
7778  * Returns 0 (uncompressed) to 9 (max compression)
7779  */
7780 int
xmlGetCompressMode(void)7781 xmlGetCompressMode(void)
7782 {
7783     return (xmlCompressMode);
7784 }
7785 
7786 /**
7787  * xmlSetCompressMode:
7788  * @mode:  the compression ratio
7789  *
7790  * set the default compression mode used, ZLIB based
7791  * Correct values: 0 (uncompressed) to 9 (max compression)
7792  */
7793 void
xmlSetCompressMode(int mode)7794 xmlSetCompressMode(int mode) {
7795     if (mode < 0) xmlCompressMode = 0;
7796     else if (mode > 9) xmlCompressMode = 9;
7797     else xmlCompressMode = mode;
7798 }
7799 
7800 #define XML_TREE_NSMAP_PARENT -1
7801 #define XML_TREE_NSMAP_XML -2
7802 #define XML_TREE_NSMAP_DOC -3
7803 #define XML_TREE_NSMAP_CUSTOM -4
7804 
7805 typedef struct xmlNsMapItem *xmlNsMapItemPtr;
7806 struct xmlNsMapItem {
7807     xmlNsMapItemPtr next;
7808     xmlNsMapItemPtr prev;
7809     xmlNsPtr oldNs; /* old ns decl reference */
7810     xmlNsPtr newNs; /* new ns decl reference */
7811     int shadowDepth; /* Shadowed at this depth */
7812     /*
7813     * depth:
7814     * >= 0 == @node's ns-decls
7815     * -1   == @parent's ns-decls
7816     * -2   == the doc->oldNs XML ns-decl
7817     * -3   == the doc->oldNs storage ns-decls
7818     * -4   == ns-decls provided via custom ns-handling
7819     */
7820     int depth;
7821 };
7822 
7823 typedef struct xmlNsMap *xmlNsMapPtr;
7824 struct xmlNsMap {
7825     xmlNsMapItemPtr first;
7826     xmlNsMapItemPtr last;
7827     xmlNsMapItemPtr pool;
7828 };
7829 
7830 #define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL))
7831 #define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next)
7832 #define XML_NSMAP_POP(m, i) \
7833     i = (m)->last; \
7834     (m)->last = (i)->prev; \
7835     if ((m)->last == NULL) \
7836 	(m)->first = NULL; \
7837     else \
7838 	(m)->last->next = NULL; \
7839     (i)->next = (m)->pool; \
7840     (m)->pool = i;
7841 
7842 /*
7843 * xmlDOMWrapNsMapFree:
7844 * @map: the ns-map
7845 *
7846 * Frees the ns-map
7847 */
7848 static void
xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)7849 xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap)
7850 {
7851     xmlNsMapItemPtr cur, tmp;
7852 
7853     if (nsmap == NULL)
7854 	return;
7855     cur = nsmap->pool;
7856     while (cur != NULL) {
7857 	tmp = cur;
7858 	cur = cur->next;
7859 	xmlFree(tmp);
7860     }
7861     cur = nsmap->first;
7862     while (cur != NULL) {
7863 	tmp = cur;
7864 	cur = cur->next;
7865 	xmlFree(tmp);
7866     }
7867     xmlFree(nsmap);
7868 }
7869 
7870 /*
7871 * xmlDOMWrapNsMapAddItem:
7872 * @map: the ns-map
7873 * @oldNs: the old ns-struct
7874 * @newNs: the new ns-struct
7875 * @depth: depth and ns-kind information
7876 *
7877 * Adds an ns-mapping item.
7878 */
7879 static xmlNsMapItemPtr
xmlDOMWrapNsMapAddItem(xmlNsMapPtr * nsmap,int position,xmlNsPtr oldNs,xmlNsPtr newNs,int depth)7880 xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position,
7881 		       xmlNsPtr oldNs, xmlNsPtr newNs, int depth)
7882 {
7883     xmlNsMapItemPtr ret;
7884     xmlNsMapPtr map;
7885 
7886     if (nsmap == NULL)
7887 	return(NULL);
7888     if ((position != -1) && (position != 0))
7889 	return(NULL);
7890     map = *nsmap;
7891 
7892     if (map == NULL) {
7893 	/*
7894 	* Create the ns-map.
7895 	*/
7896 	map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap));
7897 	if (map == NULL) {
7898 	    xmlTreeErrMemory("allocating namespace map");
7899 	    return (NULL);
7900 	}
7901 	memset(map, 0, sizeof(struct xmlNsMap));
7902 	*nsmap = map;
7903     }
7904 
7905     if (map->pool != NULL) {
7906 	/*
7907 	* Reuse an item from the pool.
7908 	*/
7909 	ret = map->pool;
7910 	map->pool = ret->next;
7911 	memset(ret, 0, sizeof(struct xmlNsMapItem));
7912     } else {
7913 	/*
7914 	* Create a new item.
7915 	*/
7916 	ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
7917 	if (ret == NULL) {
7918 	    xmlTreeErrMemory("allocating namespace map item");
7919 	    return (NULL);
7920 	}
7921 	memset(ret, 0, sizeof(struct xmlNsMapItem));
7922     }
7923 
7924     if (map->first == NULL) {
7925 	/*
7926 	* First ever.
7927 	*/
7928 	map->first = ret;
7929 	map->last = ret;
7930     } else if (position == -1) {
7931 	/*
7932 	* Append.
7933 	*/
7934 	ret->prev = map->last;
7935 	map->last->next = ret;
7936 	map->last = ret;
7937     } else if (position == 0) {
7938 	/*
7939 	* Set on first position.
7940 	*/
7941 	map->first->prev = ret;
7942 	ret->next = map->first;
7943 	map->first = ret;
7944     }
7945 
7946     ret->oldNs = oldNs;
7947     ret->newNs = newNs;
7948     ret->shadowDepth = -1;
7949     ret->depth = depth;
7950     return (ret);
7951 }
7952 
7953 /*
7954 * xmlDOMWrapStoreNs:
7955 * @doc: the doc
7956 * @nsName: the namespace name
7957 * @prefix: the prefix
7958 *
7959 * Creates or reuses an xmlNs struct on doc->oldNs with
7960 * the given prefix and namespace name.
7961 *
7962 * Returns the acquired ns struct or NULL in case of an API
7963 *         or internal error.
7964 */
7965 static xmlNsPtr
xmlDOMWrapStoreNs(xmlDocPtr doc,const xmlChar * nsName,const xmlChar * prefix)7966 xmlDOMWrapStoreNs(xmlDocPtr doc,
7967 		   const xmlChar *nsName,
7968 		   const xmlChar *prefix)
7969 {
7970     xmlNsPtr ns;
7971 
7972     if (doc == NULL)
7973 	return (NULL);
7974     ns = xmlTreeEnsureXMLDecl(doc);
7975     if (ns == NULL)
7976 	return (NULL);
7977     if (ns->next != NULL) {
7978 	/* Reuse. */
7979 	ns = ns->next;
7980 	while (ns != NULL) {
7981 	    if (((ns->prefix == prefix) ||
7982 		xmlStrEqual(ns->prefix, prefix)) &&
7983 		xmlStrEqual(ns->href, nsName)) {
7984 		return (ns);
7985 	    }
7986 	    if (ns->next == NULL)
7987 		break;
7988 	    ns = ns->next;
7989 	}
7990     }
7991     /* Create. */
7992     if (ns != NULL) {
7993         ns->next = xmlNewNs(NULL, nsName, prefix);
7994         return (ns->next);
7995     }
7996     return(NULL);
7997 }
7998 
7999 /*
8000 * xmlDOMWrapNewCtxt:
8001 *
8002 * Allocates and initializes a new DOM-wrapper context.
8003 *
8004 * Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal error.
8005 */
8006 xmlDOMWrapCtxtPtr
xmlDOMWrapNewCtxt(void)8007 xmlDOMWrapNewCtxt(void)
8008 {
8009     xmlDOMWrapCtxtPtr ret;
8010 
8011     ret = xmlMalloc(sizeof(xmlDOMWrapCtxt));
8012     if (ret == NULL) {
8013 	xmlTreeErrMemory("allocating DOM-wrapper context");
8014 	return (NULL);
8015     }
8016     memset(ret, 0, sizeof(xmlDOMWrapCtxt));
8017     return (ret);
8018 }
8019 
8020 /*
8021 * xmlDOMWrapFreeCtxt:
8022 * @ctxt: the DOM-wrapper context
8023 *
8024 * Frees the DOM-wrapper context.
8025 */
8026 void
xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)8027 xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt)
8028 {
8029     if (ctxt == NULL)
8030 	return;
8031     if (ctxt->namespaceMap != NULL)
8032 	xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap);
8033     /*
8034     * TODO: Store the namespace map in the context.
8035     */
8036     xmlFree(ctxt);
8037 }
8038 
8039 /*
8040 * xmlTreeLookupNsListByPrefix:
8041 * @nsList: a list of ns-structs
8042 * @prefix: the searched prefix
8043 *
8044 * Searches for a ns-decl with the given prefix in @nsList.
8045 *
8046 * Returns the ns-decl if found, NULL if not found and on
8047 *         API errors.
8048 */
8049 static xmlNsPtr
xmlTreeNSListLookupByPrefix(xmlNsPtr nsList,const xmlChar * prefix)8050 xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
8051 {
8052     if (nsList == NULL)
8053 	return (NULL);
8054     {
8055 	xmlNsPtr ns;
8056 	ns = nsList;
8057 	do {
8058 	    if ((prefix == ns->prefix) ||
8059 		xmlStrEqual(prefix, ns->prefix)) {
8060 		return (ns);
8061 	    }
8062 	    ns = ns->next;
8063 	} while (ns != NULL);
8064     }
8065     return (NULL);
8066 }
8067 
8068 /*
8069 *
8070 * xmlDOMWrapNSNormGatherInScopeNs:
8071 * @map: the namespace map
8072 * @node: the node to start with
8073 *
8074 * Puts in-scope namespaces into the ns-map.
8075 *
8076 * Returns 0 on success, -1 on API or internal errors.
8077 */
8078 static int
xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr * map,xmlNodePtr node)8079 xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map,
8080 				xmlNodePtr node)
8081 {
8082     xmlNodePtr cur;
8083     xmlNsPtr ns;
8084     xmlNsMapItemPtr mi;
8085     int shadowed;
8086 
8087     if ((map == NULL) || (*map != NULL))
8088 	return (-1);
8089     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
8090         return (-1);
8091     /*
8092     * Get in-scope ns-decls of @parent.
8093     */
8094     cur = node;
8095     while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
8096 	if (cur->type == XML_ELEMENT_NODE) {
8097 	    if (cur->nsDef != NULL) {
8098 		ns = cur->nsDef;
8099 		do {
8100 		    shadowed = 0;
8101 		    if (XML_NSMAP_NOTEMPTY(*map)) {
8102 			/*
8103 			* Skip shadowed prefixes.
8104 			*/
8105 			XML_NSMAP_FOREACH(*map, mi) {
8106 			    if ((ns->prefix == mi->newNs->prefix) ||
8107 				xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
8108 				shadowed = 1;
8109 				break;
8110 			    }
8111 			}
8112 		    }
8113 		    /*
8114 		    * Insert mapping.
8115 		    */
8116 		    mi = xmlDOMWrapNsMapAddItem(map, 0, NULL,
8117 			ns, XML_TREE_NSMAP_PARENT);
8118 		    if (mi == NULL)
8119 			return (-1);
8120 		    if (shadowed)
8121 			mi->shadowDepth = 0;
8122 		    ns = ns->next;
8123 		} while (ns != NULL);
8124 	    }
8125 	}
8126 	cur = cur->parent;
8127     }
8128     return (0);
8129 }
8130 
8131 /*
8132 * XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
8133 * otherwise copy it, when it was in the source-dict.
8134 */
8135 #define XML_TREE_ADOPT_STR(str) \
8136     if (adoptStr && (str != NULL)) { \
8137 	if (destDoc->dict) { \
8138 	    const xmlChar *old = str;	\
8139 	    str = xmlDictLookup(destDoc->dict, str, -1); \
8140 	    if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
8141 	        (!xmlDictOwns(sourceDoc->dict, old))) \
8142 		xmlFree((char *)old); \
8143 	} else if ((sourceDoc) && (sourceDoc->dict) && \
8144 	    xmlDictOwns(sourceDoc->dict, str)) { \
8145 	    str = BAD_CAST xmlStrdup(str); \
8146 	} \
8147     }
8148 
8149 /*
8150 * XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
8151 * put it in dest-dict or copy it.
8152 */
8153 #define XML_TREE_ADOPT_STR_2(str) \
8154     if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
8155 	(sourceDoc->dict != NULL) && \
8156 	xmlDictOwns(sourceDoc->dict, cur->content)) { \
8157 	if (destDoc->dict) \
8158 	    cur->content = (xmlChar *) \
8159 		xmlDictLookup(destDoc->dict, cur->content, -1); \
8160 	else \
8161 	    cur->content = xmlStrdup(BAD_CAST cur->content); \
8162     }
8163 
8164 /*
8165 * xmlDOMWrapNSNormAddNsMapItem2:
8166 *
8167 * For internal use. Adds a ns-decl mapping.
8168 *
8169 * Returns 0 on success, -1 on internal errors.
8170 */
8171 static int
xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr ** list,int * size,int * number,xmlNsPtr oldNs,xmlNsPtr newNs)8172 xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
8173 			xmlNsPtr oldNs, xmlNsPtr newNs)
8174 {
8175     if (*list == NULL) {
8176 	*list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
8177 	if (*list == NULL) {
8178 	    xmlTreeErrMemory("alloc ns map item");
8179 	    return(-1);
8180 	}
8181 	*size = 3;
8182 	*number = 0;
8183     } else if ((*number) >= (*size)) {
8184 	*size *= 2;
8185 	*list = (xmlNsPtr *) xmlRealloc(*list,
8186 	    (*size) * 2 * sizeof(xmlNsPtr));
8187 	if (*list == NULL) {
8188 	    xmlTreeErrMemory("realloc ns map item");
8189 	    return(-1);
8190 	}
8191     }
8192     (*list)[2 * (*number)] = oldNs;
8193     (*list)[2 * (*number) +1] = newNs;
8194     (*number)++;
8195     return (0);
8196 }
8197 
8198 /*
8199 * xmlDOMWrapRemoveNode:
8200 * @ctxt: a DOM wrapper context
8201 * @doc: the doc
8202 * @node: the node to be removed.
8203 * @options: set of options, unused at the moment
8204 *
8205 * Unlinks the given node from its owner.
8206 * This will substitute ns-references to node->nsDef for
8207 * ns-references to doc->oldNs, thus ensuring the removed
8208 * branch to be autark wrt ns-references.
8209 *
8210 * NOTE: This function was not intensively tested.
8211 *
8212 * Returns 0 on success, 1 if the node is not supported,
8213 *         -1 on API and internal errors.
8214 */
8215 int
xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr node,int options ATTRIBUTE_UNUSED)8216 xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc,
8217 		     xmlNodePtr node, int options ATTRIBUTE_UNUSED)
8218 {
8219     xmlNsPtr *list = NULL;
8220     int sizeList, nbList, i, j;
8221     xmlNsPtr ns;
8222 
8223     if ((node == NULL) || (doc == NULL) || (node->doc != doc))
8224 	return (-1);
8225 
8226     /* TODO: 0 or -1 ? */
8227     if (node->parent == NULL)
8228 	return (0);
8229 
8230     switch (node->type) {
8231 	case XML_TEXT_NODE:
8232 	case XML_CDATA_SECTION_NODE:
8233 	case XML_ENTITY_REF_NODE:
8234 	case XML_PI_NODE:
8235 	case XML_COMMENT_NODE:
8236 	    xmlUnlinkNode(node);
8237 	    return (0);
8238 	case XML_ELEMENT_NODE:
8239 	case XML_ATTRIBUTE_NODE:
8240 	    break;
8241 	default:
8242 	    return (1);
8243     }
8244     xmlUnlinkNode(node);
8245     /*
8246     * Save out-of-scope ns-references in doc->oldNs.
8247     */
8248     do {
8249 	switch (node->type) {
8250 	    case XML_ELEMENT_NODE:
8251 		if ((ctxt == NULL) && (node->nsDef != NULL)) {
8252 		    ns = node->nsDef;
8253 		    do {
8254 			if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8255 			    &nbList, ns, ns) == -1)
8256 			    goto internal_error;
8257 			ns = ns->next;
8258 		    } while (ns != NULL);
8259 		}
8260                 /* Falls through. */
8261 	    case XML_ATTRIBUTE_NODE:
8262 		if (node->ns != NULL) {
8263 		    /*
8264 		    * Find a mapping.
8265 		    */
8266 		    if (list != NULL) {
8267 			for (i = 0, j = 0; i < nbList; i++, j += 2) {
8268 			    if (node->ns == list[j]) {
8269 				node->ns = list[++j];
8270 				goto next_node;
8271 			    }
8272 			}
8273 		    }
8274 		    ns = NULL;
8275 		    if (ctxt != NULL) {
8276 			/*
8277 			* User defined.
8278 			*/
8279 		    } else {
8280 			/*
8281 			* Add to doc's oldNs.
8282 			*/
8283 			ns = xmlDOMWrapStoreNs(doc, node->ns->href,
8284 			    node->ns->prefix);
8285 			if (ns == NULL)
8286 			    goto internal_error;
8287 		    }
8288 		    if (ns != NULL) {
8289 			/*
8290 			* Add mapping.
8291 			*/
8292 			if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
8293 			    &nbList, node->ns, ns) == -1)
8294 			    goto internal_error;
8295 		    }
8296 		    node->ns = ns;
8297 		}
8298 		if ((node->type == XML_ELEMENT_NODE) &&
8299 		    (node->properties != NULL)) {
8300 		    node = (xmlNodePtr) node->properties;
8301 		    continue;
8302 		}
8303 		break;
8304 	    default:
8305 		goto next_sibling;
8306 	}
8307 next_node:
8308 	if ((node->type == XML_ELEMENT_NODE) &&
8309 	    (node->children != NULL)) {
8310 	    node = node->children;
8311 	    continue;
8312 	}
8313 next_sibling:
8314 	if (node == NULL)
8315 	    break;
8316 	if (node->next != NULL)
8317 	    node = node->next;
8318 	else {
8319 	    node = node->parent;
8320 	    goto next_sibling;
8321 	}
8322     } while (node != NULL);
8323 
8324     if (list != NULL)
8325 	xmlFree(list);
8326     return (0);
8327 
8328 internal_error:
8329     if (list != NULL)
8330 	xmlFree(list);
8331     return (-1);
8332 }
8333 
8334 /*
8335 * xmlSearchNsByNamespaceStrict:
8336 * @doc: the document
8337 * @node: the start node
8338 * @nsName: the searched namespace name
8339 * @retNs: the resulting ns-decl
8340 * @prefixed: if the found ns-decl must have a prefix (for attributes)
8341 *
8342 * Dynamically searches for a ns-declaration which matches
8343 * the given @nsName in the ancestor-or-self axis of @node.
8344 *
8345 * Returns 1 if a ns-decl was found, 0 if not and -1 on API
8346 *         and internal errors.
8347 */
8348 static int
xmlSearchNsByNamespaceStrict(xmlDocPtr doc,xmlNodePtr node,const xmlChar * nsName,xmlNsPtr * retNs,int prefixed)8349 xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node,
8350 			     const xmlChar* nsName,
8351 			     xmlNsPtr *retNs, int prefixed)
8352 {
8353     xmlNodePtr cur, prev = NULL, out = NULL;
8354     xmlNsPtr ns, prevns;
8355 
8356     if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
8357 	return (-1);
8358     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
8359         return(-1);
8360 
8361     *retNs = NULL;
8362     if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
8363 	*retNs = xmlTreeEnsureXMLDecl(doc);
8364 	if (*retNs == NULL)
8365 	    return (-1);
8366 	return (1);
8367     }
8368     cur = node;
8369     do {
8370 	if (cur->type == XML_ELEMENT_NODE) {
8371 	    if (cur->nsDef != NULL) {
8372 		for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
8373 		    if (prefixed && (ns->prefix == NULL))
8374 			continue;
8375 		    if (prev != NULL) {
8376 			/*
8377 			* Check the last level of ns-decls for a
8378 			* shadowing prefix.
8379 			*/
8380 			prevns = prev->nsDef;
8381 			do {
8382 			    if ((prevns->prefix == ns->prefix) ||
8383 				((prevns->prefix != NULL) &&
8384 				(ns->prefix != NULL) &&
8385 				xmlStrEqual(prevns->prefix, ns->prefix))) {
8386 				/*
8387 				* Shadowed.
8388 				*/
8389 				break;
8390 			    }
8391 			    prevns = prevns->next;
8392 			} while (prevns != NULL);
8393 			if (prevns != NULL)
8394 			    continue;
8395 		    }
8396 		    /*
8397 		    * Ns-name comparison.
8398 		    */
8399 		    if ((nsName == ns->href) ||
8400 			xmlStrEqual(nsName, ns->href)) {
8401 			/*
8402 			* At this point the prefix can only be shadowed,
8403 			* if we are the the (at least) 3rd level of
8404 			* ns-decls.
8405 			*/
8406 			if (out) {
8407 			    int ret;
8408 
8409 			    ret = xmlNsInScope(doc, node, prev, ns->prefix);
8410 			    if (ret < 0)
8411 				return (-1);
8412 			    /*
8413 			    * TODO: Should we try to find a matching ns-name
8414 			    * only once? This here keeps on searching.
8415 			    * I think we should try further since, there might
8416 			    * be an other matching ns-decl with an unshadowed
8417 			    * prefix.
8418 			    */
8419 			    if (! ret)
8420 				continue;
8421 			}
8422 			*retNs = ns;
8423 			return (1);
8424 		    }
8425 		}
8426 		out = prev;
8427 		prev = cur;
8428 	    }
8429 	} else if ((cur->type == XML_ENTITY_NODE) ||
8430             (cur->type == XML_ENTITY_DECL))
8431 	    return (0);
8432 	cur = cur->parent;
8433     } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8434     return (0);
8435 }
8436 
8437 /*
8438 * xmlSearchNsByPrefixStrict:
8439 * @doc: the document
8440 * @node: the start node
8441 * @prefix: the searched namespace prefix
8442 * @retNs: the resulting ns-decl
8443 *
8444 * Dynamically searches for a ns-declaration which matches
8445 * the given @nsName in the ancestor-or-self axis of @node.
8446 *
8447 * Returns 1 if a ns-decl was found, 0 if not and -1 on API
8448 *         and internal errors.
8449 */
8450 static int
xmlSearchNsByPrefixStrict(xmlDocPtr doc,xmlNodePtr node,const xmlChar * prefix,xmlNsPtr * retNs)8451 xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node,
8452 			  const xmlChar* prefix,
8453 			  xmlNsPtr *retNs)
8454 {
8455     xmlNodePtr cur;
8456     xmlNsPtr ns;
8457 
8458     if ((doc == NULL) || (node == NULL) || (node->type == XML_NAMESPACE_DECL))
8459         return(-1);
8460 
8461     if (retNs)
8462 	*retNs = NULL;
8463     if (IS_STR_XML(prefix)) {
8464 	if (retNs) {
8465 	    *retNs = xmlTreeEnsureXMLDecl(doc);
8466 	    if (*retNs == NULL)
8467 		return (-1);
8468 	}
8469 	return (1);
8470     }
8471     cur = node;
8472     do {
8473 	if (cur->type == XML_ELEMENT_NODE) {
8474 	    if (cur->nsDef != NULL) {
8475 		ns = cur->nsDef;
8476 		do {
8477 		    if ((prefix == ns->prefix) ||
8478 			xmlStrEqual(prefix, ns->prefix))
8479 		    {
8480 			/*
8481 			* Disabled namespaces, e.g. xmlns:abc="".
8482 			*/
8483 			if (ns->href == NULL)
8484 			    return(0);
8485 			if (retNs)
8486 			    *retNs = ns;
8487 			return (1);
8488 		    }
8489 		    ns = ns->next;
8490 		} while (ns != NULL);
8491 	    }
8492 	} else if ((cur->type == XML_ENTITY_NODE) ||
8493             (cur->type == XML_ENTITY_DECL))
8494 	    return (0);
8495 	cur = cur->parent;
8496     } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
8497     return (0);
8498 }
8499 
8500 /*
8501 * xmlDOMWrapNSNormDeclareNsForced:
8502 * @doc: the doc
8503 * @elem: the element-node to declare on
8504 * @nsName: the namespace-name of the ns-decl
8505 * @prefix: the preferred prefix of the ns-decl
8506 * @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
8507 *
8508 * Declares a new namespace on @elem. It tries to use the
8509 * given @prefix; if a ns-decl with the given prefix is already existent
8510 * on @elem, it will generate an other prefix.
8511 *
8512 * Returns 1 if a ns-decl was found, 0 if not and -1 on API
8513 *         and internal errors.
8514 */
8515 static xmlNsPtr
xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,xmlNodePtr elem,const xmlChar * nsName,const xmlChar * prefix,int checkShadow)8516 xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
8517 				xmlNodePtr elem,
8518 				const xmlChar *nsName,
8519 				const xmlChar *prefix,
8520 				int checkShadow)
8521 {
8522 
8523     xmlNsPtr ret;
8524     char buf[50];
8525     const xmlChar *pref;
8526     int counter = 0;
8527 
8528     if ((doc == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE))
8529         return(NULL);
8530     /*
8531     * Create a ns-decl on @anchor.
8532     */
8533     pref = prefix;
8534     while (1) {
8535 	/*
8536 	* Lookup whether the prefix is unused in elem's ns-decls.
8537 	*/
8538 	if ((elem->nsDef != NULL) &&
8539 	    (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
8540 	    goto ns_next_prefix;
8541 	if (checkShadow && elem->parent &&
8542 	    ((xmlNodePtr) elem->parent->doc != elem->parent)) {
8543 	    /*
8544 	    * Does it shadow ancestor ns-decls?
8545 	    */
8546 	    if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1)
8547 		goto ns_next_prefix;
8548 	}
8549 	ret = xmlNewNs(NULL, nsName, pref);
8550 	if (ret == NULL)
8551 	    return (NULL);
8552 	if (elem->nsDef == NULL)
8553 	    elem->nsDef = ret;
8554 	else {
8555 	    xmlNsPtr ns2 = elem->nsDef;
8556 	    while (ns2->next != NULL)
8557 		ns2 = ns2->next;
8558 	    ns2->next = ret;
8559 	}
8560 	return (ret);
8561 ns_next_prefix:
8562 	counter++;
8563 	if (counter > 1000)
8564 	    return (NULL);
8565 	if (prefix == NULL) {
8566 	    snprintf((char *) buf, sizeof(buf),
8567 		"ns_%d", counter);
8568 	} else
8569 	    snprintf((char *) buf, sizeof(buf),
8570 	    "%.30s_%d", (char *)prefix, counter);
8571 	pref = BAD_CAST buf;
8572     }
8573 }
8574 
8575 /*
8576 * xmlDOMWrapNSNormAcquireNormalizedNs:
8577 * @doc: the doc
8578 * @elem: the element-node to declare namespaces on
8579 * @ns: the ns-struct to use for the search
8580 * @retNs: the found/created ns-struct
8581 * @nsMap: the ns-map
8582 * @depth: the current tree depth
8583 * @ancestorsOnly: search in ancestor ns-decls only
8584 * @prefixed: if the searched ns-decl must have a prefix (for attributes)
8585 *
8586 * Searches for a matching ns-name in the ns-decls of @nsMap, if not
8587 * found it will either declare it on @elem, or store it in doc->oldNs.
8588 * If a new ns-decl needs to be declared on @elem, it tries to use the
8589 * @ns->prefix for it, if this prefix is already in use on @elem, it will
8590 * change the prefix or the new ns-decl.
8591 *
8592 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8593 */
8594 static int
xmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc,xmlNodePtr elem,xmlNsPtr ns,xmlNsPtr * retNs,xmlNsMapPtr * nsMap,int depth,int ancestorsOnly,int prefixed)8595 xmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc,
8596 				   xmlNodePtr elem,
8597 				   xmlNsPtr ns,
8598 				   xmlNsPtr *retNs,
8599 				   xmlNsMapPtr *nsMap,
8600 
8601 				   int depth,
8602 				   int ancestorsOnly,
8603 				   int prefixed)
8604 {
8605     xmlNsMapItemPtr mi;
8606 
8607     if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
8608 	(nsMap == NULL))
8609 	return (-1);
8610 
8611     *retNs = NULL;
8612     /*
8613     * Handle XML namespace.
8614     */
8615     if (IS_STR_XML(ns->prefix)) {
8616 	/*
8617 	* Insert XML namespace mapping.
8618 	*/
8619 	*retNs = xmlTreeEnsureXMLDecl(doc);
8620 	if (*retNs == NULL)
8621 	    return (-1);
8622 	return (0);
8623     }
8624     /*
8625     * If the search should be done in ancestors only and no
8626     * @elem (the first ancestor) was specified, then skip the search.
8627     */
8628     if ((XML_NSMAP_NOTEMPTY(*nsMap)) &&
8629 	(! (ancestorsOnly && (elem == NULL))))
8630     {
8631 	/*
8632 	* Try to find an equal ns-name in in-scope ns-decls.
8633 	*/
8634 	XML_NSMAP_FOREACH(*nsMap, mi) {
8635 	    if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8636 		/*
8637 		* ancestorsOnly: This should be turned on to gain speed,
8638 		* if one knows that the branch itself was already
8639 		* ns-wellformed and no stale references existed.
8640 		* I.e. it searches in the ancestor axis only.
8641 		*/
8642 		((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
8643 		/* Skip shadowed prefixes. */
8644 		(mi->shadowDepth == -1) &&
8645 		/* Skip xmlns="" or xmlns:foo="". */
8646 		((mi->newNs->href != NULL) &&
8647 		(mi->newNs->href[0] != 0)) &&
8648 		/* Ensure a prefix if wanted. */
8649 		((! prefixed) || (mi->newNs->prefix != NULL)) &&
8650 		/* Equal ns name */
8651 		((mi->newNs->href == ns->href) ||
8652 		xmlStrEqual(mi->newNs->href, ns->href))) {
8653 		/* Set the mapping. */
8654 		mi->oldNs = ns;
8655 		*retNs = mi->newNs;
8656 		return (0);
8657 	    }
8658 	}
8659     }
8660     /*
8661     * No luck, the namespace is out of scope or shadowed.
8662     */
8663     if (elem == NULL) {
8664 	xmlNsPtr tmpns;
8665 
8666 	/*
8667 	* Store ns-decls in "oldNs" of the document-node.
8668 	*/
8669 	tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
8670 	if (tmpns == NULL)
8671 	    return (-1);
8672 	/*
8673 	* Insert mapping.
8674 	*/
8675 	if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
8676 		tmpns, XML_TREE_NSMAP_DOC) == NULL) {
8677 	    xmlFreeNs(tmpns);
8678 	    return (-1);
8679 	}
8680 	*retNs = tmpns;
8681     } else {
8682 	xmlNsPtr tmpns;
8683 
8684 	tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
8685 	    ns->prefix, 0);
8686 	if (tmpns == NULL)
8687 	    return (-1);
8688 
8689 	if (*nsMap != NULL) {
8690 	    /*
8691 	    * Does it shadow ancestor ns-decls?
8692 	    */
8693 	    XML_NSMAP_FOREACH(*nsMap, mi) {
8694 		if ((mi->depth < depth) &&
8695 		    (mi->shadowDepth == -1) &&
8696 		    ((ns->prefix == mi->newNs->prefix) ||
8697 		    xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8698 		    /*
8699 		    * Shadows.
8700 		    */
8701 		    mi->shadowDepth = depth;
8702 		    break;
8703 		}
8704 	    }
8705 	}
8706 	if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
8707 	    xmlFreeNs(tmpns);
8708 	    return (-1);
8709 	}
8710 	*retNs = tmpns;
8711     }
8712     return (0);
8713 }
8714 
8715 typedef enum {
8716     XML_DOM_RECONNS_REMOVEREDUND = 1<<0
8717 } xmlDOMReconcileNSOptions;
8718 
8719 /*
8720 * xmlDOMWrapReconcileNamespaces:
8721 * @ctxt: DOM wrapper context, unused at the moment
8722 * @elem: the element-node
8723 * @options: option flags
8724 *
8725 * Ensures that ns-references point to ns-decls hold on element-nodes.
8726 * Ensures that the tree is namespace wellformed by creating additional
8727 * ns-decls where needed. Note that, since prefixes of already existent
8728 * ns-decls can be shadowed by this process, it could break QNames in
8729 * attribute values or element content.
8730 *
8731 * NOTE: This function was not intensively tested.
8732 *
8733 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8734 */
8735 
8736 int
xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,xmlNodePtr elem,int options)8737 xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED,
8738 			      xmlNodePtr elem,
8739 			      int options)
8740 {
8741     int depth = -1, adoptns = 0, parnsdone = 0;
8742     xmlNsPtr ns, prevns;
8743     xmlDocPtr doc;
8744     xmlNodePtr cur, curElem = NULL;
8745     xmlNsMapPtr nsMap = NULL;
8746     xmlNsMapItemPtr /* topmi = NULL, */ mi;
8747     /* @ancestorsOnly should be set by an option flag. */
8748     int ancestorsOnly = 0;
8749     int optRemoveRedundantNS =
8750 	((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
8751     xmlNsPtr *listRedund = NULL;
8752     int sizeRedund = 0, nbRedund = 0, ret, i, j;
8753 
8754     if ((elem == NULL) || (elem->doc == NULL) ||
8755 	(elem->type != XML_ELEMENT_NODE))
8756 	return (-1);
8757 
8758     doc = elem->doc;
8759     cur = elem;
8760     do {
8761 	switch (cur->type) {
8762 	    case XML_ELEMENT_NODE:
8763 		adoptns = 1;
8764 		curElem = cur;
8765 		depth++;
8766 		/*
8767 		* Namespace declarations.
8768 		*/
8769 		if (cur->nsDef != NULL) {
8770 		    prevns = NULL;
8771 		    ns = cur->nsDef;
8772 		    while (ns != NULL) {
8773 			if (! parnsdone) {
8774 			    if ((elem->parent) &&
8775 				((xmlNodePtr) elem->parent->doc != elem->parent)) {
8776 				/*
8777 				* Gather ancestor in-scope ns-decls.
8778 				*/
8779 				if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8780 				    elem->parent) == -1)
8781 				    goto internal_error;
8782 			    }
8783 			    parnsdone = 1;
8784 			}
8785 
8786 			/*
8787 			* Lookup the ns ancestor-axis for equal ns-decls in scope.
8788 			*/
8789 			if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) {
8790 			    XML_NSMAP_FOREACH(nsMap, mi) {
8791 				if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8792 				    (mi->shadowDepth == -1) &&
8793 				    ((ns->prefix == mi->newNs->prefix) ||
8794 				      xmlStrEqual(ns->prefix, mi->newNs->prefix)) &&
8795 				    ((ns->href == mi->newNs->href) ||
8796 				      xmlStrEqual(ns->href, mi->newNs->href)))
8797 				{
8798 				    /*
8799 				    * A redundant ns-decl was found.
8800 				    * Add it to the list of redundant ns-decls.
8801 				    */
8802 				    if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
8803 					&sizeRedund, &nbRedund, ns, mi->newNs) == -1)
8804 					goto internal_error;
8805 				    /*
8806 				    * Remove the ns-decl from the element-node.
8807 				    */
8808 				    if (prevns)
8809 					prevns->next = ns->next;
8810 				    else
8811 					cur->nsDef = ns->next;
8812 				    goto next_ns_decl;
8813 				}
8814 			    }
8815 			}
8816 
8817 			/*
8818 			* Skip ns-references handling if the referenced
8819 			* ns-decl is declared on the same element.
8820 			*/
8821 			if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
8822 			    adoptns = 0;
8823 			/*
8824 			* Does it shadow any ns-decl?
8825 			*/
8826 			if (XML_NSMAP_NOTEMPTY(nsMap)) {
8827 			    XML_NSMAP_FOREACH(nsMap, mi) {
8828 				if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
8829 				    (mi->shadowDepth == -1) &&
8830 				    ((ns->prefix == mi->newNs->prefix) ||
8831 				    xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
8832 
8833 				    mi->shadowDepth = depth;
8834 				}
8835 			    }
8836 			}
8837 			/*
8838 			* Push mapping.
8839 			*/
8840 			if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
8841 			    depth) == NULL)
8842 			    goto internal_error;
8843 
8844 			prevns = ns;
8845 next_ns_decl:
8846 			ns = ns->next;
8847 		    }
8848 		}
8849 		if (! adoptns)
8850 		    goto ns_end;
8851                 /* Falls through. */
8852 	    case XML_ATTRIBUTE_NODE:
8853 		/* No ns, no fun. */
8854 		if (cur->ns == NULL)
8855 		    goto ns_end;
8856 
8857 		if (! parnsdone) {
8858 		    if ((elem->parent) &&
8859 			((xmlNodePtr) elem->parent->doc != elem->parent)) {
8860 			if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
8861 				elem->parent) == -1)
8862 			    goto internal_error;
8863 		    }
8864 		    parnsdone = 1;
8865 		}
8866 		/*
8867 		* Adjust the reference if this was a redundant ns-decl.
8868 		*/
8869 		if (listRedund) {
8870 		   for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8871 		       if (cur->ns == listRedund[j]) {
8872 			   cur->ns = listRedund[++j];
8873 			   break;
8874 		       }
8875 		   }
8876 		}
8877 		/*
8878 		* Adopt ns-references.
8879 		*/
8880 		if (XML_NSMAP_NOTEMPTY(nsMap)) {
8881 		    /*
8882 		    * Search for a mapping.
8883 		    */
8884 		    XML_NSMAP_FOREACH(nsMap, mi) {
8885 			if ((mi->shadowDepth == -1) &&
8886 			    (cur->ns == mi->oldNs)) {
8887 
8888 			    cur->ns = mi->newNs;
8889 			    goto ns_end;
8890 			}
8891 		    }
8892 		}
8893 		/*
8894 		* Acquire a normalized ns-decl and add it to the map.
8895 		*/
8896 		if (xmlDOMWrapNSNormAcquireNormalizedNs(doc, curElem,
8897 			cur->ns, &ns,
8898 			&nsMap, depth,
8899 			ancestorsOnly,
8900 			(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
8901 		    goto internal_error;
8902 		cur->ns = ns;
8903 
8904 ns_end:
8905 		if ((cur->type == XML_ELEMENT_NODE) &&
8906 		    (cur->properties != NULL)) {
8907 		    /*
8908 		    * Process attributes.
8909 		    */
8910 		    cur = (xmlNodePtr) cur->properties;
8911 		    continue;
8912 		}
8913 		break;
8914 	    default:
8915 		goto next_sibling;
8916 	}
8917 into_content:
8918 	if ((cur->type == XML_ELEMENT_NODE) &&
8919 	    (cur->children != NULL)) {
8920 	    /*
8921 	    * Process content of element-nodes only.
8922 	    */
8923 	    cur = cur->children;
8924 	    continue;
8925 	}
8926 next_sibling:
8927 	if (cur == elem)
8928 	    break;
8929 	if (cur->type == XML_ELEMENT_NODE) {
8930 	    if (XML_NSMAP_NOTEMPTY(nsMap)) {
8931 		/*
8932 		* Pop mappings.
8933 		*/
8934 		while ((nsMap->last != NULL) &&
8935 		    (nsMap->last->depth >= depth))
8936 		{
8937 		    XML_NSMAP_POP(nsMap, mi)
8938 		}
8939 		/*
8940 		* Unshadow.
8941 		*/
8942 		XML_NSMAP_FOREACH(nsMap, mi) {
8943 		    if (mi->shadowDepth >= depth)
8944 			mi->shadowDepth = -1;
8945 		}
8946 	    }
8947 	    depth--;
8948 	}
8949 	if (cur->next != NULL)
8950 	    cur = cur->next;
8951 	else {
8952 	    if (cur->type == XML_ATTRIBUTE_NODE) {
8953 		cur = cur->parent;
8954 		goto into_content;
8955 	    }
8956 	    cur = cur->parent;
8957 	    goto next_sibling;
8958 	}
8959     } while (cur != NULL);
8960 
8961     ret = 0;
8962     goto exit;
8963 internal_error:
8964     ret = -1;
8965 exit:
8966     if (listRedund) {
8967 	for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
8968 	    xmlFreeNs(listRedund[j]);
8969 	}
8970 	xmlFree(listRedund);
8971     }
8972     if (nsMap != NULL)
8973 	xmlDOMWrapNsMapFree(nsMap);
8974     return (ret);
8975 }
8976 
8977 /*
8978 * xmlDOMWrapAdoptBranch:
8979 * @ctxt: the optional context for custom processing
8980 * @sourceDoc: the optional sourceDoc
8981 * @node: the element-node to start with
8982 * @destDoc: the destination doc for adoption
8983 * @destParent: the optional new parent of @node in @destDoc
8984 * @options: option flags
8985 *
8986 * Ensures that ns-references point to @destDoc: either to
8987 * elements->nsDef entries if @destParent is given, or to
8988 * @destDoc->oldNs otherwise.
8989 * If @destParent is given, it ensures that the tree is namespace
8990 * wellformed by creating additional ns-decls where needed.
8991 * Note that, since prefixes of already existent ns-decls can be
8992 * shadowed by this process, it could break QNames in attribute
8993 * values or element content.
8994 *
8995 * NOTE: This function was not intensively tested.
8996 *
8997 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
8998 */
8999 static int
xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr sourceDoc,xmlNodePtr node,xmlDocPtr destDoc,xmlNodePtr destParent,int options ATTRIBUTE_UNUSED)9000 xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
9001 		      xmlDocPtr sourceDoc,
9002 		      xmlNodePtr node,
9003 		      xmlDocPtr destDoc,
9004 		      xmlNodePtr destParent,
9005 		      int options ATTRIBUTE_UNUSED)
9006 {
9007     int ret = 0;
9008     xmlNodePtr cur, curElem = NULL;
9009     xmlNsMapPtr nsMap = NULL;
9010     xmlNsMapItemPtr mi;
9011     xmlNsPtr ns = NULL;
9012     int depth = -1, adoptStr = 1;
9013     /* gather @parent's ns-decls. */
9014     int parnsdone;
9015     /* @ancestorsOnly should be set per option. */
9016     int ancestorsOnly = 0;
9017 
9018     /*
9019     * Optimize string adoption for equal or none dicts.
9020     */
9021     if ((sourceDoc != NULL) &&
9022 	(sourceDoc->dict == destDoc->dict))
9023 	adoptStr = 0;
9024     else
9025 	adoptStr = 1;
9026 
9027     /*
9028     * Get the ns-map from the context if available.
9029     */
9030     if (ctxt)
9031 	nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
9032     /*
9033     * Disable search for ns-decls in the parent-axis of the
9034     * destination element, if:
9035     * 1) there's no destination parent
9036     * 2) custom ns-reference handling is used
9037     */
9038     if ((destParent == NULL) ||
9039 	(ctxt && ctxt->getNsForNodeFunc))
9040     {
9041 	parnsdone = 1;
9042     } else
9043 	parnsdone = 0;
9044 
9045     cur = node;
9046     if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9047 	goto internal_error;
9048 
9049     while (cur != NULL) {
9050 	/*
9051 	* Paranoid source-doc sanity check.
9052 	*/
9053 	if (cur->doc != sourceDoc) {
9054 	    /*
9055 	    * We'll assume XIncluded nodes if the doc differs.
9056 	    * TODO: Do we need to reconciliate XIncluded nodes?
9057 	    * This here skips XIncluded nodes and tries to handle
9058 	    * broken sequences.
9059 	    */
9060 	    if (cur->next == NULL)
9061 		goto leave_node;
9062 	    do {
9063 		cur = cur->next;
9064 		if ((cur->type == XML_XINCLUDE_END) ||
9065 		    (cur->doc == node->doc))
9066 		    break;
9067 	    } while (cur->next != NULL);
9068 
9069 	    if (cur->doc != node->doc)
9070 		goto leave_node;
9071 	}
9072 	cur->doc = destDoc;
9073 	switch (cur->type) {
9074 	    case XML_XINCLUDE_START:
9075 	    case XML_XINCLUDE_END:
9076 		/*
9077 		* TODO
9078 		*/
9079 		return (-1);
9080 	    case XML_ELEMENT_NODE:
9081 		curElem = cur;
9082 		depth++;
9083 		/*
9084 		* Namespace declarations.
9085 		* - ns->href and ns->prefix are never in the dict, so
9086 		*   we need not move the values over to the destination dict.
9087 		* - Note that for custom handling of ns-references,
9088 		*   the ns-decls need not be stored in the ns-map,
9089 		*   since they won't be referenced by node->ns.
9090 		*/
9091 		if ((cur->nsDef) &&
9092 		    ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL)))
9093 		{
9094 		    if (! parnsdone) {
9095 			/*
9096 			* Gather @parent's in-scope ns-decls.
9097 			*/
9098 			if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9099 			    destParent) == -1)
9100 			    goto internal_error;
9101 			parnsdone = 1;
9102 		    }
9103 		    for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
9104 			/*
9105 			* NOTE: ns->prefix and ns->href are never in the dict.
9106 			* XML_TREE_ADOPT_STR(ns->prefix)
9107 			* XML_TREE_ADOPT_STR(ns->href)
9108 			*/
9109 			/*
9110 			* Does it shadow any ns-decl?
9111 			*/
9112 			if (XML_NSMAP_NOTEMPTY(nsMap)) {
9113 			    XML_NSMAP_FOREACH(nsMap, mi) {
9114 				if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9115 				    (mi->shadowDepth == -1) &&
9116 				    ((ns->prefix == mi->newNs->prefix) ||
9117 				    xmlStrEqual(ns->prefix,
9118 				    mi->newNs->prefix))) {
9119 
9120 				    mi->shadowDepth = depth;
9121 				}
9122 			    }
9123 			}
9124 			/*
9125 			* Push mapping.
9126 			*/
9127 			if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9128 			    ns, ns, depth) == NULL)
9129 			    goto internal_error;
9130 		    }
9131 		}
9132                 /* Falls through. */
9133 	    case XML_ATTRIBUTE_NODE:
9134 		/* No namespace, no fun. */
9135 		if (cur->ns == NULL)
9136 		    goto ns_end;
9137 
9138 		if (! parnsdone) {
9139 		    if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9140 			destParent) == -1)
9141 			goto internal_error;
9142 		    parnsdone = 1;
9143 		}
9144 		/*
9145 		* Adopt ns-references.
9146 		*/
9147 		if (XML_NSMAP_NOTEMPTY(nsMap)) {
9148 		    /*
9149 		    * Search for a mapping.
9150 		    */
9151 		    XML_NSMAP_FOREACH(nsMap, mi) {
9152 			if ((mi->shadowDepth == -1) &&
9153 			    (cur->ns == mi->oldNs)) {
9154 
9155 			    cur->ns = mi->newNs;
9156 			    goto ns_end;
9157 			}
9158 		    }
9159 		}
9160 		/*
9161 		* No matching namespace in scope. We need a new one.
9162 		*/
9163 		if ((ctxt) && (ctxt->getNsForNodeFunc)) {
9164 		    /*
9165 		    * User-defined behaviour.
9166 		    */
9167 		    ns = ctxt->getNsForNodeFunc(ctxt, cur,
9168 			cur->ns->href, cur->ns->prefix);
9169 		    /*
9170 		    * Insert mapping if ns is available; it's the users fault
9171 		    * if not.
9172 		    */
9173 		    if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9174 			    cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9175 			goto internal_error;
9176 		    cur->ns = ns;
9177 		} else {
9178 		    /*
9179 		    * Acquire a normalized ns-decl and add it to the map.
9180 		    */
9181 		    if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc,
9182 			/* ns-decls on curElem or on destDoc->oldNs */
9183 			destParent ? curElem : NULL,
9184 			cur->ns, &ns,
9185 			&nsMap, depth,
9186 			ancestorsOnly,
9187 			/* ns-decls must be prefixed for attributes. */
9188 			(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9189 			goto internal_error;
9190 		    cur->ns = ns;
9191 		}
9192 ns_end:
9193 		/*
9194 		* Further node properties.
9195 		* TODO: Is this all?
9196 		*/
9197 		XML_TREE_ADOPT_STR(cur->name)
9198 		if (cur->type == XML_ELEMENT_NODE) {
9199 		    cur->psvi = NULL;
9200 		    cur->line = 0;
9201 		    cur->extra = 0;
9202 		    /*
9203 		    * Walk attributes.
9204 		    */
9205 		    if (cur->properties != NULL) {
9206 			/*
9207 			* Process first attribute node.
9208 			*/
9209 			cur = (xmlNodePtr) cur->properties;
9210 			continue;
9211 		    }
9212 		} else {
9213 		    /*
9214 		    * Attributes.
9215 		    */
9216 		    if ((sourceDoc != NULL) &&
9217 			(((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
9218 		    {
9219 			xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
9220 		    }
9221 		    ((xmlAttrPtr) cur)->atype = 0;
9222 		    ((xmlAttrPtr) cur)->psvi = NULL;
9223 		}
9224 		break;
9225 	    case XML_TEXT_NODE:
9226 	    case XML_CDATA_SECTION_NODE:
9227 		/*
9228 		* This puts the content in the dest dict, only if
9229 		* it was previously in the source dict.
9230 		*/
9231 		XML_TREE_ADOPT_STR_2(cur->content)
9232 		goto leave_node;
9233 	    case XML_ENTITY_REF_NODE:
9234 		/*
9235 		* Remove reference to the entity-node.
9236 		*/
9237 		cur->content = NULL;
9238 		cur->children = NULL;
9239 		cur->last = NULL;
9240 		if ((destDoc->intSubset) || (destDoc->extSubset)) {
9241 		    xmlEntityPtr ent;
9242 		    /*
9243 		    * Assign new entity-node if available.
9244 		    */
9245 		    ent = xmlGetDocEntity(destDoc, cur->name);
9246 		    if (ent != NULL) {
9247 			cur->content = ent->content;
9248 			cur->children = (xmlNodePtr) ent;
9249 			cur->last = (xmlNodePtr) ent;
9250 		    }
9251 		}
9252 		goto leave_node;
9253 	    case XML_PI_NODE:
9254 		XML_TREE_ADOPT_STR(cur->name)
9255 		XML_TREE_ADOPT_STR_2(cur->content)
9256 		break;
9257 	    case XML_COMMENT_NODE:
9258 		break;
9259 	    default:
9260 		goto internal_error;
9261 	}
9262 	/*
9263 	* Walk the tree.
9264 	*/
9265 	if (cur->children != NULL) {
9266 	    cur = cur->children;
9267 	    continue;
9268 	}
9269 
9270 leave_node:
9271 	if (cur == node)
9272 	    break;
9273 	if ((cur->type == XML_ELEMENT_NODE) ||
9274 	    (cur->type == XML_XINCLUDE_START) ||
9275 	    (cur->type == XML_XINCLUDE_END))
9276 	{
9277 	    /*
9278 	    * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9279 	    */
9280 	    if (XML_NSMAP_NOTEMPTY(nsMap)) {
9281 		/*
9282 		* Pop mappings.
9283 		*/
9284 		while ((nsMap->last != NULL) &&
9285 		    (nsMap->last->depth >= depth))
9286 		{
9287 		    XML_NSMAP_POP(nsMap, mi)
9288 		}
9289 		/*
9290 		* Unshadow.
9291 		*/
9292 		XML_NSMAP_FOREACH(nsMap, mi) {
9293 		    if (mi->shadowDepth >= depth)
9294 			mi->shadowDepth = -1;
9295 		}
9296 	    }
9297 	    depth--;
9298 	}
9299 	if (cur->next != NULL)
9300 	    cur = cur->next;
9301 	else if ((cur->type == XML_ATTRIBUTE_NODE) &&
9302 	    (cur->parent->children != NULL))
9303 	{
9304 	    cur = cur->parent->children;
9305 	} else {
9306 	    cur = cur->parent;
9307 	    goto leave_node;
9308 	}
9309     }
9310 
9311     goto exit;
9312 
9313 internal_error:
9314     ret = -1;
9315 
9316 exit:
9317     /*
9318     * Cleanup.
9319     */
9320     if (nsMap != NULL) {
9321 	if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9322 	    /*
9323 	    * Just cleanup the map but don't free.
9324 	    */
9325 	    if (nsMap->first) {
9326 		if (nsMap->pool)
9327 		    nsMap->last->next = nsMap->pool;
9328 		nsMap->pool = nsMap->first;
9329 		nsMap->first = NULL;
9330 	    }
9331 	} else
9332 	    xmlDOMWrapNsMapFree(nsMap);
9333     }
9334     return(ret);
9335 }
9336 
9337 /*
9338 * xmlDOMWrapCloneNode:
9339 * @ctxt: the optional context for custom processing
9340 * @sourceDoc: the optional sourceDoc
9341 * @node: the node to start with
9342 * @resNode: the clone of the given @node
9343 * @destDoc: the destination doc
9344 * @destParent: the optional new parent of @node in @destDoc
9345 * @deep: descend into child if set
9346 * @options: option flags
9347 *
9348 * References of out-of scope ns-decls are remapped to point to @destDoc:
9349 * 1) If @destParent is given, then nsDef entries on element-nodes are used
9350 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used.
9351 *    This is the case when you don't know already where the cloned branch
9352 *    will be added to.
9353 *
9354 * If @destParent is given, it ensures that the tree is namespace
9355 * wellformed by creating additional ns-decls where needed.
9356 * Note that, since prefixes of already existent ns-decls can be
9357 * shadowed by this process, it could break QNames in attribute
9358 * values or element content.
9359 * TODO:
9360 *   1) What to do with XInclude? Currently this returns an error for XInclude.
9361 *
9362 * Returns 0 if the operation succeeded,
9363 *         1 if a node of unsupported (or not yet supported) type was given,
9364 *         -1 on API/internal errors.
9365 */
9366 
9367 int
xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr sourceDoc,xmlNodePtr node,xmlNodePtr * resNode,xmlDocPtr destDoc,xmlNodePtr destParent,int deep,int options ATTRIBUTE_UNUSED)9368 xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt,
9369 		      xmlDocPtr sourceDoc,
9370 		      xmlNodePtr node,
9371 		      xmlNodePtr *resNode,
9372 		      xmlDocPtr destDoc,
9373 		      xmlNodePtr destParent,
9374 		      int deep,
9375 		      int options ATTRIBUTE_UNUSED)
9376 {
9377     int ret = 0;
9378     xmlNodePtr cur, curElem = NULL;
9379     xmlNsMapPtr nsMap = NULL;
9380     xmlNsMapItemPtr mi;
9381     xmlNsPtr ns;
9382     int depth = -1;
9383     /* int adoptStr = 1; */
9384     /* gather @parent's ns-decls. */
9385     int parnsdone = 0;
9386     /*
9387     * @ancestorsOnly:
9388     * TODO: @ancestorsOnly should be set per option.
9389     *
9390     */
9391     int ancestorsOnly = 0;
9392     xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL;
9393     xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
9394     xmlDictPtr dict; /* The destination dict */
9395 
9396     if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
9397 	return(-1);
9398     /*
9399     * TODO: Initially we support only element-nodes.
9400     */
9401     if (node->type != XML_ELEMENT_NODE)
9402 	return(1);
9403     /*
9404     * Check node->doc sanity.
9405     */
9406     if ((node->doc != NULL) && (sourceDoc != NULL) &&
9407 	(node->doc != sourceDoc)) {
9408 	/*
9409 	* Might be an XIncluded node.
9410 	*/
9411 	return (-1);
9412     }
9413     if (sourceDoc == NULL)
9414 	sourceDoc = node->doc;
9415     if (sourceDoc == NULL)
9416         return (-1);
9417 
9418     dict = destDoc->dict;
9419     /*
9420     * Reuse the namespace map of the context.
9421     */
9422     if (ctxt)
9423 	nsMap = (xmlNsMapPtr) ctxt->namespaceMap;
9424 
9425     *resNode = NULL;
9426 
9427     cur = node;
9428     if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9429         return(-1);
9430 
9431     while (cur != NULL) {
9432 	if (cur->doc != sourceDoc) {
9433 	    /*
9434 	    * We'll assume XIncluded nodes if the doc differs.
9435 	    * TODO: Do we need to reconciliate XIncluded nodes?
9436 	    * TODO: This here returns -1 in this case.
9437 	    */
9438 	    goto internal_error;
9439 	}
9440 	/*
9441 	* Create a new node.
9442 	*/
9443 	switch (cur->type) {
9444 	    case XML_XINCLUDE_START:
9445 	    case XML_XINCLUDE_END:
9446 		/*
9447 		* TODO: What to do with XInclude?
9448 		*/
9449 		goto internal_error;
9450 		break;
9451 	    case XML_ELEMENT_NODE:
9452 	    case XML_TEXT_NODE:
9453 	    case XML_CDATA_SECTION_NODE:
9454 	    case XML_COMMENT_NODE:
9455 	    case XML_PI_NODE:
9456 	    case XML_DOCUMENT_FRAG_NODE:
9457 	    case XML_ENTITY_REF_NODE:
9458 	    case XML_ENTITY_NODE:
9459 		/*
9460 		* Nodes of xmlNode structure.
9461 		*/
9462 		clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
9463 		if (clone == NULL) {
9464 		    xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node");
9465 		    goto internal_error;
9466 		}
9467 		memset(clone, 0, sizeof(xmlNode));
9468 		/*
9469 		* Set hierarchical links.
9470 		*/
9471 		if (resultClone != NULL) {
9472 		    clone->parent = parentClone;
9473 		    if (prevClone) {
9474 			prevClone->next = clone;
9475 			clone->prev = prevClone;
9476 		    } else
9477 			parentClone->children = clone;
9478 		} else
9479 		    resultClone = clone;
9480 
9481 		break;
9482 	    case XML_ATTRIBUTE_NODE:
9483 		/*
9484 		* Attributes (xmlAttr).
9485 		*/
9486 		clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr));
9487 		if (clone == NULL) {
9488 		    xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node");
9489 		    goto internal_error;
9490 		}
9491 		memset(clone, 0, sizeof(xmlAttr));
9492 		/*
9493 		* Set hierarchical links.
9494 		* TODO: Change this to add to the end of attributes.
9495 		*/
9496 		if (resultClone != NULL) {
9497 		    clone->parent = parentClone;
9498 		    if (prevClone) {
9499 			prevClone->next = clone;
9500 			clone->prev = prevClone;
9501 		    } else
9502 			parentClone->properties = (xmlAttrPtr) clone;
9503 		} else
9504 		    resultClone = clone;
9505 		break;
9506 	    default:
9507 		/*
9508 		* TODO QUESTION: Any other nodes expected?
9509 		*/
9510 		goto internal_error;
9511 	}
9512 
9513 	clone->type = cur->type;
9514 	clone->doc = destDoc;
9515 
9516 	/*
9517 	* Clone the name of the node if any.
9518 	*/
9519 	if (cur->name == xmlStringText)
9520 	    clone->name = xmlStringText;
9521 	else if (cur->name == xmlStringTextNoenc)
9522 	    /*
9523 	    * NOTE: Although xmlStringTextNoenc is never assigned to a node
9524 	    *   in tree.c, it might be set in Libxslt via
9525 	    *   "xsl:disable-output-escaping".
9526 	    */
9527 	    clone->name = xmlStringTextNoenc;
9528 	else if (cur->name == xmlStringComment)
9529 	    clone->name = xmlStringComment;
9530 	else if (cur->name != NULL) {
9531 	    DICT_CONST_COPY(cur->name, clone->name);
9532 	}
9533 
9534 	switch (cur->type) {
9535 	    case XML_XINCLUDE_START:
9536 	    case XML_XINCLUDE_END:
9537 		/*
9538 		* TODO
9539 		*/
9540 		return (-1);
9541 	    case XML_ELEMENT_NODE:
9542 		curElem = cur;
9543 		depth++;
9544 		/*
9545 		* Namespace declarations.
9546 		*/
9547 		if (cur->nsDef != NULL) {
9548 		    if (! parnsdone) {
9549 			if (destParent && (ctxt == NULL)) {
9550 			    /*
9551 			    * Gather @parent's in-scope ns-decls.
9552 			    */
9553 			    if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
9554 				destParent) == -1)
9555 				goto internal_error;
9556 			}
9557 			parnsdone = 1;
9558 		    }
9559 		    /*
9560 		    * Clone namespace declarations.
9561 		    */
9562 		    cloneNsDefSlot = &(clone->nsDef);
9563 		    for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
9564 			/*
9565 			* Create a new xmlNs.
9566 			*/
9567 			cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
9568 			if (cloneNs == NULL) {
9569 			    xmlTreeErrMemory("xmlDOMWrapCloneNode(): "
9570 				"allocating namespace");
9571 			    return(-1);
9572 			}
9573 			memset(cloneNs, 0, sizeof(xmlNs));
9574 			cloneNs->type = XML_LOCAL_NAMESPACE;
9575 
9576 			if (ns->href != NULL)
9577 			    cloneNs->href = xmlStrdup(ns->href);
9578 			if (ns->prefix != NULL)
9579 			    cloneNs->prefix = xmlStrdup(ns->prefix);
9580 
9581 			*cloneNsDefSlot = cloneNs;
9582 			cloneNsDefSlot = &(cloneNs->next);
9583 
9584 			/*
9585 			* Note that for custom handling of ns-references,
9586 			* the ns-decls need not be stored in the ns-map,
9587 			* since they won't be referenced by node->ns.
9588 			*/
9589 			if ((ctxt == NULL) ||
9590 			    (ctxt->getNsForNodeFunc == NULL))
9591 			{
9592 			    /*
9593 			    * Does it shadow any ns-decl?
9594 			    */
9595 			    if (XML_NSMAP_NOTEMPTY(nsMap)) {
9596 				XML_NSMAP_FOREACH(nsMap, mi) {
9597 				    if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
9598 					(mi->shadowDepth == -1) &&
9599 					((ns->prefix == mi->newNs->prefix) ||
9600 					xmlStrEqual(ns->prefix,
9601 					mi->newNs->prefix))) {
9602 					/*
9603 					* Mark as shadowed at the current
9604 					* depth.
9605 					*/
9606 					mi->shadowDepth = depth;
9607 				    }
9608 				}
9609 			    }
9610 			    /*
9611 			    * Push mapping.
9612 			    */
9613 			    if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9614 				ns, cloneNs, depth) == NULL)
9615 				goto internal_error;
9616 			}
9617 		    }
9618 		}
9619 		/* cur->ns will be processed further down. */
9620 		break;
9621 	    case XML_ATTRIBUTE_NODE:
9622 		/* IDs will be processed further down. */
9623 		/* cur->ns will be processed further down. */
9624 		break;
9625 	    case XML_TEXT_NODE:
9626 	    case XML_CDATA_SECTION_NODE:
9627 		/*
9628 		* Note that this will also cover the values of attributes.
9629 		*/
9630 		DICT_COPY(cur->content, clone->content);
9631 		goto leave_node;
9632 	    case XML_ENTITY_NODE:
9633 		/* TODO: What to do here? */
9634 		goto leave_node;
9635 	    case XML_ENTITY_REF_NODE:
9636 		if (sourceDoc != destDoc) {
9637 		    if ((destDoc->intSubset) || (destDoc->extSubset)) {
9638 			xmlEntityPtr ent;
9639 			/*
9640 			* Different doc: Assign new entity-node if available.
9641 			*/
9642 			ent = xmlGetDocEntity(destDoc, cur->name);
9643 			if (ent != NULL) {
9644 			    clone->content = ent->content;
9645 			    clone->children = (xmlNodePtr) ent;
9646 			    clone->last = (xmlNodePtr) ent;
9647 			}
9648 		    }
9649 		} else {
9650 		    /*
9651 		    * Same doc: Use the current node's entity declaration
9652 		    * and value.
9653 		    */
9654 		    clone->content = cur->content;
9655 		    clone->children = cur->children;
9656 		    clone->last = cur->last;
9657 		}
9658 		goto leave_node;
9659 	    case XML_PI_NODE:
9660 		DICT_COPY(cur->content, clone->content);
9661 		goto leave_node;
9662 	    case XML_COMMENT_NODE:
9663 		DICT_COPY(cur->content, clone->content);
9664 		goto leave_node;
9665 	    default:
9666 		goto internal_error;
9667 	}
9668 
9669 	if (cur->ns == NULL)
9670 	    goto end_ns_reference;
9671 
9672 /* handle_ns_reference: */
9673 	/*
9674 	** The following will take care of references to ns-decls ********
9675 	** and is intended only for element- and attribute-nodes.
9676 	**
9677 	*/
9678 	if (! parnsdone) {
9679 	    if (destParent && (ctxt == NULL)) {
9680 		if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1)
9681 		    goto internal_error;
9682 	    }
9683 	    parnsdone = 1;
9684 	}
9685 	/*
9686 	* Adopt ns-references.
9687 	*/
9688 	if (XML_NSMAP_NOTEMPTY(nsMap)) {
9689 	    /*
9690 	    * Search for a mapping.
9691 	    */
9692 	    XML_NSMAP_FOREACH(nsMap, mi) {
9693 		if ((mi->shadowDepth == -1) &&
9694 		    (cur->ns == mi->oldNs)) {
9695 		    /*
9696 		    * This is the nice case: a mapping was found.
9697 		    */
9698 		    clone->ns = mi->newNs;
9699 		    goto end_ns_reference;
9700 		}
9701 	    }
9702 	}
9703 	/*
9704 	* No matching namespace in scope. We need a new one.
9705 	*/
9706 	if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) {
9707 	    /*
9708 	    * User-defined behaviour.
9709 	    */
9710 	    ns = ctxt->getNsForNodeFunc(ctxt, cur,
9711 		cur->ns->href, cur->ns->prefix);
9712 	    /*
9713 	    * Add user's mapping.
9714 	    */
9715 	    if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
9716 		cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
9717 		goto internal_error;
9718 	    clone->ns = ns;
9719 	} else {
9720 	    /*
9721 	    * Acquire a normalized ns-decl and add it to the map.
9722 	    */
9723 	    if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc,
9724 		/* ns-decls on curElem or on destDoc->oldNs */
9725 		destParent ? curElem : NULL,
9726 		cur->ns, &ns,
9727 		&nsMap, depth,
9728 		/* if we need to search only in the ancestor-axis */
9729 		ancestorsOnly,
9730 		/* ns-decls must be prefixed for attributes. */
9731 		(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
9732 		goto internal_error;
9733 	    clone->ns = ns;
9734 	}
9735 
9736 end_ns_reference:
9737 
9738 	/*
9739 	* Some post-processing.
9740 	*
9741 	* Handle ID attributes.
9742 	*/
9743 	if ((clone->type == XML_ATTRIBUTE_NODE) &&
9744 	    (clone->parent != NULL))
9745 	{
9746 	    if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
9747 
9748 		xmlChar *idVal;
9749 
9750 		idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
9751 		if (idVal != NULL) {
9752 		    if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) {
9753 			/* TODO: error message. */
9754 			xmlFree(idVal);
9755 			goto internal_error;
9756 		    }
9757 		    xmlFree(idVal);
9758 		}
9759 	    }
9760 	}
9761 	/*
9762 	**
9763 	** The following will traverse the tree **************************
9764 	**
9765 	*
9766 	* Walk the element's attributes before descending into child-nodes.
9767 	*/
9768 	if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) {
9769 	    prevClone = NULL;
9770 	    parentClone = clone;
9771 	    cur = (xmlNodePtr) cur->properties;
9772 	    continue;
9773 	}
9774 into_content:
9775 	/*
9776 	* Descend into child-nodes.
9777 	*/
9778 	if (cur->children != NULL) {
9779 	    if (deep || (cur->type == XML_ATTRIBUTE_NODE)) {
9780 		prevClone = NULL;
9781 		parentClone = clone;
9782 		cur = cur->children;
9783 		continue;
9784 	    }
9785 	}
9786 
9787 leave_node:
9788 	/*
9789 	* At this point we are done with the node, its content
9790 	* and an element-nodes's attribute-nodes.
9791 	*/
9792 	if (cur == node)
9793 	    break;
9794 	if ((cur->type == XML_ELEMENT_NODE) ||
9795 	    (cur->type == XML_XINCLUDE_START) ||
9796 	    (cur->type == XML_XINCLUDE_END)) {
9797 	    /*
9798 	    * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
9799 	    */
9800 	    if (XML_NSMAP_NOTEMPTY(nsMap)) {
9801 		/*
9802 		* Pop mappings.
9803 		*/
9804 		while ((nsMap->last != NULL) &&
9805 		    (nsMap->last->depth >= depth))
9806 		{
9807 		    XML_NSMAP_POP(nsMap, mi)
9808 		}
9809 		/*
9810 		* Unshadow.
9811 		*/
9812 		XML_NSMAP_FOREACH(nsMap, mi) {
9813 		    if (mi->shadowDepth >= depth)
9814 			mi->shadowDepth = -1;
9815 		}
9816 	    }
9817 	    depth--;
9818 	}
9819 	if (cur->next != NULL) {
9820 	    prevClone = clone;
9821 	    cur = cur->next;
9822 	} else if (cur->type != XML_ATTRIBUTE_NODE) {
9823 	    /*
9824 	    * Set clone->last.
9825 	    */
9826 	    if (clone->parent != NULL)
9827 		clone->parent->last = clone;
9828 	    clone = clone->parent;
9829 	    if (clone != NULL)
9830 		parentClone = clone->parent;
9831 	    /*
9832 	    * Process parent --> next;
9833 	    */
9834 	    cur = cur->parent;
9835 	    goto leave_node;
9836 	} else {
9837 	    /* This is for attributes only. */
9838 	    clone = clone->parent;
9839 	    parentClone = clone->parent;
9840 	    /*
9841 	    * Process parent-element --> children.
9842 	    */
9843 	    cur = cur->parent;
9844 	    goto into_content;
9845 	}
9846     }
9847     goto exit;
9848 
9849 internal_error:
9850     ret = -1;
9851 
9852 exit:
9853     /*
9854     * Cleanup.
9855     */
9856     if (nsMap != NULL) {
9857 	if ((ctxt) && (ctxt->namespaceMap == nsMap)) {
9858 	    /*
9859 	    * Just cleanup the map but don't free.
9860 	    */
9861 	    if (nsMap->first) {
9862 		if (nsMap->pool)
9863 		    nsMap->last->next = nsMap->pool;
9864 		nsMap->pool = nsMap->first;
9865 		nsMap->first = NULL;
9866 	    }
9867 	} else
9868 	    xmlDOMWrapNsMapFree(nsMap);
9869     }
9870     /*
9871     * TODO: Should we try a cleanup of the cloned node in case of a
9872     * fatal error?
9873     */
9874     *resNode = resultClone;
9875     return (ret);
9876 }
9877 
9878 /*
9879 * xmlDOMWrapAdoptAttr:
9880 * @ctxt: the optional context for custom processing
9881 * @sourceDoc: the optional source document of attr
9882 * @attr: the attribute-node to be adopted
9883 * @destDoc: the destination doc for adoption
9884 * @destParent: the optional new parent of @attr in @destDoc
9885 * @options: option flags
9886 *
9887 * @attr is adopted by @destDoc.
9888 * Ensures that ns-references point to @destDoc: either to
9889 * elements->nsDef entries if @destParent is given, or to
9890 * @destDoc->oldNs otherwise.
9891 *
9892 * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
9893 */
9894 static int
xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr sourceDoc,xmlAttrPtr attr,xmlDocPtr destDoc,xmlNodePtr destParent,int options ATTRIBUTE_UNUSED)9895 xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
9896 		    xmlDocPtr sourceDoc,
9897 		    xmlAttrPtr attr,
9898 		    xmlDocPtr destDoc,
9899 		    xmlNodePtr destParent,
9900 		    int options ATTRIBUTE_UNUSED)
9901 {
9902     xmlNodePtr cur;
9903     int adoptStr = 1;
9904 
9905     if ((attr == NULL) || (destDoc == NULL))
9906 	return (-1);
9907 
9908     attr->doc = destDoc;
9909     if (attr->ns != NULL) {
9910 	xmlNsPtr ns = NULL;
9911 
9912 	if (ctxt != NULL) {
9913 	    /* TODO: User defined. */
9914 	}
9915 	/* XML Namespace. */
9916 	if (IS_STR_XML(attr->ns->prefix)) {
9917 	    ns = xmlTreeEnsureXMLDecl(destDoc);
9918 	} else if (destParent == NULL) {
9919 	    /*
9920 	    * Store in @destDoc->oldNs.
9921 	    */
9922 	    ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
9923 	} else {
9924 	    /*
9925 	    * Declare on @destParent.
9926 	    */
9927 	    if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
9928 		&ns, 1) == -1)
9929 		goto internal_error;
9930 	    if (ns == NULL) {
9931 		ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
9932 		    attr->ns->href, attr->ns->prefix, 1);
9933 	    }
9934 	}
9935 	if (ns == NULL)
9936 	    goto internal_error;
9937 	attr->ns = ns;
9938     }
9939 
9940     XML_TREE_ADOPT_STR(attr->name);
9941     attr->atype = 0;
9942     attr->psvi = NULL;
9943     /*
9944     * Walk content.
9945     */
9946     if (attr->children == NULL)
9947 	return (0);
9948     cur = attr->children;
9949     if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
9950         goto internal_error;
9951     while (cur != NULL) {
9952 	cur->doc = destDoc;
9953 	switch (cur->type) {
9954 	    case XML_TEXT_NODE:
9955 	    case XML_CDATA_SECTION_NODE:
9956 		XML_TREE_ADOPT_STR_2(cur->content)
9957 		break;
9958 	    case XML_ENTITY_REF_NODE:
9959 		/*
9960 		* Remove reference to the entity-node.
9961 		*/
9962 		cur->content = NULL;
9963 		cur->children = NULL;
9964 		cur->last = NULL;
9965 		if ((destDoc->intSubset) || (destDoc->extSubset)) {
9966 		    xmlEntityPtr ent;
9967 		    /*
9968 		    * Assign new entity-node if available.
9969 		    */
9970 		    ent = xmlGetDocEntity(destDoc, cur->name);
9971 		    if (ent != NULL) {
9972 			cur->content = ent->content;
9973 			cur->children = (xmlNodePtr) ent;
9974 			cur->last = (xmlNodePtr) ent;
9975 		    }
9976 		}
9977 		break;
9978 	    default:
9979 		break;
9980 	}
9981 	if (cur->children != NULL) {
9982 	    cur = cur->children;
9983 	    continue;
9984 	}
9985 next_sibling:
9986 	if (cur == (xmlNodePtr) attr)
9987 	    break;
9988 	if (cur->next != NULL)
9989 	    cur = cur->next;
9990 	else {
9991 	    cur = cur->parent;
9992 	    goto next_sibling;
9993 	}
9994     }
9995     return (0);
9996 internal_error:
9997     return (-1);
9998 }
9999 
10000 /*
10001 * xmlDOMWrapAdoptNode:
10002 * @ctxt: the optional context for custom processing
10003 * @sourceDoc: the optional sourceDoc
10004 * @node: the node to start with
10005 * @destDoc: the destination doc
10006 * @destParent: the optional new parent of @node in @destDoc
10007 * @options: option flags
10008 *
10009 * References of out-of scope ns-decls are remapped to point to @destDoc:
10010 * 1) If @destParent is given, then nsDef entries on element-nodes are used
10011 * 2) If *no* @destParent is given, then @destDoc->oldNs entries are used
10012 *    This is the case when you have an unlinked node and just want to move it
10013 *    to the context of
10014 *
10015 * If @destParent is given, it ensures that the tree is namespace
10016 * wellformed by creating additional ns-decls where needed.
10017 * Note that, since prefixes of already existent ns-decls can be
10018 * shadowed by this process, it could break QNames in attribute
10019 * values or element content.
10020 * NOTE: This function was not intensively tested.
10021 *
10022 * Returns 0 if the operation succeeded,
10023 *         1 if a node of unsupported type was given,
10024 *         2 if a node of not yet supported type was given and
10025 *         -1 on API/internal errors.
10026 */
10027 int
xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,xmlDocPtr sourceDoc,xmlNodePtr node,xmlDocPtr destDoc,xmlNodePtr destParent,int options)10028 xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt,
10029 		    xmlDocPtr sourceDoc,
10030 		    xmlNodePtr node,
10031 		    xmlDocPtr destDoc,
10032 		    xmlNodePtr destParent,
10033 		    int options)
10034 {
10035     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
10036         (destDoc == NULL) ||
10037 	((destParent != NULL) && (destParent->doc != destDoc)))
10038 	return(-1);
10039     /*
10040     * Check node->doc sanity.
10041     */
10042     if ((node->doc != NULL) && (sourceDoc != NULL) &&
10043 	(node->doc != sourceDoc)) {
10044 	/*
10045 	* Might be an XIncluded node.
10046 	*/
10047 	return (-1);
10048     }
10049     if (sourceDoc == NULL)
10050 	sourceDoc = node->doc;
10051     if (sourceDoc == destDoc)
10052 	return (-1);
10053     switch (node->type) {
10054 	case XML_ELEMENT_NODE:
10055 	case XML_ATTRIBUTE_NODE:
10056 	case XML_TEXT_NODE:
10057 	case XML_CDATA_SECTION_NODE:
10058 	case XML_ENTITY_REF_NODE:
10059 	case XML_PI_NODE:
10060 	case XML_COMMENT_NODE:
10061 	    break;
10062 	case XML_DOCUMENT_FRAG_NODE:
10063 	    /* TODO: Support document-fragment-nodes. */
10064 	    return (2);
10065 	default:
10066 	    return (1);
10067     }
10068     /*
10069     * Unlink only if @node was not already added to @destParent.
10070     */
10071     if ((node->parent != NULL) && (destParent != node->parent))
10072 	xmlUnlinkNode(node);
10073 
10074     if (node->type == XML_ELEMENT_NODE) {
10075 	    return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
10076 		    destDoc, destParent, options));
10077     } else if (node->type == XML_ATTRIBUTE_NODE) {
10078 	    return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
10079 		(xmlAttrPtr) node, destDoc, destParent, options));
10080     } else {
10081 	xmlNodePtr cur = node;
10082 	int adoptStr = 1;
10083 
10084 	cur->doc = destDoc;
10085 	/*
10086 	* Optimize string adoption.
10087 	*/
10088 	if ((sourceDoc != NULL) &&
10089 	    (sourceDoc->dict == destDoc->dict))
10090 		adoptStr = 0;
10091 	switch (node->type) {
10092 	    case XML_TEXT_NODE:
10093 	    case XML_CDATA_SECTION_NODE:
10094 		XML_TREE_ADOPT_STR_2(node->content)
10095 		    break;
10096 	    case XML_ENTITY_REF_NODE:
10097 		/*
10098 		* Remove reference to the entity-node.
10099 		*/
10100 		node->content = NULL;
10101 		node->children = NULL;
10102 		node->last = NULL;
10103 		if ((destDoc->intSubset) || (destDoc->extSubset)) {
10104 		    xmlEntityPtr ent;
10105 		    /*
10106 		    * Assign new entity-node if available.
10107 		    */
10108 		    ent = xmlGetDocEntity(destDoc, node->name);
10109 		    if (ent != NULL) {
10110 			node->content = ent->content;
10111 			node->children = (xmlNodePtr) ent;
10112 			node->last = (xmlNodePtr) ent;
10113 		    }
10114 		}
10115 		XML_TREE_ADOPT_STR(node->name)
10116 		break;
10117 	    case XML_PI_NODE: {
10118 		XML_TREE_ADOPT_STR(node->name)
10119 		XML_TREE_ADOPT_STR_2(node->content)
10120 		break;
10121 	    }
10122 	    default:
10123 		break;
10124 	}
10125     }
10126     return (0);
10127 }
10128 
10129 #define bottom_tree
10130 #include "elfgcchack.h"
10131