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