~ubuntu-branches/ubuntu/utopic/libxml2/utopic

« back to all changes in this revision

Viewing changes to .pc/0017-Fix-a-potential-NULL-dereference-in-tree-code.patch/tree.c

  • Committer: Package Import Robot
  • Author(s): Aron Xu, Christian Svensson, Daniel Schepler, Helmut Grohne, Adam Conrad, Matthias Klose, Aron Xu
  • Date: 2014-07-09 05:40:15 UTC
  • mto: This revision was merged to the branch mainline in revision 75.
  • Revision ID: package-import@ubuntu.com-20140709054015-rdnfjxrf3zvmw6l7
[ Christian Svensson ]
* Do not build-depend on readline (Closes: #742350)

[ Daniel Schepler ]
* Patch to bootstrap without python (Closes: #738080)

[ Helmut Grohne ]
* Drop unneeded B-D on perl and binutils (Closes: #753005)

[ Adam Conrad ]
* Actually run dh_autoreconf, which the old/new mixed rules file misses.

[ Matthias Klose ]
* Add patch to fix python multiarch issue
* Allow the package to cross-build by tweaking B-Ds on python
* Set PYTHON_LIBS for cross builds

[ Aron Xu ]
* Use correct $CC
* Configure udeb without python
* New round of cherry-picking upstream fixes
  - Includes fixes for CVE-2014-0191 (Closes: #747309).
* Call prename with -vf
* Require python-all-dev (>= 2.7.5-5~)
* Bump std-ver: 3.9.4 -> 3.9.5, no change

Show diffs side-by-side

added added

removed removed

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