Coverage Report

Created: 2024-08-16 12:09

/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
305k
#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
538k
{
137
538k
    if (ctxt != NULL)
138
538k
  ctxt->nbErrors++;
139
538k
    __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
140
538k
                    error, XML_ERR_ERROR, NULL, 0,
141
538k
        (const char *) extra, NULL, NULL, 0, 0,
142
538k
        msg, (const char *) extra);
143
538k
}
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
2.08M
                   const xmlChar *name) {
179
2.08M
    xmlChar *ret;
180
181
2.08M
    ret = xmlGetNsProp(cur, XINCLUDE_NS, name);
182
2.08M
    if (ret != NULL)
183
0
        return(ret);
184
2.08M
    if (ctxt->legacy != 0) {
185
1.92M
  ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name);
186
1.92M
  if (ret != NULL)
187
0
      return(ret);
188
1.92M
    }
189
2.08M
    ret = xmlGetProp(cur, name);
190
2.08M
    return(ret);
191
2.08M
}
192
/**
193
 * xmlXIncludeFreeRef:
194
 * @ref: the XInclude reference
195
 *
196
 * Free an XInclude reference
197
 */
198
static void
199
370k
xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
200
370k
    if (ref == NULL)
201
0
  return;
202
#ifdef DEBUG_XINCLUDE
203
    xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
204
#endif
205
370k
    if (ref->doc != NULL) {
206
#ifdef DEBUG_XINCLUDE
207
  xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
208
#endif
209
3.63k
  xmlFreeDoc(ref->doc);
210
3.63k
    }
211
370k
    if (ref->URI != NULL)
212
370k
  xmlFree(ref->URI);
213
370k
    if (ref->fragment != NULL)
214
191k
  xmlFree(ref->fragment);
215
370k
    if (ref->xptr != NULL)
216
0
  xmlXPathFreeObject(ref->xptr);
217
370k
    xmlFree(ref);
218
370k
}
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
386k
            xmlNodePtr ref) {
232
386k
    xmlXIncludeRefPtr ret;
233
234
#ifdef DEBUG_XINCLUDE
235
    xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
236
#endif
237
386k
    ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
238
386k
    if (ret == NULL) {
239
0
        xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
240
0
  return(NULL);
241
0
    }
242
386k
    memset(ret, 0, sizeof(xmlXIncludeRef));
243
386k
    if (URI == NULL)
244
0
  ret->URI = NULL;
245
386k
    else
246
386k
  ret->URI = xmlStrdup(URI);
247
386k
    ret->fragment = NULL;
248
386k
    ret->ref = ref;
249
386k
    ret->doc = NULL;
250
386k
    ret->count = 0;
251
386k
    ret->xml = 0;
252
386k
    ret->inc = NULL;
253
386k
    if (ctxt->incMax == 0) {
254
204k
  ctxt->incMax = 4;
255
204k
        ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
256
204k
                sizeof(ctxt->incTab[0]));
257
204k
        if (ctxt->incTab == NULL) {
258
0
      xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
259
0
      xmlXIncludeFreeRef(ret);
260
0
      return(NULL);
261
0
  }
262
204k
    }
263
386k
    if (ctxt->incNr >= ctxt->incMax) {
264
21.5k
  ctxt->incMax *= 2;
265
21.5k
        ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
266
21.5k
               ctxt->incMax * sizeof(ctxt->incTab[0]));
267
21.5k
        if (ctxt->incTab == NULL) {
268
0
      xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
269
0
      xmlXIncludeFreeRef(ret);
270
0
      return(NULL);
271
0
  }
272
21.5k
    }
273
386k
    ctxt->incTab[ctxt->incNr++] = ret;
274
386k
    return(ret);
275
386k
}
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
320k
xmlXIncludeNewContext(xmlDocPtr doc) {
287
320k
    xmlXIncludeCtxtPtr ret;
288
289
#ifdef DEBUG_XINCLUDE
290
    xmlGenericError(xmlGenericErrorContext, "New context\n");
291
#endif
292
320k
    if (doc == NULL)
293
0
  return(NULL);
294
320k
    ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
295
320k
    if (ret == NULL) {
296
0
  xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
297
0
                       "creating XInclude context");
298
0
  return(NULL);
299
0
    }
300
320k
    memset(ret, 0, sizeof(xmlXIncludeCtxt));
301
320k
    ret->doc = doc;
302
320k
    ret->incNr = 0;
303
320k
    ret->incBase = 0;
304
320k
    ret->incMax = 0;
305
320k
    ret->incTab = NULL;
306
320k
    ret->nbErrors = 0;
307
320k
    return(ret);
308
320k
}
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
305k
{
323
305k
    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
305k
    if (ctxt->urlTab == NULL) {
329
305k
  ctxt->urlMax = 4;
330
305k
  ctxt->urlNr = 0;
331
305k
  ctxt->urlTab = (xmlChar * *) xmlMalloc(
332
305k
            ctxt->urlMax * sizeof(ctxt->urlTab[0]));
333
305k
        if (ctxt->urlTab == NULL) {
334
0
      xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
335
0
            return (-1);
336
0
        }
337
305k
    }
338
305k
    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
305k
    ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
350
305k
    return (ctxt->urlNr++);
351
305k
}
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
301k
{
362
301k
    xmlChar * ret;
363
364
301k
    if (ctxt->urlNr <= 0)
365
0
        return;
366
301k
    ctxt->urlNr--;
367
301k
    if (ctxt->urlNr > 0)
368
0
        ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
369
301k
    else
370
301k
        ctxt->url = NULL;
371
301k
    ret = ctxt->urlTab[ctxt->urlNr];
372
301k
    ctxt->urlTab[ctxt->urlNr] = NULL;
373
301k
    if (ret != NULL)
374
301k
  xmlFree(ret);
375
301k
}
376
377
/**
378
 * xmlXIncludeFreeContext:
379
 * @ctxt: the XInclude context
380
 *
381
 * Free an XInclude context
382
 */
383
void
384
316k
xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
385
316k
    int i;
386
387
#ifdef DEBUG_XINCLUDE
388
    xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
389
#endif
390
316k
    if (ctxt == NULL)
391
0
  return;
392
317k
    while (ctxt->urlNr > 0)
393
1.36k
  xmlXIncludeURLPop(ctxt);
394
316k
    if (ctxt->urlTab != NULL)
395
301k
  xmlFree(ctxt->urlTab);
396
709k
    for (i = 0;i < ctxt->incNr;i++) {
397
393k
  if (ctxt->incTab[i] != NULL)
398
370k
      xmlXIncludeFreeRef(ctxt->incTab[i]);
399
393k
    }
400
316k
    if (ctxt->incTab != NULL)
401
207k
  xmlFree(ctxt->incTab);
402
316k
    if (ctxt->txtTab != NULL) {
403
824
  for (i = 0;i < ctxt->txtNr;i++) {
404
412
      if (ctxt->txtTab[i] != NULL)
405
0
    xmlFree(ctxt->txtTab[i]);
406
412
  }
407
412
  xmlFree(ctxt->txtTab);
408
412
    }
409
316k
    if (ctxt->txturlTab != NULL) {
410
824
  for (i = 0;i < ctxt->txtNr;i++) {
411
412
      if (ctxt->txturlTab[i] != NULL)
412
412
    xmlFree(ctxt->txturlTab[i]);
413
412
  }
414
412
  xmlFree(ctxt->txturlTab);
415
412
    }
416
316k
    if (ctxt->base != NULL) {
417
308k
        xmlFree(ctxt->base);
418
308k
    }
419
316k
    xmlFree(ctxt);
420
316k
}
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
191k
xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
431
191k
    xmlDocPtr ret;
432
191k
    xmlParserCtxtPtr pctxt;
433
191k
    xmlParserInputPtr inputStream;
434
435
191k
    xmlInitParser();
436
437
191k
    pctxt = xmlNewParserCtxt();
438
191k
    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
191k
    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
191k
    if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL)) {
453
67.2k
       if (pctxt->dict != NULL)
454
67.2k
            xmlDictFree(pctxt->dict);
455
67.2k
  pctxt->dict = ctxt->doc->dict;
456
67.2k
  xmlDictReference(pctxt->dict);
457
67.2k
    }
458
459
191k
    xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
460
461
    /* Don't read from stdin. */
462
191k
    if ((URL != NULL) && (strcmp(URL, "-") == 0))
463
1
        URL = "./-";
464
465
191k
    inputStream = xmlLoadExternalEntity(URL, NULL, pctxt);
466
191k
    if (inputStream == NULL) {
467
132k
  xmlFreeParserCtxt(pctxt);
468
132k
  return(NULL);
469
132k
    }
470
471
59.0k
    inputPush(pctxt, inputStream);
472
473
59.0k
    if (pctxt->directory == NULL)
474
59.0k
        pctxt->directory = xmlParserGetDirectory(URL);
475
476
59.0k
    pctxt->loadsubset |= XML_DETECT_IDS;
477
478
59.0k
    xmlParseDocument(pctxt);
479
480
59.0k
    if (pctxt->wellFormed) {
481
6.91k
        ret = pctxt->myDoc;
482
6.91k
    }
483
52.0k
    else {
484
52.0k
        ret = NULL;
485
52.0k
  if (pctxt->myDoc != NULL)
486
51.2k
      xmlFreeDoc(pctxt->myDoc);
487
52.0k
        pctxt->myDoc = NULL;
488
52.0k
    }
489
59.0k
    xmlFreeParserCtxt(pctxt);
490
491
59.0k
    return(ret);
492
191k
}
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
447k
xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
503
447k
    xmlXIncludeRefPtr ref;
504
447k
    xmlURIPtr uri;
505
447k
    xmlChar *URL;
506
447k
    xmlChar *fragment = NULL;
507
447k
    xmlChar *href;
508
447k
    xmlChar *parse;
509
447k
    xmlChar *base;
510
447k
    xmlChar *URI;
511
447k
    int xml = 1, i; /* default Issue 64 */
512
447k
    int local = 0;
513
514
515
447k
    if (ctxt == NULL)
516
0
  return(-1);
517
447k
    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
447k
    href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
527
447k
    if (href == NULL) {
528
146k
  href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
529
146k
  if (href == NULL)
530
0
      return(-1);
531
146k
    }
532
447k
    parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
533
447k
    if (parse != NULL) {
534
6.17k
  if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
535
3.47k
      xml = 1;
536
2.70k
  else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
537
2.48k
      xml = 0;
538
216
  else {
539
216
      xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
540
216
                     "invalid value %s for 'parse'\n", parse);
541
216
      if (href != NULL)
542
216
    xmlFree(href);
543
216
      if (parse != NULL)
544
216
    xmlFree(parse);
545
216
      return(-1);
546
216
  }
547
6.17k
    }
548
549
    /*
550
     * compute the URI
551
     */
552
447k
    base = xmlNodeGetBase(ctxt->doc, cur);
553
447k
    if (base == NULL) {
554
14.7k
  URI = xmlBuildURI(href, ctxt->doc->URL);
555
433k
    } else {
556
433k
  URI = xmlBuildURI(href, base);
557
433k
    }
558
447k
    if (URI == NULL) {
559
54.9k
  xmlChar *escbase;
560
54.9k
  xmlChar *eschref;
561
  /*
562
   * Some escaping may be needed
563
   */
564
54.9k
  escbase = xmlURIEscape(base);
565
54.9k
  eschref = xmlURIEscape(href);
566
54.9k
  URI = xmlBuildURI(eschref, escbase);
567
54.9k
  if (escbase != NULL)
568
48.9k
      xmlFree(escbase);
569
54.9k
  if (eschref != NULL)
570
34.7k
      xmlFree(eschref);
571
54.9k
    }
572
447k
    if (parse != NULL)
573
5.95k
  xmlFree(parse);
574
447k
    if (href != NULL)
575
447k
  xmlFree(href);
576
447k
    if (base != NULL)
577
433k
  xmlFree(base);
578
447k
    if (URI == NULL) {
579
21.0k
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
580
21.0k
                 "failed build URL\n", NULL);
581
21.0k
  return(-1);
582
21.0k
    }
583
426k
    fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
584
585
    /*
586
     * Check the URL and remove any fragment identifier
587
     */
588
426k
    uri = xmlParseURI((const char *)URI);
589
426k
    if (uri == NULL) {
590
1.99k
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
591
1.99k
                 "invalid value URI %s\n", URI);
592
1.99k
  if (fragment != NULL)
593
293
      xmlFree(fragment);
594
1.99k
  xmlFree(URI);
595
1.99k
  return(-1);
596
1.99k
    }
597
598
424k
    if (uri->fragment != NULL) {
599
104k
        if (ctxt->legacy != 0) {
600
103k
      if (fragment == NULL) {
601
100k
    fragment = (xmlChar *) uri->fragment;
602
100k
      } else {
603
3.19k
    xmlFree(uri->fragment);
604
3.19k
      }
605
103k
  } else {
606
1.01k
      xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID,
607
1.01k
       "Invalid fragment identifier in URI %s use the xpointer attribute\n",
608
1.01k
                           URI);
609
1.01k
      if (fragment != NULL)
610
166
          xmlFree(fragment);
611
1.01k
      xmlFreeURI(uri);
612
1.01k
      xmlFree(URI);
613
1.01k
      return(-1);
614
1.01k
  }
615
103k
  uri->fragment = NULL;
616
103k
    }
617
423k
    URL = xmlSaveUri(uri);
618
423k
    xmlFreeURI(uri);
619
423k
    xmlFree(URI);
620
423k
    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
423k
    if (xmlStrEqual(URL, ctxt->doc->URL))
629
182k
  local = 1;
630
631
    /*
632
     * If local and xml then we need a fragment
633
     */
634
423k
    if ((local == 1) && (xml == 1) &&
635
423k
        ((fragment == NULL) || (fragment[0] == 0))) {
636
37.3k
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
637
37.3k
                 "detected a local recursion with no xpointer in %s\n",
638
37.3k
           URL);
639
37.3k
        xmlFree(URL);
640
37.3k
        xmlFree(fragment);
641
37.3k
  return(-1);
642
37.3k
    }
643
644
    /*
645
     * Check the URL against the stack for recursions
646
     */
647
386k
    if ((!local) && (xml == 1)) {
648
466k
  for (i = 0;i < ctxt->urlNr;i++) {
649
226k
      if (xmlStrEqual(URL, ctxt->urlTab[i])) {
650
48
    xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
651
48
                   "detected a recursion in %s\n", URL);
652
48
                xmlFree(URL);
653
48
                xmlFree(fragment);
654
48
    return(-1);
655
48
      }
656
226k
  }
657
239k
    }
658
659
386k
    ref = xmlXIncludeNewRef(ctxt, URL, cur);
660
386k
    xmlFree(URL);
661
386k
    if (ref == NULL) {
662
0
  return(-1);
663
0
    }
664
386k
    ref->fragment = fragment;
665
386k
    ref->doc = NULL;
666
386k
    ref->xml = xml;
667
386k
    ref->count = 1;
668
386k
    return(0);
669
386k
}
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
6.91k
                const xmlURL url ATTRIBUTE_UNUSED) {
682
6.91k
    xmlXIncludeCtxtPtr newctxt;
683
6.91k
    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
6.91k
    newctxt = xmlXIncludeNewContext(doc);
701
6.91k
    if (newctxt != NULL) {
702
  /*
703
   * Copy the private user data
704
   */
705
6.91k
  newctxt->_private = ctxt->_private;
706
  /*
707
   * Copy the existing document set
708
   */
709
6.91k
  newctxt->incMax = ctxt->incMax;
710
6.91k
  newctxt->incNr = ctxt->incNr;
711
6.91k
        newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
712
6.91k
                              sizeof(newctxt->incTab[0]));
713
6.91k
        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
6.91k
  newctxt->urlMax = ctxt->urlMax;
722
6.91k
  newctxt->urlNr = ctxt->urlNr;
723
6.91k
  newctxt->urlTab = ctxt->urlTab;
724
725
  /*
726
   * Inherit the existing base
727
   */
728
6.91k
  newctxt->base = xmlStrdup(ctxt->base);
729
730
  /*
731
   * Inherit the documents already in use by other includes
732
   */
733
6.91k
  newctxt->incBase = ctxt->incNr;
734
29.9k
  for (i = 0;i < ctxt->incNr;i++) {
735
23.0k
      newctxt->incTab[i] = ctxt->incTab[i];
736
23.0k
      newctxt->incTab[i]->count++; /* prevent the recursion from
737
              freeing it */
738
23.0k
  }
739
  /*
740
   * The new context should also inherit the Parse Flags
741
   * (bug 132597)
742
   */
743
6.91k
  newctxt->parseFlags = ctxt->parseFlags;
744
6.91k
        newctxt->incTotal = ctxt->incTotal;
745
6.91k
  xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc), 0);
746
6.91k
        ctxt->incTotal = newctxt->incTotal;
747
29.9k
  for (i = 0;i < ctxt->incNr;i++) {
748
23.0k
      newctxt->incTab[i]->count--;
749
23.0k
      newctxt->incTab[i] = NULL;
750
23.0k
  }
751
752
  /* urlTab may have been reallocated */
753
6.91k
  ctxt->urlTab = newctxt->urlTab;
754
6.91k
  ctxt->urlMax = newctxt->urlMax;
755
756
6.91k
  newctxt->urlMax = 0;
757
6.91k
  newctxt->urlNr = 0;
758
6.91k
  newctxt->urlTab = NULL;
759
760
6.91k
  xmlXIncludeFreeContext(newctxt);
761
6.91k
    }
762
#ifdef DEBUG_XINCLUDE
763
    xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
764
#endif
765
6.91k
}
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
414
                  const xmlURL url) {
778
#ifdef DEBUG_XINCLUDE
779
    xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
780
#endif
781
414
    if (ctxt->txtMax == 0) {
782
414
  ctxt->txtMax = 4;
783
414
        ctxt->txtTab = (xmlChar **) xmlMalloc(ctxt->txtMax *
784
414
                              sizeof(ctxt->txtTab[0]));
785
414
        if (ctxt->txtTab == NULL) {
786
0
      xmlXIncludeErrMemory(ctxt, NULL, "processing text");
787
0
      return;
788
0
  }
789
414
        ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
790
414
                              sizeof(ctxt->txturlTab[0]));
791
414
        if (ctxt->txturlTab == NULL) {
792
0
      xmlXIncludeErrMemory(ctxt, NULL, "processing text");
793
0
      return;
794
0
  }
795
414
    }
796
414
    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
414
    ctxt->txtTab[ctxt->txtNr] = xmlStrdup(txt);
812
414
    ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
813
414
    ctxt->txtNr++;
814
414
}
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
16.9M
              xmlDocPtr source, xmlNodePtr elem) {
839
16.9M
    xmlNodePtr result = NULL;
840
841
16.9M
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
842
16.9M
  (elem == NULL))
843
0
  return(NULL);
844
16.9M
    if (elem->type == XML_DTD_NODE)
845
5.21k
  return(NULL);
846
16.9M
    if (elem->type == XML_DOCUMENT_NODE)
847
13.1k
  result = xmlXIncludeCopyNodeList(ctxt, target, source, elem->children);
848
16.9M
    else
849
16.9M
        result = xmlDocCopyNode(elem, target, 1);
850
16.9M
    return(result);
851
16.9M
}
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
16.8k
                  xmlDocPtr source, xmlNodePtr elem) {
866
16.8k
    xmlNodePtr cur, res, result = NULL, last = NULL;
867
868
16.8k
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
869
16.8k
  (elem == NULL))
870
0
  return(NULL);
871
16.8k
    cur = elem;
872
47.2k
    while (cur != NULL) {
873
30.4k
  res = xmlXIncludeCopyNode(ctxt, target, source, cur);
874
30.4k
  if (res != NULL) {
875
25.1k
      if (result == NULL) {
876
16.7k
    result = last = res;
877
16.7k
      } else {
878
8.40k
    last->next = res;
879
8.40k
    res->prev = last;
880
8.40k
    last = res;
881
8.40k
      }
882
25.1k
  }
883
30.4k
  cur = cur->next;
884
30.4k
    }
885
16.8k
    return(result);
886
16.8k
}
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
50.7k
                  xmlDocPtr source, xmlXPathObjectPtr obj) {
1146
50.7k
    xmlNodePtr list = NULL, last = NULL;
1147
50.7k
    int i;
1148
1149
50.7k
    if (source == NULL)
1150
0
  source = ctxt->doc;
1151
50.7k
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
1152
50.7k
  (obj == NULL))
1153
0
  return(NULL);
1154
50.7k
    switch (obj->type) {
1155
50.7k
        case XPATH_NODESET: {
1156
50.7k
      xmlNodeSetPtr set = obj->nodesetval;
1157
50.7k
      if (set == NULL)
1158
0
    return(NULL);
1159
2.32M
      for (i = 0;i < set->nodeNr;i++) {
1160
2.27M
    if (set->nodeTab[i] == NULL)
1161
79.0k
        continue;
1162
2.19M
    switch (set->nodeTab[i]->type) {
1163
1.41M
        case XML_TEXT_NODE:
1164
1.42M
        case XML_CDATA_SECTION_NODE:
1165
2.10M
        case XML_ELEMENT_NODE:
1166
2.10M
        case XML_ENTITY_REF_NODE:
1167
2.10M
        case XML_ENTITY_NODE:
1168
2.13M
        case XML_PI_NODE:
1169
2.15M
        case XML_COMMENT_NODE:
1170
2.17M
        case XML_DOCUMENT_NODE:
1171
2.17M
        case XML_HTML_DOCUMENT_NODE:
1172
2.17M
        case XML_XINCLUDE_END:
1173
2.17M
      break;
1174
18.0k
        case XML_XINCLUDE_START: {
1175
18.0k
                  xmlNodePtr tmp, cur = set->nodeTab[i];
1176
1177
18.0k
      cur = cur->next;
1178
14.7M
      while (cur != NULL) {
1179
14.7M
          switch(cur->type) {
1180
1.44M
        case XML_TEXT_NODE:
1181
1.44M
        case XML_CDATA_SECTION_NODE:
1182
14.5M
        case XML_ELEMENT_NODE:
1183
14.5M
        case XML_ENTITY_REF_NODE:
1184
14.5M
        case XML_ENTITY_NODE:
1185
14.5M
        case XML_PI_NODE:
1186
14.7M
        case XML_COMMENT_NODE:
1187
14.7M
            tmp = xmlXIncludeCopyNode(ctxt, target,
1188
14.7M
                    source, cur);
1189
14.7M
            if (last == NULL) {
1190
546
          list = last = tmp;
1191
14.7M
            } else {
1192
14.7M
          last = xmlAddNextSibling(last, tmp);
1193
14.7M
            }
1194
14.7M
            cur = cur->next;
1195
14.7M
            continue;
1196
18.0k
        default:
1197
18.0k
            break;
1198
14.7M
          }
1199
18.0k
          break;
1200
14.7M
      }
1201
18.0k
      continue;
1202
18.0k
        }
1203
18.0k
        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
2.19M
    }
1214
2.17M
    if (last == NULL)
1215
46.9k
        list = last = xmlXIncludeCopyNode(ctxt, target, source,
1216
46.9k
                                    set->nodeTab[i]);
1217
2.12M
    else {
1218
2.12M
        xmlAddNextSibling(last,
1219
2.12M
          xmlXIncludeCopyNode(ctxt, target, source,
1220
2.12M
                        set->nodeTab[i]));
1221
2.12M
        if (last->next != NULL)
1222
975k
      last = last->next;
1223
2.12M
    }
1224
2.17M
      }
1225
47.4k
      break;
1226
50.7k
  }
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
47.4k
  default:
1254
0
      break;
1255
50.7k
    }
1256
47.1k
    return(list);
1257
50.7k
}
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
606
                 const xmlChar *name ATTRIBUTE_UNUSED) {
1282
606
    xmlEntityPtr ent = (xmlEntityPtr) payload;
1283
606
    xmlXIncludeMergeDataPtr data = (xmlXIncludeMergeDataPtr) vdata;
1284
606
    xmlEntityPtr ret, prev;
1285
606
    xmlDocPtr doc;
1286
606
    xmlXIncludeCtxtPtr ctxt;
1287
1288
606
    if ((ent == NULL) || (data == NULL))
1289
0
  return;
1290
606
    ctxt = data->ctxt;
1291
606
    doc = data->doc;
1292
606
    if ((ctxt == NULL) || (doc == NULL))
1293
0
  return;
1294
606
    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
83
        case XML_INTERNAL_GENERAL_ENTITY:
1300
576
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1301
606
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1302
606
      break;
1303
606
    }
1304
606
    ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1305
606
        ent->SystemID, ent->content);
1306
606
    if (ret != NULL) {
1307
236
  if (ent->URI != NULL)
1308
186
      ret->URI = xmlStrdup(ent->URI);
1309
370
    } else {
1310
370
  prev = xmlGetDocEntity(doc, ent->name);
1311
370
  if (prev != NULL) {
1312
370
      if (ent->etype != prev->etype)
1313
15
    goto error;
1314
1315
355
      if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1316
304
    if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1317
0
        goto error;
1318
304
      } else if ((ent->ExternalID != NULL) &&
1319
51
           (prev->ExternalID != NULL)) {
1320
0
    if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1321
0
        goto error;
1322
51
      } else if ((ent->content != NULL) && (prev->content != NULL)) {
1323
51
    if (!xmlStrEqual(ent->content, prev->content))
1324
0
        goto error;
1325
51
      } else {
1326
0
    goto error;
1327
0
      }
1328
1329
355
  }
1330
370
    }
1331
591
    return;
1332
591
error:
1333
15
    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
15
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1339
15
      return;
1340
0
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1341
0
      break;
1342
15
    }
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
6.91k
                   xmlDocPtr from) {
1361
6.91k
    xmlNodePtr cur;
1362
6.91k
    xmlDtdPtr target, source;
1363
1364
6.91k
    if (ctxt == NULL)
1365
0
  return(-1);
1366
1367
6.91k
    if ((from == NULL) || (from->intSubset == NULL))
1368
5.01k
  return(0);
1369
1370
1.90k
    target = doc->intSubset;
1371
1.90k
    if (target == NULL) {
1372
732
  cur = xmlDocGetRootElement(doc);
1373
732
  if (cur == NULL)
1374
0
      return(-1);
1375
732
        target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1376
732
  if (target == NULL)
1377
0
      return(-1);
1378
732
    }
1379
1380
1.90k
    source = from->intSubset;
1381
1.90k
    if ((source != NULL) && (source->entities != NULL)) {
1382
606
  xmlXIncludeMergeData data;
1383
1384
606
  data.ctxt = ctxt;
1385
606
  data.doc = doc;
1386
1387
606
  xmlHashScan((xmlHashTablePtr) source->entities,
1388
606
        xmlXIncludeMergeEntity, &data);
1389
606
    }
1390
1.90k
    source = from->extSubset;
1391
1.90k
    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
1.90k
    return(0);
1407
1.90k
}
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
377k
xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1421
377k
    xmlDocPtr doc;
1422
377k
    xmlURIPtr uri;
1423
377k
    xmlChar *URL;
1424
377k
    xmlChar *fragment = NULL;
1425
377k
    int i = 0;
1426
377k
#ifdef LIBXML_XPTR_ENABLED
1427
377k
    int saveFlags;
1428
377k
#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
377k
    uri = xmlParseURI((const char *)url);
1437
377k
    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
377k
    if (uri->fragment != NULL) {
1444
99.7k
  fragment = (xmlChar *) uri->fragment;
1445
99.7k
  uri->fragment = NULL;
1446
99.7k
    }
1447
377k
    if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
1448
377k
        (ctxt->incTab[nr]->fragment != NULL)) {
1449
200k
  if (fragment != NULL) xmlFree(fragment);
1450
200k
  fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
1451
200k
    }
1452
377k
    URL = xmlSaveUri(uri);
1453
377k
    xmlFreeURI(uri);
1454
377k
    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
377k
    if ((URL[0] == 0) || (URL[0] == '#') ||
1473
377k
  ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
1474
183k
  doc = NULL;
1475
183k
        goto loaded;
1476
183k
    }
1477
1478
    /*
1479
     * Prevent reloading twice the document.
1480
     */
1481
861k
    for (i = 0; i < ctxt->incNr; i++) {
1482
670k
  if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1483
670k
      (ctxt->incTab[i]->doc != NULL)) {
1484
2.84k
      doc = ctxt->incTab[i]->doc;
1485
#ifdef DEBUG_XINCLUDE
1486
      printf("Already loaded %s\n", URL);
1487
#endif
1488
2.84k
      goto loaded;
1489
2.84k
  }
1490
670k
    }
1491
1492
    /*
1493
     * Load it.
1494
     */
1495
#ifdef DEBUG_XINCLUDE
1496
    printf("loading %s\n", URL);
1497
#endif
1498
191k
#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
191k
    saveFlags = ctxt->parseFlags;
1505
191k
    if (fragment != NULL) { /* if this is an XPointer eval */
1506
28.4k
  ctxt->parseFlags |= XML_PARSE_NOENT;
1507
28.4k
    }
1508
191k
#endif
1509
1510
191k
    doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
1511
191k
#ifdef LIBXML_XPTR_ENABLED
1512
191k
    ctxt->parseFlags = saveFlags;
1513
191k
#endif
1514
191k
    if (doc == NULL) {
1515
184k
  xmlFree(URL);
1516
184k
  if (fragment != NULL)
1517
24.0k
      xmlFree(fragment);
1518
184k
  return(-1);
1519
184k
    }
1520
6.91k
    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
6.91k
   if (!xmlStrEqual(URL, doc->URL)) {
1528
6.91k
       xmlFree(URL);
1529
6.91k
       URL = xmlStrdup(doc->URL);
1530
6.91k
   }
1531
16.0k
    for (i = nr + 1; i < ctxt->incNr; i++) {
1532
9.16k
  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
9.16k
    }
1540
1541
    /*
1542
     * Make sure we have all entities fixed up
1543
     */
1544
6.91k
    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
6.91k
    xmlXIncludeRecurseDoc(ctxt, doc, URL);
1560
1561
192k
loaded:
1562
192k
    if (fragment == NULL) {
1563
  /*
1564
   * Add the top children list as the replacement copy.
1565
   */
1566
16.7k
  if (doc == NULL)
1567
13.0k
  {
1568
      /* Hopefully a DTD declaration won't be copied from
1569
       * the same document */
1570
13.0k
      ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
1571
13.0k
  } else {
1572
3.67k
      ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
1573
3.67k
                                           doc, doc->children);
1574
3.67k
  }
1575
16.7k
    }
1576
176k
#ifdef LIBXML_XPTR_ENABLED
1577
176k
    else {
1578
  /*
1579
   * Computes the XPointer expression and make a copy used
1580
   * as the replacement copy.
1581
   */
1582
176k
  xmlXPathObjectPtr xptr;
1583
176k
  xmlXPathContextPtr xptrctxt;
1584
176k
  xmlNodeSetPtr set;
1585
1586
176k
  if (doc == NULL) {
1587
170k
      xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1588
170k
                             NULL);
1589
170k
  } else {
1590
6.08k
      xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1591
6.08k
  }
1592
176k
  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
176k
  xptr = xmlXPtrEval(fragment, xptrctxt);
1601
176k
  if (xptr == NULL) {
1602
117k
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1603
117k
                     XML_XINCLUDE_XPTR_FAILED,
1604
117k
         "XPointer evaluation failed: #%s\n",
1605
117k
         fragment);
1606
117k
      xmlXPathFreeContext(xptrctxt);
1607
117k
      xmlFree(URL);
1608
117k
      xmlFree(fragment);
1609
117k
      return(-1);
1610
117k
  }
1611
58.6k
  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
58.6k
      case XPATH_NODESET:
1631
58.6k
          if ((xptr->nodesetval == NULL) ||
1632
58.6k
        (xptr->nodesetval->nodeNr <= 0)) {
1633
5.87k
                    xmlXPathFreeObject(xptr);
1634
5.87k
        xmlXPathFreeContext(xptrctxt);
1635
5.87k
        xmlFree(URL);
1636
5.87k
        xmlFree(fragment);
1637
5.87k
        return(-1);
1638
5.87k
    }
1639
1640
#ifdef LIBXML_XPTR_LOCS_ENABLED
1641
      case XPATH_RANGE:
1642
      case XPATH_LOCATIONSET:
1643
    break;
1644
#endif
1645
58.6k
  }
1646
52.7k
  set = xptr->nodesetval;
1647
52.7k
  if (set != NULL) {
1648
2.60M
      for (i = 0;i < set->nodeNr;i++) {
1649
2.55M
    if (set->nodeTab[i] == NULL)
1650
0
        continue;
1651
2.55M
    switch (set->nodeTab[i]->type) {
1652
846k
        case XML_ELEMENT_NODE:
1653
2.38M
        case XML_TEXT_NODE:
1654
2.39M
        case XML_CDATA_SECTION_NODE:
1655
2.39M
        case XML_ENTITY_REF_NODE:
1656
2.39M
        case XML_ENTITY_NODE:
1657
2.43M
        case XML_PI_NODE:
1658
2.46M
        case XML_COMMENT_NODE:
1659
2.47M
        case XML_DOCUMENT_NODE:
1660
2.47M
        case XML_HTML_DOCUMENT_NODE:
1661
2.47M
      continue;
1662
1663
82.9k
        case XML_ATTRIBUTE_NODE:
1664
82.9k
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1665
82.9k
                     XML_XINCLUDE_XPTR_RESULT,
1666
82.9k
               "XPointer selects an attribute: #%s\n",
1667
82.9k
               fragment);
1668
82.9k
      set->nodeTab[i] = NULL;
1669
82.9k
      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.55M
    }
1694
2.55M
      }
1695
52.7k
  }
1696
52.7k
  if (doc == NULL) {
1697
51.8k
      ctxt->incTab[nr]->xptr = xptr;
1698
51.8k
      ctxt->incTab[nr]->inc = NULL;
1699
51.8k
  } else {
1700
892
      ctxt->incTab[nr]->inc =
1701
892
    xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1702
892
      xmlXPathFreeObject(xptr);
1703
892
  }
1704
52.7k
  xmlXPathFreeContext(xptrctxt);
1705
52.7k
  xmlFree(fragment);
1706
52.7k
    }
1707
69.4k
#endif
1708
1709
    /*
1710
     * Do the xml:base fixup if needed
1711
     */
1712
69.4k
    if ((doc != NULL) && (URL != NULL) &&
1713
69.4k
        (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) &&
1714
69.4k
  (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) {
1715
1.05k
  xmlNodePtr node;
1716
1.05k
  xmlChar *base;
1717
1.05k
  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
1.05k
  base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base",
1724
1.05k
      XML_XML_NAMESPACE);
1725
1.05k
  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
1.05k
      curBase = xmlBuildRelativeURI(URL, ctxt->base);
1731
1.05k
      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
1.05k
      } else {
1736
    /* If the URI doesn't contain a slash, it's not relative */
1737
1.05k
          if (!xmlStrchr(curBase, '/'))
1738
39
        xmlFree(curBase);
1739
1.01k
    else
1740
1.01k
        base = curBase;
1741
1.05k
      }
1742
1.05k
  }
1743
1.05k
  if (base != NULL) { /* Adjustment may be needed */
1744
1.01k
      node = ctxt->incTab[nr]->inc;
1745
2.20k
      while (node != NULL) {
1746
    /* Only work on element nodes */
1747
1.19k
    if (node->type == XML_ELEMENT_NODE) {
1748
1.18k
        curBase = xmlNodeGetBase(node->doc, node);
1749
        /* If no current base, set it */
1750
1.18k
        if (curBase == NULL) {
1751
161
      xmlNodeSetBase(node, base);
1752
1.02k
        } 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
1.02k
      if (xmlStrEqual(curBase, node->doc->URL)) {
1759
1.02k
          xmlNodeSetBase(node, base);
1760
1.02k
      } 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
1.02k
      xmlFree(curBase);
1786
1.02k
        }
1787
1.18k
    }
1788
1.19k
          node = node->next;
1789
1.19k
      }
1790
1.01k
      xmlFree(base);
1791
1.01k
  }
1792
1.05k
    }
1793
69.4k
    if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1794
69.4k
  (ctxt->incTab[nr]->count <= 1)) {
1795
#ifdef DEBUG_XINCLUDE
1796
        printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1797
#endif
1798
3.28k
  xmlFreeDoc(ctxt->incTab[nr]->doc);
1799
3.28k
  ctxt->incTab[nr]->doc = NULL;
1800
3.28k
    }
1801
69.4k
    xmlFree(URL);
1802
69.4k
    return(0);
1803
192k
}
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
2.39k
xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1817
2.39k
    xmlParserInputBufferPtr buf;
1818
2.39k
    xmlNodePtr node;
1819
2.39k
    xmlURIPtr uri;
1820
2.39k
    xmlChar *URL;
1821
2.39k
    int i;
1822
2.39k
    xmlChar *encoding = NULL;
1823
2.39k
    xmlCharEncoding enc = (xmlCharEncoding) 0;
1824
2.39k
    xmlParserCtxtPtr pctxt;
1825
2.39k
    xmlParserInputPtr inputStream;
1826
2.39k
    int xinclude_multibyte_fallback_used = 0;
1827
1828
    /* Don't read from stdin. */
1829
2.39k
    if (xmlStrcmp(url, BAD_CAST "-") == 0)
1830
0
        url = BAD_CAST "./-";
1831
1832
    /*
1833
     * Check the URL and remove any fragment identifier
1834
     */
1835
2.39k
    uri = xmlParseURI((const char *)url);
1836
2.39k
    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
2.39k
    if (uri->fragment != NULL) {
1842
337
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1843
337
                 "fragment identifier forbidden for text: %s\n",
1844
337
           (const xmlChar *) uri->fragment);
1845
337
  xmlFreeURI(uri);
1846
337
  return(-1);
1847
337
    }
1848
2.06k
    URL = xmlSaveUri(uri);
1849
2.06k
    xmlFreeURI(uri);
1850
2.06k
    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
2.06k
    if (URL[0] == 0) {
1861
152
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1862
152
                 XML_XINCLUDE_TEXT_DOCUMENT,
1863
152
           "text serialization of document not available\n", NULL);
1864
152
  xmlFree(URL);
1865
152
  return(-1);
1866
152
    }
1867
1868
    /*
1869
     * Prevent reloading twice the document.
1870
     */
1871
1.94k
    for (i = 0; i < ctxt->txtNr; i++) {
1872
447
  if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1873
408
            node = xmlNewDocText(ctxt->doc, ctxt->txtTab[i]);
1874
408
      goto loaded;
1875
408
  }
1876
447
    }
1877
    /*
1878
     * Try to get the encoding if available
1879
     */
1880
1.50k
    if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1881
1.50k
  encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1882
1.50k
    }
1883
1.50k
    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
772
        enc = xmlParseCharEncoding((const char *) encoding);
1891
772
  if (enc == XML_CHAR_ENCODING_ERROR) {
1892
193
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1893
193
                     XML_XINCLUDE_UNKNOWN_ENCODING,
1894
193
         "encoding %s not supported\n", encoding);
1895
193
      xmlFree(encoding);
1896
193
      xmlFree(URL);
1897
193
      return(-1);
1898
193
  }
1899
579
  xmlFree(encoding);
1900
579
    }
1901
1902
    /*
1903
     * Load it.
1904
     */
1905
1.30k
    pctxt = xmlNewParserCtxt();
1906
1.30k
    inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt);
1907
1.30k
    if(inputStream == NULL) {
1908
895
  xmlFreeParserCtxt(pctxt);
1909
895
  xmlFree(URL);
1910
895
  return(-1);
1911
895
    }
1912
414
    buf = inputStream->buf;
1913
414
    if (buf == NULL) {
1914
0
  xmlFreeInputStream (inputStream);
1915
0
  xmlFreeParserCtxt(pctxt);
1916
0
  xmlFree(URL);
1917
0
  return(-1);
1918
0
    }
1919
414
    if (buf->encoder)
1920
0
  xmlCharEncCloseFunc(buf->encoder);
1921
414
    buf->encoder = xmlGetCharEncodingHandler(enc);
1922
414
    node = xmlNewDocText(ctxt->doc, NULL);
1923
1924
    /*
1925
     * Scan all chars from the resource and add the to the node
1926
     */
1927
414
xinclude_multibyte_fallback:
1928
414
    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
414
    xmlFreeParserCtxt(pctxt);
1963
414
    xmlXIncludeAddTxt(ctxt, node->content, URL);
1964
414
    xmlFreeInputStream(inputStream);
1965
1966
822
loaded:
1967
    /*
1968
     * Add the element as the replacement copy.
1969
     */
1970
822
    ctxt->incTab[nr]->inc = node;
1971
822
    xmlFree(URL);
1972
822
    return(0);
1973
414
}
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
96.4k
xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1988
96.4k
    xmlXIncludeCtxtPtr newctxt;
1989
96.4k
    int ret = 0;
1990
96.4k
    int oldNbErrors = ctxt->nbErrors;
1991
1992
96.4k
    if ((fallback == NULL) || (fallback->type == XML_NAMESPACE_DECL) ||
1993
96.4k
        (ctxt == NULL))
1994
0
  return(-1);
1995
96.4k
    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
95.1k
  newctxt = xmlXIncludeNewContext(ctxt->doc);
2001
95.1k
  if (newctxt == NULL)
2002
0
      return (-1);
2003
95.1k
  newctxt->_private = ctxt->_private;
2004
95.1k
  newctxt->base = xmlStrdup(ctxt->base);  /* Inherit the base from the existing context */
2005
95.1k
  xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
2006
95.1k
        newctxt->incTotal = ctxt->incTotal;
2007
95.1k
        if (xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback, 1) < 0)
2008
893
            ret = -1;
2009
95.1k
        ctxt->incTotal = newctxt->incTotal;
2010
95.1k
  if (ctxt->nbErrors > oldNbErrors)
2011
0
      ret = -1;
2012
95.1k
  xmlXIncludeFreeContext(newctxt);
2013
2014
95.1k
  ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
2015
95.1k
                                             fallback->children);
2016
95.1k
        if (ctxt->incTab[nr]->inc == NULL)
2017
228
            ctxt->incTab[nr]->emptyFb = 1;
2018
95.1k
    } else {
2019
1.29k
        ctxt->incTab[nr]->inc = NULL;
2020
1.29k
  ctxt->incTab[nr]->emptyFb = 1;  /* flag empty callback */
2021
1.29k
    }
2022
96.4k
    ctxt->incTab[nr]->fallback = 1;
2023
96.4k
    return(ret);
2024
96.4k
}
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
447k
xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2044
447k
    xmlXIncludeAddNode(ctxt, node);
2045
447k
    return(NULL);
2046
447k
}
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
379k
xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
2059
379k
    xmlNodePtr cur;
2060
379k
    xmlChar *href;
2061
379k
    xmlChar *parse;
2062
379k
    xmlChar *base;
2063
379k
    xmlChar *oldBase;
2064
379k
    xmlChar *URI;
2065
379k
    int xml = 1; /* default Issue 64 */
2066
379k
    int ret;
2067
2068
379k
    if (ctxt == NULL)
2069
0
  return(-1);
2070
379k
    if ((nr < 0) || (nr >= ctxt->incNr))
2071
0
  return(-1);
2072
379k
    cur = ctxt->incTab[nr]->ref;
2073
379k
    if (cur == NULL)
2074
0
  return(-1);
2075
2076
    /*
2077
     * read the attributes
2078
     */
2079
379k
    href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
2080
379k
    if (href == NULL) {
2081
107k
  href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
2082
107k
  if (href == NULL)
2083
0
      return(-1);
2084
107k
    }
2085
379k
    parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
2086
379k
    if (parse != NULL) {
2087
5.59k
  if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
2088
3.19k
      xml = 1;
2089
2.39k
  else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
2090
2.39k
      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
5.59k
    }
2102
2103
    /*
2104
     * compute the URI
2105
     */
2106
379k
    base = xmlNodeGetBase(ctxt->doc, cur);
2107
379k
    if (base == NULL) {
2108
13.0k
  URI = xmlBuildURI(href, ctxt->doc->URL);
2109
366k
    } else {
2110
366k
  URI = xmlBuildURI(href, base);
2111
366k
    }
2112
379k
    if (URI == NULL) {
2113
31.7k
  xmlChar *escbase;
2114
31.7k
  xmlChar *eschref;
2115
  /*
2116
   * Some escaping may be needed
2117
   */
2118
31.7k
  escbase = xmlURIEscape(base);
2119
31.7k
  eschref = xmlURIEscape(href);
2120
31.7k
  URI = xmlBuildURI(eschref, escbase);
2121
31.7k
  if (escbase != NULL)
2122
28.9k
      xmlFree(escbase);
2123
31.7k
  if (eschref != NULL)
2124
31.7k
      xmlFree(eschref);
2125
31.7k
    }
2126
379k
    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
379k
    oldBase = ctxt->base;
2147
379k
    ctxt->base = base;
2148
2149
379k
    if (xml) {
2150
377k
  ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
2151
  /* xmlXIncludeGetFragment(ctxt, cur, URI); */
2152
377k
    } else {
2153
2.39k
  ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
2154
2.39k
    }
2155
2156
    /*
2157
     * Restore the original base before checking for fallback
2158
     */
2159
379k
    ctxt->base = oldBase;
2160
2161
379k
    if (ret < 0) {
2162
309k
  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
309k
  children = cur->children;
2171
425k
  while (children != NULL) {
2172
212k
      if ((children->type == XML_ELEMENT_NODE) &&
2173
212k
    (children->ns != NULL) &&
2174
212k
    (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
2175
212k
    ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
2176
96.6k
     (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
2177
96.4k
    ret = xmlXIncludeLoadFallback(ctxt, children, nr);
2178
96.4k
    break;
2179
96.4k
      }
2180
116k
      children = children->next;
2181
116k
  }
2182
309k
    }
2183
379k
    if (ret < 0) {
2184
213k
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2185
213k
                 XML_XINCLUDE_NO_FALLBACK,
2186
213k
           "could not load %s, and no fallback was found\n",
2187
213k
           URI);
2188
213k
    }
2189
2190
    /*
2191
     * Cleanup
2192
     */
2193
379k
    if (URI != NULL)
2194
379k
  xmlFree(URI);
2195
379k
    if (parse != NULL)
2196
5.59k
  xmlFree(parse);
2197
379k
    if (href != NULL)
2198
379k
  xmlFree(href);
2199
379k
    if (base != NULL)
2200
365k
  xmlFree(base);
2201
379k
    return(0);
2202
379k
}
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
163k
xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
2215
163k
    xmlNodePtr cur, end, list, tmp;
2216
2217
163k
    if (ctxt == NULL)
2218
0
  return(-1);
2219
163k
    if ((nr < 0) || (nr >= ctxt->incNr))
2220
0
  return(-1);
2221
163k
    cur = ctxt->incTab[nr]->ref;
2222
163k
    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
163k
    if ((ctxt->incTab[nr]->inc == NULL) &&
2229
163k
  (ctxt->incTab[nr]->xptr != NULL)) {
2230
49.8k
  ctxt->incTab[nr]->inc =
2231
49.8k
      xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
2232
49.8k
                        ctxt->incTab[nr]->xptr);
2233
49.8k
  xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
2234
49.8k
  ctxt->incTab[nr]->xptr = NULL;
2235
49.8k
    }
2236
163k
    list = ctxt->incTab[nr]->inc;
2237
163k
    ctxt->incTab[nr]->inc = NULL;
2238
163k
    ctxt->incTab[nr]->emptyFb = 0;
2239
2240
    /*
2241
     * Check against the risk of generating a multi-rooted document
2242
     */
2243
163k
    if ((cur->parent != NULL) &&
2244
163k
  (cur->parent->type != XML_ELEMENT_NODE)) {
2245
1.08k
  int nb_elem = 0;
2246
2247
1.08k
  tmp = list;
2248
12.1k
  while (tmp != NULL) {
2249
11.0k
      if (tmp->type == XML_ELEMENT_NODE)
2250
4.18k
    nb_elem++;
2251
11.0k
      tmp = tmp->next;
2252
11.0k
  }
2253
1.08k
  if (nb_elem > 1) {
2254
583
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2255
583
                     XML_XINCLUDE_MULTIPLE_ROOT,
2256
583
           "XInclude error: would result in multiple root nodes\n",
2257
583
         NULL);
2258
583
            xmlFreeNodeList(list);
2259
583
      return(-1);
2260
583
  }
2261
1.08k
    }
2262
2263
162k
    if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
2264
  /*
2265
   * Add the list of nodes
2266
   */
2267
623k
  while (list != NULL) {
2268
547k
      end = list;
2269
547k
      list = list->next;
2270
2271
547k
      xmlAddPrevSibling(cur, end);
2272
547k
  }
2273
        /*
2274
         * FIXME: xmlUnlinkNode doesn't coalesce text nodes.
2275
         */
2276
75.3k
  xmlUnlinkNode(cur);
2277
75.3k
  xmlFreeNode(cur);
2278
87.3k
    } else {
2279
87.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
87.3k
        if (ctxt->incTab[nr]->fallback)
2286
49.2k
            xmlUnsetProp(cur, BAD_CAST "href");
2287
87.3k
  cur->type = XML_XINCLUDE_START;
2288
        /* Remove fallback children */
2289
204k
        for (child = cur->children; child != NULL; child = next) {
2290
117k
            next = child->next;
2291
117k
            xmlUnlinkNode(child);
2292
117k
            xmlFreeNode(child);
2293
117k
        }
2294
87.3k
  end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
2295
87.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
87.3k
  end->type = XML_XINCLUDE_END;
2303
87.3k
  xmlAddNextSibling(cur, end);
2304
2305
  /*
2306
   * Add the list of nodes
2307
   */
2308
15.8M
  while (list != NULL) {
2309
15.7M
      cur = list;
2310
15.7M
      list = list->next;
2311
2312
15.7M
      xmlAddPrevSibling(end, cur);
2313
15.7M
  }
2314
87.3k
    }
2315
2316
2317
162k
    return(0);
2318
162k
}
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
10.8M
xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2331
10.8M
    if (node == NULL)
2332
0
  return(0);
2333
10.8M
    if (node->type != XML_ELEMENT_NODE)
2334
5.42M
  return(0);
2335
5.40M
    if (node->ns == NULL)
2336
4.46M
  return(0);
2337
943k
    if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
2338
943k
        (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
2339
596k
  if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
2340
556k
      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
203k
          ctxt->legacy = 1;
2347
203k
      }
2348
556k
  }
2349
596k
  if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2350
472k
      xmlNodePtr child = node->children;
2351
472k
      int nb_fallback = 0;
2352
2353
817k
      while (child != NULL) {
2354
367k
    if ((child->type == XML_ELEMENT_NODE) &&
2355
367k
        (child->ns != NULL) &&
2356
367k
        ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
2357
143k
         (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
2358
137k
        if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
2359
22.4k
      xmlXIncludeErr(ctxt, node,
2360
22.4k
                     XML_XINCLUDE_INCLUDE_IN_INCLUDE,
2361
22.4k
               "%s has an 'include' child\n",
2362
22.4k
               XINCLUDE_NODE);
2363
22.4k
      return(0);
2364
22.4k
        }
2365
115k
        if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2366
102k
      nb_fallback++;
2367
102k
        }
2368
115k
    }
2369
344k
    child = child->next;
2370
344k
      }
2371
450k
      if (nb_fallback > 1) {
2372
1.10k
    xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
2373
1.10k
             "%s has multiple fallback children\n",
2374
1.10k
                   XINCLUDE_NODE);
2375
1.10k
    return(0);
2376
1.10k
      }
2377
449k
      return(1);
2378
450k
  }
2379
124k
  if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2380
43.8k
      if ((node->parent == NULL) ||
2381
43.8k
    (node->parent->type != XML_ELEMENT_NODE) ||
2382
43.8k
    (node->parent->ns == NULL) ||
2383
43.8k
    ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
2384
34.5k
     (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
2385
43.8k
    (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
2386
38.3k
    xmlXIncludeErr(ctxt, node,
2387
38.3k
                   XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
2388
38.3k
             "%s is not the child of an 'include'\n",
2389
38.3k
             XINCLUDE_FALLBACK);
2390
38.3k
      }
2391
43.8k
  }
2392
124k
    }
2393
471k
    return(0);
2394
943k
}
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
326k
                     int skipRoot) {
2411
326k
    xmlNodePtr cur;
2412
326k
    int ret = 0;
2413
326k
    int i, start;
2414
2415
326k
    if ((doc == NULL) || (tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2416
0
  return(-1);
2417
326k
    if ((skipRoot) && (tree->children == NULL))
2418
0
        return(-1);
2419
326k
    if (ctxt == NULL)
2420
0
  return(-1);
2421
2422
326k
    if (doc->URL != NULL) {
2423
305k
  ret = xmlXIncludeURLPush(ctxt, doc->URL);
2424
305k
  if (ret < 0)
2425
0
      return(-1);
2426
305k
    }
2427
326k
    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
326k
    if (skipRoot)
2450
95.1k
        cur = tree->children;
2451
231k
    else
2452
231k
        cur = tree;
2453
10.8M
    do {
2454
  /* TODO: need to work on entities -> stack */
2455
10.8M
        if (xmlXIncludeTestNode(ctxt, cur) == 1) {
2456
449k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2457
            /*
2458
             * Avoid superlinear expansion by limiting the total number
2459
             * of replacements.
2460
             */
2461
449k
            if (ctxt->incTotal >= 20)
2462
1.37k
                return(-1);
2463
447k
#endif
2464
447k
            ctxt->incTotal++;
2465
447k
            xmlXIncludePreProcessNode(ctxt, cur);
2466
10.3M
        } else if ((cur->children != NULL) &&
2467
10.3M
                   ((cur->type == XML_DOCUMENT_NODE) ||
2468
2.61M
                    (cur->type == XML_ELEMENT_NODE))) {
2469
2.59M
            cur = cur->children;
2470
2.59M
            continue;
2471
2.59M
        }
2472
10.9M
        do {
2473
10.9M
            if (cur == tree)
2474
325k
                break;
2475
10.5M
            if (cur->next != NULL) {
2476
7.91M
                cur = cur->next;
2477
7.91M
                break;
2478
7.91M
            }
2479
2.68M
            cur = cur->parent;
2480
2.68M
        } while (cur != NULL);
2481
10.8M
    } while ((cur != NULL) && (cur != tree));
2482
2483
    /*
2484
     * Second Phase : collect the infosets fragments
2485
     */
2486
705k
    for (i = start;i < ctxt->incNr; i++) {
2487
379k
        xmlXIncludeLoadNode(ctxt, i);
2488
379k
  ret++;
2489
379k
    }
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
713k
    for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2503
387k
  if ((ctxt->incTab[i]->inc != NULL) ||
2504
387k
            (ctxt->incTab[i]->xptr != NULL) ||
2505
387k
      (ctxt->incTab[i]->emptyFb != 0))  /* (empty fallback) */
2506
163k
      xmlXIncludeIncludeNode(ctxt, i);
2507
387k
    }
2508
2509
325k
    if (doc->URL != NULL)
2510
300k
  xmlXIncludeURLPop(ctxt);
2511
325k
    return(ret);
2512
326k
}
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
313k
xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
2525
313k
    if (ctxt == NULL)
2526
0
        return(-1);
2527
313k
    ctxt->parseFlags = flags;
2528
313k
    return(0);
2529
313k
}
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
211k
xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
2546
211k
    xmlXIncludeCtxtPtr ctxt;
2547
211k
    int ret = 0;
2548
2549
211k
    if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) ||
2550
211k
        (tree->doc == NULL))
2551
0
        return(-1);
2552
2553
211k
    ctxt = xmlXIncludeNewContext(tree->doc);
2554
211k
    if (ctxt == NULL)
2555
0
        return(-1);
2556
211k
    ctxt->_private = data;
2557
211k
    ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
2558
211k
    xmlXIncludeSetFlags(ctxt, flags);
2559
211k
    ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0);
2560
211k
    if ((ret >= 0) && (ctxt->nbErrors > 0))
2561
96.1k
        ret = -1;
2562
2563
211k
    xmlXIncludeFreeContext(ctxt);
2564
211k
    return(ret);
2565
211k
}
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
252k
xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) {
2581
252k
    xmlNodePtr tree;
2582
2583
252k
    if (doc == NULL)
2584
19.3k
  return(-1);
2585
232k
    tree = xmlDocGetRootElement(doc);
2586
232k
    if (tree == NULL)
2587
21.6k
  return(-1);
2588
211k
    return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));
2589
232k
}
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
252k
xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
2603
252k
    return xmlXIncludeProcessFlagsData(doc, flags, NULL);
2604
252k
}
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
13.8k
xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2678
13.8k
    int ret = 0;
2679
2680
13.8k
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
2681
13.8k
        (node->doc == NULL) || (ctxt == NULL))
2682
0
  return(-1);
2683
13.8k
    ret = xmlXIncludeDoProcess(ctxt, node->doc, node, 0);
2684
13.8k
    if ((ret >= 0) && (ctxt->nbErrors > 0))
2685
13.2k
  ret = -1;
2686
13.8k
    return(ret);
2687
13.8k
}
2688
2689
#else /* !LIBXML_XINCLUDE_ENABLED */
2690
#endif