Coverage Report

Created: 2024-01-18 09:15

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