File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / catalog.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:22:19 2013 UTC (10 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, HEAD
2.8.0

    1: /**
    2:  * catalog.c: set of generic Catalog related routines 
    3:  *
    4:  * Reference:  SGML Open Technical Resolution TR9401:1997.
    5:  *             http://www.jclark.com/sp/catalog.htm
    6:  *
    7:  *             XML Catalogs Working Draft 06 August 2001
    8:  *             http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
    9:  *
   10:  * See Copyright for the status of this software.
   11:  *
   12:  * Daniel.Veillard@imag.fr
   13:  */
   14: 
   15: #define IN_LIBXML
   16: #include "libxml.h"
   17: 
   18: #ifdef LIBXML_CATALOG_ENABLED
   19: #ifdef HAVE_SYS_TYPES_H
   20: #include <sys/types.h>
   21: #endif
   22: #ifdef HAVE_SYS_STAT_H
   23: #include <sys/stat.h>
   24: #endif
   25: #ifdef HAVE_UNISTD_H
   26: #include <unistd.h>
   27: #endif
   28: #ifdef HAVE_FCNTL_H
   29: #include <fcntl.h>
   30: #endif
   31: #ifdef HAVE_STDLIB_H
   32: #include <stdlib.h>
   33: #endif
   34: #include <string.h>
   35: #include <libxml/xmlmemory.h>
   36: #include <libxml/hash.h>
   37: #include <libxml/uri.h>
   38: #include <libxml/parserInternals.h>
   39: #include <libxml/catalog.h>
   40: #include <libxml/xmlerror.h>
   41: #include <libxml/threads.h>
   42: #include <libxml/globals.h>
   43: 
   44: #define MAX_DELEGATE	50
   45: #define MAX_CATAL_DEPTH	50
   46: 
   47: #ifdef _WIN32
   48: # define PATH_SEAPARATOR ';'
   49: #else
   50: # define PATH_SEAPARATOR ':'
   51: #endif
   52: 
   53: /**
   54:  * TODO:
   55:  *
   56:  * macro to flag unimplemented blocks
   57:  * XML_CATALOG_PREFER user env to select between system/public prefered
   58:  * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
   59:  *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
   60:  *> values "system" and "public".  I have made the default be "system" to
   61:  *> match yours.
   62:  */
   63: #define TODO 								\
   64:     xmlGenericError(xmlGenericErrorContext,				\
   65: 	    "Unimplemented block at %s:%d\n",				\
   66:             __FILE__, __LINE__);
   67: 
   68: #define XML_URN_PUBID "urn:publicid:"
   69: #define XML_CATAL_BREAK ((xmlChar *) -1)
   70: #ifndef XML_XML_DEFAULT_CATALOG
   71: #define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
   72: #endif
   73: #ifndef XML_SGML_DEFAULT_CATALOG
   74: #define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
   75: #endif
   76: 
   77: #if defined(_WIN32) && defined(_MSC_VER)
   78: #undef XML_XML_DEFAULT_CATALOG
   79: static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
   80: #if defined(_WIN32_WCE)
   81: /* Windows CE don't have a A variant */
   82: #define GetModuleHandleA GetModuleHandle
   83: #define GetModuleFileNameA GetModuleFileName
   84: #else
   85: void* __stdcall GetModuleHandleA(const char*);
   86: unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
   87: #endif
   88: #endif
   89: 
   90: static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
   91: static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
   92: 
   93: /************************************************************************
   94:  *									*
   95:  *			Types, all private				*
   96:  *									*
   97:  ************************************************************************/
   98: 
   99: typedef enum {
  100:     XML_CATA_REMOVED = -1,
  101:     XML_CATA_NONE = 0,
  102:     XML_CATA_CATALOG,
  103:     XML_CATA_BROKEN_CATALOG,
  104:     XML_CATA_NEXT_CATALOG,
  105:     XML_CATA_GROUP,
  106:     XML_CATA_PUBLIC,
  107:     XML_CATA_SYSTEM,
  108:     XML_CATA_REWRITE_SYSTEM,
  109:     XML_CATA_DELEGATE_PUBLIC,
  110:     XML_CATA_DELEGATE_SYSTEM,
  111:     XML_CATA_URI,
  112:     XML_CATA_REWRITE_URI,
  113:     XML_CATA_DELEGATE_URI,
  114:     SGML_CATA_SYSTEM,
  115:     SGML_CATA_PUBLIC,
  116:     SGML_CATA_ENTITY,
  117:     SGML_CATA_PENTITY,
  118:     SGML_CATA_DOCTYPE,
  119:     SGML_CATA_LINKTYPE,
  120:     SGML_CATA_NOTATION,
  121:     SGML_CATA_DELEGATE,
  122:     SGML_CATA_BASE,
  123:     SGML_CATA_CATALOG,
  124:     SGML_CATA_DOCUMENT,
  125:     SGML_CATA_SGMLDECL
  126: } xmlCatalogEntryType;
  127: 
  128: typedef struct _xmlCatalogEntry xmlCatalogEntry;
  129: typedef xmlCatalogEntry *xmlCatalogEntryPtr;
  130: struct _xmlCatalogEntry {
  131:     struct _xmlCatalogEntry *next;
  132:     struct _xmlCatalogEntry *parent;
  133:     struct _xmlCatalogEntry *children;
  134:     xmlCatalogEntryType type;
  135:     xmlChar *name;
  136:     xmlChar *value;
  137:     xmlChar *URL;  /* The expanded URL using the base */
  138:     xmlCatalogPrefer prefer;
  139:     int dealloc;
  140:     int depth;
  141:     struct _xmlCatalogEntry *group;
  142: };
  143: 
  144: typedef enum {
  145:     XML_XML_CATALOG_TYPE = 1,
  146:     XML_SGML_CATALOG_TYPE
  147: } xmlCatalogType;
  148: 
  149: #define XML_MAX_SGML_CATA_DEPTH 10
  150: struct _xmlCatalog {
  151:     xmlCatalogType type;	/* either XML or SGML */
  152: 
  153:     /*
  154:      * SGML Catalogs are stored as a simple hash table of catalog entries
  155:      * Catalog stack to check against overflows when building the
  156:      * SGML catalog
  157:      */
  158:     char *catalTab[XML_MAX_SGML_CATA_DEPTH];	/* stack of catals */
  159:     int          catalNr;	/* Number of current catal streams */
  160:     int          catalMax;	/* Max number of catal streams */
  161:     xmlHashTablePtr sgml;
  162: 
  163:     /*
  164:      * XML Catalogs are stored as a tree of Catalog entries
  165:      */
  166:     xmlCatalogPrefer prefer;
  167:     xmlCatalogEntryPtr xml;
  168: };
  169: 
  170: /************************************************************************
  171:  *									*
  172:  *			Global variables				*
  173:  *									*
  174:  ************************************************************************/
  175: 
  176: /*
  177:  * Those are preferences
  178:  */
  179: static int xmlDebugCatalogs = 0;   /* used for debugging */
  180: static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
  181: static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
  182: 
  183: /*
  184:  * Hash table containing all the trees of XML catalogs parsed by
  185:  * the application.
  186:  */
  187: static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
  188: 
  189: /*
  190:  * The default catalog in use by the application
  191:  */
  192: static xmlCatalogPtr xmlDefaultCatalog = NULL;
  193: 
  194: /*
  195:  * A mutex for modifying the shared global catalog(s)
  196:  * xmlDefaultCatalog tree.
  197:  * It also protects xmlCatalogXMLFiles
  198:  * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
  199:  */
  200: static xmlRMutexPtr xmlCatalogMutex = NULL;
  201: 
  202: /*
  203:  * Whether the catalog support was initialized.
  204:  */
  205: static int xmlCatalogInitialized = 0;
  206: 
  207: /************************************************************************
  208:  *									*
  209:  * 			Catalog error handlers				*
  210:  *									*
  211:  ************************************************************************/
  212: 
  213: /**
  214:  * xmlCatalogErrMemory:
  215:  * @extra:  extra informations
  216:  *
  217:  * Handle an out of memory condition
  218:  */
  219: static void
  220: xmlCatalogErrMemory(const char *extra)
  221: {
  222:     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
  223:                     XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
  224: 		    extra, NULL, NULL, 0, 0,
  225: 		    "Memory allocation failed : %s\n", extra);
  226: }
  227: 
  228: /**
  229:  * xmlCatalogErr:
  230:  * @catal: the Catalog entry
  231:  * @node: the context node
  232:  * @msg:  the error message
  233:  * @extra:  extra informations
  234:  *
  235:  * Handle a catalog error
  236:  */
  237: static void
  238: xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
  239:                const char *msg, const xmlChar *str1, const xmlChar *str2,
  240: 	       const xmlChar *str3)
  241: {
  242:     __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
  243:                     error, XML_ERR_ERROR, NULL, 0,
  244: 		    (const char *) str1, (const char *) str2,
  245: 		    (const char *) str3, 0, 0,
  246: 		    msg, str1, str2, str3);
  247: }
  248: 
  249: 
  250: /************************************************************************
  251:  *									*
  252:  *			Allocation and Freeing				*
  253:  *									*
  254:  ************************************************************************/
  255: 
  256: /**
  257:  * xmlNewCatalogEntry:
  258:  * @type:  type of entry
  259:  * @name:  name of the entry
  260:  * @value:  value of the entry
  261:  * @prefer:  the PUBLIC vs. SYSTEM current preference value
  262:  * @group:  for members of a group, the group entry 
  263:  *
  264:  * create a new Catalog entry, this type is shared both by XML and 
  265:  * SGML catalogs, but the acceptable types values differs.
  266:  *
  267:  * Returns the xmlCatalogEntryPtr or NULL in case of error
  268:  */
  269: static xmlCatalogEntryPtr
  270: xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
  271: 	   const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
  272: 	   xmlCatalogEntryPtr group) {
  273:     xmlCatalogEntryPtr ret;
  274:     xmlChar *normid = NULL;
  275: 
  276:     ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
  277:     if (ret == NULL) {
  278:         xmlCatalogErrMemory("allocating catalog entry");
  279: 	return(NULL);
  280:     }
  281:     ret->next = NULL;
  282:     ret->parent = NULL;
  283:     ret->children = NULL;
  284:     ret->type = type;
  285:     if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
  286:         normid = xmlCatalogNormalizePublic(name);
  287:         if (normid != NULL)
  288:             name = (*normid != 0 ? normid : NULL);
  289:     }
  290:     if (name != NULL)
  291: 	ret->name = xmlStrdup(name);
  292:     else
  293: 	ret->name = NULL;
  294:     if (normid != NULL)
  295:         xmlFree(normid);
  296:     if (value != NULL)
  297: 	ret->value = xmlStrdup(value);
  298:     else
  299: 	ret->value = NULL;
  300:     if (URL == NULL)
  301: 	URL = value;
  302:     if (URL != NULL)
  303: 	ret->URL = xmlStrdup(URL);
  304:     else
  305: 	ret->URL = NULL;
  306:     ret->prefer = prefer;
  307:     ret->dealloc = 0;
  308:     ret->depth = 0;
  309:     ret->group = group;
  310:     return(ret);
  311: }
  312: 
  313: static void
  314: xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
  315: 
  316: /**
  317:  * xmlFreeCatalogEntry:
  318:  * @ret:  a Catalog entry
  319:  *
  320:  * Free the memory allocated to a Catalog entry
  321:  */
  322: static void
  323: xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
  324:     if (ret == NULL)
  325: 	return;
  326:     /*
  327:      * Entries stored in the file hash must be deallocated
  328:      * only by the file hash cleaner !
  329:      */
  330:     if (ret->dealloc == 1)
  331: 	return;
  332: 
  333:     if (xmlDebugCatalogs) {
  334: 	if (ret->name != NULL)
  335: 	    xmlGenericError(xmlGenericErrorContext,
  336: 		    "Free catalog entry %s\n", ret->name);
  337: 	else if (ret->value != NULL)
  338: 	    xmlGenericError(xmlGenericErrorContext,
  339: 		    "Free catalog entry %s\n", ret->value);
  340: 	else
  341: 	    xmlGenericError(xmlGenericErrorContext,
  342: 		    "Free catalog entry\n");
  343:     }
  344: 
  345:     if (ret->name != NULL)
  346: 	xmlFree(ret->name);
  347:     if (ret->value != NULL)
  348: 	xmlFree(ret->value);
  349:     if (ret->URL != NULL)
  350: 	xmlFree(ret->URL);
  351:     xmlFree(ret);
  352: }
  353: 
  354: /**
  355:  * xmlFreeCatalogEntryList:
  356:  * @ret:  a Catalog entry list
  357:  *
  358:  * Free the memory allocated to a full chained list of Catalog entries
  359:  */
  360: static void
  361: xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
  362:     xmlCatalogEntryPtr next;
  363: 
  364:     while (ret != NULL) {
  365: 	next = ret->next;
  366: 	xmlFreeCatalogEntry(ret);
  367: 	ret = next;
  368:     }
  369: }
  370: 
  371: /**
  372:  * xmlFreeCatalogHashEntryList:
  373:  * @ret:  a Catalog entry list
  374:  *
  375:  * Free the memory allocated to list of Catalog entries from the
  376:  * catalog file hash.
  377:  */
  378: static void
  379: xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
  380:     xmlCatalogEntryPtr children, next;
  381: 
  382:     if (catal == NULL)
  383: 	return;
  384: 
  385:     children = catal->children;
  386:     while (children != NULL) {
  387: 	next = children->next;
  388: 	children->dealloc = 0;
  389: 	children->children = NULL;
  390: 	xmlFreeCatalogEntry(children);
  391: 	children = next;
  392:     }
  393:     catal->dealloc = 0;
  394:     xmlFreeCatalogEntry(catal);
  395: }
  396: 
  397: /**
  398:  * xmlCreateNewCatalog:
  399:  * @type:  type of catalog
  400:  * @prefer:  the PUBLIC vs. SYSTEM current preference value
  401:  *
  402:  * create a new Catalog, this type is shared both by XML and 
  403:  * SGML catalogs, but the acceptable types values differs.
  404:  *
  405:  * Returns the xmlCatalogPtr or NULL in case of error
  406:  */
  407: static xmlCatalogPtr
  408: xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
  409:     xmlCatalogPtr ret;
  410: 
  411:     ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
  412:     if (ret == NULL) {
  413:         xmlCatalogErrMemory("allocating catalog");
  414: 	return(NULL);
  415:     }
  416:     memset(ret, 0, sizeof(xmlCatalog));
  417:     ret->type = type;
  418:     ret->catalNr = 0;
  419:     ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
  420:     ret->prefer = prefer;
  421:     if (ret->type == XML_SGML_CATALOG_TYPE)
  422: 	ret->sgml = xmlHashCreate(10);
  423:     return(ret);
  424: }
  425: 
  426: /**
  427:  * xmlFreeCatalog:
  428:  * @catal:  a Catalog
  429:  *
  430:  * Free the memory allocated to a Catalog
  431:  */
  432: void
  433: xmlFreeCatalog(xmlCatalogPtr catal) {
  434:     if (catal == NULL)
  435: 	return;
  436:     if (catal->xml != NULL)
  437: 	xmlFreeCatalogEntryList(catal->xml);
  438:     if (catal->sgml != NULL)
  439: 	xmlHashFree(catal->sgml,
  440: 		(xmlHashDeallocator) xmlFreeCatalogEntry);
  441:     xmlFree(catal);
  442: }
  443: 
  444: /************************************************************************
  445:  *									*
  446:  *			Serializing Catalogs				*
  447:  *									*
  448:  ************************************************************************/
  449: 
  450: #ifdef LIBXML_OUTPUT_ENABLED
  451: /**
  452:  * xmlCatalogDumpEntry:
  453:  * @entry:  the catalog entry
  454:  * @out:  the file.
  455:  *
  456:  * Serialize an SGML Catalog entry
  457:  */
  458: static void
  459: xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
  460:     if ((entry == NULL) || (out == NULL))
  461: 	return;
  462:     switch (entry->type) {
  463: 	case SGML_CATA_ENTITY:
  464: 	    fprintf(out, "ENTITY "); break;
  465: 	case SGML_CATA_PENTITY:
  466: 	    fprintf(out, "ENTITY %%"); break;
  467: 	case SGML_CATA_DOCTYPE:
  468: 	    fprintf(out, "DOCTYPE "); break;
  469: 	case SGML_CATA_LINKTYPE:
  470: 	    fprintf(out, "LINKTYPE "); break;
  471: 	case SGML_CATA_NOTATION:
  472: 	    fprintf(out, "NOTATION "); break;
  473: 	case SGML_CATA_PUBLIC:
  474: 	    fprintf(out, "PUBLIC "); break;
  475: 	case SGML_CATA_SYSTEM:
  476: 	    fprintf(out, "SYSTEM "); break;
  477: 	case SGML_CATA_DELEGATE:
  478: 	    fprintf(out, "DELEGATE "); break;
  479: 	case SGML_CATA_BASE:
  480: 	    fprintf(out, "BASE "); break;
  481: 	case SGML_CATA_CATALOG:
  482: 	    fprintf(out, "CATALOG "); break;
  483: 	case SGML_CATA_DOCUMENT:
  484: 	    fprintf(out, "DOCUMENT "); break;
  485: 	case SGML_CATA_SGMLDECL:
  486: 	    fprintf(out, "SGMLDECL "); break;
  487: 	default:
  488: 	    return;
  489:     }
  490:     switch (entry->type) {
  491: 	case SGML_CATA_ENTITY:
  492: 	case SGML_CATA_PENTITY:
  493: 	case SGML_CATA_DOCTYPE:
  494: 	case SGML_CATA_LINKTYPE:
  495: 	case SGML_CATA_NOTATION:
  496: 	    fprintf(out, "%s", (const char *) entry->name); break;
  497: 	case SGML_CATA_PUBLIC:
  498: 	case SGML_CATA_SYSTEM:
  499: 	case SGML_CATA_SGMLDECL:
  500: 	case SGML_CATA_DOCUMENT:
  501: 	case SGML_CATA_CATALOG:
  502: 	case SGML_CATA_BASE:
  503: 	case SGML_CATA_DELEGATE:
  504: 	    fprintf(out, "\"%s\"", entry->name); break;
  505: 	default:
  506: 	    break;
  507:     }
  508:     switch (entry->type) {
  509: 	case SGML_CATA_ENTITY:
  510: 	case SGML_CATA_PENTITY:
  511: 	case SGML_CATA_DOCTYPE:
  512: 	case SGML_CATA_LINKTYPE:
  513: 	case SGML_CATA_NOTATION:
  514: 	case SGML_CATA_PUBLIC:
  515: 	case SGML_CATA_SYSTEM:
  516: 	case SGML_CATA_DELEGATE:
  517: 	    fprintf(out, " \"%s\"", entry->value); break;
  518: 	default:
  519: 	    break;
  520:     }
  521:     fprintf(out, "\n");
  522: }
  523: 
  524: /**
  525:  * xmlDumpXMLCatalogNode:
  526:  * @catal:  top catalog entry
  527:  * @catalog: pointer to the xml tree
  528:  * @doc: the containing document
  529:  * @ns: the current namespace
  530:  * @cgroup: group node for group members
  531:  *
  532:  * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
  533:  * for group entries
  534:  */
  535: static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
  536: 		    xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
  537:     xmlNodePtr node;
  538:     xmlCatalogEntryPtr cur;
  539:     /*
  540:      * add all the catalog entries
  541:      */
  542:     cur = catal;
  543:     while (cur != NULL) {
  544:         if (cur->group == cgroup) {
  545: 	    switch (cur->type) {
  546: 	        case XML_CATA_REMOVED:
  547: 		    break;
  548: 	        case XML_CATA_BROKEN_CATALOG:
  549: 	        case XML_CATA_CATALOG:
  550: 		    if (cur == catal) {
  551: 			cur = cur->children;
  552: 		        continue;
  553: 		    }
  554: 		    break;
  555: 		case XML_CATA_NEXT_CATALOG:
  556: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
  557: 		    xmlSetProp(node, BAD_CAST "catalog", cur->value);
  558: 		    xmlAddChild(catalog, node);
  559:                     break;
  560: 		case XML_CATA_NONE:
  561: 		    break;
  562: 		case XML_CATA_GROUP:
  563: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
  564: 		    xmlSetProp(node, BAD_CAST "id", cur->name);
  565: 		    if (cur->value != NULL) {
  566: 		        xmlNsPtr xns;
  567: 			xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
  568: 			if (xns != NULL)
  569: 			    xmlSetNsProp(node, xns, BAD_CAST "base",
  570: 			    		 cur->value);
  571: 		    }
  572: 		    switch (cur->prefer) {
  573: 			case XML_CATA_PREFER_NONE:
  574: 		            break;
  575: 			case XML_CATA_PREFER_PUBLIC:
  576: 		            xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
  577: 			    break;
  578: 			case XML_CATA_PREFER_SYSTEM:
  579: 		            xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
  580: 			    break;
  581: 		    }
  582: 		    xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
  583: 		    xmlAddChild(catalog, node);
  584: 	            break;
  585: 		case XML_CATA_PUBLIC:
  586: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
  587: 		    xmlSetProp(node, BAD_CAST "publicId", cur->name);
  588: 		    xmlSetProp(node, BAD_CAST "uri", cur->value);
  589: 		    xmlAddChild(catalog, node);
  590: 		    break;
  591: 		case XML_CATA_SYSTEM:
  592: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
  593: 		    xmlSetProp(node, BAD_CAST "systemId", cur->name);
  594: 		    xmlSetProp(node, BAD_CAST "uri", cur->value);
  595: 		    xmlAddChild(catalog, node);
  596: 		    break;
  597: 		case XML_CATA_REWRITE_SYSTEM:
  598: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
  599: 		    xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
  600: 		    xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
  601: 		    xmlAddChild(catalog, node);
  602: 		    break;
  603: 		case XML_CATA_DELEGATE_PUBLIC:
  604: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
  605: 		    xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
  606: 		    xmlSetProp(node, BAD_CAST "catalog", cur->value);
  607: 		    xmlAddChild(catalog, node);
  608: 		    break;
  609: 		case XML_CATA_DELEGATE_SYSTEM:
  610: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
  611: 		    xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
  612: 		    xmlSetProp(node, BAD_CAST "catalog", cur->value);
  613: 		    xmlAddChild(catalog, node);
  614: 		    break;
  615: 		case XML_CATA_URI:
  616: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
  617: 		    xmlSetProp(node, BAD_CAST "name", cur->name);
  618: 		    xmlSetProp(node, BAD_CAST "uri", cur->value);
  619: 		    xmlAddChild(catalog, node);
  620: 		    break;
  621: 		case XML_CATA_REWRITE_URI:
  622: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
  623: 		    xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
  624: 		    xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
  625: 		    xmlAddChild(catalog, node);
  626: 		    break;
  627: 		case XML_CATA_DELEGATE_URI:
  628: 		    node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
  629: 		    xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
  630: 		    xmlSetProp(node, BAD_CAST "catalog", cur->value);
  631: 		    xmlAddChild(catalog, node);
  632: 		    break;
  633: 		case SGML_CATA_SYSTEM:
  634: 		case SGML_CATA_PUBLIC:
  635: 		case SGML_CATA_ENTITY:
  636: 		case SGML_CATA_PENTITY:
  637: 		case SGML_CATA_DOCTYPE:
  638: 		case SGML_CATA_LINKTYPE:
  639: 		case SGML_CATA_NOTATION:
  640: 		case SGML_CATA_DELEGATE:
  641: 		case SGML_CATA_BASE:
  642: 		case SGML_CATA_CATALOG:
  643: 		case SGML_CATA_DOCUMENT:
  644: 		case SGML_CATA_SGMLDECL:
  645: 		    break;
  646: 	    }
  647:         }
  648: 	cur = cur->next;
  649:     }
  650: }
  651: 
  652: static int
  653: xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
  654:     int ret;
  655:     xmlDocPtr doc;
  656:     xmlNsPtr ns;
  657:     xmlDtdPtr dtd;
  658:     xmlNodePtr catalog;
  659:     xmlOutputBufferPtr buf;
  660: 
  661:     /*
  662:      * Rebuild a catalog
  663:      */
  664:     doc = xmlNewDoc(NULL);
  665:     if (doc == NULL)
  666: 	return(-1);
  667:     dtd = xmlNewDtd(doc, BAD_CAST "catalog",
  668: 	       BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
  669: BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
  670: 
  671:     xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
  672: 
  673:     ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
  674:     if (ns == NULL) {
  675: 	xmlFreeDoc(doc);
  676: 	return(-1);
  677:     }
  678:     catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
  679:     if (catalog == NULL) {
  680: 	xmlFreeNs(ns);
  681: 	xmlFreeDoc(doc);
  682: 	return(-1);
  683:     }
  684:     catalog->nsDef = ns;
  685:     xmlAddChild((xmlNodePtr) doc, catalog);
  686: 
  687:     xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
  688:     
  689:     /*
  690:      * reserialize it
  691:      */
  692:     buf = xmlOutputBufferCreateFile(out, NULL);
  693:     if (buf == NULL) {
  694: 	xmlFreeDoc(doc);
  695: 	return(-1);
  696:     }
  697:     ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
  698: 
  699:     /*
  700:      * Free it
  701:      */
  702:     xmlFreeDoc(doc);
  703: 
  704:     return(ret);
  705: }
  706: #endif /* LIBXML_OUTPUT_ENABLED */
  707: 
  708: /************************************************************************
  709:  *									*
  710:  *			Converting SGML Catalogs to XML			*
  711:  *									*
  712:  ************************************************************************/
  713: 
  714: /**
  715:  * xmlCatalogConvertEntry:
  716:  * @entry:  the entry
  717:  * @catal:  pointer to the catalog being converted
  718:  *
  719:  * Convert one entry from the catalog
  720:  */
  721: static void
  722: xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
  723:     if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
  724: 	(catal->xml == NULL))
  725: 	return;
  726:     switch (entry->type) {
  727: 	case SGML_CATA_ENTITY:
  728: 	    entry->type = XML_CATA_PUBLIC;
  729: 	    break;
  730: 	case SGML_CATA_PENTITY:
  731: 	    entry->type = XML_CATA_PUBLIC;
  732: 	    break;
  733: 	case SGML_CATA_DOCTYPE:
  734: 	    entry->type = XML_CATA_PUBLIC;
  735: 	    break;
  736: 	case SGML_CATA_LINKTYPE:
  737: 	    entry->type = XML_CATA_PUBLIC;
  738: 	    break;
  739: 	case SGML_CATA_NOTATION:
  740: 	    entry->type = XML_CATA_PUBLIC;
  741: 	    break;
  742: 	case SGML_CATA_PUBLIC:
  743: 	    entry->type = XML_CATA_PUBLIC;
  744: 	    break;
  745: 	case SGML_CATA_SYSTEM:
  746: 	    entry->type = XML_CATA_SYSTEM;
  747: 	    break;
  748: 	case SGML_CATA_DELEGATE:
  749: 	    entry->type = XML_CATA_DELEGATE_PUBLIC;
  750: 	    break;
  751: 	case SGML_CATA_CATALOG:
  752: 	    entry->type = XML_CATA_CATALOG;
  753: 	    break;
  754: 	default:
  755: 	    xmlHashRemoveEntry(catal->sgml, entry->name,
  756: 		               (xmlHashDeallocator) xmlFreeCatalogEntry);
  757: 	    return;
  758:     }
  759:     /*
  760:      * Conversion successful, remove from the SGML catalog
  761:      * and add it to the default XML one
  762:      */
  763:     xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
  764:     entry->parent = catal->xml;
  765:     entry->next = NULL;
  766:     if (catal->xml->children == NULL)
  767: 	catal->xml->children = entry;
  768:     else {
  769: 	xmlCatalogEntryPtr prev;
  770: 
  771: 	prev = catal->xml->children;
  772: 	while (prev->next != NULL)
  773: 	    prev = prev->next;
  774: 	prev->next = entry;
  775:     }
  776: }
  777: 
  778: /**
  779:  * xmlConvertSGMLCatalog:
  780:  * @catal: the catalog
  781:  *
  782:  * Convert all the SGML catalog entries as XML ones
  783:  *
  784:  * Returns the number of entries converted if successful, -1 otherwise
  785:  */
  786: int
  787: xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
  788: 
  789:     if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
  790: 	return(-1);
  791: 
  792:     if (xmlDebugCatalogs) {
  793: 	xmlGenericError(xmlGenericErrorContext,
  794: 		"Converting SGML catalog to XML\n");
  795:     }
  796:     xmlHashScan(catal->sgml,
  797: 		(xmlHashScanner) xmlCatalogConvertEntry,
  798: 		&catal);
  799:     return(0);
  800: }
  801: 
  802: /************************************************************************
  803:  *									*
  804:  *			Helper function					*
  805:  *									*
  806:  ************************************************************************/
  807: 
  808: /**
  809:  * xmlCatalogUnWrapURN:
  810:  * @urn:  an "urn:publicid:" to unwrap
  811:  *
  812:  * Expand the URN into the equivalent Public Identifier
  813:  *
  814:  * Returns the new identifier or NULL, the string must be deallocated
  815:  *         by the caller.
  816:  */
  817: static xmlChar *
  818: xmlCatalogUnWrapURN(const xmlChar *urn) {
  819:     xmlChar result[2000];
  820:     unsigned int i = 0;
  821: 
  822:     if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
  823: 	return(NULL);
  824:     urn += sizeof(XML_URN_PUBID) - 1;
  825:     
  826:     while (*urn != 0) {
  827: 	if (i > sizeof(result) - 4)
  828: 	    break;
  829: 	if (*urn == '+') {
  830: 	    result[i++] = ' ';
  831: 	    urn++;
  832: 	} else if (*urn == ':') {
  833: 	    result[i++] = '/';
  834: 	    result[i++] = '/';
  835: 	    urn++;
  836: 	} else if (*urn == ';') {
  837: 	    result[i++] = ':';
  838: 	    result[i++] = ':';
  839: 	    urn++;
  840: 	} else if (*urn == '%') {
  841: 	    if ((urn[1] == '2') && (urn[2] == 'B'))
  842: 		result[i++] = '+';
  843: 	    else if ((urn[1] == '3') && (urn[2] == 'A'))
  844: 		result[i++] = ':';
  845: 	    else if ((urn[1] == '2') && (urn[2] == 'F'))
  846: 		result[i++] = '/';
  847: 	    else if ((urn[1] == '3') && (urn[2] == 'B'))
  848: 		result[i++] = ';';
  849: 	    else if ((urn[1] == '2') && (urn[2] == '7'))
  850: 		result[i++] = '\'';
  851: 	    else if ((urn[1] == '3') && (urn[2] == 'F'))
  852: 		result[i++] = '?';
  853: 	    else if ((urn[1] == '2') && (urn[2] == '3'))
  854: 		result[i++] = '#';
  855: 	    else if ((urn[1] == '2') && (urn[2] == '5'))
  856: 		result[i++] = '%';
  857: 	    else {
  858: 		result[i++] = *urn;
  859: 		urn++;
  860: 		continue;
  861: 	    }
  862: 	    urn += 3;
  863: 	} else {
  864: 	    result[i++] = *urn;
  865: 	    urn++;
  866: 	}
  867:     }
  868:     result[i] = 0;
  869: 
  870:     return(xmlStrdup(result));
  871: }
  872: 
  873: /**
  874:  * xmlParseCatalogFile:
  875:  * @filename:  the filename
  876:  *
  877:  * parse an XML file and build a tree. It's like xmlParseFile()
  878:  * except it bypass all catalog lookups.
  879:  *
  880:  * Returns the resulting document tree or NULL in case of error
  881:  */
  882: 
  883: xmlDocPtr
  884: xmlParseCatalogFile(const char *filename) {
  885:     xmlDocPtr ret;
  886:     xmlParserCtxtPtr ctxt;
  887:     char *directory = NULL;
  888:     xmlParserInputPtr inputStream;
  889:     xmlParserInputBufferPtr buf;
  890: 
  891:     ctxt = xmlNewParserCtxt();
  892:     if (ctxt == NULL) {
  893: #ifdef LIBXML_SAX1_ENABLED
  894: 	if (xmlDefaultSAXHandler.error != NULL) {
  895: 	    xmlDefaultSAXHandler.error(NULL, "out of memory\n");
  896: 	}
  897: #endif
  898: 	return(NULL);
  899:     }
  900: 
  901:     buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
  902:     if (buf == NULL) {
  903: 	xmlFreeParserCtxt(ctxt);
  904: 	return(NULL);
  905:     }
  906: 
  907:     inputStream = xmlNewInputStream(ctxt);
  908:     if (inputStream == NULL) {
  909: 	xmlFreeParserCtxt(ctxt);
  910: 	return(NULL);
  911:     }
  912: 
  913:     inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
  914:     inputStream->buf = buf;
  915:     inputStream->base = inputStream->buf->buffer->content;
  916:     inputStream->cur = inputStream->buf->buffer->content;
  917:     inputStream->end = 
  918: 	&inputStream->buf->buffer->content[inputStream->buf->buffer->use];
  919: 
  920:     inputPush(ctxt, inputStream);
  921:     if ((ctxt->directory == NULL) && (directory == NULL))
  922:         directory = xmlParserGetDirectory(filename);
  923:     if ((ctxt->directory == NULL) && (directory != NULL))
  924:         ctxt->directory = directory;
  925:     ctxt->valid = 0;
  926:     ctxt->validate = 0;
  927:     ctxt->loadsubset = 0;
  928:     ctxt->pedantic = 0;
  929:     ctxt->dictNames = 1;
  930: 
  931:     xmlParseDocument(ctxt);
  932: 
  933:     if (ctxt->wellFormed)
  934: 	ret = ctxt->myDoc;
  935:     else {
  936:         ret = NULL;
  937:         xmlFreeDoc(ctxt->myDoc);
  938:         ctxt->myDoc = NULL;
  939:     }
  940:     xmlFreeParserCtxt(ctxt);
  941:     
  942:     return(ret);
  943: }
  944: 
  945: /**
  946:  * xmlLoadFileContent:
  947:  * @filename:  a file path
  948:  *
  949:  * Load a file content into memory.
  950:  *
  951:  * Returns a pointer to the 0 terminated string or NULL in case of error
  952:  */
  953: static xmlChar *
  954: xmlLoadFileContent(const char *filename)
  955: {
  956: #ifdef HAVE_STAT
  957:     int fd;
  958: #else
  959:     FILE *fd;
  960: #endif
  961:     int len;
  962:     long size;
  963: 
  964: #ifdef HAVE_STAT
  965:     struct stat info;
  966: #endif
  967:     xmlChar *content;
  968: 
  969:     if (filename == NULL)
  970:         return (NULL);
  971: 
  972: #ifdef HAVE_STAT
  973:     if (stat(filename, &info) < 0)
  974:         return (NULL);
  975: #endif
  976: 
  977: #ifdef HAVE_STAT
  978:     if ((fd = open(filename, O_RDONLY)) < 0)
  979: #else
  980:     if ((fd = fopen(filename, "rb")) == NULL)
  981: #endif
  982:     {
  983:         return (NULL);
  984:     }
  985: #ifdef HAVE_STAT
  986:     size = info.st_size;
  987: #else
  988:     if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) {        /* File operations denied? ok, just close and return failure */
  989:         fclose(fd);
  990:         return (NULL);
  991:     }
  992: #endif
  993:     content = xmlMallocAtomic(size + 10);
  994:     if (content == NULL) {
  995:         xmlCatalogErrMemory("allocating catalog data");
  996:         return (NULL);
  997:     }
  998: #ifdef HAVE_STAT
  999:     len = read(fd, content, size);
 1000:     close(fd);
 1001: #else
 1002:     len = fread(content, 1, size, fd);
 1003:     fclose(fd);
 1004: #endif
 1005:     if (len < 0) {
 1006:         xmlFree(content);
 1007:         return (NULL);
 1008:     }
 1009:     content[len] = 0;
 1010: 
 1011:     return(content);
 1012: }
 1013: 
 1014: /**
 1015:  * xmlCatalogNormalizePublic:
 1016:  * @pubID:  the public ID string
 1017:  *
 1018:  *  Normalizes the Public Identifier
 1019:  *
 1020:  * Implements 6.2. Public Identifier Normalization
 1021:  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
 1022:  *
 1023:  * Returns the new string or NULL, the string must be deallocated
 1024:  *         by the caller.
 1025:  */
 1026: static xmlChar *
 1027: xmlCatalogNormalizePublic(const xmlChar *pubID)
 1028: {
 1029:     int ok = 1;
 1030:     int white;
 1031:     const xmlChar *p;
 1032:     xmlChar *ret;
 1033:     xmlChar *q;
 1034: 
 1035:     if (pubID == NULL)
 1036:         return(NULL);
 1037: 
 1038:     white = 1;
 1039:     for (p = pubID;*p != 0 && ok;p++) {
 1040:         if (!xmlIsBlank_ch(*p))
 1041:             white = 0;
 1042:         else if (*p == 0x20 && !white)
 1043:             white = 1;
 1044:         else
 1045:             ok = 0;
 1046:     }
 1047:     if (ok && !white)	/* is normalized */
 1048:         return(NULL);
 1049: 
 1050:     ret = xmlStrdup(pubID);
 1051:     q = ret;
 1052:     white = 0;
 1053:     for (p = pubID;*p != 0;p++) {
 1054:         if (xmlIsBlank_ch(*p)) {
 1055:             if (q != ret)
 1056:                 white = 1;
 1057:         } else {
 1058:             if (white) {
 1059:                 *(q++) = 0x20;
 1060:                 white = 0;
 1061:             }
 1062:             *(q++) = *p;
 1063:         }
 1064:     }
 1065:     *q = 0;
 1066:     return(ret);
 1067: }
 1068: 
 1069: /************************************************************************
 1070:  *									*
 1071:  *			The XML Catalog parser				*
 1072:  *									*
 1073:  ************************************************************************/
 1074: 
 1075: static xmlCatalogEntryPtr
 1076: xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
 1077: static void
 1078: xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
 1079: 	                   xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
 1080: static xmlChar *
 1081: xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
 1082: 	              const xmlChar *sysID);
 1083: static xmlChar *
 1084: xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
 1085: 
 1086: 
 1087: /**
 1088:  * xmlGetXMLCatalogEntryType:
 1089:  * @name:  the name
 1090:  *
 1091:  * lookup the internal type associated to an XML catalog entry name
 1092:  *
 1093:  * Returns the type associated with that name
 1094:  */
 1095: static xmlCatalogEntryType
 1096: xmlGetXMLCatalogEntryType(const xmlChar *name) {
 1097:     xmlCatalogEntryType type = XML_CATA_NONE;
 1098:     if (xmlStrEqual(name, (const xmlChar *) "system"))
 1099: 	type = XML_CATA_SYSTEM;
 1100:     else if (xmlStrEqual(name, (const xmlChar *) "public"))
 1101: 	type = XML_CATA_PUBLIC;
 1102:     else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
 1103: 	type = XML_CATA_REWRITE_SYSTEM;
 1104:     else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
 1105: 	type = XML_CATA_DELEGATE_PUBLIC;
 1106:     else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
 1107: 	type = XML_CATA_DELEGATE_SYSTEM;
 1108:     else if (xmlStrEqual(name, (const xmlChar *) "uri"))
 1109: 	type = XML_CATA_URI;
 1110:     else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
 1111: 	type = XML_CATA_REWRITE_URI;
 1112:     else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
 1113: 	type = XML_CATA_DELEGATE_URI;
 1114:     else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
 1115: 	type = XML_CATA_NEXT_CATALOG;
 1116:     else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
 1117: 	type = XML_CATA_CATALOG;
 1118:     return(type);
 1119: }
 1120: 
 1121: /**
 1122:  * xmlParseXMLCatalogOneNode:
 1123:  * @cur:  the XML node
 1124:  * @type:  the type of Catalog entry
 1125:  * @name:  the name of the node
 1126:  * @attrName:  the attribute holding the value
 1127:  * @uriAttrName:  the attribute holding the URI-Reference
 1128:  * @prefer:  the PUBLIC vs. SYSTEM current preference value
 1129:  * @cgroup:  the group which includes this node
 1130:  *
 1131:  * Finishes the examination of an XML tree node of a catalog and build
 1132:  * a Catalog entry from it.
 1133:  *
 1134:  * Returns the new Catalog entry node or NULL in case of error.
 1135:  */
 1136: static xmlCatalogEntryPtr
 1137: xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
 1138: 			  const xmlChar *name, const xmlChar *attrName,
 1139: 			  const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
 1140: 			  xmlCatalogEntryPtr cgroup) {
 1141:     int ok = 1;
 1142:     xmlChar *uriValue;
 1143:     xmlChar *nameValue = NULL;
 1144:     xmlChar *base = NULL;
 1145:     xmlChar *URL = NULL;
 1146:     xmlCatalogEntryPtr ret = NULL;
 1147: 
 1148:     if (attrName != NULL) {
 1149: 	nameValue = xmlGetProp(cur, attrName);
 1150: 	if (nameValue == NULL) {
 1151: 	    xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
 1152: 			  "%s entry lacks '%s'\n", name, attrName, NULL);
 1153: 	    ok = 0;
 1154: 	}
 1155:     }
 1156:     uriValue = xmlGetProp(cur, uriAttrName);
 1157:     if (uriValue == NULL) {
 1158: 	xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
 1159: 		"%s entry lacks '%s'\n", name, uriAttrName, NULL);
 1160: 	ok = 0;
 1161:     }
 1162:     if (!ok) {
 1163: 	if (nameValue != NULL)
 1164: 	    xmlFree(nameValue);
 1165: 	if (uriValue != NULL)
 1166: 	    xmlFree(uriValue);
 1167: 	return(NULL);
 1168:     }
 1169: 
 1170:     base = xmlNodeGetBase(cur->doc, cur);
 1171:     URL = xmlBuildURI(uriValue, base);
 1172:     if (URL != NULL) {
 1173: 	if (xmlDebugCatalogs > 1) {
 1174: 	    if (nameValue != NULL)
 1175: 		xmlGenericError(xmlGenericErrorContext,
 1176: 			"Found %s: '%s' '%s'\n", name, nameValue, URL);
 1177: 	    else
 1178: 		xmlGenericError(xmlGenericErrorContext,
 1179: 			"Found %s: '%s'\n", name, URL);
 1180: 	}
 1181: 	ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
 1182:     } else {
 1183: 	xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
 1184: 		"%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
 1185:     }
 1186:     if (nameValue != NULL)
 1187: 	xmlFree(nameValue);
 1188:     if (uriValue != NULL)
 1189: 	xmlFree(uriValue);
 1190:     if (base != NULL)
 1191: 	xmlFree(base);
 1192:     if (URL != NULL)
 1193: 	xmlFree(URL);
 1194:     return(ret);
 1195: }
 1196: 
 1197: /**
 1198:  * xmlParseXMLCatalogNode:
 1199:  * @cur:  the XML node
 1200:  * @prefer:  the PUBLIC vs. SYSTEM current preference value
 1201:  * @parent:  the parent Catalog entry
 1202:  * @cgroup:  the group which includes this node
 1203:  *
 1204:  * Examines an XML tree node of a catalog and build
 1205:  * a Catalog entry from it adding it to its parent. The examination can
 1206:  * be recursive.
 1207:  */
 1208: static void
 1209: xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
 1210: 	               xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
 1211: {
 1212:     xmlChar *base = NULL;
 1213:     xmlCatalogEntryPtr entry = NULL;
 1214: 
 1215:     if (cur == NULL)
 1216:         return;
 1217:     if (xmlStrEqual(cur->name, BAD_CAST "group")) {
 1218:         xmlChar *prop;
 1219: 	xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
 1220: 
 1221:         prop = xmlGetProp(cur, BAD_CAST "prefer");
 1222:         if (prop != NULL) {
 1223:             if (xmlStrEqual(prop, BAD_CAST "system")) {
 1224:                 prefer = XML_CATA_PREFER_SYSTEM;
 1225:             } else if (xmlStrEqual(prop, BAD_CAST "public")) {
 1226:                 prefer = XML_CATA_PREFER_PUBLIC;
 1227:             } else {
 1228: 		xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
 1229:                               "Invalid value for prefer: '%s'\n",
 1230: 			      prop, NULL, NULL);
 1231:             }
 1232:             xmlFree(prop);
 1233: 	    pref = prefer;
 1234:         }
 1235: 	prop = xmlGetProp(cur, BAD_CAST "id");
 1236: 	base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
 1237: 	entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
 1238: 	xmlFree(prop);
 1239:     } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
 1240: 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
 1241: 		BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
 1242:     } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
 1243: 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
 1244: 		BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
 1245:     } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
 1246: 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
 1247: 		BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
 1248: 		BAD_CAST "rewritePrefix", prefer, cgroup);
 1249:     } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
 1250: 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
 1251: 		BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
 1252: 		BAD_CAST "catalog", prefer, cgroup);
 1253:     } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
 1254: 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
 1255: 		BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
 1256: 		BAD_CAST "catalog", prefer, cgroup);
 1257:     } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
 1258: 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
 1259: 		BAD_CAST "uri", BAD_CAST "name",
 1260: 		BAD_CAST "uri", prefer, cgroup);
 1261:     } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
 1262: 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
 1263: 		BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
 1264: 		BAD_CAST "rewritePrefix", prefer, cgroup);
 1265:     } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
 1266: 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
 1267: 		BAD_CAST "delegateURI", BAD_CAST "uriStartString",
 1268: 		BAD_CAST "catalog", prefer, cgroup);
 1269:     } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
 1270: 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
 1271: 		BAD_CAST "nextCatalog", NULL,
 1272: 		BAD_CAST "catalog", prefer, cgroup);
 1273:     }
 1274:     if (entry != NULL) {
 1275:         if (parent != NULL) {
 1276: 	    entry->parent = parent;
 1277: 	    if (parent->children == NULL)
 1278: 		parent->children = entry;
 1279: 	    else {
 1280: 		xmlCatalogEntryPtr prev;
 1281: 
 1282: 		prev = parent->children;
 1283: 		while (prev->next != NULL)
 1284: 		    prev = prev->next;
 1285: 		prev->next = entry;
 1286: 	    }
 1287: 	}
 1288: 	if (entry->type == XML_CATA_GROUP) {
 1289: 	    /*
 1290: 	     * Recurse to propagate prefer to the subtree
 1291: 	     * (xml:base handling is automated)
 1292: 	     */
 1293:             xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
 1294: 	}
 1295:     }
 1296:     if (base != NULL)
 1297: 	xmlFree(base);
 1298: }
 1299: 
 1300: /**
 1301:  * xmlParseXMLCatalogNodeList:
 1302:  * @cur:  the XML node list of siblings
 1303:  * @prefer:  the PUBLIC vs. SYSTEM current preference value
 1304:  * @parent:  the parent Catalog entry
 1305:  * @cgroup:  the group which includes this list
 1306:  *
 1307:  * Examines a list of XML sibling nodes of a catalog and build
 1308:  * a list of Catalog entry from it adding it to the parent.
 1309:  * The examination will recurse to examine node subtrees.
 1310:  */
 1311: static void
 1312: xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
 1313: 	                   xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
 1314:     while (cur != NULL) {
 1315: 	if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
 1316: 	    (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
 1317: 	    xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
 1318: 	}
 1319: 	cur = cur->next;
 1320:     }
 1321:     /* TODO: sort the list according to REWRITE lengths and prefer value */
 1322: }
 1323: 
 1324: /**
 1325:  * xmlParseXMLCatalogFile:
 1326:  * @prefer:  the PUBLIC vs. SYSTEM current preference value
 1327:  * @filename:  the filename for the catalog
 1328:  *
 1329:  * Parses the catalog file to extract the XML tree and then analyze the
 1330:  * tree to build a list of Catalog entries corresponding to this catalog
 1331:  * 
 1332:  * Returns the resulting Catalog entries list
 1333:  */
 1334: static xmlCatalogEntryPtr
 1335: xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
 1336:     xmlDocPtr doc;
 1337:     xmlNodePtr cur;
 1338:     xmlChar *prop;
 1339:     xmlCatalogEntryPtr parent = NULL;
 1340: 
 1341:     if (filename == NULL)
 1342:         return(NULL);
 1343: 
 1344:     doc = xmlParseCatalogFile((const char *) filename);
 1345:     if (doc == NULL) {
 1346: 	if (xmlDebugCatalogs)
 1347: 	    xmlGenericError(xmlGenericErrorContext,
 1348: 		    "Failed to parse catalog %s\n", filename);
 1349: 	return(NULL);
 1350:     }
 1351: 
 1352:     if (xmlDebugCatalogs)
 1353: 	xmlGenericError(xmlGenericErrorContext,
 1354: 		"%d Parsing catalog %s\n", xmlGetThreadId(), filename);
 1355: 
 1356:     cur = xmlDocGetRootElement(doc);
 1357:     if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
 1358: 	(cur->ns != NULL) && (cur->ns->href != NULL) &&
 1359: 	(xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
 1360: 
 1361: 	parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
 1362: 				    (const xmlChar *)filename, NULL, prefer, NULL);
 1363:         if (parent == NULL) {
 1364: 	    xmlFreeDoc(doc);
 1365: 	    return(NULL);
 1366: 	}
 1367: 
 1368: 	prop = xmlGetProp(cur, BAD_CAST "prefer");
 1369: 	if (prop != NULL) {
 1370: 	    if (xmlStrEqual(prop, BAD_CAST "system")) {
 1371: 		prefer = XML_CATA_PREFER_SYSTEM;
 1372: 	    } else if (xmlStrEqual(prop, BAD_CAST "public")) {
 1373: 		prefer = XML_CATA_PREFER_PUBLIC;
 1374: 	    } else {
 1375: 		xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
 1376: 			      "Invalid value for prefer: '%s'\n",
 1377: 			      prop, NULL, NULL);
 1378: 	    }
 1379: 	    xmlFree(prop);
 1380: 	}
 1381: 	cur = cur->children;
 1382: 	xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
 1383:     } else {
 1384: 	xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
 1385: 		      "File %s is not an XML Catalog\n",
 1386: 		      filename, NULL, NULL);
 1387: 	xmlFreeDoc(doc);
 1388: 	return(NULL);
 1389:     }
 1390:     xmlFreeDoc(doc);
 1391:     return(parent);
 1392: }
 1393: 
 1394: /**
 1395:  * xmlFetchXMLCatalogFile:
 1396:  * @catal:  an existing but incomplete catalog entry
 1397:  *
 1398:  * Fetch and parse the subcatalog referenced by an entry
 1399:  * 
 1400:  * Returns 0 in case of success, -1 otherwise
 1401:  */
 1402: static int
 1403: xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
 1404:     xmlCatalogEntryPtr doc;
 1405: 
 1406:     if (catal == NULL) 
 1407: 	return(-1);
 1408:     if (catal->URL == NULL)
 1409: 	return(-1);
 1410: 
 1411:     /*
 1412:      * lock the whole catalog for modification
 1413:      */
 1414:     xmlRMutexLock(xmlCatalogMutex);
 1415:     if (catal->children != NULL) {
 1416: 	/* Okay someone else did it in the meantime */
 1417: 	xmlRMutexUnlock(xmlCatalogMutex);
 1418: 	return(0);
 1419:     }
 1420: 
 1421:     if (xmlCatalogXMLFiles != NULL) {
 1422: 	doc = (xmlCatalogEntryPtr)
 1423: 	    xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
 1424: 	if (doc != NULL) {
 1425: 	    if (xmlDebugCatalogs)
 1426: 		xmlGenericError(xmlGenericErrorContext,
 1427: 		    "Found %s in file hash\n", catal->URL);
 1428: 
 1429: 	    if (catal->type == XML_CATA_CATALOG)
 1430: 		catal->children = doc->children;
 1431: 	    else
 1432: 		catal->children = doc;
 1433: 	    catal->dealloc = 0;
 1434: 	    xmlRMutexUnlock(xmlCatalogMutex);
 1435: 	    return(0);
 1436: 	}
 1437: 	if (xmlDebugCatalogs)
 1438: 	    xmlGenericError(xmlGenericErrorContext,
 1439: 		"%s not found in file hash\n", catal->URL);
 1440:     }
 1441: 
 1442:     /*
 1443:      * Fetch and parse. Note that xmlParseXMLCatalogFile does not
 1444:      * use the existing catalog, there is no recursion allowed at
 1445:      * that level.
 1446:      */
 1447:     doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
 1448:     if (doc == NULL) {
 1449: 	catal->type = XML_CATA_BROKEN_CATALOG;
 1450: 	xmlRMutexUnlock(xmlCatalogMutex);
 1451: 	return(-1);
 1452:     }
 1453: 
 1454:     if (catal->type == XML_CATA_CATALOG)
 1455: 	catal->children = doc->children;
 1456:     else
 1457: 	catal->children = doc;
 1458: 
 1459:     doc->dealloc = 1;
 1460: 
 1461:     if (xmlCatalogXMLFiles == NULL)
 1462: 	xmlCatalogXMLFiles = xmlHashCreate(10);
 1463:     if (xmlCatalogXMLFiles != NULL) {
 1464: 	if (xmlDebugCatalogs)
 1465: 	    xmlGenericError(xmlGenericErrorContext,
 1466: 		"%s added to file hash\n", catal->URL);
 1467: 	xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
 1468:     }
 1469:     xmlRMutexUnlock(xmlCatalogMutex);
 1470:     return(0);
 1471: }
 1472: 
 1473: /************************************************************************
 1474:  *									*
 1475:  *			XML Catalog handling				*
 1476:  *									*
 1477:  ************************************************************************/
 1478: 
 1479: /**
 1480:  * xmlAddXMLCatalog:
 1481:  * @catal:  top of an XML catalog
 1482:  * @type:  the type of record to add to the catalog
 1483:  * @orig:  the system, public or prefix to match (or NULL)
 1484:  * @replace:  the replacement value for the match
 1485:  *
 1486:  * Add an entry in the XML catalog, it may overwrite existing but
 1487:  * different entries.
 1488:  *
 1489:  * Returns 0 if successful, -1 otherwise
 1490:  */
 1491: static int
 1492: xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
 1493: 	      const xmlChar *orig, const xmlChar *replace) {
 1494:     xmlCatalogEntryPtr cur;
 1495:     xmlCatalogEntryType typ;
 1496:     int doregister = 0;
 1497: 
 1498:     if ((catal == NULL) || 
 1499: 	((catal->type != XML_CATA_CATALOG) &&
 1500: 	 (catal->type != XML_CATA_BROKEN_CATALOG)))
 1501: 	return(-1);
 1502:     if (catal->children == NULL) {
 1503: 	xmlFetchXMLCatalogFile(catal);
 1504:     }
 1505:     if (catal->children == NULL)
 1506: 	doregister = 1;
 1507: 
 1508:     typ = xmlGetXMLCatalogEntryType(type);
 1509:     if (typ == XML_CATA_NONE) {
 1510: 	if (xmlDebugCatalogs)
 1511: 	    xmlGenericError(xmlGenericErrorContext,
 1512: 		    "Failed to add unknown element %s to catalog\n", type);
 1513: 	return(-1);
 1514:     }
 1515: 
 1516:     cur = catal->children;
 1517:     /*
 1518:      * Might be a simple "update in place"
 1519:      */
 1520:     if (cur != NULL) {
 1521: 	while (cur != NULL) {
 1522: 	    if ((orig != NULL) && (cur->type == typ) &&
 1523: 		(xmlStrEqual(orig, cur->name))) {
 1524: 		if (xmlDebugCatalogs)
 1525: 		    xmlGenericError(xmlGenericErrorContext,
 1526: 			    "Updating element %s to catalog\n", type);
 1527: 		if (cur->value != NULL)
 1528: 		    xmlFree(cur->value);
 1529: 		if (cur->URL != NULL)
 1530: 		    xmlFree(cur->URL);
 1531: 		cur->value = xmlStrdup(replace);
 1532: 		cur->URL = xmlStrdup(replace);
 1533: 		return(0);
 1534: 	    }
 1535: 	    if (cur->next == NULL)
 1536: 		break;
 1537: 	    cur = cur->next;
 1538: 	}
 1539:     }
 1540:     if (xmlDebugCatalogs)
 1541: 	xmlGenericError(xmlGenericErrorContext,
 1542: 		"Adding element %s to catalog\n", type);
 1543:     if (cur == NULL)
 1544: 	catal->children = xmlNewCatalogEntry(typ, orig, replace,
 1545: 		                             NULL, catal->prefer, NULL);
 1546:     else
 1547: 	cur->next = xmlNewCatalogEntry(typ, orig, replace,
 1548: 		                       NULL, catal->prefer, NULL);
 1549:     if (doregister) {
 1550:         catal->type = XML_CATA_CATALOG;
 1551: 	cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
 1552: 	if (cur != NULL)
 1553: 	    cur->children = catal->children;
 1554:     }
 1555: 
 1556:     return(0);
 1557: }
 1558: 
 1559: /**
 1560:  * xmlDelXMLCatalog:
 1561:  * @catal:  top of an XML catalog
 1562:  * @value:  the value to remove from the catalog
 1563:  *
 1564:  * Remove entries in the XML catalog where the value or the URI
 1565:  * is equal to @value
 1566:  *
 1567:  * Returns the number of entries removed if successful, -1 otherwise
 1568:  */
 1569: static int
 1570: xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
 1571:     xmlCatalogEntryPtr cur;
 1572:     int ret = 0;
 1573: 
 1574:     if ((catal == NULL) || 
 1575: 	((catal->type != XML_CATA_CATALOG) &&
 1576: 	 (catal->type != XML_CATA_BROKEN_CATALOG)))
 1577: 	return(-1);
 1578:     if (value == NULL)
 1579: 	return(-1);
 1580:     if (catal->children == NULL) {
 1581: 	xmlFetchXMLCatalogFile(catal);
 1582:     }
 1583: 
 1584:     /*
 1585:      * Scan the children
 1586:      */
 1587:     cur = catal->children;
 1588:     while (cur != NULL) {
 1589: 	if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
 1590: 	    (xmlStrEqual(value, cur->value))) {
 1591: 	    if (xmlDebugCatalogs) {
 1592: 		if (cur->name != NULL)
 1593: 		    xmlGenericError(xmlGenericErrorContext,
 1594: 			    "Removing element %s from catalog\n", cur->name);
 1595: 		else
 1596: 		    xmlGenericError(xmlGenericErrorContext,
 1597: 			    "Removing element %s from catalog\n", cur->value);
 1598: 	    }
 1599: 	    cur->type = XML_CATA_REMOVED;
 1600: 	}
 1601: 	cur = cur->next;
 1602:     }
 1603:     return(ret);
 1604: }
 1605: 
 1606: /**
 1607:  * xmlCatalogXMLResolve:
 1608:  * @catal:  a catalog list
 1609:  * @pubID:  the public ID string
 1610:  * @sysID:  the system ID string
 1611:  *
 1612:  * Do a complete resolution lookup of an External Identifier for a
 1613:  * list of catalog entries.
 1614:  *
 1615:  * Implements (or tries to) 7.1. External Identifier Resolution
 1616:  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
 1617:  *
 1618:  * Returns the URI of the resource or NULL if not found
 1619:  */
 1620: static xmlChar *
 1621: xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
 1622: 	              const xmlChar *sysID) {
 1623:     xmlChar *ret = NULL;
 1624:     xmlCatalogEntryPtr cur;
 1625:     int haveDelegate = 0;
 1626:     int haveNext = 0;
 1627: 
 1628:     /*
 1629:      * protection against loops
 1630:      */
 1631:     if (catal->depth > MAX_CATAL_DEPTH) {
 1632: 	xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
 1633: 		      "Detected recursion in catalog %s\n",
 1634: 		      catal->name, NULL, NULL);
 1635: 	return(NULL);
 1636:     }
 1637:     catal->depth++;
 1638: 
 1639:     /*
 1640:      * First tries steps 2/ 3/ 4/ if a system ID is provided.
 1641:      */
 1642:     if (sysID != NULL) {
 1643: 	xmlCatalogEntryPtr rewrite = NULL;
 1644: 	int lenrewrite = 0, len;
 1645: 	cur = catal;
 1646: 	haveDelegate = 0;
 1647: 	while (cur != NULL) {
 1648: 	    switch (cur->type) {
 1649: 		case XML_CATA_SYSTEM:
 1650: 		    if (xmlStrEqual(sysID, cur->name)) {
 1651: 			if (xmlDebugCatalogs)
 1652: 			    xmlGenericError(xmlGenericErrorContext,
 1653: 				    "Found system match %s, using %s\n",
 1654: 				            cur->name, cur->URL);
 1655: 			catal->depth--;
 1656: 			return(xmlStrdup(cur->URL));
 1657: 		    }
 1658: 		    break;
 1659: 		case XML_CATA_REWRITE_SYSTEM:
 1660: 		    len = xmlStrlen(cur->name);
 1661: 		    if ((len > lenrewrite) &&
 1662: 			(!xmlStrncmp(sysID, cur->name, len))) {
 1663: 			lenrewrite = len;
 1664: 			rewrite = cur;
 1665: 		    }
 1666: 		    break;
 1667: 		case XML_CATA_DELEGATE_SYSTEM:
 1668: 		    if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
 1669: 			haveDelegate++;
 1670: 		    break;
 1671: 		case XML_CATA_NEXT_CATALOG:
 1672: 		    haveNext++;
 1673: 		    break;
 1674: 		default:
 1675: 		    break;
 1676: 	    }
 1677: 	    cur = cur->next;
 1678: 	}
 1679: 	if (rewrite != NULL) {
 1680: 	    if (xmlDebugCatalogs)
 1681: 		xmlGenericError(xmlGenericErrorContext,
 1682: 			"Using rewriting rule %s\n", rewrite->name);
 1683: 	    ret = xmlStrdup(rewrite->URL);
 1684: 	    if (ret != NULL)
 1685: 		ret = xmlStrcat(ret, &sysID[lenrewrite]);
 1686: 	    catal->depth--;
 1687: 	    return(ret);
 1688: 	}
 1689: 	if (haveDelegate) {
 1690: 	    const xmlChar *delegates[MAX_DELEGATE];
 1691: 	    int nbList = 0, i;
 1692: 
 1693: 	    /*
 1694: 	     * Assume the entries have been sorted by decreasing substring
 1695: 	     * matches when the list was produced.
 1696: 	     */
 1697: 	    cur = catal;
 1698: 	    while (cur != NULL) {
 1699: 		if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
 1700: 		    (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
 1701: 		    for (i = 0;i < nbList;i++)
 1702: 			if (xmlStrEqual(cur->URL, delegates[i]))
 1703: 			    break;
 1704: 		    if (i < nbList) {
 1705: 			cur = cur->next;
 1706: 			continue;
 1707: 		    }
 1708: 		    if (nbList < MAX_DELEGATE)
 1709: 			delegates[nbList++] = cur->URL;
 1710: 
 1711: 		    if (cur->children == NULL) {
 1712: 			xmlFetchXMLCatalogFile(cur);
 1713: 		    }
 1714: 		    if (cur->children != NULL) {
 1715: 			if (xmlDebugCatalogs)
 1716: 			    xmlGenericError(xmlGenericErrorContext,
 1717: 				    "Trying system delegate %s\n", cur->URL);
 1718: 			ret = xmlCatalogListXMLResolve(
 1719: 				cur->children, NULL, sysID);
 1720: 			if (ret != NULL) {
 1721: 			    catal->depth--;
 1722: 			    return(ret);
 1723: 			}
 1724: 		    }
 1725: 		}
 1726: 		cur = cur->next;
 1727: 	    }
 1728: 	    /*
 1729: 	     * Apply the cut algorithm explained in 4/
 1730: 	     */
 1731: 	    catal->depth--;
 1732: 	    return(XML_CATAL_BREAK);
 1733: 	}
 1734:     }
 1735:     /*
 1736:      * Then tries 5/ 6/ if a public ID is provided
 1737:      */
 1738:     if (pubID != NULL) {
 1739: 	cur = catal;
 1740: 	haveDelegate = 0;
 1741: 	while (cur != NULL) {
 1742: 	    switch (cur->type) {
 1743: 		case XML_CATA_PUBLIC:
 1744: 		    if (xmlStrEqual(pubID, cur->name)) {
 1745: 			if (xmlDebugCatalogs)
 1746: 			    xmlGenericError(xmlGenericErrorContext,
 1747: 				    "Found public match %s\n", cur->name);
 1748: 			catal->depth--;
 1749: 			return(xmlStrdup(cur->URL));
 1750: 		    }
 1751: 		    break;
 1752: 		case XML_CATA_DELEGATE_PUBLIC:
 1753: 		    if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
 1754: 			(cur->prefer == XML_CATA_PREFER_PUBLIC))
 1755: 			haveDelegate++;
 1756: 		    break;
 1757: 		case XML_CATA_NEXT_CATALOG:
 1758: 		    if (sysID == NULL)
 1759: 			haveNext++;
 1760: 		    break;
 1761: 		default:
 1762: 		    break;
 1763: 	    }
 1764: 	    cur = cur->next;
 1765: 	}
 1766: 	if (haveDelegate) {
 1767: 	    const xmlChar *delegates[MAX_DELEGATE];
 1768: 	    int nbList = 0, i;
 1769: 
 1770: 	    /*
 1771: 	     * Assume the entries have been sorted by decreasing substring
 1772: 	     * matches when the list was produced.
 1773: 	     */
 1774: 	    cur = catal;
 1775: 	    while (cur != NULL) {
 1776: 		if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
 1777: 		    (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
 1778: 		    (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
 1779: 
 1780: 		    for (i = 0;i < nbList;i++)
 1781: 			if (xmlStrEqual(cur->URL, delegates[i]))
 1782: 			    break;
 1783: 		    if (i < nbList) {
 1784: 			cur = cur->next;
 1785: 			continue;
 1786: 		    }
 1787: 		    if (nbList < MAX_DELEGATE)
 1788: 			delegates[nbList++] = cur->URL;
 1789: 			    
 1790: 		    if (cur->children == NULL) {
 1791: 			xmlFetchXMLCatalogFile(cur);
 1792: 		    }
 1793: 		    if (cur->children != NULL) {
 1794: 			if (xmlDebugCatalogs)
 1795: 			    xmlGenericError(xmlGenericErrorContext,
 1796: 				    "Trying public delegate %s\n", cur->URL);
 1797: 			ret = xmlCatalogListXMLResolve(
 1798: 				cur->children, pubID, NULL);
 1799: 			if (ret != NULL) {
 1800: 			    catal->depth--;
 1801: 			    return(ret);
 1802: 			}
 1803: 		    }
 1804: 		}
 1805: 		cur = cur->next;
 1806: 	    }
 1807: 	    /*
 1808: 	     * Apply the cut algorithm explained in 4/
 1809: 	     */
 1810: 	    catal->depth--;
 1811: 	    return(XML_CATAL_BREAK);
 1812: 	}
 1813:     }
 1814:     if (haveNext) {
 1815: 	cur = catal;
 1816: 	while (cur != NULL) {
 1817: 	    if (cur->type == XML_CATA_NEXT_CATALOG) {
 1818: 		if (cur->children == NULL) {
 1819: 		    xmlFetchXMLCatalogFile(cur);
 1820: 		}
 1821: 		if (cur->children != NULL) {
 1822: 		    ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
 1823: 		    if (ret != NULL) {
 1824: 			catal->depth--;
 1825: 			return(ret);
 1826: 		    } else if (catal->depth > MAX_CATAL_DEPTH) {
 1827: 		        return(NULL);
 1828: 		    }
 1829: 		}
 1830: 	    }
 1831: 	    cur = cur->next;
 1832: 	}
 1833:     }
 1834: 
 1835:     catal->depth--;
 1836:     return(NULL);
 1837: }
 1838: 
 1839: /**
 1840:  * xmlCatalogXMLResolveURI:
 1841:  * @catal:  a catalog list
 1842:  * @URI:  the URI
 1843:  * @sysID:  the system ID string
 1844:  *
 1845:  * Do a complete resolution lookup of an External Identifier for a
 1846:  * list of catalog entries.
 1847:  *
 1848:  * Implements (or tries to) 7.2.2. URI Resolution
 1849:  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
 1850:  *
 1851:  * Returns the URI of the resource or NULL if not found
 1852:  */
 1853: static xmlChar *
 1854: xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
 1855:     xmlChar *ret = NULL;
 1856:     xmlCatalogEntryPtr cur;
 1857:     int haveDelegate = 0;
 1858:     int haveNext = 0;
 1859:     xmlCatalogEntryPtr rewrite = NULL;
 1860:     int lenrewrite = 0, len;
 1861: 
 1862:     if (catal == NULL)
 1863: 	return(NULL);
 1864: 
 1865:     if (URI == NULL)
 1866: 	return(NULL);
 1867: 
 1868:     if (catal->depth > MAX_CATAL_DEPTH) {
 1869: 	xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
 1870: 		      "Detected recursion in catalog %s\n",
 1871: 		      catal->name, NULL, NULL);
 1872: 	return(NULL);
 1873:     }
 1874: 
 1875:     /*
 1876:      * First tries steps 2/ 3/ 4/ if a system ID is provided.
 1877:      */
 1878:     cur = catal;
 1879:     haveDelegate = 0;
 1880:     while (cur != NULL) {
 1881: 	switch (cur->type) {
 1882: 	    case XML_CATA_URI:
 1883: 		if (xmlStrEqual(URI, cur->name)) {
 1884: 		    if (xmlDebugCatalogs)
 1885: 			xmlGenericError(xmlGenericErrorContext,
 1886: 				"Found URI match %s\n", cur->name);
 1887: 		    return(xmlStrdup(cur->URL));
 1888: 		}
 1889: 		break;
 1890: 	    case XML_CATA_REWRITE_URI:
 1891: 		len = xmlStrlen(cur->name);
 1892: 		if ((len > lenrewrite) &&
 1893: 		    (!xmlStrncmp(URI, cur->name, len))) {
 1894: 		    lenrewrite = len;
 1895: 		    rewrite = cur;
 1896: 		}
 1897: 		break;
 1898: 	    case XML_CATA_DELEGATE_URI:
 1899: 		if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
 1900: 		    haveDelegate++;
 1901: 		break;
 1902: 	    case XML_CATA_NEXT_CATALOG:
 1903: 		haveNext++;
 1904: 		break;
 1905: 	    default:
 1906: 		break;
 1907: 	}
 1908: 	cur = cur->next;
 1909:     }
 1910:     if (rewrite != NULL) {
 1911: 	if (xmlDebugCatalogs)
 1912: 	    xmlGenericError(xmlGenericErrorContext,
 1913: 		    "Using rewriting rule %s\n", rewrite->name);
 1914: 	ret = xmlStrdup(rewrite->URL);
 1915: 	if (ret != NULL)
 1916: 	    ret = xmlStrcat(ret, &URI[lenrewrite]);
 1917: 	return(ret);
 1918:     }
 1919:     if (haveDelegate) {
 1920: 	const xmlChar *delegates[MAX_DELEGATE];
 1921: 	int nbList = 0, i;
 1922: 
 1923: 	/*
 1924: 	 * Assume the entries have been sorted by decreasing substring
 1925: 	 * matches when the list was produced.
 1926: 	 */
 1927: 	cur = catal;
 1928: 	while (cur != NULL) {
 1929: 	    if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
 1930: 	         (cur->type == XML_CATA_DELEGATE_URI)) &&
 1931: 		(!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
 1932: 		for (i = 0;i < nbList;i++)
 1933: 		    if (xmlStrEqual(cur->URL, delegates[i]))
 1934: 			break;
 1935: 		if (i < nbList) {
 1936: 		    cur = cur->next;
 1937: 		    continue;
 1938: 		}
 1939: 		if (nbList < MAX_DELEGATE)
 1940: 		    delegates[nbList++] = cur->URL;
 1941: 
 1942: 		if (cur->children == NULL) {
 1943: 		    xmlFetchXMLCatalogFile(cur);
 1944: 		}
 1945: 		if (cur->children != NULL) {
 1946: 		    if (xmlDebugCatalogs)
 1947: 			xmlGenericError(xmlGenericErrorContext,
 1948: 				"Trying URI delegate %s\n", cur->URL);
 1949: 		    ret = xmlCatalogListXMLResolveURI(
 1950: 			    cur->children, URI);
 1951: 		    if (ret != NULL)
 1952: 			return(ret);
 1953: 		}
 1954: 	    }
 1955: 	    cur = cur->next;
 1956: 	}
 1957: 	/*
 1958: 	 * Apply the cut algorithm explained in 4/
 1959: 	 */
 1960: 	return(XML_CATAL_BREAK);
 1961:     }
 1962:     if (haveNext) {
 1963: 	cur = catal;
 1964: 	while (cur != NULL) {
 1965: 	    if (cur->type == XML_CATA_NEXT_CATALOG) {
 1966: 		if (cur->children == NULL) {
 1967: 		    xmlFetchXMLCatalogFile(cur);
 1968: 		}
 1969: 		if (cur->children != NULL) {
 1970: 		    ret = xmlCatalogListXMLResolveURI(cur->children, URI);
 1971: 		    if (ret != NULL)
 1972: 			return(ret);
 1973: 		}
 1974: 	    }
 1975: 	    cur = cur->next;
 1976: 	}
 1977:     }
 1978: 
 1979:     return(NULL);
 1980: }
 1981: 
 1982: /**
 1983:  * xmlCatalogListXMLResolve:
 1984:  * @catal:  a catalog list
 1985:  * @pubID:  the public ID string
 1986:  * @sysID:  the system ID string
 1987:  *
 1988:  * Do a complete resolution lookup of an External Identifier for a
 1989:  * list of catalogs
 1990:  *
 1991:  * Implements (or tries to) 7.1. External Identifier Resolution
 1992:  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
 1993:  *
 1994:  * Returns the URI of the resource or NULL if not found
 1995:  */
 1996: static xmlChar *
 1997: xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
 1998: 	              const xmlChar *sysID) {
 1999:     xmlChar *ret = NULL;
 2000:     xmlChar *urnID = NULL;
 2001:     xmlChar *normid;
 2002:     
 2003:     if (catal == NULL)
 2004:         return(NULL);
 2005:     if ((pubID == NULL) && (sysID == NULL))
 2006: 	return(NULL);
 2007: 
 2008:     normid = xmlCatalogNormalizePublic(pubID);
 2009:     if (normid != NULL)
 2010:         pubID = (*normid != 0 ? normid : NULL);
 2011:     
 2012:     if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
 2013: 	urnID = xmlCatalogUnWrapURN(pubID);
 2014: 	if (xmlDebugCatalogs) {
 2015: 	    if (urnID == NULL)
 2016: 		xmlGenericError(xmlGenericErrorContext,
 2017: 			"Public URN ID %s expanded to NULL\n", pubID);
 2018: 	    else
 2019: 		xmlGenericError(xmlGenericErrorContext,
 2020: 			"Public URN ID expanded to %s\n", urnID);
 2021: 	}
 2022: 	ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
 2023: 	if (urnID != NULL)
 2024: 	    xmlFree(urnID);
 2025: 	if (normid != NULL)
 2026: 	    xmlFree(normid);
 2027: 	return(ret);
 2028:     }
 2029:     if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
 2030: 	urnID = xmlCatalogUnWrapURN(sysID);
 2031: 	if (xmlDebugCatalogs) {
 2032: 	    if (urnID == NULL)
 2033: 		xmlGenericError(xmlGenericErrorContext,
 2034: 			"System URN ID %s expanded to NULL\n", sysID);
 2035: 	    else
 2036: 		xmlGenericError(xmlGenericErrorContext,
 2037: 			"System URN ID expanded to %s\n", urnID);
 2038: 	}
 2039: 	if (pubID == NULL)
 2040: 	    ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
 2041: 	else if (xmlStrEqual(pubID, urnID))
 2042: 	    ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
 2043: 	else {
 2044: 	    ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
 2045: 	}
 2046: 	if (urnID != NULL)
 2047: 	    xmlFree(urnID);
 2048: 	if (normid != NULL)
 2049: 	    xmlFree(normid);
 2050: 	return(ret);
 2051:     }
 2052:     while (catal != NULL) {
 2053: 	if (catal->type == XML_CATA_CATALOG) {
 2054: 	    if (catal->children == NULL) {
 2055: 		xmlFetchXMLCatalogFile(catal);
 2056: 	    }
 2057: 	    if (catal->children != NULL) {
 2058: 		ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
 2059: 		if (ret != NULL) {
 2060: 		    break;
 2061:                 } else if ((catal->children != NULL) &&
 2062: 		           (catal->children->depth > MAX_CATAL_DEPTH)) {
 2063: 	            ret = NULL;
 2064: 		    break;
 2065: 	        }
 2066: 	    }
 2067: 	}
 2068: 	catal = catal->next;
 2069:     }
 2070:     if (normid != NULL)
 2071: 	xmlFree(normid);
 2072:     return(ret);
 2073: }
 2074: 
 2075: /**
 2076:  * xmlCatalogListXMLResolveURI:
 2077:  * @catal:  a catalog list
 2078:  * @URI:  the URI
 2079:  *
 2080:  * Do a complete resolution lookup of an URI for a list of catalogs
 2081:  *
 2082:  * Implements (or tries to) 7.2. URI Resolution
 2083:  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
 2084:  *
 2085:  * Returns the URI of the resource or NULL if not found
 2086:  */
 2087: static xmlChar *
 2088: xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
 2089:     xmlChar *ret = NULL;
 2090:     xmlChar *urnID = NULL;
 2091:     
 2092:     if (catal == NULL)
 2093:         return(NULL);
 2094:     if (URI == NULL)
 2095: 	return(NULL);
 2096: 
 2097:     if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
 2098: 	urnID = xmlCatalogUnWrapURN(URI);
 2099: 	if (xmlDebugCatalogs) {
 2100: 	    if (urnID == NULL)
 2101: 		xmlGenericError(xmlGenericErrorContext,
 2102: 			"URN ID %s expanded to NULL\n", URI);
 2103: 	    else
 2104: 		xmlGenericError(xmlGenericErrorContext,
 2105: 			"URN ID expanded to %s\n", urnID);
 2106: 	}
 2107: 	ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
 2108: 	if (urnID != NULL)
 2109: 	    xmlFree(urnID);
 2110: 	return(ret);
 2111:     }
 2112:     while (catal != NULL) {
 2113: 	if (catal->type == XML_CATA_CATALOG) {
 2114: 	    if (catal->children == NULL) {
 2115: 		xmlFetchXMLCatalogFile(catal);
 2116: 	    }
 2117: 	    if (catal->children != NULL) {
 2118: 		ret = xmlCatalogXMLResolveURI(catal->children, URI);
 2119: 		if (ret != NULL)
 2120: 		    return(ret);
 2121: 	    }
 2122: 	}
 2123: 	catal = catal->next;
 2124:     }
 2125:     return(ret);
 2126: }
 2127: 
 2128: /************************************************************************
 2129:  *									*
 2130:  *			The SGML Catalog parser				*
 2131:  *									*
 2132:  ************************************************************************/
 2133: 
 2134: 
 2135: #define RAW *cur
 2136: #define NEXT cur++;
 2137: #define SKIP(x) cur += x;
 2138: 
 2139: #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
 2140: 
 2141: /**
 2142:  * xmlParseSGMLCatalogComment:
 2143:  * @cur:  the current character
 2144:  *
 2145:  * Skip a comment in an SGML catalog
 2146:  *
 2147:  * Returns new current character
 2148:  */
 2149: static const xmlChar *
 2150: xmlParseSGMLCatalogComment(const xmlChar *cur) {
 2151:     if ((cur[0] != '-') || (cur[1] != '-')) 
 2152: 	return(cur);
 2153:     SKIP(2);
 2154:     while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
 2155: 	NEXT;
 2156:     if (cur[0] == 0) {
 2157: 	return(NULL);
 2158:     }
 2159:     return(cur + 2);
 2160: }
 2161: 
 2162: /**
 2163:  * xmlParseSGMLCatalogPubid:
 2164:  * @cur:  the current character
 2165:  * @id:  the return location
 2166:  *
 2167:  * Parse an SGML catalog ID
 2168:  *
 2169:  * Returns new current character and store the value in @id
 2170:  */
 2171: static const xmlChar *
 2172: xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
 2173:     xmlChar *buf = NULL, *tmp;
 2174:     int len = 0;
 2175:     int size = 50;
 2176:     xmlChar stop;
 2177:     int count = 0;
 2178: 
 2179:     *id = NULL;
 2180: 
 2181:     if (RAW == '"') {
 2182:         NEXT;
 2183: 	stop = '"';
 2184:     } else if (RAW == '\'') {
 2185:         NEXT;
 2186: 	stop = '\'';
 2187:     } else {
 2188: 	stop = ' ';
 2189:     }
 2190:     buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
 2191:     if (buf == NULL) {
 2192:         xmlCatalogErrMemory("allocating public ID");
 2193: 	return(NULL);
 2194:     }
 2195:     while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
 2196: 	if ((*cur == stop) && (stop != ' '))
 2197: 	    break;
 2198: 	if ((stop == ' ') && (IS_BLANK_CH(*cur)))
 2199: 	    break;
 2200: 	if (len + 1 >= size) {
 2201: 	    size *= 2;
 2202: 	    tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
 2203: 	    if (tmp == NULL) {
 2204: 		xmlCatalogErrMemory("allocating public ID");
 2205: 		xmlFree(buf);
 2206: 		return(NULL);
 2207: 	    }
 2208: 	    buf = tmp;
 2209: 	}
 2210: 	buf[len++] = *cur;
 2211: 	count++;
 2212: 	NEXT;
 2213:     }
 2214:     buf[len] = 0;
 2215:     if (stop == ' ') {
 2216: 	if (!IS_BLANK_CH(*cur)) {
 2217: 	    xmlFree(buf);
 2218: 	    return(NULL);
 2219: 	}
 2220:     } else {
 2221: 	if (*cur != stop) {
 2222: 	    xmlFree(buf);
 2223: 	    return(NULL);
 2224: 	}
 2225: 	NEXT;
 2226:     }
 2227:     *id = buf;
 2228:     return(cur);
 2229: }
 2230: 
 2231: /**
 2232:  * xmlParseSGMLCatalogName:
 2233:  * @cur:  the current character
 2234:  * @name:  the return location
 2235:  *
 2236:  * Parse an SGML catalog name
 2237:  *
 2238:  * Returns new current character and store the value in @name
 2239:  */
 2240: static const xmlChar *
 2241: xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
 2242:     xmlChar buf[XML_MAX_NAMELEN + 5];
 2243:     int len = 0;
 2244:     int c;
 2245: 
 2246:     *name = NULL;
 2247: 
 2248:     /*
 2249:      * Handler for more complex cases
 2250:      */
 2251:     c = *cur;
 2252:     if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
 2253: 	return(NULL);
 2254:     }
 2255: 
 2256:     while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
 2257:             (c == '.') || (c == '-') ||
 2258: 	    (c == '_') || (c == ':'))) {
 2259: 	buf[len++] = c;
 2260: 	cur++;
 2261: 	c = *cur;
 2262: 	if (len >= XML_MAX_NAMELEN)
 2263: 	    return(NULL);
 2264:     }
 2265:     *name = xmlStrndup(buf, len);
 2266:     return(cur);
 2267: }
 2268: 
 2269: /**
 2270:  * xmlGetSGMLCatalogEntryType:
 2271:  * @name:  the entry name
 2272:  *
 2273:  * Get the Catalog entry type for a given SGML Catalog name
 2274:  *
 2275:  * Returns Catalog entry type
 2276:  */
 2277: static xmlCatalogEntryType
 2278: xmlGetSGMLCatalogEntryType(const xmlChar *name) {
 2279:     xmlCatalogEntryType type = XML_CATA_NONE;
 2280:     if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
 2281: 	type = SGML_CATA_SYSTEM;
 2282:     else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
 2283: 	type = SGML_CATA_PUBLIC;
 2284:     else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
 2285: 	type = SGML_CATA_DELEGATE;
 2286:     else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
 2287: 	type = SGML_CATA_ENTITY;
 2288:     else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
 2289: 	type = SGML_CATA_DOCTYPE;
 2290:     else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
 2291: 	type = SGML_CATA_LINKTYPE;
 2292:     else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
 2293: 	type = SGML_CATA_NOTATION;
 2294:     else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
 2295: 	type = SGML_CATA_SGMLDECL;
 2296:     else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
 2297: 	type = SGML_CATA_DOCUMENT;
 2298:     else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
 2299: 	type = SGML_CATA_CATALOG;
 2300:     else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
 2301: 	type = SGML_CATA_BASE;
 2302:     return(type);
 2303: }
 2304: 
 2305: /**
 2306:  * xmlParseSGMLCatalog:
 2307:  * @catal:  the SGML Catalog
 2308:  * @value:  the content of the SGML Catalog serialization
 2309:  * @file:  the filepath for the catalog
 2310:  * @super:  should this be handled as a Super Catalog in which case
 2311:  *          parsing is not recursive
 2312:  *
 2313:  * Parse an SGML catalog content and fill up the @catal hash table with
 2314:  * the new entries found.
 2315:  *
 2316:  * Returns 0 in case of success, -1 in case of error.
 2317:  */
 2318: static int
 2319: xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
 2320: 	            const char *file, int super) {
 2321:     const xmlChar *cur = value;
 2322:     xmlChar *base = NULL;
 2323:     int res;
 2324: 
 2325:     if ((cur == NULL) || (file == NULL))
 2326:         return(-1);
 2327:     base = xmlStrdup((const xmlChar *) file);
 2328: 
 2329:     while ((cur != NULL) && (cur[0] != 0)) {
 2330: 	SKIP_BLANKS;
 2331: 	if (cur[0] == 0)
 2332: 	    break;
 2333: 	if ((cur[0] == '-') && (cur[1] == '-')) {
 2334: 	    cur = xmlParseSGMLCatalogComment(cur);
 2335: 	    if (cur == NULL) {
 2336: 		/* error */
 2337: 		break;
 2338: 	    }
 2339: 	} else {
 2340: 	    xmlChar *sysid = NULL;
 2341: 	    xmlChar *name = NULL;
 2342: 	    xmlCatalogEntryType type = XML_CATA_NONE;
 2343: 
 2344: 	    cur = xmlParseSGMLCatalogName(cur, &name);
 2345: 	    if (name == NULL) {
 2346: 		/* error */
 2347: 		break;
 2348: 	    }
 2349: 	    if (!IS_BLANK_CH(*cur)) {
 2350: 		/* error */
 2351: 		break;
 2352: 	    }
 2353: 	    SKIP_BLANKS;
 2354: 	    if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
 2355:                 type = SGML_CATA_SYSTEM;
 2356: 	    else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
 2357:                 type = SGML_CATA_PUBLIC;
 2358: 	    else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
 2359:                 type = SGML_CATA_DELEGATE;
 2360: 	    else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
 2361:                 type = SGML_CATA_ENTITY;
 2362: 	    else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
 2363:                 type = SGML_CATA_DOCTYPE;
 2364: 	    else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
 2365:                 type = SGML_CATA_LINKTYPE;
 2366: 	    else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
 2367:                 type = SGML_CATA_NOTATION;
 2368: 	    else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
 2369:                 type = SGML_CATA_SGMLDECL;
 2370: 	    else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
 2371:                 type = SGML_CATA_DOCUMENT;
 2372: 	    else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
 2373:                 type = SGML_CATA_CATALOG;
 2374: 	    else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
 2375:                 type = SGML_CATA_BASE;
 2376: 	    else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
 2377: 		xmlFree(name);
 2378: 		cur = xmlParseSGMLCatalogName(cur, &name);
 2379: 		if (name == NULL) {
 2380: 		    /* error */
 2381: 		    break;
 2382: 		}
 2383: 		xmlFree(name);
 2384: 		continue;
 2385: 	    }
 2386: 	    xmlFree(name);
 2387: 	    name = NULL;
 2388: 
 2389: 	    switch(type) {
 2390: 		case SGML_CATA_ENTITY:
 2391: 		    if (*cur == '%')
 2392: 			type = SGML_CATA_PENTITY;
 2393: 		case SGML_CATA_PENTITY:
 2394: 		case SGML_CATA_DOCTYPE:
 2395: 		case SGML_CATA_LINKTYPE:
 2396: 		case SGML_CATA_NOTATION:
 2397: 		    cur = xmlParseSGMLCatalogName(cur, &name);
 2398: 		    if (cur == NULL) {
 2399: 			/* error */
 2400: 			break;
 2401: 		    }
 2402: 		    if (!IS_BLANK_CH(*cur)) {
 2403: 			/* error */
 2404: 			break;
 2405: 		    }
 2406: 		    SKIP_BLANKS;
 2407: 		    cur = xmlParseSGMLCatalogPubid(cur, &sysid);
 2408: 		    if (cur == NULL) {
 2409: 			/* error */
 2410: 			break;
 2411: 		    }
 2412: 		    break;
 2413: 		case SGML_CATA_PUBLIC:
 2414: 		case SGML_CATA_SYSTEM:
 2415: 		case SGML_CATA_DELEGATE:
 2416: 		    cur = xmlParseSGMLCatalogPubid(cur, &name);
 2417: 		    if (cur == NULL) {
 2418: 			/* error */
 2419: 			break;
 2420: 		    }
 2421: 		    if (type != SGML_CATA_SYSTEM) {
 2422: 		        xmlChar *normid;
 2423: 
 2424: 		        normid = xmlCatalogNormalizePublic(name);
 2425: 		        if (normid != NULL) {
 2426: 		            if (name != NULL)
 2427: 		                xmlFree(name);
 2428: 		            if (*normid != 0)
 2429: 		                name = normid;
 2430: 		            else {
 2431: 		                xmlFree(normid);
 2432: 		                name = NULL;
 2433: 		            }
 2434: 		        }
 2435: 		    }
 2436: 		    if (!IS_BLANK_CH(*cur)) {
 2437: 			/* error */
 2438: 			break;
 2439: 		    }
 2440: 		    SKIP_BLANKS;
 2441: 		    cur = xmlParseSGMLCatalogPubid(cur, &sysid);
 2442: 		    if (cur == NULL) {
 2443: 			/* error */
 2444: 			break;
 2445: 		    }
 2446: 		    break;
 2447: 		case SGML_CATA_BASE:
 2448: 		case SGML_CATA_CATALOG:
 2449: 		case SGML_CATA_DOCUMENT:
 2450: 		case SGML_CATA_SGMLDECL:
 2451: 		    cur = xmlParseSGMLCatalogPubid(cur, &sysid);
 2452: 		    if (cur == NULL) {
 2453: 			/* error */
 2454: 			break;
 2455: 		    }
 2456: 		    break;
 2457: 		default:
 2458: 		    break;
 2459: 	    }
 2460: 	    if (cur == NULL) {
 2461: 		if (name != NULL)
 2462: 		    xmlFree(name);
 2463: 		if (sysid != NULL)
 2464: 		    xmlFree(sysid);
 2465: 		break;
 2466: 	    } else if (type == SGML_CATA_BASE) {
 2467: 		if (base != NULL)
 2468: 		    xmlFree(base);
 2469: 		base = xmlStrdup(sysid);
 2470: 	    } else if ((type == SGML_CATA_PUBLIC) ||
 2471: 		       (type == SGML_CATA_SYSTEM)) {
 2472: 		xmlChar *filename;
 2473: 
 2474: 		filename = xmlBuildURI(sysid, base);
 2475: 		if (filename != NULL) {
 2476: 		    xmlCatalogEntryPtr entry;
 2477: 
 2478: 		    entry = xmlNewCatalogEntry(type, name, filename,
 2479: 			                       NULL, XML_CATA_PREFER_NONE, NULL);
 2480: 		    res = xmlHashAddEntry(catal->sgml, name, entry);
 2481: 		    if (res < 0) {
 2482: 			xmlFreeCatalogEntry(entry);
 2483: 		    }
 2484: 		    xmlFree(filename);
 2485: 		}
 2486: 
 2487: 	    } else if (type == SGML_CATA_CATALOG) {
 2488: 		if (super) {
 2489: 		    xmlCatalogEntryPtr entry;
 2490: 
 2491: 		    entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
 2492: 			                       XML_CATA_PREFER_NONE, NULL);
 2493: 		    res = xmlHashAddEntry(catal->sgml, sysid, entry);
 2494: 		    if (res < 0) {
 2495: 			xmlFreeCatalogEntry(entry);
 2496: 		    }
 2497: 		} else {
 2498: 		    xmlChar *filename;
 2499: 
 2500: 		    filename = xmlBuildURI(sysid, base);
 2501: 		    if (filename != NULL) {
 2502: 			xmlExpandCatalog(catal, (const char *)filename);
 2503: 			xmlFree(filename);
 2504: 		    }
 2505: 		}
 2506: 	    }
 2507: 	    /*
 2508: 	     * drop anything else we won't handle it
 2509: 	     */
 2510: 	    if (name != NULL)
 2511: 		xmlFree(name);
 2512: 	    if (sysid != NULL)
 2513: 		xmlFree(sysid);
 2514: 	}
 2515:     }
 2516:     if (base != NULL)
 2517: 	xmlFree(base);
 2518:     if (cur == NULL)
 2519: 	return(-1);
 2520:     return(0);
 2521: }
 2522: 
 2523: /************************************************************************
 2524:  *									*
 2525:  *			SGML Catalog handling				*
 2526:  *									*
 2527:  ************************************************************************/
 2528: 
 2529: /**
 2530:  * xmlCatalogGetSGMLPublic:
 2531:  * @catal:  an SGML catalog hash
 2532:  * @pubID:  the public ID string
 2533:  *
 2534:  * Try to lookup the catalog local reference associated to a public ID
 2535:  *
 2536:  * Returns the local resource if found or NULL otherwise.
 2537:  */
 2538: static const xmlChar *
 2539: xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
 2540:     xmlCatalogEntryPtr entry;
 2541:     xmlChar *normid;
 2542: 
 2543:     if (catal == NULL)
 2544: 	return(NULL);
 2545: 
 2546:     normid = xmlCatalogNormalizePublic(pubID);
 2547:     if (normid != NULL)
 2548:         pubID = (*normid != 0 ? normid : NULL);
 2549: 
 2550:     entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
 2551:     if (entry == NULL) {
 2552: 	if (normid != NULL)
 2553: 	    xmlFree(normid);
 2554: 	return(NULL);
 2555:     }
 2556:     if (entry->type == SGML_CATA_PUBLIC) {
 2557: 	if (normid != NULL)
 2558: 	    xmlFree(normid);
 2559: 	return(entry->URL);
 2560:     }
 2561:     if (normid != NULL)
 2562:         xmlFree(normid);
 2563:     return(NULL);
 2564: }
 2565: 
 2566: /**
 2567:  * xmlCatalogGetSGMLSystem:
 2568:  * @catal:  an SGML catalog hash
 2569:  * @sysID:  the system ID string
 2570:  *
 2571:  * Try to lookup the catalog local reference for a system ID
 2572:  *
 2573:  * Returns the local resource if found or NULL otherwise.
 2574:  */
 2575: static const xmlChar *
 2576: xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
 2577:     xmlCatalogEntryPtr entry;
 2578: 
 2579:     if (catal == NULL)
 2580: 	return(NULL);
 2581: 
 2582:     entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
 2583:     if (entry == NULL)
 2584: 	return(NULL);
 2585:     if (entry->type == SGML_CATA_SYSTEM)
 2586: 	return(entry->URL);
 2587:     return(NULL);
 2588: }
 2589: 
 2590: /**
 2591:  * xmlCatalogSGMLResolve:
 2592:  * @catal:  the SGML catalog
 2593:  * @pubID:  the public ID string
 2594:  * @sysID:  the system ID string
 2595:  *
 2596:  * Do a complete resolution lookup of an External Identifier
 2597:  *
 2598:  * Returns the URI of the resource or NULL if not found
 2599:  */
 2600: static const xmlChar *
 2601: xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
 2602: 	              const xmlChar *sysID) {
 2603:     const xmlChar *ret = NULL;
 2604: 
 2605:     if (catal->sgml == NULL)
 2606: 	return(NULL);
 2607: 
 2608:     if (pubID != NULL)
 2609: 	ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
 2610:     if (ret != NULL)
 2611: 	return(ret);
 2612:     if (sysID != NULL)
 2613: 	ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
 2614:     if (ret != NULL)
 2615: 	return(ret);
 2616:     return(NULL);
 2617: }
 2618: 
 2619: /************************************************************************
 2620:  *									*
 2621:  *			Specific Public interfaces			*
 2622:  *									*
 2623:  ************************************************************************/
 2624: 
 2625: /**
 2626:  * xmlLoadSGMLSuperCatalog:
 2627:  * @filename:  a file path
 2628:  *
 2629:  * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
 2630:  * references. This is only needed for manipulating SGML Super Catalogs
 2631:  * like adding and removing CATALOG or DELEGATE entries.
 2632:  *
 2633:  * Returns the catalog parsed or NULL in case of error
 2634:  */
 2635: xmlCatalogPtr
 2636: xmlLoadSGMLSuperCatalog(const char *filename)
 2637: {
 2638:     xmlChar *content;
 2639:     xmlCatalogPtr catal;
 2640:     int ret;
 2641: 
 2642:     content = xmlLoadFileContent(filename);
 2643:     if (content == NULL)
 2644:         return(NULL);
 2645: 
 2646:     catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
 2647:     if (catal == NULL) {
 2648: 	xmlFree(content);
 2649: 	return(NULL);
 2650:     }
 2651: 
 2652:     ret = xmlParseSGMLCatalog(catal, content, filename, 1);
 2653:     xmlFree(content);
 2654:     if (ret < 0) {
 2655: 	xmlFreeCatalog(catal);
 2656: 	return(NULL);
 2657:     }
 2658:     return (catal);
 2659: }
 2660: 
 2661: /**
 2662:  * xmlLoadACatalog:
 2663:  * @filename:  a file path
 2664:  *
 2665:  * Load the catalog and build the associated data structures.
 2666:  * This can be either an XML Catalog or an SGML Catalog
 2667:  * It will recurse in SGML CATALOG entries. On the other hand XML
 2668:  * Catalogs are not handled recursively.
 2669:  *
 2670:  * Returns the catalog parsed or NULL in case of error
 2671:  */
 2672: xmlCatalogPtr
 2673: xmlLoadACatalog(const char *filename)
 2674: {
 2675:     xmlChar *content;
 2676:     xmlChar *first;
 2677:     xmlCatalogPtr catal;
 2678:     int ret;
 2679: 
 2680:     content = xmlLoadFileContent(filename);
 2681:     if (content == NULL)
 2682:         return(NULL);
 2683: 
 2684: 
 2685:     first = content;
 2686:    
 2687:     while ((*first != 0) && (*first != '-') && (*first != '<') &&
 2688: 	   (!(((*first >= 'A') && (*first <= 'Z')) ||
 2689: 	      ((*first >= 'a') && (*first <= 'z')))))
 2690: 	first++;
 2691: 
 2692:     if (*first != '<') {
 2693: 	catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
 2694: 	if (catal == NULL) {
 2695: 	    xmlFree(content);
 2696: 	    return(NULL);
 2697: 	}
 2698:         ret = xmlParseSGMLCatalog(catal, content, filename, 0);
 2699: 	if (ret < 0) {
 2700: 	    xmlFreeCatalog(catal);
 2701: 	    xmlFree(content);
 2702: 	    return(NULL);
 2703: 	}
 2704:     } else {
 2705: 	catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
 2706: 	if (catal == NULL) {
 2707: 	    xmlFree(content);
 2708: 	    return(NULL);
 2709: 	}
 2710:         catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
 2711: 		       NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
 2712:     }
 2713:     xmlFree(content);
 2714:     return (catal);
 2715: }
 2716: 
 2717: /**
 2718:  * xmlExpandCatalog:
 2719:  * @catal:  a catalog
 2720:  * @filename:  a file path
 2721:  *
 2722:  * Load the catalog and expand the existing catal structure.
 2723:  * This can be either an XML Catalog or an SGML Catalog
 2724:  *
 2725:  * Returns 0 in case of success, -1 in case of error
 2726:  */
 2727: static int
 2728: xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
 2729: {
 2730:     int ret;
 2731: 
 2732:     if ((catal == NULL) || (filename == NULL))
 2733: 	return(-1);
 2734: 
 2735: 
 2736:     if (catal->type == XML_SGML_CATALOG_TYPE) {
 2737: 	xmlChar *content;
 2738: 
 2739: 	content = xmlLoadFileContent(filename);
 2740: 	if (content == NULL)
 2741: 	    return(-1);
 2742: 
 2743:         ret = xmlParseSGMLCatalog(catal, content, filename, 0);
 2744: 	if (ret < 0) {
 2745: 	    xmlFree(content);
 2746: 	    return(-1);
 2747: 	}
 2748: 	xmlFree(content);
 2749:     } else {
 2750: 	xmlCatalogEntryPtr tmp, cur;
 2751: 	tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
 2752: 		       NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
 2753: 
 2754: 	cur = catal->xml;
 2755: 	if (cur == NULL) {
 2756: 	    catal->xml = tmp;
 2757: 	} else {
 2758: 	    while (cur->next != NULL) cur = cur->next;
 2759: 	    cur->next = tmp;
 2760: 	}
 2761:     }
 2762:     return (0);
 2763: }
 2764: 
 2765: /**
 2766:  * xmlACatalogResolveSystem:
 2767:  * @catal:  a Catalog
 2768:  * @sysID:  the system ID string
 2769:  *
 2770:  * Try to lookup the catalog resource for a system ID
 2771:  *
 2772:  * Returns the resource if found or NULL otherwise, the value returned
 2773:  *      must be freed by the caller.
 2774:  */
 2775: xmlChar *
 2776: xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
 2777:     xmlChar *ret = NULL;
 2778: 
 2779:     if ((sysID == NULL) || (catal == NULL))
 2780: 	return(NULL);
 2781:     
 2782:     if (xmlDebugCatalogs)
 2783: 	xmlGenericError(xmlGenericErrorContext,
 2784: 		"Resolve sysID %s\n", sysID);
 2785: 
 2786:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2787: 	ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
 2788: 	if (ret == XML_CATAL_BREAK)
 2789: 	    ret = NULL;
 2790:     } else {
 2791: 	const xmlChar *sgml;
 2792: 
 2793: 	sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
 2794: 	if (sgml != NULL)
 2795: 	    ret = xmlStrdup(sgml);
 2796:     }
 2797:     return(ret);
 2798: }
 2799: 
 2800: /**
 2801:  * xmlACatalogResolvePublic:
 2802:  * @catal:  a Catalog
 2803:  * @pubID:  the public ID string
 2804:  *
 2805:  * Try to lookup the catalog local reference associated to a public ID in that catalog
 2806:  *
 2807:  * Returns the local resource if found or NULL otherwise, the value returned
 2808:  *      must be freed by the caller.
 2809:  */
 2810: xmlChar *
 2811: xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
 2812:     xmlChar *ret = NULL;
 2813: 
 2814:     if ((pubID == NULL) || (catal == NULL))
 2815: 	return(NULL);
 2816:     
 2817:     if (xmlDebugCatalogs)
 2818: 	xmlGenericError(xmlGenericErrorContext,
 2819: 		"Resolve pubID %s\n", pubID);
 2820: 
 2821:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2822: 	ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
 2823: 	if (ret == XML_CATAL_BREAK)
 2824: 	    ret = NULL;
 2825:     } else {
 2826: 	const xmlChar *sgml;
 2827: 
 2828: 	sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
 2829: 	if (sgml != NULL)
 2830: 	    ret = xmlStrdup(sgml);
 2831:     }
 2832:     return(ret);
 2833: }
 2834: 
 2835: /**
 2836:  * xmlACatalogResolve:
 2837:  * @catal:  a Catalog
 2838:  * @pubID:  the public ID string
 2839:  * @sysID:  the system ID string
 2840:  *
 2841:  * Do a complete resolution lookup of an External Identifier
 2842:  *
 2843:  * Returns the URI of the resource or NULL if not found, it must be freed
 2844:  *      by the caller.
 2845:  */
 2846: xmlChar *
 2847: xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
 2848:                    const xmlChar * sysID)
 2849: {
 2850:     xmlChar *ret = NULL;
 2851: 
 2852:     if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
 2853:         return (NULL);
 2854: 
 2855:     if (xmlDebugCatalogs) {
 2856:          if ((pubID != NULL) && (sysID != NULL)) {
 2857:              xmlGenericError(xmlGenericErrorContext,
 2858:                              "Resolve: pubID %s sysID %s\n", pubID, sysID);
 2859:          } else if (pubID != NULL) {
 2860:              xmlGenericError(xmlGenericErrorContext,
 2861:                              "Resolve: pubID %s\n", pubID);
 2862:          } else {
 2863:              xmlGenericError(xmlGenericErrorContext,
 2864:                              "Resolve: sysID %s\n", sysID);
 2865:          }
 2866:     }
 2867: 
 2868:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2869:         ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
 2870: 	if (ret == XML_CATAL_BREAK)
 2871: 	    ret = NULL;
 2872:     } else {
 2873:         const xmlChar *sgml;
 2874: 
 2875:         sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
 2876:         if (sgml != NULL)
 2877:             ret = xmlStrdup(sgml);
 2878:     }
 2879:     return (ret);
 2880: }
 2881: 
 2882: /**
 2883:  * xmlACatalogResolveURI:
 2884:  * @catal:  a Catalog
 2885:  * @URI:  the URI
 2886:  *
 2887:  * Do a complete resolution lookup of an URI
 2888:  *
 2889:  * Returns the URI of the resource or NULL if not found, it must be freed
 2890:  *      by the caller.
 2891:  */
 2892: xmlChar *
 2893: xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
 2894:     xmlChar *ret = NULL;
 2895: 
 2896:     if ((URI == NULL) || (catal == NULL))
 2897: 	return(NULL);
 2898: 
 2899:     if (xmlDebugCatalogs)
 2900: 	xmlGenericError(xmlGenericErrorContext,
 2901: 		"Resolve URI %s\n", URI);
 2902: 
 2903:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2904: 	ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
 2905: 	if (ret == XML_CATAL_BREAK)
 2906: 	    ret = NULL;
 2907:     } else {
 2908: 	const xmlChar *sgml;
 2909: 
 2910: 	sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
 2911: 	if (sgml != NULL)
 2912:             ret = xmlStrdup(sgml);
 2913:     }
 2914:     return(ret);
 2915: }
 2916: 
 2917: #ifdef LIBXML_OUTPUT_ENABLED
 2918: /**
 2919:  * xmlACatalogDump:
 2920:  * @catal:  a Catalog
 2921:  * @out:  the file.
 2922:  *
 2923:  * Dump the given catalog to the given file.
 2924:  */
 2925: void
 2926: xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
 2927:     if ((out == NULL) || (catal == NULL))
 2928: 	return;
 2929: 
 2930:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2931: 	xmlDumpXMLCatalog(out, catal->xml);
 2932:     } else {
 2933: 	xmlHashScan(catal->sgml,
 2934: 		    (xmlHashScanner) xmlCatalogDumpEntry, out);
 2935:     } 
 2936: }
 2937: #endif /* LIBXML_OUTPUT_ENABLED */
 2938: 
 2939: /**
 2940:  * xmlACatalogAdd:
 2941:  * @catal:  a Catalog
 2942:  * @type:  the type of record to add to the catalog
 2943:  * @orig:  the system, public or prefix to match 
 2944:  * @replace:  the replacement value for the match
 2945:  *
 2946:  * Add an entry in the catalog, it may overwrite existing but
 2947:  * different entries.
 2948:  *
 2949:  * Returns 0 if successful, -1 otherwise
 2950:  */
 2951: int
 2952: xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
 2953:               const xmlChar * orig, const xmlChar * replace)
 2954: {
 2955:     int res = -1;
 2956: 
 2957:     if (catal == NULL)
 2958: 	return(-1);
 2959: 
 2960:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2961:         res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
 2962:     } else {
 2963:         xmlCatalogEntryType cattype;
 2964: 
 2965:         cattype = xmlGetSGMLCatalogEntryType(type);
 2966:         if (cattype != XML_CATA_NONE) {
 2967:             xmlCatalogEntryPtr entry;
 2968: 
 2969:             entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
 2970:                                        XML_CATA_PREFER_NONE, NULL);
 2971: 	    if (catal->sgml == NULL)
 2972: 		catal->sgml = xmlHashCreate(10);
 2973:             res = xmlHashAddEntry(catal->sgml, orig, entry);
 2974:         }
 2975:     }
 2976:     return (res);
 2977: }
 2978: 
 2979: /**
 2980:  * xmlACatalogRemove:
 2981:  * @catal:  a Catalog
 2982:  * @value:  the value to remove
 2983:  *
 2984:  * Remove an entry from the catalog
 2985:  *
 2986:  * Returns the number of entries removed if successful, -1 otherwise
 2987:  */
 2988: int
 2989: xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
 2990:     int res = -1;
 2991: 
 2992:     if ((catal == NULL) || (value == NULL))
 2993: 	return(-1);
 2994: 
 2995:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2996: 	res = xmlDelXMLCatalog(catal->xml, value);
 2997:     } else {
 2998: 	res = xmlHashRemoveEntry(catal->sgml, value,
 2999: 		(xmlHashDeallocator) xmlFreeCatalogEntry);
 3000: 	if (res == 0)
 3001: 	    res = 1;
 3002:     } 
 3003:     return(res);
 3004: }
 3005: 
 3006: /**
 3007:  * xmlNewCatalog:
 3008:  * @sgml:  should this create an SGML catalog
 3009:  *
 3010:  * create a new Catalog.
 3011:  *
 3012:  * Returns the xmlCatalogPtr or NULL in case of error
 3013:  */
 3014: xmlCatalogPtr
 3015: xmlNewCatalog(int sgml) {
 3016:     xmlCatalogPtr catal = NULL;
 3017: 
 3018:     if (sgml) {
 3019: 	catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
 3020: 		                    xmlCatalogDefaultPrefer);
 3021:         if ((catal != NULL) && (catal->sgml == NULL))
 3022: 	    catal->sgml = xmlHashCreate(10);
 3023:     } else
 3024: 	catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
 3025: 		                    xmlCatalogDefaultPrefer);
 3026:     return(catal);
 3027: }
 3028: 
 3029: /**
 3030:  * xmlCatalogIsEmpty:
 3031:  * @catal:  should this create an SGML catalog
 3032:  *
 3033:  * Check is a catalog is empty
 3034:  *
 3035:  * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
 3036:  */
 3037: int
 3038: xmlCatalogIsEmpty(xmlCatalogPtr catal) {
 3039:     if (catal == NULL)
 3040: 	return(-1);
 3041: 
 3042:     if (catal->type == XML_XML_CATALOG_TYPE) {
 3043: 	if (catal->xml == NULL)
 3044: 	    return(1);
 3045: 	if ((catal->xml->type != XML_CATA_CATALOG) &&
 3046: 	    (catal->xml->type != XML_CATA_BROKEN_CATALOG))
 3047: 	    return(-1);
 3048: 	if (catal->xml->children == NULL)
 3049: 	    return(1);
 3050:         return(0);
 3051:     } else {
 3052: 	int res;
 3053: 
 3054: 	if (catal->sgml == NULL)
 3055: 	    return(1);
 3056: 	res = xmlHashSize(catal->sgml);
 3057: 	if (res == 0)
 3058: 	    return(1);
 3059: 	if (res < 0)
 3060: 	    return(-1);
 3061:     } 
 3062:     return(0);
 3063: }
 3064: 
 3065: /************************************************************************
 3066:  *									*
 3067:  *   Public interfaces manipulating the global shared default catalog	*
 3068:  *									*
 3069:  ************************************************************************/
 3070: 
 3071: /**
 3072:  * xmlInitializeCatalogData:
 3073:  *
 3074:  * Do the catalog initialization only of global data, doesn't try to load
 3075:  * any catalog actually.
 3076:  * this function is not thread safe, catalog initialization should
 3077:  * preferably be done once at startup
 3078:  */
 3079: static void
 3080: xmlInitializeCatalogData(void) {
 3081:     if (xmlCatalogInitialized != 0)
 3082: 	return;
 3083: 
 3084:     if (getenv("XML_DEBUG_CATALOG")) 
 3085: 	xmlDebugCatalogs = 1;
 3086:     xmlCatalogMutex = xmlNewRMutex();
 3087: 
 3088:     xmlCatalogInitialized = 1;
 3089: }
 3090: /**
 3091:  * xmlInitializeCatalog:
 3092:  *
 3093:  * Do the catalog initialization.
 3094:  * this function is not thread safe, catalog initialization should
 3095:  * preferably be done once at startup
 3096:  */
 3097: void
 3098: xmlInitializeCatalog(void) {
 3099:     if (xmlCatalogInitialized != 0)
 3100: 	return;
 3101: 
 3102:     xmlInitializeCatalogData();
 3103:     xmlRMutexLock(xmlCatalogMutex);
 3104: 
 3105:     if (getenv("XML_DEBUG_CATALOG")) 
 3106: 	xmlDebugCatalogs = 1;
 3107: 
 3108:     if (xmlDefaultCatalog == NULL) {
 3109: 	const char *catalogs;
 3110: 	char *path;
 3111: 	const char *cur, *paths;
 3112: 	xmlCatalogPtr catal;
 3113: 	xmlCatalogEntryPtr *nextent;
 3114: 
 3115: 	catalogs = (const char *) getenv("XML_CATALOG_FILES");
 3116: 	if (catalogs == NULL)
 3117: #if defined(_WIN32) && defined(_MSC_VER)
 3118:     {
 3119: 		void* hmodule;
 3120: 		hmodule = GetModuleHandleA("libxml2.dll");
 3121: 		if (hmodule == NULL)
 3122: 			hmodule = GetModuleHandleA(NULL);
 3123: 		if (hmodule != NULL) {
 3124: 			char buf[256];
 3125: 			unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
 3126: 			if (len != 0) {
 3127: 				char* p = &(buf[len]);
 3128: 				while (*p != '\\' && p > buf) 
 3129: 					p--;
 3130: 				if (p != buf) {
 3131: 					xmlChar* uri;
 3132: 					strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
 3133: 					uri = xmlCanonicPath(buf);
 3134: 					if (uri != NULL) {
 3135: 						strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
 3136: 						xmlFree(uri);
 3137: 					}
 3138: 				}
 3139: 			}
 3140: 		}
 3141: 		catalogs = XML_XML_DEFAULT_CATALOG;
 3142:     }
 3143: #else
 3144: 	    catalogs = XML_XML_DEFAULT_CATALOG;
 3145: #endif
 3146: 
 3147: 	catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 
 3148: 		xmlCatalogDefaultPrefer);
 3149: 	if (catal != NULL) {
 3150: 	    /* the XML_CATALOG_FILES envvar is allowed to contain a 
 3151: 	       space-separated list of entries. */
 3152: 	    cur = catalogs;
 3153: 	    nextent = &catal->xml;
 3154: 	    while (*cur != '\0') {
 3155: 		while (xmlIsBlank_ch(*cur)) 
 3156: 		    cur++;
 3157: 		if (*cur != 0) {
 3158: 		    paths = cur;
 3159: 		    while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
 3160: 			cur++;
 3161: 		    path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
 3162: 		    if (path != NULL) {
 3163: 			*nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
 3164: 				NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
 3165: 			if (*nextent != NULL)
 3166: 			    nextent = &((*nextent)->next);
 3167: 			xmlFree(path);
 3168: 		    }
 3169: 		}
 3170: 	    }
 3171: 	    xmlDefaultCatalog = catal;
 3172: 	}
 3173:     }
 3174: 
 3175:     xmlRMutexUnlock(xmlCatalogMutex);
 3176: }
 3177: 
 3178: 
 3179: /**
 3180:  * xmlLoadCatalog:
 3181:  * @filename:  a file path
 3182:  *
 3183:  * Load the catalog and makes its definitions effective for the default
 3184:  * external entity loader. It will recurse in SGML CATALOG entries.
 3185:  * this function is not thread safe, catalog initialization should
 3186:  * preferably be done once at startup
 3187:  *
 3188:  * Returns 0 in case of success -1 in case of error
 3189:  */
 3190: int
 3191: xmlLoadCatalog(const char *filename)
 3192: {
 3193:     int ret;
 3194:     xmlCatalogPtr catal;
 3195: 
 3196:     if (!xmlCatalogInitialized)
 3197: 	xmlInitializeCatalogData();
 3198: 
 3199:     xmlRMutexLock(xmlCatalogMutex);
 3200: 
 3201:     if (xmlDefaultCatalog == NULL) {
 3202: 	catal = xmlLoadACatalog(filename);
 3203: 	if (catal == NULL) {
 3204: 	    xmlRMutexUnlock(xmlCatalogMutex);
 3205: 	    return(-1);
 3206: 	}
 3207: 
 3208: 	xmlDefaultCatalog = catal;
 3209: 	xmlRMutexUnlock(xmlCatalogMutex);
 3210: 	return(0);
 3211:     }
 3212: 
 3213:     ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
 3214:     xmlRMutexUnlock(xmlCatalogMutex);
 3215:     return(ret);
 3216: }
 3217: 
 3218: /**
 3219:  * xmlLoadCatalogs:
 3220:  * @pathss:  a list of directories separated by a colon or a space.
 3221:  *
 3222:  * Load the catalogs and makes their definitions effective for the default
 3223:  * external entity loader.
 3224:  * this function is not thread safe, catalog initialization should
 3225:  * preferably be done once at startup
 3226:  */
 3227: void
 3228: xmlLoadCatalogs(const char *pathss) {
 3229:     const char *cur;
 3230:     const char *paths;
 3231:     xmlChar *path;
 3232: #ifdef _WIN32
 3233:     int i, iLen;
 3234: #endif
 3235: 
 3236:     if (pathss == NULL)
 3237: 	return;
 3238: 
 3239:     cur = pathss;
 3240:     while (*cur != 0) {
 3241: 	while (xmlIsBlank_ch(*cur)) cur++;
 3242: 	if (*cur != 0) {
 3243: 	    paths = cur;
 3244: 	    while ((*cur != 0) && (*cur != PATH_SEAPARATOR) && (!xmlIsBlank_ch(*cur)))
 3245: 		cur++;
 3246: 	    path = xmlStrndup((const xmlChar *)paths, cur - paths);
 3247: #ifdef _WIN32
 3248:         iLen = strlen(path);
 3249:         for(i = 0; i < iLen; i++) {
 3250:             if(path[i] == '\\') {
 3251:                 path[i] = '/';
 3252:             }
 3253:         }
 3254: #endif
 3255: 	    if (path != NULL) {
 3256: 		xmlLoadCatalog((const char *) path);
 3257: 		xmlFree(path);
 3258: 	    }
 3259: 	}
 3260: 	while (*cur == PATH_SEAPARATOR)
 3261: 	    cur++;
 3262:     }
 3263: }
 3264: 
 3265: /**
 3266:  * xmlCatalogCleanup:
 3267:  *
 3268:  * Free up all the memory associated with catalogs
 3269:  */
 3270: void
 3271: xmlCatalogCleanup(void) {
 3272:     if (xmlCatalogInitialized == 0)
 3273:         return;
 3274: 
 3275:     xmlRMutexLock(xmlCatalogMutex);
 3276:     if (xmlDebugCatalogs)
 3277: 	xmlGenericError(xmlGenericErrorContext,
 3278: 		"Catalogs cleanup\n");
 3279:     if (xmlCatalogXMLFiles != NULL)
 3280: 	xmlHashFree(xmlCatalogXMLFiles, 
 3281: 		    (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
 3282:     xmlCatalogXMLFiles = NULL;
 3283:     if (xmlDefaultCatalog != NULL)
 3284: 	xmlFreeCatalog(xmlDefaultCatalog);
 3285:     xmlDefaultCatalog = NULL;
 3286:     xmlDebugCatalogs = 0;
 3287:     xmlCatalogInitialized = 0;
 3288:     xmlRMutexUnlock(xmlCatalogMutex);
 3289:     xmlFreeRMutex(xmlCatalogMutex);
 3290: }
 3291: 
 3292: /**
 3293:  * xmlCatalogResolveSystem:
 3294:  * @sysID:  the system ID string
 3295:  *
 3296:  * Try to lookup the catalog resource for a system ID
 3297:  *
 3298:  * Returns the resource if found or NULL otherwise, the value returned
 3299:  *      must be freed by the caller.
 3300:  */
 3301: xmlChar *
 3302: xmlCatalogResolveSystem(const xmlChar *sysID) {
 3303:     xmlChar *ret;
 3304: 
 3305:     if (!xmlCatalogInitialized)
 3306: 	xmlInitializeCatalog();
 3307: 
 3308:     ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
 3309:     return(ret);
 3310: }
 3311: 
 3312: /**
 3313:  * xmlCatalogResolvePublic:
 3314:  * @pubID:  the public ID string
 3315:  *
 3316:  * Try to lookup the catalog reference associated to a public ID
 3317:  *
 3318:  * Returns the resource if found or NULL otherwise, the value returned
 3319:  *      must be freed by the caller.
 3320:  */
 3321: xmlChar *
 3322: xmlCatalogResolvePublic(const xmlChar *pubID) {
 3323:     xmlChar *ret;
 3324: 
 3325:     if (!xmlCatalogInitialized)
 3326: 	xmlInitializeCatalog();
 3327: 
 3328:     ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
 3329:     return(ret);
 3330: }
 3331: 
 3332: /**
 3333:  * xmlCatalogResolve:
 3334:  * @pubID:  the public ID string
 3335:  * @sysID:  the system ID string
 3336:  *
 3337:  * Do a complete resolution lookup of an External Identifier
 3338:  *
 3339:  * Returns the URI of the resource or NULL if not found, it must be freed
 3340:  *      by the caller.
 3341:  */
 3342: xmlChar *
 3343: xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
 3344:     xmlChar *ret;
 3345: 
 3346:     if (!xmlCatalogInitialized)
 3347: 	xmlInitializeCatalog();
 3348: 
 3349:     ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
 3350:     return(ret);
 3351: }
 3352: 
 3353: /**
 3354:  * xmlCatalogResolveURI:
 3355:  * @URI:  the URI
 3356:  *
 3357:  * Do a complete resolution lookup of an URI
 3358:  *
 3359:  * Returns the URI of the resource or NULL if not found, it must be freed
 3360:  *      by the caller.
 3361:  */
 3362: xmlChar *
 3363: xmlCatalogResolveURI(const xmlChar *URI) {
 3364:     xmlChar *ret;
 3365: 
 3366:     if (!xmlCatalogInitialized)
 3367: 	xmlInitializeCatalog();
 3368: 
 3369:     ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
 3370:     return(ret);
 3371: }
 3372: 
 3373: #ifdef LIBXML_OUTPUT_ENABLED
 3374: /**
 3375:  * xmlCatalogDump:
 3376:  * @out:  the file.
 3377:  *
 3378:  * Dump all the global catalog content to the given file.
 3379:  */
 3380: void
 3381: xmlCatalogDump(FILE *out) {
 3382:     if (out == NULL)
 3383: 	return;
 3384: 
 3385:     if (!xmlCatalogInitialized)
 3386: 	xmlInitializeCatalog();
 3387: 
 3388:     xmlACatalogDump(xmlDefaultCatalog, out);
 3389: }
 3390: #endif /* LIBXML_OUTPUT_ENABLED */
 3391: 
 3392: /**
 3393:  * xmlCatalogAdd:
 3394:  * @type:  the type of record to add to the catalog
 3395:  * @orig:  the system, public or prefix to match 
 3396:  * @replace:  the replacement value for the match
 3397:  *
 3398:  * Add an entry in the catalog, it may overwrite existing but
 3399:  * different entries.
 3400:  * If called before any other catalog routine, allows to override the
 3401:  * default shared catalog put in place by xmlInitializeCatalog();
 3402:  *
 3403:  * Returns 0 if successful, -1 otherwise
 3404:  */
 3405: int
 3406: xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
 3407:     int res = -1;
 3408: 
 3409:     if (!xmlCatalogInitialized)
 3410: 	xmlInitializeCatalogData();
 3411: 
 3412:     xmlRMutexLock(xmlCatalogMutex);
 3413:     /*
 3414:      * Specific case where one want to override the default catalog
 3415:      * put in place by xmlInitializeCatalog();
 3416:      */
 3417:     if ((xmlDefaultCatalog == NULL) &&
 3418: 	(xmlStrEqual(type, BAD_CAST "catalog"))) {
 3419: 	xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
 3420: 		                          xmlCatalogDefaultPrefer);
 3421: 	xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
 3422: 				    orig, NULL,  xmlCatalogDefaultPrefer, NULL);
 3423: 
 3424: 	xmlRMutexUnlock(xmlCatalogMutex);
 3425: 	return(0);
 3426:     } 
 3427: 
 3428:     res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
 3429:     xmlRMutexUnlock(xmlCatalogMutex);
 3430:     return(res);
 3431: }
 3432: 
 3433: /**
 3434:  * xmlCatalogRemove:
 3435:  * @value:  the value to remove
 3436:  *
 3437:  * Remove an entry from the catalog
 3438:  *
 3439:  * Returns the number of entries removed if successful, -1 otherwise
 3440:  */
 3441: int
 3442: xmlCatalogRemove(const xmlChar *value) {
 3443:     int res;
 3444: 
 3445:     if (!xmlCatalogInitialized)
 3446: 	xmlInitializeCatalog();
 3447: 
 3448:     xmlRMutexLock(xmlCatalogMutex);
 3449:     res = xmlACatalogRemove(xmlDefaultCatalog, value);
 3450:     xmlRMutexUnlock(xmlCatalogMutex);
 3451:     return(res);
 3452: }
 3453: 
 3454: /**
 3455:  * xmlCatalogConvert:
 3456:  *
 3457:  * Convert all the SGML catalog entries as XML ones
 3458:  *
 3459:  * Returns the number of entries converted if successful, -1 otherwise
 3460:  */
 3461: int
 3462: xmlCatalogConvert(void) {
 3463:     int res = -1;
 3464: 
 3465:     if (!xmlCatalogInitialized)
 3466: 	xmlInitializeCatalog();
 3467: 
 3468:     xmlRMutexLock(xmlCatalogMutex);
 3469:     res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
 3470:     xmlRMutexUnlock(xmlCatalogMutex);
 3471:     return(res);
 3472: }
 3473: 
 3474: /************************************************************************
 3475:  *									*
 3476:  *	Public interface manipulating the common preferences		*
 3477:  *									*
 3478:  ************************************************************************/
 3479: 
 3480: /**
 3481:  * xmlCatalogGetDefaults:
 3482:  *
 3483:  * Used to get the user preference w.r.t. to what catalogs should
 3484:  * be accepted
 3485:  *
 3486:  * Returns the current xmlCatalogAllow value
 3487:  */
 3488: xmlCatalogAllow
 3489: xmlCatalogGetDefaults(void) {
 3490:     return(xmlCatalogDefaultAllow);
 3491: }
 3492: 
 3493: /**
 3494:  * xmlCatalogSetDefaults:
 3495:  * @allow:  what catalogs should be accepted
 3496:  *
 3497:  * Used to set the user preference w.r.t. to what catalogs should
 3498:  * be accepted
 3499:  */
 3500: void
 3501: xmlCatalogSetDefaults(xmlCatalogAllow allow) {
 3502:     if (xmlDebugCatalogs) {
 3503: 	switch (allow) {
 3504: 	    case XML_CATA_ALLOW_NONE:
 3505: 		xmlGenericError(xmlGenericErrorContext,
 3506: 			"Disabling catalog usage\n");
 3507: 		break;
 3508: 	    case XML_CATA_ALLOW_GLOBAL:
 3509: 		xmlGenericError(xmlGenericErrorContext,
 3510: 			"Allowing only global catalogs\n");
 3511: 		break;
 3512: 	    case XML_CATA_ALLOW_DOCUMENT:
 3513: 		xmlGenericError(xmlGenericErrorContext,
 3514: 			"Allowing only catalogs from the document\n");
 3515: 		break;
 3516: 	    case XML_CATA_ALLOW_ALL:
 3517: 		xmlGenericError(xmlGenericErrorContext,
 3518: 			"Allowing all catalogs\n");
 3519: 		break;
 3520: 	}
 3521:     }
 3522:     xmlCatalogDefaultAllow = allow;
 3523: }
 3524: 
 3525: /**
 3526:  * xmlCatalogSetDefaultPrefer:
 3527:  * @prefer:  the default preference for delegation
 3528:  *
 3529:  * Allows to set the preference between public and system for deletion
 3530:  * in XML Catalog resolution. C.f. section 4.1.1 of the spec
 3531:  * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
 3532:  *
 3533:  * Returns the previous value of the default preference for delegation
 3534:  */
 3535: xmlCatalogPrefer
 3536: xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
 3537:     xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
 3538: 
 3539:     if (prefer == XML_CATA_PREFER_NONE)
 3540: 	return(ret);
 3541: 
 3542:     if (xmlDebugCatalogs) {
 3543: 	switch (prefer) {
 3544: 	    case XML_CATA_PREFER_PUBLIC:
 3545: 		xmlGenericError(xmlGenericErrorContext,
 3546: 			"Setting catalog preference to PUBLIC\n");
 3547: 		break;
 3548: 	    case XML_CATA_PREFER_SYSTEM:
 3549: 		xmlGenericError(xmlGenericErrorContext,
 3550: 			"Setting catalog preference to SYSTEM\n");
 3551: 		break;
 3552: 	    case XML_CATA_PREFER_NONE:
 3553: 		break;
 3554: 	}
 3555:     }
 3556:     xmlCatalogDefaultPrefer = prefer;
 3557:     return(ret);
 3558: }
 3559: 
 3560: /**
 3561:  * xmlCatalogSetDebug:
 3562:  * @level:  the debug level of catalogs required
 3563:  *
 3564:  * Used to set the debug level for catalog operation, 0 disable
 3565:  * debugging, 1 enable it
 3566:  *
 3567:  * Returns the previous value of the catalog debugging level
 3568:  */
 3569: int
 3570: xmlCatalogSetDebug(int level) {
 3571:     int ret = xmlDebugCatalogs;
 3572: 
 3573:     if (level <= 0)
 3574:         xmlDebugCatalogs = 0;
 3575:     else
 3576: 	xmlDebugCatalogs = level;
 3577:     return(ret);
 3578: }
 3579: 
 3580: /************************************************************************
 3581:  *									*
 3582:  *   Minimal interfaces used for per-document catalogs by the parser	*
 3583:  *									*
 3584:  ************************************************************************/
 3585: 
 3586: /**
 3587:  * xmlCatalogFreeLocal:
 3588:  * @catalogs:  a document's list of catalogs
 3589:  *
 3590:  * Free up the memory associated to the catalog list
 3591:  */
 3592: void
 3593: xmlCatalogFreeLocal(void *catalogs) {
 3594:     xmlCatalogEntryPtr catal;
 3595: 
 3596:     if (!xmlCatalogInitialized)
 3597: 	xmlInitializeCatalog();
 3598: 
 3599:     catal = (xmlCatalogEntryPtr) catalogs;
 3600:     if (catal != NULL)
 3601: 	xmlFreeCatalogEntryList(catal);
 3602: }
 3603: 
 3604: 
 3605: /**
 3606:  * xmlCatalogAddLocal:
 3607:  * @catalogs:  a document's list of catalogs
 3608:  * @URL:  the URL to a new local catalog
 3609:  *
 3610:  * Add the new entry to the catalog list
 3611:  *
 3612:  * Returns the updated list
 3613:  */
 3614: void *	
 3615: xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
 3616:     xmlCatalogEntryPtr catal, add;
 3617: 
 3618:     if (!xmlCatalogInitialized)
 3619: 	xmlInitializeCatalog();
 3620: 
 3621:     if (URL == NULL)
 3622: 	return(catalogs);
 3623: 
 3624:     if (xmlDebugCatalogs)
 3625: 	xmlGenericError(xmlGenericErrorContext,
 3626: 		"Adding document catalog %s\n", URL);
 3627: 
 3628:     add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
 3629: 	                     xmlCatalogDefaultPrefer, NULL);
 3630:     if (add == NULL)
 3631: 	return(catalogs);
 3632: 
 3633:     catal = (xmlCatalogEntryPtr) catalogs;
 3634:     if (catal == NULL) 
 3635: 	return((void *) add);
 3636: 
 3637:     while (catal->next != NULL)
 3638: 	catal = catal->next;
 3639:     catal->next = add;
 3640:     return(catalogs);
 3641: }
 3642: 
 3643: /**
 3644:  * xmlCatalogLocalResolve:
 3645:  * @catalogs:  a document's list of catalogs
 3646:  * @pubID:  the public ID string
 3647:  * @sysID:  the system ID string
 3648:  *
 3649:  * Do a complete resolution lookup of an External Identifier using a 
 3650:  * document's private catalog list
 3651:  *
 3652:  * Returns the URI of the resource or NULL if not found, it must be freed
 3653:  *      by the caller.
 3654:  */
 3655: xmlChar *
 3656: xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
 3657: 	               const xmlChar *sysID) {
 3658:     xmlCatalogEntryPtr catal;
 3659:     xmlChar *ret;
 3660: 
 3661:     if (!xmlCatalogInitialized)
 3662: 	xmlInitializeCatalog();
 3663: 
 3664:     if ((pubID == NULL) && (sysID == NULL))
 3665: 	return(NULL);
 3666: 
 3667:     if (xmlDebugCatalogs) {
 3668:         if ((pubID != NULL) && (sysID != NULL)) {
 3669:             xmlGenericError(xmlGenericErrorContext,
 3670:                             "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
 3671:         } else if (pubID != NULL) {
 3672:             xmlGenericError(xmlGenericErrorContext,
 3673:                             "Local Resolve: pubID %s\n", pubID);
 3674:         } else {
 3675:             xmlGenericError(xmlGenericErrorContext,
 3676:                             "Local Resolve: sysID %s\n", sysID);
 3677:         }
 3678:     }
 3679: 
 3680:     catal = (xmlCatalogEntryPtr) catalogs;
 3681:     if (catal == NULL)
 3682: 	return(NULL);
 3683:     ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
 3684:     if ((ret != NULL) && (ret != XML_CATAL_BREAK))
 3685: 	return(ret);
 3686:     return(NULL);
 3687: }
 3688: 
 3689: /**
 3690:  * xmlCatalogLocalResolveURI:
 3691:  * @catalogs:  a document's list of catalogs
 3692:  * @URI:  the URI
 3693:  *
 3694:  * Do a complete resolution lookup of an URI using a 
 3695:  * document's private catalog list
 3696:  *
 3697:  * Returns the URI of the resource or NULL if not found, it must be freed
 3698:  *      by the caller.
 3699:  */
 3700: xmlChar *
 3701: xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
 3702:     xmlCatalogEntryPtr catal;
 3703:     xmlChar *ret;
 3704: 
 3705:     if (!xmlCatalogInitialized)
 3706: 	xmlInitializeCatalog();
 3707: 
 3708:     if (URI == NULL)
 3709: 	return(NULL);
 3710: 
 3711:     if (xmlDebugCatalogs)
 3712: 	xmlGenericError(xmlGenericErrorContext,
 3713: 		"Resolve URI %s\n", URI);
 3714: 
 3715:     catal = (xmlCatalogEntryPtr) catalogs;
 3716:     if (catal == NULL)
 3717: 	return(NULL);
 3718:     ret = xmlCatalogListXMLResolveURI(catal, URI);
 3719:     if ((ret != NULL) && (ret != XML_CATAL_BREAK))
 3720: 	return(ret);
 3721:     return(NULL);
 3722: }
 3723: 
 3724: /************************************************************************
 3725:  *									*
 3726:  *			Deprecated interfaces				*
 3727:  *									*
 3728:  ************************************************************************/
 3729: /**
 3730:  * xmlCatalogGetSystem:
 3731:  * @sysID:  the system ID string
 3732:  *
 3733:  * Try to lookup the catalog reference associated to a system ID
 3734:  * DEPRECATED, use xmlCatalogResolveSystem()
 3735:  *
 3736:  * Returns the resource if found or NULL otherwise.
 3737:  */
 3738: const xmlChar *
 3739: xmlCatalogGetSystem(const xmlChar *sysID) {
 3740:     xmlChar *ret;
 3741:     static xmlChar result[1000];
 3742:     static int msg = 0;
 3743: 
 3744:     if (!xmlCatalogInitialized)
 3745: 	xmlInitializeCatalog();
 3746: 
 3747:     if (msg == 0) {
 3748: 	xmlGenericError(xmlGenericErrorContext,
 3749: 		"Use of deprecated xmlCatalogGetSystem() call\n");
 3750: 	msg++;
 3751:     }
 3752: 
 3753:     if (sysID == NULL)
 3754: 	return(NULL);
 3755:     
 3756:     /*
 3757:      * Check first the XML catalogs
 3758:      */
 3759:     if (xmlDefaultCatalog != NULL) {
 3760: 	ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
 3761: 	if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
 3762: 	    snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
 3763: 	    result[sizeof(result) - 1] = 0;
 3764: 	    return(result);
 3765: 	}
 3766:     }
 3767: 
 3768:     if (xmlDefaultCatalog != NULL)
 3769: 	return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
 3770:     return(NULL);
 3771: }
 3772: 
 3773: /**
 3774:  * xmlCatalogGetPublic:
 3775:  * @pubID:  the public ID string
 3776:  *
 3777:  * Try to lookup the catalog reference associated to a public ID
 3778:  * DEPRECATED, use xmlCatalogResolvePublic()
 3779:  *
 3780:  * Returns the resource if found or NULL otherwise.
 3781:  */
 3782: const xmlChar *
 3783: xmlCatalogGetPublic(const xmlChar *pubID) {
 3784:     xmlChar *ret;
 3785:     static xmlChar result[1000];
 3786:     static int msg = 0;
 3787: 
 3788:     if (!xmlCatalogInitialized)
 3789: 	xmlInitializeCatalog();
 3790: 
 3791:     if (msg == 0) {
 3792: 	xmlGenericError(xmlGenericErrorContext,
 3793: 		"Use of deprecated xmlCatalogGetPublic() call\n");
 3794: 	msg++;
 3795:     }
 3796: 
 3797:     if (pubID == NULL)
 3798: 	return(NULL);
 3799:     
 3800:     /*
 3801:      * Check first the XML catalogs
 3802:      */
 3803:     if (xmlDefaultCatalog != NULL) {
 3804: 	ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
 3805: 	if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
 3806: 	    snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
 3807: 	    result[sizeof(result) - 1] = 0;
 3808: 	    return(result);
 3809: 	}
 3810:     }
 3811: 
 3812:     if (xmlDefaultCatalog != NULL)
 3813: 	return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
 3814:     return(NULL);
 3815: }
 3816: 
 3817: #define bottom_catalog
 3818: #include "elfgcchack.h"
 3819: #endif /* LIBXML_CATALOG_ENABLED */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>