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