Coverage Report

Created: 2025-06-22 06:55

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