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