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