Coverage Report

Created: 2022-06-08 06:16

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