VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.14/tree.c@ 102315

最後變更 在這個檔案從102315是 95312,由 vboxsync 提交於 2 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

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

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