VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/tree.c@ 105770

Last change on this file since 105770 was 105420, checked in by vboxsync, 4 months ago

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette