Coverage Report

Created: 2025-07-23 08:13

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