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