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