Coverage Report

Created: 2024-01-18 09:16

/src/libxml2/xinclude.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xinclude.c : Code to implement XInclude processing
3
 *
4
 * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003
5
 * http://www.w3.org/TR/2003/WD-xinclude-20031110
6
 *
7
 * See Copyright for the status of this software.
8
 *
9
 * daniel@veillard.com
10
 */
11
12
#define IN_LIBXML
13
#include "libxml.h"
14
15
#include <string.h>
16
#include <libxml/xmlmemory.h>
17
#include <libxml/tree.h>
18
#include <libxml/parser.h>
19
#include <libxml/uri.h>
20
#include <libxml/xpath.h>
21
#include <libxml/xpointer.h>
22
#include <libxml/parserInternals.h>
23
#include <libxml/xmlerror.h>
24
#include <libxml/encoding.h>
25
#include <libxml/globals.h>
26
27
#ifdef LIBXML_XINCLUDE_ENABLED
28
#include <libxml/xinclude.h>
29
30
#include "private/buf.h"
31
#include "private/error.h"
32
33
222k
#define XINCLUDE_MAX_DEPTH 40
34
35
/* #define DEBUG_XINCLUDE */
36
#ifdef DEBUG_XINCLUDE
37
#ifdef LIBXML_DEBUG_ENABLED
38
#include <libxml/debugXML.h>
39
#endif
40
#endif
41
42
/************************************************************************
43
 *                  *
44
 *      XInclude context handling     *
45
 *                  *
46
 ************************************************************************/
47
48
/*
49
 * An XInclude context
50
 */
51
typedef xmlChar *xmlURL;
52
53
typedef struct _xmlXIncludeRef xmlXIncludeRef;
54
typedef xmlXIncludeRef *xmlXIncludeRefPtr;
55
struct _xmlXIncludeRef {
56
    xmlChar              *URI; /* the fully resolved resource URL */
57
    xmlChar         *fragment; /* the fragment in the URI */
58
    xmlDocPtr     doc; /* the parsed document */
59
    xmlNodePtr            ref; /* the node making the reference in the source */
60
    xmlNodePtr            inc; /* the included copy */
61
    int                   xml; /* xml or txt */
62
    int                 count; /* how many refs use that specific doc */
63
    xmlXPathObjectPtr    xptr; /* the xpointer if needed */
64
    int              fallback; /* fallback was loaded */
65
    int         emptyFb; /* flag to show fallback empty */
66
};
67
68
struct _xmlXIncludeCtxt {
69
    xmlDocPtr             doc; /* the source document */
70
    int               incBase; /* the first include for this document */
71
    int                 incNr; /* number of includes */
72
    int                incMax; /* size of includes tab */
73
    xmlXIncludeRefPtr *incTab; /* array of included references */
74
75
    int                 txtNr; /* number of unparsed documents */
76
    int                txtMax; /* size of unparsed documents tab */
77
    xmlChar *         *txtTab; /* array of unparsed text strings */
78
    xmlURL         *txturlTab; /* array of unparsed text URLs */
79
80
    xmlChar *             url; /* the current URL processed */
81
    int                 urlNr; /* number of URLs stacked */
82
    int                urlMax; /* size of URL stack */
83
    xmlChar *         *urlTab; /* URL stack */
84
85
    int              nbErrors; /* the number of errors detected */
86
    int                legacy; /* using XINCLUDE_OLD_NS */
87
    int            parseFlags; /* the flags used for parsing XML documents */
88
    xmlChar *    base; /* the current xml:base */
89
90
    void            *_private; /* application data */
91
92
    unsigned long    incTotal; /* total number of processed inclusions */
93
};
94
95
static int
96
xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree,
97
                     int skipRoot);
98
99
100
/************************************************************************
101
 *                  *
102
 *      XInclude error handler        *
103
 *                  *
104
 ************************************************************************/
105
106
/**
107
 * xmlXIncludeErrMemory:
108
 * @extra:  extra information
109
 *
110
 * Handle an out of memory condition
111
 */
112
static void
113
xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
114
                     const char *extra)
115
0
{
116
0
    if (ctxt != NULL)
117
0
  ctxt->nbErrors++;
118
0
    __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
119
0
                    XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
120
0
        extra, NULL, NULL, 0, 0,
121
0
        "Memory allocation failed : %s\n", extra);
122
0
}
123
124
/**
125
 * xmlXIncludeErr:
126
 * @ctxt: the XInclude context
127
 * @node: the context node
128
 * @msg:  the error message
129
 * @extra:  extra information
130
 *
131
 * Handle an XInclude error
132
 */
133
static void LIBXML_ATTR_FORMAT(4,0)
134
xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
135
               const char *msg, const xmlChar *extra)
136
552k
{
137
552k
    if (ctxt != NULL)
138
552k
  ctxt->nbErrors++;
139
552k
    __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
140
552k
                    error, XML_ERR_ERROR, NULL, 0,
141
552k
        (const char *) extra, NULL, NULL, 0, 0,
142
552k
        msg, (const char *) extra);
143
552k
}
144
145
#if 0
146
/**
147
 * xmlXIncludeWarn:
148
 * @ctxt: the XInclude context
149
 * @node: the context node
150
 * @msg:  the error message
151
 * @extra:  extra information
152
 *
153
 * Emit an XInclude warning.
154
 */
155
static void LIBXML_ATTR_FORMAT(4,0)
156
xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
157
               const char *msg, const xmlChar *extra)
158
{
159
    __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
160
                    error, XML_ERR_WARNING, NULL, 0,
161
        (const char *) extra, NULL, NULL, 0, 0,
162
        msg, (const char *) extra);
163
}
164
#endif
165
166
/**
167
 * xmlXIncludeGetProp:
168
 * @ctxt:  the XInclude context
169
 * @cur:  the node
170
 * @name:  the attribute name
171
 *
172
 * Get an XInclude attribute
173
 *
174
 * Returns the value (to be freed) or NULL if not found
175
 */
176
static xmlChar *
177
xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur,
178
1.38M
                   const xmlChar *name) {
179
1.38M
    xmlChar *ret;
180
181
1.38M
    ret = xmlGetNsProp(cur, XINCLUDE_NS, name);
182
1.38M
    if (ret != NULL)
183
0
        return(ret);
184
1.38M
    if (ctxt->legacy != 0) {
185
1.27M
  ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name);
186
1.27M
  if (ret != NULL)
187
0
      return(ret);
188
1.27M
    }
189
1.38M
    ret = xmlGetProp(cur, name);
190
1.38M
    return(ret);
191
1.38M
}
192
/**
193
 * xmlXIncludeFreeRef:
194
 * @ref: the XInclude reference
195
 *
196
 * Free an XInclude reference
197
 */
198
static void
199
244k
xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
200
244k
    if (ref == NULL)
201
0
  return;
202
#ifdef DEBUG_XINCLUDE
203
    xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
204
#endif
205
244k
    if (ref->doc != NULL) {
206
#ifdef DEBUG_XINCLUDE
207
  xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
208
#endif
209
790
  xmlFreeDoc(ref->doc);
210
790
    }
211
244k
    if (ref->URI != NULL)
212
244k
  xmlFree(ref->URI);
213
244k
    if (ref->fragment != NULL)
214
135k
  xmlFree(ref->fragment);
215
244k
    if (ref->xptr != NULL)
216
0
  xmlXPathFreeObject(ref->xptr);
217
244k
    xmlFree(ref);
218
244k
}
219
220
/**
221
 * xmlXIncludeNewRef:
222
 * @ctxt: the XInclude context
223
 * @URI:  the resource URI
224
 *
225
 * Creates a new reference within an XInclude context
226
 *
227
 * Returns the new set
228
 */
229
static xmlXIncludeRefPtr
230
xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
231
256k
            xmlNodePtr ref) {
232
256k
    xmlXIncludeRefPtr ret;
233
234
#ifdef DEBUG_XINCLUDE
235
    xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
236
#endif
237
256k
    ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
238
256k
    if (ret == NULL) {
239
0
        xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
240
0
  return(NULL);
241
0
    }
242
256k
    memset(ret, 0, sizeof(xmlXIncludeRef));
243
256k
    if (URI == NULL)
244
0
  ret->URI = NULL;
245
256k
    else
246
256k
  ret->URI = xmlStrdup(URI);
247
256k
    ret->fragment = NULL;
248
256k
    ret->ref = ref;
249
256k
    ret->doc = NULL;
250
256k
    ret->count = 0;
251
256k
    ret->xml = 0;
252
256k
    ret->inc = NULL;
253
256k
    if (ctxt->incMax == 0) {
254
150k
  ctxt->incMax = 4;
255
150k
        ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
256
150k
                sizeof(ctxt->incTab[0]));
257
150k
        if (ctxt->incTab == NULL) {
258
0
      xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
259
0
      xmlXIncludeFreeRef(ret);
260
0
      return(NULL);
261
0
  }
262
150k
    }
263
256k
    if (ctxt->incNr >= ctxt->incMax) {
264
12.3k
  ctxt->incMax *= 2;
265
12.3k
        ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
266
12.3k
               ctxt->incMax * sizeof(ctxt->incTab[0]));
267
12.3k
        if (ctxt->incTab == NULL) {
268
0
      xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
269
0
      xmlXIncludeFreeRef(ret);
270
0
      return(NULL);
271
0
  }
272
12.3k
    }
273
256k
    ctxt->incTab[ctxt->incNr++] = ret;
274
256k
    return(ret);
275
256k
}
276
277
/**
278
 * xmlXIncludeNewContext:
279
 * @doc:  an XML Document
280
 *
281
 * Creates a new XInclude context
282
 *
283
 * Returns the new set
284
 */
285
xmlXIncludeCtxtPtr
286
228k
xmlXIncludeNewContext(xmlDocPtr doc) {
287
228k
    xmlXIncludeCtxtPtr ret;
288
289
#ifdef DEBUG_XINCLUDE
290
    xmlGenericError(xmlGenericErrorContext, "New context\n");
291
#endif
292
228k
    if (doc == NULL)
293
0
  return(NULL);
294
228k
    ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
295
228k
    if (ret == NULL) {
296
0
  xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
297
0
                       "creating XInclude context");
298
0
  return(NULL);
299
0
    }
300
228k
    memset(ret, 0, sizeof(xmlXIncludeCtxt));
301
228k
    ret->doc = doc;
302
228k
    ret->incNr = 0;
303
228k
    ret->incBase = 0;
304
228k
    ret->incMax = 0;
305
228k
    ret->incTab = NULL;
306
228k
    ret->nbErrors = 0;
307
228k
    return(ret);
308
228k
}
309
310
/**
311
 * xmlXIncludeURLPush:
312
 * @ctxt:  the parser context
313
 * @value:  the url
314
 *
315
 * Pushes a new url on top of the url stack
316
 *
317
 * Returns -1 in case of error, the index in the stack otherwise
318
 */
319
static int
320
xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
321
             const xmlChar *value)
322
222k
{
323
222k
    if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
324
0
  xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION,
325
0
                 "detected a recursion in %s\n", value);
326
0
  return(-1);
327
0
    }
328
222k
    if (ctxt->urlTab == NULL) {
329
222k
  ctxt->urlMax = 4;
330
222k
  ctxt->urlNr = 0;
331
222k
  ctxt->urlTab = (xmlChar * *) xmlMalloc(
332
222k
            ctxt->urlMax * sizeof(ctxt->urlTab[0]));
333
222k
        if (ctxt->urlTab == NULL) {
334
0
      xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
335
0
            return (-1);
336
0
        }
337
222k
    }
338
222k
    if (ctxt->urlNr >= ctxt->urlMax) {
339
0
        ctxt->urlMax *= 2;
340
0
        ctxt->urlTab =
341
0
            (xmlChar * *) xmlRealloc(ctxt->urlTab,
342
0
                                      ctxt->urlMax *
343
0
                                      sizeof(ctxt->urlTab[0]));
344
0
        if (ctxt->urlTab == NULL) {
345
0
      xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
346
0
            return (-1);
347
0
        }
348
0
    }
349
222k
    ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
350
222k
    return (ctxt->urlNr++);
351
222k
}
352
353
/**
354
 * xmlXIncludeURLPop:
355
 * @ctxt: the parser context
356
 *
357
 * Pops the top URL from the URL stack
358
 */
359
static void
360
xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
361
219k
{
362
219k
    xmlChar * ret;
363
364
219k
    if (ctxt->urlNr <= 0)
365
0
        return;
366
219k
    ctxt->urlNr--;
367
219k
    if (ctxt->urlNr > 0)
368
0
        ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
369
219k
    else
370
219k
        ctxt->url = NULL;
371
219k
    ret = ctxt->urlTab[ctxt->urlNr];
372
219k
    ctxt->urlTab[ctxt->urlNr] = NULL;
373
219k
    if (ret != NULL)
374
219k
  xmlFree(ret);
375
219k
}
376
377
/**
378
 * xmlXIncludeFreeContext:
379
 * @ctxt: the XInclude context
380
 *
381
 * Free an XInclude context
382
 */
383
void
384
224k
xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
385
224k
    int i;
386
387
#ifdef DEBUG_XINCLUDE
388
    xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
389
#endif
390
224k
    if (ctxt == NULL)
391
0
  return;
392
225k
    while (ctxt->urlNr > 0)
393
999
  xmlXIncludeURLPop(ctxt);
394
224k
    if (ctxt->urlTab != NULL)
395
219k
  xmlFree(ctxt->urlTab);
396
475k
    for (i = 0;i < ctxt->incNr;i++) {
397
251k
  if (ctxt->incTab[i] != NULL)
398
244k
      xmlXIncludeFreeRef(ctxt->incTab[i]);
399
251k
    }
400
224k
    if (ctxt->incTab != NULL)
401
148k
  xmlFree(ctxt->incTab);
402
224k
    if (ctxt->txtTab != NULL) {
403
507
  for (i = 0;i < ctxt->txtNr;i++) {
404
261
      if (ctxt->txtTab[i] != NULL)
405
0
    xmlFree(ctxt->txtTab[i]);
406
261
  }
407
246
  xmlFree(ctxt->txtTab);
408
246
    }
409
224k
    if (ctxt->txturlTab != NULL) {
410
507
  for (i = 0;i < ctxt->txtNr;i++) {
411
261
      if (ctxt->txturlTab[i] != NULL)
412
261
    xmlFree(ctxt->txturlTab[i]);
413
261
  }
414
246
  xmlFree(ctxt->txturlTab);
415
246
    }
416
224k
    if (ctxt->base != NULL) {
417
220k
        xmlFree(ctxt->base);
418
220k
    }
419
224k
    xmlFree(ctxt);
420
224k
}
421
422
/**
423
 * xmlXIncludeParseFile:
424
 * @ctxt:  the XInclude context
425
 * @URL:  the URL or file path
426
 *
427
 * parse a document for XInclude
428
 */
429
static xmlDocPtr
430
116k
xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
431
116k
    xmlDocPtr ret;
432
116k
    xmlParserCtxtPtr pctxt;
433
116k
    xmlParserInputPtr inputStream;
434
435
116k
    xmlInitParser();
436
437
116k
    pctxt = xmlNewParserCtxt();
438
116k
    if (pctxt == NULL) {
439
0
  xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context");
440
0
  return(NULL);
441
0
    }
442
443
    /*
444
     * pass in the application data to the parser context.
445
     */
446
116k
    pctxt->_private = ctxt->_private;
447
448
    /*
449
     * try to ensure that new documents included are actually
450
     * built with the same dictionary as the including document.
451
     */
452
116k
    if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL)) {
453
40.7k
       if (pctxt->dict != NULL)
454
40.7k
            xmlDictFree(pctxt->dict);
455
40.7k
  pctxt->dict = ctxt->doc->dict;
456
40.7k
  xmlDictReference(pctxt->dict);
457
40.7k
    }
458
459
116k
    xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
460
461
    /* Don't read from stdin. */
462
116k
    if ((URL != NULL) && (strcmp(URL, "-") == 0))
463
0
        URL = "./-";
464
465
116k
    inputStream = xmlLoadExternalEntity(URL, NULL, pctxt);
466
116k
    if (inputStream == NULL) {
467
94.2k
  xmlFreeParserCtxt(pctxt);
468
94.2k
  return(NULL);
469
94.2k
    }
470
471
22.1k
    inputPush(pctxt, inputStream);
472
473
22.1k
    if (pctxt->directory == NULL)
474
22.1k
        pctxt->directory = xmlParserGetDirectory(URL);
475
476
22.1k
    pctxt->loadsubset |= XML_DETECT_IDS;
477
478
22.1k
    xmlParseDocument(pctxt);
479
480
22.1k
    if (pctxt->wellFormed) {
481
1.56k
        ret = pctxt->myDoc;
482
1.56k
    }
483
20.5k
    else {
484
20.5k
        ret = NULL;
485
20.5k
  if (pctxt->myDoc != NULL)
486
20.2k
      xmlFreeDoc(pctxt->myDoc);
487
20.5k
        pctxt->myDoc = NULL;
488
20.5k
    }
489
22.1k
    xmlFreeParserCtxt(pctxt);
490
491
22.1k
    return(ret);
492
116k
}
493
494
/**
495
 * xmlXIncludeAddNode:
496
 * @ctxt:  the XInclude context
497
 * @cur:  the new node
498
 *
499
 * Add a new node to process to an XInclude context
500
 */
501
static int
502
297k
xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
503
297k
    xmlXIncludeRefPtr ref;
504
297k
    xmlURIPtr uri;
505
297k
    xmlChar *URL;
506
297k
    xmlChar *fragment = NULL;
507
297k
    xmlChar *href;
508
297k
    xmlChar *parse;
509
297k
    xmlChar *base;
510
297k
    xmlChar *URI;
511
297k
    int xml = 1, i; /* default Issue 64 */
512
297k
    int local = 0;
513
514
515
297k
    if (ctxt == NULL)
516
0
  return(-1);
517
297k
    if (cur == NULL)
518
0
  return(-1);
519
520
#ifdef DEBUG_XINCLUDE
521
    xmlGenericError(xmlGenericErrorContext, "Add node\n");
522
#endif
523
    /*
524
     * read the attributes
525
     */
526
297k
    href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
527
297k
    if (href == NULL) {
528
119k
  href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
529
119k
  if (href == NULL)
530
0
      return(-1);
531
119k
    }
532
297k
    parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
533
297k
    if (parse != NULL) {
534
2.53k
  if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
535
1.28k
      xml = 1;
536
1.24k
  else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
537
1.09k
      xml = 0;
538
152
  else {
539
152
      xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
540
152
                     "invalid value %s for 'parse'\n", parse);
541
152
      if (href != NULL)
542
152
    xmlFree(href);
543
152
      if (parse != NULL)
544
152
    xmlFree(parse);
545
152
      return(-1);
546
152
  }
547
2.53k
    }
548
549
    /*
550
     * compute the URI
551
     */
552
297k
    base = xmlNodeGetBase(ctxt->doc, cur);
553
297k
    if (base == NULL) {
554
8.44k
  URI = xmlBuildURI(href, ctxt->doc->URL);
555
289k
    } else {
556
289k
  URI = xmlBuildURI(href, base);
557
289k
    }
558
297k
    if (URI == NULL) {
559
29.1k
  xmlChar *escbase;
560
29.1k
  xmlChar *eschref;
561
  /*
562
   * Some escaping may be needed
563
   */
564
29.1k
  escbase = xmlURIEscape(base);
565
29.1k
  eschref = xmlURIEscape(href);
566
29.1k
  URI = xmlBuildURI(eschref, escbase);
567
29.1k
  if (escbase != NULL)
568
27.0k
      xmlFree(escbase);
569
29.1k
  if (eschref != NULL)
570
14.8k
      xmlFree(eschref);
571
29.1k
    }
572
297k
    if (parse != NULL)
573
2.38k
  xmlFree(parse);
574
297k
    if (href != NULL)
575
297k
  xmlFree(href);
576
297k
    if (base != NULL)
577
289k
  xmlFree(base);
578
297k
    if (URI == NULL) {
579
14.8k
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
580
14.8k
                 "failed build URL\n", NULL);
581
14.8k
  return(-1);
582
14.8k
    }
583
282k
    fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
584
585
    /*
586
     * Check the URL and remove any fragment identifier
587
     */
588
282k
    uri = xmlParseURI((const char *)URI);
589
282k
    if (uri == NULL) {
590
1.33k
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
591
1.33k
                 "invalid value URI %s\n", URI);
592
1.33k
  if (fragment != NULL)
593
413
      xmlFree(fragment);
594
1.33k
  xmlFree(URI);
595
1.33k
  return(-1);
596
1.33k
    }
597
598
281k
    if (uri->fragment != NULL) {
599
51.2k
        if (ctxt->legacy != 0) {
600
50.6k
      if (fragment == NULL) {
601
50.2k
    fragment = (xmlChar *) uri->fragment;
602
50.2k
      } else {
603
385
    xmlFree(uri->fragment);
604
385
      }
605
50.6k
  } else {
606
653
      xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID,
607
653
       "Invalid fragment identifier in URI %s use the xpointer attribute\n",
608
653
                           URI);
609
653
      if (fragment != NULL)
610
100
          xmlFree(fragment);
611
653
      xmlFreeURI(uri);
612
653
      xmlFree(URI);
613
653
      return(-1);
614
653
  }
615
50.6k
  uri->fragment = NULL;
616
50.6k
    }
617
280k
    URL = xmlSaveUri(uri);
618
280k
    xmlFreeURI(uri);
619
280k
    xmlFree(URI);
620
280k
    if (URL == NULL) {
621
0
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
622
0
                 "invalid value URI %s\n", URI);
623
0
  if (fragment != NULL)
624
0
      xmlFree(fragment);
625
0
  return(-1);
626
0
    }
627
628
280k
    if (xmlStrEqual(URL, ctxt->doc->URL))
629
146k
  local = 1;
630
631
    /*
632
     * If local and xml then we need a fragment
633
     */
634
280k
    if ((local == 1) && (xml == 1) &&
635
280k
        ((fragment == NULL) || (fragment[0] == 0))) {
636
24.3k
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
637
24.3k
                 "detected a local recursion with no xpointer in %s\n",
638
24.3k
           URL);
639
24.3k
        xmlFree(URL);
640
24.3k
        xmlFree(fragment);
641
24.3k
  return(-1);
642
24.3k
    }
643
644
    /*
645
     * Check the URL against the stack for recursions
646
     */
647
256k
    if ((!local) && (xml == 1)) {
648
258k
  for (i = 0;i < ctxt->urlNr;i++) {
649
125k
      if (xmlStrEqual(URL, ctxt->urlTab[i])) {
650
0
    xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
651
0
                   "detected a recursion in %s\n", URL);
652
0
                xmlFree(URL);
653
0
                xmlFree(fragment);
654
0
    return(-1);
655
0
      }
656
125k
  }
657
133k
    }
658
659
256k
    ref = xmlXIncludeNewRef(ctxt, URL, cur);
660
256k
    xmlFree(URL);
661
256k
    if (ref == NULL) {
662
0
  return(-1);
663
0
    }
664
256k
    ref->fragment = fragment;
665
256k
    ref->doc = NULL;
666
256k
    ref->xml = xml;
667
256k
    ref->count = 1;
668
256k
    return(0);
669
256k
}
670
671
/**
672
 * xmlXIncludeRecurseDoc:
673
 * @ctxt:  the XInclude context
674
 * @doc:  the new document
675
 * @url:  the associated URL
676
 *
677
 * The XInclude recursive nature is handled at this point.
678
 */
679
static void
680
xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
681
1.56k
                const xmlURL url ATTRIBUTE_UNUSED) {
682
1.56k
    xmlXIncludeCtxtPtr newctxt;
683
1.56k
    int i;
684
685
    /*
686
     * Avoid recursion in already substituted resources
687
    for (i = 0;i < ctxt->urlNr;i++) {
688
  if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
689
      return;
690
    }
691
     */
692
693
#ifdef DEBUG_XINCLUDE
694
    xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
695
#endif
696
    /*
697
     * Handle recursion here.
698
     */
699
700
1.56k
    newctxt = xmlXIncludeNewContext(doc);
701
1.56k
    if (newctxt != NULL) {
702
  /*
703
   * Copy the private user data
704
   */
705
1.56k
  newctxt->_private = ctxt->_private;
706
  /*
707
   * Copy the existing document set
708
   */
709
1.56k
  newctxt->incMax = ctxt->incMax;
710
1.56k
  newctxt->incNr = ctxt->incNr;
711
1.56k
        newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
712
1.56k
                              sizeof(newctxt->incTab[0]));
713
1.56k
        if (newctxt->incTab == NULL) {
714
0
      xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
715
0
      xmlFree(newctxt);
716
0
      return;
717
0
  }
718
  /*
719
   * copy the urlTab
720
   */
721
1.56k
  newctxt->urlMax = ctxt->urlMax;
722
1.56k
  newctxt->urlNr = ctxt->urlNr;
723
1.56k
  newctxt->urlTab = ctxt->urlTab;
724
725
  /*
726
   * Inherit the existing base
727
   */
728
1.56k
  newctxt->base = xmlStrdup(ctxt->base);
729
730
  /*
731
   * Inherit the documents already in use by other includes
732
   */
733
1.56k
  newctxt->incBase = ctxt->incNr;
734
7.89k
  for (i = 0;i < ctxt->incNr;i++) {
735
6.33k
      newctxt->incTab[i] = ctxt->incTab[i];
736
6.33k
      newctxt->incTab[i]->count++; /* prevent the recursion from
737
              freeing it */
738
6.33k
  }
739
  /*
740
   * The new context should also inherit the Parse Flags
741
   * (bug 132597)
742
   */
743
1.56k
  newctxt->parseFlags = ctxt->parseFlags;
744
1.56k
        newctxt->incTotal = ctxt->incTotal;
745
1.56k
  xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc), 0);
746
1.56k
        ctxt->incTotal = newctxt->incTotal;
747
7.89k
  for (i = 0;i < ctxt->incNr;i++) {
748
6.33k
      newctxt->incTab[i]->count--;
749
6.33k
      newctxt->incTab[i] = NULL;
750
6.33k
  }
751
752
  /* urlTab may have been reallocated */
753
1.56k
  ctxt->urlTab = newctxt->urlTab;
754
1.56k
  ctxt->urlMax = newctxt->urlMax;
755
756
1.56k
  newctxt->urlMax = 0;
757
1.56k
  newctxt->urlNr = 0;
758
1.56k
  newctxt->urlTab = NULL;
759
760
1.56k
  xmlXIncludeFreeContext(newctxt);
761
1.56k
    }
762
#ifdef DEBUG_XINCLUDE
763
    xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
764
#endif
765
1.56k
}
766
767
/**
768
 * xmlXIncludeAddTxt:
769
 * @ctxt:  the XInclude context
770
 * @txt:  the new text node
771
 * @url:  the associated URL
772
 *
773
 * Add a new text node to the list
774
 */
775
static void
776
xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *txt,
777
283
                  const xmlURL url) {
778
#ifdef DEBUG_XINCLUDE
779
    xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
780
#endif
781
283
    if (ctxt->txtMax == 0) {
782
268
  ctxt->txtMax = 4;
783
268
        ctxt->txtTab = (xmlChar **) xmlMalloc(ctxt->txtMax *
784
268
                              sizeof(ctxt->txtTab[0]));
785
268
        if (ctxt->txtTab == NULL) {
786
0
      xmlXIncludeErrMemory(ctxt, NULL, "processing text");
787
0
      return;
788
0
  }
789
268
        ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
790
268
                              sizeof(ctxt->txturlTab[0]));
791
268
        if (ctxt->txturlTab == NULL) {
792
0
      xmlXIncludeErrMemory(ctxt, NULL, "processing text");
793
0
      return;
794
0
  }
795
268
    }
796
283
    if (ctxt->txtNr >= ctxt->txtMax) {
797
0
  ctxt->txtMax *= 2;
798
0
        ctxt->txtTab = (xmlChar **) xmlRealloc(ctxt->txtTab,
799
0
               ctxt->txtMax * sizeof(ctxt->txtTab[0]));
800
0
        if (ctxt->txtTab == NULL) {
801
0
      xmlXIncludeErrMemory(ctxt, NULL, "processing text");
802
0
      return;
803
0
  }
804
0
        ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
805
0
               ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
806
0
        if (ctxt->txturlTab == NULL) {
807
0
      xmlXIncludeErrMemory(ctxt, NULL, "processing text");
808
0
      return;
809
0
  }
810
0
    }
811
283
    ctxt->txtTab[ctxt->txtNr] = xmlStrdup(txt);
812
283
    ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
813
283
    ctxt->txtNr++;
814
283
}
815
816
/************************************************************************
817
 *                  *
818
 *      Node copy with specific semantic    *
819
 *                  *
820
 ************************************************************************/
821
822
static xmlNodePtr
823
xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
824
                  xmlDocPtr source, xmlNodePtr elem);
825
826
/**
827
 * xmlXIncludeCopyNode:
828
 * @ctxt:  the XInclude context
829
 * @target:  the document target
830
 * @source:  the document source
831
 * @elem:  the element
832
 *
833
 * Make a copy of the node while preserving the XInclude semantic
834
 * of the Infoset copy
835
 */
836
static xmlNodePtr
837
xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
838
5.77M
              xmlDocPtr source, xmlNodePtr elem) {
839
5.77M
    xmlNodePtr result = NULL;
840
841
5.77M
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
842
5.77M
  (elem == NULL))
843
0
  return(NULL);
844
5.77M
    if (elem->type == XML_DTD_NODE)
845
1.48k
  return(NULL);
846
5.77M
    if (elem->type == XML_DOCUMENT_NODE)
847
12.7k
  result = xmlXIncludeCopyNodeList(ctxt, target, source, elem->children);
848
5.76M
    else
849
5.76M
        result = xmlDocCopyNode(elem, target, 1);
850
5.77M
    return(result);
851
5.77M
}
852
853
/**
854
 * xmlXIncludeCopyNodeList:
855
 * @ctxt:  the XInclude context
856
 * @target:  the document target
857
 * @source:  the document source
858
 * @elem:  the element list
859
 *
860
 * Make a copy of the node list while preserving the XInclude semantic
861
 * of the Infoset copy
862
 */
863
static xmlNodePtr
864
xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
865
13.7k
                  xmlDocPtr source, xmlNodePtr elem) {
866
13.7k
    xmlNodePtr cur, res, result = NULL, last = NULL;
867
868
13.7k
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
869
13.7k
  (elem == NULL))
870
0
  return(NULL);
871
13.7k
    cur = elem;
872
34.5k
    while (cur != NULL) {
873
20.7k
  res = xmlXIncludeCopyNode(ctxt, target, source, cur);
874
20.7k
  if (res != NULL) {
875
19.2k
      if (result == NULL) {
876
13.7k
    result = last = res;
877
13.7k
      } else {
878
5.50k
    last->next = res;
879
5.50k
    res->prev = last;
880
5.50k
    last = res;
881
5.50k
      }
882
19.2k
  }
883
20.7k
  cur = cur->next;
884
20.7k
    }
885
13.7k
    return(result);
886
13.7k
}
887
888
#ifdef LIBXML_XPTR_LOCS_ENABLED
889
/**
890
 * xmlXIncludeGetNthChild:
891
 * @cur:  the node
892
 * @no:  the child number
893
 *
894
 * Returns the @n'th element child of @cur or NULL
895
 */
896
static xmlNodePtr
897
xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
898
    int i;
899
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
900
        return(NULL);
901
    cur = cur->children;
902
    for (i = 0;i <= no;cur = cur->next) {
903
  if (cur == NULL)
904
      return(cur);
905
  if ((cur->type == XML_ELEMENT_NODE) ||
906
      (cur->type == XML_DOCUMENT_NODE) ||
907
      (cur->type == XML_HTML_DOCUMENT_NODE)) {
908
      i++;
909
      if (i == no)
910
    break;
911
  }
912
    }
913
    return(cur);
914
}
915
916
xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */
917
/**
918
 * xmlXIncludeCopyRange:
919
 * @ctxt:  the XInclude context
920
 * @target:  the document target
921
 * @source:  the document source
922
 * @obj:  the XPointer result from the evaluation.
923
 *
924
 * Build a node list tree copy of the XPointer result.
925
 *
926
 * Returns an xmlNodePtr list or NULL.
927
 *         The caller has to free the node tree.
928
 */
929
static xmlNodePtr
930
xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
931
                  xmlDocPtr source, xmlXPathObjectPtr range) {
932
    /* pointers to generated nodes */
933
    xmlNodePtr list = NULL, last = NULL, listParent = NULL;
934
    xmlNodePtr tmp, tmp2;
935
    /* pointers to traversal nodes */
936
    xmlNodePtr start, cur, end;
937
    int index1, index2;
938
    int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0;
939
940
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
941
  (range == NULL))
942
  return(NULL);
943
    if (range->type != XPATH_RANGE)
944
  return(NULL);
945
    start = (xmlNodePtr) range->user;
946
947
    if ((start == NULL) || (start->type == XML_NAMESPACE_DECL))
948
  return(NULL);
949
    end = range->user2;
950
    if (end == NULL)
951
  return(xmlDocCopyNode(start, target, 1));
952
    if (end->type == XML_NAMESPACE_DECL)
953
        return(NULL);
954
955
    cur = start;
956
    index1 = range->index;
957
    index2 = range->index2;
958
    /*
959
     * level is depth of the current node under consideration
960
     * list is the pointer to the root of the output tree
961
     * listParent is a pointer to the parent of output tree (within
962
       the included file) in case we need to add another level
963
     * last is a pointer to the last node added to the output tree
964
     * lastLevel is the depth of last (relative to the root)
965
     */
966
    while (cur != NULL) {
967
  /*
968
   * Check if our output tree needs a parent
969
   */
970
  if (level < 0) {
971
      while (level < 0) {
972
          /* copy must include namespaces and properties */
973
          tmp2 = xmlDocCopyNode(listParent, target, 2);
974
          xmlAddChild(tmp2, list);
975
          list = tmp2;
976
          listParent = listParent->parent;
977
          level++;
978
      }
979
      last = list;
980
      lastLevel = 0;
981
  }
982
  /*
983
   * Check whether we need to change our insertion point
984
   */
985
  while (level < lastLevel) {
986
      last = last->parent;
987
      lastLevel --;
988
  }
989
  if (cur == end) { /* Are we at the end of the range? */
990
      if (cur->type == XML_TEXT_NODE) {
991
    const xmlChar *content = cur->content;
992
    int len;
993
994
    if (content == NULL) {
995
        tmp = xmlNewDocTextLen(target, NULL, 0);
996
    } else {
997
        len = index2;
998
        if ((cur == start) && (index1 > 1)) {
999
      content += (index1 - 1);
1000
      len -= (index1 - 1);
1001
        } else {
1002
      len = index2;
1003
        }
1004
        tmp = xmlNewDocTextLen(target, content, len);
1005
    }
1006
    /* single sub text node selection */
1007
    if (list == NULL)
1008
        return(tmp);
1009
    /* prune and return full set */
1010
    if (level == lastLevel)
1011
        xmlAddNextSibling(last, tmp);
1012
    else
1013
        xmlAddChild(last, tmp);
1014
    return(list);
1015
      } else {  /* ending node not a text node */
1016
          endLevel = level; /* remember the level of the end node */
1017
    endFlag = 1;
1018
    /* last node - need to take care of properties + namespaces */
1019
    tmp = xmlDocCopyNode(cur, target, 2);
1020
    if (list == NULL) {
1021
        list = tmp;
1022
        listParent = cur->parent;
1023
        last = tmp;
1024
    } else {
1025
        if (level == lastLevel)
1026
      last = xmlAddNextSibling(last, tmp);
1027
        else {
1028
      last = xmlAddChild(last, tmp);
1029
      lastLevel = level;
1030
        }
1031
    }
1032
1033
    if (index2 > 1) {
1034
        end = xmlXIncludeGetNthChild(cur, index2 - 1);
1035
        index2 = 0;
1036
    }
1037
    if ((cur == start) && (index1 > 1)) {
1038
        cur = xmlXIncludeGetNthChild(cur, index1 - 1);
1039
        index1 = 0;
1040
    }  else {
1041
        cur = cur->children;
1042
    }
1043
    level++;  /* increment level to show change */
1044
    /*
1045
     * Now gather the remaining nodes from cur to end
1046
     */
1047
    continue; /* while */
1048
      }
1049
  } else if (cur == start) {  /* Not at the end, are we at start? */
1050
      if ((cur->type == XML_TEXT_NODE) ||
1051
    (cur->type == XML_CDATA_SECTION_NODE)) {
1052
    const xmlChar *content = cur->content;
1053
1054
    if (content == NULL) {
1055
        tmp = xmlNewDocTextLen(target, NULL, 0);
1056
    } else {
1057
        if (index1 > 1) {
1058
      content += (index1 - 1);
1059
      index1 = 0;
1060
        }
1061
        tmp = xmlNewDocText(target, content);
1062
    }
1063
    last = list = tmp;
1064
    listParent = cur->parent;
1065
      } else {    /* Not text node */
1066
          /*
1067
     * start of the range - need to take care of
1068
     * properties and namespaces
1069
     */
1070
    tmp = xmlDocCopyNode(cur, target, 2);
1071
    list = last = tmp;
1072
    listParent = cur->parent;
1073
    if (index1 > 1) { /* Do we need to position? */
1074
        cur = xmlXIncludeGetNthChild(cur, index1 - 1);
1075
        level = lastLevel = 1;
1076
        index1 = 0;
1077
        /*
1078
         * Now gather the remaining nodes from cur to end
1079
         */
1080
        continue; /* while */
1081
    }
1082
      }
1083
  } else {
1084
      tmp = NULL;
1085
      switch (cur->type) {
1086
    case XML_DTD_NODE:
1087
    case XML_ELEMENT_DECL:
1088
    case XML_ATTRIBUTE_DECL:
1089
    case XML_ENTITY_NODE:
1090
        /* Do not copy DTD information */
1091
        break;
1092
    case XML_ENTITY_DECL:
1093
        /* handle crossing entities -> stack needed */
1094
        break;
1095
    case XML_XINCLUDE_START:
1096
    case XML_XINCLUDE_END:
1097
        /* don't consider it part of the tree content */
1098
        break;
1099
    case XML_ATTRIBUTE_NODE:
1100
        /* Humm, should not happen ! */
1101
        break;
1102
    default:
1103
        /*
1104
         * Middle of the range - need to take care of
1105
         * properties and namespaces
1106
         */
1107
        tmp = xmlDocCopyNode(cur, target, 2);
1108
        break;
1109
      }
1110
      if (tmp != NULL) {
1111
    if (level == lastLevel)
1112
        last = xmlAddNextSibling(last, tmp);
1113
    else {
1114
        last = xmlAddChild(last, tmp);
1115
        lastLevel = level;
1116
    }
1117
      }
1118
  }
1119
  /*
1120
   * Skip to next node in document order
1121
   */
1122
  cur = xmlXPtrAdvanceNode(cur, &level);
1123
  if (endFlag && (level >= endLevel))
1124
      break;
1125
    }
1126
    return(list);
1127
}
1128
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1129
1130
/**
1131
 * xmlXIncludeBuildNodeList:
1132
 * @ctxt:  the XInclude context
1133
 * @target:  the document target
1134
 * @source:  the document source
1135
 * @obj:  the XPointer result from the evaluation.
1136
 *
1137
 * Build a node list tree copy of the XPointer result.
1138
 * This will drop Attributes and Namespace declarations.
1139
 *
1140
 * Returns an xmlNodePtr list or NULL.
1141
 *         the caller has to free the node tree.
1142
 */
1143
static xmlNodePtr
1144
xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
1145
34.6k
                  xmlDocPtr source, xmlXPathObjectPtr obj) {
1146
34.6k
    xmlNodePtr list = NULL, last = NULL;
1147
34.6k
    int i;
1148
1149
34.6k
    if (source == NULL)
1150
0
  source = ctxt->doc;
1151
34.6k
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
1152
34.6k
  (obj == NULL))
1153
0
  return(NULL);
1154
34.6k
    switch (obj->type) {
1155
34.6k
        case XPATH_NODESET: {
1156
34.6k
      xmlNodeSetPtr set = obj->nodesetval;
1157
34.6k
      if (set == NULL)
1158
0
    return(NULL);
1159
2.13M
      for (i = 0;i < set->nodeNr;i++) {
1160
2.10M
    if (set->nodeTab[i] == NULL)
1161
235k
        continue;
1162
1.87M
    switch (set->nodeTab[i]->type) {
1163
940k
        case XML_TEXT_NODE:
1164
951k
        case XML_CDATA_SECTION_NODE:
1165
1.80M
        case XML_ELEMENT_NODE:
1166
1.80M
        case XML_ENTITY_REF_NODE:
1167
1.80M
        case XML_ENTITY_NODE:
1168
1.81M
        case XML_PI_NODE:
1169
1.84M
        case XML_COMMENT_NODE:
1170
1.85M
        case XML_DOCUMENT_NODE:
1171
1.85M
        case XML_HTML_DOCUMENT_NODE:
1172
1.85M
        case XML_XINCLUDE_END:
1173
1.85M
      break;
1174
11.1k
        case XML_XINCLUDE_START: {
1175
11.1k
                  xmlNodePtr tmp, cur = set->nodeTab[i];
1176
1177
11.1k
      cur = cur->next;
1178
3.90M
      while (cur != NULL) {
1179
3.90M
          switch(cur->type) {
1180
1.06M
        case XML_TEXT_NODE:
1181
1.07M
        case XML_CDATA_SECTION_NODE:
1182
3.78M
        case XML_ELEMENT_NODE:
1183
3.78M
        case XML_ENTITY_REF_NODE:
1184
3.78M
        case XML_ENTITY_NODE:
1185
3.81M
        case XML_PI_NODE:
1186
3.89M
        case XML_COMMENT_NODE:
1187
3.89M
            tmp = xmlXIncludeCopyNode(ctxt, target,
1188
3.89M
                    source, cur);
1189
3.89M
            if (last == NULL) {
1190
213
          list = last = tmp;
1191
3.89M
            } else {
1192
3.89M
          last = xmlAddNextSibling(last, tmp);
1193
3.89M
            }
1194
3.89M
            cur = cur->next;
1195
3.89M
            continue;
1196
11.1k
        default:
1197
11.1k
            break;
1198
3.90M
          }
1199
11.1k
          break;
1200
3.90M
      }
1201
11.1k
      continue;
1202
11.1k
        }
1203
11.1k
        case XML_ATTRIBUTE_NODE:
1204
0
        case XML_NAMESPACE_DECL:
1205
0
        case XML_DOCUMENT_TYPE_NODE:
1206
0
        case XML_DOCUMENT_FRAG_NODE:
1207
0
        case XML_NOTATION_NODE:
1208
0
        case XML_DTD_NODE:
1209
0
        case XML_ELEMENT_DECL:
1210
0
        case XML_ATTRIBUTE_DECL:
1211
0
        case XML_ENTITY_DECL:
1212
0
      continue; /* for */
1213
1.87M
    }
1214
1.85M
    if (last == NULL)
1215
33.2k
        list = last = xmlXIncludeCopyNode(ctxt, target, source,
1216
33.2k
                                    set->nodeTab[i]);
1217
1.82M
    else {
1218
1.82M
        xmlAddNextSibling(last,
1219
1.82M
          xmlXIncludeCopyNode(ctxt, target, source,
1220
1.82M
                        set->nodeTab[i]));
1221
1.82M
        if (last->next != NULL)
1222
1.39M
      last = last->next;
1223
1.82M
    }
1224
1.85M
      }
1225
31.7k
      break;
1226
34.6k
  }
1227
#ifdef LIBXML_XPTR_LOCS_ENABLED
1228
  case XPATH_LOCATIONSET: {
1229
      xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1230
      if (set == NULL)
1231
    return(NULL);
1232
      for (i = 0;i < set->locNr;i++) {
1233
    if (last == NULL)
1234
        list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
1235
                                        set->locTab[i]);
1236
    else
1237
        xmlAddNextSibling(last,
1238
          xmlXIncludeCopyXPointer(ctxt, target, source,
1239
                            set->locTab[i]));
1240
    if (last != NULL) {
1241
        while (last->next != NULL)
1242
      last = last->next;
1243
    }
1244
      }
1245
      break;
1246
  }
1247
  case XPATH_RANGE:
1248
      return(xmlXIncludeCopyRange(ctxt, target, source, obj));
1249
  case XPATH_POINT:
1250
      /* points are ignored in XInclude */
1251
      break;
1252
#endif
1253
31.7k
  default:
1254
0
      break;
1255
34.6k
    }
1256
31.5k
    return(list);
1257
34.6k
}
1258
/************************************************************************
1259
 *                  *
1260
 *      XInclude I/O handling       *
1261
 *                  *
1262
 ************************************************************************/
1263
1264
typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1265
typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1266
struct _xmlXIncludeMergeData {
1267
    xmlDocPtr doc;
1268
    xmlXIncludeCtxtPtr ctxt;
1269
};
1270
1271
/**
1272
 * xmlXIncludeMergeOneEntity:
1273
 * @ent: the entity
1274
 * @doc:  the including doc
1275
 * @nr: the entity name
1276
 *
1277
 * Implements the merge of one entity
1278
 */
1279
static void
1280
xmlXIncludeMergeEntity(void *payload, void *vdata,
1281
28
                 const xmlChar *name ATTRIBUTE_UNUSED) {
1282
28
    xmlEntityPtr ent = (xmlEntityPtr) payload;
1283
28
    xmlXIncludeMergeDataPtr data = (xmlXIncludeMergeDataPtr) vdata;
1284
28
    xmlEntityPtr ret, prev;
1285
28
    xmlDocPtr doc;
1286
28
    xmlXIncludeCtxtPtr ctxt;
1287
1288
28
    if ((ent == NULL) || (data == NULL))
1289
0
  return;
1290
28
    ctxt = data->ctxt;
1291
28
    doc = data->doc;
1292
28
    if ((ctxt == NULL) || (doc == NULL))
1293
0
  return;
1294
28
    switch (ent->etype) {
1295
0
        case XML_INTERNAL_PARAMETER_ENTITY:
1296
0
        case XML_EXTERNAL_PARAMETER_ENTITY:
1297
0
        case XML_INTERNAL_PREDEFINED_ENTITY:
1298
0
      return;
1299
0
        case XML_INTERNAL_GENERAL_ENTITY:
1300
10
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1301
28
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1302
28
      break;
1303
28
    }
1304
28
    ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1305
28
        ent->SystemID, ent->content);
1306
28
    if (ret != NULL) {
1307
27
  if (ent->URI != NULL)
1308
18
      ret->URI = xmlStrdup(ent->URI);
1309
27
    } else {
1310
1
  prev = xmlGetDocEntity(doc, ent->name);
1311
1
  if (prev != NULL) {
1312
1
      if (ent->etype != prev->etype)
1313
0
    goto error;
1314
1315
1
      if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1316
1
    if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1317
0
        goto error;
1318
1
      } else if ((ent->ExternalID != NULL) &&
1319
0
           (prev->ExternalID != NULL)) {
1320
0
    if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1321
0
        goto error;
1322
0
      } else if ((ent->content != NULL) && (prev->content != NULL)) {
1323
0
    if (!xmlStrEqual(ent->content, prev->content))
1324
0
        goto error;
1325
0
      } else {
1326
0
    goto error;
1327
0
      }
1328
1329
1
  }
1330
1
    }
1331
28
    return;
1332
28
error:
1333
0
    switch (ent->etype) {
1334
0
        case XML_INTERNAL_PARAMETER_ENTITY:
1335
0
        case XML_EXTERNAL_PARAMETER_ENTITY:
1336
0
        case XML_INTERNAL_PREDEFINED_ENTITY:
1337
0
        case XML_INTERNAL_GENERAL_ENTITY:
1338
0
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1339
0
      return;
1340
0
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1341
0
      break;
1342
0
    }
1343
0
    xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
1344
0
                   "mismatch in redefinition of entity %s\n",
1345
0
       ent->name);
1346
0
}
1347
1348
/**
1349
 * xmlXIncludeMergeEntities:
1350
 * @ctxt: an XInclude context
1351
 * @doc:  the including doc
1352
 * @from:  the included doc
1353
 *
1354
 * Implements the entity merge
1355
 *
1356
 * Returns 0 if merge succeeded, -1 if some processing failed
1357
 */
1358
static int
1359
xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1360
1.56k
                   xmlDocPtr from) {
1361
1.56k
    xmlNodePtr cur;
1362
1.56k
    xmlDtdPtr target, source;
1363
1364
1.56k
    if (ctxt == NULL)
1365
0
  return(-1);
1366
1367
1.56k
    if ((from == NULL) || (from->intSubset == NULL))
1368
1.13k
  return(0);
1369
1370
429
    target = doc->intSubset;
1371
429
    if (target == NULL) {
1372
309
  cur = xmlDocGetRootElement(doc);
1373
309
  if (cur == NULL)
1374
0
      return(-1);
1375
309
        target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1376
309
  if (target == NULL)
1377
0
      return(-1);
1378
309
    }
1379
1380
429
    source = from->intSubset;
1381
429
    if ((source != NULL) && (source->entities != NULL)) {
1382
28
  xmlXIncludeMergeData data;
1383
1384
28
  data.ctxt = ctxt;
1385
28
  data.doc = doc;
1386
1387
28
  xmlHashScan((xmlHashTablePtr) source->entities,
1388
28
        xmlXIncludeMergeEntity, &data);
1389
28
    }
1390
429
    source = from->extSubset;
1391
429
    if ((source != NULL) && (source->entities != NULL)) {
1392
0
  xmlXIncludeMergeData data;
1393
1394
0
  data.ctxt = ctxt;
1395
0
  data.doc = doc;
1396
1397
  /*
1398
   * don't duplicate existing stuff when external subsets are the same
1399
   */
1400
0
  if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1401
0
      (!xmlStrEqual(target->SystemID, source->SystemID))) {
1402
0
      xmlHashScan((xmlHashTablePtr) source->entities,
1403
0
      xmlXIncludeMergeEntity, &data);
1404
0
  }
1405
0
    }
1406
429
    return(0);
1407
429
}
1408
1409
/**
1410
 * xmlXIncludeLoadDoc:
1411
 * @ctxt:  the XInclude context
1412
 * @url:  the associated URL
1413
 * @nr:  the xinclude node number
1414
 *
1415
 * Load the document, and store the result in the XInclude context
1416
 *
1417
 * Returns 0 in case of success, -1 in case of failure
1418
 */
1419
static int
1420
251k
xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1421
251k
    xmlDocPtr doc;
1422
251k
    xmlURIPtr uri;
1423
251k
    xmlChar *URL;
1424
251k
    xmlChar *fragment = NULL;
1425
251k
    int i = 0;
1426
251k
#ifdef LIBXML_XPTR_ENABLED
1427
251k
    int saveFlags;
1428
251k
#endif
1429
1430
#ifdef DEBUG_XINCLUDE
1431
    xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1432
#endif
1433
    /*
1434
     * Check the URL and remove any fragment identifier
1435
     */
1436
251k
    uri = xmlParseURI((const char *)url);
1437
251k
    if (uri == NULL) {
1438
0
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1439
0
                 XML_XINCLUDE_HREF_URI,
1440
0
           "invalid value URI %s\n", url);
1441
0
  return(-1);
1442
0
    }
1443
251k
    if (uri->fragment != NULL) {
1444
48.7k
  fragment = (xmlChar *) uri->fragment;
1445
48.7k
  uri->fragment = NULL;
1446
48.7k
    }
1447
251k
    if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
1448
251k
        (ctxt->incTab[nr]->fragment != NULL)) {
1449
142k
  if (fragment != NULL) xmlFree(fragment);
1450
142k
  fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
1451
142k
    }
1452
251k
    URL = xmlSaveUri(uri);
1453
251k
    xmlFreeURI(uri);
1454
251k
    if (URL == NULL) {
1455
0
        if (ctxt->incTab != NULL)
1456
0
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1457
0
         XML_XINCLUDE_HREF_URI,
1458
0
         "invalid value URI %s\n", url);
1459
0
  else
1460
0
      xmlXIncludeErr(ctxt, NULL,
1461
0
         XML_XINCLUDE_HREF_URI,
1462
0
         "invalid value URI %s\n", url);
1463
0
  if (fragment != NULL)
1464
0
      xmlFree(fragment);
1465
0
  return(-1);
1466
0
    }
1467
1468
    /*
1469
     * Handling of references to the local document are done
1470
     * directly through ctxt->doc.
1471
     */
1472
251k
    if ((URL[0] == 0) || (URL[0] == '#') ||
1473
251k
  ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
1474
134k
  doc = NULL;
1475
134k
        goto loaded;
1476
134k
    }
1477
1478
    /*
1479
     * Prevent reloading twice the document.
1480
     */
1481
439k
    for (i = 0; i < ctxt->incNr; i++) {
1482
323k
  if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1483
323k
      (ctxt->incTab[i]->doc != NULL)) {
1484
964
      doc = ctxt->incTab[i]->doc;
1485
#ifdef DEBUG_XINCLUDE
1486
      printf("Already loaded %s\n", URL);
1487
#endif
1488
964
      goto loaded;
1489
964
  }
1490
323k
    }
1491
1492
    /*
1493
     * Load it.
1494
     */
1495
#ifdef DEBUG_XINCLUDE
1496
    printf("loading %s\n", URL);
1497
#endif
1498
116k
#ifdef LIBXML_XPTR_ENABLED
1499
    /*
1500
     * If this is an XPointer evaluation, we want to assure that
1501
     * all entities have been resolved prior to processing the
1502
     * referenced document
1503
     */
1504
116k
    saveFlags = ctxt->parseFlags;
1505
116k
    if (fragment != NULL) { /* if this is an XPointer eval */
1506
14.4k
  ctxt->parseFlags |= XML_PARSE_NOENT;
1507
14.4k
    }
1508
116k
#endif
1509
1510
116k
    doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
1511
116k
#ifdef LIBXML_XPTR_ENABLED
1512
116k
    ctxt->parseFlags = saveFlags;
1513
116k
#endif
1514
116k
    if (doc == NULL) {
1515
114k
  xmlFree(URL);
1516
114k
  if (fragment != NULL)
1517
13.5k
      xmlFree(fragment);
1518
114k
  return(-1);
1519
114k
    }
1520
1.56k
    ctxt->incTab[nr]->doc = doc;
1521
    /*
1522
     * It's possible that the requested URL has been mapped to a
1523
     * completely different location (e.g. through a catalog entry).
1524
     * To check for this, we compare the URL with that of the doc
1525
     * and change it if they disagree (bug 146988).
1526
     */
1527
1.56k
   if (!xmlStrEqual(URL, doc->URL)) {
1528
1.56k
       xmlFree(URL);
1529
1.56k
       URL = xmlStrdup(doc->URL);
1530
1.56k
   }
1531
4.38k
    for (i = nr + 1; i < ctxt->incNr; i++) {
1532
2.82k
  if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1533
0
      ctxt->incTab[nr]->count++;
1534
#ifdef DEBUG_XINCLUDE
1535
      printf("Increasing %s count since reused\n", URL);
1536
#endif
1537
0
            break;
1538
0
  }
1539
2.82k
    }
1540
1541
    /*
1542
     * Make sure we have all entities fixed up
1543
     */
1544
1.56k
    xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
1545
1546
    /*
1547
     * We don't need the DTD anymore, free up space
1548
    if (doc->intSubset != NULL) {
1549
  xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1550
  xmlFreeNode((xmlNodePtr) doc->intSubset);
1551
  doc->intSubset = NULL;
1552
    }
1553
    if (doc->extSubset != NULL) {
1554
  xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1555
  xmlFreeNode((xmlNodePtr) doc->extSubset);
1556
  doc->extSubset = NULL;
1557
    }
1558
     */
1559
1.56k
    xmlXIncludeRecurseDoc(ctxt, doc, URL);
1560
1561
136k
loaded:
1562
136k
    if (fragment == NULL) {
1563
  /*
1564
   * Add the top children list as the replacement copy.
1565
   */
1566
7.78k
  if (doc == NULL)
1567
6.70k
  {
1568
      /* Hopefully a DTD declaration won't be copied from
1569
       * the same document */
1570
6.70k
      ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
1571
6.70k
  } else {
1572
1.07k
      ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
1573
1.07k
                                           doc, doc->children);
1574
1.07k
  }
1575
7.78k
    }
1576
128k
#ifdef LIBXML_XPTR_ENABLED
1577
128k
    else {
1578
  /*
1579
   * Computes the XPointer expression and make a copy used
1580
   * as the replacement copy.
1581
   */
1582
128k
  xmlXPathObjectPtr xptr;
1583
128k
  xmlXPathContextPtr xptrctxt;
1584
128k
  xmlNodeSetPtr set;
1585
1586
128k
  if (doc == NULL) {
1587
127k
      xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1588
127k
                             NULL);
1589
127k
  } else {
1590
1.44k
      xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1591
1.44k
  }
1592
128k
  if (xptrctxt == NULL) {
1593
0
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1594
0
                     XML_XINCLUDE_XPTR_FAILED,
1595
0
         "could not create XPointer context\n", NULL);
1596
0
      xmlFree(URL);
1597
0
      xmlFree(fragment);
1598
0
      return(-1);
1599
0
  }
1600
128k
  xptr = xmlXPtrEval(fragment, xptrctxt);
1601
128k
  if (xptr == NULL) {
1602
89.4k
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1603
89.4k
                     XML_XINCLUDE_XPTR_FAILED,
1604
89.4k
         "XPointer evaluation failed: #%s\n",
1605
89.4k
         fragment);
1606
89.4k
      xmlXPathFreeContext(xptrctxt);
1607
89.4k
      xmlFree(URL);
1608
89.4k
      xmlFree(fragment);
1609
89.4k
      return(-1);
1610
89.4k
  }
1611
39.4k
  switch (xptr->type) {
1612
0
      case XPATH_UNDEFINED:
1613
0
      case XPATH_BOOLEAN:
1614
0
      case XPATH_NUMBER:
1615
0
      case XPATH_STRING:
1616
#ifdef LIBXML_XPTR_LOCS_ENABLED
1617
      case XPATH_POINT:
1618
#endif
1619
0
      case XPATH_USERS:
1620
0
      case XPATH_XSLT_TREE:
1621
0
    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1622
0
                   XML_XINCLUDE_XPTR_RESULT,
1623
0
             "XPointer is not a range: #%s\n",
1624
0
             fragment);
1625
0
                xmlXPathFreeObject(xptr);
1626
0
    xmlXPathFreeContext(xptrctxt);
1627
0
    xmlFree(URL);
1628
0
    xmlFree(fragment);
1629
0
    return(-1);
1630
39.4k
      case XPATH_NODESET:
1631
39.4k
          if ((xptr->nodesetval == NULL) ||
1632
39.4k
        (xptr->nodesetval->nodeNr <= 0)) {
1633
3.72k
                    xmlXPathFreeObject(xptr);
1634
3.72k
        xmlXPathFreeContext(xptrctxt);
1635
3.72k
        xmlFree(URL);
1636
3.72k
        xmlFree(fragment);
1637
3.72k
        return(-1);
1638
3.72k
    }
1639
1640
#ifdef LIBXML_XPTR_LOCS_ENABLED
1641
      case XPATH_RANGE:
1642
      case XPATH_LOCATIONSET:
1643
    break;
1644
#endif
1645
39.4k
  }
1646
35.7k
  set = xptr->nodesetval;
1647
35.7k
  if (set != NULL) {
1648
2.36M
      for (i = 0;i < set->nodeNr;i++) {
1649
2.32M
    if (set->nodeTab[i] == NULL)
1650
0
        continue;
1651
2.32M
    switch (set->nodeTab[i]->type) {
1652
979k
        case XML_ELEMENT_NODE:
1653
2.01M
        case XML_TEXT_NODE:
1654
2.02M
        case XML_CDATA_SECTION_NODE:
1655
2.02M
        case XML_ENTITY_REF_NODE:
1656
2.02M
        case XML_ENTITY_NODE:
1657
2.03M
        case XML_PI_NODE:
1658
2.06M
        case XML_COMMENT_NODE:
1659
2.08M
        case XML_DOCUMENT_NODE:
1660
2.08M
        case XML_HTML_DOCUMENT_NODE:
1661
2.08M
      continue;
1662
1663
242k
        case XML_ATTRIBUTE_NODE:
1664
242k
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1665
242k
                     XML_XINCLUDE_XPTR_RESULT,
1666
242k
               "XPointer selects an attribute: #%s\n",
1667
242k
               fragment);
1668
242k
      set->nodeTab[i] = NULL;
1669
242k
      continue;
1670
0
        case XML_NAMESPACE_DECL:
1671
0
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1672
0
                     XML_XINCLUDE_XPTR_RESULT,
1673
0
               "XPointer selects a namespace: #%s\n",
1674
0
               fragment);
1675
0
      set->nodeTab[i] = NULL;
1676
0
      continue;
1677
0
        case XML_DOCUMENT_TYPE_NODE:
1678
0
        case XML_DOCUMENT_FRAG_NODE:
1679
0
        case XML_NOTATION_NODE:
1680
0
        case XML_DTD_NODE:
1681
0
        case XML_ELEMENT_DECL:
1682
0
        case XML_ATTRIBUTE_DECL:
1683
0
        case XML_ENTITY_DECL:
1684
0
        case XML_XINCLUDE_START:
1685
0
        case XML_XINCLUDE_END:
1686
0
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1687
0
                     XML_XINCLUDE_XPTR_RESULT,
1688
0
           "XPointer selects unexpected nodes: #%s\n",
1689
0
               fragment);
1690
0
      set->nodeTab[i] = NULL;
1691
0
      set->nodeTab[i] = NULL;
1692
0
      continue; /* for */
1693
2.32M
    }
1694
2.32M
      }
1695
35.7k
  }
1696
35.7k
  if (doc == NULL) {
1697
35.6k
      ctxt->incTab[nr]->xptr = xptr;
1698
35.6k
      ctxt->incTab[nr]->inc = NULL;
1699
35.6k
  } else {
1700
82
      ctxt->incTab[nr]->inc =
1701
82
    xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1702
82
      xmlXPathFreeObject(xptr);
1703
82
  }
1704
35.7k
  xmlXPathFreeContext(xptrctxt);
1705
35.7k
  xmlFree(fragment);
1706
35.7k
    }
1707
43.4k
#endif
1708
1709
    /*
1710
     * Do the xml:base fixup if needed
1711
     */
1712
43.4k
    if ((doc != NULL) && (URL != NULL) &&
1713
43.4k
        (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) &&
1714
43.4k
  (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) {
1715
334
  xmlNodePtr node;
1716
334
  xmlChar *base;
1717
334
  xmlChar *curBase;
1718
1719
  /*
1720
   * The base is only adjusted if "necessary", i.e. if the xinclude node
1721
   * has a base specified, or the URL is relative
1722
   */
1723
334
  base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base",
1724
334
      XML_XML_NAMESPACE);
1725
334
  if (base == NULL) {
1726
      /*
1727
       * No xml:base on the xinclude node, so we check whether the
1728
       * URI base is different than (relative to) the context base
1729
       */
1730
334
      curBase = xmlBuildRelativeURI(URL, ctxt->base);
1731
334
      if (curBase == NULL) { /* Error return */
1732
0
          xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1733
0
                 XML_XINCLUDE_HREF_URI,
1734
0
           "trying to build relative URI from %s\n", URL);
1735
334
      } else {
1736
    /* If the URI doesn't contain a slash, it's not relative */
1737
334
          if (!xmlStrchr(curBase, '/'))
1738
0
        xmlFree(curBase);
1739
334
    else
1740
334
        base = curBase;
1741
334
      }
1742
334
  }
1743
334
  if (base != NULL) { /* Adjustment may be needed */
1744
334
      node = ctxt->incTab[nr]->inc;
1745
805
      while (node != NULL) {
1746
    /* Only work on element nodes */
1747
471
    if (node->type == XML_ELEMENT_NODE) {
1748
433
        curBase = xmlNodeGetBase(node->doc, node);
1749
        /* If no current base, set it */
1750
433
        if (curBase == NULL) {
1751
0
      xmlNodeSetBase(node, base);
1752
433
        } else {
1753
      /*
1754
       * If the current base is the same as the
1755
       * URL of the document, then reset it to be
1756
       * the specified xml:base or the relative URI
1757
       */
1758
433
      if (xmlStrEqual(curBase, node->doc->URL)) {
1759
433
          xmlNodeSetBase(node, base);
1760
433
      } else {
1761
          /*
1762
           * If the element already has an xml:base
1763
           * set, then relativise it if necessary
1764
           */
1765
0
          xmlChar *xmlBase;
1766
0
          xmlBase = xmlGetNsProp(node,
1767
0
              BAD_CAST "base",
1768
0
              XML_XML_NAMESPACE);
1769
0
          if (xmlBase != NULL) {
1770
0
        xmlChar *relBase;
1771
0
        relBase = xmlBuildURI(xmlBase, base);
1772
0
        if (relBase == NULL) { /* error */
1773
0
            xmlXIncludeErr(ctxt,
1774
0
            ctxt->incTab[nr]->ref,
1775
0
            XML_XINCLUDE_HREF_URI,
1776
0
          "trying to rebuild base from %s\n",
1777
0
            xmlBase);
1778
0
        } else {
1779
0
            xmlNodeSetBase(node, relBase);
1780
0
            xmlFree(relBase);
1781
0
        }
1782
0
        xmlFree(xmlBase);
1783
0
          }
1784
0
      }
1785
433
      xmlFree(curBase);
1786
433
        }
1787
433
    }
1788
471
          node = node->next;
1789
471
      }
1790
334
      xmlFree(base);
1791
334
  }
1792
334
    }
1793
43.4k
    if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1794
43.4k
  (ctxt->incTab[nr]->count <= 1)) {
1795
#ifdef DEBUG_XINCLUDE
1796
        printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1797
#endif
1798
754
  xmlFreeDoc(ctxt->incTab[nr]->doc);
1799
754
  ctxt->incTab[nr]->doc = NULL;
1800
754
    }
1801
43.4k
    xmlFree(URL);
1802
43.4k
    return(0);
1803
136k
}
1804
1805
/**
1806
 * xmlXIncludeLoadTxt:
1807
 * @ctxt:  the XInclude context
1808
 * @url:  the associated URL
1809
 * @nr:  the xinclude node number
1810
 *
1811
 * Load the content, and store the result in the XInclude context
1812
 *
1813
 * Returns 0 in case of success, -1 in case of failure
1814
 */
1815
static int
1816
1.04k
xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1817
1.04k
    xmlParserInputBufferPtr buf;
1818
1.04k
    xmlNodePtr node;
1819
1.04k
    xmlURIPtr uri;
1820
1.04k
    xmlChar *URL;
1821
1.04k
    int i;
1822
1.04k
    xmlChar *encoding = NULL;
1823
1.04k
    xmlCharEncoding enc = (xmlCharEncoding) 0;
1824
1.04k
    xmlParserCtxtPtr pctxt;
1825
1.04k
    xmlParserInputPtr inputStream;
1826
1.04k
    int xinclude_multibyte_fallback_used = 0;
1827
1828
    /* Don't read from stdin. */
1829
1.04k
    if (xmlStrcmp(url, BAD_CAST "-") == 0)
1830
0
        url = BAD_CAST "./-";
1831
1832
    /*
1833
     * Check the URL and remove any fragment identifier
1834
     */
1835
1.04k
    uri = xmlParseURI((const char *)url);
1836
1.04k
    if (uri == NULL) {
1837
0
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1838
0
                 "invalid value URI %s\n", url);
1839
0
  return(-1);
1840
0
    }
1841
1.04k
    if (uri->fragment != NULL) {
1842
91
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1843
91
                 "fragment identifier forbidden for text: %s\n",
1844
91
           (const xmlChar *) uri->fragment);
1845
91
  xmlFreeURI(uri);
1846
91
  return(-1);
1847
91
    }
1848
953
    URL = xmlSaveUri(uri);
1849
953
    xmlFreeURI(uri);
1850
953
    if (URL == NULL) {
1851
0
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1852
0
                 "invalid value URI %s\n", url);
1853
0
  return(-1);
1854
0
    }
1855
1856
    /*
1857
     * Handling of references to the local document are done
1858
     * directly through ctxt->doc.
1859
     */
1860
953
    if (URL[0] == 0) {
1861
35
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1862
35
                 XML_XINCLUDE_TEXT_DOCUMENT,
1863
35
           "text serialization of document not available\n", NULL);
1864
35
  xmlFree(URL);
1865
35
  return(-1);
1866
35
    }
1867
1868
    /*
1869
     * Prevent reloading twice the document.
1870
     */
1871
982
    for (i = 0; i < ctxt->txtNr; i++) {
1872
195
  if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1873
131
            node = xmlNewDocText(ctxt->doc, ctxt->txtTab[i]);
1874
131
      goto loaded;
1875
131
  }
1876
195
    }
1877
    /*
1878
     * Try to get the encoding if available
1879
     */
1880
787
    if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1881
787
  encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1882
787
    }
1883
787
    if (encoding != NULL) {
1884
  /*
1885
   * TODO: we should not have to remap to the xmlCharEncoding
1886
   *       predefined set, a better interface than
1887
   *       xmlParserInputBufferCreateFilename should allow any
1888
   *       encoding supported by iconv
1889
   */
1890
571
        enc = xmlParseCharEncoding((const char *) encoding);
1891
571
  if (enc == XML_CHAR_ENCODING_ERROR) {
1892
86
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1893
86
                     XML_XINCLUDE_UNKNOWN_ENCODING,
1894
86
         "encoding %s not supported\n", encoding);
1895
86
      xmlFree(encoding);
1896
86
      xmlFree(URL);
1897
86
      return(-1);
1898
86
  }
1899
485
  xmlFree(encoding);
1900
485
    }
1901
1902
    /*
1903
     * Load it.
1904
     */
1905
701
    pctxt = xmlNewParserCtxt();
1906
701
    inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt);
1907
701
    if(inputStream == NULL) {
1908
418
  xmlFreeParserCtxt(pctxt);
1909
418
  xmlFree(URL);
1910
418
  return(-1);
1911
418
    }
1912
283
    buf = inputStream->buf;
1913
283
    if (buf == NULL) {
1914
0
  xmlFreeInputStream (inputStream);
1915
0
  xmlFreeParserCtxt(pctxt);
1916
0
  xmlFree(URL);
1917
0
  return(-1);
1918
0
    }
1919
283
    if (buf->encoder)
1920
0
  xmlCharEncCloseFunc(buf->encoder);
1921
283
    buf->encoder = xmlGetCharEncodingHandler(enc);
1922
283
    node = xmlNewDocText(ctxt->doc, NULL);
1923
1924
    /*
1925
     * Scan all chars from the resource and add the to the node
1926
     */
1927
283
xinclude_multibyte_fallback:
1928
283
    while (xmlParserInputBufferRead(buf, 128) > 0) {
1929
0
  int len;
1930
0
  const xmlChar *content;
1931
1932
0
  content = xmlBufContent(buf->buffer);
1933
0
  len = xmlBufLength(buf->buffer);
1934
0
  for (i = 0;i < len;) {
1935
0
      int cur;
1936
0
      int l;
1937
1938
0
      cur = xmlStringCurrentChar(NULL, &content[i], &l);
1939
0
      if (!IS_CHAR(cur)) {
1940
    /* Handle split multibyte char at buffer boundary */
1941
0
    if (((len - i) < 4) && (!xinclude_multibyte_fallback_used)) {
1942
0
        xinclude_multibyte_fallback_used = 1;
1943
0
        xmlBufShrink(buf->buffer, i);
1944
0
        goto xinclude_multibyte_fallback;
1945
0
    } else {
1946
0
        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1947
0
           XML_XINCLUDE_INVALID_CHAR,
1948
0
           "%s contains invalid char\n", URL);
1949
0
        xmlFreeParserCtxt(pctxt);
1950
0
        xmlFreeParserInputBuffer(buf);
1951
0
        xmlFree(URL);
1952
0
        return(-1);
1953
0
    }
1954
0
      } else {
1955
0
    xinclude_multibyte_fallback_used = 0;
1956
0
    xmlNodeAddContentLen(node, &content[i], l);
1957
0
      }
1958
0
      i += l;
1959
0
  }
1960
0
  xmlBufShrink(buf->buffer, len);
1961
0
    }
1962
283
    xmlFreeParserCtxt(pctxt);
1963
283
    xmlXIncludeAddTxt(ctxt, node->content, URL);
1964
283
    xmlFreeInputStream(inputStream);
1965
1966
414
loaded:
1967
    /*
1968
     * Add the element as the replacement copy.
1969
     */
1970
414
    ctxt->incTab[nr]->inc = node;
1971
414
    xmlFree(URL);
1972
414
    return(0);
1973
283
}
1974
1975
/**
1976
 * xmlXIncludeLoadFallback:
1977
 * @ctxt:  the XInclude context
1978
 * @fallback:  the fallback node
1979
 * @nr:  the xinclude node number
1980
 *
1981
 * Load the content of the fallback node, and store the result
1982
 * in the XInclude context
1983
 *
1984
 * Returns 0 in case of success, -1 in case of failure
1985
 */
1986
static int
1987
75.1k
xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1988
75.1k
    xmlXIncludeCtxtPtr newctxt;
1989
75.1k
    int ret = 0;
1990
75.1k
    int oldNbErrors = ctxt->nbErrors;
1991
1992
75.1k
    if ((fallback == NULL) || (fallback->type == XML_NAMESPACE_DECL) ||
1993
75.1k
        (ctxt == NULL))
1994
0
  return(-1);
1995
75.1k
    if (fallback->children != NULL) {
1996
  /*
1997
   * It's possible that the fallback also has 'includes'
1998
   * (Bug 129969), so we re-process the fallback just in case
1999
   */
2000
74.4k
  newctxt = xmlXIncludeNewContext(ctxt->doc);
2001
74.4k
  if (newctxt == NULL)
2002
0
      return (-1);
2003
74.4k
  newctxt->_private = ctxt->_private;
2004
74.4k
  newctxt->base = xmlStrdup(ctxt->base);  /* Inherit the base from the existing context */
2005
74.4k
  xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
2006
74.4k
        newctxt->incTotal = ctxt->incTotal;
2007
74.4k
        if (xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback, 1) < 0)
2008
699
            ret = -1;
2009
74.4k
        ctxt->incTotal = newctxt->incTotal;
2010
74.4k
  if (ctxt->nbErrors > oldNbErrors)
2011
0
      ret = -1;
2012
74.4k
  xmlXIncludeFreeContext(newctxt);
2013
2014
74.4k
  ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
2015
74.4k
                                             fallback->children);
2016
74.4k
        if (ctxt->incTab[nr]->inc == NULL)
2017
63
            ctxt->incTab[nr]->emptyFb = 1;
2018
74.4k
    } else {
2019
636
        ctxt->incTab[nr]->inc = NULL;
2020
636
  ctxt->incTab[nr]->emptyFb = 1;  /* flag empty callback */
2021
636
    }
2022
75.1k
    ctxt->incTab[nr]->fallback = 1;
2023
75.1k
    return(ret);
2024
75.1k
}
2025
2026
/************************************************************************
2027
 *                  *
2028
 *      XInclude Processing       *
2029
 *                  *
2030
 ************************************************************************/
2031
2032
/**
2033
 * xmlXIncludePreProcessNode:
2034
 * @ctxt: an XInclude context
2035
 * @node: an XInclude node
2036
 *
2037
 * Implement the XInclude preprocessing, currently just adding the element
2038
 * for further processing.
2039
 *
2040
 * Returns the result list or NULL in case of error
2041
 */
2042
static xmlNodePtr
2043
297k
xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2044
297k
    xmlXIncludeAddNode(ctxt, node);
2045
297k
    return(NULL);
2046
297k
}
2047
2048
/**
2049
 * xmlXIncludeLoadNode:
2050
 * @ctxt: an XInclude context
2051
 * @nr: the node number
2052
 *
2053
 * Find and load the infoset replacement for the given node.
2054
 *
2055
 * Returns 0 if substitution succeeded, -1 if some processing failed
2056
 */
2057
static int
2058
252k
xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
2059
252k
    xmlNodePtr cur;
2060
252k
    xmlChar *href;
2061
252k
    xmlChar *parse;
2062
252k
    xmlChar *base;
2063
252k
    xmlChar *oldBase;
2064
252k
    xmlChar *URI;
2065
252k
    int xml = 1; /* default Issue 64 */
2066
252k
    int ret;
2067
2068
252k
    if (ctxt == NULL)
2069
0
  return(-1);
2070
252k
    if ((nr < 0) || (nr >= ctxt->incNr))
2071
0
  return(-1);
2072
252k
    cur = ctxt->incTab[nr]->ref;
2073
252k
    if (cur == NULL)
2074
0
  return(-1);
2075
2076
    /*
2077
     * read the attributes
2078
     */
2079
252k
    href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
2080
252k
    if (href == NULL) {
2081
93.7k
  href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
2082
93.7k
  if (href == NULL)
2083
0
      return(-1);
2084
93.7k
    }
2085
252k
    parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
2086
252k
    if (parse != NULL) {
2087
2.17k
  if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
2088
1.12k
      xml = 1;
2089
1.04k
  else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
2090
1.04k
      xml = 0;
2091
0
  else {
2092
0
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2093
0
                     XML_XINCLUDE_PARSE_VALUE,
2094
0
         "invalid value %s for 'parse'\n", parse);
2095
0
      if (href != NULL)
2096
0
    xmlFree(href);
2097
0
      if (parse != NULL)
2098
0
    xmlFree(parse);
2099
0
      return(-1);
2100
0
  }
2101
2.17k
    }
2102
2103
    /*
2104
     * compute the URI
2105
     */
2106
252k
    base = xmlNodeGetBase(ctxt->doc, cur);
2107
252k
    if (base == NULL) {
2108
7.81k
  URI = xmlBuildURI(href, ctxt->doc->URL);
2109
244k
    } else {
2110
244k
  URI = xmlBuildURI(href, base);
2111
244k
    }
2112
252k
    if (URI == NULL) {
2113
13.6k
  xmlChar *escbase;
2114
13.6k
  xmlChar *eschref;
2115
  /*
2116
   * Some escaping may be needed
2117
   */
2118
13.6k
  escbase = xmlURIEscape(base);
2119
13.6k
  eschref = xmlURIEscape(href);
2120
13.6k
  URI = xmlBuildURI(eschref, escbase);
2121
13.6k
  if (escbase != NULL)
2122
12.6k
      xmlFree(escbase);
2123
13.6k
  if (eschref != NULL)
2124
13.6k
      xmlFree(eschref);
2125
13.6k
    }
2126
252k
    if (URI == NULL) {
2127
0
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2128
0
                 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
2129
0
  if (parse != NULL)
2130
0
      xmlFree(parse);
2131
0
  if (href != NULL)
2132
0
      xmlFree(href);
2133
0
  if (base != NULL)
2134
0
      xmlFree(base);
2135
0
  return(-1);
2136
0
    }
2137
#ifdef DEBUG_XINCLUDE
2138
    xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
2139
      xml ? "xml": "text");
2140
    xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
2141
#endif
2142
2143
    /*
2144
     * Save the base for this include (saving the current one)
2145
     */
2146
252k
    oldBase = ctxt->base;
2147
252k
    ctxt->base = base;
2148
2149
252k
    if (xml) {
2150
251k
  ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
2151
  /* xmlXIncludeGetFragment(ctxt, cur, URI); */
2152
251k
    } else {
2153
1.04k
  ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
2154
1.04k
    }
2155
2156
    /*
2157
     * Restore the original base before checking for fallback
2158
     */
2159
252k
    ctxt->base = oldBase;
2160
2161
252k
    if (ret < 0) {
2162
208k
  xmlNodePtr children;
2163
2164
  /*
2165
   * Time to try a fallback if available
2166
   */
2167
#ifdef DEBUG_XINCLUDE
2168
  xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
2169
#endif
2170
208k
  children = cur->children;
2171
277k
  while (children != NULL) {
2172
144k
      if ((children->type == XML_ELEMENT_NODE) &&
2173
144k
    (children->ns != NULL) &&
2174
144k
    (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
2175
144k
    ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
2176
75.2k
     (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
2177
75.1k
    ret = xmlXIncludeLoadFallback(ctxt, children, nr);
2178
75.1k
    break;
2179
75.1k
      }
2180
69.0k
      children = children->next;
2181
69.0k
  }
2182
208k
    }
2183
252k
    if (ret < 0) {
2184
134k
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2185
134k
                 XML_XINCLUDE_NO_FALLBACK,
2186
134k
           "could not load %s, and no fallback was found\n",
2187
134k
           URI);
2188
134k
    }
2189
2190
    /*
2191
     * Cleanup
2192
     */
2193
252k
    if (URI != NULL)
2194
252k
  xmlFree(URI);
2195
252k
    if (parse != NULL)
2196
2.17k
  xmlFree(parse);
2197
252k
    if (href != NULL)
2198
252k
  xmlFree(href);
2199
252k
    if (base != NULL)
2200
244k
  xmlFree(base);
2201
252k
    return(0);
2202
252k
}
2203
2204
/**
2205
 * xmlXIncludeIncludeNode:
2206
 * @ctxt: an XInclude context
2207
 * @nr: the node number
2208
 *
2209
 * Implement the infoset replacement for the given node
2210
 *
2211
 * Returns 0 if substitution succeeded, -1 if some processing failed
2212
 */
2213
static int
2214
116k
xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
2215
116k
    xmlNodePtr cur, end, list, tmp;
2216
2217
116k
    if (ctxt == NULL)
2218
0
  return(-1);
2219
116k
    if ((nr < 0) || (nr >= ctxt->incNr))
2220
0
  return(-1);
2221
116k
    cur = ctxt->incTab[nr]->ref;
2222
116k
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
2223
0
  return(-1);
2224
2225
    /*
2226
     * If we stored an XPointer a late computation may be needed
2227
     */
2228
116k
    if ((ctxt->incTab[nr]->inc == NULL) &&
2229
116k
  (ctxt->incTab[nr]->xptr != NULL)) {
2230
34.5k
  ctxt->incTab[nr]->inc =
2231
34.5k
      xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
2232
34.5k
                        ctxt->incTab[nr]->xptr);
2233
34.5k
  xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
2234
34.5k
  ctxt->incTab[nr]->xptr = NULL;
2235
34.5k
    }
2236
116k
    list = ctxt->incTab[nr]->inc;
2237
116k
    ctxt->incTab[nr]->inc = NULL;
2238
116k
    ctxt->incTab[nr]->emptyFb = 0;
2239
2240
    /*
2241
     * Check against the risk of generating a multi-rooted document
2242
     */
2243
116k
    if ((cur->parent != NULL) &&
2244
116k
  (cur->parent->type != XML_ELEMENT_NODE)) {
2245
907
  int nb_elem = 0;
2246
2247
907
  tmp = list;
2248
9.71k
  while (tmp != NULL) {
2249
8.80k
      if (tmp->type == XML_ELEMENT_NODE)
2250
3.34k
    nb_elem++;
2251
8.80k
      tmp = tmp->next;
2252
8.80k
  }
2253
907
  if (nb_elem > 1) {
2254
455
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2255
455
                     XML_XINCLUDE_MULTIPLE_ROOT,
2256
455
           "XInclude error: would result in multiple root nodes\n",
2257
455
         NULL);
2258
455
            xmlFreeNodeList(list);
2259
455
      return(-1);
2260
455
  }
2261
907
    }
2262
2263
116k
    if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
2264
  /*
2265
   * Add the list of nodes
2266
   */
2267
733k
  while (list != NULL) {
2268
681k
      end = list;
2269
681k
      list = list->next;
2270
2271
681k
      xmlAddPrevSibling(cur, end);
2272
681k
  }
2273
        /*
2274
         * FIXME: xmlUnlinkNode doesn't coalesce text nodes.
2275
         */
2276
51.8k
  xmlUnlinkNode(cur);
2277
51.8k
  xmlFreeNode(cur);
2278
64.3k
    } else {
2279
64.3k
        xmlNodePtr child, next;
2280
2281
  /*
2282
   * Change the current node as an XInclude start one, and add an
2283
   * XInclude end one
2284
   */
2285
64.3k
        if (ctxt->incTab[nr]->fallback)
2286
37.7k
            xmlUnsetProp(cur, BAD_CAST "href");
2287
64.3k
  cur->type = XML_XINCLUDE_START;
2288
        /* Remove fallback children */
2289
154k
        for (child = cur->children; child != NULL; child = next) {
2290
89.7k
            next = child->next;
2291
89.7k
            xmlUnlinkNode(child);
2292
89.7k
            xmlFreeNode(child);
2293
89.7k
        }
2294
64.3k
  end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
2295
64.3k
  if (end == NULL) {
2296
0
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2297
0
                     XML_XINCLUDE_BUILD_FAILED,
2298
0
         "failed to build node\n", NULL);
2299
0
            xmlFreeNodeList(list);
2300
0
      return(-1);
2301
0
  }
2302
64.3k
  end->type = XML_XINCLUDE_END;
2303
64.3k
  xmlAddNextSibling(cur, end);
2304
2305
  /*
2306
   * Add the list of nodes
2307
   */
2308
5.41M
  while (list != NULL) {
2309
5.34M
      cur = list;
2310
5.34M
      list = list->next;
2311
2312
5.34M
      xmlAddPrevSibling(end, cur);
2313
5.34M
  }
2314
64.3k
    }
2315
2316
2317
116k
    return(0);
2318
116k
}
2319
2320
/**
2321
 * xmlXIncludeTestNode:
2322
 * @ctxt: the XInclude processing context
2323
 * @node: an XInclude node
2324
 *
2325
 * test if the node is an XInclude node
2326
 *
2327
 * Returns 1 true, 0 otherwise
2328
 */
2329
static int
2330
8.05M
xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2331
8.05M
    if (node == NULL)
2332
0
  return(0);
2333
8.05M
    if (node->type != XML_ELEMENT_NODE)
2334
3.90M
  return(0);
2335
4.15M
    if (node->ns == NULL)
2336
3.48M
  return(0);
2337
668k
    if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
2338
668k
        (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
2339
395k
  if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
2340
367k
      if (ctxt->legacy == 0) {
2341
#if 0 /* wait for the XML Core Working Group to get something stable ! */
2342
    xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
2343
                 "Deprecated XInclude namespace found, use %s",
2344
                    XINCLUDE_NS);
2345
#endif
2346
152k
          ctxt->legacy = 1;
2347
152k
      }
2348
367k
  }
2349
395k
  if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2350
314k
      xmlNodePtr child = node->children;
2351
314k
      int nb_fallback = 0;
2352
2353
607k
      while (child != NULL) {
2354
306k
    if ((child->type == XML_ELEMENT_NODE) &&
2355
306k
        (child->ns != NULL) &&
2356
306k
        ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
2357
111k
         (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
2358
106k
        if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
2359
14.0k
      xmlXIncludeErr(ctxt, node,
2360
14.0k
                     XML_XINCLUDE_INCLUDE_IN_INCLUDE,
2361
14.0k
               "%s has an 'include' child\n",
2362
14.0k
               XINCLUDE_NODE);
2363
14.0k
      return(0);
2364
14.0k
        }
2365
92.1k
        if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2366
82.8k
      nb_fallback++;
2367
82.8k
        }
2368
92.1k
    }
2369
292k
    child = child->next;
2370
292k
      }
2371
300k
      if (nb_fallback > 1) {
2372
1.65k
    xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
2373
1.65k
             "%s has multiple fallback children\n",
2374
1.65k
                   XINCLUDE_NODE);
2375
1.65k
    return(0);
2376
1.65k
      }
2377
299k
      return(1);
2378
300k
  }
2379
81.0k
  if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2380
37.2k
      if ((node->parent == NULL) ||
2381
37.2k
    (node->parent->type != XML_ELEMENT_NODE) ||
2382
37.2k
    (node->parent->ns == NULL) ||
2383
37.2k
    ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
2384
31.6k
     (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
2385
37.2k
    (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
2386
28.4k
    xmlXIncludeErr(ctxt, node,
2387
28.4k
                   XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
2388
28.4k
             "%s is not the child of an 'include'\n",
2389
28.4k
             XINCLUDE_FALLBACK);
2390
28.4k
      }
2391
37.2k
  }
2392
81.0k
    }
2393
353k
    return(0);
2394
668k
}
2395
2396
/**
2397
 * xmlXIncludeDoProcess:
2398
 * @ctxt: the XInclude processing context
2399
 * @doc: an XML document
2400
 * @tree: the top of the tree to process
2401
 * @skipRoot: don't process the root node of the tree
2402
 *
2403
 * Implement the XInclude substitution on the XML document @doc
2404
 *
2405
 * Returns 0 if no substitution were done, -1 if some processing failed
2406
 *    or the number of substitutions done.
2407
 */
2408
static int
2409
xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree,
2410
233k
                     int skipRoot) {
2411
233k
    xmlNodePtr cur;
2412
233k
    int ret = 0;
2413
233k
    int i, start;
2414
2415
233k
    if ((doc == NULL) || (tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2416
0
  return(-1);
2417
233k
    if ((skipRoot) && (tree->children == NULL))
2418
0
        return(-1);
2419
233k
    if (ctxt == NULL)
2420
0
  return(-1);
2421
2422
233k
    if (doc->URL != NULL) {
2423
222k
  ret = xmlXIncludeURLPush(ctxt, doc->URL);
2424
222k
  if (ret < 0)
2425
0
      return(-1);
2426
222k
    }
2427
233k
    start = ctxt->incNr;
2428
2429
    /*
2430
     * TODO: The phases must run separately for recursive inclusions.
2431
     *
2432
     * - Phase 1 should start with top-level XInclude nodes, load documents,
2433
     *   execute XPointer expressions, then process only the result nodes
2434
     *   (not whole document, see bug #324081) and only for phase 1
2435
     *   recursively. We will need a backreference from xmlNodes to
2436
     *   xmlIncludeRefs to detect references that were already visited.
2437
     *   This can also be used for proper cycle detection, see bug #344240.
2438
     *
2439
     * - Phase 2 should visit all top-level XInclude nodes and expand
2440
     *   possible subreferences in the replacement recursively.
2441
     *
2442
     * - Phase 3 should finally replace the top-level XInclude nodes.
2443
     *   It could also be run together with phase 2.
2444
     */
2445
2446
    /*
2447
     * First phase: lookup the elements in the document
2448
     */
2449
233k
    if (skipRoot)
2450
74.4k
        cur = tree->children;
2451
158k
    else
2452
158k
        cur = tree;
2453
8.05M
    do {
2454
  /* TODO: need to work on entities -> stack */
2455
8.05M
        if (xmlXIncludeTestNode(ctxt, cur) == 1) {
2456
299k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2457
            /*
2458
             * Avoid superlinear expansion by limiting the total number
2459
             * of replacements.
2460
             */
2461
299k
            if (ctxt->incTotal >= 20)
2462
1.25k
                return(-1);
2463
297k
#endif
2464
297k
            ctxt->incTotal++;
2465
297k
            xmlXIncludePreProcessNode(ctxt, cur);
2466
7.75M
        } else if ((cur->children != NULL) &&
2467
7.75M
                   ((cur->type == XML_DOCUMENT_NODE) ||
2468
1.64M
                    (cur->type == XML_ELEMENT_NODE))) {
2469
1.63M
            cur = cur->children;
2470
1.63M
            continue;
2471
1.63M
        }
2472
8.12M
        do {
2473
8.12M
            if (cur == tree)
2474
232k
                break;
2475
7.89M
            if (cur->next != NULL) {
2476
6.19M
                cur = cur->next;
2477
6.19M
                break;
2478
6.19M
            }
2479
1.70M
            cur = cur->parent;
2480
1.70M
        } while (cur != NULL);
2481
8.05M
    } while ((cur != NULL) && (cur != tree));
2482
2483
    /*
2484
     * Second Phase : collect the infosets fragments
2485
     */
2486
484k
    for (i = start;i < ctxt->incNr; i++) {
2487
252k
        xmlXIncludeLoadNode(ctxt, i);
2488
252k
  ret++;
2489
252k
    }
2490
2491
    /*
2492
     * Third phase: extend the original document infoset.
2493
     *
2494
     * Originally we bypassed the inclusion if there were any errors
2495
     * encountered on any of the XIncludes.  A bug was raised (bug
2496
     * 132588) requesting that we output the XIncludes without error,
2497
     * so the check for inc!=NULL || xptr!=NULL was put in.  This may
2498
     * give some other problems in the future, but for now it seems to
2499
     * work ok.
2500
     *
2501
     */
2502
501k
    for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2503
269k
  if ((ctxt->incTab[i]->inc != NULL) ||
2504
269k
            (ctxt->incTab[i]->xptr != NULL) ||
2505
269k
      (ctxt->incTab[i]->emptyFb != 0))  /* (empty fallback) */
2506
116k
      xmlXIncludeIncludeNode(ctxt, i);
2507
269k
    }
2508
2509
232k
    if (doc->URL != NULL)
2510
218k
  xmlXIncludeURLPop(ctxt);
2511
232k
    return(ret);
2512
233k
}
2513
2514
/**
2515
 * xmlXIncludeSetFlags:
2516
 * @ctxt:  an XInclude processing context
2517
 * @flags: a set of xmlParserOption used for parsing XML includes
2518
 *
2519
 * Set the flags used for further processing of XML resources.
2520
 *
2521
 * Returns 0 in case of success and -1 in case of error.
2522
 */
2523
int
2524
226k
xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
2525
226k
    if (ctxt == NULL)
2526
0
        return(-1);
2527
226k
    ctxt->parseFlags = flags;
2528
226k
    return(0);
2529
226k
}
2530
2531
/**
2532
 * xmlXIncludeProcessTreeFlagsData:
2533
 * @tree: an XML node
2534
 * @flags: a set of xmlParserOption used for parsing XML includes
2535
 * @data: application data that will be passed to the parser context
2536
 *        in the _private field of the parser context(s)
2537
 *
2538
 * Implement the XInclude substitution on the XML node @tree
2539
 *
2540
 * Returns 0 if no substitution were done, -1 if some processing failed
2541
 *    or the number of substitutions done.
2542
 */
2543
2544
int
2545
148k
xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
2546
148k
    xmlXIncludeCtxtPtr ctxt;
2547
148k
    int ret = 0;
2548
2549
148k
    if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) ||
2550
148k
        (tree->doc == NULL))
2551
0
        return(-1);
2552
2553
148k
    ctxt = xmlXIncludeNewContext(tree->doc);
2554
148k
    if (ctxt == NULL)
2555
0
        return(-1);
2556
148k
    ctxt->_private = data;
2557
148k
    ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
2558
148k
    xmlXIncludeSetFlags(ctxt, flags);
2559
148k
    ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0);
2560
148k
    if ((ret >= 0) && (ctxt->nbErrors > 0))
2561
66.0k
        ret = -1;
2562
2563
148k
    xmlXIncludeFreeContext(ctxt);
2564
148k
    return(ret);
2565
148k
}
2566
2567
/**
2568
 * xmlXIncludeProcessFlagsData:
2569
 * @doc: an XML document
2570
 * @flags: a set of xmlParserOption used for parsing XML includes
2571
 * @data: application data that will be passed to the parser context
2572
 *        in the _private field of the parser context(s)
2573
 *
2574
 * Implement the XInclude substitution on the XML document @doc
2575
 *
2576
 * Returns 0 if no substitution were done, -1 if some processing failed
2577
 *    or the number of substitutions done.
2578
 */
2579
int
2580
173k
xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) {
2581
173k
    xmlNodePtr tree;
2582
2583
173k
    if (doc == NULL)
2584
11.7k
  return(-1);
2585
161k
    tree = xmlDocGetRootElement(doc);
2586
161k
    if (tree == NULL)
2587
13.1k
  return(-1);
2588
148k
    return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));
2589
161k
}
2590
2591
/**
2592
 * xmlXIncludeProcessFlags:
2593
 * @doc: an XML document
2594
 * @flags: a set of xmlParserOption used for parsing XML includes
2595
 *
2596
 * Implement the XInclude substitution on the XML document @doc
2597
 *
2598
 * Returns 0 if no substitution were done, -1 if some processing failed
2599
 *    or the number of substitutions done.
2600
 */
2601
int
2602
173k
xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
2603
173k
    return xmlXIncludeProcessFlagsData(doc, flags, NULL);
2604
173k
}
2605
2606
/**
2607
 * xmlXIncludeProcess:
2608
 * @doc: an XML document
2609
 *
2610
 * Implement the XInclude substitution on the XML document @doc
2611
 *
2612
 * Returns 0 if no substitution were done, -1 if some processing failed
2613
 *    or the number of substitutions done.
2614
 */
2615
int
2616
0
xmlXIncludeProcess(xmlDocPtr doc) {
2617
0
    return(xmlXIncludeProcessFlags(doc, 0));
2618
0
}
2619
2620
/**
2621
 * xmlXIncludeProcessTreeFlags:
2622
 * @tree: a node in an XML document
2623
 * @flags: a set of xmlParserOption used for parsing XML includes
2624
 *
2625
 * Implement the XInclude substitution for the given subtree
2626
 *
2627
 * Returns 0 if no substitution were done, -1 if some processing failed
2628
 *    or the number of substitutions done.
2629
 */
2630
int
2631
0
xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
2632
0
    xmlXIncludeCtxtPtr ctxt;
2633
0
    int ret = 0;
2634
2635
0
    if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) ||
2636
0
        (tree->doc == NULL))
2637
0
  return(-1);
2638
0
    ctxt = xmlXIncludeNewContext(tree->doc);
2639
0
    if (ctxt == NULL)
2640
0
  return(-1);
2641
0
    ctxt->base = xmlNodeGetBase(tree->doc, tree);
2642
0
    xmlXIncludeSetFlags(ctxt, flags);
2643
0
    ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0);
2644
0
    if ((ret >= 0) && (ctxt->nbErrors > 0))
2645
0
  ret = -1;
2646
2647
0
    xmlXIncludeFreeContext(ctxt);
2648
0
    return(ret);
2649
0
}
2650
2651
/**
2652
 * xmlXIncludeProcessTree:
2653
 * @tree: a node in an XML document
2654
 *
2655
 * Implement the XInclude substitution for the given subtree
2656
 *
2657
 * Returns 0 if no substitution were done, -1 if some processing failed
2658
 *    or the number of substitutions done.
2659
 */
2660
int
2661
0
xmlXIncludeProcessTree(xmlNodePtr tree) {
2662
0
    return(xmlXIncludeProcessTreeFlags(tree, 0));
2663
0
}
2664
2665
/**
2666
 * xmlXIncludeProcessNode:
2667
 * @ctxt: an existing XInclude context
2668
 * @node: a node in an XML document
2669
 *
2670
 * Implement the XInclude substitution for the given subtree reusing
2671
 * the information and data coming from the given context.
2672
 *
2673
 * Returns 0 if no substitution were done, -1 if some processing failed
2674
 *    or the number of substitutions done.
2675
 */
2676
int
2677
8.79k
xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2678
8.79k
    int ret = 0;
2679
2680
8.79k
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
2681
8.79k
        (node->doc == NULL) || (ctxt == NULL))
2682
0
  return(-1);
2683
8.79k
    ret = xmlXIncludeDoProcess(ctxt, node->doc, node, 0);
2684
8.79k
    if ((ret >= 0) && (ctxt->nbErrors > 0))
2685
8.26k
  ret = -1;
2686
8.79k
    return(ret);
2687
8.79k
}
2688
2689
#else /* !LIBXML_XINCLUDE_ENABLED */
2690
#endif