Coverage Report

Created: 2022-11-15 06:34

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