Coverage Report

Created: 2024-02-28 06:07

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