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