Coverage Report

Created: 2024-01-18 09:16

/src/libxml2/xinclude.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xinclude.c : Code to implement XInclude processing
3
 *
4
 * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003
5
 * http://www.w3.org/TR/2003/WD-xinclude-20031110
6
 *
7
 * See Copyright for the status of this software.
8
 *
9
 * daniel@veillard.com
10
 */
11
12
#define IN_LIBXML
13
#include "libxml.h"
14
15
#include <string.h>
16
#include <libxml/xmlmemory.h>
17
#include <libxml/tree.h>
18
#include <libxml/parser.h>
19
#include <libxml/uri.h>
20
#include <libxml/xpath.h>
21
#include <libxml/xpointer.h>
22
#include <libxml/parserInternals.h>
23
#include <libxml/xmlerror.h>
24
#include <libxml/encoding.h>
25
#include <libxml/globals.h>
26
27
#ifdef LIBXML_XINCLUDE_ENABLED
28
#include <libxml/xinclude.h>
29
30
#include "private/buf.h"
31
#include "private/error.h"
32
33
397k
#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
803k
{
137
803k
    if (ctxt != NULL)
138
803k
  ctxt->nbErrors++;
139
803k
    __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
140
803k
                    error, XML_ERR_ERROR, NULL, 0,
141
803k
        (const char *) extra, NULL, NULL, 0, 0,
142
803k
        msg, (const char *) extra);
143
803k
}
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
3.23M
                   const xmlChar *name) {
179
3.23M
    xmlChar *ret;
180
181
3.23M
    ret = xmlGetNsProp(cur, XINCLUDE_NS, name);
182
3.23M
    if (ret != NULL)
183
0
        return(ret);
184
3.23M
    if (ctxt->legacy != 0) {
185
3.10M
  ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name);
186
3.10M
  if (ret != NULL)
187
0
      return(ret);
188
3.10M
    }
189
3.23M
    ret = xmlGetProp(cur, name);
190
3.23M
    return(ret);
191
3.23M
}
192
/**
193
 * xmlXIncludeFreeRef:
194
 * @ref: the XInclude reference
195
 *
196
 * Free an XInclude reference
197
 */
198
static void
199
590k
xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
200
590k
    if (ref == NULL)
201
0
  return;
202
#ifdef DEBUG_XINCLUDE
203
    xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
204
#endif
205
590k
    if (ref->doc != NULL) {
206
#ifdef DEBUG_XINCLUDE
207
  xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
208
#endif
209
1.37k
  xmlFreeDoc(ref->doc);
210
1.37k
    }
211
590k
    if (ref->URI != NULL)
212
590k
  xmlFree(ref->URI);
213
590k
    if (ref->fragment != NULL)
214
280k
  xmlFree(ref->fragment);
215
590k
    if (ref->xptr != NULL)
216
0
  xmlXPathFreeObject(ref->xptr);
217
590k
    xmlFree(ref);
218
590k
}
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
601k
            xmlNodePtr ref) {
232
601k
    xmlXIncludeRefPtr ret;
233
234
#ifdef DEBUG_XINCLUDE
235
    xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
236
#endif
237
601k
    ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
238
601k
    if (ret == NULL) {
239
0
        xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
240
0
  return(NULL);
241
0
    }
242
601k
    memset(ret, 0, sizeof(xmlXIncludeRef));
243
601k
    if (URI == NULL)
244
0
  ret->URI = NULL;
245
601k
    else
246
601k
  ret->URI = xmlStrdup(URI);
247
601k
    ret->fragment = NULL;
248
601k
    ret->ref = ref;
249
601k
    ret->doc = NULL;
250
601k
    ret->count = 0;
251
601k
    ret->xml = 0;
252
601k
    ret->inc = NULL;
253
601k
    if (ctxt->incMax == 0) {
254
277k
  ctxt->incMax = 4;
255
277k
        ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
256
277k
                sizeof(ctxt->incTab[0]));
257
277k
        if (ctxt->incTab == NULL) {
258
0
      xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
259
0
      xmlXIncludeFreeRef(ret);
260
0
      return(NULL);
261
0
  }
262
277k
    }
263
601k
    if (ctxt->incNr >= ctxt->incMax) {
264
41.6k
  ctxt->incMax *= 2;
265
41.6k
        ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
266
41.6k
               ctxt->incMax * sizeof(ctxt->incTab[0]));
267
41.6k
        if (ctxt->incTab == NULL) {
268
0
      xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
269
0
      xmlXIncludeFreeRef(ret);
270
0
      return(NULL);
271
0
  }
272
41.6k
    }
273
601k
    ctxt->incTab[ctxt->incNr++] = ret;
274
601k
    return(ret);
275
601k
}
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
419k
xmlXIncludeNewContext(xmlDocPtr doc) {
287
419k
    xmlXIncludeCtxtPtr ret;
288
289
#ifdef DEBUG_XINCLUDE
290
    xmlGenericError(xmlGenericErrorContext, "New context\n");
291
#endif
292
419k
    if (doc == NULL)
293
0
  return(NULL);
294
419k
    ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
295
419k
    if (ret == NULL) {
296
0
  xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
297
0
                       "creating XInclude context");
298
0
  return(NULL);
299
0
    }
300
419k
    memset(ret, 0, sizeof(xmlXIncludeCtxt));
301
419k
    ret->doc = doc;
302
419k
    ret->incNr = 0;
303
419k
    ret->incBase = 0;
304
419k
    ret->incMax = 0;
305
419k
    ret->incTab = NULL;
306
419k
    ret->nbErrors = 0;
307
419k
    return(ret);
308
419k
}
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
397k
{
323
397k
    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
397k
    if (ctxt->urlTab == NULL) {
329
397k
  ctxt->urlMax = 4;
330
397k
  ctxt->urlNr = 0;
331
397k
  ctxt->urlTab = (xmlChar * *) xmlMalloc(
332
397k
            ctxt->urlMax * sizeof(ctxt->urlTab[0]));
333
397k
        if (ctxt->urlTab == NULL) {
334
0
      xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
335
0
            return (-1);
336
0
        }
337
397k
    }
338
397k
    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
397k
    ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
350
397k
    return (ctxt->urlNr++);
351
397k
}
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
393k
{
362
393k
    xmlChar * ret;
363
364
393k
    if (ctxt->urlNr <= 0)
365
0
        return;
366
393k
    ctxt->urlNr--;
367
393k
    if (ctxt->urlNr > 0)
368
0
        ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
369
393k
    else
370
393k
        ctxt->url = NULL;
371
393k
    ret = ctxt->urlTab[ctxt->urlNr];
372
393k
    ctxt->urlTab[ctxt->urlNr] = NULL;
373
393k
    if (ret != NULL)
374
393k
  xmlFree(ret);
375
393k
}
376
377
/**
378
 * xmlXIncludeFreeContext:
379
 * @ctxt: the XInclude context
380
 *
381
 * Free an XInclude context
382
 */
383
void
384
415k
xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
385
415k
    int i;
386
387
#ifdef DEBUG_XINCLUDE
388
    xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
389
#endif
390
415k
    if (ctxt == NULL)
391
0
  return;
392
416k
    while (ctxt->urlNr > 0)
393
1.24k
  xmlXIncludeURLPop(ctxt);
394
415k
    if (ctxt->urlTab != NULL)
395
393k
  xmlFree(ctxt->urlTab);
396
1.04M
    for (i = 0;i < ctxt->incNr;i++) {
397
627k
  if (ctxt->incTab[i] != NULL)
398
590k
      xmlXIncludeFreeRef(ctxt->incTab[i]);
399
627k
    }
400
415k
    if (ctxt->incTab != NULL)
401
280k
  xmlFree(ctxt->incTab);
402
415k
    if (ctxt->txtTab != NULL) {
403
470
  for (i = 0;i < ctxt->txtNr;i++) {
404
239
      if (ctxt->txtTab[i] != NULL)
405
0
    xmlFree(ctxt->txtTab[i]);
406
239
  }
407
231
  xmlFree(ctxt->txtTab);
408
231
    }
409
415k
    if (ctxt->txturlTab != NULL) {
410
470
  for (i = 0;i < ctxt->txtNr;i++) {
411
239
      if (ctxt->txturlTab[i] != NULL)
412
239
    xmlFree(ctxt->txturlTab[i]);
413
239
  }
414
231
  xmlFree(ctxt->txturlTab);
415
231
    }
416
415k
    if (ctxt->base != NULL) {
417
399k
        xmlFree(ctxt->base);
418
399k
    }
419
415k
    xmlFree(ctxt);
420
415k
}
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
340k
xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
431
340k
    xmlDocPtr ret;
432
340k
    xmlParserCtxtPtr pctxt;
433
340k
    xmlParserInputPtr inputStream;
434
435
340k
    xmlInitParser();
436
437
340k
    pctxt = xmlNewParserCtxt();
438
340k
    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
340k
    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
340k
    if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL)) {
453
129k
       if (pctxt->dict != NULL)
454
129k
            xmlDictFree(pctxt->dict);
455
129k
  pctxt->dict = ctxt->doc->dict;
456
129k
  xmlDictReference(pctxt->dict);
457
129k
    }
458
459
340k
    xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
460
461
    /* Don't read from stdin. */
462
340k
    if ((URL != NULL) && (strcmp(URL, "-") == 0))
463
0
        URL = "./-";
464
465
340k
    inputStream = xmlLoadExternalEntity(URL, NULL, pctxt);
466
340k
    if (inputStream == NULL) {
467
164k
  xmlFreeParserCtxt(pctxt);
468
164k
  return(NULL);
469
164k
    }
470
471
175k
    inputPush(pctxt, inputStream);
472
473
175k
    if (pctxt->directory == NULL)
474
175k
        pctxt->directory = xmlParserGetDirectory(URL);
475
476
175k
    pctxt->loadsubset |= XML_DETECT_IDS;
477
478
175k
    xmlParseDocument(pctxt);
479
480
175k
    if (pctxt->wellFormed) {
481
6.37k
        ret = pctxt->myDoc;
482
6.37k
    }
483
169k
    else {
484
169k
        ret = NULL;
485
169k
  if (pctxt->myDoc != NULL)
486
166k
      xmlFreeDoc(pctxt->myDoc);
487
169k
        pctxt->myDoc = NULL;
488
169k
    }
489
175k
    xmlFreeParserCtxt(pctxt);
490
491
175k
    return(ret);
492
340k
}
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
696k
xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
503
696k
    xmlXIncludeRefPtr ref;
504
696k
    xmlURIPtr uri;
505
696k
    xmlChar *URL;
506
696k
    xmlChar *fragment = NULL;
507
696k
    xmlChar *href;
508
696k
    xmlChar *parse;
509
696k
    xmlChar *base;
510
696k
    xmlChar *URI;
511
696k
    int xml = 1, i; /* default Issue 64 */
512
696k
    int local = 0;
513
514
515
696k
    if (ctxt == NULL)
516
0
  return(-1);
517
696k
    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
696k
    href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
527
696k
    if (href == NULL) {
528
158k
  href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
529
158k
  if (href == NULL)
530
0
      return(-1);
531
158k
    }
532
696k
    parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
533
696k
    if (parse != NULL) {
534
2.89k
  if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
535
564
      xml = 1;
536
2.33k
  else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
537
1.91k
      xml = 0;
538
415
  else {
539
415
      xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
540
415
                     "invalid value %s for 'parse'\n", parse);
541
415
      if (href != NULL)
542
415
    xmlFree(href);
543
415
      if (parse != NULL)
544
415
    xmlFree(parse);
545
415
      return(-1);
546
415
  }
547
2.89k
    }
548
549
    /*
550
     * compute the URI
551
     */
552
696k
    base = xmlNodeGetBase(ctxt->doc, cur);
553
696k
    if (base == NULL) {
554
34.5k
  URI = xmlBuildURI(href, ctxt->doc->URL);
555
661k
    } else {
556
661k
  URI = xmlBuildURI(href, base);
557
661k
    }
558
696k
    if (URI == NULL) {
559
107k
  xmlChar *escbase;
560
107k
  xmlChar *eschref;
561
  /*
562
   * Some escaping may be needed
563
   */
564
107k
  escbase = xmlURIEscape(base);
565
107k
  eschref = xmlURIEscape(href);
566
107k
  URI = xmlBuildURI(eschref, escbase);
567
107k
  if (escbase != NULL)
568
91.5k
      xmlFree(escbase);
569
107k
  if (eschref != NULL)
570
70.5k
      xmlFree(eschref);
571
107k
    }
572
696k
    if (parse != NULL)
573
2.48k
  xmlFree(parse);
574
696k
    if (href != NULL)
575
696k
  xmlFree(href);
576
696k
    if (base != NULL)
577
661k
  xmlFree(base);
578
696k
    if (URI == NULL) {
579
38.1k
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
580
38.1k
                 "failed build URL\n", NULL);
581
38.1k
  return(-1);
582
38.1k
    }
583
657k
    fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
584
585
    /*
586
     * Check the URL and remove any fragment identifier
587
     */
588
657k
    uri = xmlParseURI((const char *)URI);
589
657k
    if (uri == NULL) {
590
5.57k
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
591
5.57k
                 "invalid value URI %s\n", URI);
592
5.57k
  if (fragment != NULL)
593
751
      xmlFree(fragment);
594
5.57k
  xmlFree(URI);
595
5.57k
  return(-1);
596
5.57k
    }
597
598
652k
    if (uri->fragment != NULL) {
599
186k
        if (ctxt->legacy != 0) {
600
183k
      if (fragment == NULL) {
601
178k
    fragment = (xmlChar *) uri->fragment;
602
178k
      } else {
603
5.12k
    xmlFree(uri->fragment);
604
5.12k
      }
605
183k
  } else {
606
3.33k
      xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID,
607
3.33k
       "Invalid fragment identifier in URI %s use the xpointer attribute\n",
608
3.33k
                           URI);
609
3.33k
      if (fragment != NULL)
610
122
          xmlFree(fragment);
611
3.33k
      xmlFreeURI(uri);
612
3.33k
      xmlFree(URI);
613
3.33k
      return(-1);
614
3.33k
  }
615
183k
  uri->fragment = NULL;
616
183k
    }
617
649k
    URL = xmlSaveUri(uri);
618
649k
    xmlFreeURI(uri);
619
649k
    xmlFree(URI);
620
649k
    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
649k
    if (xmlStrEqual(URL, ctxt->doc->URL))
629
259k
  local = 1;
630
631
    /*
632
     * If local and xml then we need a fragment
633
     */
634
649k
    if ((local == 1) && (xml == 1) &&
635
649k
        ((fragment == NULL) || (fragment[0] == 0))) {
636
47.8k
  xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
637
47.8k
                 "detected a local recursion with no xpointer in %s\n",
638
47.8k
           URL);
639
47.8k
        xmlFree(URL);
640
47.8k
        xmlFree(fragment);
641
47.8k
  return(-1);
642
47.8k
    }
643
644
    /*
645
     * Check the URL against the stack for recursions
646
     */
647
601k
    if ((!local) && (xml == 1)) {
648
745k
  for (i = 0;i < ctxt->urlNr;i++) {
649
357k
      if (xmlStrEqual(URL, ctxt->urlTab[i])) {
650
67
    xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
651
67
                   "detected a recursion in %s\n", URL);
652
67
                xmlFree(URL);
653
67
                xmlFree(fragment);
654
67
    return(-1);
655
67
      }
656
357k
  }
657
388k
    }
658
659
601k
    ref = xmlXIncludeNewRef(ctxt, URL, cur);
660
601k
    xmlFree(URL);
661
601k
    if (ref == NULL) {
662
0
  return(-1);
663
0
    }
664
601k
    ref->fragment = fragment;
665
601k
    ref->doc = NULL;
666
601k
    ref->xml = xml;
667
601k
    ref->count = 1;
668
601k
    return(0);
669
601k
}
670
671
/**
672
 * xmlXIncludeRecurseDoc:
673
 * @ctxt:  the XInclude context
674
 * @doc:  the new document
675
 * @url:  the associated URL
676
 *
677
 * The XInclude recursive nature is handled at this point.
678
 */
679
static void
680
xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
681
6.37k
                const xmlURL url ATTRIBUTE_UNUSED) {
682
6.37k
    xmlXIncludeCtxtPtr newctxt;
683
6.37k
    int i;
684
685
    /*
686
     * Avoid recursion in already substituted resources
687
    for (i = 0;i < ctxt->urlNr;i++) {
688
  if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
689
      return;
690
    }
691
     */
692
693
#ifdef DEBUG_XINCLUDE
694
    xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
695
#endif
696
    /*
697
     * Handle recursion here.
698
     */
699
700
6.37k
    newctxt = xmlXIncludeNewContext(doc);
701
6.37k
    if (newctxt != NULL) {
702
  /*
703
   * Copy the private user data
704
   */
705
6.37k
  newctxt->_private = ctxt->_private;
706
  /*
707
   * Copy the existing document set
708
   */
709
6.37k
  newctxt->incMax = ctxt->incMax;
710
6.37k
  newctxt->incNr = ctxt->incNr;
711
6.37k
        newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
712
6.37k
                              sizeof(newctxt->incTab[0]));
713
6.37k
        if (newctxt->incTab == NULL) {
714
0
      xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
715
0
      xmlFree(newctxt);
716
0
      return;
717
0
  }
718
  /*
719
   * copy the urlTab
720
   */
721
6.37k
  newctxt->urlMax = ctxt->urlMax;
722
6.37k
  newctxt->urlNr = ctxt->urlNr;
723
6.37k
  newctxt->urlTab = ctxt->urlTab;
724
725
  /*
726
   * Inherit the existing base
727
   */
728
6.37k
  newctxt->base = xmlStrdup(ctxt->base);
729
730
  /*
731
   * Inherit the documents already in use by other includes
732
   */
733
6.37k
  newctxt->incBase = ctxt->incNr;
734
43.4k
  for (i = 0;i < ctxt->incNr;i++) {
735
37.1k
      newctxt->incTab[i] = ctxt->incTab[i];
736
37.1k
      newctxt->incTab[i]->count++; /* prevent the recursion from
737
              freeing it */
738
37.1k
  }
739
  /*
740
   * The new context should also inherit the Parse Flags
741
   * (bug 132597)
742
   */
743
6.37k
  newctxt->parseFlags = ctxt->parseFlags;
744
6.37k
        newctxt->incTotal = ctxt->incTotal;
745
6.37k
  xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc), 0);
746
6.37k
        ctxt->incTotal = newctxt->incTotal;
747
43.4k
  for (i = 0;i < ctxt->incNr;i++) {
748
37.1k
      newctxt->incTab[i]->count--;
749
37.1k
      newctxt->incTab[i] = NULL;
750
37.1k
  }
751
752
  /* urlTab may have been reallocated */
753
6.37k
  ctxt->urlTab = newctxt->urlTab;
754
6.37k
  ctxt->urlMax = newctxt->urlMax;
755
756
6.37k
  newctxt->urlMax = 0;
757
6.37k
  newctxt->urlNr = 0;
758
6.37k
  newctxt->urlTab = NULL;
759
760
6.37k
  xmlXIncludeFreeContext(newctxt);
761
6.37k
    }
762
#ifdef DEBUG_XINCLUDE
763
    xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
764
#endif
765
6.37k
}
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
239
                  const xmlURL url) {
778
#ifdef DEBUG_XINCLUDE
779
    xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
780
#endif
781
239
    if (ctxt->txtMax == 0) {
782
231
  ctxt->txtMax = 4;
783
231
        ctxt->txtTab = (xmlChar **) xmlMalloc(ctxt->txtMax *
784
231
                              sizeof(ctxt->txtTab[0]));
785
231
        if (ctxt->txtTab == NULL) {
786
0
      xmlXIncludeErrMemory(ctxt, NULL, "processing text");
787
0
      return;
788
0
  }
789
231
        ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
790
231
                              sizeof(ctxt->txturlTab[0]));
791
231
        if (ctxt->txturlTab == NULL) {
792
0
      xmlXIncludeErrMemory(ctxt, NULL, "processing text");
793
0
      return;
794
0
  }
795
231
    }
796
239
    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
239
    ctxt->txtTab[ctxt->txtNr] = xmlStrdup(txt);
812
239
    ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
813
239
    ctxt->txtNr++;
814
239
}
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
6.63M
              xmlDocPtr source, xmlNodePtr elem) {
839
6.63M
    xmlNodePtr result = NULL;
840
841
6.63M
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
842
6.63M
  (elem == NULL))
843
0
  return(NULL);
844
6.63M
    if (elem->type == XML_DTD_NODE)
845
4.72k
  return(NULL);
846
6.63M
    if (elem->type == XML_DOCUMENT_NODE)
847
22.3k
  result = xmlXIncludeCopyNodeList(ctxt, target, source, elem->children);
848
6.61M
    else
849
6.61M
        result = xmlDocCopyNode(elem, target, 1);
850
6.63M
    return(result);
851
6.63M
}
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
28.2k
                  xmlDocPtr source, xmlNodePtr elem) {
866
28.2k
    xmlNodePtr cur, res, result = NULL, last = NULL;
867
868
28.2k
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
869
28.2k
  (elem == NULL))
870
0
  return(NULL);
871
28.2k
    cur = elem;
872
77.1k
    while (cur != NULL) {
873
48.8k
  res = xmlXIncludeCopyNode(ctxt, target, source, cur);
874
48.8k
  if (res != NULL) {
875
44.1k
      if (result == NULL) {
876
28.2k
    result = last = res;
877
28.2k
      } else {
878
15.8k
    last->next = res;
879
15.8k
    res->prev = last;
880
15.8k
    last = res;
881
15.8k
      }
882
44.1k
  }
883
48.8k
  cur = cur->next;
884
48.8k
    }
885
28.2k
    return(result);
886
28.2k
}
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
54.0k
                  xmlDocPtr source, xmlXPathObjectPtr obj) {
1146
54.0k
    xmlNodePtr list = NULL, last = NULL;
1147
54.0k
    int i;
1148
1149
54.0k
    if (source == NULL)
1150
0
  source = ctxt->doc;
1151
54.0k
    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
1152
54.0k
  (obj == NULL))
1153
0
  return(NULL);
1154
54.0k
    switch (obj->type) {
1155
54.0k
        case XPATH_NODESET: {
1156
54.0k
      xmlNodeSetPtr set = obj->nodesetval;
1157
54.0k
      if (set == NULL)
1158
0
    return(NULL);
1159
4.04M
      for (i = 0;i < set->nodeNr;i++) {
1160
3.99M
    if (set->nodeTab[i] == NULL)
1161
41.6k
        continue;
1162
3.94M
    switch (set->nodeTab[i]->type) {
1163
2.67M
        case XML_TEXT_NODE:
1164
2.72M
        case XML_CDATA_SECTION_NODE:
1165
3.85M
        case XML_ELEMENT_NODE:
1166
3.85M
        case XML_ENTITY_REF_NODE:
1167
3.85M
        case XML_ENTITY_NODE:
1168
3.86M
        case XML_PI_NODE:
1169
3.90M
        case XML_COMMENT_NODE:
1170
3.93M
        case XML_DOCUMENT_NODE:
1171
3.93M
        case XML_HTML_DOCUMENT_NODE:
1172
3.93M
        case XML_XINCLUDE_END:
1173
3.93M
      break;
1174
14.3k
        case XML_XINCLUDE_START: {
1175
14.3k
                  xmlNodePtr tmp, cur = set->nodeTab[i];
1176
1177
14.3k
      cur = cur->next;
1178
2.67M
      while (cur != NULL) {
1179
2.67M
          switch(cur->type) {
1180
948k
        case XML_TEXT_NODE:
1181
964k
        case XML_CDATA_SECTION_NODE:
1182
2.54M
        case XML_ELEMENT_NODE:
1183
2.54M
        case XML_ENTITY_REF_NODE:
1184
2.54M
        case XML_ENTITY_NODE:
1185
2.58M
        case XML_PI_NODE:
1186
2.65M
        case XML_COMMENT_NODE:
1187
2.65M
            tmp = xmlXIncludeCopyNode(ctxt, target,
1188
2.65M
                    source, cur);
1189
2.65M
            if (last == NULL) {
1190
243
          list = last = tmp;
1191
2.65M
            } else {
1192
2.65M
          last = xmlAddNextSibling(last, tmp);
1193
2.65M
            }
1194
2.65M
            cur = cur->next;
1195
2.65M
            continue;
1196
14.2k
        default:
1197
14.2k
            break;
1198
2.67M
          }
1199
14.2k
          break;
1200
2.67M
      }
1201
14.3k
      continue;
1202
14.3k
        }
1203
14.3k
        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
3.94M
    }
1214
3.93M
    if (last == NULL)
1215
53.0k
        list = last = xmlXIncludeCopyNode(ctxt, target, source,
1216
53.0k
                                    set->nodeTab[i]);
1217
3.87M
    else {
1218
3.87M
        xmlAddNextSibling(last,
1219
3.87M
          xmlXIncludeCopyNode(ctxt, target, source,
1220
3.87M
                        set->nodeTab[i]));
1221
3.87M
        if (last->next != NULL)
1222
1.73M
      last = last->next;
1223
3.87M
    }
1224
3.93M
      }
1225
50.8k
      break;
1226
54.0k
  }
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
50.8k
  default:
1254
0
      break;
1255
54.0k
    }
1256
50.7k
    return(list);
1257
54.0k
}
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
966
                 const xmlChar *name ATTRIBUTE_UNUSED) {
1282
966
    xmlEntityPtr ent = (xmlEntityPtr) payload;
1283
966
    xmlXIncludeMergeDataPtr data = (xmlXIncludeMergeDataPtr) vdata;
1284
966
    xmlEntityPtr ret, prev;
1285
966
    xmlDocPtr doc;
1286
966
    xmlXIncludeCtxtPtr ctxt;
1287
1288
966
    if ((ent == NULL) || (data == NULL))
1289
0
  return;
1290
966
    ctxt = data->ctxt;
1291
966
    doc = data->doc;
1292
966
    if ((ctxt == NULL) || (doc == NULL))
1293
0
  return;
1294
966
    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
390
        case XML_INTERNAL_GENERAL_ENTITY:
1300
488
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1301
966
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1302
966
      break;
1303
966
    }
1304
966
    ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1305
966
        ent->SystemID, ent->content);
1306
966
    if (ret != NULL) {
1307
277
  if (ent->URI != NULL)
1308
192
      ret->URI = xmlStrdup(ent->URI);
1309
689
    } else {
1310
689
  prev = xmlGetDocEntity(doc, ent->name);
1311
689
  if (prev != NULL) {
1312
689
      if (ent->etype != prev->etype)
1313
81
    goto error;
1314
1315
608
      if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1316
339
    if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1317
0
        goto error;
1318
339
      } else if ((ent->ExternalID != NULL) &&
1319
269
           (prev->ExternalID != NULL)) {
1320
0
    if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1321
0
        goto error;
1322
269
      } else if ((ent->content != NULL) && (prev->content != NULL)) {
1323
269
    if (!xmlStrEqual(ent->content, prev->content))
1324
0
        goto error;
1325
269
      } else {
1326
0
    goto error;
1327
0
      }
1328
1329
608
  }
1330
689
    }
1331
885
    return;
1332
885
error:
1333
81
    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
57
        case XML_INTERNAL_GENERAL_ENTITY:
1338
57
        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1339
57
      return;
1340
24
        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1341
24
      break;
1342
81
    }
1343
24
    xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
1344
24
                   "mismatch in redefinition of entity %s\n",
1345
24
       ent->name);
1346
24
}
1347
1348
/**
1349
 * xmlXIncludeMergeEntities:
1350
 * @ctxt: an XInclude context
1351
 * @doc:  the including doc
1352
 * @from:  the included doc
1353
 *
1354
 * Implements the entity merge
1355
 *
1356
 * Returns 0 if merge succeeded, -1 if some processing failed
1357
 */
1358
static int
1359
xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1360
6.37k
                   xmlDocPtr from) {
1361
6.37k
    xmlNodePtr cur;
1362
6.37k
    xmlDtdPtr target, source;
1363
1364
6.37k
    if (ctxt == NULL)
1365
0
  return(-1);
1366
1367
6.37k
    if ((from == NULL) || (from->intSubset == NULL))
1368
2.87k
  return(0);
1369
1370
3.50k
    target = doc->intSubset;
1371
3.50k
    if (target == NULL) {
1372
975
  cur = xmlDocGetRootElement(doc);
1373
975
  if (cur == NULL)
1374
0
      return(-1);
1375
975
        target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1376
975
  if (target == NULL)
1377
0
      return(-1);
1378
975
    }
1379
1380
3.50k
    source = from->intSubset;
1381
3.50k
    if ((source != NULL) && (source->entities != NULL)) {
1382
964
  xmlXIncludeMergeData data;
1383
1384
964
  data.ctxt = ctxt;
1385
964
  data.doc = doc;
1386
1387
964
  xmlHashScan((xmlHashTablePtr) source->entities,
1388
964
        xmlXIncludeMergeEntity, &data);
1389
964
    }
1390
3.50k
    source = from->extSubset;
1391
3.50k
    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
3.50k
    return(0);
1407
3.50k
}
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
589k
xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1421
589k
    xmlDocPtr doc;
1422
589k
    xmlURIPtr uri;
1423
589k
    xmlChar *URL;
1424
589k
    xmlChar *fragment = NULL;
1425
589k
    int i = 0;
1426
589k
#ifdef LIBXML_XPTR_ENABLED
1427
589k
    int saveFlags;
1428
589k
#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
589k
    uri = xmlParseURI((const char *)url);
1437
589k
    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
589k
    if (uri->fragment != NULL) {
1444
177k
  fragment = (xmlChar *) uri->fragment;
1445
177k
  uri->fragment = NULL;
1446
177k
    }
1447
589k
    if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
1448
589k
        (ctxt->incTab[nr]->fragment != NULL)) {
1449
281k
  if (fragment != NULL) xmlFree(fragment);
1450
281k
  fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
1451
281k
    }
1452
589k
    URL = xmlSaveUri(uri);
1453
589k
    xmlFreeURI(uri);
1454
589k
    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
589k
    if ((URL[0] == 0) || (URL[0] == '#') ||
1473
589k
  ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
1474
247k
  doc = NULL;
1475
247k
        goto loaded;
1476
247k
    }
1477
1478
    /*
1479
     * Prevent reloading twice the document.
1480
     */
1481
2.45M
    for (i = 0; i < ctxt->incNr; i++) {
1482
2.11M
  if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1483
2.11M
      (ctxt->incTab[i]->doc != NULL)) {
1484
2.10k
      doc = ctxt->incTab[i]->doc;
1485
#ifdef DEBUG_XINCLUDE
1486
      printf("Already loaded %s\n", URL);
1487
#endif
1488
2.10k
      goto loaded;
1489
2.10k
  }
1490
2.11M
    }
1491
1492
    /*
1493
     * Load it.
1494
     */
1495
#ifdef DEBUG_XINCLUDE
1496
    printf("loading %s\n", URL);
1497
#endif
1498
340k
#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
340k
    saveFlags = ctxt->parseFlags;
1505
340k
    if (fragment != NULL) { /* if this is an XPointer eval */
1506
44.2k
  ctxt->parseFlags |= XML_PARSE_NOENT;
1507
44.2k
    }
1508
340k
#endif
1509
1510
340k
    doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
1511
340k
#ifdef LIBXML_XPTR_ENABLED
1512
340k
    ctxt->parseFlags = saveFlags;
1513
340k
#endif
1514
340k
    if (doc == NULL) {
1515
334k
  xmlFree(URL);
1516
334k
  if (fragment != NULL)
1517
42.3k
      xmlFree(fragment);
1518
334k
  return(-1);
1519
334k
    }
1520
6.37k
    ctxt->incTab[nr]->doc = doc;
1521
    /*
1522
     * It's possible that the requested URL has been mapped to a
1523
     * completely different location (e.g. through a catalog entry).
1524
     * To check for this, we compare the URL with that of the doc
1525
     * and change it if they disagree (bug 146988).
1526
     */
1527
6.37k
   if (!xmlStrEqual(URL, doc->URL)) {
1528
6.37k
       xmlFree(URL);
1529
6.37k
       URL = xmlStrdup(doc->URL);
1530
6.37k
   }
1531
23.0k
    for (i = nr + 1; i < ctxt->incNr; i++) {
1532
16.6k
  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
16.6k
    }
1540
1541
    /*
1542
     * Make sure we have all entities fixed up
1543
     */
1544
6.37k
    xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
1545
1546
    /*
1547
     * We don't need the DTD anymore, free up space
1548
    if (doc->intSubset != NULL) {
1549
  xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1550
  xmlFreeNode((xmlNodePtr) doc->intSubset);
1551
  doc->intSubset = NULL;
1552
    }
1553
    if (doc->extSubset != NULL) {
1554
  xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1555
  xmlFreeNode((xmlNodePtr) doc->extSubset);
1556
  doc->extSubset = NULL;
1557
    }
1558
     */
1559
6.37k
    xmlXIncludeRecurseDoc(ctxt, doc, URL);
1560
1561
255k
loaded:
1562
255k
    if (fragment == NULL) {
1563
  /*
1564
   * Add the top children list as the replacement copy.
1565
   */
1566
16.4k
  if (doc == NULL)
1567
10.4k
  {
1568
      /* Hopefully a DTD declaration won't be copied from
1569
       * the same document */
1570
10.4k
      ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
1571
10.4k
  } else {
1572
5.94k
      ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
1573
5.94k
                                           doc, doc->children);
1574
5.94k
  }
1575
16.4k
    }
1576
239k
#ifdef LIBXML_XPTR_ENABLED
1577
239k
    else {
1578
  /*
1579
   * Computes the XPointer expression and make a copy used
1580
   * as the replacement copy.
1581
   */
1582
239k
  xmlXPathObjectPtr xptr;
1583
239k
  xmlXPathContextPtr xptrctxt;
1584
239k
  xmlNodeSetPtr set;
1585
1586
239k
  if (doc == NULL) {
1587
236k
      xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1588
236k
                             NULL);
1589
236k
  } else {
1590
2.53k
      xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1591
2.53k
  }
1592
239k
  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
239k
  xptr = xmlXPtrEval(fragment, xptrctxt);
1601
239k
  if (xptr == NULL) {
1602
173k
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1603
173k
                     XML_XINCLUDE_XPTR_FAILED,
1604
173k
         "XPointer evaluation failed: #%s\n",
1605
173k
         fragment);
1606
173k
      xmlXPathFreeContext(xptrctxt);
1607
173k
      xmlFree(URL);
1608
173k
      xmlFree(fragment);
1609
173k
      return(-1);
1610
173k
  }
1611
66.1k
  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
66.1k
      case XPATH_NODESET:
1631
66.1k
          if ((xptr->nodesetval == NULL) ||
1632
66.1k
        (xptr->nodesetval->nodeNr <= 0)) {
1633
11.3k
                    xmlXPathFreeObject(xptr);
1634
11.3k
        xmlXPathFreeContext(xptrctxt);
1635
11.3k
        xmlFree(URL);
1636
11.3k
        xmlFree(fragment);
1637
11.3k
        return(-1);
1638
11.3k
    }
1639
1640
#ifdef LIBXML_XPTR_LOCS_ENABLED
1641
      case XPATH_RANGE:
1642
      case XPATH_LOCATIONSET:
1643
    break;
1644
#endif
1645
66.1k
  }
1646
54.7k
  set = xptr->nodesetval;
1647
54.7k
  if (set != NULL) {
1648
4.24M
      for (i = 0;i < set->nodeNr;i++) {
1649
4.18M
    if (set->nodeTab[i] == NULL)
1650
0
        continue;
1651
4.18M
    switch (set->nodeTab[i]->type) {
1652
1.21M
        case XML_ELEMENT_NODE:
1653
4.01M
        case XML_TEXT_NODE:
1654
4.05M
        case XML_CDATA_SECTION_NODE:
1655
4.05M
        case XML_ENTITY_REF_NODE:
1656
4.05M
        case XML_ENTITY_NODE:
1657
4.07M
        case XML_PI_NODE:
1658
4.12M
        case XML_COMMENT_NODE:
1659
4.14M
        case XML_DOCUMENT_NODE:
1660
4.14M
        case XML_HTML_DOCUMENT_NODE:
1661
4.14M
      continue;
1662
1663
41.7k
        case XML_ATTRIBUTE_NODE:
1664
41.7k
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1665
41.7k
                     XML_XINCLUDE_XPTR_RESULT,
1666
41.7k
               "XPointer selects an attribute: #%s\n",
1667
41.7k
               fragment);
1668
41.7k
      set->nodeTab[i] = NULL;
1669
41.7k
      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
4.18M
    }
1694
4.18M
      }
1695
54.7k
  }
1696
54.7k
  if (doc == NULL) {
1697
54.1k
      ctxt->incTab[nr]->xptr = xptr;
1698
54.1k
      ctxt->incTab[nr]->inc = NULL;
1699
54.1k
  } else {
1700
694
      ctxt->incTab[nr]->inc =
1701
694
    xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1702
694
      xmlXPathFreeObject(xptr);
1703
694
  }
1704
54.7k
  xmlXPathFreeContext(xptrctxt);
1705
54.7k
  xmlFree(fragment);
1706
54.7k
    }
1707
71.2k
#endif
1708
1709
    /*
1710
     * Do the xml:base fixup if needed
1711
     */
1712
71.2k
    if ((doc != NULL) && (URL != NULL) &&
1713
71.2k
        (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) &&
1714
71.2k
  (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) {
1715
1.19k
  xmlNodePtr node;
1716
1.19k
  xmlChar *base;
1717
1.19k
  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.19k
  base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base",
1724
1.19k
      XML_XML_NAMESPACE);
1725
1.19k
  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.19k
      curBase = xmlBuildRelativeURI(URL, ctxt->base);
1731
1.19k
      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.19k
      } else {
1736
    /* If the URI doesn't contain a slash, it's not relative */
1737
1.19k
          if (!xmlStrchr(curBase, '/'))
1738
0
        xmlFree(curBase);
1739
1.19k
    else
1740
1.19k
        base = curBase;
1741
1.19k
      }
1742
1.19k
  }
1743
1.19k
  if (base != NULL) { /* Adjustment may be needed */
1744
1.19k
      node = ctxt->incTab[nr]->inc;
1745
2.53k
      while (node != NULL) {
1746
    /* Only work on element nodes */
1747
1.33k
    if (node->type == XML_ELEMENT_NODE) {
1748
1.29k
        curBase = xmlNodeGetBase(node->doc, node);
1749
        /* If no current base, set it */
1750
1.29k
        if (curBase == NULL) {
1751
242
      xmlNodeSetBase(node, base);
1752
1.05k
        } 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.05k
      if (xmlStrEqual(curBase, node->doc->URL)) {
1759
1.05k
          xmlNodeSetBase(node, base);
1760
1.05k
      } 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.05k
      xmlFree(curBase);
1786
1.05k
        }
1787
1.29k
    }
1788
1.33k
          node = node->next;
1789
1.33k
      }
1790
1.19k
      xmlFree(base);
1791
1.19k
  }
1792
1.19k
    }
1793
71.2k
    if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1794
71.2k
  (ctxt->incTab[nr]->count <= 1)) {
1795
#ifdef DEBUG_XINCLUDE
1796
        printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1797
#endif
1798
5.00k
  xmlFreeDoc(ctxt->incTab[nr]->doc);
1799
5.00k
  ctxt->incTab[nr]->doc = NULL;
1800
5.00k
    }
1801
71.2k
    xmlFree(URL);
1802
71.2k
    return(0);
1803
255k
}
1804
1805
/**
1806
 * xmlXIncludeLoadTxt:
1807
 * @ctxt:  the XInclude context
1808
 * @url:  the associated URL
1809
 * @nr:  the xinclude node number
1810
 *
1811
 * Load the content, and store the result in the XInclude context
1812
 *
1813
 * Returns 0 in case of success, -1 in case of failure
1814
 */
1815
static int
1816
1.71k
xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1817
1.71k
    xmlParserInputBufferPtr buf;
1818
1.71k
    xmlNodePtr node;
1819
1.71k
    xmlURIPtr uri;
1820
1.71k
    xmlChar *URL;
1821
1.71k
    int i;
1822
1.71k
    xmlChar *encoding = NULL;
1823
1.71k
    xmlCharEncoding enc = (xmlCharEncoding) 0;
1824
1.71k
    xmlParserCtxtPtr pctxt;
1825
1.71k
    xmlParserInputPtr inputStream;
1826
1.71k
    int xinclude_multibyte_fallback_used = 0;
1827
1828
    /* Don't read from stdin. */
1829
1.71k
    if (xmlStrcmp(url, BAD_CAST "-") == 0)
1830
0
        url = BAD_CAST "./-";
1831
1832
    /*
1833
     * Check the URL and remove any fragment identifier
1834
     */
1835
1.71k
    uri = xmlParseURI((const char *)url);
1836
1.71k
    if (uri == NULL) {
1837
0
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1838
0
                 "invalid value URI %s\n", url);
1839
0
  return(-1);
1840
0
    }
1841
1.71k
    if (uri->fragment != NULL) {
1842
197
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1843
197
                 "fragment identifier forbidden for text: %s\n",
1844
197
           (const xmlChar *) uri->fragment);
1845
197
  xmlFreeURI(uri);
1846
197
  return(-1);
1847
197
    }
1848
1.52k
    URL = xmlSaveUri(uri);
1849
1.52k
    xmlFreeURI(uri);
1850
1.52k
    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
1.52k
    if (URL[0] == 0) {
1861
96
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1862
96
                 XML_XINCLUDE_TEXT_DOCUMENT,
1863
96
           "text serialization of document not available\n", NULL);
1864
96
  xmlFree(URL);
1865
96
  return(-1);
1866
96
    }
1867
1868
    /*
1869
     * Prevent reloading twice the document.
1870
     */
1871
1.49k
    for (i = 0; i < ctxt->txtNr; i++) {
1872
239
  if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1873
172
            node = xmlNewDocText(ctxt->doc, ctxt->txtTab[i]);
1874
172
      goto loaded;
1875
172
  }
1876
239
    }
1877
    /*
1878
     * Try to get the encoding if available
1879
     */
1880
1.25k
    if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1881
1.25k
  encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1882
1.25k
    }
1883
1.25k
    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
718
        enc = xmlParseCharEncoding((const char *) encoding);
1891
718
  if (enc == XML_CHAR_ENCODING_ERROR) {
1892
93
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1893
93
                     XML_XINCLUDE_UNKNOWN_ENCODING,
1894
93
         "encoding %s not supported\n", encoding);
1895
93
      xmlFree(encoding);
1896
93
      xmlFree(URL);
1897
93
      return(-1);
1898
93
  }
1899
625
  xmlFree(encoding);
1900
625
    }
1901
1902
    /*
1903
     * Load it.
1904
     */
1905
1.16k
    pctxt = xmlNewParserCtxt();
1906
1.16k
    inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt);
1907
1.16k
    if(inputStream == NULL) {
1908
921
  xmlFreeParserCtxt(pctxt);
1909
921
  xmlFree(URL);
1910
921
  return(-1);
1911
921
    }
1912
239
    buf = inputStream->buf;
1913
239
    if (buf == NULL) {
1914
0
  xmlFreeInputStream (inputStream);
1915
0
  xmlFreeParserCtxt(pctxt);
1916
0
  xmlFree(URL);
1917
0
  return(-1);
1918
0
    }
1919
239
    if (buf->encoder)
1920
0
  xmlCharEncCloseFunc(buf->encoder);
1921
239
    buf->encoder = xmlGetCharEncodingHandler(enc);
1922
239
    node = xmlNewDocText(ctxt->doc, NULL);
1923
1924
    /*
1925
     * Scan all chars from the resource and add the to the node
1926
     */
1927
239
xinclude_multibyte_fallback:
1928
239
    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
239
    xmlFreeParserCtxt(pctxt);
1963
239
    xmlXIncludeAddTxt(ctxt, node->content, URL);
1964
239
    xmlFreeInputStream(inputStream);
1965
1966
411
loaded:
1967
    /*
1968
     * Add the element as the replacement copy.
1969
     */
1970
411
    ctxt->incTab[nr]->inc = node;
1971
411
    xmlFree(URL);
1972
411
    return(0);
1973
239
}
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
104k
xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1988
104k
    xmlXIncludeCtxtPtr newctxt;
1989
104k
    int ret = 0;
1990
104k
    int oldNbErrors = ctxt->nbErrors;
1991
1992
104k
    if ((fallback == NULL) || (fallback->type == XML_NAMESPACE_DECL) ||
1993
104k
        (ctxt == NULL))
1994
0
  return(-1);
1995
104k
    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
103k
  newctxt = xmlXIncludeNewContext(ctxt->doc);
2001
103k
  if (newctxt == NULL)
2002
0
      return (-1);
2003
103k
  newctxt->_private = ctxt->_private;
2004
103k
  newctxt->base = xmlStrdup(ctxt->base);  /* Inherit the base from the existing context */
2005
103k
  xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
2006
103k
        newctxt->incTotal = ctxt->incTotal;
2007
103k
        if (xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback, 1) < 0)
2008
505
            ret = -1;
2009
103k
        ctxt->incTotal = newctxt->incTotal;
2010
103k
  if (ctxt->nbErrors > oldNbErrors)
2011
0
      ret = -1;
2012
103k
  xmlXIncludeFreeContext(newctxt);
2013
2014
103k
  ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
2015
103k
                                             fallback->children);
2016
103k
        if (ctxt->incTab[nr]->inc == NULL)
2017
224
            ctxt->incTab[nr]->emptyFb = 1;
2018
103k
    } else {
2019
1.42k
        ctxt->incTab[nr]->inc = NULL;
2020
1.42k
  ctxt->incTab[nr]->emptyFb = 1;  /* flag empty callback */
2021
1.42k
    }
2022
104k
    ctxt->incTab[nr]->fallback = 1;
2023
104k
    return(ret);
2024
104k
}
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
696k
xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2044
696k
    xmlXIncludeAddNode(ctxt, node);
2045
696k
    return(NULL);
2046
696k
}
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
591k
xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
2059
591k
    xmlNodePtr cur;
2060
591k
    xmlChar *href;
2061
591k
    xmlChar *parse;
2062
591k
    xmlChar *base;
2063
591k
    xmlChar *oldBase;
2064
591k
    xmlChar *URI;
2065
591k
    int xml = 1; /* default Issue 64 */
2066
591k
    int ret;
2067
2068
591k
    if (ctxt == NULL)
2069
0
  return(-1);
2070
591k
    if ((nr < 0) || (nr >= ctxt->incNr))
2071
0
  return(-1);
2072
591k
    cur = ctxt->incTab[nr]->ref;
2073
591k
    if (cur == NULL)
2074
0
  return(-1);
2075
2076
    /*
2077
     * read the attributes
2078
     */
2079
591k
    href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
2080
591k
    if (href == NULL) {
2081
106k
  href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
2082
106k
  if (href == NULL)
2083
0
      return(-1);
2084
106k
    }
2085
591k
    parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
2086
591k
    if (parse != NULL) {
2087
2.21k
  if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
2088
494
      xml = 1;
2089
1.71k
  else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
2090
1.71k
      xml = 0;
2091
0
  else {
2092
0
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2093
0
                     XML_XINCLUDE_PARSE_VALUE,
2094
0
         "invalid value %s for 'parse'\n", parse);
2095
0
      if (href != NULL)
2096
0
    xmlFree(href);
2097
0
      if (parse != NULL)
2098
0
    xmlFree(parse);
2099
0
      return(-1);
2100
0
  }
2101
2.21k
    }
2102
2103
    /*
2104
     * compute the URI
2105
     */
2106
591k
    base = xmlNodeGetBase(ctxt->doc, cur);
2107
591k
    if (base == NULL) {
2108
31.9k
  URI = xmlBuildURI(href, ctxt->doc->URL);
2109
559k
    } else {
2110
559k
  URI = xmlBuildURI(href, base);
2111
559k
    }
2112
591k
    if (URI == NULL) {
2113
64.1k
  xmlChar *escbase;
2114
64.1k
  xmlChar *eschref;
2115
  /*
2116
   * Some escaping may be needed
2117
   */
2118
64.1k
  escbase = xmlURIEscape(base);
2119
64.1k
  eschref = xmlURIEscape(href);
2120
64.1k
  URI = xmlBuildURI(eschref, escbase);
2121
64.1k
  if (escbase != NULL)
2122
54.6k
      xmlFree(escbase);
2123
64.1k
  if (eschref != NULL)
2124
64.1k
      xmlFree(eschref);
2125
64.1k
    }
2126
591k
    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
591k
    oldBase = ctxt->base;
2147
591k
    ctxt->base = base;
2148
2149
591k
    if (xml) {
2150
589k
  ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
2151
  /* xmlXIncludeGetFragment(ctxt, cur, URI); */
2152
589k
    } else {
2153
1.71k
  ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
2154
1.71k
    }
2155
2156
    /*
2157
     * Restore the original base before checking for fallback
2158
     */
2159
591k
    ctxt->base = oldBase;
2160
2161
591k
    if (ret < 0) {
2162
519k
  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
519k
  children = cur->children;
2171
659k
  while (children != NULL) {
2172
244k
      if ((children->type == XML_ELEMENT_NODE) &&
2173
244k
    (children->ns != NULL) &&
2174
244k
    (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
2175
244k
    ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
2176
104k
     (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
2177
104k
    ret = xmlXIncludeLoadFallback(ctxt, children, nr);
2178
104k
    break;
2179
104k
      }
2180
139k
      children = children->next;
2181
139k
  }
2182
519k
    }
2183
591k
    if (ret < 0) {
2184
415k
  xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2185
415k
                 XML_XINCLUDE_NO_FALLBACK,
2186
415k
           "could not load %s, and no fallback was found\n",
2187
415k
           URI);
2188
415k
    }
2189
2190
    /*
2191
     * Cleanup
2192
     */
2193
591k
    if (URI != NULL)
2194
591k
  xmlFree(URI);
2195
591k
    if (parse != NULL)
2196
2.21k
  xmlFree(parse);
2197
591k
    if (href != NULL)
2198
591k
  xmlFree(href);
2199
591k
    if (base != NULL)
2200
559k
  xmlFree(base);
2201
591k
    return(0);
2202
591k
}
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
173k
xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
2215
173k
    xmlNodePtr cur, end, list, tmp;
2216
2217
173k
    if (ctxt == NULL)
2218
0
  return(-1);
2219
173k
    if ((nr < 0) || (nr >= ctxt->incNr))
2220
0
  return(-1);
2221
173k
    cur = ctxt->incTab[nr]->ref;
2222
173k
    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
173k
    if ((ctxt->incTab[nr]->inc == NULL) &&
2229
173k
  (ctxt->incTab[nr]->xptr != NULL)) {
2230
53.3k
  ctxt->incTab[nr]->inc =
2231
53.3k
      xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
2232
53.3k
                        ctxt->incTab[nr]->xptr);
2233
53.3k
  xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
2234
53.3k
  ctxt->incTab[nr]->xptr = NULL;
2235
53.3k
    }
2236
173k
    list = ctxt->incTab[nr]->inc;
2237
173k
    ctxt->incTab[nr]->inc = NULL;
2238
173k
    ctxt->incTab[nr]->emptyFb = 0;
2239
2240
    /*
2241
     * Check against the risk of generating a multi-rooted document
2242
     */
2243
173k
    if ((cur->parent != NULL) &&
2244
173k
  (cur->parent->type != XML_ELEMENT_NODE)) {
2245
1.97k
  int nb_elem = 0;
2246
2247
1.97k
  tmp = list;
2248
14.3k
  while (tmp != NULL) {
2249
12.3k
      if (tmp->type == XML_ELEMENT_NODE)
2250
5.61k
    nb_elem++;
2251
12.3k
      tmp = tmp->next;
2252
12.3k
  }
2253
1.97k
  if (nb_elem > 1) {
2254
976
      xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2255
976
                     XML_XINCLUDE_MULTIPLE_ROOT,
2256
976
           "XInclude error: would result in multiple root nodes\n",
2257
976
         NULL);
2258
976
            xmlFreeNodeList(list);
2259
976
      return(-1);
2260
976
  }
2261
1.97k
    }
2262
2263
172k
    if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
2264
  /*
2265
   * Add the list of nodes
2266
   */
2267
506k
  while (list != NULL) {
2268
448k
      end = list;
2269
448k
      list = list->next;
2270
2271
448k
      xmlAddPrevSibling(cur, end);
2272
448k
  }
2273
        /*
2274
         * FIXME: xmlUnlinkNode doesn't coalesce text nodes.
2275
         */
2276
57.4k
  xmlUnlinkNode(cur);
2277
57.4k
  xmlFreeNode(cur);
2278
114k
    } else {
2279
114k
        xmlNodePtr child, next;
2280
2281
  /*
2282
   * Change the current node as an XInclude start one, and add an
2283
   * XInclude end one
2284
   */
2285
114k
        if (ctxt->incTab[nr]->fallback)
2286
60.2k
            xmlUnsetProp(cur, BAD_CAST "href");
2287
114k
  cur->type = XML_XINCLUDE_START;
2288
        /* Remove fallback children */
2289
297k
        for (child = cur->children; child != NULL; child = next) {
2290
182k
            next = child->next;
2291
182k
            xmlUnlinkNode(child);
2292
182k
            xmlFreeNode(child);
2293
182k
        }
2294
114k
  end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
2295
114k
  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
114k
  end->type = XML_XINCLUDE_END;
2303
114k
  xmlAddNextSibling(cur, end);
2304
2305
  /*
2306
   * Add the list of nodes
2307
   */
2308
5.14M
  while (list != NULL) {
2309
5.02M
      cur = list;
2310
5.02M
      list = list->next;
2311
2312
5.02M
      xmlAddPrevSibling(end, cur);
2313
5.02M
  }
2314
114k
    }
2315
2316
2317
172k
    return(0);
2318
172k
}
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
18.0M
xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2331
18.0M
    if (node == NULL)
2332
0
  return(0);
2333
18.0M
    if (node->type != XML_ELEMENT_NODE)
2334
9.47M
  return(0);
2335
8.61M
    if (node->ns == NULL)
2336
6.99M
  return(0);
2337
1.61M
    if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
2338
1.61M
        (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
2339
886k
  if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
2340
848k
      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
284k
          ctxt->legacy = 1;
2347
284k
      }
2348
848k
  }
2349
886k
  if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2350
725k
      xmlNodePtr child = node->children;
2351
725k
      int nb_fallback = 0;
2352
2353
1.18M
      while (child != NULL) {
2354
482k
    if ((child->type == XML_ELEMENT_NODE) &&
2355
482k
        (child->ns != NULL) &&
2356
482k
        ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
2357
162k
         (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
2358
155k
        if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
2359
23.7k
      xmlXIncludeErr(ctxt, node,
2360
23.7k
                     XML_XINCLUDE_INCLUDE_IN_INCLUDE,
2361
23.7k
               "%s has an 'include' child\n",
2362
23.7k
               XINCLUDE_NODE);
2363
23.7k
      return(0);
2364
23.7k
        }
2365
131k
        if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2366
112k
      nb_fallback++;
2367
112k
        }
2368
131k
    }
2369
458k
    child = child->next;
2370
458k
      }
2371
701k
      if (nb_fallback > 1) {
2372
1.31k
    xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
2373
1.31k
             "%s has multiple fallback children\n",
2374
1.31k
                   XINCLUDE_NODE);
2375
1.31k
    return(0);
2376
1.31k
      }
2377
699k
      return(1);
2378
701k
  }
2379
161k
  if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2380
58.1k
      if ((node->parent == NULL) ||
2381
58.1k
    (node->parent->type != XML_ELEMENT_NODE) ||
2382
58.1k
    (node->parent->ns == NULL) ||
2383
58.1k
    ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
2384
44.1k
     (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
2385
58.1k
    (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
2386
50.7k
    xmlXIncludeErr(ctxt, node,
2387
50.7k
                   XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
2388
50.7k
             "%s is not the child of an 'include'\n",
2389
50.7k
             XINCLUDE_FALLBACK);
2390
50.7k
      }
2391
58.1k
  }
2392
161k
    }
2393
894k
    return(0);
2394
1.61M
}
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
440k
                     int skipRoot) {
2411
440k
    xmlNodePtr cur;
2412
440k
    int ret = 0;
2413
440k
    int i, start;
2414
2415
440k
    if ((doc == NULL) || (tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
2416
0
  return(-1);
2417
440k
    if ((skipRoot) && (tree->children == NULL))
2418
0
        return(-1);
2419
440k
    if (ctxt == NULL)
2420
0
  return(-1);
2421
2422
440k
    if (doc->URL != NULL) {
2423
397k
  ret = xmlXIncludeURLPush(ctxt, doc->URL);
2424
397k
  if (ret < 0)
2425
0
      return(-1);
2426
397k
    }
2427
440k
    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
440k
    if (skipRoot)
2450
103k
        cur = tree->children;
2451
337k
    else
2452
337k
        cur = tree;
2453
18.0M
    do {
2454
  /* TODO: need to work on entities -> stack */
2455
18.0M
        if (xmlXIncludeTestNode(ctxt, cur) == 1) {
2456
699k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2457
            /*
2458
             * Avoid superlinear expansion by limiting the total number
2459
             * of replacements.
2460
             */
2461
699k
            if (ctxt->incTotal >= 20)
2462
3.47k
                return(-1);
2463
696k
#endif
2464
696k
            ctxt->incTotal++;
2465
696k
            xmlXIncludePreProcessNode(ctxt, cur);
2466
17.3M
        } else if ((cur->children != NULL) &&
2467
17.3M
                   ((cur->type == XML_DOCUMENT_NODE) ||
2468
4.12M
                    (cur->type == XML_ELEMENT_NODE))) {
2469
4.09M
            cur = cur->children;
2470
4.09M
            continue;
2471
4.09M
        }
2472
18.1M
        do {
2473
18.1M
            if (cur == tree)
2474
437k
                break;
2475
17.7M
            if (cur->next != NULL) {
2476
13.5M
                cur = cur->next;
2477
13.5M
                break;
2478
13.5M
            }
2479
4.18M
            cur = cur->parent;
2480
4.18M
        } while (cur != NULL);
2481
18.0M
    } while ((cur != NULL) && (cur != tree));
2482
2483
    /*
2484
     * Second Phase : collect the infosets fragments
2485
     */
2486
1.02M
    for (i = start;i < ctxt->incNr; i++) {
2487
591k
        xmlXIncludeLoadNode(ctxt, i);
2488
591k
  ret++;
2489
591k
    }
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
1.08M
    for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2503
651k
  if ((ctxt->incTab[i]->inc != NULL) ||
2504
651k
            (ctxt->incTab[i]->xptr != NULL) ||
2505
651k
      (ctxt->incTab[i]->emptyFb != 0))  /* (empty fallback) */
2506
173k
      xmlXIncludeIncludeNode(ctxt, i);
2507
651k
    }
2508
2509
437k
    if (doc->URL != NULL)
2510
392k
  xmlXIncludeURLPop(ctxt);
2511
437k
    return(ret);
2512
440k
}
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
294k
xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
2546
294k
    xmlXIncludeCtxtPtr ctxt;
2547
294k
    int ret = 0;
2548
2549
294k
    if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) ||
2550
294k
        (tree->doc == NULL))
2551
0
        return(-1);
2552
2553
294k
    ctxt = xmlXIncludeNewContext(tree->doc);
2554
294k
    if (ctxt == NULL)
2555
0
        return(-1);
2556
294k
    ctxt->_private = data;
2557
294k
    ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
2558
294k
    xmlXIncludeSetFlags(ctxt, flags);
2559
294k
    ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0);
2560
294k
    if ((ret >= 0) && (ctxt->nbErrors > 0))
2561
153k
        ret = -1;
2562
2563
294k
    xmlXIncludeFreeContext(ctxt);
2564
294k
    return(ret);
2565
294k
}
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
342k
xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) {
2581
342k
    xmlNodePtr tree;
2582
2583
342k
    if (doc == NULL)
2584
21.7k
  return(-1);
2585
320k
    tree = xmlDocGetRootElement(doc);
2586
320k
    if (tree == NULL)
2587
25.8k
  return(-1);
2588
294k
    return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));
2589
320k
}
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
342k
xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
2603
342k
    return xmlXIncludeProcessFlagsData(doc, flags, NULL);
2604
342k
}
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
36.1k
xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2678
36.1k
    int ret = 0;
2679
2680
36.1k
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
2681
36.1k
        (node->doc == NULL) || (ctxt == NULL))
2682
0
  return(-1);
2683
36.1k
    ret = xmlXIncludeDoProcess(ctxt, node->doc, node, 0);
2684
36.1k
    if ((ret >= 0) && (ctxt->nbErrors > 0))
2685
32.8k
  ret = -1;
2686
36.1k
    return(ret);
2687
36.1k
}
2688
2689
#else /* !LIBXML_XINCLUDE_ENABLED */
2690
#endif