Coverage Report

Created: 2025-07-18 06:56

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