Coverage Report

Created: 2023-12-13 20:03

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