Coverage Report

Created: 2023-06-07 06:05

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