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