Coverage Report

Created: 2024-08-27 12:19

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