Coverage Report

Created: 2024-02-11 06:24

/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
0
#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) {   \
79
0
    xmlNodePtr ulccur = (n)->children;          \
80
0
    if (ulccur == NULL) {           \
81
0
        (n)->last = NULL;           \
82
0
    } else {               \
83
0
        while (ulccur->next != NULL) {         \
84
0
    ulccur->parent = (n);         \
85
0
    ulccur = ulccur->next;          \
86
0
  }                \
87
0
  ulccur->parent = (n);           \
88
0
  (n)->last = ulccur;           \
89
0
}}
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
3.03k
xmlGetEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
115
3.03k
    xmlEntitiesTablePtr table;
116
117
3.03k
    if((dtd != NULL) && (dtd->entities != NULL)) {
118
3.03k
  table = (xmlEntitiesTablePtr) dtd->entities;
119
3.03k
  return((xmlEntityPtr) xmlHashLookup(table, name));
120
  /* return(xmlGetEntityFromTable(table, name)); */
121
3.03k
    }
122
0
    return(NULL);
123
3.03k
}
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
957
xmlGetParameterEntityFromDtd(const xmlDtd *dtd, const xmlChar *name) {
136
957
    xmlEntitiesTablePtr table;
137
138
957
    if ((dtd != NULL) && (dtd->pentities != NULL)) {
139
957
  table = (xmlEntitiesTablePtr) dtd->pentities;
140
957
  return((xmlEntityPtr) xmlHashLookup(table, name));
141
  /* return(xmlGetEntityFromTable(table, name)); */
142
957
    }
143
0
    return(NULL);
144
957
}
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
618k
        xmlChar *memory, int len) {
170
618k
    int lenn, lenp;
171
618k
    xmlChar *ret;
172
173
618k
    if (ncname == NULL) return(NULL);
174
618k
    if (prefix == NULL) return((xmlChar *) ncname);
175
176
458k
    lenn = strlen((char *) ncname);
177
458k
    lenp = strlen((char *) prefix);
178
179
458k
    if ((memory == NULL) || (len < lenn + lenp + 2)) {
180
114k
  ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
181
114k
  if (ret == NULL)
182
126
      return(NULL);
183
344k
    } else {
184
344k
  ret = memory;
185
344k
    }
186
458k
    memcpy(&ret[0], prefix, lenp);
187
458k
    ret[lenp] = ':';
188
458k
    memcpy(&ret[lenp + 1], ncname, lenn);
189
458k
    ret[lenn + lenp + 1] = 0;
190
458k
    return(ret);
191
458k
}
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
637
xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
214
637
    int len = 0;
215
637
    xmlChar *ret = NULL;
216
217
637
    if (prefix == NULL) return(NULL);
218
637
    *prefix = NULL;
219
637
    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
637
    if (name[0] == ':')
230
0
  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
4.80k
    while ((name[len] != 0) && (name[len] != ':'))
237
4.17k
  len++;
238
239
637
    if (name[len] == 0)
240
33
  return(NULL);
241
242
604
    *prefix = xmlStrndup(name, len);
243
604
    if (*prefix == NULL)
244
0
  return(NULL);
245
604
    ret = xmlStrdup(&name[len + 1]);
246
604
    if (ret == NULL) {
247
0
  if (*prefix != NULL) {
248
0
      xmlFree(*prefix);
249
0
      *prefix = NULL;
250
0
  }
251
0
  return(NULL);
252
0
    }
253
254
604
    return(ret);
255
604
}
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
980k
xmlSplitQName3(const xmlChar *name, int *len) {
271
980k
    int l = 0;
272
273
980k
    if (name == NULL) return(NULL);
274
980k
    if (len == NULL) return(NULL);
275
276
    /* nasty but valid */
277
980k
    if (name[0] == ':')
278
10.2k
  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
9.79M
    while ((name[l] != 0) && (name[l] != ':'))
285
8.82M
  l++;
286
287
970k
    if (name[l] == 0)
288
730k
  return(NULL);
289
290
239k
    *len = l;
291
292
239k
    return(&name[l+1]);
293
970k
}
294
295
const xmlChar *
296
1.04M
xmlSplitQName4(const xmlChar *name, xmlChar **prefixPtr) {
297
1.04M
    xmlChar *prefix;
298
1.04M
    int l = 0;
299
300
1.04M
    if ((name == NULL) || (prefixPtr == NULL))
301
0
        return(NULL);
302
303
1.04M
    *prefixPtr = NULL;
304
305
    /* nasty but valid */
306
1.04M
    if (name[0] == ':')
307
4.58k
  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
5.96M
    while ((name[l] != 0) && (name[l] != ':'))
314
4.92M
  l++;
315
316
    /*
317
     * TODO: What about names with multiple colons?
318
     */
319
1.04M
    if ((name[l] == 0) || (name[l+1] == 0))
320
714k
  return(name);
321
322
326k
    prefix = xmlStrndup(name, l);
323
326k
    if (prefix == NULL)
324
174
        return(NULL);
325
326
326k
    *prefixPtr = prefix;
327
326k
    return(&name[l+1]);
328
326k
}
329
330
/************************************************************************
331
 *                  *
332
 *    Check Name, NCName and QName strings      *
333
 *                  *
334
 ************************************************************************/
335
336
1.88M
#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
152k
xmlValidateNCName(const xmlChar *value, int space) {
350
152k
    const xmlChar *cur = value;
351
152k
    int c,l;
352
353
152k
    if (value == NULL)
354
0
        return(-1);
355
356
    /*
357
     * First quick algorithm for ASCII range
358
     */
359
152k
    if (space)
360
152k
  while (IS_BLANK_CH(*cur)) cur++;
361
152k
    if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
362
152k
  (*cur == '_'))
363
102k
  cur++;
364
50.0k
    else
365
50.0k
  goto try_complex;
366
589k
    while (((*cur >= 'a') && (*cur <= 'z')) ||
367
589k
     ((*cur >= 'A') && (*cur <= 'Z')) ||
368
589k
     ((*cur >= '0') && (*cur <= '9')) ||
369
589k
     (*cur == '_') || (*cur == '-') || (*cur == '.'))
370
487k
  cur++;
371
102k
    if (space)
372
365k
  while (IS_BLANK_CH(*cur)) cur++;
373
102k
    if (*cur == 0)
374
56.8k
  return(0);
375
376
95.7k
try_complex:
377
    /*
378
     * Second check for chars outside the ASCII range
379
     */
380
95.7k
    cur = value;
381
95.7k
    c = CUR_SCHAR(cur, l);
382
95.7k
    if (space) {
383
95.7k
  while (IS_BLANK(c)) {
384
34.2k
      cur += l;
385
34.2k
      c = CUR_SCHAR(cur, l);
386
34.2k
  }
387
95.7k
    }
388
95.7k
    if ((!IS_LETTER(c)) && (c != '_'))
389
21.6k
  return(1);
390
74.1k
    cur += l;
391
74.1k
    c = CUR_SCHAR(cur, l);
392
603k
    while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
393
603k
     (c == '-') || (c == '_') || IS_COMBINING(c) ||
394
603k
     IS_EXTENDER(c)) {
395
529k
  cur += l;
396
529k
  c = CUR_SCHAR(cur, l);
397
529k
    }
398
74.1k
    if (space) {
399
366k
  while (IS_BLANK(c)) {
400
366k
      cur += l;
401
366k
      c = CUR_SCHAR(cur, l);
402
366k
  }
403
74.1k
    }
404
74.1k
    if (c != 0)
405
58.4k
  return(1);
406
407
15.6k
    return(0);
408
74.1k
}
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
176k
xmlValidateQName(const xmlChar *value, int space) {
423
176k
    const xmlChar *cur = value;
424
176k
    int c,l;
425
426
176k
    if (value == NULL)
427
0
        return(-1);
428
    /*
429
     * First quick algorithm for ASCII range
430
     */
431
176k
    if (space)
432
176k
  while (IS_BLANK_CH(*cur)) cur++;
433
176k
    if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
434
176k
  (*cur == '_'))
435
106k
  cur++;
436
70.0k
    else
437
70.0k
  goto try_complex;
438
286k
    while (((*cur >= 'a') && (*cur <= 'z')) ||
439
286k
     ((*cur >= 'A') && (*cur <= 'Z')) ||
440
286k
     ((*cur >= '0') && (*cur <= '9')) ||
441
286k
     (*cur == '_') || (*cur == '-') || (*cur == '.'))
442
180k
  cur++;
443
106k
    if (*cur == ':') {
444
59.9k
  cur++;
445
59.9k
  if (((*cur >= 'a') && (*cur <= 'z')) ||
446
59.9k
      ((*cur >= 'A') && (*cur <= 'Z')) ||
447
59.9k
      (*cur == '_'))
448
25.6k
      cur++;
449
34.2k
  else
450
34.2k
      goto try_complex;
451
161k
  while (((*cur >= 'a') && (*cur <= 'z')) ||
452
161k
         ((*cur >= 'A') && (*cur <= 'Z')) ||
453
161k
         ((*cur >= '0') && (*cur <= '9')) ||
454
161k
         (*cur == '_') || (*cur == '-') || (*cur == '.'))
455
135k
      cur++;
456
25.6k
    }
457
72.3k
    if (space)
458
72.3k
  while (IS_BLANK_CH(*cur)) cur++;
459
72.3k
    if (*cur == 0)
460
54.9k
  return(0);
461
462
121k
try_complex:
463
    /*
464
     * Second check for chars outside the ASCII range
465
     */
466
121k
    cur = value;
467
121k
    c = CUR_SCHAR(cur, l);
468
121k
    if (space) {
469
121k
  while (IS_BLANK(c)) {
470
605
      cur += l;
471
605
      c = CUR_SCHAR(cur, l);
472
605
  }
473
121k
    }
474
121k
    if ((!IS_LETTER(c)) && (c != '_'))
475
36.2k
  return(1);
476
85.4k
    cur += l;
477
85.4k
    c = CUR_SCHAR(cur, l);
478
174k
    while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
479
174k
     (c == '-') || (c == '_') || IS_COMBINING(c) ||
480
174k
     IS_EXTENDER(c)) {
481
88.8k
  cur += l;
482
88.8k
  c = CUR_SCHAR(cur, l);
483
88.8k
    }
484
85.4k
    if (c == ':') {
485
43.9k
  cur += l;
486
43.9k
  c = CUR_SCHAR(cur, l);
487
43.9k
  if ((!IS_LETTER(c)) && (c != '_'))
488
28.1k
      return(1);
489
15.8k
  cur += l;
490
15.8k
  c = CUR_SCHAR(cur, l);
491
87.5k
  while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') ||
492
87.5k
         (c == '-') || (c == '_') || IS_COMBINING(c) ||
493
87.5k
         IS_EXTENDER(c)) {
494
71.7k
      cur += l;
495
71.7k
      c = CUR_SCHAR(cur, l);
496
71.7k
  }
497
15.8k
    }
498
57.3k
    if (space) {
499
57.3k
  while (IS_BLANK(c)) {
500
1.03k
      cur += l;
501
1.03k
      c = CUR_SCHAR(cur, l);
502
1.03k
  }
503
57.3k
    }
504
57.3k
    if (c != 0)
505
19.5k
  return(1);
506
37.8k
    return(0);
507
57.3k
}
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
9.13k
xmlValidateName(const xmlChar *value, int space) {
521
9.13k
    const xmlChar *cur = value;
522
9.13k
    int c,l;
523
524
9.13k
    if (value == NULL)
525
0
        return(-1);
526
    /*
527
     * First quick algorithm for ASCII range
528
     */
529
9.13k
    if (space)
530
9.13k
  while (IS_BLANK_CH(*cur)) cur++;
531
9.13k
    if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) ||
532
9.13k
  (*cur == '_') || (*cur == ':'))
533
2.77k
  cur++;
534
6.35k
    else
535
6.35k
  goto try_complex;
536
21.6k
    while (((*cur >= 'a') && (*cur <= 'z')) ||
537
21.6k
     ((*cur >= 'A') && (*cur <= 'Z')) ||
538
21.6k
     ((*cur >= '0') && (*cur <= '9')) ||
539
21.6k
     (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
540
18.8k
  cur++;
541
2.77k
    if (space)
542
2.77k
  while (IS_BLANK_CH(*cur)) cur++;
543
2.77k
    if (*cur == 0)
544
534
  return(0);
545
546
8.60k
try_complex:
547
    /*
548
     * Second check for chars outside the ASCII range
549
     */
550
8.60k
    cur = value;
551
8.60k
    c = CUR_SCHAR(cur, l);
552
8.60k
    if (space) {
553
8.60k
  while (IS_BLANK(c)) {
554
510
      cur += l;
555
510
      c = CUR_SCHAR(cur, l);
556
510
  }
557
8.60k
    }
558
8.60k
    if ((!IS_LETTER(c)) && (c != '_') && (c != ':'))
559
1.47k
  return(1);
560
7.12k
    cur += l;
561
7.12k
    c = CUR_SCHAR(cur, l);
562
91.7k
    while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
563
91.7k
     (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
564
84.5k
  cur += l;
565
84.5k
  c = CUR_SCHAR(cur, l);
566
84.5k
    }
567
7.12k
    if (space) {
568
7.12k
  while (IS_BLANK(c)) {
569
687
      cur += l;
570
687
      c = CUR_SCHAR(cur, l);
571
687
  }
572
7.12k
    }
573
7.12k
    if (c != 0)
574
5.81k
  return(1);
575
1.31k
    return(0);
576
7.12k
}
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
37.1k
xmlValidateNMToken(const xmlChar *value, int space) {
590
37.1k
    const xmlChar *cur = value;
591
37.1k
    int c,l;
592
593
37.1k
    if (value == NULL)
594
0
        return(-1);
595
    /*
596
     * First quick algorithm for ASCII range
597
     */
598
37.1k
    if (space)
599
37.1k
  while (IS_BLANK_CH(*cur)) cur++;
600
37.1k
    if (((*cur >= 'a') && (*cur <= 'z')) ||
601
37.1k
        ((*cur >= 'A') && (*cur <= 'Z')) ||
602
37.1k
        ((*cur >= '0') && (*cur <= '9')) ||
603
37.1k
        (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
604
22.5k
  cur++;
605
14.6k
    else
606
14.6k
  goto try_complex;
607
164k
    while (((*cur >= 'a') && (*cur <= 'z')) ||
608
164k
     ((*cur >= 'A') && (*cur <= 'Z')) ||
609
164k
     ((*cur >= '0') && (*cur <= '9')) ||
610
164k
     (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
611
141k
  cur++;
612
22.5k
    if (space)
613
22.5k
  while (IS_BLANK_CH(*cur)) cur++;
614
22.5k
    if (*cur == 0)
615
14.7k
  return(0);
616
617
22.3k
try_complex:
618
    /*
619
     * Second check for chars outside the ASCII range
620
     */
621
22.3k
    cur = value;
622
22.3k
    c = CUR_SCHAR(cur, l);
623
22.3k
    if (space) {
624
22.3k
  while (IS_BLANK(c)) {
625
0
      cur += l;
626
0
      c = CUR_SCHAR(cur, l);
627
0
  }
628
22.3k
    }
629
22.3k
    if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
630
22.3k
        (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)))
631
1.29k
  return(1);
632
21.0k
    cur += l;
633
21.0k
    c = CUR_SCHAR(cur, l);
634
230k
    while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') ||
635
230k
     (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) {
636
209k
  cur += l;
637
209k
  c = CUR_SCHAR(cur, l);
638
209k
    }
639
21.0k
    if (space) {
640
21.0k
  while (IS_BLANK(c)) {
641
1
      cur += l;
642
1
      c = CUR_SCHAR(cur, l);
643
1
  }
644
21.0k
    }
645
21.0k
    if (c != 0)
646
2.00k
  return(1);
647
19.0k
    return(0);
648
21.0k
}
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.11M
xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
710
1.11M
    xmlNsPtr cur;
711
712
1.11M
    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.11M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
719
1.11M
    if (cur == NULL)
720
341
  return(NULL);
721
1.11M
    memset(cur, 0, sizeof(xmlNs));
722
1.11M
    cur->type = XML_LOCAL_NAMESPACE;
723
724
1.11M
    if (href != NULL) {
725
1.03M
  cur->href = xmlStrdup(href);
726
1.03M
        if (cur->href == NULL)
727
306
            goto error;
728
1.03M
    }
729
1.11M
    if (prefix != NULL) {
730
728k
  cur->prefix = xmlStrdup(prefix);
731
728k
        if (cur->prefix == NULL)
732
272
            goto error;
733
728k
    }
734
735
    /*
736
     * Add it at the end to preserve parsing order ...
737
     * and checks for existing use of the prefix
738
     */
739
1.11M
    if (node != NULL) {
740
172k
  if (node->nsDef == NULL) {
741
152k
      node->nsDef = cur;
742
152k
  } else {
743
20.1k
      xmlNsPtr prev = node->nsDef;
744
745
20.1k
      if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
746
20.1k
    (xmlStrEqual(prev->prefix, cur->prefix)))
747
0
                goto error;
748
24.3k
      while (prev->next != NULL) {
749
4.12k
          prev = prev->next;
750
4.12k
    if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
751
4.12k
        (xmlStrEqual(prev->prefix, cur->prefix)))
752
0
                    goto error;
753
4.12k
      }
754
20.1k
      prev->next = cur;
755
20.1k
  }
756
172k
    }
757
1.11M
    return(cur);
758
759
578
error:
760
578
    xmlFreeNs(cur);
761
578
    return(NULL);
762
1.11M
}
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
137k
xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
773
137k
    if (node == NULL) {
774
0
  return;
775
0
    }
776
137k
    if ((node->type == XML_ELEMENT_NODE) ||
777
137k
        (node->type == XML_ATTRIBUTE_NODE))
778
137k
  node->ns = ns;
779
137k
}
780
781
/**
782
 * xmlFreeNs:
783
 * @cur:  the namespace pointer
784
 *
785
 * Free up the structures associated to a namespace
786
 */
787
void
788
1.33M
xmlFreeNs(xmlNsPtr cur) {
789
1.33M
    if (cur == NULL) {
790
0
  return;
791
0
    }
792
1.33M
    if (cur->href != NULL) xmlFree((char *) cur->href);
793
1.33M
    if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
794
1.33M
    xmlFree(cur);
795
1.33M
}
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.10M
xmlFreeNsList(xmlNsPtr cur) {
805
1.10M
    xmlNsPtr next;
806
1.10M
    if (cur == NULL) {
807
262
  return;
808
262
    }
809
2.43M
    while (cur != NULL) {
810
1.33M
        next = cur->next;
811
1.33M
        xmlFreeNs(cur);
812
1.33M
  cur = next;
813
1.33M
    }
814
1.10M
}
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
19.4k
                    const xmlChar *ExternalID, const xmlChar *SystemID) {
831
19.4k
    xmlDtdPtr cur;
832
833
19.4k
    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
19.4k
    cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
841
19.4k
    if (cur == NULL)
842
76
  return(NULL);
843
19.4k
    memset(cur, 0 , sizeof(xmlDtd));
844
19.4k
    cur->type = XML_DTD_NODE;
845
846
19.4k
    if (name != NULL) {
847
18.7k
  cur->name = xmlStrdup(name);
848
18.7k
        if (cur->name == NULL)
849
75
            goto error;
850
18.7k
    }
851
19.3k
    if (ExternalID != NULL) {
852
5.68k
  cur->ExternalID = xmlStrdup(ExternalID);
853
5.68k
        if (cur->ExternalID == NULL)
854
40
            goto error;
855
5.68k
    }
856
19.3k
    if (SystemID != NULL) {
857
12.6k
  cur->SystemID = xmlStrdup(SystemID);
858
12.6k
        if (cur->SystemID == NULL)
859
64
            goto error;
860
12.6k
    }
861
19.2k
    if (doc != NULL)
862
7.79k
  doc->extSubset = cur;
863
19.2k
    cur->doc = doc;
864
865
19.2k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
866
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
867
19.2k
    return(cur);
868
869
179
error:
870
179
    xmlFreeDtd(cur);
871
179
    return(NULL);
872
19.3k
}
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
306k
xmlGetIntSubset(const xmlDoc *doc) {
884
306k
    xmlNodePtr cur;
885
886
306k
    if (doc == NULL)
887
0
  return(NULL);
888
306k
    cur = doc->children;
889
649k
    while (cur != NULL) {
890
390k
  if (cur->type == XML_DTD_NODE)
891
47.4k
      return((xmlDtdPtr) cur);
892
342k
  cur = cur->next;
893
342k
    }
894
259k
    return((xmlDtdPtr) doc->intSubset);
895
306k
}
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
125k
                   const xmlChar *ExternalID, const xmlChar *SystemID) {
910
125k
    xmlDtdPtr cur;
911
912
125k
    if (doc != NULL) {
913
125k
        cur = xmlGetIntSubset(doc);
914
125k
        if (cur != NULL)
915
0
            return(cur);
916
125k
    }
917
918
    /*
919
     * Allocate a new DTD and fill the fields.
920
     */
921
125k
    cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
922
125k
    if (cur == NULL)
923
304
  return(NULL);
924
125k
    memset(cur, 0, sizeof(xmlDtd));
925
125k
    cur->type = XML_DTD_NODE;
926
927
125k
    if (name != NULL) {
928
116k
  cur->name = xmlStrdup(name);
929
116k
  if (cur->name == NULL)
930
446
            goto error;
931
116k
    }
932
124k
    if (ExternalID != NULL) {
933
14.6k
  cur->ExternalID = xmlStrdup(ExternalID);
934
14.6k
  if (cur->ExternalID  == NULL)
935
74
            goto error;
936
14.6k
    }
937
124k
    if (SystemID != NULL) {
938
31.4k
  cur->SystemID = xmlStrdup(SystemID);
939
31.4k
  if (cur->SystemID == NULL)
940
143
            goto error;
941
31.4k
    }
942
124k
    if (doc != NULL) {
943
124k
  doc->intSubset = cur;
944
124k
  cur->parent = doc;
945
124k
  cur->doc = doc;
946
124k
  if (doc->children == NULL) {
947
108k
      doc->children = (xmlNodePtr) cur;
948
108k
      doc->last = (xmlNodePtr) cur;
949
108k
  } else {
950
16.0k
      if (doc->type == XML_HTML_DOCUMENT_NODE) {
951
10.6k
    xmlNodePtr prev;
952
953
10.6k
    prev = doc->children;
954
10.6k
    prev->prev = (xmlNodePtr) cur;
955
10.6k
    cur->next = prev;
956
10.6k
    doc->children = (xmlNodePtr) cur;
957
10.6k
      } else {
958
5.34k
    xmlNodePtr next;
959
960
5.34k
    next = doc->children;
961
148k
    while ((next != NULL) && (next->type != XML_ELEMENT_NODE))
962
142k
        next = next->next;
963
5.34k
    if (next == NULL) {
964
5.34k
        cur->prev = doc->last;
965
5.34k
        cur->prev->next = (xmlNodePtr) cur;
966
5.34k
        cur->next = NULL;
967
5.34k
        doc->last = (xmlNodePtr) cur;
968
5.34k
    } 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
5.34k
      }
978
16.0k
  }
979
124k
    }
980
981
124k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
982
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
983
124k
    return(cur);
984
985
663
error:
986
663
    xmlFreeDtd(cur);
987
663
    return(NULL);
988
124k
}
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
21.5M
  if ((str) && ((!dict) ||       \
999
20.7M
      (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
1000
14.7M
      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
144k
xmlFreeDtd(xmlDtdPtr cur) {
1046
144k
    xmlDictPtr dict = NULL;
1047
1048
144k
    if (cur == NULL) {
1049
0
  return;
1050
0
    }
1051
144k
    if (cur->doc != NULL) dict = cur->doc->dict;
1052
1053
144k
    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
1054
0
  xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1055
1056
144k
    if (cur->children != NULL) {
1057
85.4k
  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
3.95M
        while (c != NULL) {
1064
3.87M
      next = c->next;
1065
3.87M
      if ((c->type != XML_NOTATION_NODE) &&
1066
3.87M
          (c->type != XML_ELEMENT_DECL) &&
1067
3.87M
    (c->type != XML_ATTRIBUTE_DECL) &&
1068
3.87M
    (c->type != XML_ENTITY_DECL)) {
1069
3.41M
    xmlUnlinkNode(c);
1070
3.41M
    xmlFreeNode(c);
1071
3.41M
      }
1072
3.87M
      c = next;
1073
3.87M
  }
1074
85.4k
    }
1075
144k
    DICT_FREE(cur->name)
1076
144k
    DICT_FREE(cur->SystemID)
1077
144k
    DICT_FREE(cur->ExternalID)
1078
    /* TODO !!! */
1079
144k
    if (cur->notations != NULL)
1080
1.06k
        xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
1081
1082
144k
    if (cur->elements != NULL)
1083
53.2k
        xmlFreeElementTable((xmlElementTablePtr) cur->elements);
1084
144k
    if (cur->attributes != NULL)
1085
38.4k
        xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
1086
144k
    if (cur->entities != NULL)
1087
31.8k
        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
1088
144k
    if (cur->pentities != NULL)
1089
18.5k
        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
1090
1091
144k
    xmlFree(cur);
1092
144k
}
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
250k
xmlNewDoc(const xmlChar *version) {
1104
250k
    xmlDocPtr cur;
1105
1106
250k
    if (version == NULL)
1107
19.1k
  version = (const xmlChar *) "1.0";
1108
1109
    /*
1110
     * Allocate a new document and fill the fields.
1111
     */
1112
250k
    cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
1113
250k
    if (cur == NULL)
1114
533
  return(NULL);
1115
250k
    memset(cur, 0, sizeof(xmlDoc));
1116
250k
    cur->type = XML_DOCUMENT_NODE;
1117
1118
250k
    cur->version = xmlStrdup(version);
1119
250k
    if (cur->version == NULL) {
1120
483
  xmlFree(cur);
1121
483
  return(NULL);
1122
483
    }
1123
249k
    cur->standalone = -1;
1124
249k
    cur->compression = -1; /* not initialized */
1125
249k
    cur->doc = cur;
1126
249k
    cur->parseFlags = 0;
1127
249k
    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
249k
    cur->charset = XML_CHAR_ENCODING_UTF8;
1134
1135
249k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1136
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
1137
249k
    return(cur);
1138
250k
}
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
263k
xmlFreeDoc(xmlDocPtr cur) {
1148
263k
    xmlDtdPtr extSubset, intSubset;
1149
263k
    xmlDictPtr dict = NULL;
1150
1151
263k
    if (cur == NULL) {
1152
51.4k
  return;
1153
51.4k
    }
1154
1155
212k
    if (cur != NULL) dict = cur->dict;
1156
1157
212k
    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
1158
0
  xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
1159
1160
    /*
1161
     * Do this before freeing the children list to avoid ID lookups
1162
     */
1163
212k
    if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
1164
212k
    cur->ids = NULL;
1165
212k
    if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
1166
212k
    cur->refs = NULL;
1167
212k
    extSubset = cur->extSubset;
1168
212k
    intSubset = cur->intSubset;
1169
212k
    if (intSubset == extSubset)
1170
107k
  extSubset = NULL;
1171
212k
    if (extSubset != NULL) {
1172
4.34k
  xmlUnlinkNode((xmlNodePtr) cur->extSubset);
1173
4.34k
  cur->extSubset = NULL;
1174
4.34k
  xmlFreeDtd(extSubset);
1175
4.34k
    }
1176
212k
    if (intSubset != NULL) {
1177
106k
  xmlUnlinkNode((xmlNodePtr) cur->intSubset);
1178
106k
  cur->intSubset = NULL;
1179
106k
  xmlFreeDtd(intSubset);
1180
106k
    }
1181
1182
212k
    if (cur->children != NULL) xmlFreeNodeList(cur->children);
1183
212k
    if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
1184
1185
212k
    DICT_FREE(cur->version)
1186
212k
    DICT_FREE(cur->name)
1187
212k
    DICT_FREE(cur->encoding)
1188
212k
    DICT_FREE(cur->URL)
1189
212k
    xmlFree(cur);
1190
212k
    if (dict) xmlDictFree(dict);
1191
212k
}
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
328k
xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) {
1205
328k
    xmlNodePtr ret = NULL, head = NULL, last = NULL;
1206
328k
    xmlNodePtr node;
1207
328k
    xmlChar *val = NULL;
1208
328k
    const xmlChar *cur, *end;
1209
328k
    const xmlChar *q;
1210
328k
    xmlEntityPtr ent;
1211
328k
    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
328k
    if (value == NULL) return(NULL);
1224
328k
    cur = value;
1225
328k
    end = cur + len;
1226
1227
328k
    buf = xmlBufCreateSize(0);
1228
328k
    if (buf == NULL) return(NULL);
1229
328k
    xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
1230
1231
328k
    q = cur;
1232
496M
    while ((cur < end) && (*cur != 0)) {
1233
496M
  if (cur[0] == '&') {
1234
766k
      int charval = 0;
1235
766k
      xmlChar tmp;
1236
1237
      /*
1238
       * Save the current text.
1239
       */
1240
766k
            if (cur != q) {
1241
90.3k
    if (xmlBufAdd(buf, q, cur - q))
1242
38
        goto out;
1243
90.3k
      }
1244
766k
      q = cur;
1245
766k
      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
766k
      } else if ((cur + 1 < end) && (cur[1] == '#')) {
1272
67.3k
    cur += 2;
1273
67.3k
    if (cur < end)
1274
67.3k
        tmp = *cur;
1275
0
    else
1276
0
        tmp = 0;
1277
202k
    while (tmp != ';') { /* Non input consuming loops */
1278
                    /* Don't check for integer overflow, see above. */
1279
134k
        if ((tmp >= '0') && (tmp <= '9'))
1280
134k
      charval = charval * 10 + (tmp - '0');
1281
0
        else {
1282
0
      charval = 0;
1283
0
      break;
1284
0
        }
1285
134k
        cur++;
1286
134k
        if (cur < end)
1287
134k
      tmp = *cur;
1288
0
        else
1289
0
      tmp = 0;
1290
134k
    }
1291
67.3k
    if (tmp == ';')
1292
67.3k
        cur++;
1293
67.3k
    q = cur;
1294
699k
      } else {
1295
    /*
1296
     * Read the entity string
1297
     */
1298
699k
    cur++;
1299
699k
    q = cur;
1300
1.40M
    while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
1301
699k
    if ((cur >= end) || (*cur == 0))
1302
0
        break;
1303
699k
    if (cur != q) {
1304
        /*
1305
         * Predefined entities don't generate nodes
1306
         */
1307
699k
        val = xmlStrndup(q, cur - q);
1308
699k
        ent = xmlGetDocEntity(doc, val);
1309
699k
        if ((ent != NULL) &&
1310
699k
      (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1311
1312
0
      if (xmlBufCat(buf, ent->content))
1313
0
          goto out;
1314
699k
        } else {
1315
      /*
1316
       * Flush buffer so far
1317
       */
1318
699k
      if (!xmlBufIsEmpty(buf)) {
1319
60.1k
          node = xmlNewDocText(doc, NULL);
1320
60.1k
          if (node == NULL)
1321
24
        goto out;
1322
60.0k
          node->content = xmlBufDetach(buf);
1323
1324
60.0k
          if (last == NULL) {
1325
10.3k
        last = head = node;
1326
49.7k
          } else {
1327
49.7k
        last = xmlAddNextSibling(last, node);
1328
49.7k
          }
1329
60.0k
      }
1330
1331
      /*
1332
       * Create a new REFERENCE_REF node
1333
       */
1334
699k
      node = xmlNewReference(doc, val);
1335
699k
      if (node == NULL)
1336
99
          goto out;
1337
699k
      else if ((ent != NULL) &&
1338
699k
                                 ((ent->flags & XML_ENT_PARSED) == 0) &&
1339
699k
                                 ((ent->flags & XML_ENT_EXPANDING) == 0)) {
1340
1.94k
          xmlNodePtr temp;
1341
1342
                            /*
1343
                             * The entity should have been checked already,
1344
                             * but set the flag anyway to avoid recursion.
1345
                             */
1346
1.94k
                            if (node->content != NULL) {
1347
1.94k
                                ent->flags |= XML_ENT_EXPANDING;
1348
1.94k
                                ent->children = xmlStringGetNodeList(doc,
1349
1.94k
                                        node->content);
1350
1.94k
                                ent->flags &= ~XML_ENT_EXPANDING;
1351
1.94k
                                if (ent->children == NULL) {
1352
138
                                    xmlFreeNode(node);
1353
138
                                    goto out;
1354
138
                                }
1355
1.94k
                            }
1356
1.80k
                            ent->flags |= XML_ENT_PARSED;
1357
1.80k
          temp = ent->children;
1358
9.42k
          while (temp) {
1359
7.62k
        temp->parent = (xmlNodePtr)ent;
1360
7.62k
        ent->last = temp;
1361
7.62k
        temp = temp->next;
1362
7.62k
          }
1363
1.80k
      }
1364
699k
      if (last == NULL) {
1365
4.32k
          last = head = node;
1366
695k
      } else {
1367
695k
          last = xmlAddNextSibling(last, node);
1368
695k
      }
1369
699k
        }
1370
699k
        xmlFree(val);
1371
699k
                    val = NULL;
1372
699k
    }
1373
699k
    cur++;
1374
699k
    q = cur;
1375
699k
      }
1376
766k
      if (charval != 0) {
1377
67.3k
    xmlChar buffer[10];
1378
67.3k
    int l;
1379
1380
67.3k
    l = xmlCopyCharMultiByte(buffer, charval);
1381
67.3k
    buffer[l] = 0;
1382
1383
67.3k
    if (xmlBufCat(buf, buffer))
1384
20
        goto out;
1385
67.3k
    charval = 0;
1386
67.3k
      }
1387
766k
  } else
1388
495M
      cur++;
1389
496M
    }
1390
1391
328k
    if (cur != q) {
1392
        /*
1393
   * Handle the last piece of text.
1394
   */
1395
317k
  if (xmlBufAdd(buf, q, cur - q))
1396
82
      goto out;
1397
317k
    }
1398
1399
328k
    if (!xmlBufIsEmpty(buf)) {
1400
318k
  node = xmlNewDocText(doc, NULL);
1401
318k
  if (node == NULL)
1402
75
            goto out;
1403
318k
  node->content = xmlBufDetach(buf);
1404
1405
318k
  if (last == NULL) {
1406
313k
      head = node;
1407
313k
  } else {
1408
4.95k
      xmlAddNextSibling(last, node);
1409
4.95k
  }
1410
318k
    } else if (head == NULL) {
1411
0
        head = xmlNewDocText(doc, BAD_CAST "");
1412
0
    }
1413
1414
328k
    ret = head;
1415
328k
    head = NULL;
1416
1417
328k
out:
1418
328k
    xmlBufFree(buf);
1419
328k
    if (val != NULL)
1420
228
        xmlFree(val);
1421
328k
    if (head != NULL)
1422
156
        xmlFreeNodeList(head);
1423
328k
    return(ret);
1424
328k
}
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
101k
xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) {
1437
101k
    xmlNodePtr ret = NULL, head = NULL, last = NULL;
1438
101k
    xmlNodePtr node;
1439
101k
    xmlChar *val = NULL;
1440
101k
    const xmlChar *cur = value;
1441
101k
    const xmlChar *q;
1442
101k
    xmlEntityPtr ent;
1443
101k
    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
101k
    if (value == NULL) return(NULL);
1456
1457
101k
    buf = xmlBufCreateSize(0);
1458
101k
    if (buf == NULL) return(NULL);
1459
101k
    xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
1460
1461
101k
    q = cur;
1462
4.14M
    while (*cur != 0) {
1463
4.04M
  if (cur[0] == '&') {
1464
27.7k
      int charval = 0;
1465
27.7k
      xmlChar tmp;
1466
1467
      /*
1468
       * Save the current text.
1469
       */
1470
27.7k
            if (cur != q) {
1471
12.2k
    if (xmlBufAdd(buf, q, cur - q))
1472
29
        goto out;
1473
12.2k
      }
1474
27.7k
      q = cur;
1475
27.7k
      if ((cur[1] == '#') && (cur[2] == 'x')) {
1476
795
    cur += 3;
1477
795
    tmp = *cur;
1478
4.88k
    while (tmp != ';') { /* Non input consuming loop */
1479
4.08k
        if ((tmp >= '0') && (tmp <= '9'))
1480
1.56k
      charval = charval * 16 + (tmp - '0');
1481
2.52k
        else if ((tmp >= 'a') && (tmp <= 'f'))
1482
707
      charval = charval * 16 + (tmp - 'a') + 10;
1483
1.81k
        else if ((tmp >= 'A') && (tmp <= 'F'))
1484
1.81k
      charval = charval * 16 + (tmp - 'A') + 10;
1485
0
        else {
1486
0
      charval = 0;
1487
0
      break;
1488
0
        }
1489
4.08k
        cur++;
1490
4.08k
        tmp = *cur;
1491
4.08k
    }
1492
795
    if (tmp == ';')
1493
795
        cur++;
1494
795
    q = cur;
1495
26.9k
      } else if  (cur[1] == '#') {
1496
6.55k
    cur += 2;
1497
6.55k
    tmp = *cur;
1498
19.7k
    while (tmp != ';') { /* Non input consuming loops */
1499
                    /* Don't check for integer overflow, see above. */
1500
13.1k
        if ((tmp >= '0') && (tmp <= '9'))
1501
13.1k
      charval = charval * 10 + (tmp - '0');
1502
0
        else {
1503
0
      charval = 0;
1504
0
      break;
1505
0
        }
1506
13.1k
        cur++;
1507
13.1k
        tmp = *cur;
1508
13.1k
    }
1509
6.55k
    if (tmp == ';')
1510
6.55k
        cur++;
1511
6.55k
    q = cur;
1512
20.3k
      } else {
1513
    /*
1514
     * Read the entity string
1515
     */
1516
20.3k
    cur++;
1517
20.3k
    q = cur;
1518
142k
    while ((*cur != 0) && (*cur != ';')) cur++;
1519
20.3k
    if (*cur == 0)
1520
0
        break;
1521
20.3k
    if (cur != q) {
1522
        /*
1523
         * Predefined entities don't generate nodes
1524
         */
1525
20.3k
        val = xmlStrndup(q, cur - q);
1526
20.3k
                    if (val == NULL)
1527
60
                        goto out;
1528
20.2k
        ent = xmlGetDocEntity(doc, val);
1529
20.2k
        if ((ent != NULL) &&
1530
20.2k
      (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
1531
1532
516
      if (xmlBufCat(buf, ent->content))
1533
9
          goto out;
1534
1535
19.7k
        } else {
1536
      /*
1537
       * Flush buffer so far
1538
       */
1539
19.7k
      if (!xmlBufIsEmpty(buf)) {
1540
8.90k
          node = xmlNewDocText(doc, NULL);
1541
8.90k
                            if (node == NULL)
1542
19
                                goto out;
1543
8.88k
          node->content = xmlBufDetach(buf);
1544
1545
8.88k
          if (last == NULL) {
1546
3.57k
        last = head = node;
1547
5.30k
          } else {
1548
5.30k
        last = xmlAddNextSibling(last, node);
1549
5.30k
          }
1550
8.88k
      }
1551
1552
      /*
1553
       * Create a new REFERENCE_REF node
1554
       */
1555
19.7k
      node = xmlNewReference(doc, val);
1556
19.7k
      if (node == NULL)
1557
85
          goto out;
1558
19.6k
      if ((ent != NULL) &&
1559
19.6k
                            ((ent->flags & XML_ENT_PARSED) == 0) &&
1560
19.6k
                            ((ent->flags & XML_ENT_EXPANDING) == 0)) {
1561
2.49k
          xmlNodePtr temp;
1562
1563
                            /*
1564
                             * The entity should have been checked already,
1565
                             * but set the flag anyway to avoid recursion.
1566
                             */
1567
2.49k
                            if (node->content != NULL) {
1568
2.45k
                                ent->flags |= XML_ENT_EXPANDING;
1569
2.45k
                                ent->children = xmlStringGetNodeList(doc,
1570
2.45k
                                        node->content);
1571
2.45k
                                ent->flags &= ~XML_ENT_EXPANDING;
1572
2.45k
                                if (ent->children == NULL) {
1573
326
                                    xmlFreeNode(node);
1574
326
                                    goto out;
1575
326
                                }
1576
2.45k
                            }
1577
2.16k
                            ent->flags |= XML_ENT_PARSED;
1578
2.16k
          temp = ent->children;
1579
6.54k
          while (temp) {
1580
4.37k
        temp->parent = (xmlNodePtr)ent;
1581
4.37k
        ent->last = temp;
1582
4.37k
        temp = temp->next;
1583
4.37k
          }
1584
2.16k
      }
1585
19.3k
      if (last == NULL) {
1586
3.41k
          last = head = node;
1587
15.9k
      } else {
1588
15.9k
          last = xmlAddNextSibling(last, node);
1589
15.9k
      }
1590
19.3k
        }
1591
19.8k
        xmlFree(val);
1592
19.8k
                    val = NULL;
1593
19.8k
    }
1594
19.8k
    cur++;
1595
19.8k
    q = cur;
1596
19.8k
      }
1597
27.2k
      if (charval != 0) {
1598
7.35k
    xmlChar buffer[10];
1599
7.35k
    int len;
1600
1601
7.35k
    len = xmlCopyCharMultiByte(buffer, charval);
1602
7.35k
    buffer[len] = 0;
1603
1604
7.35k
    if (xmlBufCat(buf, buffer))
1605
15
        goto out;
1606
7.33k
    charval = 0;
1607
7.33k
      }
1608
27.2k
  } else
1609
4.01M
      cur++;
1610
4.04M
    }
1611
100k
    if ((cur != q) || (head == NULL)) {
1612
        /*
1613
   * Handle the last piece of text.
1614
   */
1615
95.3k
  xmlBufAdd(buf, q, cur - q);
1616
95.3k
    }
1617
1618
100k
    if (xmlBufIsEmpty(buf) <= 0) {
1619
94.6k
  node = xmlNewDocText(doc, NULL);
1620
94.6k
        if (node == NULL)
1621
68
            goto out;
1622
94.5k
  node->content = xmlBufDetach(buf);
1623
94.5k
        if (node->content == NULL) {
1624
55
            xmlFreeNode(node);
1625
55
            goto out;
1626
55
        }
1627
1628
94.5k
  if (last == NULL) {
1629
93.0k
      head = node;
1630
93.0k
  } else {
1631
1.44k
      xmlAddNextSibling(last, node);
1632
1.44k
  }
1633
94.5k
    } else if (head == NULL) {
1634
709
        head = xmlNewDocText(doc, BAD_CAST "");
1635
709
    }
1636
1637
100k
    ret = head;
1638
100k
    head = NULL;
1639
1640
101k
out:
1641
101k
    xmlBufFree(buf);
1642
101k
    if (val != NULL) xmlFree(val);
1643
101k
    if (head != NULL) xmlFreeNodeList(head);
1644
101k
    return(ret);
1645
100k
}
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
480k
{
1661
480k
    const xmlNode *node = list;
1662
480k
    xmlChar *ret = NULL;
1663
480k
    xmlEntityPtr ent;
1664
480k
    int attr;
1665
1666
480k
    if (list == NULL)
1667
48.1k
        return xmlStrdup(BAD_CAST "");
1668
431k
    if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
1669
382k
        attr = 1;
1670
49.6k
    else
1671
49.6k
        attr = 0;
1672
1673
939k
    while (node != NULL) {
1674
507k
        if ((node->type == XML_TEXT_NODE) ||
1675
507k
            (node->type == XML_CDATA_SECTION_NODE)) {
1676
434k
            if (inLine) {
1677
139k
                ret = xmlStrcat(ret, node->content);
1678
139k
                if (ret == NULL)
1679
37
                    goto error;
1680
295k
            } else {
1681
295k
                xmlChar *buffer;
1682
1683
295k
    if (attr)
1684
295k
        buffer = xmlEncodeAttributeEntities(doc, node->content);
1685
0
    else
1686
0
        buffer = xmlEncodeEntitiesReentrant(doc, node->content);
1687
295k
                if (buffer == NULL)
1688
56
                    goto error;
1689
295k
                ret = xmlStrcat(ret, buffer);
1690
295k
                xmlFree(buffer);
1691
295k
                if (ret == NULL)
1692
59
                    goto error;
1693
295k
            }
1694
434k
        } else if (node->type == XML_ENTITY_REF_NODE) {
1695
70.7k
            if (inLine) {
1696
65.6k
                ent = xmlGetDocEntity(doc, node->name);
1697
65.6k
                if (ent != NULL) {
1698
49.8k
                    if (ent->children != NULL) {
1699
49.6k
                        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
49.6k
                        buffer = xmlNodeListGetString(doc, ent->children, 1);
1709
49.6k
                        if (buffer == NULL)
1710
120
                            goto error;
1711
49.5k
                        ret = xmlStrcat(ret, buffer);
1712
49.5k
                        xmlFree(buffer);
1713
49.5k
                        if (ret == NULL)
1714
10
                            goto error;
1715
49.5k
                    }
1716
49.8k
                } else if (node->content != NULL) {
1717
0
                    ret = xmlStrcat(ret, node->content);
1718
0
                    if (ret == NULL)
1719
0
                        goto error;
1720
0
                }
1721
65.6k
            } else {
1722
5.08k
                xmlChar buf[2];
1723
1724
5.08k
                buf[0] = '&';
1725
5.08k
                buf[1] = 0;
1726
5.08k
                ret = xmlStrncat(ret, buf, 1);
1727
5.08k
                ret = xmlStrcat(ret, node->name);
1728
5.08k
                buf[0] = ';';
1729
5.08k
                buf[1] = 0;
1730
5.08k
                ret = xmlStrncat(ret, buf, 1);
1731
5.08k
                if (ret == NULL)
1732
1
                    goto error;
1733
5.08k
            }
1734
70.7k
        }
1735
507k
        node = node->next;
1736
507k
    }
1737
431k
    if (ret == NULL)
1738
9.71k
        ret = xmlStrdup(BAD_CAST "");
1739
431k
    return (ret);
1740
1741
283
error:
1742
283
    xmlFree(ret);
1743
283
    return(NULL);
1744
431k
}
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
634k
{
1830
634k
    xmlAttrPtr cur;
1831
634k
    xmlDocPtr doc = NULL;
1832
1833
634k
    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
634k
    cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
1845
634k
    if (cur == NULL) {
1846
188
        if ((eatname == 1) &&
1847
188
      ((node == NULL) || (node->doc == NULL) ||
1848
188
             (node->doc->dict == NULL) ||
1849
188
       (!(xmlDictOwns(node->doc->dict, name)))))
1850
188
            xmlFree((xmlChar *) name);
1851
188
        return (NULL);
1852
188
    }
1853
634k
    memset(cur, 0, sizeof(xmlAttr));
1854
634k
    cur->type = XML_ATTRIBUTE_NODE;
1855
1856
634k
    cur->parent = node;
1857
634k
    if (node != NULL) {
1858
634k
        doc = node->doc;
1859
634k
        cur->doc = doc;
1860
634k
    }
1861
634k
    cur->ns = ns;
1862
1863
634k
    if (eatname == 0) {
1864
2.00k
        if ((doc != NULL) && (doc->dict != NULL))
1865
1.71k
            cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1);
1866
292
        else
1867
292
            cur->name = xmlStrdup(name);
1868
2.00k
        if (cur->name == NULL)
1869
0
            goto error;
1870
2.00k
    } else
1871
632k
        cur->name = name;
1872
1873
634k
    if (value != NULL) {
1874
2.00k
        xmlNodePtr tmp;
1875
1876
2.00k
        cur->children = xmlNewDocText(doc, value);
1877
2.00k
        if (cur->children == NULL)
1878
0
            goto error;
1879
2.00k
        cur->last = NULL;
1880
2.00k
        tmp = cur->children;
1881
4.01k
        while (tmp != NULL) {
1882
2.00k
            tmp->parent = (xmlNodePtr) cur;
1883
2.00k
            if (tmp->next == NULL)
1884
2.00k
                cur->last = tmp;
1885
2.00k
            tmp = tmp->next;
1886
2.00k
        }
1887
2.00k
    }
1888
1889
634k
    if ((value != NULL) && (node != NULL) &&
1890
634k
        (xmlIsID(node->doc, node, cur) == 1) &&
1891
634k
        (xmlAddIDSafe(node->doc, value, cur, 0, NULL) < 0))
1892
0
        goto error;
1893
1894
    /*
1895
     * Add it at the end to preserve parsing order ...
1896
     */
1897
634k
    if (node != NULL) {
1898
634k
        if (node->properties == NULL) {
1899
400k
            node->properties = cur;
1900
400k
        } else {
1901
233k
            xmlAttrPtr prev = node->properties;
1902
1903
75.0M
            while (prev->next != NULL)
1904
74.7M
                prev = prev->next;
1905
233k
            prev->next = cur;
1906
233k
            cur->prev = prev;
1907
233k
        }
1908
634k
    }
1909
1910
634k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
1911
0
        xmlRegisterNodeDefaultValue((xmlNodePtr) cur);
1912
634k
    return (cur);
1913
1914
0
error:
1915
0
    xmlFreeProp(cur);
1916
0
    return(NULL);
1917
634k
}
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
0
xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
1932
1933
0
    if (name == NULL) {
1934
0
  return(NULL);
1935
0
    }
1936
1937
0
  return xmlNewPropInternal(node, NULL, name, value, 0);
1938
0
}
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
0
           const xmlChar *value) {
1954
1955
0
    if (name == NULL) {
1956
0
  return(NULL);
1957
0
    }
1958
1959
0
    return xmlNewPropInternal(node, ns, name, value, 0);
1960
0
}
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
632k
           const xmlChar *value) {
1975
1976
632k
    if (name == NULL) {
1977
0
  return(NULL);
1978
0
    }
1979
1980
632k
    return xmlNewPropInternal(node, ns, name, value, 1);
1981
632k
}
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
561k
xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
1999
561k
    xmlAttrPtr cur;
2000
2001
561k
    if (name == NULL) {
2002
0
  return(NULL);
2003
0
    }
2004
2005
    /*
2006
     * Allocate a new property and fill the fields.
2007
     */
2008
561k
    cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
2009
561k
    if (cur == NULL)
2010
166
  return(NULL);
2011
561k
    memset(cur, 0, sizeof(xmlAttr));
2012
561k
    cur->type = XML_ATTRIBUTE_NODE;
2013
2014
561k
    if ((doc != NULL) && (doc->dict != NULL))
2015
71.1k
  cur->name = xmlDictLookup(doc->dict, name, -1);
2016
490k
    else
2017
490k
  cur->name = xmlStrdup(name);
2018
561k
    if (cur->name == NULL)
2019
127
        goto error;
2020
561k
    cur->doc = doc;
2021
561k
    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
561k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2037
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2038
561k
    return(cur);
2039
2040
127
error:
2041
127
    xmlFreeProp(cur);
2042
127
    return(NULL);
2043
561k
}
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
2.08M
xmlFreePropList(xmlAttrPtr cur) {
2053
2.08M
    xmlAttrPtr next;
2054
2.08M
    if (cur == NULL) return;
2055
5.05M
    while (cur != NULL) {
2056
2.96M
        next = cur->next;
2057
2.96M
        xmlFreeProp(cur);
2058
2.96M
  cur = next;
2059
2.96M
    }
2060
2.08M
}
2061
2062
/**
2063
 * xmlFreeProp:
2064
 * @cur:  an attribute
2065
 *
2066
 * Free one attribute, all the content is freed too
2067
 */
2068
void
2069
2.96M
xmlFreeProp(xmlAttrPtr cur) {
2070
2.96M
    xmlDictPtr dict = NULL;
2071
2.96M
    if (cur == NULL) return;
2072
2073
2.96M
    if (cur->doc != NULL) dict = cur->doc->dict;
2074
2075
2.96M
    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
2076
0
  xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
2077
2078
    /* Check for ID removal -> leading to invalid references ! */
2079
2.96M
    if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) {
2080
242k
      xmlRemoveID(cur->doc, cur);
2081
242k
    }
2082
2.96M
    if (cur->children != NULL) xmlFreeNodeList(cur->children);
2083
2.96M
    DICT_FREE(cur->name)
2084
2.96M
    xmlFree(cur);
2085
2.96M
}
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
128k
xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
2137
128k
    xmlNodePtr cur;
2138
2139
128k
    if (name == NULL) {
2140
0
  return(NULL);
2141
0
    }
2142
2143
    /*
2144
     * Allocate a new node and fill the fields.
2145
     */
2146
128k
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2147
128k
    if (cur == NULL)
2148
61
  return(NULL);
2149
128k
    memset(cur, 0, sizeof(xmlNode));
2150
128k
    cur->type = XML_PI_NODE;
2151
128k
    cur->doc = doc;
2152
2153
128k
    if ((doc != NULL) && (doc->dict != NULL))
2154
74.6k
        cur->name = xmlDictLookup(doc->dict, name, -1);
2155
53.9k
    else
2156
53.9k
  cur->name = xmlStrdup(name);
2157
128k
    if (cur->name == NULL)
2158
35
        goto error;
2159
128k
    if (content != NULL) {
2160
70.0k
  cur->content = xmlStrdup(content);
2161
70.0k
        if (cur->content == NULL)
2162
55
            goto error;
2163
70.0k
    }
2164
2165
128k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2166
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2167
128k
    return(cur);
2168
2169
90
error:
2170
90
    xmlFreeNode(cur);
2171
90
    return(NULL);
2172
128k
}
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
484k
xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
2204
484k
    xmlNodePtr cur;
2205
2206
484k
    if (name == NULL) {
2207
0
  return(NULL);
2208
0
    }
2209
2210
    /*
2211
     * Allocate a new node and fill the fields.
2212
     */
2213
484k
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2214
484k
    if (cur == NULL)
2215
157
  return(NULL);
2216
484k
    memset(cur, 0, sizeof(xmlNode));
2217
484k
    cur->type = XML_ELEMENT_NODE;
2218
2219
484k
    cur->name = xmlStrdup(name);
2220
484k
    if (cur->name == NULL)
2221
186
        goto error;
2222
484k
    cur->ns = ns;
2223
2224
484k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2225
0
  xmlRegisterNodeDefaultValue(cur);
2226
484k
    return(cur);
2227
2228
186
error:
2229
186
    xmlFreeNode(cur);
2230
186
    return(NULL);
2231
484k
}
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
5.12M
xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
2248
5.12M
    xmlNodePtr cur;
2249
2250
5.12M
    if (name == NULL) {
2251
179
  return(NULL);
2252
179
    }
2253
2254
    /*
2255
     * Allocate a new node and fill the fields.
2256
     */
2257
5.12M
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2258
5.12M
    if (cur == NULL)
2259
1.00k
  return(NULL);
2260
5.12M
    memset(cur, 0, sizeof(xmlNode));
2261
5.12M
    cur->type = XML_ELEMENT_NODE;
2262
2263
5.12M
    cur->name = name;
2264
5.12M
    cur->ns = ns;
2265
2266
5.12M
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2267
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
2268
5.12M
    return(cur);
2269
5.12M
}
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
512k
              const xmlChar *name, const xmlChar *content) {
2290
512k
    xmlNodePtr cur;
2291
2292
512k
    if ((doc != NULL) && (doc->dict != NULL))
2293
28.0k
        cur = xmlNewNodeEatName(ns, (xmlChar *)
2294
28.0k
                          xmlDictLookup(doc->dict, name, -1));
2295
484k
    else
2296
484k
  cur = xmlNewNode(ns, name);
2297
512k
    if (cur != NULL) {
2298
512k
        cur->doc = doc;
2299
512k
  if (content != NULL) {
2300
0
      cur->children = xmlStringGetNodeList(doc, content);
2301
0
      UPDATE_LAST_CHILD_AND_PARENT(cur)
2302
0
  }
2303
512k
    }
2304
2305
512k
    return(cur);
2306
512k
}
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.09M
              xmlChar *name, const xmlChar *content) {
2327
5.09M
    xmlNodePtr cur;
2328
2329
5.09M
    cur = xmlNewNodeEatName(ns, name);
2330
5.09M
    if (cur != NULL) {
2331
5.09M
        cur->doc = doc;
2332
5.09M
  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.09M
    } else {
2341
        /* if name don't come from the doc dictionary free it here */
2342
1.12k
        if ((name != NULL) &&
2343
1.12k
            ((doc == NULL) || (doc->dict == NULL) ||
2344
954
       (!(xmlDictOwns(doc->dict, name)))))
2345
471
      xmlFree(name);
2346
1.12k
    }
2347
5.09M
    return(cur);
2348
5.09M
}
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
0
                 const xmlChar *name, const xmlChar *content) {
2366
0
    xmlNodePtr cur;
2367
2368
0
    cur = xmlNewDocNode(doc, ns, name, NULL);
2369
0
    if (cur != NULL) {
2370
0
        cur->doc = doc;
2371
0
  if (content != NULL) {
2372
0
      cur->children = xmlNewDocText(doc, content);
2373
0
      UPDATE_LAST_CHILD_AND_PARENT(cur)
2374
0
  }
2375
0
    }
2376
0
    return(cur);
2377
0
}
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
894k
xmlNewText(const xmlChar *content) {
2419
894k
    xmlNodePtr cur;
2420
2421
    /*
2422
     * Allocate a new node and fill the fields.
2423
     */
2424
894k
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2425
894k
    if (cur == NULL)
2426
273
  return(NULL);
2427
893k
    memset(cur, 0, sizeof(xmlNode));
2428
893k
    cur->type = XML_TEXT_NODE;
2429
2430
893k
    cur->name = xmlStringText;
2431
893k
    if (content != NULL) {
2432
411k
  cur->content = xmlStrdup(content);
2433
411k
        if (cur->content == NULL)
2434
109
            goto error;
2435
411k
    }
2436
2437
893k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2438
0
  xmlRegisterNodeDefaultValue(cur);
2439
893k
    return(cur);
2440
2441
109
error:
2442
109
    xmlFreeNode(cur);
2443
109
    return(NULL);
2444
893k
}
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
0
            const xmlChar *name, const xmlChar *content) {
2469
0
    xmlNodePtr cur, prev;
2470
2471
0
    if (parent == NULL) {
2472
0
  return(NULL);
2473
0
    }
2474
2475
0
    if (name == NULL) {
2476
0
  return(NULL);
2477
0
    }
2478
2479
    /*
2480
     * Allocate a new node
2481
     */
2482
0
    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
0
    } else if ((parent->type == XML_DOCUMENT_NODE) ||
2488
0
         (parent->type == XML_HTML_DOCUMENT_NODE)) {
2489
0
  if (ns == NULL)
2490
0
      cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
2491
0
  else
2492
0
      cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
2493
0
    } 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
0
    if (cur == NULL) return(NULL);
2499
2500
    /*
2501
     * add the new element at the end of the children list.
2502
     */
2503
0
    cur->type = XML_ELEMENT_NODE;
2504
0
    cur->parent = parent;
2505
0
    cur->doc = parent->doc;
2506
0
    if (parent->children == NULL) {
2507
0
        parent->children = cur;
2508
0
  parent->last = cur;
2509
0
    } else {
2510
0
        prev = parent->last;
2511
0
  prev->next = cur;
2512
0
  cur->prev = prev;
2513
0
  parent->last = cur;
2514
0
    }
2515
2516
0
    return(cur);
2517
0
}
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
796k
xmlNewReference(const xmlDoc *doc, const xmlChar *name) {
2577
796k
    xmlNodePtr cur;
2578
796k
    xmlEntityPtr ent;
2579
2580
796k
    if (name == NULL)
2581
33
        return(NULL);
2582
2583
    /*
2584
     * Allocate a new node and fill the fields.
2585
     */
2586
796k
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2587
796k
    if (cur == NULL)
2588
113
  return(NULL);
2589
796k
    memset(cur, 0, sizeof(xmlNode));
2590
796k
    cur->type = XML_ENTITY_REF_NODE;
2591
2592
796k
    cur->doc = (xmlDoc *)doc;
2593
796k
    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
796k
  cur->name = xmlStrdup(name);
2603
796k
    if (cur->name == NULL)
2604
100
        goto error;
2605
2606
795k
    ent = xmlGetDocEntity(doc, cur->name);
2607
795k
    if (ent != NULL) {
2608
765k
  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
765k
  cur->children = (xmlNodePtr) ent;
2615
765k
  cur->last = (xmlNodePtr) ent;
2616
765k
    }
2617
2618
795k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2619
0
  xmlRegisterNodeDefaultValue(cur);
2620
795k
    return(cur);
2621
2622
100
error:
2623
100
    xmlFreeNode(cur);
2624
100
    return(NULL);
2625
796k
}
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
894k
xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
2637
894k
    xmlNodePtr cur;
2638
2639
894k
    cur = xmlNewText(content);
2640
894k
    if (cur != NULL) cur->doc = (xmlDoc *)doc;
2641
894k
    return(cur);
2642
894k
}
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
0
xmlNewTextLen(const xmlChar *content, int len) {
2656
0
    xmlNodePtr cur;
2657
2658
    /*
2659
     * Allocate a new node and fill the fields.
2660
     */
2661
0
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2662
0
    if (cur == NULL)
2663
0
  return(NULL);
2664
0
    memset(cur, 0, sizeof(xmlNode));
2665
0
    cur->type = XML_TEXT_NODE;
2666
2667
0
    cur->name = xmlStringText;
2668
0
    if (content != NULL) {
2669
0
  cur->content = xmlStrndup(content, len);
2670
0
    }
2671
2672
0
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2673
0
  xmlRegisterNodeDefaultValue(cur);
2674
0
    return(cur);
2675
0
}
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
4.21M
xmlNewComment(const xmlChar *content) {
2707
4.21M
    xmlNodePtr cur;
2708
2709
    /*
2710
     * Allocate a new node and fill the fields.
2711
     */
2712
4.21M
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2713
4.21M
    if (cur == NULL)
2714
86
  return(NULL);
2715
4.21M
    memset(cur, 0, sizeof(xmlNode));
2716
4.21M
    cur->type = XML_COMMENT_NODE;
2717
2718
4.21M
    cur->name = xmlStringComment;
2719
4.21M
    if (content != NULL) {
2720
4.21M
  cur->content = xmlStrdup(content);
2721
4.21M
        if (cur->content == NULL)
2722
78
            goto error;
2723
4.21M
    }
2724
2725
4.21M
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2726
0
  xmlRegisterNodeDefaultValue(cur);
2727
4.21M
    return(cur);
2728
2729
78
error:
2730
78
    xmlFreeNode(cur);
2731
78
    return(NULL);
2732
4.21M
}
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
152k
xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
2745
152k
    xmlNodePtr cur;
2746
2747
    /*
2748
     * Allocate a new node and fill the fields.
2749
     */
2750
152k
    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
2751
152k
    if (cur == NULL)
2752
43
  return(NULL);
2753
152k
    memset(cur, 0, sizeof(xmlNode));
2754
152k
    cur->type = XML_CDATA_SECTION_NODE;
2755
152k
    cur->doc = doc;
2756
2757
152k
    if (content != NULL) {
2758
152k
  cur->content = xmlStrndup(content, len);
2759
152k
        if (cur->content == NULL) {
2760
34
            xmlFree(cur);
2761
34
            return(NULL);
2762
34
        }
2763
152k
    }
2764
2765
152k
    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
2766
0
  xmlRegisterNodeDefaultValue(cur);
2767
152k
    return(cur);
2768
152k
}
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
4.21M
xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
2780
4.21M
    xmlNodePtr cur;
2781
2782
4.21M
    cur = xmlNewComment(content);
2783
4.21M
    if (cur != NULL) cur->doc = doc;
2784
4.21M
    return(cur);
2785
4.21M
}
2786
2787
49.6k
static const xmlChar *_copyStringForNewDictIfNeeded(xmlDictPtr oldDict, xmlDictPtr newDict, const xmlChar *oldValue) {
2788
49.6k
    const xmlChar *newValue = oldValue;
2789
49.6k
    if (oldValue) {
2790
38.2k
        int oldDictOwnsOldValue = oldDict && (xmlDictOwns(oldDict, oldValue) == 1);
2791
38.2k
        if (oldDictOwnsOldValue) {
2792
0
            if (newDict)
2793
0
                newValue = xmlDictLookup(newDict, oldValue, -1);
2794
0
            else
2795
0
                newValue = xmlStrdup(oldValue);
2796
0
        }
2797
38.2k
    }
2798
49.6k
    return newValue;
2799
49.6k
}
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
24.8k
xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
2810
24.8k
    xmlAttrPtr prop;
2811
2812
24.8k
    if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2813
0
  return;
2814
24.8k
    if (tree->doc != doc) {
2815
24.8k
        xmlDictPtr oldTreeDict = tree->doc ? tree->doc->dict : NULL;
2816
24.8k
        xmlDictPtr newDict = doc ? doc->dict : NULL;
2817
2818
24.8k
  if(tree->type == XML_ELEMENT_NODE) {
2819
0
      prop = tree->properties;
2820
0
      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
0
  }
2850
24.8k
        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
24.8k
        } else if (tree->children != NULL) {
2857
3.74k
      xmlSetListDoc(tree->children, doc);
2858
3.74k
        }
2859
2860
        /* TODO: malloc check */
2861
24.8k
        tree->name = _copyStringForNewDictIfNeeded(oldTreeDict, newDict, tree->name);
2862
24.8k
        tree->content = (xmlChar *)_copyStringForNewDictIfNeeded(oldTreeDict, NULL, tree->content);
2863
        /* FIXME: tree->ns should be updated as in xmlStaticCopyNode(). */
2864
24.8k
  tree->doc = doc;
2865
24.8k
    }
2866
24.8k
}
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
3.74k
xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
2877
3.74k
    xmlNodePtr cur;
2878
2879
3.74k
    if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
2880
0
  return;
2881
3.74k
    cur = list;
2882
17.3k
    while (cur != NULL) {
2883
13.6k
  if (cur->doc != doc)
2884
13.6k
      xmlSetTreeDoc(cur, doc);
2885
13.6k
  cur = cur->next;
2886
13.6k
    }
2887
3.74k
}
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
784k
xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
3032
784k
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3033
0
  return(NULL);
3034
0
    }
3035
784k
    if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3036
0
  return(NULL);
3037
0
    }
3038
3039
784k
    if (cur == elem) {
3040
0
  return(NULL);
3041
0
    }
3042
3043
784k
    xmlUnlinkNode(elem);
3044
3045
784k
    if (elem->type == XML_TEXT_NODE) {
3046
61.4k
  if (cur->type == XML_TEXT_NODE) {
3047
0
      xmlNodeAddContent(cur, elem->content);
3048
0
      xmlFreeNode(elem);
3049
0
      return(cur);
3050
0
  }
3051
61.4k
  if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
3052
61.4k
            (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
723k
    } else if (elem->type == XML_ATTRIBUTE_NODE) {
3064
0
    return xmlAddPropSibling(cur, cur, elem);
3065
0
    }
3066
3067
784k
    if (elem->doc != cur->doc) {
3068
0
  xmlSetTreeDoc(elem, cur->doc);
3069
0
    }
3070
784k
    elem->parent = cur->parent;
3071
784k
    elem->prev = cur;
3072
784k
    elem->next = cur->next;
3073
784k
    cur->next = elem;
3074
784k
    if (elem->next != NULL)
3075
10.3k
  elem->next->prev = elem;
3076
784k
    if ((elem->parent != NULL) && (elem->parent->last == cur))
3077
2.21k
  elem->parent->last = elem;
3078
784k
    return(elem);
3079
784k
}
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
8.51k
xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
3101
8.51k
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3102
0
  return(NULL);
3103
0
    }
3104
8.51k
    if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
3105
0
  return(NULL);
3106
0
    }
3107
3108
8.51k
    if (cur == elem) {
3109
0
  return(NULL);
3110
0
    }
3111
3112
8.51k
    xmlUnlinkNode(elem);
3113
3114
8.51k
    if (elem->type == XML_TEXT_NODE) {
3115
3.18k
  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
3.18k
  if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
3127
3.18k
            (cur->name == cur->prev->name)) {
3128
0
      xmlNodeAddContent(cur->prev, elem->content);
3129
0
      xmlFreeNode(elem);
3130
0
      return(cur->prev);
3131
0
  }
3132
5.32k
    } else if (elem->type == XML_ATTRIBUTE_NODE) {
3133
0
    return xmlAddPropSibling(cur->prev, cur, elem);
3134
0
    }
3135
3136
8.51k
    if (elem->doc != cur->doc) {
3137
0
  xmlSetTreeDoc(elem, cur->doc);
3138
0
    }
3139
8.51k
    elem->parent = cur->parent;
3140
8.51k
    elem->next = cur;
3141
8.51k
    elem->prev = cur->prev;
3142
8.51k
    cur->prev = elem;
3143
8.51k
    if (elem->prev != NULL)
3144
8.45k
  elem->prev->next = elem;
3145
8.51k
    if ((elem->parent != NULL) && (elem->parent->children == cur)) {
3146
61
    elem->parent->children = elem;
3147
61
    }
3148
8.51k
    return(elem);
3149
8.51k
}
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
15.4M
xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
3314
15.4M
    xmlNodePtr prev;
3315
3316
15.4M
    if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3317
3.50k
  return(NULL);
3318
3.50k
    }
3319
3320
15.4M
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
3321
0
  return(NULL);
3322
0
    }
3323
3324
15.4M
    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
15.4M
    if (cur->type == XML_TEXT_NODE) {
3332
3.55M
  if ((parent->type == XML_TEXT_NODE) &&
3333
3.55M
      (parent->content != NULL) &&
3334
3.55M
      (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.55M
  if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
3343
3.55M
      (parent->last->name == cur->name) &&
3344
3.55M
      (parent->last != cur)) {
3345
2.87k
      if (xmlNodeAddContent(parent->last, cur->content) != 0) {
3346
2
                xmlFreeNode(cur);
3347
2
                return(NULL);
3348
2
            }
3349
2.87k
      xmlFreeNode(cur);
3350
2.87k
      return(parent->last);
3351
2.87k
  }
3352
3.55M
    }
3353
3354
    /*
3355
     * add the new element at the end of the children list.
3356
     */
3357
15.4M
    prev = cur->parent;
3358
15.4M
    cur->parent = parent;
3359
15.4M
    if (cur->doc != parent->doc) {
3360
0
  xmlSetTreeDoc(cur, parent->doc);
3361
0
    }
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
15.4M
    if (prev == parent)
3366
3.11M
  return(cur);
3367
3368
    /*
3369
     * Coalescing
3370
     */
3371
12.3M
    if ((parent->type == XML_TEXT_NODE) &&
3372
12.3M
  (parent->content != NULL) &&
3373
12.3M
  (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.3M
    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.3M
    } else {
3413
12.3M
  if (parent->children == NULL) {
3414
1.95M
      parent->children = cur;
3415
1.95M
      parent->last = cur;
3416
10.3M
  } else {
3417
10.3M
      prev = parent->last;
3418
10.3M
      prev->next = cur;
3419
10.3M
      cur->prev = prev;
3420
10.3M
      parent->last = cur;
3421
10.3M
  }
3422
12.3M
    }
3423
12.3M
    return(cur);
3424
12.3M
}
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
126k
xmlGetLastChild(const xmlNode *parent) {
3435
126k
    if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
3436
0
  return(NULL);
3437
0
    }
3438
126k
    return(parent->last);
3439
126k
}
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.85M
xmlFreeNodeList(xmlNodePtr cur) {
3646
2.85M
    xmlNodePtr next;
3647
2.85M
    xmlNodePtr parent;
3648
2.85M
    xmlDictPtr dict = NULL;
3649
2.85M
    size_t depth = 0;
3650
3651
2.85M
    if (cur == NULL) return;
3652
2.80M
    if (cur->type == XML_NAMESPACE_DECL) {
3653
0
  xmlFreeNsList((xmlNsPtr) cur);
3654
0
  return;
3655
0
    }
3656
2.80M
    if (cur->doc != NULL) dict = cur->doc->dict;
3657
14.0M
    while (1) {
3658
16.9M
        while ((cur->children != NULL) &&
3659
16.9M
               (cur->type != XML_DOCUMENT_NODE) &&
3660
16.9M
               (cur->type != XML_HTML_DOCUMENT_NODE) &&
3661
16.9M
               (cur->type != XML_DTD_NODE) &&
3662
16.9M
               (cur->type != XML_ENTITY_REF_NODE)) {
3663
2.93M
            cur = cur->children;
3664
2.93M
            depth += 1;
3665
2.93M
        }
3666
3667
14.0M
        next = cur->next;
3668
14.0M
        parent = cur->parent;
3669
14.0M
  if ((cur->type == XML_DOCUMENT_NODE) ||
3670
14.0M
            (cur->type == XML_HTML_DOCUMENT_NODE)) {
3671
0
            xmlFreeDoc((xmlDocPtr) cur);
3672
14.0M
        } else if (cur->type != XML_DTD_NODE) {
3673
3674
14.0M
      if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3675
0
    xmlDeregisterNodeDefaultValue(cur);
3676
3677
14.0M
      if (((cur->type == XML_ELEMENT_NODE) ||
3678
14.0M
     (cur->type == XML_XINCLUDE_START) ||
3679
14.0M
     (cur->type == XML_XINCLUDE_END)) &&
3680
14.0M
    (cur->properties != NULL))
3681
2.08M
    xmlFreePropList(cur->properties);
3682
14.0M
      if ((cur->type != XML_ELEMENT_NODE) &&
3683
14.0M
    (cur->type != XML_XINCLUDE_START) &&
3684
14.0M
    (cur->type != XML_XINCLUDE_END) &&
3685
14.0M
    (cur->type != XML_ENTITY_REF_NODE) &&
3686
14.0M
    (cur->content != (xmlChar *) &(cur->properties))) {
3687
6.52M
    DICT_FREE(cur->content)
3688
6.52M
      }
3689
14.0M
      if (((cur->type == XML_ELEMENT_NODE) ||
3690
14.0M
           (cur->type == XML_XINCLUDE_START) ||
3691
14.0M
     (cur->type == XML_XINCLUDE_END)) &&
3692
14.0M
    (cur->nsDef != NULL))
3693
731k
    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
14.0M
      if ((cur->name != NULL) &&
3702
14.0M
    (cur->type != XML_TEXT_NODE) &&
3703
14.0M
    (cur->type != XML_COMMENT_NODE))
3704
6.89M
    DICT_FREE(cur->name)
3705
14.0M
      xmlFree(cur);
3706
14.0M
  }
3707
3708
14.0M
        if (next != NULL) {
3709
8.28M
      cur = next;
3710
8.28M
        } else {
3711
5.74M
            if ((depth == 0) || (parent == NULL))
3712
2.80M
                break;
3713
2.93M
            depth -= 1;
3714
2.93M
            cur = parent;
3715
2.93M
            cur->children = NULL;
3716
2.93M
        }
3717
14.0M
    }
3718
2.80M
}
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
3.82M
xmlFreeNode(xmlNodePtr cur) {
3729
3.82M
    xmlDictPtr dict = NULL;
3730
3731
3.82M
    if (cur == NULL) return;
3732
3733
    /* use xmlFreeDtd for DTD nodes */
3734
3.82M
    if (cur->type == XML_DTD_NODE) {
3735
0
  xmlFreeDtd((xmlDtdPtr) cur);
3736
0
  return;
3737
0
    }
3738
3.82M
    if (cur->type == XML_NAMESPACE_DECL) {
3739
0
  xmlFreeNs((xmlNsPtr) cur);
3740
0
        return;
3741
0
    }
3742
3.82M
    if (cur->type == XML_ATTRIBUTE_NODE) {
3743
0
  xmlFreeProp((xmlAttrPtr) cur);
3744
0
  return;
3745
0
    }
3746
3747
3.82M
    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
3748
0
  xmlDeregisterNodeDefaultValue(cur);
3749
3750
3.82M
    if (cur->doc != NULL) dict = cur->doc->dict;
3751
3752
3.82M
    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
3.82M
    if ((cur->children != NULL) &&
3758
3.82M
  (cur->type != XML_ENTITY_REF_NODE))
3759
3.44k
  xmlFreeNodeList(cur->children);
3760
3761
3.82M
    if ((cur->type == XML_ELEMENT_NODE) ||
3762
3.82M
        (cur->type == XML_XINCLUDE_START) ||
3763
3.82M
        (cur->type == XML_XINCLUDE_END)) {
3764
85.4k
        if (cur->properties != NULL)
3765
1.81k
            xmlFreePropList(cur->properties);
3766
85.4k
        if (cur->nsDef != NULL)
3767
428
            xmlFreeNsList(cur->nsDef);
3768
3.73M
    } else if ((cur->content != NULL) &&
3769
3.73M
               (cur->type != XML_ENTITY_REF_NODE) &&
3770
3.73M
               (cur->content != (xmlChar *) &(cur->properties))) {
3771
3.72M
        DICT_FREE(cur->content)
3772
3.72M
    }
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
3.82M
    if ((cur->name != NULL) &&
3780
3.82M
        (cur->type != XML_TEXT_NODE) &&
3781
3.82M
        (cur->type != XML_COMMENT_NODE))
3782
106k
  DICT_FREE(cur->name)
3783
3784
3.82M
    xmlFree(cur);
3785
3.82M
}
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
6.34M
xmlUnlinkNode(xmlNodePtr cur) {
3799
6.34M
    if (cur == NULL) {
3800
0
  return;
3801
0
    }
3802
6.34M
    if (cur->type == XML_NAMESPACE_DECL)
3803
0
        return;
3804
6.34M
    if (cur->type == XML_DTD_NODE) {
3805
143k
  xmlDocPtr doc;
3806
143k
  doc = cur->doc;
3807
143k
  if (doc != NULL) {
3808
143k
      if (doc->intSubset == (xmlDtdPtr) cur)
3809
136k
    doc->intSubset = NULL;
3810
143k
      if (doc->extSubset == (xmlDtdPtr) cur)
3811
7.73k
    doc->extSubset = NULL;
3812
143k
  }
3813
143k
    }
3814
6.34M
    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
6.34M
    if (cur->parent != NULL) {
3837
5.25M
  xmlNodePtr parent;
3838
5.25M
  parent = cur->parent;
3839
5.25M
  if (cur->type == XML_ATTRIBUTE_NODE) {
3840
519
      if (parent->properties == (xmlAttrPtr) cur)
3841
275
    parent->properties = ((xmlAttrPtr) cur)->next;
3842
5.25M
  } else {
3843
5.25M
      if (parent->children == cur)
3844
1.36M
    parent->children = cur->next;
3845
5.25M
      if (parent->last == cur)
3846
548k
    parent->last = cur->prev;
3847
5.25M
  }
3848
5.25M
  cur->parent = NULL;
3849
5.25M
    }
3850
6.34M
    if (cur->next != NULL)
3851
4.71M
        cur->next->prev = cur->prev;
3852
6.34M
    if (cur->prev != NULL)
3853
3.89M
        cur->prev->next = cur->next;
3854
6.34M
    cur->next = cur->prev = NULL;
3855
6.34M
}
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
235k
xmlCopyNamespace(xmlNsPtr cur) {
3933
235k
    xmlNsPtr ret;
3934
3935
235k
    if (cur == NULL) return(NULL);
3936
235k
    switch (cur->type) {
3937
235k
  case XML_LOCAL_NAMESPACE:
3938
235k
      ret = xmlNewNs(NULL, cur->href, cur->prefix);
3939
235k
      break;
3940
0
  default:
3941
0
      return(NULL);
3942
235k
    }
3943
235k
    return(ret);
3944
235k
}
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
201k
xmlCopyNamespaceList(xmlNsPtr cur) {
3956
201k
    xmlNsPtr ret = NULL;
3957
201k
    xmlNsPtr p = NULL,q;
3958
3959
437k
    while (cur != NULL) {
3960
235k
        q = xmlCopyNamespace(cur);
3961
235k
        if (q == NULL) {
3962
332
            xmlFreeNsList(ret);
3963
332
            return(NULL);
3964
332
        }
3965
235k
  if (p == NULL) {
3966
201k
      ret = p = q;
3967
201k
  } else {
3968
34.2k
      p->next = q;
3969
34.2k
      p = q;
3970
34.2k
  }
3971
235k
  cur = cur->next;
3972
235k
    }
3973
201k
    return(ret);
3974
201k
}
3975
3976
static xmlAttrPtr
3977
561k
xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
3978
561k
    xmlAttrPtr ret = NULL;
3979
3980
561k
    if (cur == NULL) return(NULL);
3981
561k
    if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
3982
0
        return(NULL);
3983
561k
    if (target != NULL)
3984
561k
  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
561k
    if (ret == NULL) return(NULL);
3994
561k
    ret->parent = target;
3995
3996
561k
    if ((cur->ns != NULL) && (target != NULL)) {
3997
96.4k
      xmlNsPtr ns;
3998
3999
96.4k
      ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
4000
96.4k
      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
166
        ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
4007
166
        if (ns != NULL) {
4008
166
          xmlNodePtr root = target;
4009
166
          xmlNodePtr pred = NULL;
4010
4011
1.43k
          while (root->parent != NULL) {
4012
1.26k
            pred = root;
4013
1.26k
            root = root->parent;
4014
1.26k
          }
4015
166
          if (root == (xmlNodePtr) target->doc) {
4016
            /* correct possibly cycling above the document elt */
4017
0
            root = pred;
4018
0
          }
4019
166
          ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4020
166
          if (ret->ns == NULL)
4021
0
              goto error;
4022
166
        }
4023
96.2k
      } 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
96.2k
        if (xmlStrEqual(ns->href, cur->ns->href)) {
4030
          /* this is the nice case */
4031
95.1k
          ret->ns = ns;
4032
95.1k
        } else {
4033
          /*
4034
           * we are in trouble: we need a new reconciled namespace.
4035
           * This is expensive
4036
           */
4037
1.06k
          ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns);
4038
1.06k
          if (ret->ns == NULL)
4039
1
              goto error;
4040
1.06k
        }
4041
96.2k
      }
4042
4043
96.4k
    } else
4044
465k
        ret->ns = NULL;
4045
4046
561k
    if (cur->children != NULL) {
4047
529k
  xmlNodePtr tmp;
4048
4049
529k
  ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
4050
529k
        if (ret->children == NULL)
4051
255
            goto error;
4052
529k
  ret->last = NULL;
4053
529k
  tmp = ret->children;
4054
1.06M
  while (tmp != NULL) {
4055
      /* tmp->parent = (xmlNodePtr)ret; */
4056
532k
      if (tmp->next == NULL)
4057
529k
          ret->last = tmp;
4058
532k
      tmp = tmp->next;
4059
532k
  }
4060
529k
    }
4061
    /*
4062
     * Try to handle IDs
4063
     */
4064
561k
    if ((target != NULL) && (cur != NULL) &&
4065
561k
  (target->doc != NULL) && (cur->doc != NULL) &&
4066
561k
  (cur->doc->ids != NULL) &&
4067
561k
        (cur->parent != NULL) &&
4068
561k
        (cur->children != NULL)) {
4069
161k
        int res = xmlIsID(cur->doc, cur->parent, cur);
4070
4071
161k
        if (res < 0)
4072
3
            goto error;
4073
161k
  if (res != 0) {
4074
86.2k
      xmlChar *id;
4075
4076
86.2k
      id = xmlNodeListGetString(cur->doc, cur->children, 1);
4077
86.2k
      if (id == NULL)
4078
23
                goto error;
4079
86.2k
            res = xmlAddIDSafe(target->doc, id, ret, 0, NULL);
4080
86.2k
      xmlFree(id);
4081
86.2k
            if (res < 0)
4082
21
                goto error;
4083
86.2k
  }
4084
161k
    }
4085
561k
    return(ret);
4086
4087
303
error:
4088
303
    xmlFreeProp(ret);
4089
303
    return(NULL);
4090
561k
}
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
561k
xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
4103
561k
  return xmlCopyPropInternal(NULL, target, cur);
4104
561k
}
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
453k
xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
4117
453k
    xmlAttrPtr ret = NULL;
4118
453k
    xmlAttrPtr p = NULL,q;
4119
4120
453k
    if ((target != NULL) && (target->type != XML_ELEMENT_NODE))
4121
0
        return(NULL);
4122
1.01M
    while (cur != NULL) {
4123
561k
        q = xmlCopyProp(target, cur);
4124
561k
  if (q == NULL) {
4125
596
            xmlFreePropList(ret);
4126
596
      return(NULL);
4127
596
        }
4128
561k
  if (p == NULL) {
4129
452k
      ret = p = q;
4130
452k
  } else {
4131
108k
      p->next = q;
4132
108k
      q->prev = p;
4133
108k
      p = q;
4134
108k
  }
4135
561k
  cur = cur->next;
4136
561k
    }
4137
452k
    return(ret);
4138
453k
}
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
3.41M
                  int extended) {
4162
3.41M
    xmlNodePtr ret;
4163
4164
3.41M
    if (node == NULL) return(NULL);
4165
3.41M
    switch (node->type) {
4166
1.44M
        case XML_TEXT_NODE:
4167
1.52M
        case XML_CDATA_SECTION_NODE:
4168
3.04M
        case XML_ELEMENT_NODE:
4169
3.04M
        case XML_DOCUMENT_FRAG_NODE:
4170
3.05M
        case XML_ENTITY_REF_NODE:
4171
3.05M
        case XML_ENTITY_NODE:
4172
3.07M
        case XML_PI_NODE:
4173
3.39M
        case XML_COMMENT_NODE:
4174
3.40M
        case XML_XINCLUDE_START:
4175
3.41M
        case XML_XINCLUDE_END:
4176
3.41M
      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
3.41M
    }
4195
4196
    /*
4197
     * Allocate a new node and fill the fields.
4198
     */
4199
3.41M
    ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4200
3.41M
    if (ret == NULL)
4201
740
  return(NULL);
4202
3.41M
    memset(ret, 0, sizeof(xmlNode));
4203
3.41M
    ret->type = node->type;
4204
4205
3.41M
    ret->doc = doc;
4206
3.41M
    ret->parent = parent;
4207
3.41M
    if (node->name == xmlStringText)
4208
1.44M
  ret->name = xmlStringText;
4209
1.96M
    else if (node->name == xmlStringTextNoenc)
4210
0
  ret->name = xmlStringTextNoenc;
4211
1.96M
    else if (node->name == xmlStringComment)
4212
319k
  ret->name = xmlStringComment;
4213
1.65M
    else if (node->name != NULL) {
4214
1.57M
        if ((doc != NULL) && (doc->dict != NULL))
4215
336k
      ret->name = xmlDictLookup(doc->dict, node->name, -1);
4216
1.24M
  else
4217
1.24M
      ret->name = xmlStrdup(node->name);
4218
1.57M
        if (ret->name == NULL)
4219
336
            goto error;
4220
1.57M
    }
4221
3.41M
    if ((node->type != XML_ELEMENT_NODE) &&
4222
3.41M
  (node->content != NULL) &&
4223
3.41M
  (node->type != XML_ENTITY_REF_NODE) &&
4224
3.41M
  (node->type != XML_XINCLUDE_END) &&
4225
3.41M
  (node->type != XML_XINCLUDE_START)) {
4226
1.84M
  ret->content = xmlStrdup(node->content);
4227
1.84M
        if (ret->content == NULL)
4228
333
            goto error;
4229
1.84M
    }else{
4230
1.56M
      if (node->type == XML_ELEMENT_NODE)
4231
1.52M
        ret->line = node->line;
4232
1.56M
    }
4233
3.41M
    if (parent != NULL) {
4234
3.10M
  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.10M
  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.10M
        tmp = xmlAddChild(parent, ret);
4253
  /* node could have coalesced */
4254
3.10M
  if (tmp != ret)
4255
2.87k
      return(tmp);
4256
3.10M
    }
4257
4258
3.41M
    if (!extended)
4259
707
  goto out;
4260
3.41M
    if (((node->type == XML_ELEMENT_NODE) ||
4261
3.41M
         (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL)) {
4262
186k
        ret->nsDef = xmlCopyNamespaceList(node->nsDef);
4263
186k
        if (ret->nsDef == NULL)
4264
199
            goto error;
4265
186k
    }
4266
4267
3.41M
    if ((node->type == XML_ELEMENT_NODE) && (node->ns != NULL)) {
4268
324k
        xmlNsPtr ns;
4269
4270
324k
  ns = xmlSearchNs(doc, ret, node->ns->prefix);
4271
324k
  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
1.11k
      ns = xmlSearchNs(node->doc, node, node->ns->prefix);
4281
1.11k
      if (ns != NULL) {
4282
1.11k
          xmlNodePtr root = ret;
4283
4284
4.93k
    while (root->parent != NULL) root = root->parent;
4285
1.11k
    ret->ns = xmlNewNs(root, ns->href, ns->prefix);
4286
1.11k
            } else {
4287
0
                ret->ns = xmlNewReconciledNs(doc, ret, node->ns);
4288
0
      }
4289
1.11k
            if (ret->ns == NULL)
4290
0
                goto error;
4291
323k
  } else {
4292
      /*
4293
       * reference the existing namespace definition in our own tree.
4294
       */
4295
323k
      ret->ns = ns;
4296
323k
  }
4297
324k
    }
4298
3.41M
    if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL)) {
4299
453k
        ret->properties = xmlCopyPropList(ret, node->properties);
4300
453k
        if (ret->properties == NULL)
4301
596
            goto error;
4302
453k
    }
4303
3.41M
    if (node->type == XML_ENTITY_REF_NODE) {
4304
9.57k
  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
6.52k
      ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name);
4312
6.52k
  } else {
4313
3.04k
            ret->children = node->children;
4314
3.04k
  }
4315
9.57k
  ret->last = ret->children;
4316
3.40M
    } else if ((node->children != NULL) && (extended != 2)) {
4317
38.9k
        xmlNodePtr cur, insert;
4318
4319
38.9k
        cur = node->children;
4320
38.9k
        insert = ret;
4321
2.36M
        while (cur != NULL) {
4322
2.32M
            xmlNodePtr copy = xmlStaticCopyNode(cur, doc, insert, 2);
4323
2.32M
            if (copy == NULL)
4324
1.37k
                goto error;
4325
4326
            /* Check for coalesced text nodes */
4327
2.32M
            if (insert->last != copy) {
4328
2.32M
                if (insert->last == NULL) {
4329
696k
                    insert->children = copy;
4330
1.62M
                } else {
4331
1.62M
                    copy->prev = insert->last;
4332
1.62M
                    insert->last->next = copy;
4333
1.62M
                }
4334
2.32M
                insert->last = copy;
4335
2.32M
            }
4336
4337
2.32M
            if ((cur->type != XML_ENTITY_REF_NODE) &&
4338
2.32M
                (cur->children != NULL)) {
4339
658k
                cur = cur->children;
4340
658k
                insert = copy;
4341
658k
                continue;
4342
658k
            }
4343
4344
2.31M
            while (1) {
4345
2.31M
                if (cur->next != NULL) {
4346
1.63M
                    cur = cur->next;
4347
1.63M
                    break;
4348
1.63M
                }
4349
4350
680k
                cur = cur->parent;
4351
680k
                insert = insert->parent;
4352
680k
                if (cur == node) {
4353
37.5k
                    cur = NULL;
4354
37.5k
                    break;
4355
37.5k
                }
4356
680k
            }
4357
1.66M
        }
4358
38.9k
    }
4359
4360
3.41M
out:
4361
    /* if parent != NULL we already registered the node above */
4362
3.41M
    if ((parent == NULL) &&
4363
3.41M
        ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)))
4364
0
  xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
4365
3.41M
    return(ret);
4366
4367
2.83k
error:
4368
2.83k
    xmlFreeNode(ret);
4369
2.83k
    return(NULL);
4370
3.41M
}
4371
4372
xmlNodePtr
4373
552k
xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
4374
552k
    xmlNodePtr ret = NULL;
4375
552k
    xmlNodePtr p = NULL,q;
4376
552k
    xmlDtdPtr newSubset = NULL;
4377
552k
    int linkedSubset = 0;
4378
4379
1.25M
    while (node != NULL) {
4380
701k
#ifdef LIBXML_TREE_ENABLED
4381
701k
  if (node->type == XML_DTD_NODE ) {
4382
11.1k
      if (doc == NULL) {
4383
0
    node = node->next;
4384
0
    continue;
4385
0
      }
4386
11.1k
      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
11.1k
      } else {
4394
11.1k
                linkedSubset = 1;
4395
11.1k
    q = (xmlNodePtr) doc->intSubset;
4396
11.1k
    xmlAddChild(parent, q);
4397
11.1k
      }
4398
11.1k
  } else
4399
690k
#endif /* LIBXML_TREE_ENABLED */
4400
690k
      q = xmlStaticCopyNode(node, doc, parent, 1);
4401
701k
  if (q == NULL) goto error;
4402
699k
  if (ret == NULL) {
4403
551k
      q->prev = NULL;
4404
551k
      ret = p = q;
4405
551k
  } else if (p != q) {
4406
  /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */
4407
148k
      p->next = q;
4408
148k
      q->prev = p;
4409
148k
      p = q;
4410
148k
  }
4411
699k
  node = node->next;
4412
699k
    }
4413
550k
    if ((doc != NULL) && (newSubset != NULL))
4414
0
        doc->intSubset = newSubset;
4415
550k
    return(ret);
4416
1.50k
error:
4417
1.50k
    xmlFreeNodeList(ret);
4418
1.50k
    if (linkedSubset != 0) {
4419
646
        doc->intSubset->next = NULL;
4420
646
        doc->intSubset->prev = NULL;
4421
646
    }
4422
1.50k
    return(NULL);
4423
552k
}
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
713
xmlCopyNode(xmlNodePtr node, int extended) {
4438
713
    xmlNodePtr ret;
4439
4440
713
    ret = xmlStaticCopyNode(node, NULL, NULL, extended);
4441
713
    return(ret);
4442
713
}
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
291k
xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
4458
291k
    xmlNodePtr ret;
4459
4460
291k
    ret = xmlStaticCopyNode(node, doc, NULL, extended);
4461
291k
    return(ret);
4462
291k
}
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
11.6k
xmlCopyDtd(xmlDtdPtr dtd) {
4503
11.6k
    xmlDtdPtr ret;
4504
11.6k
    xmlNodePtr cur, p = NULL, q;
4505
4506
11.6k
    if (dtd == NULL) return(NULL);
4507
11.6k
    ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
4508
11.6k
    if (ret == NULL) return(NULL);
4509
11.4k
    if (dtd->entities != NULL) {
4510
1.38k
        ret->entities = (void *) xmlCopyEntitiesTable(
4511
1.38k
                      (xmlEntitiesTablePtr) dtd->entities);
4512
1.38k
        if (ret->entities == NULL)
4513
45
            goto error;
4514
1.38k
    }
4515
11.3k
    if (dtd->notations != NULL) {
4516
66
        ret->notations = (void *) xmlCopyNotationTable(
4517
66
                      (xmlNotationTablePtr) dtd->notations);
4518
66
        if (ret->notations == NULL)
4519
7
            goto error;
4520
66
    }
4521
11.3k
    if (dtd->elements != NULL) {
4522
2.49k
        ret->elements = (void *) xmlCopyElementTable(
4523
2.49k
                      (xmlElementTablePtr) dtd->elements);
4524
2.49k
        if (ret->elements == NULL)
4525
81
            goto error;
4526
2.49k
    }
4527
11.3k
    if (dtd->attributes != NULL) {
4528
2.05k
        ret->attributes = (void *) xmlCopyAttributeTable(
4529
2.05k
                      (xmlAttributeTablePtr) dtd->attributes);
4530
2.05k
        if (ret->attributes == NULL)
4531
69
            goto error;
4532
2.05k
    }
4533
11.2k
    if (dtd->pentities != NULL) {
4534
662
  ret->pentities = (void *) xmlCopyEntitiesTable(
4535
662
          (xmlEntitiesTablePtr) dtd->pentities);
4536
662
        if (ret->pentities == NULL)
4537
17
            goto error;
4538
662
    }
4539
4540
11.2k
    cur = dtd->children;
4541
26.2k
    while (cur != NULL) {
4542
14.9k
  q = NULL;
4543
4544
14.9k
  if (cur->type == XML_ENTITY_DECL) {
4545
3.99k
      xmlEntityPtr tmp = (xmlEntityPtr) cur;
4546
3.99k
      switch (tmp->etype) {
4547
2.37k
    case XML_INTERNAL_GENERAL_ENTITY:
4548
2.90k
    case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
4549
3.03k
    case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
4550
3.03k
        q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name);
4551
3.03k
        break;
4552
472
    case XML_INTERNAL_PARAMETER_ENTITY:
4553
957
    case XML_EXTERNAL_PARAMETER_ENTITY:
4554
957
        q = (xmlNodePtr)
4555
957
      xmlGetParameterEntityFromDtd(ret, tmp->name);
4556
957
        break;
4557
0
    case XML_INTERNAL_PREDEFINED_ENTITY:
4558
0
        break;
4559
3.99k
      }
4560
10.9k
  } else if (cur->type == XML_ELEMENT_DECL) {
4561
2.70k
      xmlElementPtr tmp = (xmlElementPtr) cur;
4562
2.70k
      q = (xmlNodePtr)
4563
2.70k
    xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix);
4564
8.29k
  } else if (cur->type == XML_ATTRIBUTE_DECL) {
4565
6.31k
      xmlAttributePtr tmp = (xmlAttributePtr) cur;
4566
6.31k
      q = (xmlNodePtr)
4567
6.31k
    xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix);
4568
6.31k
  } else if (cur->type == XML_COMMENT_NODE) {
4569
713
      q = xmlCopyNode(cur, 0);
4570
713
            if (q == NULL)
4571
6
                goto error;
4572
713
  }
4573
4574
14.9k
  if (q == NULL) {
4575
1.26k
      cur = cur->next;
4576
1.26k
      continue;
4577
1.26k
  }
4578
4579
13.7k
  if (p == NULL)
4580
3.75k
      ret->children = q;
4581
9.96k
  else
4582
9.96k
      p->next = q;
4583
4584
13.7k
  q->prev = p;
4585
13.7k
  q->parent = (xmlNodePtr) ret;
4586
13.7k
  q->next = NULL;
4587
13.7k
  ret->last = q;
4588
13.7k
  p = q;
4589
13.7k
  cur = cur->next;
4590
13.7k
    }
4591
4592
11.2k
    return(ret);
4593
4594
225
error:
4595
225
    xmlFreeDtd(ret);
4596
225
    return(NULL);
4597
11.2k
}
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
34.5k
xmlCopyDoc(xmlDocPtr doc, int recursive) {
4613
34.5k
    xmlDocPtr ret;
4614
4615
34.5k
    if (doc == NULL) return(NULL);
4616
25.0k
    ret = xmlNewDoc(doc->version);
4617
25.0k
    if (ret == NULL) return(NULL);
4618
24.8k
    ret->type = doc->type;
4619
24.8k
    if (doc->name != NULL) {
4620
0
        ret->name = xmlMemStrdup(doc->name);
4621
0
        if (ret->name == NULL)
4622
0
            goto error;
4623
0
    }
4624
24.8k
    if (doc->encoding != NULL) {
4625
5.23k
        ret->encoding = xmlStrdup(doc->encoding);
4626
5.23k
        if (ret->encoding == NULL)
4627
18
            goto error;
4628
5.23k
    }
4629
24.8k
    if (doc->URL != NULL) {
4630
15.0k
        ret->URL = xmlStrdup(doc->URL);
4631
15.0k
        if (ret->URL == NULL)
4632
52
            goto error;
4633
15.0k
    }
4634
24.7k
    ret->charset = doc->charset;
4635
24.7k
    ret->compression = doc->compression;
4636
24.7k
    ret->standalone = doc->standalone;
4637
24.7k
    if (!recursive) return(ret);
4638
4639
24.7k
    ret->last = NULL;
4640
24.7k
    ret->children = NULL;
4641
24.7k
#ifdef LIBXML_TREE_ENABLED
4642
24.7k
    if (doc->intSubset != NULL) {
4643
11.6k
        ret->intSubset = xmlCopyDtd(doc->intSubset);
4644
11.6k
  if (ret->intSubset == NULL)
4645
401
            goto error;
4646
11.2k
  xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
4647
11.2k
  ret->intSubset->parent = ret;
4648
11.2k
    }
4649
24.3k
#endif
4650
24.3k
    if (doc->oldNs != NULL) {
4651
14.6k
        ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
4652
14.6k
        if (ret->oldNs == NULL)
4653
133
            goto error;
4654
14.6k
    }
4655
24.2k
    if (doc->children != NULL) {
4656
22.7k
  xmlNodePtr tmp;
4657
4658
22.7k
  ret->children = xmlStaticCopyNodeList(doc->children, ret,
4659
22.7k
                                   (xmlNodePtr)ret);
4660
22.7k
        if (ret->children == NULL)
4661
1.25k
            goto error;
4662
21.5k
  ret->last = NULL;
4663
21.5k
  tmp = ret->children;
4664
161k
  while (tmp != NULL) {
4665
140k
      if (tmp->next == NULL)
4666
21.5k
          ret->last = tmp;
4667
140k
      tmp = tmp->next;
4668
140k
  }
4669
21.5k
    }
4670
22.9k
    return(ret);
4671
4672
1.85k
error:
4673
1.85k
    xmlFreeDoc(ret);
4674
1.85k
    return(NULL);
4675
24.2k
}
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
2.15M
{
4697
2.15M
    long result = -1;
4698
4699
2.15M
    if (depth >= 5)
4700
233k
        return(-1);
4701
4702
1.92M
    if (!node)
4703
0
        return result;
4704
1.92M
    if ((node->type == XML_ELEMENT_NODE) ||
4705
1.92M
        (node->type == XML_TEXT_NODE) ||
4706
1.92M
  (node->type == XML_COMMENT_NODE) ||
4707
1.92M
  (node->type == XML_PI_NODE)) {
4708
1.89M
  if (node->line == 65535) {
4709
1.48M
      if ((node->type == XML_TEXT_NODE) && (node->psvi != NULL))
4710
70.0k
          result = (long) (ptrdiff_t) node->psvi;
4711
1.41M
      else if ((node->type == XML_ELEMENT_NODE) &&
4712
1.41M
               (node->children != NULL))
4713
806k
          result = xmlGetLineNoInternal(node->children, depth + 1);
4714
607k
      else if (node->next != NULL)
4715
430k
          result = xmlGetLineNoInternal(node->next, depth + 1);
4716
176k
      else if (node->prev != NULL)
4717
108k
          result = xmlGetLineNoInternal(node->prev, depth + 1);
4718
1.48M
  }
4719
1.89M
  if ((result == -1) || (result == 65535))
4720
1.65M
      result = (long) node->line;
4721
1.89M
    } else if ((node->prev != NULL) &&
4722
20.0k
             ((node->prev->type == XML_ELEMENT_NODE) ||
4723
3.15k
        (node->prev->type == XML_TEXT_NODE) ||
4724
3.15k
        (node->prev->type == XML_COMMENT_NODE) ||
4725
3.15k
        (node->prev->type == XML_PI_NODE)))
4726
3.08k
        result = xmlGetLineNoInternal(node->prev, depth + 1);
4727
17.0k
    else if ((node->parent != NULL) &&
4728
17.0k
             (node->parent->type == XML_ELEMENT_NODE))
4729
408
        result = xmlGetLineNoInternal(node->parent, depth + 1);
4730
4731
1.92M
    return result;
4732
1.92M
}
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
804k
{
4747
804k
    return(xmlGetLineNoInternal(node, 0));
4748
804k
}
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
137k
xmlDocGetRootElement(const xmlDoc *doc) {
5005
137k
    xmlNodePtr ret;
5006
5007
137k
    if (doc == NULL) return(NULL);
5008
137k
    ret = doc->children;
5009
195k
    while (ret != NULL) {
5010
189k
  if (ret->type == XML_ELEMENT_NODE)
5011
131k
      return(ret);
5012
58.0k
        ret = ret->next;
5013
58.0k
    }
5014
6.72k
    return(ret);
5015
137k
}
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
void
5140
0
xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
5141
0
    xmlNsPtr ns;
5142
5143
0
    if (cur == NULL) return;
5144
0
    switch(cur->type) {
5145
0
        case XML_TEXT_NODE:
5146
0
        case XML_CDATA_SECTION_NODE:
5147
0
        case XML_COMMENT_NODE:
5148
0
        case XML_DOCUMENT_NODE:
5149
0
        case XML_DOCUMENT_TYPE_NODE:
5150
0
        case XML_DOCUMENT_FRAG_NODE:
5151
0
        case XML_NOTATION_NODE:
5152
0
        case XML_HTML_DOCUMENT_NODE:
5153
0
        case XML_DTD_NODE:
5154
0
        case XML_ELEMENT_DECL:
5155
0
        case XML_ATTRIBUTE_DECL:
5156
0
        case XML_ENTITY_DECL:
5157
0
        case XML_PI_NODE:
5158
0
        case XML_ENTITY_REF_NODE:
5159
0
        case XML_ENTITY_NODE:
5160
0
  case XML_NAMESPACE_DECL:
5161
0
  case XML_XINCLUDE_START:
5162
0
  case XML_XINCLUDE_END:
5163
0
      return;
5164
0
        case XML_ELEMENT_NODE:
5165
0
        case XML_ATTRIBUTE_NODE:
5166
0
      break;
5167
0
    }
5168
0
    ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
5169
0
    if (ns == NULL)
5170
0
  return;
5171
0
    switch (val) {
5172
0
    case 0:
5173
0
  xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
5174
0
  break;
5175
0
    case 1:
5176
0
  xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
5177
0
  break;
5178
0
    }
5179
0
}
5180
#endif /* LIBXML_TREE_ENABLED */
5181
5182
/**
5183
 * xmlNodeGetSpacePreserve:
5184
 * @cur:  the node being checked
5185
 *
5186
 * Searches the space preserving behaviour of a node, i.e. the values
5187
 * of the xml:space attribute or the one carried by the nearest
5188
 * ancestor.
5189
 *
5190
 * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve"
5191
 */
5192
int
5193
409k
xmlNodeGetSpacePreserve(const xmlNode *cur) {
5194
409k
    xmlChar *space;
5195
5196
409k
    if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
5197
409k
        return(-1);
5198
0
    while (cur != NULL) {
5199
0
  space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
5200
0
  if (space != NULL) {
5201
0
      if (xmlStrEqual(space, BAD_CAST "preserve")) {
5202
0
    xmlFree(space);
5203
0
    return(1);
5204
0
      }
5205
0
      if (xmlStrEqual(space, BAD_CAST "default")) {
5206
0
    xmlFree(space);
5207
0
    return(0);
5208
0
      }
5209
0
      xmlFree(space);
5210
0
  }
5211
0
  cur = cur->parent;
5212
0
    }
5213
0
    return(-1);
5214
0
}
5215
5216
#ifdef LIBXML_TREE_ENABLED
5217
/**
5218
 * xmlNodeSetName:
5219
 * @cur:  the node being changed
5220
 * @name:  the new tag name
5221
 *
5222
 * Set (or reset) the name of a node.
5223
 */
5224
void
5225
0
xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
5226
0
    xmlDocPtr doc;
5227
0
    xmlDictPtr dict;
5228
0
    const xmlChar *freeme = NULL;
5229
5230
0
    if (cur == NULL) return;
5231
0
    if (name == NULL) return;
5232
0
    switch(cur->type) {
5233
0
        case XML_TEXT_NODE:
5234
0
        case XML_CDATA_SECTION_NODE:
5235
0
        case XML_COMMENT_NODE:
5236
0
        case XML_DOCUMENT_TYPE_NODE:
5237
0
        case XML_DOCUMENT_FRAG_NODE:
5238
0
        case XML_NOTATION_NODE:
5239
0
        case XML_HTML_DOCUMENT_NODE:
5240
0
  case XML_NAMESPACE_DECL:
5241
0
  case XML_XINCLUDE_START:
5242
0
  case XML_XINCLUDE_END:
5243
0
      return;
5244
0
        case XML_ELEMENT_NODE:
5245
0
        case XML_ATTRIBUTE_NODE:
5246
0
        case XM