Coverage Report

Created: 2024-02-11 06:23

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