VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.2/tree.c@ 61328

最後變更 在這個檔案從61328是 58076,由 vboxsync 提交於 9 年 前

upstream fixes post 2.9.2

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

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