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