ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

xinclude.c
Go to the documentation of this file.
00001 /*
00002  * xinclude.c : Code to implement XInclude processing
00003  *
00004  * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003
00005  * http://www.w3.org/TR/2003/WD-xinclude-20031110
00006  *
00007  * See Copyright for the status of this software.
00008  *
00009  * daniel@veillard.com
00010  */
00011 
00012 #define IN_LIBXML
00013 #include "libxml.h"
00014 
00015 #include <string.h>
00016 #include <libxml/xmlmemory.h>
00017 #include <libxml/tree.h>
00018 #include <libxml/parser.h>
00019 #include <libxml/uri.h>
00020 #include <libxml/xpointer.h>
00021 #include <libxml/parserInternals.h>
00022 #include <libxml/xmlerror.h>
00023 #include <libxml/encoding.h>
00024 #include <libxml/globals.h>
00025 
00026 #ifdef LIBXML_XINCLUDE_ENABLED
00027 #include <libxml/xinclude.h>
00028 
00029 
00030 #define XINCLUDE_MAX_DEPTH 40
00031 
00032 /* #define DEBUG_XINCLUDE */
00033 #ifdef DEBUG_XINCLUDE
00034 #ifdef LIBXML_DEBUG_ENABLED
00035 #include <libxml/debugXML.h>
00036 #endif
00037 #endif
00038 
00039 /************************************************************************
00040  *                                  *
00041  *          XInclude context handling           *
00042  *                                  *
00043  ************************************************************************/
00044 
00045 /*
00046  * An XInclude context
00047  */
00048 typedef xmlChar *xmlURL;
00049 
00050 typedef struct _xmlXIncludeRef xmlXIncludeRef;
00051 typedef xmlXIncludeRef *xmlXIncludeRefPtr;
00052 struct _xmlXIncludeRef {
00053     xmlChar              *URI; /* the fully resolved resource URL */
00054     xmlChar         *fragment; /* the fragment in the URI */
00055     xmlDocPtr         doc; /* the parsed document */
00056     xmlNodePtr            ref; /* the node making the reference in the source */
00057     xmlNodePtr            inc; /* the included copy */
00058     int                   xml; /* xml or txt */
00059     int                 count; /* how many refs use that specific doc */
00060     xmlXPathObjectPtr    xptr; /* the xpointer if needed */
00061     int           emptyFb; /* flag to show fallback empty */
00062 };
00063 
00064 struct _xmlXIncludeCtxt {
00065     xmlDocPtr             doc; /* the source document */
00066     int               incBase; /* the first include for this document */
00067     int                 incNr; /* number of includes */
00068     int                incMax; /* size of includes tab */
00069     xmlXIncludeRefPtr *incTab; /* array of included references */
00070 
00071     int                 txtNr; /* number of unparsed documents */
00072     int                txtMax; /* size of unparsed documents tab */
00073     xmlNodePtr        *txtTab; /* array of unparsed text nodes */
00074     xmlURL         *txturlTab; /* array of unparsed text URLs */
00075 
00076     xmlChar *             url; /* the current URL processed */
00077     int                 urlNr; /* number of URLs stacked */
00078     int                urlMax; /* size of URL stack */
00079     xmlChar *         *urlTab; /* URL stack */
00080 
00081     int              nbErrors; /* the number of errors detected */
00082     int                legacy; /* using XINCLUDE_OLD_NS */
00083     int            parseFlags; /* the flags used for parsing XML documents */
00084     xmlChar *        base; /* the current xml:base */
00085 
00086     void            *_private; /* application data */
00087 };
00088 
00089 static int
00090 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree);
00091 
00092 
00093 /************************************************************************
00094  *                                  *
00095  *          XInclude error handler              *
00096  *                                  *
00097  ************************************************************************/
00098 
00105 static void
00106 xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
00107                      const char *extra)
00108 {
00109     if (ctxt != NULL)
00110     ctxt->nbErrors++;
00111     __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
00112                     XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
00113             extra, NULL, NULL, 0, 0,
00114             "Memory allocation failed : %s\n", extra);
00115 }
00116 
00126 static void
00127 xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
00128                const char *msg, const xmlChar *extra)
00129 {
00130     if (ctxt != NULL)
00131     ctxt->nbErrors++;
00132     __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
00133                     error, XML_ERR_ERROR, NULL, 0,
00134             (const char *) extra, NULL, NULL, 0, 0,
00135             msg, (const char *) extra);
00136 }
00137 
00138 #if 0
00139 
00148 static void
00149 xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
00150                const char *msg, const xmlChar *extra)
00151 {
00152     __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
00153                     error, XML_ERR_WARNING, NULL, 0,
00154             (const char *) extra, NULL, NULL, 0, 0,
00155             msg, (const char *) extra);
00156 }
00157 #endif
00158 
00169 static xmlChar *
00170 xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur,
00171                    const xmlChar *name) {
00172     xmlChar *ret;
00173 
00174     ret = xmlGetNsProp(cur, XINCLUDE_NS, name);
00175     if (ret != NULL)
00176         return(ret);
00177     if (ctxt->legacy != 0) {
00178     ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name);
00179     if (ret != NULL)
00180         return(ret);
00181     }
00182     ret = xmlGetProp(cur, name);
00183     return(ret);
00184 }
00191 static void
00192 xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
00193     if (ref == NULL)
00194     return;
00195 #ifdef DEBUG_XINCLUDE
00196     xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
00197 #endif
00198     if (ref->doc != NULL) {
00199 #ifdef DEBUG_XINCLUDE
00200     xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
00201 #endif
00202     xmlFreeDoc(ref->doc);
00203     }
00204     if (ref->URI != NULL)
00205     xmlFree(ref->URI);
00206     if (ref->fragment != NULL)
00207     xmlFree(ref->fragment);
00208     if (ref->xptr != NULL)
00209     xmlXPathFreeObject(ref->xptr);
00210     xmlFree(ref);
00211 }
00212 
00222 static xmlXIncludeRefPtr
00223 xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
00224               xmlNodePtr ref) {
00225     xmlXIncludeRefPtr ret;
00226 
00227 #ifdef DEBUG_XINCLUDE
00228     xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
00229 #endif
00230     ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
00231     if (ret == NULL) {
00232         xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
00233     return(NULL);
00234     }
00235     memset(ret, 0, sizeof(xmlXIncludeRef));
00236     if (URI == NULL)
00237     ret->URI = NULL;
00238     else
00239     ret->URI = xmlStrdup(URI);
00240     ret->fragment = NULL;
00241     ret->ref = ref;
00242     ret->doc = NULL;
00243     ret->count = 0;
00244     ret->xml = 0;
00245     ret->inc = NULL;
00246     if (ctxt->incMax == 0) {
00247     ctxt->incMax = 4;
00248         ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
00249                           sizeof(ctxt->incTab[0]));
00250         if (ctxt->incTab == NULL) {
00251         xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
00252         xmlXIncludeFreeRef(ret);
00253         return(NULL);
00254     }
00255     }
00256     if (ctxt->incNr >= ctxt->incMax) {
00257     ctxt->incMax *= 2;
00258         ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
00259                  ctxt->incMax * sizeof(ctxt->incTab[0]));
00260         if (ctxt->incTab == NULL) {
00261         xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
00262         xmlXIncludeFreeRef(ret);
00263         return(NULL);
00264     }
00265     }
00266     ctxt->incTab[ctxt->incNr++] = ret;
00267     return(ret);
00268 }
00269 
00278 xmlXIncludeCtxtPtr
00279 xmlXIncludeNewContext(xmlDocPtr doc) {
00280     xmlXIncludeCtxtPtr ret;
00281 
00282 #ifdef DEBUG_XINCLUDE
00283     xmlGenericError(xmlGenericErrorContext, "New context\n");
00284 #endif
00285     if (doc == NULL)
00286     return(NULL);
00287     ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
00288     if (ret == NULL) {
00289     xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
00290                          "creating XInclude context");
00291     return(NULL);
00292     }
00293     memset(ret, 0, sizeof(xmlXIncludeCtxt));
00294     ret->doc = doc;
00295     ret->incNr = 0;
00296     ret->incBase = 0;
00297     ret->incMax = 0;
00298     ret->incTab = NULL;
00299     ret->nbErrors = 0;
00300     return(ret);
00301 }
00302 
00312 static int
00313 xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
00314                const xmlChar *value)
00315 {
00316     if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
00317     xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION,
00318                    "detected a recursion in %s\n", value);
00319     return(-1);
00320     }
00321     if (ctxt->urlTab == NULL) {
00322     ctxt->urlMax = 4;
00323     ctxt->urlNr = 0;
00324     ctxt->urlTab = (xmlChar * *) xmlMalloc(
00325                 ctxt->urlMax * sizeof(ctxt->urlTab[0]));
00326         if (ctxt->urlTab == NULL) {
00327         xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
00328             return (-1);
00329         }
00330     }
00331     if (ctxt->urlNr >= ctxt->urlMax) {
00332         ctxt->urlMax *= 2;
00333         ctxt->urlTab =
00334             (xmlChar * *) xmlRealloc(ctxt->urlTab,
00335                                       ctxt->urlMax *
00336                                       sizeof(ctxt->urlTab[0]));
00337         if (ctxt->urlTab == NULL) {
00338         xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
00339             return (-1);
00340         }
00341     }
00342     ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
00343     return (ctxt->urlNr++);
00344 }
00345 
00352 static void
00353 xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
00354 {
00355     xmlChar * ret;
00356 
00357     if (ctxt->urlNr <= 0)
00358         return;
00359     ctxt->urlNr--;
00360     if (ctxt->urlNr > 0)
00361         ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
00362     else
00363         ctxt->url = NULL;
00364     ret = ctxt->urlTab[ctxt->urlNr];
00365     ctxt->urlTab[ctxt->urlNr] = NULL;
00366     if (ret != NULL)
00367     xmlFree(ret);
00368 }
00369 
00376 void
00377 xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
00378     int i;
00379 
00380 #ifdef DEBUG_XINCLUDE
00381     xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
00382 #endif
00383     if (ctxt == NULL)
00384     return;
00385     while (ctxt->urlNr > 0)
00386     xmlXIncludeURLPop(ctxt);
00387     if (ctxt->urlTab != NULL)
00388     xmlFree(ctxt->urlTab);
00389     for (i = 0;i < ctxt->incNr;i++) {
00390     if (ctxt->incTab[i] != NULL)
00391         xmlXIncludeFreeRef(ctxt->incTab[i]);
00392     }
00393     if (ctxt->txturlTab != NULL) {
00394     for (i = 0;i < ctxt->txtNr;i++) {
00395         if (ctxt->txturlTab[i] != NULL)
00396         xmlFree(ctxt->txturlTab[i]);
00397     }
00398     }
00399     if (ctxt->incTab != NULL)
00400     xmlFree(ctxt->incTab);
00401     if (ctxt->txtTab != NULL)
00402     xmlFree(ctxt->txtTab);
00403     if (ctxt->txturlTab != NULL)
00404     xmlFree(ctxt->txturlTab);
00405     if (ctxt->base != NULL) {
00406         xmlFree(ctxt->base);
00407     }
00408     xmlFree(ctxt);
00409 }
00410 
00418 static xmlDocPtr
00419 xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
00420     xmlDocPtr ret;
00421     xmlParserCtxtPtr pctxt;
00422     xmlParserInputPtr inputStream;
00423 
00424     xmlInitParser();
00425 
00426     pctxt = xmlNewParserCtxt();
00427     if (pctxt == NULL) {
00428     xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context");
00429     return(NULL);
00430     }
00431 
00432     /*
00433      * pass in the application data to the parser context.
00434      */
00435     pctxt->_private = ctxt->_private;
00436     
00437     /*
00438      * try to ensure that new documents included are actually
00439      * built with the same dictionary as the including document.
00440      */
00441     if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL)) {
00442        if (pctxt->dict != NULL)
00443             xmlDictFree(pctxt->dict);
00444     pctxt->dict = ctxt->doc->dict;
00445     xmlDictReference(pctxt->dict);
00446     }
00447 
00448     xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
00449     
00450     inputStream = xmlLoadExternalEntity(URL, NULL, pctxt);
00451     if (inputStream == NULL) {
00452     xmlFreeParserCtxt(pctxt);
00453     return(NULL);
00454     }
00455 
00456     inputPush(pctxt, inputStream);
00457 
00458     if (pctxt->directory == NULL)
00459         pctxt->directory = xmlParserGetDirectory(URL);
00460 
00461     pctxt->loadsubset |= XML_DETECT_IDS;
00462 
00463     xmlParseDocument(pctxt);
00464 
00465     if (pctxt->wellFormed) {
00466         ret = pctxt->myDoc;
00467     }
00468     else {
00469         ret = NULL;
00470     if (pctxt->myDoc != NULL)
00471         xmlFreeDoc(pctxt->myDoc);
00472         pctxt->myDoc = NULL;
00473     }
00474     xmlFreeParserCtxt(pctxt);
00475     
00476     return(ret);
00477 }
00478 
00486 static int
00487 xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
00488     xmlXIncludeRefPtr ref;
00489     xmlURIPtr uri;
00490     xmlChar *URL;
00491     xmlChar *fragment = NULL;
00492     xmlChar *href;
00493     xmlChar *parse;
00494     xmlChar *base;
00495     xmlChar *URI;
00496     int xml = 1, i; /* default Issue 64 */
00497     int local = 0;
00498 
00499 
00500     if (ctxt == NULL)
00501     return(-1);
00502     if (cur == NULL)
00503     return(-1);
00504 
00505 #ifdef DEBUG_XINCLUDE
00506     xmlGenericError(xmlGenericErrorContext, "Add node\n");
00507 #endif
00508     /*
00509      * read the attributes
00510      */
00511     href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
00512     if (href == NULL) {
00513     href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
00514     if (href == NULL) 
00515         return(-1);
00516     }
00517     if ((href[0] == '#') || (href[0] == 0))
00518     local = 1;
00519     parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
00520     if (parse != NULL) {
00521     if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
00522         xml = 1;
00523     else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
00524         xml = 0;
00525     else {
00526         xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
00527                        "invalid value %s for 'parse'\n", parse);
00528         if (href != NULL)
00529         xmlFree(href);
00530         if (parse != NULL)
00531         xmlFree(parse);
00532         return(-1);
00533     }
00534     }
00535 
00536     /*
00537      * compute the URI
00538      */
00539     base = xmlNodeGetBase(ctxt->doc, cur);
00540     if (base == NULL) {
00541     URI = xmlBuildURI(href, ctxt->doc->URL);
00542     } else {
00543     URI = xmlBuildURI(href, base);
00544     }
00545     if (URI == NULL) {
00546     xmlChar *escbase;
00547     xmlChar *eschref;
00548     /*
00549      * Some escaping may be needed
00550      */
00551     escbase = xmlURIEscape(base);
00552     eschref = xmlURIEscape(href);
00553     URI = xmlBuildURI(eschref, escbase);
00554     if (escbase != NULL)
00555         xmlFree(escbase);
00556     if (eschref != NULL)
00557         xmlFree(eschref);
00558     }
00559     if (parse != NULL)
00560     xmlFree(parse);
00561     if (href != NULL)
00562     xmlFree(href);
00563     if (base != NULL)
00564     xmlFree(base);
00565     if (URI == NULL) {
00566     xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
00567                    "failed build URL\n", NULL);
00568     return(-1);
00569     }
00570     fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
00571 
00572     /*
00573      * Check the URL and remove any fragment identifier
00574      */
00575     uri = xmlParseURI((const char *)URI);
00576     if (uri == NULL) {
00577     xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
00578                    "invalid value URI %s\n", URI);
00579     if (fragment != NULL)
00580         xmlFree(fragment);
00581     xmlFree(URI);
00582     return(-1);
00583     }
00584 
00585     if (uri->fragment != NULL) {
00586         if (ctxt->legacy != 0) {
00587         if (fragment == NULL) {
00588         fragment = (xmlChar *) uri->fragment;
00589         } else {
00590         xmlFree(uri->fragment);
00591         }
00592     } else {
00593         xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID,
00594        "Invalid fragment identifier in URI %s use the xpointer attribute\n",
00595                            URI);
00596         if (fragment != NULL)
00597             xmlFree(fragment);
00598         xmlFreeURI(uri);
00599         xmlFree(URI);
00600         return(-1);
00601     }
00602     uri->fragment = NULL;
00603     }
00604     URL = xmlSaveUri(uri);
00605     xmlFreeURI(uri);
00606     xmlFree(URI);
00607     if (URL == NULL) {
00608     xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
00609                    "invalid value URI %s\n", URI);
00610     if (fragment != NULL)
00611         xmlFree(fragment);
00612     return(-1);
00613     }
00614 
00615     /*
00616      * If local and xml then we need a fragment
00617      */
00618     if ((local == 1) && (xml == 1) &&
00619         ((fragment == NULL) || (fragment[0] == 0))) {
00620     xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
00621                    "detected a local recursion with no xpointer in %s\n",
00622                URL);
00623     if (fragment != NULL)
00624         xmlFree(fragment);
00625     return(-1);
00626     }
00627 
00628     /*
00629      * Check the URL against the stack for recursions
00630      */
00631     if ((!local) && (xml == 1)) {
00632     for (i = 0;i < ctxt->urlNr;i++) {
00633         if (xmlStrEqual(URL, ctxt->urlTab[i])) {
00634         xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
00635                        "detected a recursion in %s\n", URL);
00636         return(-1);
00637         }
00638     }
00639     }
00640 
00641     ref = xmlXIncludeNewRef(ctxt, URL, cur);
00642     if (ref == NULL) {
00643     return(-1);
00644     }
00645     ref->fragment = fragment;
00646     ref->doc = NULL;
00647     ref->xml = xml;
00648     ref->count = 1;
00649     xmlFree(URL);
00650     return(0);
00651 }
00652 
00661 static void
00662 xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
00663                   const xmlURL url ATTRIBUTE_UNUSED) {
00664     xmlXIncludeCtxtPtr newctxt;
00665     int i;
00666 
00667     /*
00668      * Avoid recursion in already substitued resources
00669     for (i = 0;i < ctxt->urlNr;i++) {
00670     if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
00671         return;
00672     }
00673      */
00674 
00675 #ifdef DEBUG_XINCLUDE
00676     xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
00677 #endif
00678     /*
00679      * Handle recursion here.
00680      */
00681 
00682     newctxt = xmlXIncludeNewContext(doc);
00683     if (newctxt != NULL) {
00684     /*
00685      * Copy the private user data
00686      */
00687     newctxt->_private = ctxt->_private; 
00688     /*
00689      * Copy the existing document set
00690      */
00691     newctxt->incMax = ctxt->incMax;
00692     newctxt->incNr = ctxt->incNr;
00693         newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
00694                                   sizeof(newctxt->incTab[0]));
00695         if (newctxt->incTab == NULL) {
00696         xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
00697         xmlFree(newctxt);
00698         return;
00699     }
00700     /*
00701      * copy the urlTab
00702      */
00703     newctxt->urlMax = ctxt->urlMax;
00704     newctxt->urlNr = ctxt->urlNr;
00705     newctxt->urlTab = ctxt->urlTab;
00706 
00707     /*
00708      * Inherit the existing base
00709      */
00710     newctxt->base = xmlStrdup(ctxt->base);
00711 
00712     /*
00713      * Inherit the documents already in use by other includes
00714      */
00715     newctxt->incBase = ctxt->incNr;
00716     for (i = 0;i < ctxt->incNr;i++) {
00717         newctxt->incTab[i] = ctxt->incTab[i];
00718         newctxt->incTab[i]->count++; /* prevent the recursion from
00719                         freeing it */
00720     }
00721     /*
00722      * The new context should also inherit the Parse Flags
00723      * (bug 132597)
00724      */
00725     newctxt->parseFlags = ctxt->parseFlags;
00726     xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc));
00727     for (i = 0;i < ctxt->incNr;i++) {
00728         newctxt->incTab[i]->count--;
00729         newctxt->incTab[i] = NULL;
00730     }
00731 
00732     /* urlTab may have been reallocated */
00733     ctxt->urlTab = newctxt->urlTab;
00734     ctxt->urlMax = newctxt->urlMax;
00735 
00736     newctxt->urlMax = 0;
00737     newctxt->urlNr = 0;
00738     newctxt->urlTab = NULL;
00739 
00740     xmlXIncludeFreeContext(newctxt);
00741     }
00742 #ifdef DEBUG_XINCLUDE
00743     xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
00744 #endif
00745 }
00746 
00755 static void
00756 xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
00757 #ifdef DEBUG_XINCLUDE
00758     xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
00759 #endif
00760     if (ctxt->txtMax == 0) {
00761     ctxt->txtMax = 4;
00762         ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
00763                                   sizeof(ctxt->txtTab[0]));
00764         if (ctxt->txtTab == NULL) {
00765         xmlXIncludeErrMemory(ctxt, NULL, "processing text");
00766         return;
00767     }
00768         ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
00769                                   sizeof(ctxt->txturlTab[0]));
00770         if (ctxt->txturlTab == NULL) {
00771         xmlXIncludeErrMemory(ctxt, NULL, "processing text");
00772         return;
00773     }
00774     }
00775     if (ctxt->txtNr >= ctxt->txtMax) {
00776     ctxt->txtMax *= 2;
00777         ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
00778                  ctxt->txtMax * sizeof(ctxt->txtTab[0]));
00779         if (ctxt->txtTab == NULL) {
00780         xmlXIncludeErrMemory(ctxt, NULL, "processing text");
00781         return;
00782     }
00783         ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
00784                  ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
00785         if (ctxt->txturlTab == NULL) {
00786         xmlXIncludeErrMemory(ctxt, NULL, "processing text");
00787         return;
00788     }
00789     }
00790     ctxt->txtTab[ctxt->txtNr] = txt;
00791     ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
00792     ctxt->txtNr++;
00793 }
00794 
00795 /************************************************************************
00796  *                                  *
00797  *          Node copy with specific semantic        *
00798  *                                  *
00799  ************************************************************************/
00800 
00801 static xmlNodePtr
00802 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
00803                     xmlDocPtr source, xmlNodePtr elem);
00804 
00815 static xmlNodePtr
00816 xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
00817                 xmlDocPtr source, xmlNodePtr elem) {
00818     xmlNodePtr result = NULL;
00819 
00820     if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
00821     (elem == NULL))
00822     return(NULL);
00823     if (elem->type == XML_DTD_NODE)
00824     return(NULL);
00825     if (elem->type == XML_DOCUMENT_NODE)
00826     result = xmlXIncludeCopyNodeList(ctxt, target, source, elem->children);
00827     else
00828         result = xmlDocCopyNode(elem, target, 1);
00829     return(result);
00830 }
00831 
00842 static xmlNodePtr
00843 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
00844                     xmlDocPtr source, xmlNodePtr elem) {
00845     xmlNodePtr cur, res, result = NULL, last = NULL;
00846 
00847     if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
00848     (elem == NULL))
00849     return(NULL);
00850     cur = elem;
00851     while (cur != NULL) {
00852     res = xmlXIncludeCopyNode(ctxt, target, source, cur);
00853     if (res != NULL) {
00854         if (result == NULL) {
00855         result = last = res;
00856         } else {
00857         last->next = res;
00858         res->prev = last;
00859         last = res;
00860         }
00861     }
00862     cur = cur->next;
00863     }
00864     return(result);
00865 }
00866 
00874 static xmlNodePtr
00875 xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
00876     int i;
00877     if (cur == NULL) 
00878     return(cur);
00879     cur = cur->children;
00880     for (i = 0;i <= no;cur = cur->next) {
00881     if (cur == NULL) 
00882         return(cur);
00883     if ((cur->type == XML_ELEMENT_NODE) ||
00884         (cur->type == XML_DOCUMENT_NODE) ||
00885         (cur->type == XML_HTML_DOCUMENT_NODE)) {
00886         i++;
00887         if (i == no)
00888         break;
00889     }
00890     }
00891     return(cur);
00892 }
00893 
00894 xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */
00907 static xmlNodePtr
00908 xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
00909                     xmlDocPtr source, xmlXPathObjectPtr range) {
00910     /* pointers to generated nodes */
00911     xmlNodePtr list = NULL, last = NULL, listParent = NULL;
00912     xmlNodePtr tmp, tmp2;
00913     /* pointers to traversal nodes */
00914     xmlNodePtr start, cur, end;
00915     int index1, index2;
00916     int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0;
00917 
00918     if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
00919     (range == NULL))
00920     return(NULL);
00921     if (range->type != XPATH_RANGE)
00922     return(NULL);
00923     start = (xmlNodePtr) range->user;
00924 
00925     if (start == NULL)
00926     return(NULL);
00927     end = range->user2;
00928     if (end == NULL)
00929     return(xmlDocCopyNode(start, target, 1));
00930 
00931     cur = start;
00932     index1 = range->index;
00933     index2 = range->index2;
00934     /*
00935      * level is depth of the current node under consideration
00936      * list is the pointer to the root of the output tree
00937      * listParent is a pointer to the parent of output tree (within
00938        the included file) in case we need to add another level
00939      * last is a pointer to the last node added to the output tree
00940      * lastLevel is the depth of last (relative to the root)
00941      */
00942     while (cur != NULL) {
00943     /*
00944      * Check if our output tree needs a parent
00945      */
00946     if (level < 0) {
00947         while (level < 0) {
00948             /* copy must include namespaces and properties */
00949             tmp2 = xmlDocCopyNode(listParent, target, 2);
00950             xmlAddChild(tmp2, list);
00951             list = tmp2;
00952             listParent = listParent->parent;
00953             level++;
00954         }
00955         last = list;
00956         lastLevel = 0;
00957     }
00958     /*
00959      * Check whether we need to change our insertion point
00960      */
00961     while (level < lastLevel) {
00962         last = last->parent;
00963         lastLevel --;
00964     }
00965     if (cur == end) {   /* Are we at the end of the range? */
00966         if (cur->type == XML_TEXT_NODE) {
00967         const xmlChar *content = cur->content;
00968         int len;
00969 
00970         if (content == NULL) {
00971             tmp = xmlNewTextLen(NULL, 0);
00972         } else {
00973             len = index2;
00974             if ((cur == start) && (index1 > 1)) {
00975             content += (index1 - 1);
00976             len -= (index1 - 1);
00977             } else {
00978             len = index2;
00979             }
00980             tmp = xmlNewTextLen(content, len);
00981         }
00982         /* single sub text node selection */
00983         if (list == NULL)
00984             return(tmp);
00985         /* prune and return full set */
00986         if (level == lastLevel)
00987             xmlAddNextSibling(last, tmp);
00988         else 
00989             xmlAddChild(last, tmp);
00990         return(list);
00991         } else {    /* ending node not a text node */
00992             endLevel = level;   /* remember the level of the end node */
00993         endFlag = 1;
00994         /* last node - need to take care of properties + namespaces */
00995         tmp = xmlDocCopyNode(cur, target, 2);
00996         if (list == NULL) {
00997             list = tmp;
00998             listParent = cur->parent;
00999         } else {
01000             if (level == lastLevel)
01001             xmlAddNextSibling(last, tmp);
01002             else {
01003             xmlAddChild(last, tmp);
01004             lastLevel = level;
01005             }
01006         }
01007         last = tmp;
01008 
01009         if (index2 > 1) {
01010             end = xmlXIncludeGetNthChild(cur, index2 - 1);
01011             index2 = 0;
01012         }
01013         if ((cur == start) && (index1 > 1)) {
01014             cur = xmlXIncludeGetNthChild(cur, index1 - 1);
01015             index1 = 0;
01016         }  else {
01017             cur = cur->children;
01018         }
01019         level++;    /* increment level to show change */
01020         /*
01021          * Now gather the remaining nodes from cur to end
01022          */
01023         continue;   /* while */
01024         }
01025     } else if (cur == start) {  /* Not at the end, are we at start? */
01026         if ((cur->type == XML_TEXT_NODE) ||
01027         (cur->type == XML_CDATA_SECTION_NODE)) {
01028         const xmlChar *content = cur->content;
01029 
01030         if (content == NULL) {
01031             tmp = xmlNewTextLen(NULL, 0);
01032         } else {
01033             if (index1 > 1) {
01034             content += (index1 - 1);
01035             index1 = 0;
01036             }
01037             tmp = xmlNewText(content);
01038         }
01039         last = list = tmp;
01040         listParent = cur->parent;
01041         } else {        /* Not text node */
01042             /*
01043          * start of the range - need to take care of
01044          * properties and namespaces
01045          */
01046         tmp = xmlDocCopyNode(cur, target, 2);
01047         list = last = tmp;
01048         listParent = cur->parent;
01049         if (index1 > 1) {   /* Do we need to position? */
01050             cur = xmlXIncludeGetNthChild(cur, index1 - 1);
01051             level = lastLevel = 1;
01052             index1 = 0;
01053             /*
01054              * Now gather the remaining nodes from cur to end
01055              */
01056             continue; /* while */
01057         }
01058         }
01059     } else {
01060         tmp = NULL;
01061         switch (cur->type) {
01062         case XML_DTD_NODE:
01063         case XML_ELEMENT_DECL:
01064         case XML_ATTRIBUTE_DECL:
01065         case XML_ENTITY_NODE:
01066             /* Do not copy DTD informations */
01067             break;
01068         case XML_ENTITY_DECL:
01069             /* handle crossing entities -> stack needed */
01070             break;
01071         case XML_XINCLUDE_START:
01072         case XML_XINCLUDE_END:
01073             /* don't consider it part of the tree content */
01074             break;
01075         case XML_ATTRIBUTE_NODE:
01076             /* Humm, should not happen ! */
01077             break;
01078         default:
01079             /*
01080              * Middle of the range - need to take care of
01081              * properties and namespaces
01082              */
01083             tmp = xmlDocCopyNode(cur, target, 2);
01084             break;
01085         }
01086         if (tmp != NULL) {
01087         if (level == lastLevel)
01088             xmlAddNextSibling(last, tmp);
01089         else {
01090             xmlAddChild(last, tmp);
01091             lastLevel = level;
01092         }
01093         last = tmp;
01094         }
01095     }
01096     /*
01097      * Skip to next node in document order
01098      */
01099     cur = xmlXPtrAdvanceNode(cur, &level);
01100     if (endFlag && (level >= endLevel))
01101         break;
01102     }
01103     return(list);
01104 }
01105 
01119 static xmlNodePtr
01120 xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
01121                     xmlDocPtr source, xmlXPathObjectPtr obj) {
01122     xmlNodePtr list = NULL, last = NULL;
01123     int i;
01124 
01125     if (source == NULL)
01126     source = ctxt->doc;
01127     if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
01128     (obj == NULL))
01129     return(NULL);
01130     switch (obj->type) {
01131         case XPATH_NODESET: {
01132         xmlNodeSetPtr set = obj->nodesetval;
01133         if (set == NULL)
01134         return(NULL);
01135         for (i = 0;i < set->nodeNr;i++) {
01136         if (set->nodeTab[i] == NULL)
01137             continue;
01138         switch (set->nodeTab[i]->type) {
01139             case XML_TEXT_NODE:
01140             case XML_CDATA_SECTION_NODE:
01141             case XML_ELEMENT_NODE:
01142             case XML_ENTITY_REF_NODE:
01143             case XML_ENTITY_NODE:
01144             case XML_PI_NODE:
01145             case XML_COMMENT_NODE:
01146             case XML_DOCUMENT_NODE:
01147             case XML_HTML_DOCUMENT_NODE:
01148 #ifdef LIBXML_DOCB_ENABLED
01149             case XML_DOCB_DOCUMENT_NODE:
01150 #endif
01151             case XML_XINCLUDE_END:
01152             break;
01153             case XML_XINCLUDE_START: {
01154                     xmlNodePtr tmp, cur = set->nodeTab[i];
01155 
01156             cur = cur->next;
01157             while (cur != NULL) {
01158                 switch(cur->type) {
01159                 case XML_TEXT_NODE:
01160                 case XML_CDATA_SECTION_NODE:
01161                 case XML_ELEMENT_NODE:
01162                 case XML_ENTITY_REF_NODE:
01163                 case XML_ENTITY_NODE:
01164                 case XML_PI_NODE:
01165                 case XML_COMMENT_NODE:
01166                     tmp = xmlXIncludeCopyNode(ctxt, target,
01167                                   source, cur);
01168                     if (last == NULL) {
01169                     list = last = tmp;
01170                     } else {
01171                     xmlAddNextSibling(last, tmp);
01172                     last = tmp;
01173                     }
01174                     cur = cur->next;
01175                     continue;
01176                 default:
01177                     break;
01178                 }
01179                 break;
01180             }
01181             continue;
01182             }
01183             case XML_ATTRIBUTE_NODE:
01184             case XML_NAMESPACE_DECL:
01185             case XML_DOCUMENT_TYPE_NODE:
01186             case XML_DOCUMENT_FRAG_NODE:
01187             case XML_NOTATION_NODE:
01188             case XML_DTD_NODE:
01189             case XML_ELEMENT_DECL:
01190             case XML_ATTRIBUTE_DECL:
01191             case XML_ENTITY_DECL:
01192             continue; /* for */
01193         }
01194         if (last == NULL)
01195             list = last = xmlXIncludeCopyNode(ctxt, target, source,
01196                                           set->nodeTab[i]);
01197         else {
01198             xmlAddNextSibling(last,
01199                 xmlXIncludeCopyNode(ctxt, target, source,
01200                                 set->nodeTab[i]));
01201             if (last->next != NULL)
01202             last = last->next;
01203         }
01204         }
01205         break;
01206     }
01207     case XPATH_LOCATIONSET: {
01208         xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
01209         if (set == NULL)
01210         return(NULL);
01211         for (i = 0;i < set->locNr;i++) {
01212         if (last == NULL)
01213             list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
01214                                               set->locTab[i]);
01215         else
01216             xmlAddNextSibling(last,
01217                 xmlXIncludeCopyXPointer(ctxt, target, source,
01218                                     set->locTab[i]));
01219         if (last != NULL) {
01220             while (last->next != NULL)
01221             last = last->next;
01222         }
01223         }
01224         break;
01225     }
01226 #ifdef LIBXML_XPTR_ENABLED
01227     case XPATH_RANGE:
01228         return(xmlXIncludeCopyRange(ctxt, target, source, obj));
01229 #endif
01230     case XPATH_POINT:
01231         /* points are ignored in XInclude */
01232         break;
01233     default:
01234         break;
01235     }
01236     return(list);
01237 }
01238 /************************************************************************
01239  *                                  *
01240  *          XInclude I/O handling               *
01241  *                                  *
01242  ************************************************************************/
01243 
01244 typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
01245 typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
01246 struct _xmlXIncludeMergeData {
01247     xmlDocPtr doc;
01248     xmlXIncludeCtxtPtr ctxt;
01249 };
01250 
01259 static void
01260 xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
01261                    xmlChar *name ATTRIBUTE_UNUSED) {
01262     xmlEntityPtr ret, prev;
01263     xmlDocPtr doc;
01264     xmlXIncludeCtxtPtr ctxt;
01265 
01266     if ((ent == NULL) || (data == NULL))
01267     return;
01268     ctxt = data->ctxt;
01269     doc = data->doc;
01270     if ((ctxt == NULL) || (doc == NULL))
01271     return;
01272     switch (ent->etype) {
01273         case XML_INTERNAL_PARAMETER_ENTITY:
01274         case XML_EXTERNAL_PARAMETER_ENTITY:
01275         case XML_INTERNAL_PREDEFINED_ENTITY:
01276         return;
01277         case XML_INTERNAL_GENERAL_ENTITY:
01278         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
01279         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
01280         break;
01281     }
01282     ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
01283               ent->SystemID, ent->content);
01284     if (ret != NULL) {
01285     if (ent->URI != NULL)
01286         ret->URI = xmlStrdup(ent->URI);
01287     } else {
01288     prev = xmlGetDocEntity(doc, ent->name);
01289     if (prev != NULL) {
01290         if (ent->etype != prev->etype)
01291         goto error;
01292     
01293         if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
01294         if (!xmlStrEqual(ent->SystemID, prev->SystemID))
01295             goto error;
01296         } else if ((ent->ExternalID != NULL) &&
01297                (prev->ExternalID != NULL)) {
01298         if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
01299             goto error;
01300         } else if ((ent->content != NULL) && (prev->content != NULL)) {
01301         if (!xmlStrEqual(ent->content, prev->content))
01302             goto error;
01303         } else {
01304         goto error;
01305         }
01306 
01307     }
01308     }
01309     return;
01310 error:
01311     switch (ent->etype) {
01312         case XML_INTERNAL_PARAMETER_ENTITY:
01313         case XML_EXTERNAL_PARAMETER_ENTITY:
01314         case XML_INTERNAL_PREDEFINED_ENTITY:
01315         case XML_INTERNAL_GENERAL_ENTITY:
01316         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
01317         return;
01318         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
01319         break;
01320     }
01321     xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
01322                    "mismatch in redefinition of entity %s\n",
01323            ent->name);
01324 }
01325 
01336 static int
01337 xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
01338                      xmlDocPtr from) {
01339     xmlNodePtr cur;
01340     xmlDtdPtr target, source;
01341 
01342     if (ctxt == NULL)
01343     return(-1);
01344 
01345     if ((from == NULL) || (from->intSubset == NULL))
01346     return(0);
01347 
01348     target = doc->intSubset;
01349     if (target == NULL) {
01350     cur = xmlDocGetRootElement(doc);
01351     if (cur == NULL)
01352         return(-1);
01353         target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
01354     if (target == NULL)
01355         return(-1);
01356     }
01357 
01358     source = from->intSubset;
01359     if ((source != NULL) && (source->entities != NULL)) {
01360     xmlXIncludeMergeData data;
01361 
01362     data.ctxt = ctxt;
01363     data.doc = doc;
01364 
01365     xmlHashScan((xmlHashTablePtr) source->entities,
01366             (xmlHashScanner) xmlXIncludeMergeEntity, &data);
01367     }
01368     source = from->extSubset;
01369     if ((source != NULL) && (source->entities != NULL)) {
01370     xmlXIncludeMergeData data;
01371 
01372     data.ctxt = ctxt;
01373     data.doc = doc;
01374 
01375     /*
01376      * don't duplicate existing stuff when external subsets are the same
01377      */
01378     if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
01379         (!xmlStrEqual(target->SystemID, source->SystemID))) {
01380         xmlHashScan((xmlHashTablePtr) source->entities,
01381             (xmlHashScanner) xmlXIncludeMergeEntity, &data);
01382     }
01383     }
01384     return(0);
01385 }
01386 
01397 static int
01398 xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
01399     xmlDocPtr doc;
01400     xmlURIPtr uri;
01401     xmlChar *URL;
01402     xmlChar *fragment = NULL;
01403     int i = 0;
01404 #ifdef LIBXML_XPTR_ENABLED
01405     int saveFlags;
01406 #endif
01407 
01408 #ifdef DEBUG_XINCLUDE
01409     xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
01410 #endif
01411     /*
01412      * Check the URL and remove any fragment identifier
01413      */
01414     uri = xmlParseURI((const char *)url);
01415     if (uri == NULL) {
01416     xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
01417                    XML_XINCLUDE_HREF_URI,
01418                "invalid value URI %s\n", url);
01419     return(-1);
01420     }
01421     if (uri->fragment != NULL) {
01422     fragment = (xmlChar *) uri->fragment;
01423     uri->fragment = NULL;
01424     }
01425     if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
01426         (ctxt->incTab[nr]->fragment != NULL)) {
01427     if (fragment != NULL) xmlFree(fragment);
01428     fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
01429     }
01430     URL = xmlSaveUri(uri);
01431     xmlFreeURI(uri);
01432     if (URL == NULL) {
01433         if (ctxt->incTab != NULL)
01434         xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
01435                XML_XINCLUDE_HREF_URI,
01436                "invalid value URI %s\n", url);
01437     else
01438         xmlXIncludeErr(ctxt, NULL,
01439                XML_XINCLUDE_HREF_URI,
01440                "invalid value URI %s\n", url);
01441     if (fragment != NULL)
01442         xmlFree(fragment);
01443     return(-1);
01444     }
01445 
01446     /*
01447      * Handling of references to the local document are done
01448      * directly through ctxt->doc.
01449      */
01450     if ((URL[0] == 0) || (URL[0] == '#') ||
01451     ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
01452     doc = NULL;
01453         goto loaded;
01454     }
01455 
01456     /*
01457      * Prevent reloading twice the document.
01458      */
01459     for (i = 0; i < ctxt->incNr; i++) {
01460     if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
01461         (ctxt->incTab[i]->doc != NULL)) {
01462         doc = ctxt->incTab[i]->doc;
01463 #ifdef DEBUG_XINCLUDE
01464         printf("Already loaded %s\n", URL);
01465 #endif
01466         goto loaded;
01467     }
01468     }
01469 
01470     /*
01471      * Load it.
01472      */
01473 #ifdef DEBUG_XINCLUDE
01474     printf("loading %s\n", URL);
01475 #endif
01476 #ifdef LIBXML_XPTR_ENABLED
01477     /*
01478      * If this is an XPointer evaluation, we want to assure that
01479      * all entities have been resolved prior to processing the
01480      * referenced document
01481      */
01482     saveFlags = ctxt->parseFlags;
01483     if (fragment != NULL) { /* if this is an XPointer eval */
01484     ctxt->parseFlags |= XML_PARSE_NOENT;
01485     }
01486 #endif
01487 
01488     doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
01489 #ifdef LIBXML_XPTR_ENABLED
01490     ctxt->parseFlags = saveFlags;
01491 #endif
01492     if (doc == NULL) {
01493     xmlFree(URL);
01494     if (fragment != NULL)
01495         xmlFree(fragment);
01496     return(-1);
01497     }
01498     ctxt->incTab[nr]->doc = doc;
01499     /*
01500      * It's possible that the requested URL has been mapped to a
01501      * completely different location (e.g. through a catalog entry).
01502      * To check for this, we compare the URL with that of the doc
01503      * and change it if they disagree (bug 146988).
01504      */
01505    if (!xmlStrEqual(URL, doc->URL)) {
01506        xmlFree(URL);
01507        URL = xmlStrdup(doc->URL);
01508    }
01509     for (i = nr + 1; i < ctxt->incNr; i++) {
01510     if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
01511         ctxt->incTab[nr]->count++;
01512 #ifdef DEBUG_XINCLUDE
01513         printf("Increasing %s count since reused\n", URL);
01514 #endif
01515             break;
01516     }
01517     }
01518 
01519     /*
01520      * Make sure we have all entities fixed up
01521      */
01522     xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
01523 
01524     /*
01525      * We don't need the DTD anymore, free up space
01526     if (doc->intSubset != NULL) {
01527     xmlUnlinkNode((xmlNodePtr) doc->intSubset);
01528     xmlFreeNode((xmlNodePtr) doc->intSubset);
01529     doc->intSubset = NULL;
01530     }
01531     if (doc->extSubset != NULL) {
01532     xmlUnlinkNode((xmlNodePtr) doc->extSubset);
01533     xmlFreeNode((xmlNodePtr) doc->extSubset);
01534     doc->extSubset = NULL;
01535     }
01536      */
01537     xmlXIncludeRecurseDoc(ctxt, doc, URL);
01538 
01539 loaded:
01540     if (fragment == NULL) {
01541     /*
01542      * Add the top children list as the replacement copy.
01543      */
01544     if (doc == NULL)
01545     {
01546         /* Hopefully a DTD declaration won't be copied from
01547          * the same document */
01548         ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
01549     } else {
01550         ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
01551                                                doc, doc->children);
01552     }
01553     } 
01554 #ifdef LIBXML_XPTR_ENABLED
01555     else {
01556     /*
01557      * Computes the XPointer expression and make a copy used
01558      * as the replacement copy.
01559      */
01560     xmlXPathObjectPtr xptr;
01561     xmlXPathContextPtr xptrctxt;
01562     xmlNodeSetPtr set;
01563 
01564     if (doc == NULL) {
01565         xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
01566                                  NULL);
01567     } else {
01568         xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
01569     }
01570     if (xptrctxt == NULL) {
01571         xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
01572                        XML_XINCLUDE_XPTR_FAILED,
01573                "could not create XPointer context\n", NULL);
01574         xmlFree(URL);
01575         xmlFree(fragment);
01576         return(-1);
01577     }
01578     xptr = xmlXPtrEval(fragment, xptrctxt);
01579     if (xptr == NULL) {
01580         xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
01581                        XML_XINCLUDE_XPTR_FAILED,
01582                "XPointer evaluation failed: #%s\n",
01583                fragment);
01584         xmlXPathFreeContext(xptrctxt);
01585         xmlFree(URL);
01586         xmlFree(fragment);
01587         return(-1);
01588     }
01589     switch (xptr->type) {
01590         case XPATH_UNDEFINED:
01591         case XPATH_BOOLEAN:
01592         case XPATH_NUMBER:
01593         case XPATH_STRING:
01594         case XPATH_POINT:
01595         case XPATH_USERS:
01596         case XPATH_XSLT_TREE:
01597         xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
01598                        XML_XINCLUDE_XPTR_RESULT,
01599                    "XPointer is not a range: #%s\n",
01600                    fragment);
01601         xmlXPathFreeContext(xptrctxt);
01602         xmlFree(URL);
01603         xmlFree(fragment);
01604         return(-1);
01605         case XPATH_NODESET:
01606             if ((xptr->nodesetval == NULL) ||
01607             (xptr->nodesetval->nodeNr <= 0)) {
01608             xmlXPathFreeContext(xptrctxt);
01609             xmlFree(URL);
01610             xmlFree(fragment);
01611             return(-1);
01612         }
01613 
01614         case XPATH_RANGE:
01615         case XPATH_LOCATIONSET:
01616         break;
01617     }
01618     set = xptr->nodesetval;
01619     if (set != NULL) {
01620         for (i = 0;i < set->nodeNr;i++) {
01621         if (set->nodeTab[i] == NULL)
01622             continue;
01623         switch (set->nodeTab[i]->type) {
01624             case XML_ELEMENT_NODE:
01625             case XML_TEXT_NODE:
01626             case XML_CDATA_SECTION_NODE:
01627             case XML_ENTITY_REF_NODE:
01628             case XML_ENTITY_NODE:
01629             case XML_PI_NODE:
01630             case XML_COMMENT_NODE:
01631             case XML_DOCUMENT_NODE:
01632             case XML_HTML_DOCUMENT_NODE:
01633 #ifdef LIBXML_DOCB_ENABLED
01634             case XML_DOCB_DOCUMENT_NODE:
01635 #endif
01636             continue;
01637 
01638             case XML_ATTRIBUTE_NODE:
01639             xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
01640                            XML_XINCLUDE_XPTR_RESULT,
01641                        "XPointer selects an attribute: #%s\n",
01642                        fragment);
01643             set->nodeTab[i] = NULL;
01644             continue;
01645             case XML_NAMESPACE_DECL:
01646             xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
01647                            XML_XINCLUDE_XPTR_RESULT,
01648                        "XPointer selects a namespace: #%s\n",
01649                        fragment);
01650             set->nodeTab[i] = NULL;
01651             continue;
01652             case XML_DOCUMENT_TYPE_NODE:
01653             case XML_DOCUMENT_FRAG_NODE:
01654             case XML_NOTATION_NODE:
01655             case XML_DTD_NODE:
01656             case XML_ELEMENT_DECL:
01657             case XML_ATTRIBUTE_DECL:
01658             case XML_ENTITY_DECL:
01659             case XML_XINCLUDE_START:
01660             case XML_XINCLUDE_END:
01661             xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
01662                            XML_XINCLUDE_XPTR_RESULT,
01663                    "XPointer selects unexpected nodes: #%s\n",
01664                        fragment);
01665             set->nodeTab[i] = NULL;
01666             set->nodeTab[i] = NULL;
01667             continue; /* for */
01668         }
01669         }
01670     }
01671     if (doc == NULL) {
01672         ctxt->incTab[nr]->xptr = xptr;
01673         ctxt->incTab[nr]->inc = NULL;
01674     } else {
01675         ctxt->incTab[nr]->inc =
01676         xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
01677         xmlXPathFreeObject(xptr);
01678     }
01679     xmlXPathFreeContext(xptrctxt);
01680     xmlFree(fragment);
01681     }
01682 #endif
01683 
01684     /*
01685      * Do the xml:base fixup if needed
01686      */
01687     if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/')) &&
01688         (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) &&
01689     (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) {
01690     xmlNodePtr node;
01691     xmlChar *base;
01692     xmlChar *curBase;
01693 
01694     /*
01695      * The base is only adjusted if "necessary", i.e. if the xinclude node
01696      * has a base specified, or the URL is relative
01697      */
01698     base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base",
01699             XML_XML_NAMESPACE);
01700     if (base == NULL) {
01701         /*
01702          * No xml:base on the xinclude node, so we check whether the
01703          * URI base is different than (relative to) the context base
01704          */
01705         curBase = xmlBuildRelativeURI(URL, ctxt->base);
01706         if (curBase == NULL) {  /* Error return */
01707             xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
01708                    XML_XINCLUDE_HREF_URI,
01709                "trying to build relative URI from %s\n", URL);
01710         } else {
01711         /* If the URI doesn't contain a slash, it's not relative */
01712             if (!xmlStrchr(curBase, (xmlChar) '/'))
01713             xmlFree(curBase);
01714         else
01715             base = curBase;
01716         }
01717     }
01718     if (base != NULL) { /* Adjustment may be needed */
01719         node = ctxt->incTab[nr]->inc;
01720         while (node != NULL) {
01721         /* Only work on element nodes */
01722         if (node->type == XML_ELEMENT_NODE) {
01723             curBase = xmlNodeGetBase(node->doc, node);
01724             /* If no current base, set it */
01725             if (curBase == NULL) {
01726             xmlNodeSetBase(node, base);
01727             } else {
01728             /*
01729              * If the current base is the same as the
01730              * URL of the document, then reset it to be
01731              * the specified xml:base or the relative URI
01732              */
01733             if (xmlStrEqual(curBase, node->doc->URL)) {
01734                 xmlNodeSetBase(node, base);
01735             } else {
01736                 /*
01737                  * If the element already has an xml:base
01738                  * set, then relativise it if necessary
01739                  */
01740                 xmlChar *xmlBase;
01741                 xmlBase = xmlGetNsProp(node,
01742                         BAD_CAST "base",
01743                         XML_XML_NAMESPACE);
01744                 if (xmlBase != NULL) {
01745                 xmlChar *relBase;
01746                 relBase = xmlBuildURI(xmlBase, base);
01747                 if (relBase == NULL) { /* error */
01748                     xmlXIncludeErr(ctxt, 
01749                         ctxt->incTab[nr]->ref,
01750                         XML_XINCLUDE_HREF_URI,
01751                     "trying to rebuild base from %s\n",
01752                         xmlBase);
01753                 } else {
01754                     xmlNodeSetBase(node, relBase);
01755                     xmlFree(relBase);
01756                 }
01757                 xmlFree(xmlBase);
01758                 }
01759             }
01760             xmlFree(curBase);
01761             }
01762         }
01763             node = node->next;
01764         }
01765         xmlFree(base);
01766     }
01767     }
01768     if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
01769     (ctxt->incTab[nr]->count <= 1)) {
01770 #ifdef DEBUG_XINCLUDE
01771         printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
01772 #endif
01773     xmlFreeDoc(ctxt->incTab[nr]->doc);
01774     ctxt->incTab[nr]->doc = NULL;
01775     }
01776     xmlFree(URL);
01777     return(0);
01778 }
01779 
01790 static int
01791 xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
01792     xmlParserInputBufferPtr buf;
01793     xmlNodePtr node;
01794     xmlURIPtr uri;
01795     xmlChar *URL;
01796     int i;
01797     xmlChar *encoding = NULL;
01798     xmlCharEncoding enc = (xmlCharEncoding) 0;
01799 
01800     /*
01801      * Check the URL and remove any fragment identifier
01802      */
01803     uri = xmlParseURI((const char *)url);
01804     if (uri == NULL) {
01805     xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
01806                    "invalid value URI %s\n", url);
01807     return(-1);
01808     }
01809     if (uri->fragment != NULL) {
01810     xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
01811                    "fragment identifier forbidden for text: %s\n",
01812                (const xmlChar *) uri->fragment);
01813     xmlFreeURI(uri);
01814     return(-1);
01815     }
01816     URL = xmlSaveUri(uri);
01817     xmlFreeURI(uri);
01818     if (URL == NULL) {
01819     xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
01820                    "invalid value URI %s\n", url);
01821     return(-1);
01822     }
01823 
01824     /*
01825      * Handling of references to the local document are done
01826      * directly through ctxt->doc.
01827      */
01828     if (URL[0] == 0) {
01829     xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
01830                    XML_XINCLUDE_TEXT_DOCUMENT,
01831                "text serialization of document not available\n", NULL);
01832     xmlFree(URL);
01833     return(-1);
01834     }
01835 
01836     /*
01837      * Prevent reloading twice the document.
01838      */
01839     for (i = 0; i < ctxt->txtNr; i++) {
01840     if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
01841         node = xmlCopyNode(ctxt->txtTab[i], 1);
01842         goto loaded;
01843     }
01844     }
01845     /*
01846      * Try to get the encoding if available
01847      */
01848     if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
01849     encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
01850     }
01851     if (encoding != NULL) {
01852     /*
01853      * TODO: we should not have to remap to the xmlCharEncoding
01854      *       predefined set, a better interface than
01855      *       xmlParserInputBufferCreateFilename should allow any
01856      *       encoding supported by iconv
01857      */
01858         enc = xmlParseCharEncoding((const char *) encoding);
01859     if (enc == XML_CHAR_ENCODING_ERROR) {
01860         xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
01861                        XML_XINCLUDE_UNKNOWN_ENCODING,
01862                "encoding %s not supported\n", encoding);
01863         xmlFree(encoding);
01864         xmlFree(URL);
01865         return(-1);
01866     }
01867     xmlFree(encoding);
01868     }
01869 
01870     /*
01871      * Load it.
01872      */
01873     buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
01874     if (buf == NULL) {
01875     xmlFree(URL);
01876     return(-1);
01877     }
01878     node = xmlNewText(NULL);
01879 
01880     /*
01881      * Scan all chars from the resource and add the to the node
01882      */
01883     while (xmlParserInputBufferRead(buf, 128) > 0) {
01884     int len;
01885     const xmlChar *content;
01886 
01887     content = xmlBufferContent(buf->buffer);
01888     len = xmlBufferLength(buf->buffer);
01889     for (i = 0;i < len;) {
01890         int cur;
01891         int l;
01892 
01893         cur = xmlStringCurrentChar(NULL, &content[i], &l);
01894         if (!IS_CHAR(cur)) {
01895         xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
01896                        XML_XINCLUDE_INVALID_CHAR,
01897                    "%s contains invalid char\n", URL);
01898         xmlFreeParserInputBuffer(buf);
01899         xmlFree(URL);
01900         return(-1);
01901         } else {
01902         xmlNodeAddContentLen(node, &content[i], l);
01903         }
01904         i += l;
01905     }
01906     xmlBufferShrink(buf->buffer, len);
01907     }
01908     xmlFreeParserInputBuffer(buf);
01909     xmlXIncludeAddTxt(ctxt, node, URL);
01910 
01911 loaded:
01912     /*
01913      * Add the element as the replacement copy.
01914      */
01915     ctxt->incTab[nr]->inc = node;
01916     xmlFree(URL);
01917     return(0);
01918 }
01919 
01931 static int
01932 xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
01933     xmlXIncludeCtxtPtr newctxt;
01934     int ret = 0;
01935     
01936     if ((fallback == NULL) || (ctxt == NULL))
01937     return(-1);
01938     if (fallback->children != NULL) {
01939     /*
01940      * It's possible that the fallback also has 'includes'
01941      * (Bug 129969), so we re-process the fallback just in case
01942      */
01943     newctxt = xmlXIncludeNewContext(ctxt->doc);
01944     if (newctxt == NULL)
01945         return (-1);
01946     newctxt->_private = ctxt->_private;
01947     newctxt->base = xmlStrdup(ctxt->base);  /* Inherit the base from the existing context */
01948     xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
01949     ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
01950     if (ctxt->nbErrors > 0)
01951         ret = -1;
01952     else if (ret > 0)
01953         ret = 0;    /* xmlXIncludeDoProcess can return +ve number */
01954     xmlXIncludeFreeContext(newctxt);
01955 
01956     ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
01957                                                fallback->children);
01958     } else {
01959         ctxt->incTab[nr]->inc = NULL;
01960     ctxt->incTab[nr]->emptyFb = 1;  /* flag empty callback */
01961     }
01962     return(ret);
01963 }
01964 
01965 /************************************************************************
01966  *                                  *
01967  *          XInclude Processing             *
01968  *                                  *
01969  ************************************************************************/
01970 
01981 static xmlNodePtr
01982 xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
01983     xmlXIncludeAddNode(ctxt, node);
01984     return(NULL);
01985 }
01986 
01996 static int
01997 xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
01998     xmlNodePtr cur;
01999     xmlChar *href;
02000     xmlChar *parse;
02001     xmlChar *base;
02002     xmlChar *oldBase;
02003     xmlChar *URI;
02004     int xml = 1; /* default Issue 64 */
02005     int ret;
02006 
02007     if (ctxt == NULL)
02008     return(-1);
02009     if ((nr < 0) || (nr >= ctxt->incNr))
02010     return(-1);
02011     cur = ctxt->incTab[nr]->ref;
02012     if (cur == NULL)
02013     return(-1);
02014 
02015     /*
02016      * read the attributes
02017      */
02018     href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
02019     if (href == NULL) {
02020     href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
02021     if (href == NULL) 
02022         return(-1);
02023     }
02024     parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
02025     if (parse != NULL) {
02026     if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
02027         xml = 1;
02028     else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
02029         xml = 0;
02030     else {
02031         xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
02032                        XML_XINCLUDE_PARSE_VALUE,
02033                "invalid value %s for 'parse'\n", parse);
02034         if (href != NULL)
02035         xmlFree(href);
02036         if (parse != NULL)
02037         xmlFree(parse);
02038         return(-1);
02039     }
02040     }
02041 
02042     /*
02043      * compute the URI
02044      */
02045     base = xmlNodeGetBase(ctxt->doc, cur);
02046     if (base == NULL) {
02047     URI = xmlBuildURI(href, ctxt->doc->URL);
02048     } else {
02049     URI = xmlBuildURI(href, base);
02050     }
02051     if (URI == NULL) {
02052     xmlChar *escbase;
02053     xmlChar *eschref;
02054     /*
02055      * Some escaping may be needed
02056      */
02057     escbase = xmlURIEscape(base);
02058     eschref = xmlURIEscape(href);
02059     URI = xmlBuildURI(eschref, escbase);
02060     if (escbase != NULL)
02061         xmlFree(escbase);
02062     if (eschref != NULL)
02063         xmlFree(eschref);
02064     }
02065     if (URI == NULL) {
02066     xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
02067                    XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
02068     if (parse != NULL)
02069         xmlFree(parse);
02070     if (href != NULL)
02071         xmlFree(href);
02072     if (base != NULL)
02073         xmlFree(base);
02074     return(-1);
02075     }
02076 #ifdef DEBUG_XINCLUDE
02077     xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
02078         xml ? "xml": "text");
02079     xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
02080 #endif
02081 
02082     /*
02083      * Save the base for this include (saving the current one)
02084      */
02085     oldBase = ctxt->base;
02086     ctxt->base = base;
02087 
02088     if (xml) {
02089     ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
02090     /* xmlXIncludeGetFragment(ctxt, cur, URI); */
02091     } else {
02092     ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
02093     }
02094 
02095     /*
02096      * Restore the original base before checking for fallback
02097      */
02098     ctxt->base = oldBase;
02099     
02100     if (ret < 0) {
02101     xmlNodePtr children;
02102 
02103     /*
02104      * Time to try a fallback if availble
02105      */
02106 #ifdef DEBUG_XINCLUDE
02107     xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
02108 #endif
02109     children = cur->children;
02110     while (children != NULL) {
02111         if ((children->type == XML_ELEMENT_NODE) &&
02112         (children->ns != NULL) &&
02113         (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
02114         ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
02115          (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
02116         ret = xmlXIncludeLoadFallback(ctxt, children, nr);
02117         if (ret == 0) 
02118             break;
02119         }
02120         children = children->next;
02121     }
02122     }
02123     if (ret < 0) {
02124     xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
02125                    XML_XINCLUDE_NO_FALLBACK,
02126                "could not load %s, and no fallback was found\n",
02127                URI);
02128     }
02129 
02130     /*
02131      * Cleanup
02132      */
02133     if (URI != NULL)
02134     xmlFree(URI);
02135     if (parse != NULL)
02136     xmlFree(parse);
02137     if (href != NULL)
02138     xmlFree(href);
02139     if (base != NULL)
02140     xmlFree(base);
02141     return(0);
02142 }
02143 
02153 static int
02154 xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
02155     xmlNodePtr cur, end, list, tmp;
02156 
02157     if (ctxt == NULL)
02158     return(-1);
02159     if ((nr < 0) || (nr >= ctxt->incNr))
02160     return(-1);
02161     cur = ctxt->incTab[nr]->ref;
02162     if (cur == NULL)
02163     return(-1);
02164 
02165     /*
02166      * If we stored an XPointer a late computation may be needed
02167      */
02168     if ((ctxt->incTab[nr]->inc == NULL) &&
02169     (ctxt->incTab[nr]->xptr != NULL)) {
02170     ctxt->incTab[nr]->inc =
02171         xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
02172                             ctxt->incTab[nr]->xptr);
02173     xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
02174     ctxt->incTab[nr]->xptr = NULL;
02175     }
02176     list = ctxt->incTab[nr]->inc;
02177     ctxt->incTab[nr]->inc = NULL;
02178 
02179     /*
02180      * Check against the risk of generating a multi-rooted document
02181      */
02182     if ((cur->parent != NULL) &&
02183     (cur->parent->type != XML_ELEMENT_NODE)) {
02184     int nb_elem = 0;
02185 
02186     tmp = list;
02187     while (tmp != NULL) {
02188         if (tmp->type == XML_ELEMENT_NODE)
02189         nb_elem++;
02190         tmp = tmp->next;
02191     }
02192     if (nb_elem > 1) {
02193         xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
02194                        XML_XINCLUDE_MULTIPLE_ROOT,
02195                "XInclude error: would result in multiple root nodes\n",
02196                NULL);
02197         return(-1);
02198     }
02199     }
02200 
02201     if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
02202     /*
02203      * Add the list of nodes
02204      */
02205     while (list != NULL) {
02206         end = list;
02207         list = list->next;
02208 
02209         xmlAddPrevSibling(cur, end);
02210     }
02211     xmlUnlinkNode(cur);
02212     xmlFreeNode(cur);
02213     } else {
02214     /*
02215      * Change the current node as an XInclude start one, and add an
02216      * XInclude end one
02217      */
02218     cur->type = XML_XINCLUDE_START;
02219     end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
02220     if (end == NULL) {
02221         xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
02222                        XML_XINCLUDE_BUILD_FAILED,
02223                "failed to build node\n", NULL);
02224         return(-1);
02225     }
02226     end->type = XML_XINCLUDE_END;
02227     xmlAddNextSibling(cur, end);
02228 
02229     /*
02230      * Add the list of nodes
02231      */
02232     while (list != NULL) {
02233         cur = list;
02234         list = list->next;
02235 
02236         xmlAddPrevSibling(end, cur);
02237     }
02238     }
02239 
02240     
02241     return(0);
02242 }
02243 
02253 static int
02254 xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
02255     if (node == NULL)
02256     return(0);
02257     if (node->type != XML_ELEMENT_NODE)
02258     return(0);
02259     if (node->ns == NULL)
02260     return(0);
02261     if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
02262         (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
02263     if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
02264         if (ctxt->legacy == 0) {
02265 #if 0 /* wait for the XML Core Working Group to get something stable ! */
02266         xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
02267                    "Deprecated XInclude namespace found, use %s",
02268                         XINCLUDE_NS);
02269 #endif
02270             ctxt->legacy = 1;
02271         }
02272     }
02273     if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
02274         xmlNodePtr child = node->children;
02275         int nb_fallback = 0;
02276 
02277         while (child != NULL) {
02278         if ((child->type == XML_ELEMENT_NODE) &&
02279             (child->ns != NULL) &&
02280             ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
02281              (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
02282             if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
02283             xmlXIncludeErr(ctxt, node,
02284                            XML_XINCLUDE_INCLUDE_IN_INCLUDE,
02285                        "%s has an 'include' child\n",
02286                        XINCLUDE_NODE);
02287             return(0);
02288             }
02289             if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
02290             nb_fallback++;
02291             }
02292         }
02293         child = child->next;
02294         }
02295         if (nb_fallback > 1) {
02296         xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
02297                    "%s has multiple fallback children\n",
02298                        XINCLUDE_NODE);
02299         return(0);
02300         }
02301         return(1);
02302     }
02303     if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
02304         if ((node->parent == NULL) ||
02305         (node->parent->type != XML_ELEMENT_NODE) ||
02306         (node->parent->ns == NULL) ||
02307         ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
02308          (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
02309         (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
02310         xmlXIncludeErr(ctxt, node,
02311                        XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
02312                    "%s is not the child of an 'include'\n",
02313                    XINCLUDE_FALLBACK);
02314         }
02315     }
02316     }
02317     return(0);
02318 }
02319 
02331 static int
02332 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
02333     xmlNodePtr cur;
02334     int ret = 0;
02335     int i, start;
02336 
02337     if ((doc == NULL) || (tree == NULL))
02338     return(-1);
02339     if (ctxt == NULL)
02340     return(-1);
02341 
02342     if (doc->URL != NULL) {
02343     ret = xmlXIncludeURLPush(ctxt, doc->URL);
02344     if (ret < 0)
02345         return(-1);
02346     }
02347     start = ctxt->incNr;
02348 
02349     /*
02350      * First phase: lookup the elements in the document
02351      */
02352     cur = tree;
02353     if (xmlXIncludeTestNode(ctxt, cur) == 1)
02354     xmlXIncludePreProcessNode(ctxt, cur);
02355     while ((cur != NULL) && (cur != tree->parent)) {
02356     /* TODO: need to work on entities -> stack */
02357     if ((cur->children != NULL) &&
02358         (cur->children->type != XML_ENTITY_DECL) &&
02359         (cur->children->type != XML_XINCLUDE_START) &&
02360         (cur->children->type != XML_XINCLUDE_END)) {
02361         cur = cur->children;
02362         if (xmlXIncludeTestNode(ctxt, cur))
02363         xmlXIncludePreProcessNode(ctxt, cur);
02364     } else if (cur->next != NULL) {
02365         cur = cur->next;
02366         if (xmlXIncludeTestNode(ctxt, cur))
02367         xmlXIncludePreProcessNode(ctxt, cur);
02368     } else {
02369         if (cur == tree)
02370             break;
02371         do {
02372         cur = cur->parent;
02373         if ((cur == NULL) || (cur == tree->parent))
02374             break; /* do */
02375         if (cur->next != NULL) {
02376             cur = cur->next;
02377             if (xmlXIncludeTestNode(ctxt, cur))
02378             xmlXIncludePreProcessNode(ctxt, cur);
02379             break; /* do */
02380         }
02381         } while (cur != NULL);
02382     }
02383     }
02384 
02385     /*
02386      * Second Phase : collect the infosets fragments
02387      */
02388     for (i = start;i < ctxt->incNr; i++) {
02389         xmlXIncludeLoadNode(ctxt, i);
02390     ret++;
02391     }
02392 
02393     /*
02394      * Third phase: extend the original document infoset.
02395      *
02396      * Originally we bypassed the inclusion if there were any errors
02397      * encountered on any of the XIncludes.  A bug was raised (bug
02398      * 132588) requesting that we output the XIncludes without error,
02399      * so the check for inc!=NULL || xptr!=NULL was put in.  This may
02400      * give some other problems in the future, but for now it seems to
02401      * work ok.
02402      *
02403      */
02404     for (i = ctxt->incBase;i < ctxt->incNr; i++) {
02405     if ((ctxt->incTab[i]->inc != NULL) ||
02406         (ctxt->incTab[i]->xptr != NULL) ||
02407         (ctxt->incTab[i]->emptyFb != 0))    /* (empty fallback) */
02408         xmlXIncludeIncludeNode(ctxt, i);
02409     }
02410 
02411     if (doc->URL != NULL)
02412     xmlXIncludeURLPop(ctxt);
02413     return(ret);
02414 }
02415 
02425 int
02426 xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
02427     if (ctxt == NULL)
02428         return(-1);
02429     ctxt->parseFlags = flags;
02430     return(0);
02431 }
02432 
02446 int
02447 xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
02448     xmlXIncludeCtxtPtr ctxt;
02449     int ret = 0;
02450 
02451     if ((tree == NULL) || (tree->doc == NULL))
02452         return(-1);
02453 
02454     ctxt = xmlXIncludeNewContext(tree->doc);
02455     if (ctxt == NULL)
02456         return(-1);
02457     ctxt->_private = data;
02458     ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
02459     xmlXIncludeSetFlags(ctxt, flags);
02460     ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
02461     if ((ret >= 0) && (ctxt->nbErrors > 0))
02462         ret = -1;
02463 
02464     xmlXIncludeFreeContext(ctxt);
02465     return(ret);
02466 }
02467 
02480 int
02481 xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) {
02482     xmlNodePtr tree;
02483 
02484     if (doc == NULL)
02485     return(-1);
02486     tree = xmlDocGetRootElement(doc);
02487     if (tree == NULL)
02488     return(-1);
02489     return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));
02490 }
02491 
02502 int
02503 xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
02504     return xmlXIncludeProcessFlagsData(doc, flags, NULL);
02505 }
02506 
02516 int
02517 xmlXIncludeProcess(xmlDocPtr doc) {
02518     return(xmlXIncludeProcessFlags(doc, 0));
02519 }
02520 
02531 int
02532 xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
02533     xmlXIncludeCtxtPtr ctxt;
02534     int ret = 0;
02535 
02536     if ((tree == NULL) || (tree->doc == NULL))
02537     return(-1);
02538     ctxt = xmlXIncludeNewContext(tree->doc);
02539     if (ctxt == NULL)
02540     return(-1);
02541     ctxt->base = xmlNodeGetBase(tree->doc, tree);
02542     xmlXIncludeSetFlags(ctxt, flags);
02543     ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
02544     if ((ret >= 0) && (ctxt->nbErrors > 0))
02545     ret = -1;
02546 
02547     xmlXIncludeFreeContext(ctxt);
02548     return(ret);
02549 }
02550 
02560 int
02561 xmlXIncludeProcessTree(xmlNodePtr tree) {
02562     return(xmlXIncludeProcessTreeFlags(tree, 0));
02563 }
02564 
02576 int
02577 xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
02578     int ret = 0;
02579 
02580     if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
02581     return(-1);
02582     ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
02583     if ((ret >= 0) && (ctxt->nbErrors > 0))
02584     ret = -1;
02585     return(ret);
02586 }
02587 
02588 #else /* !LIBXML_XINCLUDE_ENABLED */
02589 #endif
02590 #define bottom_xinclude
02591 #include "elfgcchack.h"

Generated on Sat May 26 2012 04:33:35 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.