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