Coverage Report

Created: 2025-11-16 09:57

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