Coverage Report

Created: 2025-08-26 06:42

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