diff --git a/ChangeLog b/ChangeLog index 01b50819..cbc24aaf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Aug 22 16:27:03 CEST 2001 Daniel Veillard + + * include/libxml/catalog.h include/libxml/parser.h + include/libxml/xmlerror.h catalog.c parser.c parserInternals.c + xmlIO.c: added support and APIs needed for the catalog PI + * include/libxml/xmlIO.h: cleanup + Wed Aug 22 02:03:31 CEST 2001 Daniel Veillard * catalog.c parser.c xmlIO.c xmlcatalog.c xmllint.c diff --git a/catalog.c b/catalog.c index 2ea69db8..06b2b53b 100644 --- a/catalog.c +++ b/catalog.c @@ -93,10 +93,11 @@ struct _xmlCatalogEntry { xmlCatalogPrefer prefer; }; +static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL; +static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_SYSTEM; static xmlHashTablePtr xmlDefaultCatalog; static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL; static int xmlCatalogInitialized = 0; -static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_SYSTEM; /* Catalog stack */ @@ -1562,7 +1563,17 @@ xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) { */ static const xmlChar * xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) { - TODO + const xmlChar *ret = NULL; + + if (xmlDefaultCatalog == NULL) + return(NULL); + + if (pubID != NULL) + ret = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID); + if (ret != NULL) + return(ret); + if (sysID != NULL) + ret = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID); return(NULL); } @@ -2010,12 +2021,59 @@ xmlCatalogRemove(const xmlChar *value) { return(res); } +/** + * xmlCatalogGetDefaults: + * + * Used to get the user preference w.r.t. to what catalogs should + * be accepted + * + * Returns the current xmlCatalogAllow value + */ +xmlCatalogAllow +xmlCatalogGetDefaults(void) { + return(xmlCatalogDefaultAllow); +} + +/** + * xmlCatalogSetDefaults: + * + * Used to set the user preference w.r.t. to what catalogs should + * be accepted + */ +void +xmlCatalogSetDefaults(xmlCatalogAllow allow) { + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + if (xmlDebugCatalogs) { + switch (allow) { + case XML_CATA_ALLOW_NONE: + xmlGenericError(xmlGenericErrorContext, + "Disabling catalog usage\n"); + break; + case XML_CATA_ALLOW_GLOBAL: + xmlGenericError(xmlGenericErrorContext, + "Allowing only global catalogs\n"); + break; + case XML_CATA_ALLOW_DOCUMENT: + xmlGenericError(xmlGenericErrorContext, + "Allowing only catalogs from the document\n"); + break; + case XML_CATA_ALLOW_ALL: + xmlGenericError(xmlGenericErrorContext, + "Allowing all catalogs\n"); + break; + } + } + xmlCatalogDefaultAllow = allow; +} + /** * xmlCatalogSetDefaultPrefer: * @prefer: the default preference for delegation * * Allows to set the preference between public and system for deletion * in XML Catalog resolution. C.f. section 4.1.1 of the spec + * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM * * Returns the previous value of the default preference for delegation */ @@ -2023,6 +2081,25 @@ xmlCatalogPrefer xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) { xmlCatalogPrefer ret = xmlCatalogDefaultPrefer; + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + if (prefer == XML_CATA_PREFER_NONE) + return(ret); + + if (xmlDebugCatalogs) { + switch (prefer) { + case XML_CATA_PREFER_PUBLIC: + xmlGenericError(xmlGenericErrorContext, + "Setting catalog preference to PUBLIC\n"); + break; + case XML_CATA_PREFER_SYSTEM: + xmlGenericError(xmlGenericErrorContext, + "Setting catalog preference to SYSTEM\n"); + break; + case XML_CATA_PREFER_NONE: + break; + } + } xmlCatalogDefaultPrefer = prefer; return(ret); } @@ -2046,4 +2123,83 @@ xmlCatalogSetDebug(int level) { xmlDebugCatalogs = level; return(ret); } + +/** + * xmlCatalogFreeLocal: + * @catalogs: a document's list of catalogs + * + * Free up the memory associated to the catalog list + */ +void +xmlCatalogFreeLocal(void *catalogs) { + xmlCatalogEntryPtr catal; + + catal = (xmlCatalogEntryPtr) catalogs; + if (catal != NULL) + xmlFreeCatalogEntryList(catal); +} + + +/** + * xmlCatalogAddLocal: + * @catalogs: a document's list of catalogs + * @URL: the URL to a new local catalog + * + * Add the new entry to the catalog list + * + * Returns the updated list + */ +void * +xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) { + xmlCatalogEntryPtr catal, add; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + if (URL == NULL) + return(catalogs); + + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Adding document catalog %s\n", URL); + + add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, + xmlCatalogDefaultPrefer); + if (add == NULL) + return(catalogs); + + catal = (xmlCatalogEntryPtr) catalogs; + if (catal == NULL) + return((void *) add); + + while (catal->next != NULL) + catal = catal->next; + catal->next = add; + return(catalogs); +} + +/** + * xmlCatalogLocalResolve: + * @catalogs: a document's list of catalogs + * @pubId: the public ID string + * @sysId: the system ID string + * + * Do a complete resolution lookup of an External Identifier using a + * document's private catalog list + * + * Returns the URI of the resource or NULL if not found, it must be freed + * by the caller. + */ +xmlChar * +xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID, + const xmlChar *sysID) { + xmlCatalogEntryPtr catal; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + catal = (xmlCatalogEntryPtr) catalogs; + if (catal == NULL) + return(NULL); + return(xmlCatalogListXMLResolve(catal, pubID, sysID)); +} + #endif /* LIBXML_CATALOG_ENABLED */ diff --git a/include/libxml/catalog.h b/include/libxml/catalog.h index 7693996f..d39fb60e 100644 --- a/include/libxml/catalog.h +++ b/include/libxml/catalog.h @@ -33,8 +33,10 @@ extern "C" { * * The namespace for the XML Catalogs elements */ -#define XML_CATALOGS_NAMESPACE \ +#define XML_CATALOGS_NAMESPACE \ (const xmlChar *) "urn:oasis:names:tc:entity:xmlns:xml:catalog" +#define XML_CATALOG_PI \ + (const xmlChar *) "oasis-xml-catalog" /* * The API is voluntarily limited to general cataloging @@ -45,6 +47,13 @@ typedef enum { XML_CATA_PREFER_SYSTEM } xmlCatalogPrefer; +typedef enum { + XML_CATA_ALLOW_NONE = 0, + XML_CATA_ALLOW_GLOBAL = 1, + XML_CATA_ALLOW_DOCUMENT = 2, + XML_CATA_ALLOW_ALL = 3 +} xmlCatalogAllow; + void xmlInitializeCatalog (void); int xmlLoadCatalog (const char *filename); void xmlLoadCatalogs (const char *paths); @@ -58,8 +67,24 @@ int xmlCatalogAdd (const xmlChar *type, const xmlChar *orig, const xmlChar *replace); int xmlCatalogRemove (const xmlChar *value); + +/* + * Strictly minimal interfaces for per-document catalogs used + * by the parser. + */ +void xmlCatalogFreeLocal (void *catalogs); +void * xmlCatalogAddLocal (void *catalogs, + const xmlChar *URL); +xmlChar * xmlCatalogLocalResolve (void *catalogs, + const xmlChar *pubID, + const xmlChar *sysID); +/* + * Preference settings + */ int xmlCatalogSetDebug (int level); xmlCatalogPrefer xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer); +void xmlCatalogSetDefaults (xmlCatalogAllow allow); +xmlCatalogAllow xmlCatalogGetDefaults (void); /* DEPRECATED interfaces */ const xmlChar * xmlCatalogGetSystem (const xmlChar *sysID); diff --git a/include/libxml/parser.h b/include/libxml/parser.h index de0bebbe..1cf7f527 100644 --- a/include/libxml/parser.h +++ b/include/libxml/parser.h @@ -217,6 +217,7 @@ struct _xmlParserCtxt { int loadsubset; /* should the external subset be loaded */ int linenumbers; /* set line number in element content */ + void *catalogs; /* document's own catalog */ }; /** diff --git a/include/libxml/xmlIO.h b/include/libxml/xmlIO.h index 9f248d1e..0bdf6a51 100644 --- a/include/libxml/xmlIO.h +++ b/include/libxml/xmlIO.h @@ -165,7 +165,7 @@ int xmlRegisterOutputCallbacks (xmlOutputMatchCallback matchFunc, #ifdef LIBXML_HTTP_ENABLED void * xmlIOHTTPOpenW (const char * post_uri, int compression ); -void xmlRegisterHTTPPostCallbacksI (void ); +void xmlRegisterHTTPPostCallbacks (void ); #endif /* diff --git a/include/libxml/xmlerror.h b/include/libxml/xmlerror.h index 53c57518..88daeff9 100644 --- a/include/libxml/xmlerror.h +++ b/include/libxml/xmlerror.h @@ -132,7 +132,8 @@ typedef enum { XML_ERR_ENTITY_LOOP, /* 89 */ XML_ERR_ENTITY_BOUNDARY, /* 90 */ XML_ERR_INVALID_URI, /* 91 */ - XML_ERR_URI_FRAGMENT /* 92 */ + XML_ERR_URI_FRAGMENT, /* 92 */ + XML_WAR_CATALOG_PI /* 93 */ }xmlParserErrors; /* diff --git a/parser.c b/parser.c index ee68b626..ca966966 100644 --- a/parser.c +++ b/parser.c @@ -50,6 +50,9 @@ #include #include #include +#ifdef LIBXML_CATALOG_ENABLED +#include +#endif #ifdef HAVE_CTYPE_H #include @@ -2941,6 +2944,69 @@ xmlParsePITarget(xmlParserCtxtPtr ctxt) { return(name); } +#ifdef LIBXML_CATALOG_ENABLED +/** + * xmlParseCatalogPI: + * @ctxt: an XML parser context + * @catalog: the PI value string + * + * parse an XML Catalog Processing Instruction. + * + * + * + * Occurs only if allowed by the user and if happening in the Misc + * part of the document before any doctype informations + * This will add the given catalog to the parsing context in order + * to be used if there is a resolution need further down in the document + */ + +static void +xmlParseCatalogPI(xmlParserCtxtPtr ctxt, const xmlChar *catalog) { + xmlChar *URL = NULL; + const xmlChar *tmp, *base; + xmlChar marker; + + tmp = catalog; + while (IS_BLANK(*tmp)) tmp++; + if (xmlStrncmp(tmp, BAD_CAST"catalog", 7)) + goto error; + tmp += 7; + while (IS_BLANK(*tmp)) tmp++; + if (*tmp != '=') { + return; + } + tmp++; + while (IS_BLANK(*tmp)) tmp++; + marker = *tmp; + if ((marker != '\'') && (marker != '"')) + goto error; + tmp++; + base = tmp; + while ((*tmp != 0) && (*tmp != marker)) tmp++; + if (*tmp == 0) + goto error; + URL = xmlStrndup(base, tmp - base); + tmp++; + while (IS_BLANK(*tmp)) tmp++; + if (*tmp != 0) + goto error; + + if (URL != NULL) { + ctxt->catalogs = xmlCatalogAddLocal(ctxt->catalogs, URL); + xmlFree(URL); + } + return; + +error: + ctxt->errNo = XML_WAR_CATALOG_PI; + if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) + ctxt->sax->warning(ctxt->userData, + "Catalog PI syntax error: %s\n", catalog); + if (URL != NULL) + xmlFree(URL); +} +#endif + /** * xmlParsePI: * @ctxt: an XML parser context @@ -3063,6 +3129,18 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { } SKIP(2); +#ifdef LIBXML_CATALOG_ENABLED + if (((state == XML_PARSER_MISC) || + (state == XML_PARSER_START)) && + (xmlStrEqual(target, XML_CATALOG_PI))) { + xmlCatalogAllow allow = xmlCatalogGetDefaults(); + if ((allow == XML_CATA_ALLOW_DOCUMENT) || + (allow == XML_CATA_ALLOW_ALL)) + xmlParseCatalogPI(ctxt, buf); + } +#endif + + /* * SAX: PI detected. */ @@ -5324,7 +5402,7 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { ctxt->disableSAX = 1; } else { ctxt->errNo = XML_WAR_UNDECLARED_ENTITY; - if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) ctxt->sax->error(ctxt->userData, "Entity '%s' not defined\n", name); } diff --git a/parserInternals.c b/parserInternals.c index e31e6f29..8e652b3c 100644 --- a/parserInternals.c +++ b/parserInternals.c @@ -46,6 +46,9 @@ #include #include #include +#ifdef LIBXML_CATALOG_ENABLED +#include +#endif void xmlUpgradeOldNs(xmlDocPtr doc); @@ -2270,6 +2273,7 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) ctxt->errNo = XML_ERR_OK; ctxt->depth = 0; ctxt->charset = XML_CHAR_ENCODING_UTF8; + ctxt->catalogs = NULL; xmlInitNodeInfoSeq(&ctxt->node_seq); } @@ -2308,6 +2312,10 @@ xmlFreeParserCtxt(xmlParserCtxtPtr ctxt) xmlFree(ctxt->sax); if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory); if (ctxt->vctxt.nodeTab != NULL) xmlFree(ctxt->vctxt.nodeTab); +#ifdef LIBXML_CATALOG_ENABLED + if (ctxt->catalogs != NULL) + xmlCatalogFreeLocal(ctxt->catalogs); +#endif xmlFree(ctxt); } diff --git a/xmlIO.c b/xmlIO.c index 1cfefcef..bff4479d 100644 --- a/xmlIO.c +++ b/xmlIO.c @@ -2374,6 +2374,7 @@ xmlDefaultExternalEntityLoader(const char *URL, const char *ID, xmlChar *resource = NULL; #ifdef LIBXML_CATALOG_ENABLED struct stat info; + xmlCatalogAllow pref; #endif #ifdef DEBUG_EXTERNAL_ENTITIES @@ -2385,11 +2386,40 @@ xmlDefaultExternalEntityLoader(const char *URL, const char *ID, * If the resource doesn't exists as a file, * try to load it from the resource pointed in the catalog */ + pref = xmlCatalogGetDefaults(); + + if ((pref != XML_CATA_ALLOW_NONE) #ifdef HAVE_STAT - if ((URL == NULL) || (stat(URL, &info) < 0)) + && ((URL == NULL) || (stat(URL, &info) < 0)) #endif - resource = xmlCatalogResolve((const xmlChar *)ID, - (const xmlChar *)URL); + ) { + /* + * Do a local lookup + */ + if ((ctxt->catalogs != NULL) && + ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_DOCUMENT))) { + resource = xmlCatalogLocalResolve(ctxt->catalogs, + (const xmlChar *)ID, + (const xmlChar *)URL); + } + /* + * Do a global lookup + */ + if (((resource == NULL) +#ifdef HAVE_STAT + || (stat((const char *) resource, &info) < 0) +#endif + ) && ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_GLOBAL))) { + + resource = xmlCatalogResolve((const xmlChar *)ID, + (const xmlChar *)URL); + } + /* + * TODO: do an URI lookup on the reference + */ + } #endif if (resource == NULL)