Coverage Report

Created: 2023-11-19 06:13

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