Coverage Report

Created: 2024-02-11 06:24

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