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