Coverage Report

Created: 2025-08-04 07:15

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