Coverage Report

Created: 2026-09-03 06:06

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