VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/tree.c

Last change on this file was 104106, checked in by vboxsync, 8 weeks ago

libxml2-2.9.14: Applied and adjusted our libxml2 changes to 2.9.14. bugref:10640

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

© 2023 Oracle
ContactPrivacy policyTerms of Use