Skip to content
Snippets Groups Projects
catalog.c 96.7 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * catalog.c: set of generic Catalog related routines
    
     *
     * 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
     */
    
    
    #include "libxml.h"
    
    #ifdef LIBXML_CATALOG_ENABLED
    
    #include <stdlib.h>
    #include <string.h>
    
    #ifdef HAVE_SYS_TYPES_H
    #include <sys/types.h>
    #endif
    #ifdef HAVE_SYS_STAT_H
    #include <sys/stat.h>
    #endif
    #ifdef HAVE_UNISTD_H
    #include <unistd.h>
    #endif
    #ifdef HAVE_FCNTL_H
    #include <fcntl.h>
    #endif
    #include <libxml/xmlmemory.h>
    #include <libxml/hash.h>
    #include <libxml/uri.h>
    #include <libxml/parserInternals.h>
    #include <libxml/catalog.h>
    #include <libxml/xmlerror.h>
    
    # define PATH_SEPARATOR ';'
    
    # define PATH_SEPARATOR ':'
    
    /**
     * TODO:
     *
     * macro to flag unimplemented blocks
    
     * XML_CATALOG_PREFER user env to select between system/public preferred
    
     * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
     *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
     *> values "system" and "public".  I have made the default be "system" to
     *> match yours.
    
    #define TODO								\
    
        xmlGenericError(xmlGenericErrorContext,				\
    	    "Unimplemented block at %s:%d\n",				\
                __FILE__, __LINE__);
    
    
    #define XML_URN_PUBID "urn:publicid:"
    
    #define XML_CATAL_BREAK ((xmlChar *) -1)
    
    #define XML_XML_DEFAULT_CATALOG "file://" SYSCONFDIR "/xml/catalog"
    
    #define XML_SGML_DEFAULT_CATALOG "file://" SYSCONFDIR "/sgml/catalog"
    
    #if defined(_WIN32) && defined(_MSC_VER)
    #undef XML_XML_DEFAULT_CATALOG
    
    static char XML_XML_DEFAULT_CATALOG[256] = "file://" SYSCONFDIR "/xml/catalog";
    
    #if !defined(_WINDOWS_)
    
    void* __stdcall GetModuleHandleA(const char*);
    unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
    #endif
    
    static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
    
    static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
    
    /************************************************************************
     *									*
     *			Types, all private				*
     *									*
     ************************************************************************/
    
    typedef enum {
    
        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;
    
        xmlChar *URL;  /* The expanded URL using the base */
    
    typedef enum {
        XML_XML_CATALOG_TYPE = 1,
        XML_SGML_CATALOG_TYPE
    } xmlCatalogType;
    
    #define XML_MAX_SGML_CATA_DEPTH 10
    struct _xmlCatalog {
        xmlCatalogType type;	/* either XML or SGML */
    
        /*
         * SGML Catalogs are stored as a simple hash table of catalog entries
         * Catalog stack to check against overflows when building the
         * SGML catalog
         */
        char *catalTab[XML_MAX_SGML_CATA_DEPTH];	/* stack of catals */
        int          catalNr;	/* Number of current catal streams */
        int          catalMax;	/* Max number of catal streams */
        xmlHashTablePtr sgml;
    
        /*
         * XML Catalogs are stored as a tree of Catalog entries
         */
        xmlCatalogPrefer prefer;
        xmlCatalogEntryPtr xml;
    };
    
    /************************************************************************
     *									*
     *			Global variables				*
     *									*
     ************************************************************************/
    
    
    /*
     * Those are preferences
     */
    static int xmlDebugCatalogs = 0;   /* used for debugging */
    
    static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
    
    static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
    
    
    /*
     * Hash table containing all the trees of XML catalogs parsed by
     * the application.
     */
    
    static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
    
    
    /*
     * The default catalog in use by the application
     */
    static xmlCatalogPtr xmlDefaultCatalog = NULL;
    
    /*
    
     * A mutex for modifying the shared global catalog(s)
     * xmlDefaultCatalog tree.
     * It also protects xmlCatalogXMLFiles
     * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
     */
    static xmlRMutexPtr xmlCatalogMutex = NULL;
    
    /*
    
     * Whether the catalog support was initialized.
     */
    
    /************************************************************************
     *									*
    
     *			Catalog error handlers				*
    
     *									*
     ************************************************************************/
    
    /**
     * xmlCatalogErrMemory:
    
    Nick Wellnhofer's avatar
    Nick Wellnhofer committed
     * @extra:  extra information
    
     *
     * Handle an out of memory condition
     */
    static void
    xmlCatalogErrMemory(const char *extra)
    {
    
        __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
    
                        XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
    		    extra, NULL, NULL, 0, 0,
    		    "Memory allocation failed : %s\n", extra);
    }
    
    /**
     * xmlCatalogErr:
     * @catal: the Catalog entry
     * @node: the context node
     * @msg:  the error message
    
    Nick Wellnhofer's avatar
    Nick Wellnhofer committed
     * @extra:  extra information
    
    static void LIBXML_ATTR_FORMAT(4,0)
    
    xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
                   const char *msg, const xmlChar *str1, const xmlChar *str2,
    	       const xmlChar *str3)
    {
    
        __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
    
                        error, XML_ERR_ERROR, NULL, 0,
    		    (const char *) str1, (const char *) str2,
    		    (const char *) str3, 0, 0,
    		    msg, str1, str2, str3);
    }
    
    
    
    /************************************************************************
     *									*
    
     *									*
     ************************************************************************/
    
    
    /**
     * xmlNewCatalogEntry:
     * @type:  type of entry
     * @name:  name of the entry
     * @value:  value of the entry
     * @prefer:  the PUBLIC vs. SYSTEM current preference value
    
     * @group:  for members of a group, the group entry
    
     * create a new Catalog entry, this type is shared both by XML and
    
     * SGML catalogs, but the acceptable types values differs.
     *
     * Returns the xmlCatalogEntryPtr or NULL in case of error
     */
    
    xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
    
    	   const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
    	   xmlCatalogEntryPtr group) {
    
    
        ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
        if (ret == NULL) {
    
            xmlCatalogErrMemory("allocating catalog entry");
    
        ret->next = NULL;
        ret->parent = NULL;
        ret->children = NULL;
    
        if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
            normid = xmlCatalogNormalizePublic(name);
            if (normid != NULL)
                name = (*normid != 0 ? normid : NULL);
        }
    
        if (name != NULL)
    	ret->name = xmlStrdup(name);
        else
    	ret->name = NULL;
    
        if (value != NULL)
    	ret->value = xmlStrdup(value);
        else
    	ret->value = NULL;
    
        if (URL == NULL)
    	URL = value;
        if (URL != NULL)
    	ret->URL = xmlStrdup(URL);
        else
    	ret->URL = NULL;
    
    xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
    
    
     * @payload:  a Catalog entry
    
     *
     * Free the memory allocated to a Catalog entry
     */
    
    xmlFreeCatalogEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
        xmlCatalogEntryPtr ret = (xmlCatalogEntryPtr) payload;
    
         * Entries stored in the file hash must be deallocated
    
         * only by the file hash cleaner !
         */
        if (ret->dealloc == 1)
    	return;
    
        if (xmlDebugCatalogs) {
    	if (ret->name != NULL)
    	    xmlGenericError(xmlGenericErrorContext,
    		    "Free catalog entry %s\n", ret->name);
    	else if (ret->value != NULL)
    	    xmlGenericError(xmlGenericErrorContext,
    		    "Free catalog entry %s\n", ret->value);
    	else
    	    xmlGenericError(xmlGenericErrorContext,
    		    "Free catalog entry\n");
        }
    
    
        if (ret->name != NULL)
    	xmlFree(ret->name);
        if (ret->value != NULL)
    	xmlFree(ret->value);
    
        if (ret->URL != NULL)
    	xmlFree(ret->URL);
    
    /**
     * xmlFreeCatalogEntryList:
     * @ret:  a Catalog entry list
     *
     * Free the memory allocated to a full chained list of Catalog entries
     */
    
    static void
    xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
        xmlCatalogEntryPtr next;
    
        while (ret != NULL) {
    	next = ret->next;
    
    	xmlFreeCatalogEntry(ret, NULL);
    
     * @payload:  a Catalog entry list
    
     *
     * Free the memory allocated to list of Catalog entries from the
     * catalog file hash.
     */
    static void
    
    xmlFreeCatalogHashEntryList(void *payload,
                                const xmlChar *name ATTRIBUTE_UNUSED) {
        xmlCatalogEntryPtr catal = (xmlCatalogEntryPtr) payload;
    
        xmlCatalogEntryPtr children, next;
    
        if (catal == NULL)
    	return;
    
        children = catal->children;
        while (children != NULL) {
    	next = children->next;
    	children->dealloc = 0;
    	children->children = NULL;
    
    	xmlFreeCatalogEntry(children, NULL);
    
        xmlFreeCatalogEntry(catal, NULL);
    
     * @type:  type of catalog
     * @prefer:  the PUBLIC vs. SYSTEM current preference value
     *
    
     * create a new Catalog, this type is shared both by XML and
    
     * SGML catalogs, but the acceptable types values differs.
     *
     * Returns the xmlCatalogPtr or NULL in case of error
     */
    static xmlCatalogPtr
    
    xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
    
        xmlCatalogPtr ret;
    
        ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
        if (ret == NULL) {
    
            xmlCatalogErrMemory("allocating catalog");
    
    	return(NULL);
        }
        memset(ret, 0, sizeof(xmlCatalog));
        ret->type = type;
        ret->catalNr = 0;
        ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
        ret->prefer = prefer;
    
        if (ret->type == XML_SGML_CATALOG_TYPE)
    	ret->sgml = xmlHashCreate(10);
    
     *
     * Free the memory allocated to a Catalog
     */
    void
    xmlFreeCatalog(xmlCatalogPtr catal) {
        if (catal == NULL)
    	return;
        if (catal->xml != NULL)
    	xmlFreeCatalogEntryList(catal->xml);
        if (catal->sgml != NULL)
    
    	xmlHashFree(catal->sgml, xmlFreeCatalogEntry);
    
        xmlFree(catal);
    }
    
    /************************************************************************
     *									*
     *			Serializing Catalogs				*
     *									*
     ************************************************************************/
    
    
    xmlCatalogDumpEntry(void *payload, void *data,
                        const xmlChar *name ATTRIBUTE_UNUSED) {
        xmlCatalogEntryPtr entry = (xmlCatalogEntryPtr) payload;
        FILE *out = (FILE *) data;
    
        if ((entry == NULL) || (out == NULL))
    	return;
        switch (entry->type) {
    
    	    fprintf(out, "ENTITY "); break;
    
    	    fprintf(out, "ENTITY %%"); break;
    
    	    fprintf(out, "DOCTYPE "); break;
    
    	    fprintf(out, "LINKTYPE "); break;
    
    	    fprintf(out, "NOTATION "); break;
    
    	    fprintf(out, "PUBLIC "); break;
    
    	    fprintf(out, "SYSTEM "); break;
    
    	    fprintf(out, "DELEGATE "); break;
    
    	    fprintf(out, "BASE "); break;
    
    	    fprintf(out, "CATALOG "); break;
    
    	    fprintf(out, "DOCUMENT "); break;
    
    	    fprintf(out, "SGMLDECL "); break;
    	default:
    	    return;
        }
        switch (entry->type) {
    
    	case SGML_CATA_ENTITY:
    	case SGML_CATA_PENTITY:
    	case SGML_CATA_DOCTYPE:
    	case SGML_CATA_LINKTYPE:
    	case SGML_CATA_NOTATION:
    
    	    fprintf(out, "%s", (const char *) entry->name); break;
    
    	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 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;
        }
        fprintf(out, "\n");
    }
    
    
    /**
     * xmlDumpXMLCatalogNode:
     * @catal:  top catalog entry
     * @catalog: pointer to the xml tree
     * @doc: the containing document
     * @ns: the current namespace
     * @cgroup: group node for group members
     *
     * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
     * for group entries
     */
    static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
    		    xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
        xmlNodePtr node;
        xmlCatalogEntryPtr cur;
        /*
         * add all the catalog entries
         */
        cur = catal;
        while (cur != NULL) {
            if (cur->group == cgroup) {
    	    switch (cur->type) {
    	        case XML_CATA_REMOVED:
    		    break;
    	        case XML_CATA_BROKEN_CATALOG:
    	        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_GROUP:
    		    node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
    		    xmlSetProp(node, BAD_CAST "id", cur->name);
    
    		    if (cur->value != NULL) {
    		        xmlNsPtr xns;
    			xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
    			if (xns != NULL)
    			    xmlSetNsProp(node, xns, BAD_CAST "base",
    
    					 cur->value);
    
    		    switch (cur->prefer) {
    			case XML_CATA_PREFER_NONE:
    		            break;
    			case XML_CATA_PREFER_PUBLIC:
    		            xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
    			    break;
    			case XML_CATA_PREFER_SYSTEM:
    		            xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
    			    break;
    		    }
    		    xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
    		    xmlAddChild(catalog, node);
    	            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;
        }
    }
    
    
    static int
    xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
        int ret;
        xmlDocPtr doc;
        xmlNsPtr ns;
        xmlDtdPtr dtd;
    
        xmlOutputBufferPtr buf;
    
        /*
         * 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);
    
    
        xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
    
        /*
         * 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);
    }
    
    #endif /* LIBXML_OUTPUT_ENABLED */
    
    
    /************************************************************************
     *									*
     *			Converting SGML Catalogs to XML			*
     *									*
     ************************************************************************/
    
    
    /**
     * xmlCatalogConvertEntry:
     * @entry:  the entry
    
     * @catal:  pointer to the catalog being converted
    
     * Convert one entry from the catalog
    
    xmlCatalogConvertEntry(void *payload, void *data,
                           const xmlChar *name ATTRIBUTE_UNUSED) {
        xmlCatalogEntryPtr entry = (xmlCatalogEntryPtr) payload;
        xmlCatalogPtr catal = (xmlCatalogPtr) data;
    
        if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
    	(catal->xml == NULL))
    
    	return;
        switch (entry->type) {
    	case SGML_CATA_ENTITY:
    	    entry->type = XML_CATA_PUBLIC;
    	    break;
    	case SGML_CATA_PENTITY:
    	    entry->type = XML_CATA_PUBLIC;
    	    break;
    	case SGML_CATA_DOCTYPE:
    	    entry->type = XML_CATA_PUBLIC;
    	    break;
    	case SGML_CATA_LINKTYPE:
    	    entry->type = XML_CATA_PUBLIC;
    	    break;
    	case SGML_CATA_NOTATION:
    	    entry->type = XML_CATA_PUBLIC;
    	    break;
    	case SGML_CATA_PUBLIC:
    	    entry->type = XML_CATA_PUBLIC;
    	    break;
    	case SGML_CATA_SYSTEM:
    	    entry->type = XML_CATA_SYSTEM;
    	    break;
    	case SGML_CATA_DELEGATE:
    	    entry->type = XML_CATA_DELEGATE_PUBLIC;
    	    break;
    	case SGML_CATA_CATALOG:
    	    entry->type = XML_CATA_CATALOG;
    	    break;
    	default:
    
    	    xmlHashRemoveEntry(catal->sgml, entry->name, xmlFreeCatalogEntry);
    
    	    return;
        }
        /*
         * Conversion successful, remove from the SGML catalog
         * and add it to the default XML one
         */
    
        xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
        entry->parent = catal->xml;
    
        if (catal->xml->children == NULL)
    	catal->xml->children = entry;
    
    	while (prev->next != NULL)
    	    prev = prev->next;
    	prev->next = entry;
        }
    
    }
    
    /**
     * xmlConvertSGMLCatalog:
     * @catal: the catalog
     *
     * Convert all the SGML catalog entries as XML ones
     *
     * Returns the number of entries converted if successful, -1 otherwise
     */
    int
    xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
    
        if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
    	return(-1);
    
        if (xmlDebugCatalogs) {
    	xmlGenericError(xmlGenericErrorContext,
    		"Converting SGML catalog to XML\n");
        }
    
        xmlHashScan(catal->sgml, xmlCatalogConvertEntry, &catal);
    
    /************************************************************************
     *									*
    
     *			Helper function					*
     *									*
     ************************************************************************/
    
    /**
     * xmlCatalogUnWrapURN:
    
     * @urn:  an "urn:publicid:" to unwrap
    
     *
     * Expand the URN into the equivalent Public Identifier
     *
     * Returns the new identifier or NULL, the string must be deallocated
     *         by the caller.
     */
    static xmlChar *
    xmlCatalogUnWrapURN(const xmlChar *urn) {
        xmlChar result[2000];
        unsigned int i = 0;
    
        if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
    	return(NULL);
        urn += sizeof(XML_URN_PUBID) - 1;
    
    	    break;
    	if (*urn == '+') {
    	    result[i++] = ' ';
    	    urn++;
    	} else if (*urn == ':') {
    	    result[i++] = '/';
    	    result[i++] = '/';
    	    urn++;
    	} else if (*urn == ';') {
    	    result[i++] = ':';
    	    result[i++] = ':';
    	    urn++;
    	} else if (*urn == '%') {
    
    	    if ((urn[1] == '2') && (urn[2] == 'B'))
    
    	    else if ((urn[1] == '3') && (urn[2] == 'A'))
    
    	    else if ((urn[1] == '2') && (urn[2] == 'F'))
    
    	    else if ((urn[1] == '3') && (urn[2] == 'B'))
    
    	    else if ((urn[1] == '2') && (urn[2] == '7'))
    
    	    else if ((urn[1] == '3') && (urn[2] == 'F'))
    
    	    else if ((urn[1] == '2') && (urn[2] == '3'))
    
    	    else if ((urn[1] == '2') && (urn[2] == '5'))
    
    		result[i++] = '%';
    	    else {
    		result[i++] = *urn;
    		urn++;
    		continue;
    	    }
    	    urn += 3;
    	} else {
    	    result[i++] = *urn;
    	    urn++;
    	}
        }
        result[i] = 0;
    
        return(xmlStrdup(result));
    }
    
    
    /**
     * xmlParseCatalogFile:
     * @filename:  the filename
     *
     * parse an XML file and build a tree. It's like xmlParseFile()
     * except it bypass all catalog lookups.
     *
     * Returns the resulting document tree or NULL in case of error
     */
    
    xmlDocPtr
    xmlParseCatalogFile(const char *filename) {
        xmlDocPtr ret;
        xmlParserCtxtPtr ctxt;
        char *directory = NULL;
        xmlParserInputPtr inputStream;
        xmlParserInputBufferPtr buf;
    
        ctxt = xmlNewParserCtxt();
        if (ctxt == NULL) {
    
    	if (xmlDefaultSAXHandler.error != NULL) {
    	    xmlDefaultSAXHandler.error(NULL, "out of memory\n");
    	}
    
    	return(NULL);
        }
    
        buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
        if (buf == NULL) {
    	xmlFreeParserCtxt(ctxt);
    	return(NULL);
        }
    
        inputStream = xmlNewInputStream(ctxt);
        if (inputStream == NULL) {
    
    	xmlFreeParserInputBuffer(buf);
    
        inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
    
        xmlBufResetInput(buf->buffer, inputStream);
    
        if (ctxt->directory == NULL)
    
            directory = xmlParserGetDirectory(filename);
        if ((ctxt->directory == NULL) && (directory != NULL))
            ctxt->directory = directory;
    
        ctxt->valid = 0;
        ctxt->validate = 0;
        ctxt->loadsubset = 0;
        ctxt->pedantic = 0;
    
    
        xmlParseDocument(ctxt);
    
        if (ctxt->wellFormed)
    	ret = ctxt->myDoc;
        else {
            ret = NULL;
            xmlFreeDoc(ctxt->myDoc);
            ctxt->myDoc = NULL;
        }
        xmlFreeParserCtxt(ctxt);
    
    /**
     * xmlLoadFileContent:
     * @filename:  a file path
     *
     * Load a file content into memory.
     *
     * Returns a pointer to the 0 terminated string or NULL in case of error
     */
    static xmlChar *
    xmlLoadFileContent(const char *filename)
    {
    #ifdef HAVE_STAT
        int fd;
    #else
        FILE *fd;
    #endif
        int len;
        long size;
    
    #ifdef HAVE_STAT
        struct stat info;
    #endif
        xmlChar *content;
    
        if (filename == NULL)
            return (NULL);
    
    #ifdef HAVE_STAT
        if (stat(filename, &info) < 0)
            return (NULL);
    #endif
    
    #ifdef HAVE_STAT
    
        if ((fd = open(filename, O_RDONLY)) < 0)
    
        if ((fd = fopen(filename, "rb")) == NULL)
    
            return (NULL);
        }
    #ifdef HAVE_STAT
        size = info.st_size;
    #else
        if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) {        /* File operations denied? ok, just close and return failure */
            fclose(fd);
            return (NULL);
        }
    #endif
    
        content = (xmlChar*)xmlMallocAtomic(size + 10);
    
            xmlCatalogErrMemory("allocating catalog data");
    
    #ifdef HAVE_STAT
    	close(fd);
    #else
    	fclose(fd);
    #endif