Coverage Report

Created: 2024-02-11 06:19

/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
#ifdef LIBXML_DEBUG_ENABLED
42
#include <libxml/debugXML.h>
43
#endif
44
45
#include "private/buf.h"
46
#include "private/entities.h"
47
#include "private/error.h"
48
#include "private/tree.h"
49
50
int __xmlRegisterCallbacks = 0;
51
52
/************************************************************************
53
 *                  *
54
 *    Forward declarations          *
55
 *                  *
56
 ************************************************************************/
57
58
static xmlNsPtr
59
xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
60
61
static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
62
63
/************************************************************************
64
 *                  *
65
 *    A few static variables and macros     *
66
 *                  *
67
 ************************************************************************/
68
/* #undef xmlStringText */
69
const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
70
/* #undef xmlStringTextNoenc */
71
const xmlChar xmlStringTextNoenc[] =
72
              { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
73
/* #undef xmlStringComment */
74
const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
75
76
static int xmlCompressMode = 0;
77
78
530k
#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) {   \
79
530k
    xmlNodePtr ulccur = (n)->children;          \
80
530k
    if (ulccur == NULL) {           \
81
44
        (n)->last = NULL;           \
82
530k
    } else {               \
83
530k
        while (ulccur->next != NULL) {         \
84
0
    ulccur->parent = (n);         \
85
0
    ulccur = ulccur->next;          \
86
0
  }                \
87
530k
  ulccur->parent = (n);           \
88
530k
  (n)->last = ulccur;           \
89
530k
}}
90
91
0
#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
92
0
  (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
93
94
/************************************************************************
95
 *                  *
96
 *    Functions to move to entities.c once the    *
97
 *    API freeze is smoothen and they can be made public. *
98
 *                  *
99
 ************************************************************************/
100
#include <libxml/hash.h>
101
102
#ifdef LIBXML_TREE_ENABLED
103
/**
104
 * xmlGetEntityFromDtd:
105
 * @dtd:  A pointer to the DTD to search
106
 * @name:  The entity name
107
 *
108
 * Do an entity lookup in the DTD entity hash table and
109
 * return the corresponding entity, if found.
110
 *
111
 * Returns A pointer to the entity structure or NULL if not found.
112
 */
113
static xmlEntityPtr
114
0
xmlGetEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
115
0
    xmlEntitiesTablePtr table;
116
117
0
    if((dtd != NULL) && (dtd->entities != NULL)) {
118
0
  table = (xmlEntitiesTablePtr) dtd->entities;
119
0
  return((xmlEntityPtr) xmlHashLookup(table, name));
120
  /* return(xmlGetEntityFromTable(table, name)); */
121
0
    }
122
0
    return(NULL);
123
0
}
124
/**
125
 * xmlGetParameterEntityFromDtd:
126
 * @dtd:  A pointer to the DTD to search
127
 * @name:  The entity name
128
 *
129
 * Do an entity lookup in the DTD parameter entity hash table and
130
 * return the corresponding entity, if found.
131
 *
132
 * Returns A pointer to the entity structure or NULL if not found.
133
 */
134
static xmlEntityPtr
135
0
xmlGetParameterEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
136
0
    xmlEntitiesTablePtr table;
137
138
0
    if ((dtd != NULL) && (dtd->pentities != NULL)) {
139
0
  table = (xmlEntitiesTablePtr) dtd->pentities;
140
0
  return((xmlEntityPtr) xmlHashLookup(table, name));
141
  /* return(xmlGetEntityFromTable(table, name)); */
142
0
    }
143
0
    return(NULL);
144
0
}
145
#endif /* LIBXML_TREE_ENABLED */
146
147
/************************************************************************
148
 *                  *
149
 *      QName handling helper       *
150
 *                  *
151
 ************************************************************************/
152
153
/**
154
 * xmlBuildQName:
155
 * @ncname:  the Name
156
 * @prefix:  the prefix
157
 * @memory:  preallocated memory
158
 * @len:  preallocated memory length
159
 *
160
 * Builds the QName @prefix:@ncname in @memory if there is enough space
161
 * and prefix is not NULL nor empty, otherwise allocate a new string.
162
 * If prefix is NULL or empty it returns ncname.
163
 *
164
 * Returns the new string which must be freed by the caller if different from
165
 *         @memory and @ncname or NULL in case of error
166
 */
167
xmlChar *
168
xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix,
169
60.2k
        xmlChar *memory, int len) {
170
60.2k
    int lenn, lenp;
171
60.2k
    xmlChar *ret;
172
173
60.2k
    if (ncname == NULL) return(NULL);
174
60.2k
    if (prefix == NULL) return((xmlChar *) ncname);
175
176
60.2k
    lenn = strlen((char *) ncname);
177
60.2k
    lenp = strlen((char *) prefix);
178
179
60.2k
    if ((memory == NULL) || (len < lenn + lenp + 2)) {
180
8.06k
  ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
181
8.06k
  if (ret == NULL)
182
837
      return(NULL);
183
52.1k
    } else {
184
52.1k
  ret = memory;
185
52.1k
    }
186
59.4k
    memcpy(&ret[0], prefix, lenp);
187
59.4k
    ret[lenp] = ':';
188
59.4k
    memcpy(&ret[lenp + 1], ncname, lenn);
189
59.4k
    ret[lenn + lenp + 1] = 0;
190
59.4k
    return(ret);
191
60.2k
}
192
193
/**
194
 * xmlSplitQName2:
195
 * @name:  the full QName
196
 * @prefix:  a xmlChar **
197
 *
198
 * DEPRECATED: This function doesn't report malloc failures.
199
 *
200
 * parse an XML qualified name string
201
 *
202
 * [NS 5] QName ::= (Prefix ':')? LocalPart
203
 *
204
 * [NS 6] Prefix ::= NCName
205
 *
206
 * [NS 7] LocalPart ::= NCName
207
 *
208
 * Returns NULL if the name doesn't have a prefix. Otherwise, returns the
209
 * local part, and prefix is updated to get the Prefix. Both the return value
210
 * and the prefix must be freed by the caller.
211
 */
212
xmlChar *
213
15.9k
xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
214
15.9k
    int len = 0;
215
15.9k
    xmlChar *ret = NULL;
216
217
15.9k
    if (prefix == NULL) return(NULL);
218
15.9k
    *prefix = NULL;
219
15.9k
    if (name == NULL) return(NULL);
220
221
#ifndef XML_XML_NAMESPACE
222
    /* xml: prefix is not really a namespace */
223
    if ((name[0] == 'x') && (name[1] == 'm') &&
224
        (name[2] == 'l') && (name[3] == ':'))
225
  return(NULL);
226
#endif
227
228
    /* nasty but valid */
229
15.5k
    if (name[0] == ':')
230
1.17k
  return(NULL);
231
232
    /*
233
     * we are not trying to validate but just to cut, and yes it will
234
     * work even if this is as set of UTF-8 encoded chars
235
     */
236
126k
    while ((name[len] != 0) && (name[len] != ':'))
237
112k
  len++;
238
239
14.4k
    if (name[len] == 0)
240
6.08k
  return(NULL);
241
242
8.33k
    *prefix = xmlStrndup(name, len);
243
8.33k
    if (*prefix == NULL)
244
1
  return(NULL);
245
8.33k
    ret = xmlStrdup(&name[len + 1]);
246
8.33k
    if (ret == NULL) {
247
2
  if (*prefix != NULL) {
248
2
      xmlFree(*prefix);
249
2
      *prefix = NULL;
250
2
  }
251
2
  return(NULL);
252
2
    }
253
254
8.33k
    return(ret);
255
8.33k
}
256
257
/**
258
 * xmlSplitQName3:
259
 * @name:  the full QName
260
 * @len: an int *
261
 *
262
 * parse an XML qualified name string,i
263
 *
264
 * returns NULL if it is not a Qualified Name, otherwise, update len
265
 *         with the length in byte of the prefix and return a pointer
266
 *         to the start of the name without the prefix
267
 */
268
269
const xmlChar *
270
150k
xmlSplitQName3(const xmlChar *name, int *len) {
271
150k
    int l = 0;
272
273
150k
    if (name == NULL) return(NULL);
274
150k
    if (len == NULL) return(NULL);
275
276
    /* nasty but valid */
277
150k
    if (name[0] == ':')
278
6.07k
  return(NULL);
279
280
    /*
281
     * we are not trying to validate but just to cut, and yes it will
282
     * work even if this is as set of UTF-8 encoded chars
283
     */
284
1.44M
    while ((name[l] != 0) && (name[l] != ':'))
285
1.30M
  l++;
286
287
143k
    if (name[l] == 0)
288
113k
  return(NULL);
289
290
30.1k
    *len = l;
291
292
30.1k
    return(&name[l+1]);
293
143k
}
294
295
const xmlChar *
296
19.7k
xmlSplitQName4(const xmlChar *name, xmlChar **prefixPtr) {
297
19.7k
    xmlChar *prefix;
298
19.7k
    int l = 0;
299
300
19.7k
    if ((name == NULL) || (prefixPtr == NULL))
301
0
        return(NULL);
302
303
19.7k
    *prefixPtr = NULL;
304
305
    /* nasty but valid */
306
19.7k
    if (name[0] == ':')
307
2.87k
  return(name);
308
309
    /*
310
     * we are not trying to validate but just to cut, and yes it will
311
     * work even if this is as set of UTF-8 encoded chars
312
     */
313
231k
    while ((name[l] != 0) && (name[l] != ':'))
314
214k
  l++;
315
316
    /*
317
     * TODO: What about names with multiple colons?
318
     */
319
16.8k
    if ((name[l] == 0) || (name[l+1] == 0))
320
15.6k
  return(name);
321
322
1.19k
    prefix = xmlStrndup(name, l);
323
1.19k
    if (prefix == NULL)
324
1
        return(NULL);
325
326
1.19k
    *prefixPtr = prefix;
327
1.19k
    return(&name[l+1]);
328
1.19k
}
329
330
/************************************************************************
331
 *                  *
332
 *    Check Name, NCName and QName strings      *
333
 *                  *
334
 ************************************************************************/
335
336
516k
#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
337
338
/**
339
 * xmlValidateNCName:
340
 * @value: the value to check
341
 * @space: allow spaces in front and end of the string
342
 *
343
 * Check that a value conforms to the lexical space of NCName
344
 *
345
 * Returns 0 if this validates, a positive error code number otherwise
346
 *         and -1 in case of internal or API error.
347
 */
348
int
349
56.2k
xmlValidateNCName(const xmlChar *value, int space) {
350
56.2k
    const xmlChar *cur = value;
351
56.2k
    int c,l;
352
353
56.2k
    if (value == NULL)
354
0
        return(-1);
355
356
    /*
357
     * First quick algorithm for ASCII range
358
     */
359
56.2k
    if (space)
360
106k
  while (IS_BLANK_CH(*cur)) cur++;
361
56.2k
    if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
362
56.2k
  (*cur == '_'))
363
13.8k
  cur++;
364
42.3k
    else
365
42.3k
  goto try_complex;
366
31.8k
    while (((*cur >= 'a') && (*cur <= 'z')) ||
367
31.8k
     ((*cur >= 'A') && (*cur <= 'Z')) ||
368
31.8k
     ((*cur >= '0') && (*cur <= '9')) ||
369
31.8k
     (*cur == '_') || (*cur == '-') || (*cur == '.'))
370
18.0k
  cur++;
371
13.8k
    if (space)
372
11.9k
  while (IS_BLANK_CH(*cur)) cur++;
373
13.8k
    if (*cur == 0)
374
2.38k
  return(0);
375
376
53.8k
try_complex:
377
    /*
378
     * Second check for chars outside the ASCII range
379
     */
380
53.8k
    cur = value;
381
53.8k
    c = CUR_SCHAR(cur, l);
382
53.8k
    if (space) {
383
105k
  while (IS_BLANK(c)) {
384
105k
      cur += l;
385
105k
      c = CUR_SCHAR(cur, l);
386
105k
  }
387
53.0k
    }
388
53.8k
    if ((!IS_LETTER(c)) && (c != '_'))
389
34.1k
  return(1);
390
19.6k
    cur += l;
391
19.6k
    c = CUR_SCHAR(cur, l);
392
103k
    while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
393
103k
     (c == '-') || (c == '_') || IS_COMBINING(c) ||
394
103k
     IS_EXTENDER(c)) {
395
83.9k
  cur += l;
396
83.9k
  c = CUR_SCHAR(cur, l);
397
83.9k
    }
398
19.6k
    if (space) {
399
19.1k
  while (IS_BLANK(c)) {
400
8.92k
      cur += l;
401
8.92k
      c = CUR_SCHAR(cur, l);
402
8.92k
  }
403
19.1k
    }
404
19.6k
    if (c != 0)
405
18.3k
  return(1);
406
407
1.33k
    return(0);
408
19.6k
}
409
410
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
411
/**
412
 * xmlValidateQName:
413
 * @value: the value to check
414
 * @space: allow spaces in front and end of the string
415
 *
416
 * Check that a value conforms to the lexical space of QName
417
 *
418
 * Returns 0 if this validates, a positive error code number otherwise
419
 *         and -1 in case of internal or API error.
420
 */
421
int
422
78.7k
xmlValidateQName(const xmlChar *value, int space) {
423
78.7k
    const xmlChar *cur = value;
424
78.7k
    int c,l;
425
426
78.7k
    if (value == NULL)
427
0
        return(-1);
428
    /*
429
     * First quick algorithm for ASCII range
430
     */
431
78.7k
    if (space)
432
0
  while (IS_BLANK_CH(*cur)) cur++;
433
78.7k
    if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
434
78.7k
  (*cur == '_'))
435
70.3k
  cur++;
436
8.35k
    else
437
8.35k
  goto try_complex;
438
454k
    while (((*cur >= 'a') && (*cur <= 'z')) ||
439
454k
     ((*cur >= 'A') && (*cur <= 'Z')) ||
440
454k
     ((*cur >= '0') && (*cur <= '9')) ||
441
454k
     (*cur == '_') || (*cur == '-') || (*cur == '.'))
442
383k
  cur++;
443
70.3k
    if (*cur == ':') {
444
8.09k
  cur++;
445
8.09k
  if (((*cur >= 'a') && (*cur <= 'z')) ||
446
8.09k
      ((*cur >= 'A') && (*cur <= 'Z')) ||
447
8.09k
      (*cur == '_'))
448
7.19k
      cur++;
449
904
  else
450
904
      goto try_complex;
451
50.1k
  while (((*cur >= 'a') && (*cur <= 'z')) ||
452
50.1k
         ((*cur >= 'A') && (*cur <= 'Z')) ||
453
50.1k
         ((*cur >= '0') && (*cur <= '9')) ||
454
50.1k
         (*cur == '_') || (*cur == '-') || (*cur == '.'))
455
42.9k
      cur++;
456
7.19k
    }
457
69.4k
    if (space)
458
0
  while (IS_BLANK_CH(*cur)) cur++;
459
69.4k
    if (*cur == 0)
460
57.6k
  return(0);
461
462
21.0k
try_complex:
463
    /*
464
     * Second check for chars outside the ASCII range
465
     */
466
21.0k
    cur = value;
467
21.0k
    c = CUR_SCHAR(cur, l);
468
21.0k
    if (space) {
469
0
  while (IS_BLANK(c)) {
470
0
      cur += l;
471
0
      c = CUR_SCHAR(cur, l);
472
0
  }
473
0
    }
474
21.0k
    if ((!IS_LETTER(c)) && (c != '_'))
475
6.17k
  return(1);
476
14.9k
    cur += l;
477
14.9k
    c = CUR_SCHAR(cur, l);
478
173k
    while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
479
173k
     (c == '-') || (c == '_') || IS_COMBINING(c) ||
480
173k
     IS_EXTENDER(c)) {
481
158k
  cur += l;
482
158k
  c = CUR_SCHAR(cur, l);
483
158k
    }
484
14.9k
    if (c == ':') {
485
7.46k
  cur += l;
486
7.46k
  c = CUR_SCHAR(cur, l);
487
7.46k
  if ((!IS_LETTER(c)) && (c != '_'))
488
467
      return(1);
489
7.00k
  cur += l;
490
7.00k
  c = CUR_SCHAR(cur, l);
491
42.9k
  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
492
42.9k
         (c == '-') || (c == '_') || IS_COMBINING(c) ||
493
42.9k
         IS_EXTENDER(c)) {
494
35.9k
      cur += l;
495
35.9k
      c = CUR_SCHAR(cur, l);
496
35.9k
  }
497
7.00k
    }
498
14.4k
    if (space) {
499
0
  while (IS_BLANK(c)) {
500
0
      cur += l;
501
0
      c = CUR_SCHAR(cur, l);
502
0
  }
503
0
    }
504
14.4k
    if (c != 0)
505
10.6k
  return(1);
506
3.76k
    return(0);
507
14.4k
}
508
509
/**
510
 * xmlValidateName:
511
 * @value: the value to check
512
 * @space: allow spaces in front and end of the string
513
 *
514
 * Check that a value conforms to the lexical space of Name
515
 *
516
 * Returns 0 if this validates, a positive error code number otherwise
517
 *         and -1 in case of internal or API error.
518
 */
519
int
520
0
xmlValidateName(const xmlChar *value, int space) {
521
0
    const xmlChar *cur = value;
522
0
    int c,l;
523
524
0
    if (value == NULL)
525
0
        return(-1);
526
    /*
527
     * First quick algorithm for ASCII range
528
     */
529
0
    if (space)
530
0
  while (IS_BLANK_CH(*cur)) cur++;
531
0
    if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
532
0
  (*cur == '_') || (*cur == ':'))
533
0
  cur++;
534
0
    else
535
0
  goto try_complex;
536
0
    while (((*cur >= 'a') && (*cur <= 'z')) ||
537
0
     ((*cur >= 'A') && (*cur <= 'Z')) ||
538
0
     ((*cur >= '0') && (*cur <= '9')) ||
539
0
     (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
540
0
  cur++;
541
0
    if (space)
542
0
  while (IS_BLANK_CH(*cur)) cur++;
543
0
    if (*cur == 0)
544
0
  return(0);
545
546
0
try_complex:
547
    /*
548
     * Second check for chars outside the ASCII range
549
     */
550
0
    cur = value;
551
0
    c = CUR_SCHAR(cur, l);
552
0
    if (space) {
553
0
  while (IS_BLANK(c)) {
554
0
      cur += l;
555
0
      c = CUR_SCHAR(cur, l);
556
0
  }
557
0
    }
558
0
    if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
559
0
  return(1);
560
0
    cur += l;
561
0
    c = CUR_SCHAR(cur, l);
562
0
    while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
563
0
     (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
564
0
  cur += l;
565
0
  c = CUR_SCHAR(cur, l);
566
0
    }
567
0
    if (space) {
568
0
  while (IS_BLANK(c)) {
569
0
      cur += l;
570
0
      c = CUR_SCHAR(cur, l);
571
0
  }
572
0
    }
573
0
    if (c != 0)
574
0
  return(1);
575
0
    return(0);
576
0
}
577
578
/**
579
 * xmlValidateNMToken:
580
 * @value: the value to check
581
 * @space: allow spaces in front and end of the string
582
 *
583
 * Check that a value conforms to the lexical space of NMToken
584
 *
585
 * Returns 0 if this validates, a positive error code number otherwise
586
 *         and -1 in case of internal or API error.
587
 */
588
int
589
0
xmlValidateNMToken(const xmlChar *value, int space) {
590
0
    const xmlChar *cur = value;
591
0
    int c,l;
592
593
0
    if (value == NULL)
594
0
        return(-1);
595
    /*
596
     * First quick algorithm for ASCII range
597
     */
598
0
    if (space)
599
0
  while (IS_BLANK_CH(*cur)) cur++;
600
0
    if (((*cur >= 'a') && (*cur <= 'z')) ||
601
0
        ((*cur >= 'A') && (*cur <= 'Z')) ||
602
0
        ((*cur >= '0') && (*cur <= '9')) ||
603
0
        (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
604
0
  cur++;
605
0
    else
606
0
  goto try_complex;
607
0
    while (((*cur >= 'a') && (*cur <= 'z')) ||
608
0
     ((*cur >= 'A') && (*cur <= 'Z')) ||
609
0
     ((*cur >= '0') && (*cur <= '9')) ||
610
0
     (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
611
0
  cur++;
612
0
    if (space)
613
0
  while (IS_BLANK_CH(*cur)) cur++;
614
0
    if (*cur == 0)
615
0
  return(0);
616
617
0
try_complex:
618
    /*
619
     * Second check for chars outside the ASCII range
620
     */
621
0
    cur = value;
622
0
    c = CUR_SCHAR(cur, l);
623
0
    if (space) {
624
0
  while (IS_BLANK(c)) {
625
0
      cur += l;
626
0
      c = CUR_SCHAR(cur, l);
627
0
  }
628
0
    }
629
0
    if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
630
0
        (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
631
0
  return(1);
632
0
    cur += l;
633
0
    c = CUR_SCHAR(cur, l);
634
0
    while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
635
0
     (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
636
0
  cur += l;
637
0
  c = CUR_SCHAR(cur, l);
638
0
    }
639
0
    if (space) {
640
0
  while (IS_BLANK(c)) {
641
0
      cur += l;
642
0
      c = CUR_SCHAR(cur, l);
643
0
  }
644
0
    }
645
0
    if (c != 0)
646
0
  return(1);
647
0
    return(0);
648
0
}
649
#endif /* LIBXML_TREE_ENABLED */
650
651
/************************************************************************
652
 *                  *
653
 *    Allocation and deallocation of basic structures   *
654
 *                  *
655
 ************************************************************************/
656
657
/**
658
 * xmlSetBufferAllocationScheme:
659
 * @scheme:  allocation method to use
660
 *
661
 * Set the buffer allocation method.  Types are
662
 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
663
 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
664
 *                             improves performance
665
 */
666
void
667
0
xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
668
0
    if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
669
0
        (scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
670
0
        (scheme == XML_BUFFER_ALLOC_HYBRID))
671
0
  xmlBufferAllocScheme = scheme;
672
0
}
673
674
/**
675
 * xmlGetBufferAllocationScheme:
676
 *
677
 * Types are
678
 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
679
 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
680
 *                             improves performance
681
 * XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight
682
 *                            in normal usage, and doubleit on large strings to avoid
683
 *                            pathological performance.
684
 *
685
 * Returns the current allocation scheme
686
 */
687
xmlBufferAllocationScheme
688
0
xmlGetBufferAllocationScheme(void) {
689
0
    return(xmlBufferAllocScheme);
690
0
}
691
692
/**
693
 * xmlNewNs:
694
 * @node:  the element carrying the namespace
695
 * @href:  the URI associated
696
 * @prefix:  the prefix for the namespace
697
 *
698
 * Creation of a new Namespace. This function will refuse to create
699
 * a namespace with a similar prefix than an existing one present on this
700
 * node.
701
 * Note that for a default namespace, @prefix should be NULL.
702
 *
703
 * We use href==NULL in the case of an element creation where the namespace
704
 * was not defined.
705
 *
706
 * Returns a new namespace pointer or NULL
707
 */
708
xmlNsPtr
709
1.85M
xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
710
1.85M
    xmlNsPtr cur;
711
712
1.85M
    if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
713
0
  return(NULL);
714
715
    /*
716
     * Allocate a new Namespace and fill the fields.
717
     */
718
1.85M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
719
1.85M
    if (cur == NULL)
720
1.13k
  return(NULL);
721
1.85M
    memset(cur, 0, sizeof(xmlNs));
722
1.85M
    cur->type = XML_LOCAL_NAMESPACE;
723
724
1.85M
    if (href != NULL) {
725
1.85M
  cur->href = xmlStrdup(href);
726
1.85M
        if (cur->href == NULL)
727
114
            goto error;
728
1.85M
    }
729
1.85M
    if (prefix != NULL) {
730
1.34M
  cur->prefix = xmlStrdup(prefix);
731
1.34M
        if (cur->prefix == NULL)
732
78
            goto error;
733
1.34M
    }
734
735
    /*
736
     * Add it at the end to preserve parsing order ...
737
     * and checks for existing use of the prefix
738
     */
739
1.85M
    if (node != NULL) {
740
1.68M
  if (node->nsDef == NULL) {
741
1.03M
      node->nsDef = cur;
742
1.03M
  } else {
743
644k
      xmlNsPtr prev = node->nsDef;
744
745
644k
      if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
746
644k
    (xmlStrEqual(prev->prefix, cur->prefix)))
747
5.74k
                goto error;
748
2.69M
      while (prev->next != NULL) {
749
2.05M
          prev = prev->next;
750
2.05M
    if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
751
2.05M
        (xmlStrEqual(prev->prefix, cur->prefix)))
752
2.19k
                    goto error;
753
2.05M
      }
754
636k
      prev->next = cur;
755
636k
  }
756
1.68M
    }
757
1.84M
    return(cur);
758
759
8.13k
error:
760
8.13k
    xmlFreeNs(cur);
761
8.13k
    return(NULL);
762
1.85M
}
763
764
/**
765
 * xmlSetNs:
766
 * @node:  a node in the document
767
 * @ns:  a namespace pointer
768
 *
769
 * Associate a namespace to a node, a posteriori.
770
 */
771
void
772
0
xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
773
0
    if (node == NULL) {
774
0
  return;
775
0
    }
776
0
    if ((node->type == XML_ELEMENT_NODE) ||
777
0
        (node->type == XML_ATTRIBUTE_NODE))
778
0
  node->ns = ns;
779
0
}
780
781
/**
782
 * xmlFreeNs:
783
 * @cur:  the namespace pointer
784
 *
785
 * Free up the structures associated to a namespace
786
 */
787
void
788
1.99M
xmlFreeNs(xmlNsPtr cur) {
789
1.99M
    if (cur == NULL) {
790
0
  return;
791
0
    }
792
1.99M
    if (cur->href != NULL) xmlFree((char *) cur->href);
793
1.99M
    if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
794
1.99M
    xmlFree(cur);
795
1.99M
}
796
797
/**
798
 * xmlFreeNsList:
799
 * @cur:  the first namespace pointer
800
 *
801
 * Free up all the structures associated to the chained namespaces.
802
 */
803
void
804
1.32M
xmlFreeNsList(xmlNsPtr cur) {
805
1.32M
    xmlNsPtr next;
806
1.32M
    if (cur == NULL) {
807
2
  return;
808
2
    }
809
3.30M
    while (cur != NULL) {
810
1.98M
        next = cur->next;
811
1.98M
        xmlFreeNs(cur);
812
1.98M
  cur = next;
813
1.98M
    }
814
1.32M
}
815
816
/**
817
 * xmlNewDtd:
818
 * @doc:  the document pointer
819
 * @name:  the DTD name
820
 * @ExternalID:  the external ID
821
 * @SystemID:  the system ID
822
 *
823
 * Creation of a new DTD for the external subset. To create an
824
 * internal subset, use xmlCreateIntSubset().
825
 *
826
 * Returns a pointer to the new DTD structure
827
 */
828
xmlDtdPtr
829
xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
830
7.71k
                    const xmlChar *ExternalID, const xmlChar *SystemID) {
831
7.71k
    xmlDtdPtr cur;
832
833
7.71k
    if ((doc != NULL) && (doc->extSubset != NULL)) {
834
0
  return(NULL);
835
0
    }
836
837
    /*
838
     * Allocate a new DTD and fill the fields.
839
     */
840
7.71k
    cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
841
7.71k
    if (cur == NULL)
842
1
  return(NULL);
843
7.71k
    memset(cur, 0 , sizeof(xmlDtd));
844
7.71k
    cur->type = XML_DTD_NODE;
845
846
7.71k
    if (name != NULL) {
847
7.71k
  cur->name = xmlStrdup(name);
848
7.71k
        if (cur->name == NULL)
849
3
            goto error;
850
7.71k
    }
851
7.70k
    if (ExternalID != NULL) {
852
116
  cur->ExternalID = xmlStrdup(ExternalID);
853
116
        if (cur->ExternalID == NULL)
854
0
            goto error;
855
116
    }
856
7.70k
    if (SystemID != NULL) {
857
3.73k
  cur->SystemID = xmlStrdup(SystemID);
858
3.73k
        if (cur->SystemID == NULL)
859
1
            goto error;
860
3.73k
    }
861
7.70k
    if (doc != NULL)
862
7.70k
  doc->extSubset = cur;
863
7.70k
    cur->doc = doc;
864
865
7.70k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
866
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
867
7.70k
    return(cur);
868
869
4
error:
870
4
    xmlFreeDtd(cur);
871
4
    return(NULL);
872
7.70k
}
873
874
/**
875
 * xmlGetIntSubset:
876
 * @doc:  the document pointer
877
 *
878
 * Get the internal subset of a document
879
 * Returns a pointer to the DTD structure or NULL if not found
880
 */
881
882
xmlDtdPtr
883
101k
xmlGetIntSubset(const xmlDoc *doc) {
884
101k
    xmlNodePtr cur;
885
886
101k
    if (doc == NULL)
887
0
  return(NULL);
888
101k
    cur = doc->children;
889
115k
    while (cur != NULL) {
890
13.9k
  if (cur->type == XML_DTD_NODE)
891
124
      return((xmlDtdPtr) cur);
892
13.7k
  cur = cur->next;
893
13.7k
    }
894
101k
    return((xmlDtdPtr) doc->intSubset);
895
101k
}
896
897
/**
898
 * xmlCreateIntSubset:
899
 * @doc:  the document pointer
900
 * @name:  the DTD name
901
 * @ExternalID:  the external (PUBLIC) ID
902
 * @SystemID:  the system ID
903
 *
904
 * Create the internal subset of a document
905
 * Returns a pointer to the new DTD structure
906
 */
907
xmlDtdPtr
908
xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
909
28.4k
                   const xmlChar *ExternalID, const xmlChar *SystemID) {
910
28.4k
    xmlDtdPtr cur;
911
912
28.4k
    if (doc != NULL) {
913
28.4k
        cur = xmlGetIntSubset(doc);
914
28.4k
        if (cur != NULL)
915
0
            return(cur);
916
28.4k
    }
917
918
    /*
919
     * Allocate a new DTD and fill the fields.
920
     */
921
28.4k
    cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
922
28.4k
    if (cur == NULL)
923
3
  return(NULL);
924
28.4k
    memset(cur, 0, sizeof(xmlDtd));
925
28.4k
    cur->type = XML_DTD_NODE;
926
927
28.4k
    if (name != NULL) {
928
28.4k
  cur->name = xmlStrdup(name);
929
28.4k
  if (cur->name == NULL)
930
8
            goto error;
931
28.4k
    }
932
28.4k
    if (ExternalID != NULL) {
933
682
  cur->ExternalID = xmlStrdup(ExternalID);
934
682
  if (cur->ExternalID  == NULL)
935
0
            goto error;
936
682
    }
937
28.4k
    if (SystemID != NULL) {
938
5.31k
  cur->SystemID = xmlStrdup(SystemID);
939
5.31k
  if (cur->SystemID == NULL)
940
1
            goto error;
941
5.31k
    }
942
28.4k
    if (doc != NULL) {
943
28.4k
  doc->intSubset = cur;
944
28.4k
  cur->parent = doc;
945
28.4k
  cur->doc = doc;
946
28.4k
  if (doc->children == NULL) {
947
21.9k
      doc->children = (xmlNodePtr) cur;
948
21.9k
      doc->last = (xmlNodePtr) cur;
949
21.9k
  } else {
950
6.47k
      if (doc->type == XML_HTML_DOCUMENT_NODE) {
951
0
    xmlNodePtr prev;
952
953
0
    prev = doc->children;
954
0
    prev->prev = (xmlNodePtr) cur;
955
0
    cur->next = prev;
956
0
    doc->children = (xmlNodePtr) cur;
957
6.47k
      } else {
958
6.47k
    xmlNodePtr next;
959
960
6.47k
    next = doc->children;
961
13.3k
    while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
962
6.88k
        next = next->next;
963
6.47k
    if (next == NULL) {
964
6.47k
        cur->prev = doc->last;
965
6.47k
        cur->prev->next = (xmlNodePtr) cur;
966
6.47k
        cur->next = NULL;
967
6.47k
        doc->last = (xmlNodePtr) cur;
968
6.47k
    } else {
969
0
        cur->next = next;
970
0
        cur->prev = next->prev;
971
0
        if (cur->prev == NULL)
972
0
      doc->children = (xmlNodePtr) cur;
973
0
        else
974
0
      cur->prev->next = (xmlNodePtr) cur;
975
0
        next->prev = (xmlNodePtr) cur;
976
0
    }
977
6.47k
      }
978
6.47k
  }
979
28.4k
    }
980
981
28.4k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
982
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
983
28.4k
    return(cur);
984
985
9
error:
986
9
    xmlFreeDtd(cur);
987
9
    return(NULL);
988
28.4k
}
989
990
/**
991
 * DICT_FREE:
992
 * @str:  a string
993
 *
994
 * Free a string if it is not owned by the "dict" dictionary in the
995
 * current scope
996
 */
997
#define DICT_FREE(str)            \
998
19.8M
  if ((str) && ((!dict) ||       \
999
19.1M
      (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1000
9.02M
      xmlFree((char *)(str));
1001
1002
1003
/**
1004
 * DICT_COPY:
1005
 * @str:  a string
1006
 *
1007
 * Copy a string using a "dict" dictionary in the current scope,
1008
 * if available.
1009
 */
1010
#define DICT_COPY(str, cpy) \
1011
0
    if (str) { \
1012
0
  if (dict) { \
1013
0
      if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1014
0
    cpy = (xmlChar *) (str); \
1015
0
      else \
1016
0
    cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1017
0
  } else \
1018
0
      cpy = xmlStrdup((const xmlChar *)(str)); }
1019
1020
/**
1021
 * DICT_CONST_COPY:
1022
 * @str:  a string
1023
 *
1024
 * Copy a string using a "dict" dictionary in the current scope,
1025
 * if available.
1026
 */
1027
#define DICT_CONST_COPY(str, cpy) \
1028
0
    if (str) { \
1029
0
  if (dict) { \
1030
0
      if (xmlDictOwns(dict, (const xmlChar *)(str))) \
1031
0
    cpy = (const xmlChar *) (str); \
1032
0
      else \
1033
0
    cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
1034
0
  } else \
1035
0
      cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
1036
1037
1038
/**
1039
 * xmlFreeDtd:
1040
 * @cur:  the DTD structure to free up
1041
 *
1042
 * Free a DTD structure.
1043
 */
1044
void
1045
36.1k
xmlFreeDtd(xmlDtdPtr cur) {
1046
36.1k
    xmlDictPtr dict = NULL;
1047
1048
36.1k
    if (cur == NULL) {
1049
0
  return;
1050
0
    }
1051
36.1k
    if (cur->doc != NULL) dict = cur->doc->dict;
1052
1053
36.1k
    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
1054
0
  xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1055
1056
36.1k
    if (cur->children != NULL) {
1057
17.1k
  xmlNodePtr next, c = cur->children;
1058
1059
  /*
1060
   * Cleanup all nodes which are not part of the specific lists
1061
   * of notations, elements, attributes and entities.
1062
   */
1063
70.7k
        while (c != NULL) {
1064
53.6k
      next = c->next;
1065
53.6k
      if ((c->type != XML_NOTATION_NODE) &&
1066
53.6k
          (c->type != XML_ELEMENT_DECL) &&
1067
53.6k
    (c->type != XML_ATTRIBUTE_DECL) &&
1068
53.6k
    (c->type != XML_ENTITY_DECL)) {
1069
14.6k
    xmlUnlinkNode(c);
1070
14.6k
    xmlFreeNode(c);
1071
14.6k
      }
1072
53.6k
      c = next;
1073
53.6k
  }
1074
17.1k
    }
1075
36.1k
    DICT_FREE(cur->name)
1076
36.1k
    DICT_FREE(cur->SystemID)
1077
36.1k
    DICT_FREE(cur->ExternalID)
1078
    /* TODO !!! */
1079
36.1k
    if (cur->notations != NULL)
1080
263
        xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1081
1082
36.1k
    if (cur->elements != NULL)
1083
7.46k
        xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1084
36.1k
    if (cur->attributes != NULL)
1085
5.13k
        xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1086
36.1k
    if (cur->entities != NULL)
1087
8.16k
        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1088
36.1k
    if (cur->pentities != NULL)
1089
1.43k
        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1090
1091
36.1k
    xmlFree(cur);
1092
36.1k
}
1093
1094
/**
1095
 * xmlNewDoc:
1096
 * @version:  xmlChar string giving the version of XML "1.0"
1097
 *
1098
 * Creates a new XML document
1099
 *
1100
 * Returns a new document
1101
 */
1102
xmlDocPtr
1103
329k
xmlNewDoc(const xmlChar *version) {
1104
329k
    xmlDocPtr cur;
1105
1106
329k
    if (version == NULL)
1107
185k
  version = (const xmlChar *) "1.0";
1108
1109
    /*
1110
     * Allocate a new document and fill the fields.
1111
     */
1112
329k
    cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1113
329k
    if (cur == NULL)
1114
71
  return(NULL);
1115
329k
    memset(cur, 0, sizeof(xmlDoc));
1116
329k
    cur->type = XML_DOCUMENT_NODE;
1117
1118
329k
    cur->version = xmlStrdup(version);
1119
329k
    if (cur->version == NULL) {
1120
51
  xmlFree(cur);
1121
51
  return(NULL);
1122
51
    }
1123
329k
    cur->standalone = -1;
1124
329k
    cur->compression = -1; /* not initialized */
1125
329k
    cur->doc = cur;
1126
329k
    cur->parseFlags = 0;
1127
329k
    cur->properties = XML_DOC_USERBUILT;
1128
    /*
1129
     * The in memory encoding is always UTF8
1130
     * This field will never change and would
1131
     * be obsolete if not for binary compatibility.
1132
     */
1133
329k
    cur->charset = XML_CHAR_ENCODING_UTF8;
1134
1135
329k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1136
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
1137
329k
    return(cur);
1138
329k
}
1139
1140
/**
1141
 * xmlFreeDoc:
1142
 * @cur:  pointer to the document
1143
 *
1144
 * Free up all the structures used by a document, tree included.
1145
 */
1146
void
1147
378k
xmlFreeDoc(xmlDocPtr cur) {
1148
378k
    xmlDtdPtr extSubset, intSubset;
1149
378k
    xmlDictPtr dict = NULL;
1150
1151
378k
    if (cur == NULL) {
1152
49.2k
  return;
1153
49.2k
    }
1154
1155
329k
    if (cur != NULL) dict = cur->dict;
1156
1157
329k
    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
1158
0
  xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1159
1160
    /*
1161
     * Do this before freeing the children list to avoid ID lookups
1162
     */
1163
329k
    if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1164
329k
    cur->ids = NULL;
1165
329k
    if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1166
329k
    cur->refs = NULL;
1167
329k
    extSubset = cur->extSubset;
1168
329k
    intSubset = cur->intSubset;
1169
329k
    if (intSubset == extSubset)
1170
300k
  extSubset = NULL;
1171
329k
    if (extSubset != NULL) {
1172
3.73k
  xmlUnlinkNode((xmlNodePtr) cur->extSubset);
1173
3.73k
  cur->extSubset = NULL;
1174
3.73k
  xmlFreeDtd(extSubset);
1175
3.73k
    }
1176
329k
    if (intSubset != NULL) {
1177
32.3k
  xmlUnlinkNode((xmlNodePtr) cur->intSubset);
1178
32.3k
  cur->intSubset = NULL;
1179
32.3k
  xmlFreeDtd(intSubset);
1180
32.3k
    }
1181
1182
329k
    if (cur->children != NULL) xmlFreeNodeList(cur->children);
1183
329k
    if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1184
1185
329k
    DICT_FREE(cur->version)
1186
329k
    DICT_FREE(cur->name)
1187
329k
    DICT_FREE(cur->encoding)
1188
329k
    DICT_FREE(cur->URL)
1189
329k
    xmlFree(cur);
1190
329k
    if (dict) xmlDictFree(dict);
1191
329k
}
1192
1193
/**
1194
 * xmlStringLenGetNodeList:
1195
 * @doc:  the document
1196
 * @value:  the value of the text
1197
 * @len:  the length of the string value
1198
 *
1199
 * Parse the value string and build the node list associated. Should
1200
 * produce a flat tree with only TEXTs and ENTITY_REFs.
1201
 * Returns a pointer to the first child
1202
 */
1203
xmlNodePtr
1204
48.7k
xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) {
1205
48.7k
    xmlNodePtr ret = NULL, head = NULL, last = NULL;
1206
48.7k
    xmlNodePtr node;
1207
48.7k
    xmlChar *val = NULL;
1208
48.7k
    const xmlChar *cur, *end;
1209
48.7k
    const xmlChar *q;
1210
48.7k
    xmlEntityPtr ent;
1211
48.7k
    xmlBufPtr buf;
1212
1213
    /*
1214
     * This function should only receive valid attribute values that
1215
     * were checked by the parser, typically by xmlParseAttValueComplex
1216
     * calling xmlStringDecodeEntities.
1217
     *
1218
     * In recovery mode, the parser can produce invalid attribute
1219
     * values. For now, we ignore any errors silently. If this is fixed,
1220
     * we could add assertions here to catch parser issues.
1221
     */
1222
1223
48.7k
    if (value == NULL) return(NULL);
1224
48.7k
    cur = value;
1225
48.7k
    end = cur + len;
1226
1227
48.7k
    buf = xmlBufCreateSize(0);
1228
48.7k
    if (buf == NULL) return(NULL);
1229
48.7k
    xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
1230
1231
48.7k
    q = cur;
1232
71.5M
    while ((cur < end) && (*cur != 0)) {
1233
71.4M
  if (cur[0] == '&') {
1234
14.7k
      int charval = 0;
1235
14.7k
      xmlChar tmp;
1236
1237
      /*
1238
       * Save the current text.
1239
       */
1240
14.7k
            if (cur != q) {
1241
11.5k
    if (xmlBufAdd(buf, q, cur - q))
1242
0
        goto out;
1243
11.5k
      }
1244
14.7k
      q = cur;
1245
14.7k
      if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
1246
0
    cur += 3;
1247
0
    if (cur < end)
1248
0
        tmp = *cur;
1249
0
    else
1250
0
        tmp = 0;
1251
0
    while (tmp != ';') { /* Non input consuming loop */
1252
0
        if ((tmp >= '0') && (tmp <= '9'))
1253
0
      charval = charval * 16 + (tmp - '0');
1254
0
        else if ((tmp >= 'a') && (tmp <= 'f'))
1255
0
      charval = charval * 16 + (tmp - 'a') + 10;
1256
0
        else if ((tmp >= 'A') && (tmp <= 'F'))
1257
0
      charval = charval * 16 + (tmp - 'A') + 10;
1258
0
        else {
1259
0
      charval = 0;
1260
0
      break;
1261
0
        }
1262
0
        cur++;
1263
0
        if (cur < end)
1264
0
      tmp = *cur;
1265
0
        else
1266
0
      tmp = 0;
1267
0
    }
1268
0
    if (tmp == ';')
1269
0
        cur++;
1270
0
    q = cur;
1271
14.7k
      } else if ((cur + 1 < end) && (cur[1] == '#')) {
1272
903
    cur += 2;
1273
903
    if (cur < end)
1274
903
        tmp = *cur;
1275
0
    else
1276
0
        tmp = 0;
1277
2.70k
    while (tmp != ';') { /* Non input consuming loops */
1278
                    /* Don't check for integer overflow, see above. */
1279
1.80k
        if ((tmp >= '0') && (tmp <= '9'))
1280
1.80k
      charval = charval * 10 + (tmp - '0');
1281
0
        else {
1282
0
      charval = 0;
1283
0
      break;
1284
0
        }
1285
1.80k
        cur++;
1286
1.80k
        if (cur < end)
1287
1.80k
      tmp = *cur;
1288
0
        else
1289
0
      tmp = 0;
1290
1.80k
    }
1291
903
    if (tmp == ';')
1292
903
        cur++;
1293
903
    q = cur;
1294
13.8k
      } else {
1295
    /*
1296
     * Read the entity string
1297
     */
1298
13.8k
    cur++;
1299
13.8k
    q = cur;
1300
115k
    while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1301
13.8k
    if ((cur >= end) || (*cur == 0))
1302
0
        break;
1303
13.8k
    if (cur != q) {
1304
        /*
1305
         * Predefined entities don't generate nodes
1306
         */
1307
13.8k
        val = xmlStrndup(q, cur - q);
1308
13.8k
        ent = xmlGetDocEntity(doc, val);
1309
13.8k
        if ((ent != NULL) &&
1310
13.8k
      (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1311
1312
0
      if (xmlBufCat(buf, ent->content))
1313
0
          goto out;
1314
13.8k
        } else {
1315
      /*
1316
       * Flush buffer so far
1317
       */
1318
13.8k
      if (!xmlBufIsEmpty(buf)) {
1319
11.0k
          node = xmlNewDocText(doc, NULL);
1320
11.0k
          if (node == NULL)
1321
0
        goto out;
1322
11.0k
          node->content = xmlBufDetach(buf);
1323
1324
11.0k
          if (last == NULL) {
1325
3.24k
        last = head = node;
1326
7.80k
          } else {
1327
7.80k
        last = xmlAddNextSibling(last, node);
1328
7.80k
          }
1329
11.0k
      }
1330
1331
      /*
1332
       * Create a new REFERENCE_REF node
1333
       */
1334
13.8k
      node = xmlNewReference(doc, val);
1335
13.8k
      if (node == NULL)
1336
0
          goto out;
1337
13.8k
      else if ((ent != NULL) &&
1338
13.8k
                                 ((ent->flags & XML_ENT_PARSED) == 0) &&
1339
13.8k
                                 ((ent->flags & XML_ENT_EXPANDING) == 0)) {
1340
122
          xmlNodePtr temp;
1341
1342
                            /*
1343
                             * The entity should have been checked already,
1344
                             * but set the flag anyway to avoid recursion.
1345
                             */
1346
122
                            if (node->content != NULL) {
1347
122
                                ent->flags |= XML_ENT_EXPANDING;
1348
122
                                ent->children = xmlStringGetNodeList(doc,
1349
122
                                        node->content);
1350
122
                                ent->flags &= ~XML_ENT_EXPANDING;
1351
122
                                if (ent->children == NULL) {
1352
0
                                    xmlFreeNode(node);
1353
0
                                    goto out;
1354
0
                                }
1355
122
                            }
1356
122
                            ent->flags |= XML_ENT_PARSED;
1357
122
          temp = ent->children;
1358
283
          while (temp) {
1359
161
        temp->parent = (xmlNodePtr)ent;
1360
161
        ent->last = temp;
1361
161
        temp = temp->next;
1362
161
          }
1363
122
      }
1364
13.8k
      if (last == NULL) {
1365
934
          last = head = node;
1366
12.9k
      } else {
1367
12.9k
          last = xmlAddNextSibling(last, node);
1368
12.9k
      }
1369
13.8k
        }
1370
13.8k
        xmlFree(val);
1371
13.8k
                    val = NULL;
1372
13.8k
    }
1373
13.8k
    cur++;
1374
13.8k
    q = cur;
1375
13.8k
      }
1376
14.7k
      if (charval != 0) {
1377
903
    xmlChar buffer[10];
1378
903
    int l;
1379
1380
903
    l = xmlCopyCharMultiByte(buffer, charval);
1381
903
    buffer[l] = 0;
1382
1383
903
    if (xmlBufCat(buf, buffer))
1384
0
        goto out;
1385
903
    charval = 0;
1386
903
      }
1387
14.7k
  } else
1388
71.4M
      cur++;
1389
71.4M
    }
1390
1391
48.7k
    if (cur != q) {
1392
        /*
1393
   * Handle the last piece of text.
1394
   */
1395
46.8k
  if (xmlBufAdd(buf, q, cur - q))
1396
0
      goto out;
1397
46.8k
    }
1398
1399
48.7k
    if (!xmlBufIsEmpty(buf)) {
1400
47.2k
  node = xmlNewDocText(doc, NULL);
1401
47.2k
  if (node == NULL)
1402
0
            goto out;
1403
47.2k
  node->content = xmlBufDetach(buf);
1404
1405
47.2k
  if (last == NULL) {
1406
44.5k
      head = node;
1407
44.5k
  } else {
1408
2.68k
      xmlAddNextSibling(last, node);
1409
2.68k
  }
1410
47.2k
    } else if (head == NULL) {
1411
0
        head = xmlNewDocText(doc, BAD_CAST "");
1412
0
    }
1413
1414
48.7k
    ret = head;
1415
48.7k
    head = NULL;
1416
1417
48.7k
out:
1418
48.7k
    xmlBufFree(buf);
1419
48.7k
    if (val != NULL)
1420
0
        xmlFree(val);
1421
48.7k
    if (head != NULL)
1422
0
        xmlFreeNodeList(head);
1423
48.7k
    return(ret);
1424
48.7k
}
1425
1426
/**
1427
 * xmlStringGetNodeList:
1428
 * @doc:  the document
1429
 * @value:  the value of the attribute
1430
 *
1431
 * Parse the value string and build the node list associated. Should
1432
 * produce a flat tree with only TEXTs and ENTITY_REFs.
1433
 * Returns a pointer to the first child
1434
 */
1435
xmlNodePtr
1436
134
xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) {
1437
134
    xmlNodePtr ret = NULL, head = NULL, last = NULL;
1438
134
    xmlNodePtr node;
1439
134
    xmlChar *val = NULL;
1440
134
    const xmlChar *cur = value;
1441
134
    const xmlChar *q;
1442
134
    xmlEntityPtr ent;
1443
134
    xmlBufPtr buf;
1444
1445
    /*
1446
     * This function should only receive valid attribute values that
1447
     * were checked by the parser, typically by xmlParseAttValueComplex
1448
     * calling xmlStringDecodeEntities.
1449
     *
1450
     * In recovery mode, the parser can produce invalid attribute
1451
     * values. For now, we ignore any errors silently. If this is fixed,
1452
     * we could add assertions here to catch parser issues.
1453
     */
1454
1455
134
    if (value == NULL) return(NULL);
1456
1457
134
    buf = xmlBufCreateSize(0);
1458
134
    if (buf == NULL) return(NULL);
1459
134
    xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
1460
1461
134
    q = cur;
1462
608k
    while (*cur != 0) {
1463
608k
  if (cur[0] == '&') {
1464
323
      int charval = 0;
1465
323
      xmlChar tmp;
1466
1467
      /*
1468
       * Save the current text.
1469
       */
1470
323
            if (cur != q) {
1471
292
    if (xmlBufAdd(buf, q, cur - q))
1472
0
        goto out;
1473
292
      }
1474
323
      q = cur;
1475
323
      if ((cur[1] == '#') && (cur[2] == 'x')) {
1476
0
    cur += 3;
1477
0
    tmp = *cur;
1478
0
    while (tmp != ';') { /* Non input consuming loop */
1479
0
        if ((tmp >= '0') && (tmp <= '9'))
1480
0
      charval = charval * 16 + (tmp - '0');
1481
0
        else if ((tmp >= 'a') && (tmp <= 'f'))
1482
0
      charval = charval * 16 + (tmp - 'a') + 10;
1483
0
        else if ((tmp >= 'A') && (tmp <= 'F'))
1484
0
      charval = charval * 16 + (tmp - 'A') + 10;
1485
0
        else {
1486
0
      charval = 0;
1487
0
      break;
1488
0
        }
1489
0
        cur++;
1490
0
        tmp = *cur;
1491
0
    }
1492
0
    if (tmp == ';')
1493
0
        cur++;
1494
0
    q = cur;
1495
323
      } else if  (cur[1] == '#') {
1496
0
    cur += 2;
1497
0
    tmp = *cur;
1498
0
    while (tmp != ';') { /* Non input consuming loops */
1499
                    /* Don't check for integer overflow, see above. */
1500
0
        if ((tmp >= '0') && (tmp <= '9'))
1501
0
      charval = charval * 10 + (tmp - '0');
1502
0
        else {
1503
0
      charval = 0;
1504
0
      break;
1505
0
        }
1506
0
        cur++;
1507
0
        tmp = *cur;
1508
0
    }
1509
0
    if (tmp == ';')
1510
0
        cur++;
1511
0
    q = cur;
1512
323
      } else {
1513
    /*
1514
     * Read the entity string
1515
     */
1516
323
    cur++;
1517
323
    q = cur;
1518
1.59k
    while ((*cur != 0) && (*cur != ';')) cur++;
1519
323
    if (*cur == 0)
1520
0
        break;
1521
323
    if (cur != q) {
1522
        /*
1523
         * Predefined entities don't generate nodes
1524
         */
1525
323
        val = xmlStrndup(q, cur - q);
1526
323
                    if (val == NULL)
1527
0
                        goto out;
1528
323
        ent = xmlGetDocEntity(doc, val);
1529
323
        if ((ent != NULL) &&
1530
323
      (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1531
1532
264
      if (xmlBufCat(buf, ent->content))
1533
0
          goto out;
1534
1535
264
        } else {
1536
      /*
1537
       * Flush buffer so far
1538
       */
1539
59
      if (!xmlBufIsEmpty(buf)) {
1540
32
          node = xmlNewDocText(doc, NULL);
1541
32
                            if (node == NULL)
1542
0
                                goto out;
1543
32
          node->content = xmlBufDetach(buf);
1544
1545
32
          if (last == NULL) {
1546
15
        last = head = node;
1547
17
          } else {
1548
17
        last = xmlAddNextSibling(last, node);
1549
17
          }
1550
32
      }
1551
1552
      /*
1553
       * Create a new REFERENCE_REF node
1554
       */
1555
59
      node = xmlNewReference(doc, val);
1556
59
      if (node == NULL)
1557
0
          goto out;
1558
59
      if ((ent != NULL) &&
1559
59
                            ((ent->flags & XML_ENT_PARSED) == 0) &&
1560
59
                            ((ent->flags & XML_ENT_EXPANDING) == 0)) {
1561
12
          xmlNodePtr temp;
1562
1563
                            /*
1564
                             * The entity should have been checked already,
1565
                             * but set the flag anyway to avoid recursion.
1566
                             */
1567
12
                            if (node->content != NULL) {
1568
12
                                ent->flags |= XML_ENT_EXPANDING;
1569
12
                                ent->children = xmlStringGetNodeList(doc,
1570
12
                                        node->content);
1571
12
                                ent->flags &= ~XML_ENT_EXPANDING;
1572
12
                                if (ent->children == NULL) {
1573
0
                                    xmlFreeNode(node);
1574
0
                                    goto out;
1575
0
                                }
1576
12
                            }
1577
12
                            ent->flags |= XML_ENT_PARSED;
1578
12
          temp = ent->children;
1579
63
          while (temp) {
1580
51
        temp->parent = (xmlNodePtr)ent;
1581
51
        ent->last = temp;
1582
51
        temp = temp->next;
1583
51
          }
1584
12
      }
1585
59
      if (last == NULL) {
1586
9
          last = head = node;
1587
50
      } else {
1588
50
          last = xmlAddNextSibling(last, node);
1589
50
      }
1590
59
        }
1591
323
        xmlFree(val);
1592
323
                    val = NULL;
1593
323
    }
1594
323
    cur++;
1595
323
    q = cur;
1596
323
      }
1597
323
      if (charval != 0) {
1598
0
    xmlChar buffer[10];
1599
0
    int len;
1600
1601
0
    len = xmlCopyCharMultiByte(buffer, charval);
1602
0
    buffer[len] = 0;
1603
1604
0
    if (xmlBufCat(buf, buffer))
1605
0
        goto out;
1606
0
    charval = 0;
1607
0
      }
1608
323
  } else
1609
608k
      cur++;
1610
608k
    }
1611
134
    if ((cur != q) || (head == NULL)) {
1612
        /*
1613
   * Handle the last piece of text.
1614
   */
1615
119
  xmlBufAdd(buf, q, cur - q);
1616
119
    }
1617
1618
134
    if (xmlBufIsEmpty(buf) <= 0) {
1619
112
  node = xmlNewDocText(doc, NULL);
1620
112
        if (node == NULL)
1621
0
            goto out;
1622
112
  node->content = xmlBufDetach(buf);
1623
112
        if (node->content == NULL) {
1624
0
            xmlFreeNode(node);
1625
0
            goto out;
1626
0
        }
1627
1628
112
  if (last == NULL) {
1629
101
      head = node;
1630
101
  } else {
1631
11
      xmlAddNextSibling(last, node);
1632
11
  }
1633
112
    } else if (head == NULL) {
1634
9
        head = xmlNewDocText(doc, BAD_CAST "");
1635
9
    }
1636
1637
134
    ret = head;
1638
134
    head = NULL;
1639
1640
134
out:
1641
134
    xmlBufFree(buf);
1642
134
    if (val != NULL) xmlFree(val);
1643
134
    if (head != NULL) xmlFreeNodeList(head);
1644
134
    return(ret);
1645
134
}
1646
1647
/**
1648
 * xmlNodeListGetString:
1649
 * @doc:  the document
1650
 * @list:  a Node list
1651
 * @inLine:  should we replace entity contents or show their external form
1652
 *
1653
 * Build the string equivalent to the text contained in the Node list
1654
 * made of TEXTs and ENTITY_REFs
1655
 *
1656
 * Returns a pointer to the string copy, the caller must free it with xmlFree().
1657
 */
1658
xmlChar *
1659
xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
1660
502k
{
1661
502k
    const xmlNode *node = list;
1662
502k
    xmlChar *ret = NULL;
1663
502k
    xmlEntityPtr ent;
1664
502k
    int attr;
1665
1666
502k
    if (list == NULL)
1667
0
        return xmlStrdup(BAD_CAST "");
1668
502k
    if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
1669
501k
        attr = 1;
1670
747
    else
1671
747
        attr = 0;
1672
1673
1.00M
    while (node != NULL) {
1674
504k
        if ((node->type == XML_TEXT_NODE) ||
1675
504k
            (node->type == XML_CDATA_SECTION_NODE)) {
1676
502k
            if (inLine) {
1677
132k
                ret = xmlStrcat(ret, node->content);
1678
132k
                if (ret == NULL)
1679
784
                    goto error;
1680
370k
            } else {
1681
370k
                xmlChar *buffer;
1682
1683
370k
    if (attr)
1684
370k
        buffer = xmlEncodeAttributeEntities(doc, node->content);
1685
0
    else
1686
0
        buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1687
370k
                if (buffer == NULL)
1688
73
                    goto error;
1689
370k
                ret = xmlStrcat(ret, buffer);
1690
370k
                xmlFree(buffer);
1691
370k
                if (ret == NULL)
1692
4
                    goto error;
1693
370k
            }
1694
502k
        } else if (node->type == XML_ENTITY_REF_NODE) {
1695
1.93k
            if (inLine) {
1696
1.93k
                ent = xmlGetDocEntity(doc, node->name);
1697
1.93k
                if (ent != NULL) {
1698
979
                    if (ent->children != NULL) {
1699
747
                        xmlChar *buffer;
1700
1701
                        /* an entity content can be any "well balanced chunk",
1702
                         * i.e. the result of the content [43] production:
1703
                         * http://www.w3.org/TR/REC-xml#NT-content.
1704
                         * So it can contain text, CDATA section or nested
1705
                         * entity reference nodes (among others).
1706
                         * -> we recursive  call xmlNodeListGetString()
1707
                         * which handles these types */
1708
747
                        buffer = xmlNodeListGetString(doc, ent->children, 1);
1709
747
                        if (buffer == NULL)
1710
0
                            goto error;
1711
747
                        ret = xmlStrcat(ret, buffer);
1712
747
                        xmlFree(buffer);
1713
747
                        if (ret == NULL)
1714
2
                            goto error;
1715
747
                    }
1716
979
                } else if (node->content != NULL) {
1717
0
                    ret = xmlStrcat(ret, node->content);
1718
0
                    if (ret == NULL)
1719
0
                        goto error;
1720
0
                }
1721
1.93k
            } else {
1722
0
                xmlChar buf[2];
1723
1724
0
                buf[0] = '&';
1725
0
                buf[1] = 0;
1726
0
                ret = xmlStrncat(ret, buf, 1);
1727
0
                ret = xmlStrcat(ret, node->name);
1728
0
                buf[0] = ';';
1729
0
                buf[1] = 0;
1730
0
                ret = xmlStrncat(ret, buf, 1);
1731
0
                if (ret == NULL)
1732
0
                    goto error;
1733
0
            }
1734
1.93k
        }
1735
503k
        node = node->next;
1736
503k
    }
1737
501k
    if (ret == NULL)
1738
480
        ret = xmlStrdup(BAD_CAST "");
1739
501k
    return (ret);
1740
1741
863
error:
1742
863
    xmlFree(ret);
1743
863
    return(NULL);
1744
502k
}
1745
1746
#ifdef LIBXML_TREE_ENABLED
1747
/**
1748
 * xmlNodeListGetRawString:
1749
 * @doc:  the document
1750
 * @list:  a Node list
1751
 * @inLine:  should we replace entity contents or show their external form
1752
 *
1753
 * Builds the string equivalent to the text contained in the Node list
1754
 * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
1755
 * this function doesn't do any character encoding handling.
1756
 *
1757
 * Returns a pointer to the string copy, the caller must free it with xmlFree().
1758
 */
1759
xmlChar *
1760
xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine)
1761
0
{
1762
0
    const xmlNode *node = list;
1763
0
    xmlChar *ret = NULL;
1764
0
    xmlEntityPtr ent;
1765
1766
0
    if (list == NULL)
1767
0
        return xmlStrdup(BAD_CAST "");
1768
1769
0
    while (node != NULL) {
1770
0
        if ((node->type == XML_TEXT_NODE) ||
1771
0
            (node->type == XML_CDATA_SECTION_NODE)) {
1772
0
            if (inLine) {
1773
0
                ret = xmlStrcat(ret, node->content);
1774
0
            } else {
1775
0
                xmlChar *buffer;
1776
1777
0
                buffer = xmlEncodeSpecialChars(doc, node->content);
1778
0
                if (buffer != NULL) {
1779
0
                    ret = xmlStrcat(ret, buffer);
1780
0
                    xmlFree(buffer);
1781
0
                }
1782
0
            }
1783
0
        } else if (node->type == XML_ENTITY_REF_NODE) {
1784
0
            if (inLine) {
1785
0
                ent = xmlGetDocEntity(doc, node->name);
1786
0
                if (ent != NULL) {
1787
0
                    xmlChar *buffer;
1788
1789
                    /* an entity content can be any "well balanced chunk",
1790
                     * i.e. the result of the content [43] production:
1791
                     * http://www.w3.org/TR/REC-xml#NT-content.
1792
                     * So it can contain text, CDATA section or nested
1793
                     * entity reference nodes (among others).
1794
                     * -> we recursive  call xmlNodeListGetRawString()
1795
                     * which handles these types */
1796
0
                    buffer =
1797
0
                        xmlNodeListGetRawString(doc, ent->children, 1);
1798
0
                    if (buffer != NULL) {
1799
0
                        ret = xmlStrcat(ret, buffer);
1800
0
                        xmlFree(buffer);
1801
0
                    }
1802
0
                } else {
1803
0
                    ret = xmlStrcat(ret, node->content);
1804
0
                }
1805
0
            } else {
1806
0
                xmlChar buf[2];
1807
1808
0
                buf[0] = '&';
1809
0
                buf[1] = 0;
1810
0
                ret = xmlStrncat(ret, buf, 1);
1811
0
                ret = xmlStrcat(ret, node->name);
1812
0
                buf[0] = ';';
1813
0
                buf[1] = 0;
1814
0
                ret = xmlStrncat(ret, buf, 1);
1815
0
            }
1816
0
        }
1817
0
        node = node->next;
1818
0
    }
1819
0
    if (ret == NULL)
1820
0
        ret = xmlStrdup(BAD_CAST "");
1821
0
    return (ret);
1822
0
}
1823
#endif /* LIBXML_TREE_ENABLED */
1824
1825
static xmlAttrPtr
1826
xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
1827
                   const xmlChar * name, const xmlChar * value,
1828
                   int eatname)
1829
615k
{
1830
615k
    xmlAttrPtr cur;
1831
615k
    xmlDocPtr doc = NULL;
1832
1833
615k
    if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) {
1834
0
        if ((eatname == 1) &&
1835
0
      ((node->doc == NULL) || (node->doc->dict == NULL) ||
1836
0
       (!(xmlDictOwns(node->doc->dict, name)))))
1837
0
            xmlFree((xmlChar *) name);
1838
0
        return (NULL);
1839
0
    }
1840
1841
    /*
1842
     * Allocate a new property and fill the fields.
1843
     */
1844
615k
    cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1845
615k
    if (cur == NULL) {
1846
561
        if ((eatname == 1) &&
1847
561
      ((node == NULL) || (node->doc == NULL) ||
1848
0
             (node->doc->dict == NULL) ||
1849
0
       (!(xmlDictOwns(node->doc->dict, name)))))
1850
0
            xmlFree((xmlChar *) name);
1851
561
        return (NULL);
1852
561
    }
1853
614k
    memset(cur, 0, sizeof(xmlAttr));
1854
614k
    cur->type = XML_ATTRIBUTE_NODE;
1855
1856
614k
    cur->parent = node;
1857
614k
    if (node != NULL) {
1858
614k
        doc = node->doc;
1859
614k
        cur->doc = doc;
1860
614k
    }
1861
614k
    cur->ns = ns;
1862
1863
614k
    if (eatname == 0) {
1864
614k
        if ((doc != NULL) && (doc->dict != NULL))
1865
614k
            cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1866
0
        else
1867
0
            cur->name = xmlStrdup(name);
1868
614k
        if (cur->name == NULL)
1869
0
            goto error;
1870
614k
    } else
1871
0
        cur->name = name;
1872
1873
614k
    if (value != NULL) {
1874
613k
        xmlNodePtr tmp;
1875
1876
613k
        cur->children = xmlNewDocText(doc, value);
1877
613k
        if (cur->children == NULL)
1878
26
            goto error;
1879
613k
        cur->last = NULL;
1880
613k
        tmp = cur->children;
1881
1.22M
        while (tmp != NULL) {
1882
613k
            tmp->parent = (xmlNodePtr) cur;
1883
613k
            if (tmp->next == NULL)
1884
613k
                cur->last = tmp;
1885
613k
            tmp = tmp->next;
1886
613k
        }
1887
613k
    }
1888
1889
614k
    if ((value != NULL) && (node != NULL) &&
1890
614k
        (xmlIsID(node->doc, node, cur) == 1) &&
1891
614k
        (xmlAddIDSafe(node->doc, value, cur, 0, NULL) < 0))
1892
1
        goto error;
1893
1894
    /*
1895
     * Add it at the end to preserve parsing order ...
1896
     */
1897
614k
    if (node != NULL) {
1898
614k
        if (node->properties == NULL) {
1899
592k
            node->properties = cur;
1900
592k
        } else {
1901
21.8k
            xmlAttrPtr prev = node->properties;
1902
1903
22.9k
            while (prev->next != NULL)
1904
1.14k
                prev = prev->next;
1905
21.8k
            prev->next = cur;
1906
21.8k
            cur->prev = prev;
1907
21.8k
        }
1908
614k
    }
1909
1910
614k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1911
0
        xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1912
614k
    return (cur);
1913
1914
27
error:
1915
27
    xmlFreeProp(cur);
1916
27
    return(NULL);
1917
614k
}
1918
1919
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
1920
    defined(LIBXML_SCHEMAS_ENABLED)
1921
/**
1922
 * xmlNewProp:
1923
 * @node:  the holding node
1924
 * @name:  the name of the attribute
1925
 * @value:  the value of the attribute
1926
 *
1927
 * Create a new property carried by a node.
1928
 * Returns a pointer to the attribute
1929
 */
1930
xmlAttrPtr
1931
6
xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1932
1933
6
    if (name == NULL) {
1934
0
  return(NULL);
1935
0
    }
1936
1937
6
  return xmlNewPropInternal(node, NULL, name, value, 0);
1938
6
}
1939
#endif /* LIBXML_TREE_ENABLED */
1940
1941
/**
1942
 * xmlNewNsProp:
1943
 * @node:  the holding node
1944
 * @ns:  the namespace
1945
 * @name:  the name of the attribute
1946
 * @value:  the value of the attribute
1947
 *
1948
 * Create a new property tagged with a namespace and carried by a node.
1949
 * Returns a pointer to the attribute
1950
 */
1951
xmlAttrPtr
1952
xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
1953
606k
           const xmlChar *value) {
1954
1955
606k
    if (name == NULL) {
1956
0
  return(NULL);
1957
0
    }
1958
1959
606k
    return xmlNewPropInternal(node, ns, name, value, 0);
1960
606k
}
1961
1962
/**
1963
 * xmlNewNsPropEatName:
1964
 * @node:  the holding node
1965
 * @ns:  the namespace
1966
 * @name:  the name of the attribute
1967
 * @value:  the value of the attribute
1968
 *
1969
 * Create a new property tagged with a namespace and carried by a node.
1970
 * Returns a pointer to the attribute
1971
 */
1972
xmlAttrPtr
1973
xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
1974
0
           const xmlChar *value) {
1975
1976
0
    if (name == NULL) {
1977
0
  return(NULL);
1978
0
    }
1979
1980
0
    return xmlNewPropInternal(node, ns, name, value, 1);
1981
0
}
1982
1983
/**
1984
 * xmlNewDocProp:
1985
 * @doc:  the document
1986
 * @name:  the name of the attribute
1987
 * @value:  the value of the attribute
1988
 *
1989
 * Create a new property carried by a document.
1990
 * NOTE: @value is supposed to be a piece of XML CDATA, so it allows entity
1991
 *       references, but XML special chars need to be escaped first by using
1992
 *       xmlEncodeEntitiesReentrant(). Use xmlNewProp() if you don't need
1993
 *       entities support.
1994
 *
1995
 * Returns a pointer to the attribute
1996
 */
1997
xmlAttrPtr
1998
286k
xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1999
286k
    xmlAttrPtr cur;
2000
2001
286k
    if (name == NULL) {
2002
0
  return(NULL);
2003
0
    }
2004
2005
    /*
2006
     * Allocate a new property and fill the fields.
2007
     */
2008
286k
    cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
2009
286k
    if (cur == NULL)
2010
105
  return(NULL);
2011
286k
    memset(cur, 0, sizeof(xmlAttr));
2012
286k
    cur->type = XML_ATTRIBUTE_NODE;
2013
2014
286k
    if ((doc != NULL) && (doc->dict != NULL))
2015
286k
  cur->name = xmlDictLookup(doc->dict, name, -1);
2016
0
    else
2017
0
  cur->name = xmlStrdup(name);
2018
286k
    if (cur->name == NULL)
2019
0
        goto error;
2020
286k
    cur->doc = doc;
2021
286k
    if (value != NULL) {
2022
0
  xmlNodePtr tmp;
2023
2024
0
  cur->children = xmlStringGetNodeList(doc, value);
2025
0
  cur->last = NULL;
2026
2027
0
  tmp = cur->children;
2028
0
  while (tmp != NULL) {
2029
0
      tmp->parent = (xmlNodePtr) cur;
2030
0
      if (tmp->next == NULL)
2031
0
    cur->last = tmp;
2032
0
      tmp = tmp->next;
2033
0
  }
2034
0
    }
2035
2036
286k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2037
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2038
286k
    return(cur);
2039
2040
0
error:
2041
0
    xmlFreeProp(cur);
2042
0
    return(NULL);
2043
286k
}
2044
2045
/**
2046
 * xmlFreePropList:
2047
 * @cur:  the first property in the list
2048
 *
2049
 * Free a property and all its siblings, all the children are freed too.
2050
 */
2051
void
2052
1.94M
xmlFreePropList(xmlAttrPtr cur) {
2053
1.94M
    xmlAttrPtr next;
2054
1.94M
    if (cur == NULL) return;
2055
4.35M
    while (cur != NULL) {
2056
2.41M
        next = cur->next;
2057
2.41M
        xmlFreeProp(cur);
2058
2.41M
  cur = next;
2059
2.41M
    }
2060
1.94M
}
2061
2062
/**
2063
 * xmlFreeProp:
2064
 * @cur:  an attribute
2065
 *
2066
 * Free one attribute, all the content is freed too
2067
 */
2068
void
2069
2.41M
xmlFreeProp(xmlAttrPtr cur) {
2070
2.41M
    xmlDictPtr dict = NULL;
2071
2.41M
    if (cur == NULL) return;
2072
2073
2.41M
    if (cur->doc != NULL) dict = cur->doc->dict;
2074
2075
2.41M
    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
2076
0
  xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2077
2078
    /* Check for ID removal -> leading to invalid references ! */
2079
2.41M
    if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2080
223k
      xmlRemoveID(cur->doc, cur);
2081
223k
    }
2082
2.41M
    if (cur->children != NULL) xmlFreeNodeList(cur->children);
2083
2.41M
    DICT_FREE(cur->name)
2084
2.41M
    xmlFree(cur);
2085
2.41M
}
2086
2087
/**
2088
 * xmlRemoveProp:
2089
 * @cur:  an attribute
2090
 *
2091
 * Unlink and free one attribute, all the content is freed too
2092
 * Note this doesn't work for namespace definition attributes
2093
 *
2094
 * Returns 0 if success and -1 in case of error.
2095
 */
2096
int
2097
0
xmlRemoveProp(xmlAttrPtr cur) {
2098
0
    xmlAttrPtr tmp;
2099
0
    if (cur == NULL) {
2100
0
  return(-1);
2101
0
    }
2102
0
    if (cur->parent == NULL) {
2103
0
  return(-1);
2104
0
    }
2105
0
    tmp = cur->parent->properties;
2106
0
    if (tmp == cur) {
2107
0
        cur->parent->properties = cur->next;
2108
0
    if (cur->next != NULL)
2109
0
      cur->next->prev = NULL;
2110
0
  xmlFreeProp(cur);
2111
0
  return(0);
2112
0
    }
2113
0
    while (tmp != NULL) {
2114
0
  if (tmp->next == cur) {
2115
0
      tmp->next = cur->next;
2116
0
      if (tmp->next != NULL)
2117
0
    tmp->next->prev = tmp;
2118
0
      xmlFreeProp(cur);
2119
0
      return(0);
2120
0
  }
2121
0
        tmp = tmp->next;
2122
0
    }
2123
0
    return(-1);
2124
0
}
2125
2126
/**
2127
 * xmlNewDocPI:
2128
 * @doc:  the target document
2129
 * @name:  the processing instruction name
2130
 * @content:  the PI content
2131
 *
2132
 * Creation of a processing instruction element.
2133
 * Returns a pointer to the new node object.
2134
 */
2135
xmlNodePtr
2136
80.3k
xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
2137
80.3k
    xmlNodePtr cur;
2138
2139
80.3k
    if (name == NULL) {
2140
0
  return(NULL);
2141
0
    }
2142
2143
    /*
2144
     * Allocate a new node and fill the fields.
2145
     */
2146
80.3k
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2147
80.3k
    if (cur == NULL)
2148
18
  return(NULL);
2149
80.2k
    memset(cur, 0, sizeof(xmlNode));
2150
80.2k
    cur->type = XML_PI_NODE;
2151
80.2k
    cur->doc = doc;
2152
2153
80.2k
    if ((doc != NULL) && (doc->dict != NULL))
2154
80.2k
        cur->name = xmlDictLookup(doc->dict, name, -1);
2155
0
    else
2156
0
  cur->name = xmlStrdup(name);
2157
80.2k
    if (cur->name == NULL)
2158
0
        goto error;
2159
80.2k
    if (content != NULL) {
2160
29.7k
  cur->content = xmlStrdup(content);
2161
29.7k
        if (cur->content == NULL)
2162
3
            goto error;
2163
29.7k
    }
2164
2165
80.2k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2166
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2167
80.2k
    return(cur);
2168
2169
3
error:
2170
3
    xmlFreeNode(cur);
2171
3
    return(NULL);
2172
80.2k
}
2173
2174
/**
2175
 * xmlNewPI:
2176
 * @name:  the processing instruction name
2177
 * @content:  the PI content
2178
 *
2179
 * Creation of a processing instruction element.
2180
 *
2181
 * Use of this function is DISCOURAGED in favor of xmlNewDocPI.
2182
 *
2183
 * Returns a pointer to the new node object.
2184
 */
2185
xmlNodePtr
2186
0
xmlNewPI(const xmlChar *name, const xmlChar *content) {
2187
0
    return(xmlNewDocPI(NULL, name, content));
2188
0
}
2189
2190
/**
2191
 * xmlNewNode:
2192
 * @ns:  namespace if any
2193
 * @name:  the node name
2194
 *
2195
 * Creation of a new node element. @ns is optional (NULL).
2196
 *
2197
 * Use of this function is DISCOURAGED in favor of xmlNewDocNode.
2198
 *
2199
 * Returns a pointer to the new node object. Uses xmlStrdup() to make
2200
 * copy of @name.
2201
 */
2202
xmlNodePtr
2203
0
xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2204
0
    xmlNodePtr cur;
2205
2206
0
    if (name == NULL) {
2207
0
  return(NULL);
2208
0
    }
2209
2210
    /*
2211
     * Allocate a new node and fill the fields.
2212
     */
2213
0
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2214
0
    if (cur == NULL)
2215
0
  return(NULL);
2216
0
    memset(cur, 0, sizeof(xmlNode));
2217
0
    cur->type = XML_ELEMENT_NODE;
2218
2219
0
    cur->name = xmlStrdup(name);
2220
0
    if (cur->name == NULL)
2221
0
        goto error;
2222
0
    cur->ns = ns;
2223
2224
0
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2225
0
  xmlRegisterNodeDefaultValue(cur);
2226
0
    return(cur);
2227
2228
0
error:
2229
0
    xmlFreeNode(cur);
2230
0
    return(NULL);
2231
0
}
2232
2233
/**
2234
 * xmlNewNodeEatName:
2235
 * @ns:  namespace if any
2236
 * @name:  the node name
2237
 *
2238
 * Creation of a new node element. @ns is optional (NULL).
2239
 *
2240
 * Use of this function is DISCOURAGED in favor of xmlNewDocNodeEatName.
2241
 *
2242
 * Returns a pointer to the new node object, with pointer @name as
2243
 * new node's name. Use xmlNewNode() if a copy of @name string is
2244
 * is needed as new node's name.
2245
 */
2246
xmlNodePtr
2247
6.45M
xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2248
6.45M
    xmlNodePtr cur;
2249
2250
6.45M
    if (name == NULL) {
2251
633
  return(NULL);
2252
633
    }
2253
2254
    /*
2255
     * Allocate a new node and fill the fields.
2256
     */
2257
6.45M
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2258
6.45M
    if (cur == NULL)
2259
2.59k
  return(NULL);
2260
6.45M
    memset(cur, 0, sizeof(xmlNode));
2261
6.45M
    cur->type = XML_ELEMENT_NODE;
2262
2263
6.45M
    cur->name = name;
2264
6.45M
    cur->ns = ns;
2265
2266
6.45M
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2267
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2268
6.45M
    return(cur);
2269
6.45M
}
2270
2271
/**
2272
 * xmlNewDocNode:
2273
 * @doc:  the document
2274
 * @ns:  namespace if any
2275
 * @name:  the node name
2276
 * @content:  the XML text content if any
2277
 *
2278
 * Creation of a new node element within a document. @ns and @content
2279
 * are optional (NULL).
2280
 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2281
 *       references, but XML special chars need to be escaped first by using
2282
 *       xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2283
 *       need entities support.
2284
 *
2285
 * Returns a pointer to the new node object.
2286
 */
2287
xmlNodePtr
2288
xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
2289
544k
              const xmlChar *name, const xmlChar *content) {
2290
544k
    xmlNodePtr cur;
2291
2292
544k
    if ((doc != NULL) && (doc->dict != NULL))
2293
544k
        cur = xmlNewNodeEatName(ns, (xmlChar *)
2294
544k
                          xmlDictLookup(doc->dict, name, -1));
2295
0
    else
2296
0
  cur = xmlNewNode(ns, name);
2297
544k
    if (cur != NULL) {
2298
541k
        cur->doc = doc;
2299
541k
  if (content != NULL) {
2300
0
      cur->children = xmlStringGetNodeList(doc, content);
2301
0
      UPDATE_LAST_CHILD_AND_PARENT(cur)
2302
0
  }
2303
541k
    }
2304
2305
544k
    return(cur);
2306
544k
}
2307
2308
/**
2309
 * xmlNewDocNodeEatName:
2310
 * @doc:  the document
2311
 * @ns:  namespace if any
2312
 * @name:  the node name
2313
 * @content:  the XML text content if any
2314
 *
2315
 * Creation of a new node element within a document. @ns and @content
2316
 * are optional (NULL).
2317
 * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
2318
 *       references, but XML special chars need to be escaped first by using
2319
 *       xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
2320
 *       need entities support.
2321
 *
2322
 * Returns a pointer to the new node object.
2323
 */
2324
xmlNodePtr
2325
xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
2326
5.91M
              xmlChar *name, const xmlChar *content) {
2327
5.91M
    xmlNodePtr cur;
2328
2329
5.91M
    cur = xmlNewNodeEatName(ns, name);
2330
5.91M
    if (cur != NULL) {
2331
5.91M
        cur->doc = doc;
2332
5.91M
  if (content != NULL) {
2333
0
      cur->children = xmlStringGetNodeList(doc, content);
2334
0
            if (cur->children == NULL) {
2335
0
                xmlFreeNode(cur);
2336
0
                return(NULL);
2337
0
            }
2338
0
      UPDATE_LAST_CHILD_AND_PARENT(cur)
2339
0
  }
2340
5.91M
    } else {
2341
        /* if name don't come from the doc dictionary free it here */
2342
573
        if ((name != NULL) &&
2343
573
            ((doc == NULL) || (doc->dict == NULL) ||
2344
573
       (!(xmlDictOwns(doc->dict, name)))))
2345
0
      xmlFree(name);
2346
573
    }
2347
5.91M
    return(cur);
2348
5.91M
}
2349
2350
#ifdef LIBXML_TREE_ENABLED
2351
/**
2352
 * xmlNewDocRawNode:
2353
 * @doc:  the document
2354
 * @ns:  namespace if any
2355
 * @name:  the node name
2356
 * @content:  the text content if any
2357
 *
2358
 * Creation of a new node element within a document. @ns and @content
2359
 * are optional (NULL).
2360
 *
2361
 * Returns a pointer to the new node object.
2362
 */
2363
xmlNodePtr
2364
xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
2365
533k
                 const xmlChar *name, const xmlChar *content) {
2366
533k
    xmlNodePtr cur;
2367
2368
533k
    cur = xmlNewDocNode(doc, ns, name, NULL);
2369
533k
    if (cur != NULL) {
2370
530k
        cur->doc = doc;
2371
530k
  if (content != NULL) {
2372
530k
      cur->children = xmlNewDocText(doc, content);
2373
530k
      UPDATE_LAST_CHILD_AND_PARENT(cur)
2374
530k
  }
2375
530k
    }
2376
533k
    return(cur);
2377
533k
}
2378
2379
/**
2380
 * xmlNewDocFragment:
2381
 * @doc:  the document owning the fragment
2382
 *
2383
 * Creation of a new Fragment node.
2384
 * Returns a pointer to the new node object.
2385
 */
2386
xmlNodePtr
2387
0
xmlNewDocFragment(xmlDocPtr doc) {
2388
0
    xmlNodePtr cur;
2389
2390
    /*
2391
     * Allocate a new DocumentFragment node and fill the fields.
2392
     */
2393
0
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2394
0
    if (cur == NULL)
2395
0
  return(NULL);
2396
0
    memset(cur, 0, sizeof(xmlNode));
2397
0
    cur->type = XML_DOCUMENT_FRAG_NODE;
2398
2399
0
    cur->doc = doc;
2400
2401
0
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2402
0
  xmlRegisterNodeDefaultValue(cur);
2403
0
    return(cur);
2404
0
}
2405
#endif /* LIBXML_TREE_ENABLED */
2406
2407
/**
2408
 * xmlNewText:
2409
 * @content:  the text content
2410
 *
2411
 * Creation of a new text node.
2412
 *
2413
 * Use of this function is DISCOURAGED in favor of xmlNewDocText.
2414
 *
2415
 * Returns a pointer to the new node object.
2416
 */
2417
xmlNodePtr
2418
1.49M
xmlNewText(const xmlChar *content) {
2419
1.49M
    xmlNodePtr cur;
2420
2421
    /*
2422
     * Allocate a new node and fill the fields.
2423
     */
2424
1.49M
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2425
1.49M
    if (cur == NULL)
2426
117
  return(NULL);
2427
1.49M
    memset(cur, 0, sizeof(xmlNode));
2428
1.49M
    cur->type = XML_TEXT_NODE;
2429
2430
1.49M
    cur->name = xmlStringText;
2431
1.49M
    if (content != NULL) {
2432
1.14M
  cur->content = xmlStrdup(content);
2433
1.14M
        if (cur->content == NULL)
2434
42
            goto error;
2435
1.14M
    }
2436
2437
1.49M
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2438
0
  xmlRegisterNodeDefaultValue(cur);
2439
1.49M
    return(cur);
2440
2441
42
error:
2442
42
    xmlFreeNode(cur);
2443
42
    return(NULL);
2444
1.49M
}
2445
2446
#ifdef LIBXML_TREE_ENABLED
2447
/**
2448
 * xmlNewTextChild:
2449
 * @parent:  the parent node
2450
 * @ns:  a namespace if any
2451
 * @name:  the name of the child
2452
 * @content:  the text content of the child if any.
2453
 *
2454
 * Creation of a new child element, added at the end of @parent children list.
2455
 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2456
 * created element inherits the namespace of @parent. If @content is non NULL,
2457
 * a child TEXT node will be created containing the string @content.
2458
 * NOTE: Use xmlNewChild() if @content will contain entities that need to be
2459
 * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
2460
 * reserved XML chars that might appear in @content, such as the ampersand,
2461
 * greater-than or less-than signs, are automatically replaced by their XML
2462
 * escaped entity representations.
2463
 *
2464
 * Returns a pointer to the new node object.
2465
 */
2466
xmlNodePtr
2467
xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
2468
456k
            const xmlChar *name, const xmlChar *content) {
2469
456k
    xmlNodePtr cur, prev;
2470
2471
456k
    if (parent == NULL) {
2472
0
  return(NULL);
2473
0
    }
2474
2475
456k
    if (name == NULL) {
2476
0
  return(NULL);
2477
0
    }
2478
2479
    /*
2480
     * Allocate a new node
2481
     */
2482
456k
    if (parent->type == XML_ELEMENT_NODE) {
2483
0
  if (ns == NULL)
2484
0
      cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
2485
0
  else
2486
0
      cur = xmlNewDocRawNode(parent->doc, ns, name, content);
2487
456k
    } else if ((parent->type == XML_DOCUMENT_NODE) ||
2488
456k
         (parent->type == XML_HTML_DOCUMENT_NODE)) {
2489
456k
  if (ns == NULL)
2490
456k
      cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2491
0
  else
2492
0
      cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2493
456k
    } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2494
0
      cur = xmlNewDocRawNode( parent->doc, ns, name, content);
2495
0
    } else {
2496
0
  return(NULL);
2497
0
    }
2498
456k
    if (cur == NULL) return(NULL);
2499
2500
    /*
2501
     * add the new element at the end of the children list.
2502
     */
2503
455k
    cur->type = XML_ELEMENT_NODE;
2504
455k
    cur->parent = parent;
2505
455k
    cur->doc = parent->doc;
2506
455k
    if (parent->children == NULL) {
2507
35.9k
        parent->children = cur;
2508
35.9k
  parent->last = cur;
2509
419k
    } else {
2510
419k
        prev = parent->last;
2511
419k
  prev->next = cur;
2512
419k
  cur->prev = prev;
2513
419k
  parent->last = cur;
2514
419k
    }
2515
2516
455k
    return(cur);
2517
456k
}
2518
#endif /* LIBXML_TREE_ENABLED */
2519
2520
/**
2521
 * xmlNewCharRef:
2522
 * @doc: the document
2523
 * @name:  the char ref string, starting with # or "&# ... ;"
2524
 *
2525
 * Creation of a new character reference node.
2526
 * Returns a pointer to the new node object.
2527
 */
2528
xmlNodePtr
2529
0
xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
2530
0
    xmlNodePtr cur;
2531
2532
0
    if (name == NULL)
2533
0
        return(NULL);
2534
2535
    /*
2536
     * Allocate a new node and fill the fields.
2537
     */
2538
0
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2539
0
    if (cur == NULL)
2540
0
  return(NULL);
2541
0
    memset(cur, 0, sizeof(xmlNode));
2542
0
    cur->type = XML_ENTITY_REF_NODE;
2543
2544
0
    cur->doc = doc;
2545
0
    if (name[0] == '&') {
2546
0
        int len;
2547
0
        name++;
2548
0
  len = xmlStrlen(name);
2549
0
  if (name[len - 1] == ';')
2550
0
      cur->name = xmlStrndup(name, len - 1);
2551
0
  else
2552
0
      cur->name = xmlStrndup(name, len);
2553
0
    } else
2554
0
  cur->name = xmlStrdup(name);
2555
0
    if (cur->name == NULL)
2556
0
        goto error;
2557
2558
0
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2559
0
  xmlRegisterNodeDefaultValue(cur);
2560
0
    return(cur);
2561
2562
0
error:
2563
0
    xmlFreeNode(cur);
2564
0
    return(NULL);
2565
0
}
2566
2567
/**
2568
 * xmlNewReference:
2569
 * @doc: the document
2570
 * @name:  the reference name, or the reference string with & and ;
2571
 *
2572
 * Creation of a new reference node.
2573
 * Returns a pointer to the new node object.
2574
 */
2575
xmlNodePtr
2576
24.4k
xmlNewReference(const xmlDoc *doc, const xmlChar *name) {
2577
24.4k
    xmlNodePtr cur;
2578
24.4k
    xmlEntityPtr ent;
2579
2580
24.4k
    if (name == NULL)
2581
0
        return(NULL);
2582
2583
    /*
2584
     * Allocate a new node and fill the fields.
2585
     */
2586
24.4k
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2587
24.4k
    if (cur == NULL)
2588
0
  return(NULL);
2589
24.4k
    memset(cur, 0, sizeof(xmlNode));
2590
24.4k
    cur->type = XML_ENTITY_REF_NODE;
2591
2592
24.4k
    cur->doc = (xmlDoc *)doc;
2593
24.4k
    if (name[0] == '&') {
2594
0
        int len;
2595
0
        name++;
2596
0
  len = xmlStrlen(name);
2597
0
  if (name[len - 1] == ';')
2598
0
      cur->name = xmlStrndup(name, len - 1);
2599
0
  else
2600
0
      cur->name = xmlStrndup(name, len);
2601
0
    } else
2602
24.4k
  cur->name = xmlStrdup(name);
2603
24.4k
    if (cur->name == NULL)
2604
1
        goto error;
2605
2606
24.4k
    ent = xmlGetDocEntity(doc, cur->name);
2607
24.4k
    if (ent != NULL) {
2608
13.8k
  cur->content = ent->content;
2609
  /*
2610
   * The parent pointer in entity is a DTD pointer and thus is NOT
2611
   * updated.  Not sure if this is 100% correct.
2612
   *  -George
2613
   */
2614
13.8k
  cur->children = (xmlNodePtr) ent;
2615
13.8k
  cur->last = (xmlNodePtr) ent;
2616
13.8k
    }
2617
2618
24.4k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2619
0
  xmlRegisterNodeDefaultValue(cur);
2620
24.4k
    return(cur);
2621
2622
1
error:
2623
1
    xmlFreeNode(cur);
2624
1
    return(NULL);
2625
24.4k
}
2626
2627
/**
2628
 * xmlNewDocText:
2629
 * @doc: the document
2630
 * @content:  the text content
2631
 *
2632
 * Creation of a new text node within a document.
2633
 * Returns a pointer to the new node object.
2634
 */
2635
xmlNodePtr
2636
1.20M
xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
2637
1.20M
    xmlNodePtr cur;
2638
2639
1.20M
    cur = xmlNewText(content);
2640
1.20M
    if (cur != NULL) cur->doc = (xmlDoc *)doc;
2641
1.20M
    return(cur);
2642
1.20M
}
2643
2644
/**
2645
 * xmlNewTextLen:
2646
 * @content:  the text content
2647
 * @len:  the text len.
2648
 *
2649
 * Use of this function is DISCOURAGED in favor of xmlNewDocTextLen.
2650
 *
2651
 * Creation of a new text node with an extra parameter for the content's length
2652
 * Returns a pointer to the new node object.
2653
 */
2654
xmlNodePtr
2655
1.39M
xmlNewTextLen(const xmlChar *content, int len) {
2656
1.39M
    xmlNodePtr cur;
2657
2658
    /*
2659
     * Allocate a new node and fill the fields.
2660
     */
2661
1.39M
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2662
1.39M
    if (cur == NULL)
2663
3.78k
  return(NULL);
2664
1.38M
    memset(cur, 0, sizeof(xmlNode));
2665
1.38M
    cur->type = XML_TEXT_NODE;
2666
2667
1.38M
    cur->name = xmlStringText;
2668
1.38M
    if (content != NULL) {
2669
838k
  cur->content = xmlStrndup(content, len);
2670
838k
    }
2671
2672
1.38M
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2673
0
  xmlRegisterNodeDefaultValue(cur);
2674
1.38M
    return(cur);
2675
1.39M
}
2676
2677
/**
2678
 * xmlNewDocTextLen:
2679
 * @doc: the document
2680
 * @content:  the text content
2681
 * @len:  the text len.
2682
 *
2683
 * Creation of a new text node with an extra content length parameter. The
2684
 * text node pertain to a given document.
2685
 * Returns a pointer to the new node object.
2686
 */
2687
xmlNodePtr
2688
0
xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
2689
0
    xmlNodePtr cur;
2690
2691
0
    cur = xmlNewTextLen(content, len);
2692
0
    if (cur != NULL) cur->doc = doc;
2693
0
    return(cur);
2694
0
}
2695
2696
/**
2697
 * xmlNewComment:
2698
 * @content:  the comment content
2699
 *
2700
 * Use of this function is DISCOURAGED in favor of xmlNewDocComment.
2701
 *
2702
 * Creation of a new node containing a comment.
2703
 * Returns a pointer to the new node object.
2704
 */
2705
xmlNodePtr
2706
44.4k
xmlNewComment(const xmlChar *content) {
2707
44.4k
    xmlNodePtr cur;
2708
2709
    /*
2710
     * Allocate a new node and fill the fields.
2711
     */
2712
44.4k
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2713
44.4k
    if (cur == NULL)
2714
25
  return(NULL);
2715
44.4k
    memset(cur, 0, sizeof(xmlNode));
2716
44.4k
    cur->type = XML_COMMENT_NODE;
2717
2718
44.4k
    cur->name = xmlStringComment;
2719
44.4k
    if (content != NULL) {
2720
41.8k
  cur->content = xmlStrdup(content);
2721
41.8k
        if (cur->content == NULL)
2722
3
            goto error;
2723
41.8k
    }
2724
2725
44.4k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2726
0
  xmlRegisterNodeDefaultValue(cur);
2727
44.4k
    return(cur);
2728
2729
3
error:
2730
3
    xmlFreeNode(cur);
2731
3
    return(NULL);
2732
44.4k
}
2733
2734
/**
2735
 * xmlNewCDataBlock:
2736
 * @doc:  the document
2737
 * @content:  the CDATA block content content
2738
 * @len:  the length of the block
2739
 *
2740
 * Creation of a new node containing a CDATA block.
2741
 * Returns a pointer to the new node object.
2742
 */
2743
xmlNodePtr
2744
202k
xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2745
202k
    xmlNodePtr cur;
2746
2747
    /*
2748
     * Allocate a new node and fill the fields.
2749
     */
2750
202k
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2751
202k
    if (cur == NULL)
2752
32
  return(NULL);
2753
202k
    memset(cur, 0, sizeof(xmlNode));
2754
202k
    cur->type = XML_CDATA_SECTION_NODE;
2755
202k
    cur->doc = doc;
2756
2757
202k
    if (content != NULL) {
2758
202k
  cur->content = xmlStrndup(content, len);
2759
202k
        if (cur->content == NULL) {
2760
8
            xmlFree(cur);
2761
8
            return(NULL);
2762
8
        }
2763
202k
    }
2764
2765
202k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2766
0
  xmlRegisterNodeDefaultValue(cur);
2767
202k
    return(cur);
2768
202k
}
2769
2770
/**
2771
 * xmlNewDocComment:
2772
 * @doc:  the document
2773
 * @content:  the comment content
2774
 *
2775
 * Creation of a new node containing a comment within a document.
2776
 * Returns a pointer to the new node object.
2777
 */
2778
xmlNodePtr
2779
39.9k
xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2780
39.9k
    xmlNodePtr cur;
2781
2782
39.9k
    cur = xmlNewComment(content);
2783
39.9k
    if (cur != NULL) cur->doc = doc;
2784
39.9k
    return(cur);
2785
39.9k
}
2786
2787
1.65M
static const xmlChar *_copyStringForNewDictIfNeeded(xmlDictPtr oldDict, xmlDictPtr newDict, const xmlChar *oldValue) {
2788
1.65M
    const xmlChar *newValue = oldValue;
2789
1.65M
    if (oldValue) {
2790
1.64M
        int oldDictOwnsOldValue = oldDict && (xmlDictOwns(oldDict, oldValue) == 1);
2791
1.64M
        if (oldDictOwnsOldValue) {
2792
1.80k
            if (newDict)
2793
1.80k
                newValue = xmlDictLookup(newDict, oldValue, -1);
2794
0
            else
2795
0
                newValue = xmlStrdup(oldValue);
2796
1.80k
        }
2797
1.64M
    }
2798
1.65M
    return newValue;
2799
1.65M
}
2800
2801
/**
2802
 * xmlSetTreeDoc:
2803
 * @tree:  the top element
2804
 * @doc:  the document
2805
 *
2806
 * update all nodes under the tree to point to the right document
2807
 */
2808
void
2809
826k
xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
2810
826k
    xmlAttrPtr prop;
2811
2812
826k
    if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2813
0
  return;
2814
826k
    if (tree->doc != doc) {
2815
826k
        xmlDictPtr oldTreeDict = tree->doc ? tree->doc->dict : NULL;
2816
826k
        xmlDictPtr newDict = doc ? doc->dict : NULL;
2817
2818
826k
  if(tree->type == XML_ELEMENT_NODE) {
2819
1.80k
      prop = tree->properties;
2820
1.80k
      while (prop != NULL) {
2821
0
                if (prop->atype == XML_ATTRIBUTE_ID) {
2822
0
                    xmlRemoveID(tree->doc, prop);
2823
0
                }
2824
2825
0
                if (prop->doc != doc) {
2826
0
                    xmlDictPtr oldPropDict = prop->doc ? prop->doc->dict : NULL;
2827
                    /* TODO: malloc check */
2828
0
                    prop->name = _copyStringForNewDictIfNeeded(oldPropDict, newDict, prop->name);
2829
0
                    prop->doc = doc;
2830
0
                }
2831
0
    xmlSetListDoc(prop->children, doc);
2832
2833
                /*
2834
                 * TODO: ID attributes should be also added to the new
2835
                 * document, but this breaks things like xmlReplaceNode.
2836
                 * The underlying problem is that xmlRemoveID is only called
2837
                 * if a node is destroyed, not if it's unlinked.
2838
                 */
2839
#if 0
2840
                if (xmlIsID(doc, tree, prop)) {
2841
                    xmlChar *idVal = xmlNodeListGetString(doc, prop->children,
2842
                                                          1);
2843
                    xmlAddID(NULL, doc, idVal, prop);
2844
                }
2845
#endif
2846
2847
0
    prop = prop->next;
2848
0
      }
2849
1.80k
  }
2850
826k
        if (tree->type == XML_ENTITY_REF_NODE) {
2851
            /*
2852
             * Clear 'children' which points to the entity declaration
2853
             * from the original document.
2854
             */
2855
0
            tree->children = NULL;
2856
826k
        } else if (tree->children != NULL) {
2857
0
      xmlSetListDoc(tree->children, doc);
2858
0
        }
2859
2860
        /* TODO: malloc check */
2861
826k
        tree->name = _copyStringForNewDictIfNeeded(oldTreeDict, newDict, tree->name);
2862
826k
        tree->content = (xmlChar *)_copyStringForNewDictIfNeeded(oldTreeDict, NULL, tree->content);
2863
        /* FIXME: tree->ns should be updated as in xmlStaticCopyNode(). */
2864
826k
  tree->doc = doc;
2865
826k
    }
2866
826k
}
2867
2868
/**
2869
 * xmlSetListDoc:
2870
 * @list:  the first element
2871
 * @doc:  the document
2872
 *
2873
 * update all nodes in the list to point to the right document
2874
 */
2875
void
2876
0
xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2877
0
    xmlNodePtr cur;
2878
2879
0
    if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
2880
0
  return;
2881
0
    cur = list;
2882
0
    while (cur != NULL) {
2883
0
  if (cur->doc != doc)
2884
0
      xmlSetTreeDoc(cur, doc);
2885
0
  cur = cur->next;
2886
0
    }
2887
0
}
2888
2889
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
2890
/**
2891
 * xmlNewChild:
2892
 * @parent:  the parent node
2893
 * @ns:  a namespace if any
2894
 * @name:  the name of the child
2895
 * @content:  the XML content of the child if any.
2896
 *
2897
 * Creation of a new child element, added at the end of @parent children list.
2898
 * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
2899
 * created element inherits the namespace of @parent. If @content is non NULL,
2900
 * a child list containing the TEXTs and ENTITY_REFs node will be created.
2901
 * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
2902
 *       references. XML special chars must be escaped first by using
2903
 *       xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
2904
 *
2905
 * Returns a pointer to the new node object.
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) {
2913
0
  return(NULL);
2914
0
    }
2915
2916
0
    if (name == NULL) {
2917
0
  return(NULL);
2918
0
    }
2919
2920
    /*
2921
     * Allocate a new node
2922
     */
2923
0
    if (parent->type == XML_ELEMENT_NODE) {
2924
0
  if (ns == NULL)
2925
0
      cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
2926
0
  else
2927
0
      cur = xmlNewDocNode(parent->doc, ns, name, content);
2928
0
    } else if ((parent->type == XML_DOCUMENT_NODE) ||
2929
0
         (parent->type == XML_HTML_DOCUMENT_NODE)) {
2930
0
  if (ns == NULL)
2931
0
      cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
2932
0
  else
2933
0
      cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
2934
0
    } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
2935
0
      cur = xmlNewDocNode( parent->doc, ns, name, content);
2936
0
    } else {
2937
0
  return(NULL);
2938
0
    }
2939
0
    if (cur == NULL) return(NULL);
2940
2941
    /*
2942
     * add the new element at the end of the children list.
2943
     */
2944
0
    cur->type = XML_ELEMENT_NODE;
2945
0
    cur->parent = parent;
2946
0
    cur->doc = parent->doc;
2947
0
    if (parent->children == NULL) {
2948
0
        parent->children = cur;
2949
0
  parent->last = cur;
2950
0
    } else {
2951
0
        prev = parent->last;
2952
0
  prev->next = cur;
2953
0
  cur->prev = prev;
2954
0
  parent->last = cur;
2955
0
    }
2956
2957
0
    return(cur);
2958
0
}
2959
#endif /* LIBXML_TREE_ENABLED */
2960
2961
/**
2962
 * xmlAddPropSibling:
2963
 * @prev:  the attribute to which @prop is added after
2964
 * @cur:   the base attribute passed to calling function
2965
 * @prop:  the new attribute
2966
 *
2967
 * Add a new attribute after @prev using @cur as base attribute.
2968
 * When inserting before @cur, @prev is passed as @cur->prev.
2969
 * When inserting after @cur, @prev is passed as @cur.
2970
 * If an existing attribute is found it is destroyed prior to adding @prop.
2971
 *
2972
 * See the note regarding namespaces in xmlAddChild.
2973
 *
2974
 * Returns the attribute being inserted or NULL in case of error.
2975
 */
2976
static xmlNodePtr
2977
0
xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
2978
0
  xmlAttrPtr attr;
2979
2980
0
  if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) ||
2981
0
      (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) ||
2982
0
      ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)))
2983
0
    return(NULL);
2984
2985
  /* check if an attribute with the same name exists */
2986
0
  if (prop->ns == NULL)
2987
0
    attr = xmlHasNsProp(cur->parent, prop->name, NULL);
2988
0
  else
2989
0
    attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
2990
2991
0
  if (prop->doc != cur->doc) {
2992
0
    xmlSetTreeDoc(prop, cur->doc);
2993
0
  }
2994
0
  prop->parent = cur->parent;
2995
0
  prop->prev = prev;
2996
0
  if (prev != NULL) {
2997
0
    prop->next = prev->next;
2998
0
    prev->next = prop;
2999
0
    if (prop->next)
3000
0
      prop->next->prev = prop;
3001
0
  } else {
3002
0
    prop->next = cur;
3003
0
    cur->prev = prop;
3004
0
  }
3005
0
  if (prop->prev == NULL && prop->parent != NULL)
3006
0
    prop->parent->properties = (xmlAttrPtr) prop;
3007
0
  if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
3008
    /* different instance, destroy it (attributes must be unique) */
3009
0
    xmlRemoveProp((xmlAttrPtr) attr);
3010
0
  }
3011
0
  return prop;
3012
0
}
3013
3014
/**
3015
 * xmlAddNextSibling:
3016
 * @cur:  the child node
3017
 * @elem:  the new node
3018
 *
3019
 * Add a new node @elem as the next sibling of @cur
3020
 * If the new node was already inserted in a document it is
3021
 * first unlinked from its existing context.
3022
 * As a result of text merging @elem may be freed.
3023
 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3024
 * If there is an attribute with equal name, it is first destroyed.
3025
 *
3026
 * See the note regarding namespaces in xmlAddChild.
3027
 *
3028
 * Returns the new node or NULL in case of error.
3029
 */
3030
xmlNodePtr
3031
23.4k
xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
3032
23.4k
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3033
0
  return(NULL);
3034
0
    }
3035
23.4k
    if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3036
0
  return(NULL);
3037
0
    }
3038
3039
23.4k
    if (cur == elem) {
3040
0
  return(NULL);
3041
0
    }
3042
3043
23.4k
    xmlUnlinkNode(elem);
3044
3045
23.4k
    if (elem->type == XML_TEXT_NODE) {
3046
10.5k
  if (cur->type == XML_TEXT_NODE) {
3047
0
      xmlNodeAddContent(cur, elem->content);
3048
0
      xmlFreeNode(elem);
3049
0
      return(cur);
3050
0
  }
3051
10.5k
  if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
3052
10.5k
            (cur->name == cur->next->name)) {
3053
0
      xmlChar *tmp;
3054
3055
            /* TODO: malloc check */
3056
0
      tmp = xmlStrdup(elem->content);
3057
0
      tmp = xmlStrcat(tmp, cur->next->content);
3058
0
      xmlNodeSetContent(cur->next, tmp);
3059
0
      xmlFree(tmp);
3060
0
      xmlFreeNode(elem);
3061
0
      return(cur->next);
3062
0
  }
3063
12.9k
    } else if (elem->type == XML_ATTRIBUTE_NODE) {
3064
0
    return xmlAddPropSibling(cur, cur, elem);
3065
0
    }
3066
3067
23.4k
    if (elem->doc != cur->doc) {
3068
0
  xmlSetTreeDoc(elem, cur->doc);
3069
0
    }
3070
23.4k
    elem->parent = cur->parent;
3071
23.4k
    elem->prev = cur;
3072
23.4k
    elem->next = cur->next;
3073
23.4k
    cur->next = elem;
3074
23.4k
    if (elem->next != NULL)
3075
0
  elem->next->prev = elem;
3076
23.4k
    if ((elem->parent != NULL) && (elem->parent->last == cur))
3077
0
  elem->parent->last = elem;
3078
23.4k
    return(elem);
3079
23.4k
}
3080
3081
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
3082
    defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
3083
/**
3084
 * xmlAddPrevSibling:
3085
 * @cur:  the child node
3086
 * @elem:  the new node
3087
 *
3088
 * Add a new node @elem as the previous sibling of @cur
3089
 * merging adjacent TEXT nodes (@elem may be freed)
3090
 * If the new node was already inserted in a document it is
3091
 * first unlinked from its existing context.
3092
 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3093
 * If there is an attribute with equal name, it is first destroyed.
3094
 *
3095
 * See the note regarding namespaces in xmlAddChild.
3096
 *
3097
 * Returns the new node or NULL in case of error.
3098
 */
3099
xmlNodePtr
3100
14.8k
xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
3101
14.8k
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3102
0
  return(NULL);
3103
0
    }
3104
14.8k
    if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3105
0
  return(NULL);
3106
0
    }
3107
3108
14.8k
    if (cur == elem) {
3109
0
  return(NULL);
3110
0
    }
3111
3112
14.8k
    xmlUnlinkNode(elem);
3113
3114
14.8k
    if (elem->type == XML_TEXT_NODE) {
3115
14.5k
  if (cur->type == XML_TEXT_NODE) {
3116
0
      xmlChar *tmp;
3117
3118
            /* TODO: malloc check */
3119
0
      tmp = xmlStrdup(elem->content);
3120
0
      tmp = xmlStrcat(tmp, cur->content);
3121
0
      xmlNodeSetContent(cur, tmp);
3122
0
      xmlFree(tmp);
3123
0
      xmlFreeNode(elem);
3124
0
      return(cur);
3125
0
  }
3126
14.5k
  if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3127
14.5k
            (cur->name == cur->prev->name)) {
3128
0
      xmlNodeAddContent(cur->prev, elem->content);
3129
0
      xmlFreeNode(elem);
3130
0
      return(cur->prev);
3131
0
  }
3132
14.5k
    } else if (elem->type == XML_ATTRIBUTE_NODE) {
3133
0
    return xmlAddPropSibling(cur->prev, cur, elem);
3134
0
    }
3135
3136
14.8k
    if (elem->doc != cur->doc) {
3137
0
  xmlSetTreeDoc(elem, cur->doc);
3138
0
    }
3139
14.8k
    elem->parent = cur->parent;
3140
14.8k
    elem->next = cur;
3141
14.8k
    elem->prev = cur->prev;
3142
14.8k
    cur->prev = elem;
3143
14.8k
    if (elem->prev != NULL)
3144
13.7k
  elem->prev->next = elem;
3145
14.8k
    if ((elem->parent != NULL) && (elem->parent->children == cur)) {
3146
1.11k
    elem->parent->children = elem;
3147
1.11k
    }
3148
14.8k
    return(elem);
3149
14.8k
}
3150
#endif /* LIBXML_TREE_ENABLED */
3151
3152
/**
3153
 * xmlAddSibling:
3154
 * @cur:  the child node
3155
 * @elem:  the new node
3156
 *
3157
 * Add a new element @elem to the list of siblings of @cur
3158
 * merging adjacent TEXT nodes (@elem may be freed)
3159
 * If the new element was already inserted in a document it is
3160
 * first unlinked from its existing context.
3161
 *
3162
 * See the note regarding namespaces in xmlAddChild.
3163
 *
3164
 * Returns the new element or NULL in case of error.
3165
 */
3166
xmlNodePtr
3167
0
xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
3168
0
    xmlNodePtr parent;
3169
3170
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3171
0
  return(NULL);
3172
0
    }
3173
3174
0
    if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3175
0
  return(NULL);
3176
0
    }
3177
3178
0
    if (cur == elem) {
3179
0
  return(NULL);
3180
0
    }
3181
3182
    /*
3183
     * Constant time is we can rely on the ->parent->last to find
3184
     * the last sibling.
3185
     */
3186
0
    if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
3187
0
  (cur->parent->children != NULL) &&
3188
0
  (cur->parent->last != NULL) &&
3189
0
  (cur->parent->last->next == NULL)) {
3190
0
  cur = cur->parent->last;
3191
0
    } else {
3192
0
  while (cur->next != NULL) cur = cur->next;
3193
0
    }
3194
3195
0
    xmlUnlinkNode(elem);
3196
3197
0
    if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
3198
0
        (cur->name == elem->name)) {
3199
0
  xmlNodeAddContent(cur, elem->content);
3200
0
  xmlFreeNode(elem);
3201
0
  return(cur);
3202
0
    } else if (elem->type == XML_ATTRIBUTE_NODE) {
3203
0
    return xmlAddPropSibling(cur, cur, elem);
3204
0
    }
3205
3206
0
    if (elem->doc != cur->doc) {
3207
0
  xmlSetTreeDoc(elem, cur->doc);
3208
0
    }
3209
0
    parent = cur->parent;
3210
0
    elem->prev = cur;
3211
0
    elem->next = NULL;
3212
0
    elem->parent = parent;
3213
0
    cur->next = elem;
3214
0
    if (parent != NULL)
3215
0
  parent->last = elem;
3216
3217
0
    return(elem);
3218
0
}
3219
3220
/**
3221
 * xmlAddChildList:
3222
 * @parent:  the parent node
3223
 * @cur:  the first node in the list
3224
 *
3225
 * Add a list of node at the end of the child list of the parent
3226
 * merging adjacent TEXT nodes (@cur may be freed)
3227
 *
3228
 * See the note regarding namespaces in xmlAddChild.
3229
 *
3230
 * Returns the last child or NULL in case of error.
3231
 */
3232
xmlNodePtr
3233
0
xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
3234
0
    xmlNodePtr prev;
3235
3236
0
    if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3237
0
  return(NULL);
3238
0
    }
3239
3240
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3241
0
  return(NULL);
3242
0
    }
3243
3244
0
    if ((cur->doc != NULL) && (parent->doc != NULL) &&
3245
0
        (cur->doc != parent->doc)) {
3246
0
    }
3247
3248
    /*
3249
     * add the first element at the end of the children list.
3250
     */
3251
3252
0
    if (parent->children == NULL) {
3253
0
        parent->children = cur;
3254
0
    } else {
3255
  /*
3256
   * If cur and parent->last both are TEXT nodes, then merge them.
3257
   */
3258
0
  if ((cur->type == XML_TEXT_NODE) &&
3259
0
      (parent->last->type == XML_TEXT_NODE) &&
3260
0
      (cur->name == parent->last->name)) {
3261
0
      xmlNodeAddContent(parent->last, cur->content);
3262
      /*
3263
       * if it's the only child, nothing more to be done.
3264
       */
3265
0
      if (cur->next == NULL) {
3266
0
    xmlFreeNode(cur);
3267
0
    return(parent->last);
3268
0
      }
3269
0
      prev = cur;
3270
0
      cur = cur->next;
3271
0
      xmlFreeNode(prev);
3272
0
  }
3273
0
        prev = parent->last;
3274
0
  prev->next = cur;
3275
0
  cur->prev = prev;
3276
0
    }
3277
0
    while (cur->next != NULL) {
3278
0
  cur->parent = parent;
3279
0
  if (cur->doc != parent->doc) {
3280
0
      xmlSetTreeDoc(cur, parent->doc);
3281
0
  }
3282
0
        cur = cur->next;
3283
0
    }
3284
0
    cur->parent = parent;
3285
    /* the parent may not be linked to a doc ! */
3286
0
    if (cur->doc != parent->doc) {
3287
0
        xmlSetTreeDoc(cur, parent->doc);
3288
0
    }
3289
0
    parent->last = cur;
3290
3291
0
    return(cur);
3292
0
}
3293
3294
/**
3295
 * xmlAddChild:
3296
 * @parent:  the parent node
3297
 * @cur:  the child node
3298
 *
3299
 * Add a new node to @parent, at the end of the child (or property) list
3300
 * merging adjacent TEXT nodes (in which case @cur is freed)
3301
 * If the new node is ATTRIBUTE, it is added into properties instead of children.
3302
 * If there is an attribute with equal name, it is first destroyed.
3303
 *
3304
 * All tree manipulation functions can safely move nodes within a document.
3305
 * But when moving nodes from one document to another, references to
3306
 * namespaces in element or attribute nodes are NOT fixed. In this case,
3307
 * you MUST call xmlReconciliateNs after the move operation to avoid
3308
 * memory errors.
3309
 *
3310
 * Returns the child or NULL in case of error.
3311
 */
3312
xmlNodePtr
3313
12.0M
xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3314
12.0M
    xmlNodePtr prev;
3315
3316
12.0M
    if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3317
2.71k
  return(NULL);
3318
2.71k
    }
3319
3320
12.0M
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3321
1.70k
  return(NULL);
3322
1.70k
    }
3323
3324
12.0M
    if (parent == cur) {
3325
0
  return(NULL);
3326
0
    }
3327
    /*
3328
     * If cur is a TEXT node, merge its content with adjacent TEXT nodes
3329
     * cur is then freed.
3330
     */
3331
12.0M
    if (cur->type == XML_TEXT_NODE) {
3332
3.20M
  if ((parent->type == XML_TEXT_NODE) &&
3333
3.20M
      (parent->content != NULL) &&
3334
3.20M
      (parent->name == cur->name)) {
3335
0
      if (xmlNodeAddContent(parent, cur->content) != 0) {
3336
0
                xmlFreeNode(cur);
3337
0
                return(NULL);
3338
0
            }
3339
0
      xmlFreeNode(cur);
3340
0
      return(parent);
3341
0
  }
3342
3.20M
  if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
3343
3.20M
      (parent->last->name == cur->name) &&
3344
3.20M
      (parent->last != cur)) {
3345
0
      if (xmlNodeAddContent(parent->last, cur->content) != 0) {
3346
0
                xmlFreeNode(cur);
3347
0
                return(NULL);
3348
0
            }
3349
0
      xmlFreeNode(cur);
3350
0
      return(parent->last);
3351
0
  }
3352
3.20M
    }
3353
3354
    /*
3355
     * add the new element at the end of the children list.
3356
     */
3357
12.0M
    prev = cur->parent;
3358
12.0M
    cur->parent = parent;
3359
12.0M
    if (cur->doc != parent->doc) {
3360
826k
  xmlSetTreeDoc(cur, parent->doc);
3361
826k
    }
3362
    /* this check prevents a loop on tree-traversions if a developer
3363
     * tries to add a node to its parent multiple times
3364
     */
3365
12.0M
    if (prev == parent)
3366
3.78k
  return(cur);
3367
3368
    /*
3369
     * Coalescing
3370
     */
3371
12.0M
    if ((parent->type == XML_TEXT_NODE) &&
3372
12.0M
  (parent->content != NULL) &&
3373
12.0M
  (parent != cur)) {
3374
0
  if (xmlNodeAddContent(parent, cur->content) != 0) {
3375
0
            xmlFreeNode(cur);
3376
0
            return(NULL);
3377
0
        }
3378
0
  xmlFreeNode(cur);
3379
0
  return(parent);
3380
0
    }
3381
12.0M
    if (cur->type == XML_ATTRIBUTE_NODE) {
3382
0
    if (parent->type != XML_ELEMENT_NODE)
3383
0
      return(NULL);
3384
0
  if (parent->properties != NULL) {
3385
      /* check if an attribute with the same name exists */
3386
0
      xmlAttrPtr lastattr;
3387
3388
0
      if (cur->ns == NULL)
3389
0
    lastattr = xmlHasNsProp(parent, cur->name, NULL);
3390
0
      else
3391
0
    lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
3392
0
      if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
3393
    /* different instance, destroy it (attributes must be unique) */
3394
0
      xmlUnlinkNode((xmlNodePtr) lastattr);
3395
0
    xmlFreeProp(lastattr);
3396
0
      }
3397
0
    if (lastattr == (xmlAttrPtr) cur)
3398
0
      return(cur);
3399
3400
0
  }
3401
0
  if (parent->properties == NULL) {
3402
0
      parent->properties = (xmlAttrPtr) cur;
3403
0
  } else {
3404
      /* find the end */
3405
0
      xmlAttrPtr lastattr = parent->properties;
3406
0
      while (lastattr->next != NULL) {
3407
0
    lastattr = lastattr->next;
3408
0
      }
3409
0
      lastattr->next = (xmlAttrPtr) cur;
3410
0
      ((xmlAttrPtr) cur)->prev = lastattr;
3411
0
  }
3412
12.0M
    } else {
3413
12.0M
  if (parent->children == NULL) {
3414
1.44M
      parent->children = cur;
3415
1.44M
      parent->last = cur;
3416
10.5M
  } else {
3417
10.5M
      prev = parent->last;
3418
10.5M
      prev->next = cur;
3419
10.5M
      cur->prev = prev;
3420
10.5M
      parent->last = cur;
3421
10.5M
  }
3422
12.0M
    }
3423
12.0M
    return(cur);
3424
12.0M
}
3425
3426
/**
3427
 * xmlGetLastChild:
3428
 * @parent:  the parent node
3429
 *
3430
 * Search the last child of a node.
3431
 * Returns the last child or NULL if none.
3432
 */
3433
xmlNodePtr
3434
0
xmlGetLastChild(const xmlNode *parent) {
3435
0
    if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3436
0
  return(NULL);
3437
0
    }
3438
0
    return(parent->last);
3439
0
}
3440
3441
#ifdef LIBXML_TREE_ENABLED
3442
/*
3443
 * 5 interfaces from DOM ElementTraversal
3444
 */
3445
3446
/**
3447
 * xmlChildElementCount:
3448
 * @parent: the parent node
3449
 *
3450
 * Finds the current number of child nodes of that element which are
3451
 * element nodes.
3452
 * Note the handling of entities references is different than in
3453
 * the W3C DOM element traversal spec since we don't have back reference
3454
 * from entities content to entities references.
3455
 *
3456
 * Returns the count of element child or 0 if not available
3457
 */
3458
unsigned long
3459
0
xmlChildElementCount(xmlNodePtr parent) {
3460
0
    unsigned long ret = 0;
3461
0
    xmlNodePtr cur = NULL;
3462
3463
0
    if (parent == NULL)
3464
0
        return(0);
3465
0
    switch (parent->type) {
3466
0
        case XML_ELEMENT_NODE:
3467
0
        case XML_ENTITY_NODE:
3468
0
        case XML_DOCUMENT_NODE:
3469
0
        case XML_DOCUMENT_FRAG_NODE:
3470
0
        case XML_HTML_DOCUMENT_NODE:
3471
0
            cur = parent->children;
3472
0
            break;
3473
0
        default:
3474
0
            return(0);
3475
0
    }
3476
0
    while (cur != NULL) {
3477
0
        if (cur->type == XML_ELEMENT_NODE)
3478
0
            ret++;
3479
0
        cur = cur->next;
3480
0
    }
3481
0
    return(ret);
3482
0
}
3483
3484
/**
3485
 * xmlFirstElementChild:
3486
 * @parent: the parent node
3487
 *
3488
 * Finds the first child node of that element which is a Element node
3489
 * Note the handling of entities references is different than in
3490
 * the W3C DOM element traversal spec since we don't have back reference
3491
 * from entities content to entities references.
3492
 *
3493
 * Returns the first element child or NULL if not available
3494
 */
3495
xmlNodePtr
3496
0
xmlFirstElementChild(xmlNodePtr parent) {
3497
0
    xmlNodePtr cur = NULL;
3498
3499
0
    if (parent == NULL)
3500
0
        return(NULL);
3501
0
    switch (parent->type) {
3502
0
        case XML_ELEMENT_NODE:
3503
0
        case XML_ENTITY_NODE:
3504
0
        case XML_DOCUMENT_NODE:
3505
0
        case XML_DOCUMENT_FRAG_NODE:
3506
0
        case XML_HTML_DOCUMENT_NODE:
3507
0
            cur = parent->children;
3508
0
            break;
3509
0
        default:
3510
0
            return(NULL);
3511
0
    }
3512
0
    while (cur != NULL) {
3513
0
        if (cur->type == XML_ELEMENT_NODE)
3514
0
            return(cur);
3515
0
        cur = cur->next;
3516
0
    }
3517
0
    return(NULL);
3518
0
}
3519
3520
/**
3521
 * xmlLastElementChild:
3522
 * @parent: the parent node
3523
 *
3524
 * Finds the last child node of that element which is a Element node
3525
 * Note the handling of entities references is different than in
3526
 * the W3C DOM element traversal spec since we don't have back reference
3527
 * from entities content to entities references.
3528
 *
3529
 * Returns the last element child or NULL if not available
3530
 */
3531
xmlNodePtr
3532
0
xmlLastElementChild(xmlNodePtr parent) {
3533
0
    xmlNodePtr cur = NULL;
3534
3535
0
    if (parent == NULL)
3536
0
        return(NULL);
3537
0
    switch (parent->type) {
3538
0
        case XML_ELEMENT_NODE:
3539
0
        case XML_ENTITY_NODE:
3540
0
        case XML_DOCUMENT_NODE:
3541
0
        case XML_DOCUMENT_FRAG_NODE:
3542
0
        case XML_HTML_DOCUMENT_NODE:
3543
0
            cur = parent->last;
3544
0
            break;
3545
0
        default:
3546
0
            return(NULL);
3547
0
    }
3548
0
    while (cur != NULL) {
3549
0
        if (cur->type == XML_ELEMENT_NODE)
3550
0
            return(cur);
3551
0
        cur = cur->prev;
3552
0
    }
3553
0
    return(NULL);
3554
0
}
3555
3556
/**
3557
 * xmlPreviousElementSibling:
3558
 * @node: the current node
3559
 *
3560
 * Finds the first closest previous sibling of the node which is an
3561
 * element node.
3562
 * Note the handling of entities references is different than in
3563
 * the W3C DOM element traversal spec since we don't have back reference
3564
 * from entities content to entities references.
3565
 *
3566
 * Returns the previous element sibling or NULL if not available
3567
 */
3568
xmlNodePtr
3569
0
xmlPreviousElementSibling(xmlNodePtr node) {
3570
0
    if (node == NULL)
3571
0
        return(NULL);
3572
0
    switch (node->type) {
3573
0
        case XML_ELEMENT_NODE:
3574
0
        case XML_TEXT_NODE:
3575
0
        case XML_CDATA_SECTION_NODE:
3576
0
        case XML_ENTITY_REF_NODE:
3577
0
        case XML_ENTITY_NODE:
3578
0
        case XML_PI_NODE:
3579
0
        case XML_COMMENT_NODE:
3580
0
        case XML_XINCLUDE_START:
3581
0
        case XML_XINCLUDE_END:
3582
0
            node = node->prev;
3583
0
            break;
3584
0
        default:
3585
0
            return(NULL);
3586
0
    }
3587
0
    while (node != NULL) {
3588
0
        if (node->type == XML_ELEMENT_NODE)
3589
0
            return(node);
3590
0
        node = node->prev;
3591
0
    }
3592
0
    return(NULL);
3593
0
}
3594
3595
/**
3596
 * xmlNextElementSibling:
3597
 * @node: the current node
3598
 *
3599
 * Finds the first closest next sibling of the node which is an
3600
 * element node.
3601
 * Note the handling of entities references is different than in
3602
 * the W3C DOM element traversal spec since we don't have back reference
3603
 * from entities content to entities references.
3604
 *
3605
 * Returns the next element sibling or NULL if not available
3606
 */
3607
xmlNodePtr
3608
0
xmlNextElementSibling(xmlNodePtr node) {
3609
0
    if (node == NULL)
3610
0
        return(NULL);
3611
0
    switch (node->type) {
3612
0
        case XML_ELEMENT_NODE:
3613
0
        case XML_TEXT_NODE:
3614
0
        case XML_CDATA_SECTION_NODE:
3615
0
        case XML_ENTITY_REF_NODE:
3616
0
        case XML_ENTITY_NODE:
3617
0
        case XML_PI_NODE:
3618
0
        case XML_COMMENT_NODE:
3619
0
        case XML_DTD_NODE:
3620
0
        case XML_XINCLUDE_START:
3621
0
        case XML_XINCLUDE_END:
3622
0
            node = node->next;
3623
0
            break;
3624
0
        default:
3625
0
            return(NULL);
3626
0
    }
3627
0
    while (node != NULL) {
3628
0
        if (node->type == XML_ELEMENT_NODE)
3629
0
            return(node);
3630
0
        node = node->next;
3631
0
    }
3632
0
    return(NULL);
3633
0
}
3634
3635
#endif /* LIBXML_TREE_ENABLED */
3636
3637
/**
3638
 * xmlFreeNodeList:
3639
 * @cur:  the first node in the list
3640
 *
3641
 * Free a node and all its siblings, this is a recursive behaviour, all
3642
 * the children are freed too.
3643
 */
3644
void
3645
2.61M
xmlFreeNodeList(xmlNodePtr cur) {
3646
2.61M
    xmlNodePtr next;
3647
2.61M
    xmlNodePtr parent;
3648
2.61M
    xmlDictPtr dict = NULL;
3649
2.61M
    size_t depth = 0;
3650
3651
2.61M
    if (cur == NULL) return;
3652
2.61M
    if (cur->type == XML_NAMESPACE_DECL) {
3653
0
  xmlFreeNsList((xmlNsPtr) cur);
3654
0
  return;
3655
0
    }
3656
2.61M
    if (cur->doc != NULL) dict = cur->doc->dict;
3657
15.6M
    while (1) {
3658
18.0M
        while ((cur->children != NULL) &&
3659
18.0M
               (cur->type != XML_DOCUMENT_NODE) &&
3660
18.0M
               (cur->type != XML_HTML_DOCUMENT_NODE) &&
3661
18.0M
               (cur->type != XML_DTD_NODE) &&
3662
18.0M
               (cur->type != XML_ENTITY_REF_NODE)) {
3663
2.33M
            cur = cur->children;
3664
2.33M
            depth += 1;
3665
2.33M
        }
3666
3667
15.6M
        next = cur->next;
3668
15.6M
        parent = cur->parent;
3669
15.6M
  if ((cur->type == XML_DOCUMENT_NODE) ||
3670
15.6M
            (cur->type == XML_HTML_DOCUMENT_NODE)) {
3671
0
            xmlFreeDoc((xmlDocPtr) cur);
3672
15.6M
        } else if (cur->type != XML_DTD_NODE) {
3673
3674
15.6M
      if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3675
0
    xmlDeregisterNodeDefaultValue(cur);
3676
3677
15.6M
      if (((cur->type == XML_ELEMENT_NODE) ||
3678
15.6M
     (cur->type == XML_XINCLUDE_START) ||
3679
15.6M
     (cur->type == XML_XINCLUDE_END)) &&
3680
15.6M
    (cur->properties != NULL))
3681
1.94M
    xmlFreePropList(cur->properties);
3682
15.6M
      if ((cur->type != XML_ELEMENT_NODE) &&
3683
15.6M
    (cur->type != XML_XINCLUDE_START) &&
3684
15.6M
    (cur->type != XML_XINCLUDE_END) &&
3685
15.6M
    (cur->type != XML_ENTITY_REF_NODE) &&
3686
15.6M
    (cur->content != (xmlChar *) &(cur->properties))) {
3687
6.75M
    DICT_FREE(cur->content)
3688
6.75M
      }
3689
15.6M
      if (((cur->type == XML_ELEMENT_NODE) ||
3690
15.6M
           (cur->type == XML_XINCLUDE_START) ||
3691
15.6M
     (cur->type == XML_XINCLUDE_END)) &&
3692
15.6M
    (cur->nsDef != NULL))
3693
1.18M
    xmlFreeNsList(cur->nsDef);
3694
3695
      /*
3696
       * When a node is a text node or a comment, it uses a global static
3697
       * variable for the name of the node.
3698
       * Otherwise the node name might come from the document's
3699
       * dictionary
3700
       */
3701
15.6M
      if ((cur->name != NULL) &&
3702
15.6M
    (cur->type != XML_TEXT_NODE) &&
3703
15.6M
    (cur->type != XML_COMMENT_NODE))
3704
8.97M
    DICT_FREE(cur->name)
3705
15.6M
      xmlFree(cur);
3706
15.6M
  }
3707
3708
15.6M
        if (next != NULL) {
3709
10.7M
      cur = next;
3710
10.7M
        } else {
3711
4.94M
            if ((depth == 0) || (parent == NULL))
3712
2.61M
                break;
3713
2.33M
            depth -= 1;
3714
2.33M
            cur = parent;
3715
2.33M
            cur->children = NULL;
3716
2.33M
        }
3717
15.6M
    }
3718
2.61M
}
3719
3720
/**
3721
 * xmlFreeNode:
3722
 * @cur:  the node
3723
 *
3724
 * Free a node, this is a recursive behaviour, all the children are freed too.
3725
 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
3726
 */
3727
void
3728
314k
xmlFreeNode(xmlNodePtr cur) {
3729
314k
    xmlDictPtr dict = NULL;
3730
3731
314k
    if (cur == NULL) return;
3732
3733
    /* use xmlFreeDtd for DTD nodes */
3734
314k
    if (cur->type == XML_DTD_NODE) {
3735
0
  xmlFreeDtd((xmlDtdPtr) cur);
3736
0
  return;
3737
0
    }
3738
314k
    if (cur->type == XML_NAMESPACE_DECL) {
3739
0
  xmlFreeNs((xmlNsPtr) cur);
3740
0
        return;
3741
0
    }
3742
314k
    if (cur->type == XML_ATTRIBUTE_NODE) {
3743
0
  xmlFreeProp((xmlAttrPtr) cur);
3744
0
  return;
3745
0
    }
3746
3747
314k
    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3748
0
  xmlDeregisterNodeDefaultValue(cur);
3749
3750
314k
    if (cur->doc != NULL) dict = cur->doc->dict;
3751
3752
314k
    if (cur->type == XML_ENTITY_DECL) {
3753
0
        xmlEntityPtr ent = (xmlEntityPtr) cur;
3754
0
  DICT_FREE(ent->SystemID);
3755
0
  DICT_FREE(ent->ExternalID);
3756
0
    }
3757
314k
    if ((cur->children != NULL) &&
3758
314k
  (cur->type != XML_ENTITY_REF_NODE))
3759
5.80k
  xmlFreeNodeList(cur->children);
3760
3761
314k
    if ((cur->type == XML_ELEMENT_NODE) ||
3762
314k
        (cur->type == XML_XINCLUDE_START) ||
3763
314k
        (cur->type == XML_XINCLUDE_END)) {
3764
25.3k
        if (cur->properties != NULL)
3765
1.90k
            xmlFreePropList(cur->properties);
3766
25.3k
        if (cur->nsDef != NULL)
3767
126
            xmlFreeNsList(cur->nsDef);
3768
288k
    } else if ((cur->content != NULL) &&
3769
288k
               (cur->type != XML_ENTITY_REF_NODE) &&
3770
288k
               (cur->content != (xmlChar *) &(cur->properties))) {
3771
273k
        DICT_FREE(cur->content)
3772
273k
    }
3773
3774
    /*
3775
     * When a node is a text node or a comment, it uses a global static
3776
     * variable for the name of the node.
3777
     * Otherwise the node name might come from the document's dictionary
3778
     */
3779
314k
    if ((cur->name != NULL) &&
3780
314k
        (cur->type != XML_TEXT_NODE) &&
3781
314k
        (cur->type != XML_COMMENT_NODE))
3782
49.2k
  DICT_FREE(cur->name)
3783
3784
314k
    xmlFree(cur);
3785
314k
}
3786
3787
/**
3788
 * xmlUnlinkNode:
3789
 * @cur:  the node
3790
 *
3791
 * Unlink a node from it's current context, the node is not freed
3792
 * If one need to free the node, use xmlFreeNode() routine after the
3793
 * unlink to discard it.
3794
 * Note that namespace nodes can't be unlinked as they do not have
3795
 * pointer to their parent.
3796
 */
3797
void
3798
427k
xmlUnlinkNode(xmlNodePtr cur) {
3799
427k
    if (cur == NULL) {
3800
0
  return;
3801
0
    }
3802
427k
    if (cur->type == XML_NAMESPACE_DECL)
3803
0
        return;
3804
427k
    if (cur->type == XML_DTD_NODE) {
3805
36.1k
  xmlDocPtr doc;
3806
36.1k
  doc = cur->doc;
3807
36.1k
  if (doc != NULL) {
3808
36.1k
      if (doc->intSubset == (xmlDtdPtr) cur)
3809
32.4k
    doc->intSubset = NULL;
3810
36.1k
      if (doc->extSubset == (xmlDtdPtr) cur)
3811
7.70k
    doc->extSubset = NULL;
3812
36.1k
  }
3813
36.1k
    }
3814
427k
    if (cur->type == XML_ENTITY_DECL) {
3815
0
        xmlDocPtr doc;
3816
0
  doc = cur->doc;
3817
0
  if (doc != NULL) {
3818
0
      if (doc->intSubset != NULL) {
3819
0
          if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur)
3820
0
        xmlHashRemoveEntry(doc->intSubset->entities, cur->name,
3821
0
                           NULL);
3822
0
          if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur)
3823
0
        xmlHashRemoveEntry(doc->intSubset->pentities, cur->name,
3824
0
                           NULL);
3825
0
      }
3826
0
      if (doc->extSubset != NULL) {
3827
0
          if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur)
3828
0
        xmlHashRemoveEntry(doc->extSubset->entities, cur->name,
3829
0
                           NULL);
3830
0
          if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur)
3831
0
        xmlHashRemoveEntry(doc->extSubset->pentities, cur->name,
3832
0
                           NULL);
3833
0
      }
3834
0
  }
3835
0
    }
3836
427k
    if (cur->parent != NULL) {
3837
363k
  xmlNodePtr parent;
3838
363k
  parent = cur->parent;
3839
363k
  if (cur->type == XML_ATTRIBUTE_NODE) {
3840
0
      if (parent->properties == (xmlAttrPtr) cur)
3841
0
    parent->properties = ((xmlAttrPtr) cur)->next;
3842
363k
  } else {
3843
363k
      if (parent->children == cur)
3844
126k
    parent->children = cur->next;
3845
363k
      if (parent->last == cur)
3846
111k
    parent->last = cur->prev;
3847
363k
  }
3848
363k
  cur->parent = NULL;
3849
363k
    }
3850
427k
    if (cur->next != NULL)
3851
252k
        cur->next->prev = cur->prev;
3852
427k
    if (cur->prev != NULL)
3853
236k
        cur->prev->next = cur->next;
3854
427k
    cur->next = cur->prev = NULL;
3855
427k
}
3856
3857
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
3858
/**
3859
 * xmlReplaceNode:
3860
 * @old:  the old node
3861
 * @cur:  the node
3862
 *
3863
 * Unlink the old node from its current context, prune the new one
3864
 * at the same place. If @cur was already inserted in a document it is
3865
 * first unlinked from its existing context.
3866
 *
3867
 * See the note regarding namespaces in xmlAddChild.
3868
 *
3869
 * Returns the @old node
3870
 */
3871
xmlNodePtr
3872
0
xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
3873
0
    if (old == cur) return(NULL);
3874
0
    if ((old == NULL) || (old->type == XML_NAMESPACE_DECL) ||
3875
0
        (old->parent == NULL)) {
3876
0
  return(NULL);
3877
0
    }
3878
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3879
0
  xmlUnlinkNode(old);
3880
0
  return(old);
3881
0
    }
3882
0
    if (cur == old) {
3883
0
  return(old);
3884
0
    }
3885
0
    if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) {
3886
0
  return(old);
3887
0
    }
3888
0
    if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) {
3889
0
  return(old);
3890
0
    }
3891
0
    xmlUnlinkNode(cur);
3892
0
    xmlSetTreeDoc(cur, old->doc);
3893
0
    cur->parent = old->parent;
3894
0
    cur->next = old->next;
3895
0
    if (cur->next != NULL)
3896
0
  cur->next->prev = cur;
3897
0
    cur->prev = old->prev;
3898
0
    if (cur->prev != NULL)
3899
0
  cur->prev->next = cur;
3900
0
    if (cur->parent != NULL) {
3901
0
  if (cur->type == XML_ATTRIBUTE_NODE) {
3902
0
      if (cur->parent->properties == (xmlAttrPtr)old)
3903
0
    cur->parent->properties = ((xmlAttrPtr) cur);
3904
0
  } else {
3905
0
      if (cur->parent->children == old)
3906
0
    cur->parent->children = cur;
3907
0
      if (cur->parent->last == old)
3908
0
    cur->parent->last = cur;
3909
0
  }
3910
0
    }
3911
0
    old->next = old->prev = NULL;
3912
0
    old->parent = NULL;
3913
0
    return(old);
3914
0
}
3915
#endif /* LIBXML_TREE_ENABLED */
3916
3917
/************************************************************************
3918
 *                  *
3919
 *    Copy operations           *
3920
 *                  *
3921
 ************************************************************************/
3922
3923
/**
3924
 * xmlCopyNamespace:
3925
 * @cur:  the namespace
3926
 *
3927
 * Do a copy of the namespace.
3928
 *
3929
 * Returns: a new #xmlNsPtr, or NULL in case of error.
3930
 */
3931
xmlNsPtr
3932
209
xmlCopyNamespace(xmlNsPtr cur) {
3933
209
    xmlNsPtr ret;
3934
3935
209
    if (cur == NULL) return(NULL);
3936
209
    switch (cur->type) {
3937
209
  case XML_LOCAL_NAMESPACE:
3938
209
      ret = xmlNewNs(NULL, cur->href, cur->prefix);
3939
209
      break;
3940
0
  default:
3941
0
      return(NULL);
3942
209
    }
3943
209
    return(ret);
3944
209
}
3945
3946
/**
3947
 * xmlCopyNamespaceList:
3948
 * @cur:  the first namespace
3949
 *
3950
 * Do a copy of an namespace list.
3951
 *
3952
 * Returns: a new #xmlNsPtr, or NULL in case of error.
3953
 */
3954
xmlNsPtr
3955
142
xmlCopyNamespaceList(xmlNsPtr cur) {
3956
142
    xmlNsPtr ret = NULL;
3957
142
    xmlNsPtr p = NULL,q;
3958
3959
349
    while (cur != NULL) {
3960
209
        q = xmlCopyNamespace(cur);
3961
209
        if (q == NULL) {
3962
2
            xmlFreeNsList(ret);
3963
2
            return(NULL);
3964
2
        }
3965
207
  if (p == NULL) {
3966
140
      ret = p = q;
3967
140
  } else {
3968
67
      p->next = q;
3969
67
      p = q;
3970
67
  }
3971
207
  cur = cur->next;
3972
207
    }
3973
140
    return(ret);
3974
142
}
3975
3976
static xmlAttrPtr
3977
1.34k
xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
3978
1.34k
    xmlAttrPtr ret = NULL;
3979
3980
1.34k
    if (cur == NULL) return(NULL);
3981
1.34k
    if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
3982
0
        return(NULL);
3983
1.34k
    if (target != NULL)
3984
1.34k
  ret = xmlNewDocProp(target->doc, cur->name, NULL);
3985
0
    else if (doc != NULL)
3986
0
  ret = xmlNewDocProp(doc, cur->name, NULL);
3987
0
    else if (cur->parent != NULL)
3988
0
  ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
3989
0
    else if (cur->children != NULL)
3990
0
  ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
3991
0
    else
3992
0
  ret = xmlNewDocProp(NULL, cur->name, NULL);
3993
1.34k
    if (ret == NULL) return(NULL);
3994
1.34k
    ret->parent = target;
3995
3996
1.34k
    if ((cur->ns != NULL) && (target != NULL)) {
3997
189
      xmlNsPtr ns;
3998
3999
189
      ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
4000
189
      if (ns == NULL) {
4001
        /*
4002
         * Humm, we are copying an element whose namespace is defined
4003
         * out of the new tree scope. Search it in the original tree
4004
         * and add it at the top of the new tree
4005
         */
4006
0
        ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
4007
0
        if (ns != NULL) {
4008
0
          xmlNodePtr root = target;
4009
0
          xmlNodePtr pred = NULL;
4010
4011
0
          while (root->parent != NULL) {
4012
0
            pred = root;
4013
0
            root = root->parent;
4014
0
          }
4015
0
          if (root == (xmlNodePtr) target->doc) {
4016
            /* correct possibly cycling above the document elt */
4017
0
            root = pred;
4018
0
          }
4019
0
          ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4020
0
          if (ret->ns == NULL)
4021
0
              goto error;
4022
0
        }
4023
189
      } else {
4024
        /*
4025
         * we have to find something appropriate here since
4026
         * we can't be sure, that the namespace we found is identified
4027
         * by the prefix
4028
         */
4029
189
        if (xmlStrEqual(ns->href, cur->ns->href)) {
4030
          /* this is the nice case */
4031
189
          ret->ns = ns;
4032
189
        } else {
4033
          /*
4034
           * we are in trouble: we need a new reconciled namespace.
4035
           * This is expensive
4036
           */
4037
0
          ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns);
4038
0
          if (ret->ns == NULL)
4039
0
              goto error;
4040
0
        }
4041
189
      }
4042
4043
189
    } else
4044
1.16k
        ret->ns = NULL;
4045
4046
1.34k
    if (cur->children != NULL) {
4047
1.34k
  xmlNodePtr tmp;
4048
4049
1.34k
  ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4050
1.34k
        if (ret->children == NULL)
4051
0
            goto error;
4052
1.34k
  ret->last = NULL;
4053
1.34k
  tmp = ret->children;
4054
2.69k
  while (tmp != NULL) {
4055
      /* tmp->parent = (xmlNodePtr)ret; */
4056
1.34k
      if (tmp->next == NULL)
4057
1.34k
          ret->last = tmp;
4058
1.34k
      tmp = tmp->next;
4059
1.34k
  }
4060
1.34k
    }
4061
    /*
4062
     * Try to handle IDs
4063
     */
4064
1.34k
    if ((target != NULL) && (cur != NULL) &&
4065
1.34k
  (target->doc != NULL) && (cur->doc != NULL) &&
4066
1.34k
  (cur->doc->ids != NULL) &&
4067
1.34k
        (cur->parent != NULL) &&
4068
1.34k
        (cur->children != NULL)) {
4069
0
        int res = xmlIsID(cur->doc, cur->parent, cur);
4070
4071
0
        if (res < 0)
4072
0
            goto error;
4073
0
  if (res != 0) {
4074
0
      xmlChar *id;
4075
4076
0
      id = xmlNodeListGetString(cur->doc, cur->children, 1);
4077
0
      if (id == NULL)
4078
0
                goto error;
4079
0
            res = xmlAddIDSafe(target->doc, id, ret, 0, NULL);
4080
0
      xmlFree(id);
4081
0
            if (res < 0)
4082
0
                goto error;
4083
0
  }
4084
0
    }
4085
1.34k
    return(ret);
4086
4087
0
error:
4088
0
    xmlFreeProp(ret);
4089
0
    return(NULL);
4090
1.34k
}
4091
4092
/**
4093
 * xmlCopyProp:
4094
 * @target:  the element where the attribute will be grafted
4095
 * @cur:  the attribute
4096
 *
4097
 * Do a copy of the attribute.
4098
 *
4099
 * Returns: a new #xmlAttrPtr, or NULL in case of error.
4100
 */
4101
xmlAttrPtr
4102
1.34k
xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
4103
1.34k
  return xmlCopyPropInternal(NULL, target, cur);
4104
1.34k
}
4105
4106
/**
4107
 * xmlCopyPropList:
4108
 * @target:  the element where the attributes will be grafted
4109
 * @cur:  the first attribute
4110
 *
4111
 * Do a copy of an attribute list.
4112
 *
4113
 * Returns: a new #xmlAttrPtr, or NULL in case of error.
4114
 */
4115
xmlAttrPtr
4116
838
xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
4117
838
    xmlAttrPtr ret = NULL;
4118
838
    xmlAttrPtr p = NULL,q;
4119
4120
838
    if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4121
0
        return(NULL);
4122
2.18k
    while (cur != NULL) {
4123
1.34k
        q = xmlCopyProp(target, cur);
4124
1.34k
  if (q == NULL) {
4125
0
            xmlFreePropList(ret);
4126
0
      return(NULL);
4127
0
        }
4128
1.34k
  if (p == NULL) {
4129
838
      ret = p = q;
4130
838
  } else {
4131
511
      p->next = q;
4132
511
      q->prev = p;
4133
511
      p = q;
4134
511
  }
4135
1.34k
  cur = cur->next;
4136
1.34k
    }
4137
838
    return(ret);
4138
838
}
4139
4140
/*
4141
 * NOTE about the CopyNode operations !
4142
 *
4143
 * They are split into external and internal parts for one
4144
 * tricky reason: namespaces. Doing a direct copy of a node
4145
 * say RPM:Copyright without changing the namespace pointer to
4146
 * something else can produce stale links. One way to do it is
4147
 * to keep a reference counter but this doesn't work as soon
4148
 * as one moves the element or the subtree out of the scope of
4149
 * the existing namespace. The actual solution seems to be to add
4150
 * a copy of the namespace at the top of the copied tree if
4151
 * not available in the subtree.
4152
 * Hence two functions, the public front-end call the inner ones
4153
 * The argument "recursive" normally indicates a recursive copy
4154
 * of the node with values 0 (no) and 1 (yes).  For XInclude,
4155
 * however, we allow a value of 2 to indicate copy properties and
4156
 * namespace info, but don't recurse on children.
4157
 */
4158
4159
xmlNodePtr
4160
xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
4161
2.49M
                  int extended) {
4162
2.49M
    xmlNodePtr ret;
4163
4164
2.49M
    if (node == NULL) return(NULL);
4165
2.49M
    switch (node->type) {
4166
2.99k
        case XML_TEXT_NODE:
4167
2.99k
        case XML_CDATA_SECTION_NODE:
4168
2.47M
        case XML_ELEMENT_NODE:
4169
2.47M
        case XML_DOCUMENT_FRAG_NODE:
4170
2.47M
        case XML_ENTITY_REF_NODE:
4171
2.47M
        case XML_ENTITY_NODE:
4172
2.47M
        case XML_PI_NODE:
4173
2.49M
        case XML_COMMENT_NODE:
4174
2.49M
        case XML_XINCLUDE_START:
4175
2.49M
        case XML_XINCLUDE_END:
4176
2.49M
      break;
4177
0
        case XML_ATTRIBUTE_NODE:
4178
0
    return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node));
4179
0
        case XML_NAMESPACE_DECL:
4180
0
      return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node));
4181
4182
0
        case XML_DOCUMENT_NODE:
4183
0
        case XML_HTML_DOCUMENT_NODE:
4184
0
#ifdef LIBXML_TREE_ENABLED
4185
0
      return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
4186
0
#endif /* LIBXML_TREE_ENABLED */
4187
0
        case XML_DOCUMENT_TYPE_NODE:
4188
0
        case XML_NOTATION_NODE:
4189
0
        case XML_DTD_NODE:
4190
0
        case XML_ELEMENT_DECL:
4191
0
        case XML_ATTRIBUTE_DECL:
4192
0
        case XML_ENTITY_DECL:
4193
0
            return(NULL);
4194
2.49M
    }
4195
4196
    /*
4197
     * Allocate a new node and fill the fields.
4198
     */
4199
2.49M
    ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4200
2.49M
    if (ret == NULL)
4201
4.88k
  return(NULL);
4202
2.48M
    memset(ret, 0, sizeof(xmlNode));
4203
2.48M
    ret->type = node->type;
4204
4205
2.48M
    ret->doc = doc;
4206
2.48M
    ret->parent = parent;
4207
2.48M
    if (node->name == xmlStringText)
4208
2.99k
  ret->name = xmlStringText;
4209
2.48M
    else if (node->name == xmlStringTextNoenc)
4210
0
  ret->name = xmlStringTextNoenc;
4211
2.48M
    else if (node->name == xmlStringComment)
4212
20.7k
  ret->name = xmlStringComment;
4213
2.46M
    else if (node->name != NULL) {
4214
2.46M
        if ((doc != NULL) && (doc->dict != NULL))
4215
2.46M
      ret->name = xmlDictLookup(doc->dict, node->name, -1);
4216
0
  else
4217
0
      ret->name = xmlStrdup(node->name);
4218
2.46M
        if (ret->name == NULL)
4219
1
            goto error;
4220
2.46M
    }
4221
2.48M
    if ((node->type != XML_ELEMENT_NODE) &&
4222
2.48M
  (node->content != NULL) &&
4223
2.48M
  (node->type != XML_ENTITY_REF_NODE) &&
4224
2.48M
  (node->type != XML_XINCLUDE_END) &&
4225
2.48M
  (node->type != XML_XINCLUDE_START)) {
4226
23.7k
  ret->content = xmlStrdup(node->content);
4227
23.7k
        if (ret->content == NULL)
4228
0
            goto error;
4229
2.46M
    }else{
4230
2.46M
      if (node->type == XML_ELEMENT_NODE)
4231
2.46M
        ret->line = node->line;
4232
2.46M
    }
4233
2.48M
    if (parent != NULL) {
4234
3.78k
  xmlNodePtr tmp;
4235
4236
  /*
4237
   * this is a tricky part for the node register thing:
4238
   * in case ret does get coalesced in xmlAddChild
4239
   * the deregister-node callback is called; so we register ret now already
4240
   */
4241
3.78k
  if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
4242
0
      xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4243
4244
        /*
4245
         * Note that since ret->parent is already set, xmlAddChild will
4246
         * return early and not actually insert the node. It will only
4247
         * coalesce text nodes and unnecessarily call xmlSetTreeDoc.
4248
         * Assuming that the subtree to be copied always has its text
4249
         * nodes coalesced, the somewhat confusing call to xmlAddChild
4250
         * could be removed.
4251
         */
4252
3.78k
        tmp = xmlAddChild(parent, ret);
4253
  /* node could have coalesced */
4254
3.78k
  if (tmp != ret)
4255
0
      return(tmp);
4256
3.78k
    }
4257
4258
2.48M
    if (!extended)
4259
2.48M
  goto out;
4260
5.78k
    if (((node->type == XML_ELEMENT_NODE) ||
4261
5.78k
         (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL)) {
4262
142
        ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4263
142
        if (ret->nsDef == NULL)
4264
2
            goto error;
4265
142
    }
4266
4267
5.78k
    if ((node->type == XML_ELEMENT_NODE) && (node->ns != NULL)) {
4268
208
        xmlNsPtr ns;
4269
4270
208
  ns = xmlSearchNs(doc, ret, node->ns->prefix);
4271
208
  if (ns == NULL) {
4272
      /*
4273
       * Humm, we are copying an element whose namespace is defined
4274
       * out of the new tree scope. Search it in the original tree
4275
       * and add it at the top of the new tree.
4276
             *
4277
             * TODO: Searching the original tree seems unnecessary. We
4278
             * already have a namespace URI.
4279
       */
4280
0
      ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4281
0
      if (ns != NULL) {
4282
0
          xmlNodePtr root = ret;
4283
4284
0
    while (root->parent != NULL) root = root->parent;
4285
0
    ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4286
0
            } else {
4287
0
                ret->ns = xmlNewReconciledNs(doc, ret, node->ns);
4288
0
      }
4289
0
            if (ret->ns == NULL)
4290
0
                goto error;
4291
208
  } else {
4292
      /*
4293
       * reference the existing namespace definition in our own tree.
4294
       */
4295
208
      ret->ns = ns;
4296
208
  }
4297
208
    }
4298
5.78k
    if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL)) {
4299
838
        ret->properties = xmlCopyPropList(ret, node->properties);
4300
838
        if (ret->properties == NULL)
4301
0
            goto error;
4302
838
    }
4303
5.78k
    if (node->type == XML_ENTITY_REF_NODE) {
4304
0
  if ((doc == NULL) || (node->doc != doc)) {
4305
      /*
4306
       * The copied node will go into a separate document, so
4307
       * to avoid dangling references to the ENTITY_DECL node
4308
       * we cannot keep the reference. Try to find it in the
4309
       * target document.
4310
       */
4311
0
      ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4312
0
  } else {
4313
0
            ret->children = node->children;
4314
0
  }
4315
0
  ret->last = ret->children;
4316
5.78k
    } else if ((node->children != NULL) && (extended != 2)) {
4317
582
        xmlNodePtr cur, insert;
4318
4319
582
        cur = node->children;
4320
582
        insert = ret;
4321
3.02k
        while (cur != NULL) {
4322
2.43k
            xmlNodePtr copy = xmlStaticCopyNode(cur, doc, insert, 2);
4323
2.43k
            if (copy == NULL)
4324
0
                goto error;
4325
4326
            /* Check for coalesced text nodes */
4327
2.43k
            if (insert->last != copy) {
4328
2.43k
                if (insert->last == NULL) {
4329
1.75k
                    insert->children = copy;
4330
1.75k
                } else {
4331
685
                    copy->prev = insert->last;
4332
685
                    insert->last->next = copy;
4333
685
                }
4334
2.43k
                insert->last = copy;
4335
2.43k
            }
4336
4337
2.43k
            if ((cur->type != XML_ENTITY_REF_NODE) &&
4338
2.43k
                (cur->children != NULL)) {
4339
1.17k
                cur = cur->children;
4340
1.17k
                insert = copy;
4341
1.17k
                continue;
4342
1.17k
            }
4343
4344
2.43k
            while (1) {
4345
2.43k
                if (cur->next != NULL) {
4346
685
                    cur = cur->next;
4347
685
                    break;
4348
685
                }
4349
4350
1.75k
                cur = cur->parent;
4351
1.75k
                insert = insert->parent;
4352
1.75k
                if (cur == node) {
4353
582
                    cur = NULL;
4354
582
                    break;
4355
582
                }
4356
1.75k
            }
4357
1.26k
        }
4358
582
    }
4359
4360
2.48M
out:
4361
    /* if parent != NULL we already registered the node above */
4362
2.48M
    if ((parent == NULL) &&
4363
2.48M
        ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
4364
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4365
2.48M
    return(ret);
4366
4367
3
error:
4368
3
    xmlFreeNode(ret);
4369
3
    return(NULL);
4370
5.78k
}
4371
4372
xmlNodePtr
4373
1.34k
xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4374
1.34k
    xmlNodePtr ret = NULL;
4375
1.34k
    xmlNodePtr p = NULL,q;
4376
1.34k
    xmlDtdPtr newSubset = NULL;
4377
1.34k
    int linkedSubset = 0;
4378
4379
2.69k
    while (node != NULL) {
4380
1.34k
#ifdef LIBXML_TREE_ENABLED
4381
1.34k
  if (node->type == XML_DTD_NODE ) {
4382
0
      if (doc == NULL) {
4383
0
    node = node->next;
4384
0
    continue;
4385
0
      }
4386
0
      if ((doc->intSubset == NULL) && (newSubset == NULL)) {
4387
0
    q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
4388
0
    if (q == NULL) goto error;
4389
0
    q->doc = doc;
4390
0
    q->parent = parent;
4391
0
    newSubset = (xmlDtdPtr) q;
4392
0
    xmlAddChild(parent, q);
4393
0
      } else {
4394
0
                linkedSubset = 1;
4395
0
    q = (xmlNodePtr) doc->intSubset;
4396
0
    xmlAddChild(parent, q);
4397
0
      }
4398
0
  } else
4399
1.34k
#endif /* LIBXML_TREE_ENABLED */
4400
1.34k
      q = xmlStaticCopyNode(node, doc, parent, 1);
4401
1.34k
  if (q == NULL) goto error;
4402
1.34k
  if (ret == NULL) {
4403
1.34k
      q->prev = NULL;
4404
1.34k
      ret = p = q;
4405
1.34k
  } else if (p != q) {
4406
  /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
4407
0
      p->next = q;
4408
0
      q->prev = p;
4409
0
      p = q;
4410
0
  }
4411
1.34k
  node = node->next;
4412
1.34k
    }
4413
1.34k
    if ((doc != NULL) && (newSubset != NULL))
4414
0
        doc->intSubset = newSubset;
4415
1.34k
    return(ret);
4416
0
error:
4417
0
    xmlFreeNodeList(ret);
4418
0
    if (linkedSubset != 0) {
4419
0
        doc->intSubset->next = NULL;
4420
0
        doc->intSubset->prev = NULL;
4421
0
    }
4422
0
    return(NULL);
4423
1.34k
}
4424
4425
/**
4426
 * xmlCopyNode:
4427
 * @node:  the node
4428
 * @extended:   if 1 do a recursive copy (properties, namespaces and children
4429
 *      when applicable)
4430
 *    if 2 copy properties and namespaces (when applicable)
4431
 *
4432
 * Do a copy of the node.
4433
 *
4434
 * Returns: a new #xmlNodePtr, or NULL in case of error.
4435
 */
4436
xmlNodePtr
4437
0
xmlCopyNode(xmlNodePtr node, int extended) {
4438
0
    xmlNodePtr ret;
4439
4440
0
    ret = xmlStaticCopyNode(node, NULL, NULL, extended);
4441
0
    return(ret);
4442
0
}
4443
4444
/**
4445
 * xmlDocCopyNode:
4446
 * @node:  the node
4447
 * @doc:  the document
4448
 * @extended:   if 1 do a recursive copy (properties, namespaces and children
4449
 *      when applicable)
4450
 *    if 2 copy properties and namespaces (when applicable)
4451
 *
4452
 * Do a copy of the node to a given document.
4453
 *
4454
 * Returns: a new #xmlNodePtr, or NULL in case of error.
4455
 */
4456
xmlNodePtr
4457
2.48M
xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
4458
2.48M
    xmlNodePtr ret;
4459
4460
2.48M
    ret = xmlStaticCopyNode(node, doc, NULL, extended);
4461
2.48M
    return(ret);
4462
2.48M
}
4463
4464
/**
4465
 * xmlDocCopyNodeList:
4466
 * @doc: the target document
4467
 * @node:  the first node in the list.
4468
 *
4469
 * Do a recursive copy of the node list.
4470
 *
4471
 * Returns: a new #xmlNodePtr, or NULL in case of error.
4472
 */
4473
0
xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) {
4474
0
    xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
4475
0
    return(ret);
4476
0
}
4477
4478
/**
4479
 * xmlCopyNodeList:
4480
 * @node:  the first node in the list.
4481
 *
4482
 * Do a recursive copy of the node list.
4483
 * Use xmlDocCopyNodeList() if possible to ensure string interning.
4484
 *
4485
 * Returns: a new #xmlNodePtr, or NULL in case of error.
4486
 */
4487
0
xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
4488
0
    xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
4489
0
    return(ret);
4490
0
}
4491
4492
#if defined(LIBXML_TREE_ENABLED)
4493
/**
4494
 * xmlCopyDtd:
4495
 * @dtd:  the dtd
4496
 *
4497
 * Do a copy of the dtd.
4498
 *
4499
 * Returns: a new #xmlDtdPtr, or NULL in case of error.
4500
 */
4501
xmlDtdPtr
4502
0
xmlCopyDtd(xmlDtdPtr dtd) {
4503
0
    xmlDtdPtr ret;
4504
0
    xmlNodePtr cur, p = NULL, q;
4505
4506
0
    if (dtd == NULL) return(NULL);
4507
0
    ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4508
0
    if (ret == NULL) return(NULL);
4509
0
    if (dtd->entities != NULL) {
4510
0
        ret->entities = (void *) xmlCopyEntitiesTable(
4511
0
                      (xmlEntitiesTablePtr) dtd->entities);
4512
0
        if (ret->entities == NULL)
4513
0
            goto error;
4514
0
    }
4515
0
    if (dtd->notations != NULL) {
4516
0
        ret->notations = (void *) xmlCopyNotationTable(
4517
0
                      (xmlNotationTablePtr) dtd->notations);
4518
0
        if (ret->notations == NULL)
4519
0
            goto error;
4520
0
    }
4521
0
    if (dtd->elements != NULL) {
4522
0
        ret->elements = (void *) xmlCopyElementTable(
4523
0
                      (xmlElementTablePtr) dtd->elements);
4524
0
        if (ret->elements == NULL)
4525
0
            goto error;
4526
0
    }
4527
0
    if (dtd->attributes != NULL) {
4528
0
        ret->attributes = (void *) xmlCopyAttributeTable(
4529
0
                      (xmlAttributeTablePtr) dtd->attributes);
4530
0
        if (ret->attributes == NULL)
4531
0
            goto error;
4532
0
    }
4533
0
    if (dtd->pentities != NULL) {
4534
0
  ret->pentities = (void *) xmlCopyEntitiesTable(
4535
0
          (xmlEntitiesTablePtr) dtd->pentities);
4536
0
        if (ret->pentities == NULL)
4537
0
            goto error;
4538
0
    }
4539
4540
0
    cur = dtd->children;
4541
0
    while (cur != NULL) {
4542
0
  q = NULL;
4543
4544
0
  if (cur->type == XML_ENTITY_DECL) {
4545
0
      xmlEntityPtr tmp = (xmlEntityPtr) cur;
4546
0
      switch (tmp->etype) {
4547
0
    case XML_INTERNAL_GENERAL_ENTITY:
4548
0
    case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4549
0
    case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4550
0
        q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4551
0
        break;
4552
0
    case XML_INTERNAL_PARAMETER_ENTITY:
4553
0
    case XML_EXTERNAL_PARAMETER_ENTITY:
4554
0
        q = (xmlNodePtr)
4555
0
      xmlGetParameterEntityFromDtd(ret, tmp->name);
4556
0
        break;
4557
0
    case XML_INTERNAL_PREDEFINED_ENTITY:
4558
0
        break;
4559
0
      }
4560
0
  } else if (cur->type == XML_ELEMENT_DECL) {
4561
0
      xmlElementPtr tmp = (xmlElementPtr) cur;
4562
0
      q = (xmlNodePtr)
4563
0
    xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4564
0
  } else if (cur->type == XML_ATTRIBUTE_DECL) {
4565
0
      xmlAttributePtr tmp = (xmlAttributePtr) cur;
4566
0
      q = (xmlNodePtr)
4567
0
    xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4568
0
  } else if (cur->type == XML_COMMENT_NODE) {
4569
0
      q = xmlCopyNode(cur, 0);
4570
0
            if (q == NULL)
4571
0
                goto error;
4572
0
  }
4573
4574
0
  if (q == NULL) {
4575
0
      cur = cur->next;
4576
0
      continue;
4577
0
  }
4578
4579
0
  if (p == NULL)
4580
0
      ret->children = q;
4581
0
  else
4582
0
      p->next = q;
4583
4584
0
  q->prev = p;
4585
0
  q->parent = (xmlNodePtr) ret;
4586
0
  q->next = NULL;
4587
0
  ret->last = q;
4588
0
  p = q;
4589
0
  cur = cur->next;
4590
0
    }
4591
4592
0
    return(ret);
4593
4594
0
error:
4595
0
    xmlFreeDtd(ret);
4596
0
    return(NULL);
4597
0
}
4598
#endif
4599
4600
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
4601
/**
4602
 * xmlCopyDoc:
4603
 * @doc:  the document
4604
 * @recursive:  if not zero do a recursive copy.
4605
 *
4606
 * Do a copy of the document info. If recursive, the content tree will
4607
 * be copied too as well as DTD, namespaces and entities.
4608
 *
4609
 * Returns: a new #xmlDocPtr, or NULL in case of error.
4610
 */
4611
xmlDocPtr
4612
0
xmlCopyDoc(xmlDocPtr doc, int recursive) {
4613
0
    xmlDocPtr ret;
4614
4615
0
    if (doc == NULL) return(NULL);
4616
0
    ret = xmlNewDoc(doc->version);
4617
0
    if (ret == NULL) return(NULL);
4618
0
    ret->type = doc->type;
4619
0
    if (doc->name != NULL) {
4620
0
        ret->name = xmlMemStrdup(doc->name);
4621
0
        if (ret->name == NULL)
4622
0
            goto error;
4623
0
    }
4624
0
    if (doc->encoding != NULL) {
4625
0
        ret->encoding = xmlStrdup(doc->encoding);
4626
0
        if (ret->encoding == NULL)
4627
0
            goto error;
4628
0
    }
4629
0
    if (doc->URL != NULL) {
4630
0
        ret->URL = xmlStrdup(doc->URL);
4631
0
        if (ret->URL == NULL)
4632
0
            goto error;
4633
0
    }
4634
0
    ret->charset = doc->charset;
4635
0
    ret->compression = doc->compression;
4636
0
    ret->standalone = doc->standalone;
4637
0
    if (!recursive) return(ret);
4638
4639
0
    ret->last = NULL;
4640
0
    ret->children = NULL;
4641
0
#ifdef LIBXML_TREE_ENABLED
4642
0
    if (doc->intSubset != NULL) {
4643
0
        ret->intSubset = xmlCopyDtd(doc->intSubset);
4644
0
  if (ret->intSubset == NULL)
4645
0
            goto error;
4646
0
  xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
4647
0
  ret->intSubset->parent = ret;
4648
0
    }
4649
0
#endif
4650
0
    if (doc->oldNs != NULL) {
4651
0
        ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4652
0
        if (ret->oldNs == NULL)
4653
0
            goto error;
4654
0
    }
4655
0
    if (doc->children != NULL) {
4656
0
  xmlNodePtr tmp;
4657
4658
0
  ret->children = xmlStaticCopyNodeList(doc->children, ret,
4659
0
                                   (xmlNodePtr)ret);
4660
0
        if (ret->children == NULL)
4661
0
            goto error;
4662
0
  ret->last = NULL;
4663
0
  tmp = ret->children;
4664
0
  while (tmp != NULL) {
4665
0
      if (tmp->next == NULL)
4666
0
          ret->last = tmp;
4667
0
      tmp = tmp->next;
4668
0
  }
4669
0
    }
4670
0
    return(ret);
4671
4672
0
error:
4673
0
    xmlFreeDoc(ret);
4674
0
    return(NULL);
4675
0
}
4676
#endif /* LIBXML_TREE_ENABLED */
4677
4678
/************************************************************************
4679
 *                  *
4680
 *    Content access functions        *
4681
 *                  *
4682
 ************************************************************************/
4683
4684
/**
4685
 * xmlGetLineNoInternal:
4686
 * @node: valid node
4687
 * @depth: used to limit any risk of recursion
4688
 *
4689
 * Get line number of @node.
4690
 * Try to override the limitation of lines being store in 16 bits ints
4691
 *
4692
 * Returns the line number if successful, -1 otherwise
4693
 */
4694
static long
4695
xmlGetLineNoInternal(const xmlNode *node, int depth)
4696
3.82M
{
4697
3.82M
    long result = -1;
4698
4699
3.82M
    if (depth >= 5)
4700
113k
        return(-1);
4701
4702
3.70M
    if (!node)
4703
0
        return result;
4704
3.70M
    if ((node->type == XML_ELEMENT_NODE) ||
4705
3.70M
        (node->type == XML_TEXT_NODE) ||
4706
3.70M
  (node->type == XML_COMMENT_NODE) ||
4707
3.70M
  (node->type == XML_PI_NODE)) {
4708
3.67M
  if (node->line == 65535) {
4709
608k
      if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL))
4710
0
          result = (long) (ptrdiff_t) node->psvi;
4711
608k
      else if ((node->type == XML_ELEMENT_NODE) &&
4712
608k
               (node->children != NULL))
4713
14.3k
          result = xmlGetLineNoInternal(node->children, depth + 1);
4714
594k
      else if (node->next != NULL)
4715
581k
          result = xmlGetLineNoInternal(node->next, depth + 1);
4716
12.6k
      else if (node->prev != NULL)
4717
2.56k
          result = xmlGetLineNoInternal(node->prev, depth + 1);
4718
608k
  }
4719
3.67M
  if ((result == -1) || (result == 65535))
4720
3.67M
      result = (long) node->line;
4721
3.67M
    } else if ((node->prev != NULL) &&
4722
38.3k
             ((node->prev->type == XML_ELEMENT_NODE) ||
4723
37.5k
        (node->prev->type == XML_TEXT_NODE) ||
4724
37.5k
        (node->prev->type == XML_COMMENT_NODE) ||
4725
37.5k
        (node->prev->type == XML_PI_NODE)))
4726
37.0k
        result = xmlGetLineNoInternal(node->prev, depth + 1);
4727
1.36k
    else if ((node->parent != NULL) &&
4728
1.36k
             (node->parent->type == XML_ELEMENT_NODE))
4729
782
        result = xmlGetLineNoInternal(node->parent, depth + 1);
4730
4731
3.70M
    return result;
4732
3.70M
}
4733
4734
/**
4735
 * xmlGetLineNo:
4736
 * @node: valid node
4737
 *
4738
 * Get line number of @node.
4739
 * Try to override the limitation of lines being store in 16 bits ints
4740
 * if XML_PARSE_BIG_LINES parser option was used
4741
 *
4742
 * Returns the line number if successful, -1 otherwise
4743
 */
4744
long
4745
xmlGetLineNo(const xmlNode *node)
4746
3.18M
{
4747
3.18M
    return(xmlGetLineNoInternal(node, 0));
4748
3.18M
}
4749
4750
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED)
4751
/**
4752
 * xmlGetNodePath:
4753
 * @node: a node
4754
 *
4755
 * Build a structure based Path for the given node
4756
 *
4757
 * Returns the new path or NULL in case of error. The caller must free
4758
 *     the returned string
4759
 */
4760
xmlChar *
4761
xmlGetNodePath(const xmlNode *node)
4762
0
{
4763
0
    const xmlNode *cur, *tmp, *next;
4764
0
    xmlChar *buffer = NULL, *temp;
4765
0
    size_t buf_len;
4766
0
    xmlChar *buf;
4767
0
    const char *sep;
4768
0
    const char *name;
4769
0
    char nametemp[100];
4770
0
    int occur = 0, generic;
4771
4772
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
4773
0
        return (NULL);
4774
4775
0
    buf_len = 500;
4776
0
    buffer = (xmlChar *) xmlMallocAtomic(buf_len);
4777
0
    if (buffer == NULL)
4778
0
        return (NULL);
4779
0
    buf = (xmlChar *) xmlMallocAtomic(buf_len);
4780
0
    if (buf == NULL) {
4781
0
        xmlFree(buffer);
4782
0
        return (NULL);
4783
0
    }
4784
4785
0
    buffer[0] = 0;
4786
0
    cur = node;
4787
0
    do {
4788
0
        name = "";
4789
0
        sep = "?";
4790
0
        occur = 0;
4791
0
        if ((cur->type == XML_DOCUMENT_NODE) ||
4792
0
            (cur->type == XML_HTML_DOCUMENT_NODE)) {
4793
0
            if (buffer[0] == '/')
4794
0
                break;
4795
0
            sep = "/";
4796
0
            next = NULL;
4797
0
        } else if (cur->type == XML_ELEMENT_NODE) {
4798
0
      generic = 0;
4799
0
            sep = "/";
4800
0
            name = (const char *) cur->name;
4801
0
            if (cur->ns) {
4802
0
    if (cur->ns->prefix != NULL) {
4803
0
                    snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4804
0
      (char *)cur->ns->prefix, (char *)cur->name);
4805
0
        nametemp[sizeof(nametemp) - 1] = 0;
4806
0
        name = nametemp;
4807
0
    } else {
4808
        /*
4809
        * We cannot express named elements in the default
4810
        * namespace, so use "*".
4811
        */
4812
0
        generic = 1;
4813
0
        name = "*";
4814
0
    }
4815
0
            }
4816
0
            next = cur->parent;
4817
4818
            /*
4819
             * Thumbler index computation
4820
       * TODO: the occurrence test seems bogus for namespaced names
4821
             */
4822
0
            tmp = cur->prev;
4823
0
            while (tmp != NULL) {
4824
0
                if ((tmp->type == XML_ELEMENT_NODE) &&
4825
0
        (generic ||
4826
0
         (xmlStrEqual(cur->name, tmp->name) &&
4827
0
         ((tmp->ns == cur->ns) ||
4828
0
          ((tmp->ns != NULL) && (cur->ns != NULL) &&
4829
0
           (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4830
0
                    occur++;
4831
0
                tmp = tmp->prev;
4832
0
            }
4833
0
            if (occur == 0) {
4834
0
                tmp = cur->next;
4835
0
                while (tmp != NULL && occur == 0) {
4836
0
                    if ((tmp->type == XML_ELEMENT_NODE) &&
4837
0
      (generic ||
4838
0
       (xmlStrEqual(cur->name, tmp->name) &&
4839
0
       ((tmp->ns == cur->ns) ||
4840
0
        ((tmp->ns != NULL) && (cur->ns != NULL) &&
4841
0
         (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix)))))))
4842
0
                        occur++;
4843
0
                    tmp = tmp->next;
4844
0
                }
4845
0
                if (occur != 0)
4846
0
                    occur = 1;
4847
0
            } else
4848
0
                occur++;
4849
0
        } else if (cur->type == XML_COMMENT_NODE) {
4850
0
            sep = "/";
4851
0
      name = "comment()";
4852
0
            next = cur->parent;
4853
4854
            /*
4855
             * Thumbler index computation
4856
             */
4857
0
            tmp = cur->prev;
4858
0
            while (tmp != NULL) {
4859
0
                if (tmp->type == XML_COMMENT_NODE)
4860
0
        occur++;
4861
0
                tmp = tmp->prev;
4862
0
            }
4863
0
            if (occur == 0) {
4864
0
                tmp = cur->next;
4865
0
                while (tmp != NULL && occur == 0) {
4866
0
        if (tmp->type == XML_COMMENT_NODE)
4867
0
            occur++;
4868
0
                    tmp = tmp->next;
4869
0
                }
4870
0
                if (occur != 0)
4871
0
                    occur = 1;
4872
0
            } else
4873
0
                occur++;
4874
0
        } else if ((cur->type == XML_TEXT_NODE) ||
4875
0
                   (cur->type == XML_CDATA_SECTION_NODE)) {
4876
0
            sep = "/";
4877
0
      name = "text()";
4878
0
            next = cur->parent;
4879
4880
            /*
4881
             * Thumbler index computation
4882
             */
4883
0
            tmp = cur->prev;
4884
0
            while (tmp != NULL) {
4885
0
                if ((tmp->type == XML_TEXT_NODE) ||
4886
0
        (tmp->type == XML_CDATA_SECTION_NODE))
4887
0
        occur++;
4888
0
                tmp = tmp->prev;
4889
0
            }
4890
      /*
4891
      * Evaluate if this is the only text- or CDATA-section-node;
4892
      * if yes, then we'll get "text()", otherwise "text()[1]".
4893
      */
4894
0
            if (occur == 0) {
4895
0
                tmp = cur->next;
4896
0
                while (tmp != NULL) {
4897
0
        if ((tmp->type == XML_TEXT_NODE) ||
4898
0
      (tmp->type == XML_CDATA_SECTION_NODE))
4899
0
        {
4900
0
      occur = 1;
4901
0
      break;
4902
0
        }
4903
0
        tmp = tmp->next;
4904
0
    }
4905
0
            } else
4906
0
                occur++;
4907
0
        } else if (cur->type == XML_PI_NODE) {
4908
0
            sep = "/";
4909
0
      snprintf(nametemp, sizeof(nametemp) - 1,
4910
0
         "processing-instruction('%s')", (char *)cur->name);
4911
0
            nametemp[sizeof(nametemp) - 1] = 0;
4912
0
            name = nametemp;
4913
4914
0
      next = cur->parent;
4915
4916
            /*
4917
             * Thumbler index computation
4918
             */
4919
0
            tmp = cur->prev;
4920
0
            while (tmp != NULL) {
4921
0
                if ((tmp->type == XML_PI_NODE) &&
4922
0
        (xmlStrEqual(cur->name, tmp->name)))
4923
0
                    occur++;
4924
0
                tmp = tmp->prev;
4925
0
            }
4926
0
            if (occur == 0) {
4927
0
                tmp = cur->next;
4928
0
                while (tmp != NULL && occur == 0) {
4929
0
                    if ((tmp->type == XML_PI_NODE) &&
4930
0
      (xmlStrEqual(cur->name, tmp->name)))
4931
0
                        occur++;
4932
0
                    tmp = tmp->next;
4933
0
                }
4934
0
                if (occur != 0)
4935
0
                    occur = 1;
4936
0
            } else
4937
0
                occur++;
4938
4939
0
        } else if (cur->type == XML_ATTRIBUTE_NODE) {
4940
0
            sep = "/@";
4941
0
            name = (const char *) (((xmlAttrPtr) cur)->name);
4942
0
            if (cur->ns) {
4943
0
          if (cur->ns->prefix != NULL)
4944
0
                    snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s",
4945
0
      (char *)cur->ns->prefix, (char *)cur->name);
4946
0
    else
4947
0
        snprintf(nametemp, sizeof(nametemp) - 1, "%s",
4948
0
      (char *)cur->name);
4949
0
                nametemp[sizeof(nametemp) - 1] = 0;
4950
0
                name = nametemp;
4951
0
            }
4952
0
            next = ((xmlAttrPtr) cur)->parent;
4953
0
        } else {
4954
0
            xmlFree(buf);
4955
0
            xmlFree(buffer);
4956
0
            return (NULL);
4957
0
        }
4958
4959
        /*
4960
         * Make sure there is enough room
4961
         */
4962
0
        if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) {
4963
0
            buf_len =
4964
0
                2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20;
4965
0
            temp = (xmlChar *) xmlRealloc(buffer, buf_len);
4966
0
            if (temp == NULL) {
4967
0
                xmlFree(buf);
4968
0
                xmlFree(buffer);
4969
0
                return (NULL);
4970
0
            }
4971
0
            buffer = temp;
4972
0
            temp = (xmlChar *) xmlRealloc(buf, buf_len);
4973
0
            if (temp == NULL) {
4974
0
                xmlFree(buf);
4975
0
                xmlFree(buffer);
4976
0
                return (NULL);
4977
0
            }
4978
0
            buf = temp;
4979
0
        }
4980
0
        if (occur == 0)
4981
0
            snprintf((char *) buf, buf_len, "%s%s%s",
4982
0
                     sep, name, (char *) buffer);
4983
0
        else
4984
0
            snprintf((char *) buf, buf_len, "%s%s[%d]%s",
4985
0
                     sep, name, occur, (char *) buffer);
4986
0
        snprintf((char *) buffer, buf_len, "%s", (char *)buf);
4987
0
        cur = next;
4988
0
    } while (cur != NULL);
4989
0
    xmlFree(buf);
4990
0
    return (buffer);
4991
0
}
4992
#endif /* LIBXML_TREE_ENABLED */
4993
4994
/**
4995
 * xmlDocGetRootElement:
4996
 * @doc:  the document
4997
 *
4998
 * Get the root element of the document (doc->children is a list
4999
 * containing possibly comments, PIs, etc ...).
5000
 *
5001
 * Returns the #xmlNodePtr for the root or NULL
5002
 */
5003
xmlNodePtr
5004
456k
xmlDocGetRootElement(const xmlDoc *doc) {
5005
456k
    xmlNodePtr ret;
5006
5007
456k
    if (doc == NULL) return(NULL);
5008
431k
    ret = doc->children;
5009
483k
    while (ret != NULL) {
5010
467k
  if (ret->type == XML_ELEMENT_NODE)
5011
415k
      return(ret);
5012
51.9k
        ret = ret->next;
5013
51.9k
    }
5014
15.6k
    return(ret);
5015
431k
}
5016
5017
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED)
5018
/**
5019
 * xmlDocSetRootElement:
5020
 * @doc:  the document
5021
 * @root:  the new document root element, if root is NULL no action is taken,
5022
 *         to remove a node from a document use xmlUnlinkNode(root) instead.
5023
 *
5024
 * Set the root element of the document (doc->children is a list
5025
 * containing possibly comments, PIs, etc ...).
5026
 *
5027
 * Returns the old root element if any was found, NULL if root was NULL
5028
 */
5029
xmlNodePtr
5030
0
xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
5031
0
    xmlNodePtr old = NULL;
5032
5033
0
    if (doc == NULL) return(NULL);
5034
0
    if ((root == NULL) || (root->type == XML_NAMESPACE_DECL))
5035
0
  return(NULL);
5036
0
    xmlUnlinkNode(root);
5037
0
    xmlSetTreeDoc(root, doc);
5038
0
    root->parent = (xmlNodePtr) doc;
5039
0
    old = doc->children;
5040
0
    while (old != NULL) {
5041
0
  if (old->type == XML_ELEMENT_NODE)
5042
0
      break;
5043
0
        old = old->next;
5044
0
    }
5045
0
    if (old == NULL) {
5046
0
  if (doc->children == NULL) {
5047
0
      doc->children = root;
5048
0
      doc->last = root;
5049
0
  } else {
5050
0
      xmlAddSibling(doc->children, root);
5051
0
  }
5052
0
    } else {
5053
0
  xmlReplaceNode(old, root);
5054
0
    }
5055
0
    return(old);
5056
0
}
5057
#endif
5058
5059
#if defined(LIBXML_TREE_ENABLED)
5060
/**
5061
 * xmlNodeSetLang:
5062
 * @cur:  the node being changed
5063
 * @lang:  the language description
5064
 *
5065
 * Set the language of a node, i.e. the values of the xml:lang
5066
 * attribute.
5067
 */
5068
void
5069
0
xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
5070
0
    xmlNsPtr ns;
5071
5072
0
    if (cur == NULL) return;
5073
0
    switch(cur->type) {
5074
0
        case XML_TEXT_NODE:
5075
0
        case XML_CDATA_SECTION_NODE:
5076
0
        case XML_COMMENT_NODE:
5077
0
        case XML_DOCUMENT_NODE:
5078
0
        case XML_DOCUMENT_TYPE_NODE:
5079
0
        case XML_DOCUMENT_FRAG_NODE:
5080
0
        case XML_NOTATION_NODE:
5081
0
        case XML_HTML_DOCUMENT_NODE:
5082
0
        case XML_DTD_NODE:
5083
0
        case XML_ELEMENT_DECL:
5084
0
        case XML_ATTRIBUTE_DECL:
5085
0
        case XML_ENTITY_DECL:
5086
0
        case XML_PI_NODE:
5087
0
        case XML_ENTITY_REF_NODE:
5088
0
        case XML_ENTITY_NODE:
5089
0
  case XML_NAMESPACE_DECL:
5090
0
  case XML_XINCLUDE_START:
5091
0
  case XML_XINCLUDE_END:
5092
0
      return;
5093
0
        case XML_ELEMENT_NODE:
5094
0
        case XML_ATTRIBUTE_NODE:
5095
0
      break;
5096
0
    }
5097
0
    ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5098
0
    if (ns == NULL)
5099
0
  return;
5100
0
    xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
5101
0
}
5102
#endif /* LIBXML_TREE_ENABLED */
5103
5104
/**
5105
 * xmlNodeGetLang:
5106
 * @cur:  the node being checked
5107
 *
5108
 * Searches the language of a node, i.e. the values of the xml:lang
5109
 * attribute or the one carried by the nearest ancestor.
5110
 *
5111
 * Returns a pointer to the lang value, or NULL if not found
5112
 *     It's up to the caller to free the memory with xmlFree().
5113
 */
5114
xmlChar *
5115
0
xmlNodeGetLang(const xmlNode *cur) {
5116
0
    xmlChar *lang;
5117
5118
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
5119
0
        return(NULL);
5120
0
    while (cur != NULL) {
5121
0
        lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
5122
0
  if (lang != NULL)
5123
0
      return(lang);
5124
0
  cur = cur->parent;
5125
0
    }
5126
0
    return(NULL);
5127
0
}
5128
5129
5130
#ifdef LIBXML_TREE_ENABLED
5131
/**
5132
 * xmlNodeSetSpacePreserve:
5133
 * @cur:  the node being changed
5134
 * @val:  the xml:space value ("0": default, 1: "preserve")
5135
 *
5136
 * Set (or reset) the space preserving behaviour of a node, i.e. the
5137
 * value of the xml:space attribute.
5138
 */
5139