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