diff options
author | Daniel Veillard <veillard@src.gnome.org> | 2001-08-20 00:08:40 +0000 |
---|---|---|
committer | Daniel Veillard <veillard@src.gnome.org> | 2001-08-20 00:08:40 +0000 |
commit | 344cee76a675e83ff159ffc02b009f304569ceda (patch) | |
tree | ccb61b9f5893fe0cabb2b0f19bd9a3ea88a3cf32 /catalog.c | |
parent | b7664f444160425950a2a03a38f1b8256d3705e6 (diff) | |
download | android_external_libxml2-344cee76a675e83ff159ffc02b009f304569ceda.tar.gz android_external_libxml2-344cee76a675e83ff159ffc02b009f304569ceda.tar.bz2 android_external_libxml2-344cee76a675e83ff159ffc02b009f304569ceda.zip |
renaming testCatalog as xmlcatalog, making it an installed app adding a
* Makefile.am xmlcatalog.c libxml.spec.in: renaming
testCatalog as xmlcatalog, making it an installed app
adding a shell, and preparing it to be a /etc/xml/catalog
management tool, though not ready yet
* catalog.c include/libxml/catalog.h: adding support for
XML Catalogs http://www.oasis-open.org/committees/entity/
not finished, there is some interesting tradeoffs and a
few open questions left.
Daniel
Diffstat (limited to 'catalog.c')
-rw-r--r-- | catalog.c | 932 |
1 files changed, 847 insertions, 85 deletions
@@ -4,6 +4,9 @@ * Reference: SGML Open Technical Resolution TR9401:1997. * http://www.jclark.com/sp/catalog.htm * + * XML Catalogs Working Draft 06 August 2001 + * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * * See Copyright for the status of this software. * * Daniel.Veillard@imag.fr @@ -32,6 +35,17 @@ #include <libxml/catalog.h> #include <libxml/xmlerror.h> +/** + * TODO: + * + * macro to flag unimplemented blocks + */ +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + + /************************************************************************ * * * Types, all private * @@ -39,36 +53,57 @@ ************************************************************************/ typedef enum { + XML_CATA_PREFER_PUBLIC = 1, + XML_CATA_PREFER_SYSTEM +} xmlCatalogPrefer; + +typedef enum { XML_CATA_NONE = 0, - XML_CATA_SYSTEM, - XML_CATA_PUBLIC, - XML_CATA_ENTITY, - XML_CATA_PENTITY, - XML_CATA_DOCTYPE, - XML_CATA_LINKTYPE, - XML_CATA_NOTATION, - XML_CATA_DELEGATE, - XML_CATA_BASE, XML_CATA_CATALOG, - XML_CATA_DOCUMENT, - XML_CATA_SGMLDECL + XML_CATA_NEXT_CATALOG, + XML_CATA_PUBLIC, + XML_CATA_SYSTEM, + XML_CATA_REWRITE_SYSTEM, + XML_CATA_DELEGATE_PUBLIC, + XML_CATA_DELEGATE_SYSTEM, + XML_CATA_URI, + XML_CATA_REWRITE_URI, + XML_CATA_DELEGATE_URI, + SGML_CATA_SYSTEM, + SGML_CATA_PUBLIC, + SGML_CATA_ENTITY, + SGML_CATA_PENTITY, + SGML_CATA_DOCTYPE, + SGML_CATA_LINKTYPE, + SGML_CATA_NOTATION, + SGML_CATA_DELEGATE, + SGML_CATA_BASE, + SGML_CATA_CATALOG, + SGML_CATA_DOCUMENT, + SGML_CATA_SGMLDECL } xmlCatalogEntryType; typedef struct _xmlCatalogEntry xmlCatalogEntry; typedef xmlCatalogEntry *xmlCatalogEntryPtr; struct _xmlCatalogEntry { + struct _xmlCatalogEntry *next; + struct _xmlCatalogEntry *parent; + struct _xmlCatalogEntry *children; xmlCatalogEntryType type; xmlChar *name; xmlChar *value; }; static xmlHashTablePtr xmlDefaultCatalog; +static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL; /* Catalog stack */ static const char * catalTab[10]; /* stack of catals */ static int catalNr = 0; /* Number of current catal streams */ static int catalMax = 10; /* Max number of catal streams */ +static int xmlDebugCatalogs = 0; /* used for debugging */ + /************************************************************************ * * * alloc or dealloc * @@ -76,7 +111,8 @@ static int catalMax = 10; /* Max number of catal streams */ ************************************************************************/ static xmlCatalogEntryPtr -xmlNewCatalogEntry(int type, xmlChar *name, xmlChar *value) { +xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name, + const xmlChar *value) { xmlCatalogEntryPtr ret; ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry)); @@ -85,16 +121,30 @@ xmlNewCatalogEntry(int type, xmlChar *name, xmlChar *value) { "malloc of %d byte failed\n", sizeof(xmlCatalogEntry)); return(NULL); } + ret->next = NULL; + ret->parent = NULL; + ret->children = NULL; ret->type = type; - ret->name = xmlStrdup(name); - ret->value = xmlStrdup(value); + if (name != NULL) + ret->name = xmlStrdup(name); + else + ret->name = NULL; + if (value != NULL) + ret->value = xmlStrdup(value); + else + ret->value = NULL; return(ret); } static void +xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret); + +static void xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) { if (ret == NULL) return; + if (ret->children != NULL) + xmlFreeCatalogEntryList(ret->children); if (ret->name != NULL) xmlFree(ret->name); if (ret->value != NULL) @@ -102,6 +152,17 @@ xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) { xmlFree(ret); } +static void +xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) { + xmlCatalogEntryPtr next; + + while (ret != NULL) { + next = ret->next; + xmlFreeCatalogEntry(ret); + ret = next; + } +} + /** * xmlCatalogDumpEntry: * @entry: the @@ -114,60 +175,60 @@ xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) { if ((entry == NULL) || (out == NULL)) return; switch (entry->type) { - case XML_CATA_ENTITY: + case SGML_CATA_ENTITY: fprintf(out, "ENTITY "); break; - case XML_CATA_PENTITY: + case SGML_CATA_PENTITY: fprintf(out, "ENTITY %%"); break; - case XML_CATA_DOCTYPE: + case SGML_CATA_DOCTYPE: fprintf(out, "DOCTYPE "); break; - case XML_CATA_LINKTYPE: + case SGML_CATA_LINKTYPE: fprintf(out, "LINKTYPE "); break; - case XML_CATA_NOTATION: + case SGML_CATA_NOTATION: fprintf(out, "NOTATION "); break; - case XML_CATA_PUBLIC: + case SGML_CATA_PUBLIC: fprintf(out, "PUBLIC "); break; - case XML_CATA_SYSTEM: + case SGML_CATA_SYSTEM: fprintf(out, "SYSTEM "); break; - case XML_CATA_DELEGATE: + case SGML_CATA_DELEGATE: fprintf(out, "DELEGATE "); break; - case XML_CATA_BASE: + case SGML_CATA_BASE: fprintf(out, "BASE "); break; - case XML_CATA_CATALOG: + case SGML_CATA_CATALOG: fprintf(out, "CATALOG "); break; - case XML_CATA_DOCUMENT: + case SGML_CATA_DOCUMENT: fprintf(out, "DOCUMENT "); break; - case XML_CATA_SGMLDECL: + case SGML_CATA_SGMLDECL: fprintf(out, "SGMLDECL "); break; default: return; } switch (entry->type) { - case XML_CATA_ENTITY: - case XML_CATA_PENTITY: - case XML_CATA_DOCTYPE: - case XML_CATA_LINKTYPE: - case XML_CATA_NOTATION: + case SGML_CATA_ENTITY: + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: fprintf(out, "%s", entry->name); break; - case XML_CATA_PUBLIC: - case XML_CATA_SYSTEM: - case XML_CATA_SGMLDECL: - case XML_CATA_DOCUMENT: - case XML_CATA_CATALOG: - case XML_CATA_BASE: - case XML_CATA_DELEGATE: + case SGML_CATA_PUBLIC: + case SGML_CATA_SYSTEM: + case SGML_CATA_SGMLDECL: + case SGML_CATA_DOCUMENT: + case SGML_CATA_CATALOG: + case SGML_CATA_BASE: + case SGML_CATA_DELEGATE: fprintf(out, "\"%s\"", entry->name); break; default: break; } switch (entry->type) { - case XML_CATA_ENTITY: - case XML_CATA_PENTITY: - case XML_CATA_DOCTYPE: - case XML_CATA_LINKTYPE: - case XML_CATA_NOTATION: - case XML_CATA_PUBLIC: - case XML_CATA_SYSTEM: - case XML_CATA_DELEGATE: + case SGML_CATA_ENTITY: + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: + case SGML_CATA_PUBLIC: + case SGML_CATA_SYSTEM: + case SGML_CATA_DELEGATE: fprintf(out, " \"%s\"", entry->value); break; default: break; @@ -177,7 +238,498 @@ xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) { /************************************************************************ * * - * The parser * + * The XML Catalog parser * + * * + ************************************************************************/ + +static xmlCatalogEntryPtr +xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename); + +static xmlCatalogEntryPtr +xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer, + const char *file); +static void +xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr parent); + +static xmlCatalogEntryType +xmlGetXMLCatalogEntryType(const xmlChar *name) { + xmlCatalogEntryType type = XML_CATA_NONE; + if (xmlStrEqual(name, (const xmlChar *) "system")) + type = XML_CATA_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "public")) + type = XML_CATA_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem")) + type = XML_CATA_REWRITE_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic")) + type = XML_CATA_DELEGATE_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem")) + type = XML_CATA_DELEGATE_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "uri")) + type = XML_CATA_URI; + else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI")) + type = XML_CATA_REWRITE_URI; + else if (xmlStrEqual(name, (const xmlChar *) "delegateURI")) + type = XML_CATA_DELEGATE_URI; + else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog")) + type = XML_CATA_NEXT_CATALOG; + else if (xmlStrEqual(name, (const xmlChar *) "catalog")) + type = XML_CATA_CATALOG; + return(type); +} + +static xmlCatalogEntryPtr +xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type, + const xmlChar *name, const xmlChar *attrName, + const xmlChar *uriAttrName) { + int ok = 1; + xmlChar *uriValue; + xmlChar *nameValue = NULL; + xmlChar *base = NULL; + xmlChar *URL = NULL; + xmlCatalogEntryPtr ret = NULL; + + if (attrName != NULL) { + nameValue = xmlGetProp(cur, attrName); + if (nameValue == NULL) { + xmlGenericError(xmlGenericErrorContext, + "%s entry lacks '%s'\n", name, attrName); + ok = 0; + } + } + uriValue = xmlGetProp(cur, uriAttrName); + if (uriValue == NULL) { + xmlGenericError(xmlGenericErrorContext, + "%s entry lacks '%s'\n", name, uriAttrName); + ok = 0; + } + if (!ok) { + if (nameValue != NULL) + xmlFree(nameValue); + if (uriValue != NULL) + xmlFree(uriValue); + return(NULL); + } + + base = xmlNodeGetBase(cur->doc, cur); + URL = xmlBuildURI(uriValue, base); + if (URL != NULL) { + if (xmlDebugCatalogs) { + if (nameValue != NULL) + printf("Found %s: '%s' '%s'\n", name, nameValue, URL); + else + printf("Found %s: '%s'\n", name, URL); + } + ret = xmlNewCatalogEntry(type, nameValue, URL); + } else { + xmlGenericError(xmlGenericErrorContext, + "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue); + } + if (nameValue != NULL) + xmlFree(nameValue); + if (uriValue != NULL) + xmlFree(uriValue); + if (base != NULL) + xmlFree(base); + if (URL != NULL) + xmlFree(URL); + return(ret); +} + +static void +xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr parent) +{ + xmlChar *uri = NULL; + xmlChar *URL = NULL; + xmlChar *base = NULL; + xmlCatalogEntryPtr entry = NULL; + + if (cur == NULL) + return; + if (xmlStrEqual(cur->name, BAD_CAST "group")) { + xmlChar *prop; + + prop = xmlGetProp(cur, BAD_CAST "prefer"); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST "system")) { + prefer = XML_CATA_PREFER_SYSTEM; + } else if (xmlStrEqual(prop, BAD_CAST "public")) { + prefer = XML_CATA_PREFER_PUBLIC; + } else { + xmlGenericError(xmlGenericErrorContext, + "Invalid value for prefer: '%s'\n", prop); + } + xmlFree(prop); + } + /* + * Recurse to propagate prefer to the subtree + * (xml:base handling is automated) + */ + xmlParseXMLCatalogNodeList(cur->children, prefer, parent); + } else if (xmlStrEqual(cur->name, BAD_CAST "public")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC, + BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri"); + } else if (xmlStrEqual(cur->name, BAD_CAST "system")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM, + BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri"); + } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM, + BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString", + BAD_CAST "rewritePrefix"); + } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC, + BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString", + BAD_CAST "catalog"); + } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM, + BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString", + BAD_CAST "catalog"); + } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI, + BAD_CAST "uri", BAD_CAST "name", + BAD_CAST "uri"); + } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI, + BAD_CAST "rewriteURI", BAD_CAST "uriStartString", + BAD_CAST "rewritePrefix"); + } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI, + BAD_CAST "delegateURI", BAD_CAST "uriStartString", + BAD_CAST "catalog"); + } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG, + BAD_CAST "nextCatalog", NULL, + BAD_CAST "catalog"); + } + if ((entry != NULL) && (parent != NULL)) { + entry->parent = parent; + if (parent->children == NULL) + parent->children = entry; + else { + xmlCatalogEntryPtr prev; + + prev = parent->children; + while (prev->next != NULL) + prev = prev->next; + prev->next = entry; + } + } + if (base != NULL) + xmlFree(base); + if (uri != NULL) + xmlFree(uri); + if (URL != NULL) + xmlFree(URL); +} + +static void +xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr parent) { + while (cur != NULL) { + if ((cur->ns != NULL) && (cur->ns->href != NULL) && + (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { + xmlParseXMLCatalogNode(cur, prefer, parent); + } + cur = cur->next; + } + /* TODO: sort the list according to REWRITE lengths and prefer value */ +} + +static xmlCatalogEntryPtr +xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer, + const char *file) { + xmlDocPtr doc; + xmlNodePtr cur; + xmlChar *prop; + xmlCatalogEntryPtr parent = NULL; + + if ((value == NULL) || (file == NULL)) + return(NULL); + + doc = xmlParseDoc((xmlChar *) value); + if (doc == NULL) + return(NULL); + doc->URL = xmlStrdup((const xmlChar *) file); + + cur = xmlDocGetRootElement(doc); + if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) && + (cur->ns != NULL) && (cur->ns->href != NULL) && + (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { + + parent = xmlNewCatalogEntry(XML_CATA_CATALOG, + (const xmlChar *)file, NULL); + if (parent == NULL) { + xmlFreeDoc(doc); + return(NULL); + } + + prop = xmlGetProp(cur, BAD_CAST "prefer"); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST "system")) { + prefer = XML_CATA_PREFER_SYSTEM; + } else if (xmlStrEqual(prop, BAD_CAST "public")) { + prefer = XML_CATA_PREFER_PUBLIC; + } else { + xmlGenericError(xmlGenericErrorContext, + "Invalid value for prefer: '%s'\n", + prop); + } + xmlFree(prop); + } + cur = cur->children; + xmlParseXMLCatalogNodeList(cur, prefer, parent); + } else { + xmlGenericError(xmlGenericErrorContext, + "File %s is not an XML Catalog\n", file); + xmlFreeDoc(doc); + return(NULL); + } + xmlFreeDoc(doc); + return(parent); +} + +static xmlCatalogEntryPtr +xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) { + xmlDocPtr doc; + xmlNodePtr cur; + xmlChar *prop; + xmlCatalogEntryPtr parent = NULL; + + if (filename == NULL) + return(NULL); + + doc = xmlParseFile((const char *) filename); + if (doc == NULL) + return(NULL); + + cur = xmlDocGetRootElement(doc); + if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) && + (cur->ns != NULL) && (cur->ns->href != NULL) && + (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { + + parent = xmlNewCatalogEntry(XML_CATA_CATALOG, + (const xmlChar *)filename, NULL); + if (parent == NULL) { + xmlFreeDoc(doc); + return(NULL); + } + + prop = xmlGetProp(cur, BAD_CAST "prefer"); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST "system")) { + prefer = XML_CATA_PREFER_SYSTEM; + } else if (xmlStrEqual(prop, BAD_CAST "public")) { + prefer = XML_CATA_PREFER_PUBLIC; + } else { + xmlGenericError(xmlGenericErrorContext, + "Invalid value for prefer: '%s'\n", + prop); + } + xmlFree(prop); + } + cur = cur->children; + xmlParseXMLCatalogNodeList(cur, prefer, parent); + } else { + xmlGenericError(xmlGenericErrorContext, + "File %s is not an XML Catalog\n", filename); + xmlFreeDoc(doc); + return(NULL); + } + xmlFreeDoc(doc); + return(parent); +} + +static int +xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) { + int ret; + xmlDocPtr doc; + xmlNsPtr ns; + xmlDtdPtr dtd; + xmlNodePtr node, catalog; + xmlOutputBufferPtr buf; + xmlCatalogEntryPtr cur; + + /* + * Rebuild a catalog + */ + doc = xmlNewDoc(NULL); + if (doc == NULL) + return(-1); + dtd = xmlNewDtd(doc, BAD_CAST "catalog", + BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN", +BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"); + + xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd); + + ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL); + if (ns == NULL) { + xmlFreeDoc(doc); + return(-1); + } + catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL); + if (catalog == NULL) { + xmlFreeNs(ns); + xmlFreeDoc(doc); + return(-1); + } + catalog->nsDef = ns; + xmlAddChild((xmlNodePtr) doc, catalog); + + /* + * add all the catalog entries + */ + cur = catal; + while (cur != NULL) { + switch (cur->type) { + case XML_CATA_CATALOG: + if (cur == catal) { + cur = cur->children; + continue; + } + break; + case XML_CATA_NEXT_CATALOG: + node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_NONE: + break; + case XML_CATA_PUBLIC: + node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL); + xmlSetProp(node, BAD_CAST "publicId", cur->name); + xmlSetProp(node, BAD_CAST "uri", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_SYSTEM: + node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL); + xmlSetProp(node, BAD_CAST "systemId", cur->name); + xmlSetProp(node, BAD_CAST "uri", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_REWRITE_SYSTEM: + node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL); + xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); + xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_DELEGATE_PUBLIC: + node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL); + xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_DELEGATE_SYSTEM: + node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL); + xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_URI: + node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL); + xmlSetProp(node, BAD_CAST "name", cur->name); + xmlSetProp(node, BAD_CAST "uri", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_REWRITE_URI: + node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL); + xmlSetProp(node, BAD_CAST "uriStartString", cur->name); + xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_DELEGATE_URI: + node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL); + xmlSetProp(node, BAD_CAST "uriStartString", cur->name); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case SGML_CATA_SYSTEM: + case SGML_CATA_PUBLIC: + case SGML_CATA_ENTITY: + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: + case SGML_CATA_DELEGATE: + case SGML_CATA_BASE: + case SGML_CATA_CATALOG: + case SGML_CATA_DOCUMENT: + case SGML_CATA_SGMLDECL: + break; + } + cur = cur->next; + } + + /* + * reserialize it + */ + buf = xmlOutputBufferCreateFile(out, NULL); + if (buf == NULL) { + xmlFreeDoc(doc); + return(-1); + } + ret = xmlSaveFormatFileTo(buf, doc, NULL, 1); + + /* + * Free it + */ + xmlFreeDoc(doc); + + return(ret); +} + +/** + * xmlAddXMLCatalog: + * @catal: top of an XML catalog + * @type: the type of record to add to the catalog + * @orig: the system, public or prefix to match + * @replace: the replacement value for the match + * + * Add an entry in the XML catalog, it may overwrite existing but + * different entries. + * + * Returns 0 if successful, -1 otherwise + */ +static int +xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, + const xmlChar *orig, const xmlChar *replace) { + xmlCatalogEntryPtr cur; + xmlCatalogEntryType typ; + + if ((catal == NULL) || (catal->type != XML_CATA_CATALOG)) + return(-1); + typ = xmlGetXMLCatalogEntryType(type); + if (typ == XML_CATA_NONE) + return(-1); + + cur = catal->children; + /* + * Might be a simple "update in place" + */ + if (cur != NULL) { + while (cur != NULL) { + cur = cur->next; + if ((cur->type == typ) && (xmlStrEqual(orig, cur->name))) { + if (cur->value != NULL) + xmlFree(cur->value); + cur->value = xmlStrdup(replace); + return(1); + } + if (cur->next == NULL) + break; + cur = cur->next; + } + } + if (cur == NULL) + catal->children = xmlNewCatalogEntry(typ, orig, replace); + else + cur->next = xmlNewCatalogEntry(typ, orig, replace); + return(1); +} + +/************************************************************************ + * * + * The SGML Catalog parser * * * ************************************************************************/ @@ -290,6 +842,36 @@ xmlParseCatalogName(const xmlChar *cur, xmlChar **name) { return(cur); } +static xmlCatalogEntryType +xmlGetCatalogEntryType(const xmlChar *name) { + xmlCatalogEntryType type = XML_CATA_NONE; + if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) + type = SGML_CATA_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) + type = SGML_CATA_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) + type = SGML_CATA_DELEGATE; + else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) + type = SGML_CATA_ENTITY; + else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) + type = SGML_CATA_DOCTYPE; + else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) + type = SGML_CATA_LINKTYPE; + else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) + type = SGML_CATA_NOTATION; + else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) + type = SGML_CATA_SGMLDECL; + else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) + type = SGML_CATA_DOCUMENT; + else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) + type = SGML_CATA_CATALOG; + else if (xmlStrEqual(name, (const xmlChar *) "BASE")) + type = SGML_CATA_BASE; + else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) + type = SGML_CATA_DELEGATE; + return(type); +} + static int xmlParseCatalog(const xmlChar *value, const char *file) { const xmlChar *cur = value; @@ -324,29 +906,29 @@ xmlParseCatalog(const xmlChar *value, const char *file) { } SKIP_BLANKS; if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) - type = XML_CATA_SYSTEM; + type = SGML_CATA_SYSTEM; else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) - type = XML_CATA_PUBLIC; + type = SGML_CATA_PUBLIC; else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) - type = XML_CATA_DELEGATE; + type = SGML_CATA_DELEGATE; else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) - type = XML_CATA_ENTITY; + type = SGML_CATA_ENTITY; else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) - type = XML_CATA_DOCTYPE; + type = SGML_CATA_DOCTYPE; else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) - type = XML_CATA_LINKTYPE; + type = SGML_CATA_LINKTYPE; else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) - type = XML_CATA_NOTATION; + type = SGML_CATA_NOTATION; else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) - type = XML_CATA_SGMLDECL; + type = SGML_CATA_SGMLDECL; else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) - type = XML_CATA_DOCUMENT; + type = SGML_CATA_DOCUMENT; else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) - type = XML_CATA_CATALOG; + type = SGML_CATA_CATALOG; else if (xmlStrEqual(name, (const xmlChar *) "BASE")) - type = XML_CATA_BASE; + type = SGML_CATA_BASE; else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) - type = XML_CATA_DELEGATE; + type = SGML_CATA_DELEGATE; else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) { xmlFree(name); cur = xmlParseCatalogName(cur, &name); @@ -361,13 +943,13 @@ xmlParseCatalog(const xmlChar *value, const char *file) { name = NULL; switch(type) { - case XML_CATA_ENTITY: + case SGML_CATA_ENTITY: if (*cur == '%') - type = XML_CATA_PENTITY; - case XML_CATA_PENTITY: - case XML_CATA_DOCTYPE: - case XML_CATA_LINKTYPE: - case XML_CATA_NOTATION: + type = SGML_CATA_PENTITY; + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: cur = xmlParseCatalogName(cur, &name); if (cur == NULL) { /* error */ @@ -384,9 +966,9 @@ xmlParseCatalog(const xmlChar *value, const char *file) { break; } break; - case XML_CATA_PUBLIC: - case XML_CATA_SYSTEM: - case XML_CATA_DELEGATE: + case SGML_CATA_PUBLIC: + case SGML_CATA_SYSTEM: + case SGML_CATA_DELEGATE: cur = xmlParseCatalogPubid(cur, &name); if (cur == NULL) { /* error */ @@ -403,10 +985,10 @@ xmlParseCatalog(const xmlChar *value, const char *file) { break; } break; - case XML_CATA_BASE: - case XML_CATA_CATALOG: - case XML_CATA_DOCUMENT: - case XML_CATA_SGMLDECL: + case SGML_CATA_BASE: + case SGML_CATA_CATALOG: + case SGML_CATA_DOCUMENT: + case SGML_CATA_SGMLDECL: cur = xmlParseCatalogPubid(cur, &sysid); if (cur == NULL) { /* error */ @@ -422,12 +1004,12 @@ xmlParseCatalog(const xmlChar *value, const char *file) { if (sysid != NULL) xmlFree(sysid); break; - } else if (type == XML_CATA_BASE) { + } else if (type == SGML_CATA_BASE) { if (base != NULL) xmlFree(base); base = xmlStrdup(sysid); - } else if ((type == XML_CATA_PUBLIC) || - (type == XML_CATA_SYSTEM)) { + } else if ((type == SGML_CATA_PUBLIC) || + (type == SGML_CATA_SYSTEM)) { xmlChar *filename; filename = xmlBuildURI(sysid, base); @@ -442,7 +1024,7 @@ xmlParseCatalog(const xmlChar *value, const char *file) { xmlFree(filename); } - } else if (type == XML_CATA_CATALOG) { + } else if (type == SGML_CATA_CATALOG) { xmlChar *filename; filename = xmlBuildURI(sysid, base); @@ -542,7 +1124,27 @@ xmlLoadCatalog(const char *filename) { content[len] = 0; close(fd); - ret = xmlParseCatalog(content, filename); + if ((content[0] == ' ') || (content[0] == '-') || + ((content[0] >= 'A') && (content[0] <= 'Z')) || + ((content[0] >= 'a') && (content[0] <= 'z'))) + ret = xmlParseCatalog(content, filename); + else { + xmlCatalogEntryPtr catal, tmp; + /* TODO: allow to switch the default preference */ + catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename); + if (catal != NULL) { + if (xmlDefaultXMLCatalogList == NULL) + xmlDefaultXMLCatalogList = catal; + else { + tmp = xmlDefaultXMLCatalogList; + while (tmp->next != NULL) + tmp = tmp->next; + tmp->next = catal; + } + ret = 0; + } else + ret = -1; + } xmlFree(content); catalNr--; return(ret); @@ -611,13 +1213,14 @@ xmlCatalogGetSystem(const xmlChar *sysID) { entry = (xmlCatalogEntryPtr) xmlHashLookup(xmlDefaultCatalog, sysID); if (entry == NULL) return(NULL); - if (entry->type == XML_CATA_SYSTEM) + if (entry->type == SGML_CATA_SYSTEM) return(entry->value); return(NULL); } /** - * xmlCatalogGetPublic: + * xmlCatalogGetXMLPublic: + * @catal: an XML catalog * @pubId: the public ID string * * Try to lookup the system ID associated to a public ID @@ -625,18 +1228,112 @@ xmlCatalogGetSystem(const xmlChar *sysID) { * Returns the system ID if found or NULL otherwise. */ const xmlChar * -xmlCatalogGetPublic(const xmlChar *pubID) { +xmlCatalogGetXMLPublic(xmlCatalogEntryPtr catal, const xmlChar *pubID) { + const xmlChar *ret; + while (catal != NULL) { + switch (catal->type) { + case XML_CATA_CATALOG: + if (catal->children == NULL) { + TODO /* fetch and fill */ + } + ret = xmlCatalogGetXMLPublic(catal->children, pubID); + if (ret != NULL) + return(ret); + break; + case XML_CATA_NEXT_CATALOG: + if (catal->children == NULL) { + TODO /* fetch and fill */ + } + case XML_CATA_PUBLIC: + if (xmlStrEqual(pubID, catal->name)) + return(catal->value); + break; + case XML_CATA_SYSTEM: + case XML_CATA_REWRITE_SYSTEM: + case XML_CATA_DELEGATE_PUBLIC: + case XML_CATA_DELEGATE_SYSTEM: + case XML_CATA_URI: + case XML_CATA_REWRITE_URI: + case XML_CATA_DELEGATE_URI: + TODO; + break; + + case XML_CATA_NONE: + case SGML_CATA_SYSTEM: + case SGML_CATA_PUBLIC: + case SGML_CATA_ENTITY: + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: + case SGML_CATA_DELEGATE: + case SGML_CATA_BASE: + case SGML_CATA_CATALOG: + case SGML_CATA_DOCUMENT: + case SGML_CATA_SGMLDECL: + /* Ignored entries */ + break; + } + catal = catal->next; + } + return(NULL); +} + +/** + * xmlCatalogGetSGMLPublic: + * @catal: an SGML catalog hash + * @pubId: the public ID string + * + * Try to lookup the system ID associated to a public ID + * + * Returns the system ID if found or NULL otherwise. + */ +static const xmlChar * +xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) { xmlCatalogEntryPtr entry; - if ((pubID == NULL) || (xmlDefaultCatalog == NULL)) + if (catal == NULL) return(NULL); - entry = (xmlCatalogEntryPtr) xmlHashLookup(xmlDefaultCatalog, pubID); + + entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID); if (entry == NULL) return(NULL); - if (entry->type == XML_CATA_PUBLIC) + if (entry->type == SGML_CATA_PUBLIC) return(entry->value); return(NULL); } + +/** + * xmlCatalogGetPublic: + * @pubId: the public ID string + * + * Try to lookup the system ID associated to a public ID + * + * Returns the system ID if found or NULL otherwise. + */ +const xmlChar * +xmlCatalogGetPublic(const xmlChar *pubID) { + xmlCatalogEntryPtr catal; + const xmlChar *ret; + + if (pubID == NULL) + return(NULL); + + /* + * Check first the XML catalogs + */ + catal = xmlDefaultXMLCatalogList; + if (catal != NULL) { + ret = xmlCatalogGetXMLPublic(catal, pubID); + if (ret != NULL) + return(ret); + } + + if (xmlDefaultCatalog != NULL) + return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID)); + return(NULL); +} + /** * xmlCatalogDump: * @out: the file. @@ -647,9 +1344,74 @@ void xmlCatalogDump(FILE *out) { if (out == NULL) return; - if (xmlDefaultCatalog != NULL) { + + if (xmlDefaultXMLCatalogList != NULL) { + xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList); + } else if (xmlDefaultCatalog != NULL) { xmlHashScan(xmlDefaultCatalog, (xmlHashScanner) xmlCatalogDumpEntry, out); - } + } +} + +/** + * xmlCatalogAdd: + * @type: the type of record to add to the catalog + * @orig: the system, public or prefix to match + * @replace: the replacement value for the match + * + * Add an entry in the catalog, it may overwrite existing but + * different entries. + * + * Returns 0 if successful, -1 otherwise + */ +int +xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) { + int res = -1; + + if (xmlDefaultXMLCatalogList != NULL) { + res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace); + } else if (xmlDefaultCatalog != NULL) { + xmlCatalogEntryType typ; + + typ = xmlGetCatalogEntryType(type); + if (type != XML_CATA_NONE) { + xmlCatalogEntryPtr entry; + entry = xmlNewCatalogEntry(typ, orig, replace); + res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry); + } + } + return(res); +} + +/** + * xmlCatalogRemove: + * @value: the value to remove + * + * Remove an entry from the catalog + * + * Returns 0 if successful, -1 otherwise + */ +int +xmlCatalogRemove(const xmlChar *value) { +} + +/** + * xmlCatalogSetDebug: + * @level: the debug level of catalogs required + * + * Used to set the debug level for catalog operation, 0 disable + * debugging, 1 enable it + * + * Returns the previous value of the catalog debugging level + */ +int +xmlCatalogSetDebug(int level) { + int ret = xmlDebugCatalogs; + + if (level <= 0) + xmlDebugCatalogs = 0; + else + xmlDebugCatalogs = level; + return(ret); } #endif /* LIBXML_CATALOG_ENABLED */ |