Coverage Report

Created: 2023-06-07 06:14

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