Coverage Report

Created: 2025-08-29 06:18

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