Coverage Report

Created: 2025-07-01 06:27

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