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