Coverage Report

Created: 2025-07-18 06:31

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