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