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