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