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