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