Coverage Report

Created: 2024-08-16 12:09

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