Coverage Report

Created: 2025-08-04 07:15

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