File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / catalog.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:58 2012 UTC (12 years, 4 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_7_8, HEAD
libxml2

    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:     if (catal->children != NULL)
 1411: 	return(-1);
 1412: 
 1413:     /*
 1414:      * lock the whole catalog for modification
 1415:      */
 1416:     xmlRMutexLock(xmlCatalogMutex);
 1417:     if (catal->children != NULL) {
 1418: 	/* Okay someone else did it in the meantime */
 1419: 	xmlRMutexUnlock(xmlCatalogMutex);
 1420: 	return(0);
 1421:     }
 1422: 
 1423:     if (xmlCatalogXMLFiles != NULL) {
 1424: 	doc = (xmlCatalogEntryPtr)
 1425: 	    xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
 1426: 	if (doc != NULL) {
 1427: 	    if (xmlDebugCatalogs)
 1428: 		xmlGenericError(xmlGenericErrorContext,
 1429: 		    "Found %s in file hash\n", catal->URL);
 1430: 
 1431: 	    if (catal->type == XML_CATA_CATALOG)
 1432: 		catal->children = doc->children;
 1433: 	    else
 1434: 		catal->children = doc;
 1435: 	    catal->dealloc = 0;
 1436: 	    xmlRMutexUnlock(xmlCatalogMutex);
 1437: 	    return(0);
 1438: 	}
 1439: 	if (xmlDebugCatalogs)
 1440: 	    xmlGenericError(xmlGenericErrorContext,
 1441: 		"%s not found in file hash\n", catal->URL);
 1442:     }
 1443: 
 1444:     /*
 1445:      * Fetch and parse. Note that xmlParseXMLCatalogFile does not
 1446:      * use the existing catalog, there is no recursion allowed at
 1447:      * that level.
 1448:      */
 1449:     doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
 1450:     if (doc == NULL) {
 1451: 	catal->type = XML_CATA_BROKEN_CATALOG;
 1452: 	xmlRMutexUnlock(xmlCatalogMutex);
 1453: 	return(-1);
 1454:     }
 1455: 
 1456:     if (catal->type == XML_CATA_CATALOG)
 1457: 	catal->children = doc->children;
 1458:     else
 1459: 	catal->children = doc;
 1460: 
 1461:     doc->dealloc = 1;
 1462: 
 1463:     if (xmlCatalogXMLFiles == NULL)
 1464: 	xmlCatalogXMLFiles = xmlHashCreate(10);
 1465:     if (xmlCatalogXMLFiles != NULL) {
 1466: 	if (xmlDebugCatalogs)
 1467: 	    xmlGenericError(xmlGenericErrorContext,
 1468: 		"%s added to file hash\n", catal->URL);
 1469: 	xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
 1470:     }
 1471:     xmlRMutexUnlock(xmlCatalogMutex);
 1472:     return(0);
 1473: }
 1474: 
 1475: /************************************************************************
 1476:  *									*
 1477:  *			XML Catalog handling				*
 1478:  *									*
 1479:  ************************************************************************/
 1480: 
 1481: /**
 1482:  * xmlAddXMLCatalog:
 1483:  * @catal:  top of an XML catalog
 1484:  * @type:  the type of record to add to the catalog
 1485:  * @orig:  the system, public or prefix to match (or NULL)
 1486:  * @replace:  the replacement value for the match
 1487:  *
 1488:  * Add an entry in the XML catalog, it may overwrite existing but
 1489:  * different entries.
 1490:  *
 1491:  * Returns 0 if successful, -1 otherwise
 1492:  */
 1493: static int
 1494: xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
 1495: 	      const xmlChar *orig, const xmlChar *replace) {
 1496:     xmlCatalogEntryPtr cur;
 1497:     xmlCatalogEntryType typ;
 1498:     int doregister = 0;
 1499: 
 1500:     if ((catal == NULL) || 
 1501: 	((catal->type != XML_CATA_CATALOG) &&
 1502: 	 (catal->type != XML_CATA_BROKEN_CATALOG)))
 1503: 	return(-1);
 1504:     if (catal->children == NULL) {
 1505: 	xmlFetchXMLCatalogFile(catal);
 1506:     }
 1507:     if (catal->children == NULL)
 1508: 	doregister = 1;
 1509: 
 1510:     typ = xmlGetXMLCatalogEntryType(type);
 1511:     if (typ == XML_CATA_NONE) {
 1512: 	if (xmlDebugCatalogs)
 1513: 	    xmlGenericError(xmlGenericErrorContext,
 1514: 		    "Failed to add unknown element %s to catalog\n", type);
 1515: 	return(-1);
 1516:     }
 1517: 
 1518:     cur = catal->children;
 1519:     /*
 1520:      * Might be a simple "update in place"
 1521:      */
 1522:     if (cur != NULL) {
 1523: 	while (cur != NULL) {
 1524: 	    if ((orig != NULL) && (cur->type == typ) &&
 1525: 		(xmlStrEqual(orig, cur->name))) {
 1526: 		if (xmlDebugCatalogs)
 1527: 		    xmlGenericError(xmlGenericErrorContext,
 1528: 			    "Updating element %s to catalog\n", type);
 1529: 		if (cur->value != NULL)
 1530: 		    xmlFree(cur->value);
 1531: 		if (cur->URL != NULL)
 1532: 		    xmlFree(cur->URL);
 1533: 		cur->value = xmlStrdup(replace);
 1534: 		cur->URL = xmlStrdup(replace);
 1535: 		return(0);
 1536: 	    }
 1537: 	    if (cur->next == NULL)
 1538: 		break;
 1539: 	    cur = cur->next;
 1540: 	}
 1541:     }
 1542:     if (xmlDebugCatalogs)
 1543: 	xmlGenericError(xmlGenericErrorContext,
 1544: 		"Adding element %s to catalog\n", type);
 1545:     if (cur == NULL)
 1546: 	catal->children = xmlNewCatalogEntry(typ, orig, replace,
 1547: 		                             NULL, catal->prefer, NULL);
 1548:     else
 1549: 	cur->next = xmlNewCatalogEntry(typ, orig, replace,
 1550: 		                       NULL, catal->prefer, NULL);
 1551:     if (doregister) {
 1552:         catal->type = XML_CATA_CATALOG;
 1553: 	cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
 1554: 	if (cur != NULL)
 1555: 	    cur->children = catal->children;
 1556:     }
 1557: 
 1558:     return(0);
 1559: }
 1560: 
 1561: /**
 1562:  * xmlDelXMLCatalog:
 1563:  * @catal:  top of an XML catalog
 1564:  * @value:  the value to remove from the catalog
 1565:  *
 1566:  * Remove entries in the XML catalog where the value or the URI
 1567:  * is equal to @value
 1568:  *
 1569:  * Returns the number of entries removed if successful, -1 otherwise
 1570:  */
 1571: static int
 1572: xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
 1573:     xmlCatalogEntryPtr cur;
 1574:     int ret = 0;
 1575: 
 1576:     if ((catal == NULL) || 
 1577: 	((catal->type != XML_CATA_CATALOG) &&
 1578: 	 (catal->type != XML_CATA_BROKEN_CATALOG)))
 1579: 	return(-1);
 1580:     if (value == NULL)
 1581: 	return(-1);
 1582:     if (catal->children == NULL) {
 1583: 	xmlFetchXMLCatalogFile(catal);
 1584:     }
 1585: 
 1586:     /*
 1587:      * Scan the children
 1588:      */
 1589:     cur = catal->children;
 1590:     while (cur != NULL) {
 1591: 	if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
 1592: 	    (xmlStrEqual(value, cur->value))) {
 1593: 	    if (xmlDebugCatalogs) {
 1594: 		if (cur->name != NULL)
 1595: 		    xmlGenericError(xmlGenericErrorContext,
 1596: 			    "Removing element %s from catalog\n", cur->name);
 1597: 		else
 1598: 		    xmlGenericError(xmlGenericErrorContext,
 1599: 			    "Removing element %s from catalog\n", cur->value);
 1600: 	    }
 1601: 	    cur->type = XML_CATA_REMOVED;
 1602: 	}
 1603: 	cur = cur->next;
 1604:     }
 1605:     return(ret);
 1606: }
 1607: 
 1608: /**
 1609:  * xmlCatalogXMLResolve:
 1610:  * @catal:  a catalog list
 1611:  * @pubID:  the public ID string
 1612:  * @sysID:  the system ID string
 1613:  *
 1614:  * Do a complete resolution lookup of an External Identifier for a
 1615:  * list of catalog entries.
 1616:  *
 1617:  * Implements (or tries to) 7.1. External Identifier Resolution
 1618:  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
 1619:  *
 1620:  * Returns the URI of the resource or NULL if not found
 1621:  */
 1622: static xmlChar *
 1623: xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
 1624: 	              const xmlChar *sysID) {
 1625:     xmlChar *ret = NULL;
 1626:     xmlCatalogEntryPtr cur;
 1627:     int haveDelegate = 0;
 1628:     int haveNext = 0;
 1629: 
 1630:     /*
 1631:      * protection against loops
 1632:      */
 1633:     if (catal->depth > MAX_CATAL_DEPTH) {
 1634: 	xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
 1635: 		      "Detected recursion in catalog %s\n",
 1636: 		      catal->name, NULL, NULL);
 1637: 	return(NULL);
 1638:     }
 1639:     catal->depth++;
 1640: 
 1641:     /*
 1642:      * First tries steps 2/ 3/ 4/ if a system ID is provided.
 1643:      */
 1644:     if (sysID != NULL) {
 1645: 	xmlCatalogEntryPtr rewrite = NULL;
 1646: 	int lenrewrite = 0, len;
 1647: 	cur = catal;
 1648: 	haveDelegate = 0;
 1649: 	while (cur != NULL) {
 1650: 	    switch (cur->type) {
 1651: 		case XML_CATA_SYSTEM:
 1652: 		    if (xmlStrEqual(sysID, cur->name)) {
 1653: 			if (xmlDebugCatalogs)
 1654: 			    xmlGenericError(xmlGenericErrorContext,
 1655: 				    "Found system match %s, using %s\n",
 1656: 				            cur->name, cur->URL);
 1657: 			catal->depth--;
 1658: 			return(xmlStrdup(cur->URL));
 1659: 		    }
 1660: 		    break;
 1661: 		case XML_CATA_REWRITE_SYSTEM:
 1662: 		    len = xmlStrlen(cur->name);
 1663: 		    if ((len > lenrewrite) &&
 1664: 			(!xmlStrncmp(sysID, cur->name, len))) {
 1665: 			lenrewrite = len;
 1666: 			rewrite = cur;
 1667: 		    }
 1668: 		    break;
 1669: 		case XML_CATA_DELEGATE_SYSTEM:
 1670: 		    if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
 1671: 			haveDelegate++;
 1672: 		    break;
 1673: 		case XML_CATA_NEXT_CATALOG:
 1674: 		    haveNext++;
 1675: 		    break;
 1676: 		default:
 1677: 		    break;
 1678: 	    }
 1679: 	    cur = cur->next;
 1680: 	}
 1681: 	if (rewrite != NULL) {
 1682: 	    if (xmlDebugCatalogs)
 1683: 		xmlGenericError(xmlGenericErrorContext,
 1684: 			"Using rewriting rule %s\n", rewrite->name);
 1685: 	    ret = xmlStrdup(rewrite->URL);
 1686: 	    if (ret != NULL)
 1687: 		ret = xmlStrcat(ret, &sysID[lenrewrite]);
 1688: 	    catal->depth--;
 1689: 	    return(ret);
 1690: 	}
 1691: 	if (haveDelegate) {
 1692: 	    const xmlChar *delegates[MAX_DELEGATE];
 1693: 	    int nbList = 0, i;
 1694: 
 1695: 	    /*
 1696: 	     * Assume the entries have been sorted by decreasing substring
 1697: 	     * matches when the list was produced.
 1698: 	     */
 1699: 	    cur = catal;
 1700: 	    while (cur != NULL) {
 1701: 		if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
 1702: 		    (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
 1703: 		    for (i = 0;i < nbList;i++)
 1704: 			if (xmlStrEqual(cur->URL, delegates[i]))
 1705: 			    break;
 1706: 		    if (i < nbList) {
 1707: 			cur = cur->next;
 1708: 			continue;
 1709: 		    }
 1710: 		    if (nbList < MAX_DELEGATE)
 1711: 			delegates[nbList++] = cur->URL;
 1712: 
 1713: 		    if (cur->children == NULL) {
 1714: 			xmlFetchXMLCatalogFile(cur);
 1715: 		    }
 1716: 		    if (cur->children != NULL) {
 1717: 			if (xmlDebugCatalogs)
 1718: 			    xmlGenericError(xmlGenericErrorContext,
 1719: 				    "Trying system delegate %s\n", cur->URL);
 1720: 			ret = xmlCatalogListXMLResolve(
 1721: 				cur->children, NULL, sysID);
 1722: 			if (ret != NULL) {
 1723: 			    catal->depth--;
 1724: 			    return(ret);
 1725: 			}
 1726: 		    }
 1727: 		}
 1728: 		cur = cur->next;
 1729: 	    }
 1730: 	    /*
 1731: 	     * Apply the cut algorithm explained in 4/
 1732: 	     */
 1733: 	    catal->depth--;
 1734: 	    return(XML_CATAL_BREAK);
 1735: 	}
 1736:     }
 1737:     /*
 1738:      * Then tries 5/ 6/ if a public ID is provided
 1739:      */
 1740:     if (pubID != NULL) {
 1741: 	cur = catal;
 1742: 	haveDelegate = 0;
 1743: 	while (cur != NULL) {
 1744: 	    switch (cur->type) {
 1745: 		case XML_CATA_PUBLIC:
 1746: 		    if (xmlStrEqual(pubID, cur->name)) {
 1747: 			if (xmlDebugCatalogs)
 1748: 			    xmlGenericError(xmlGenericErrorContext,
 1749: 				    "Found public match %s\n", cur->name);
 1750: 			catal->depth--;
 1751: 			return(xmlStrdup(cur->URL));
 1752: 		    }
 1753: 		    break;
 1754: 		case XML_CATA_DELEGATE_PUBLIC:
 1755: 		    if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
 1756: 			(cur->prefer == XML_CATA_PREFER_PUBLIC))
 1757: 			haveDelegate++;
 1758: 		    break;
 1759: 		case XML_CATA_NEXT_CATALOG:
 1760: 		    if (sysID == NULL)
 1761: 			haveNext++;
 1762: 		    break;
 1763: 		default:
 1764: 		    break;
 1765: 	    }
 1766: 	    cur = cur->next;
 1767: 	}
 1768: 	if (haveDelegate) {
 1769: 	    const xmlChar *delegates[MAX_DELEGATE];
 1770: 	    int nbList = 0, i;
 1771: 
 1772: 	    /*
 1773: 	     * Assume the entries have been sorted by decreasing substring
 1774: 	     * matches when the list was produced.
 1775: 	     */
 1776: 	    cur = catal;
 1777: 	    while (cur != NULL) {
 1778: 		if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
 1779: 		    (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
 1780: 		    (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
 1781: 
 1782: 		    for (i = 0;i < nbList;i++)
 1783: 			if (xmlStrEqual(cur->URL, delegates[i]))
 1784: 			    break;
 1785: 		    if (i < nbList) {
 1786: 			cur = cur->next;
 1787: 			continue;
 1788: 		    }
 1789: 		    if (nbList < MAX_DELEGATE)
 1790: 			delegates[nbList++] = cur->URL;
 1791: 			    
 1792: 		    if (cur->children == NULL) {
 1793: 			xmlFetchXMLCatalogFile(cur);
 1794: 		    }
 1795: 		    if (cur->children != NULL) {
 1796: 			if (xmlDebugCatalogs)
 1797: 			    xmlGenericError(xmlGenericErrorContext,
 1798: 				    "Trying public delegate %s\n", cur->URL);
 1799: 			ret = xmlCatalogListXMLResolve(
 1800: 				cur->children, pubID, NULL);
 1801: 			if (ret != NULL) {
 1802: 			    catal->depth--;
 1803: 			    return(ret);
 1804: 			}
 1805: 		    }
 1806: 		}
 1807: 		cur = cur->next;
 1808: 	    }
 1809: 	    /*
 1810: 	     * Apply the cut algorithm explained in 4/
 1811: 	     */
 1812: 	    catal->depth--;
 1813: 	    return(XML_CATAL_BREAK);
 1814: 	}
 1815:     }
 1816:     if (haveNext) {
 1817: 	cur = catal;
 1818: 	while (cur != NULL) {
 1819: 	    if (cur->type == XML_CATA_NEXT_CATALOG) {
 1820: 		if (cur->children == NULL) {
 1821: 		    xmlFetchXMLCatalogFile(cur);
 1822: 		}
 1823: 		if (cur->children != NULL) {
 1824: 		    ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
 1825: 		    if (ret != NULL) {
 1826: 			catal->depth--;
 1827: 			return(ret);
 1828: 		    } else if (catal->depth > MAX_CATAL_DEPTH) {
 1829: 		        return(NULL);
 1830: 		    }
 1831: 		}
 1832: 	    }
 1833: 	    cur = cur->next;
 1834: 	}
 1835:     }
 1836: 
 1837:     catal->depth--;
 1838:     return(NULL);
 1839: }
 1840: 
 1841: /**
 1842:  * xmlCatalogXMLResolveURI:
 1843:  * @catal:  a catalog list
 1844:  * @URI:  the URI
 1845:  * @sysID:  the system ID string
 1846:  *
 1847:  * Do a complete resolution lookup of an External Identifier for a
 1848:  * list of catalog entries.
 1849:  *
 1850:  * Implements (or tries to) 7.2.2. URI Resolution
 1851:  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
 1852:  *
 1853:  * Returns the URI of the resource or NULL if not found
 1854:  */
 1855: static xmlChar *
 1856: xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
 1857:     xmlChar *ret = NULL;
 1858:     xmlCatalogEntryPtr cur;
 1859:     int haveDelegate = 0;
 1860:     int haveNext = 0;
 1861:     xmlCatalogEntryPtr rewrite = NULL;
 1862:     int lenrewrite = 0, len;
 1863: 
 1864:     if (catal == NULL)
 1865: 	return(NULL);
 1866: 
 1867:     if (URI == NULL)
 1868: 	return(NULL);
 1869: 
 1870:     if (catal->depth > MAX_CATAL_DEPTH) {
 1871: 	xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
 1872: 		      "Detected recursion in catalog %s\n",
 1873: 		      catal->name, NULL, NULL);
 1874: 	return(NULL);
 1875:     }
 1876: 
 1877:     /*
 1878:      * First tries steps 2/ 3/ 4/ if a system ID is provided.
 1879:      */
 1880:     cur = catal;
 1881:     haveDelegate = 0;
 1882:     while (cur != NULL) {
 1883: 	switch (cur->type) {
 1884: 	    case XML_CATA_URI:
 1885: 		if (xmlStrEqual(URI, cur->name)) {
 1886: 		    if (xmlDebugCatalogs)
 1887: 			xmlGenericError(xmlGenericErrorContext,
 1888: 				"Found URI match %s\n", cur->name);
 1889: 		    return(xmlStrdup(cur->URL));
 1890: 		}
 1891: 		break;
 1892: 	    case XML_CATA_REWRITE_URI:
 1893: 		len = xmlStrlen(cur->name);
 1894: 		if ((len > lenrewrite) &&
 1895: 		    (!xmlStrncmp(URI, cur->name, len))) {
 1896: 		    lenrewrite = len;
 1897: 		    rewrite = cur;
 1898: 		}
 1899: 		break;
 1900: 	    case XML_CATA_DELEGATE_URI:
 1901: 		if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
 1902: 		    haveDelegate++;
 1903: 		break;
 1904: 	    case XML_CATA_NEXT_CATALOG:
 1905: 		haveNext++;
 1906: 		break;
 1907: 	    default:
 1908: 		break;
 1909: 	}
 1910: 	cur = cur->next;
 1911:     }
 1912:     if (rewrite != NULL) {
 1913: 	if (xmlDebugCatalogs)
 1914: 	    xmlGenericError(xmlGenericErrorContext,
 1915: 		    "Using rewriting rule %s\n", rewrite->name);
 1916: 	ret = xmlStrdup(rewrite->URL);
 1917: 	if (ret != NULL)
 1918: 	    ret = xmlStrcat(ret, &URI[lenrewrite]);
 1919: 	return(ret);
 1920:     }
 1921:     if (haveDelegate) {
 1922: 	const xmlChar *delegates[MAX_DELEGATE];
 1923: 	int nbList = 0, i;
 1924: 
 1925: 	/*
 1926: 	 * Assume the entries have been sorted by decreasing substring
 1927: 	 * matches when the list was produced.
 1928: 	 */
 1929: 	cur = catal;
 1930: 	while (cur != NULL) {
 1931: 	    if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
 1932: 	         (cur->type == XML_CATA_DELEGATE_URI)) &&
 1933: 		(!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
 1934: 		for (i = 0;i < nbList;i++)
 1935: 		    if (xmlStrEqual(cur->URL, delegates[i]))
 1936: 			break;
 1937: 		if (i < nbList) {
 1938: 		    cur = cur->next;
 1939: 		    continue;
 1940: 		}
 1941: 		if (nbList < MAX_DELEGATE)
 1942: 		    delegates[nbList++] = cur->URL;
 1943: 
 1944: 		if (cur->children == NULL) {
 1945: 		    xmlFetchXMLCatalogFile(cur);
 1946: 		}
 1947: 		if (cur->children != NULL) {
 1948: 		    if (xmlDebugCatalogs)
 1949: 			xmlGenericError(xmlGenericErrorContext,
 1950: 				"Trying URI delegate %s\n", cur->URL);
 1951: 		    ret = xmlCatalogListXMLResolveURI(
 1952: 			    cur->children, URI);
 1953: 		    if (ret != NULL)
 1954: 			return(ret);
 1955: 		}
 1956: 	    }
 1957: 	    cur = cur->next;
 1958: 	}
 1959: 	/*
 1960: 	 * Apply the cut algorithm explained in 4/
 1961: 	 */
 1962: 	return(XML_CATAL_BREAK);
 1963:     }
 1964:     if (haveNext) {
 1965: 	cur = catal;
 1966: 	while (cur != NULL) {
 1967: 	    if (cur->type == XML_CATA_NEXT_CATALOG) {
 1968: 		if (cur->children == NULL) {
 1969: 		    xmlFetchXMLCatalogFile(cur);
 1970: 		}
 1971: 		if (cur->children != NULL) {
 1972: 		    ret = xmlCatalogListXMLResolveURI(cur->children, URI);
 1973: 		    if (ret != NULL)
 1974: 			return(ret);
 1975: 		}
 1976: 	    }
 1977: 	    cur = cur->next;
 1978: 	}
 1979:     }
 1980: 
 1981:     return(NULL);
 1982: }
 1983: 
 1984: /**
 1985:  * xmlCatalogListXMLResolve:
 1986:  * @catal:  a catalog list
 1987:  * @pubID:  the public ID string
 1988:  * @sysID:  the system ID string
 1989:  *
 1990:  * Do a complete resolution lookup of an External Identifier for a
 1991:  * list of catalogs
 1992:  *
 1993:  * Implements (or tries to) 7.1. External Identifier Resolution
 1994:  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
 1995:  *
 1996:  * Returns the URI of the resource or NULL if not found
 1997:  */
 1998: static xmlChar *
 1999: xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
 2000: 	              const xmlChar *sysID) {
 2001:     xmlChar *ret = NULL;
 2002:     xmlChar *urnID = NULL;
 2003:     xmlChar *normid;
 2004:     
 2005:     if (catal == NULL)
 2006:         return(NULL);
 2007:     if ((pubID == NULL) && (sysID == NULL))
 2008: 	return(NULL);
 2009: 
 2010:     normid = xmlCatalogNormalizePublic(pubID);
 2011:     if (normid != NULL)
 2012:         pubID = (*normid != 0 ? normid : NULL);
 2013:     
 2014:     if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
 2015: 	urnID = xmlCatalogUnWrapURN(pubID);
 2016: 	if (xmlDebugCatalogs) {
 2017: 	    if (urnID == NULL)
 2018: 		xmlGenericError(xmlGenericErrorContext,
 2019: 			"Public URN ID %s expanded to NULL\n", pubID);
 2020: 	    else
 2021: 		xmlGenericError(xmlGenericErrorContext,
 2022: 			"Public URN ID expanded to %s\n", urnID);
 2023: 	}
 2024: 	ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
 2025: 	if (urnID != NULL)
 2026: 	    xmlFree(urnID);
 2027: 	if (normid != NULL)
 2028: 	    xmlFree(normid);
 2029: 	return(ret);
 2030:     }
 2031:     if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
 2032: 	urnID = xmlCatalogUnWrapURN(sysID);
 2033: 	if (xmlDebugCatalogs) {
 2034: 	    if (urnID == NULL)
 2035: 		xmlGenericError(xmlGenericErrorContext,
 2036: 			"System URN ID %s expanded to NULL\n", sysID);
 2037: 	    else
 2038: 		xmlGenericError(xmlGenericErrorContext,
 2039: 			"System URN ID expanded to %s\n", urnID);
 2040: 	}
 2041: 	if (pubID == NULL)
 2042: 	    ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
 2043: 	else if (xmlStrEqual(pubID, urnID))
 2044: 	    ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
 2045: 	else {
 2046: 	    ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
 2047: 	}
 2048: 	if (urnID != NULL)
 2049: 	    xmlFree(urnID);
 2050: 	if (normid != NULL)
 2051: 	    xmlFree(normid);
 2052: 	return(ret);
 2053:     }
 2054:     while (catal != NULL) {
 2055: 	if (catal->type == XML_CATA_CATALOG) {
 2056: 	    if (catal->children == NULL) {
 2057: 		xmlFetchXMLCatalogFile(catal);
 2058: 	    }
 2059: 	    if (catal->children != NULL) {
 2060: 		ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
 2061: 		if (ret != NULL) {
 2062: 		    break;
 2063:                 } else if ((catal->children != NULL) &&
 2064: 		           (catal->children->depth > MAX_CATAL_DEPTH)) {
 2065: 	            ret = NULL;
 2066: 		    break;
 2067: 	        }
 2068: 	    }
 2069: 	}
 2070: 	catal = catal->next;
 2071:     }
 2072:     if (normid != NULL)
 2073: 	xmlFree(normid);
 2074:     return(ret);
 2075: }
 2076: 
 2077: /**
 2078:  * xmlCatalogListXMLResolveURI:
 2079:  * @catal:  a catalog list
 2080:  * @URI:  the URI
 2081:  *
 2082:  * Do a complete resolution lookup of an URI for a list of catalogs
 2083:  *
 2084:  * Implements (or tries to) 7.2. URI Resolution
 2085:  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
 2086:  *
 2087:  * Returns the URI of the resource or NULL if not found
 2088:  */
 2089: static xmlChar *
 2090: xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
 2091:     xmlChar *ret = NULL;
 2092:     xmlChar *urnID = NULL;
 2093:     
 2094:     if (catal == NULL)
 2095:         return(NULL);
 2096:     if (URI == NULL)
 2097: 	return(NULL);
 2098: 
 2099:     if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
 2100: 	urnID = xmlCatalogUnWrapURN(URI);
 2101: 	if (xmlDebugCatalogs) {
 2102: 	    if (urnID == NULL)
 2103: 		xmlGenericError(xmlGenericErrorContext,
 2104: 			"URN ID %s expanded to NULL\n", URI);
 2105: 	    else
 2106: 		xmlGenericError(xmlGenericErrorContext,
 2107: 			"URN ID expanded to %s\n", urnID);
 2108: 	}
 2109: 	ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
 2110: 	if (urnID != NULL)
 2111: 	    xmlFree(urnID);
 2112: 	return(ret);
 2113:     }
 2114:     while (catal != NULL) {
 2115: 	if (catal->type == XML_CATA_CATALOG) {
 2116: 	    if (catal->children == NULL) {
 2117: 		xmlFetchXMLCatalogFile(catal);
 2118: 	    }
 2119: 	    if (catal->children != NULL) {
 2120: 		ret = xmlCatalogXMLResolveURI(catal->children, URI);
 2121: 		if (ret != NULL)
 2122: 		    return(ret);
 2123: 	    }
 2124: 	}
 2125: 	catal = catal->next;
 2126:     }
 2127:     return(ret);
 2128: }
 2129: 
 2130: /************************************************************************
 2131:  *									*
 2132:  *			The SGML Catalog parser				*
 2133:  *									*
 2134:  ************************************************************************/
 2135: 
 2136: 
 2137: #define RAW *cur
 2138: #define NEXT cur++;
 2139: #define SKIP(x) cur += x;
 2140: 
 2141: #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
 2142: 
 2143: /**
 2144:  * xmlParseSGMLCatalogComment:
 2145:  * @cur:  the current character
 2146:  *
 2147:  * Skip a comment in an SGML catalog
 2148:  *
 2149:  * Returns new current character
 2150:  */
 2151: static const xmlChar *
 2152: xmlParseSGMLCatalogComment(const xmlChar *cur) {
 2153:     if ((cur[0] != '-') || (cur[1] != '-')) 
 2154: 	return(cur);
 2155:     SKIP(2);
 2156:     while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
 2157: 	NEXT;
 2158:     if (cur[0] == 0) {
 2159: 	return(NULL);
 2160:     }
 2161:     return(cur + 2);
 2162: }
 2163: 
 2164: /**
 2165:  * xmlParseSGMLCatalogPubid:
 2166:  * @cur:  the current character
 2167:  * @id:  the return location
 2168:  *
 2169:  * Parse an SGML catalog ID
 2170:  *
 2171:  * Returns new current character and store the value in @id
 2172:  */
 2173: static const xmlChar *
 2174: xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
 2175:     xmlChar *buf = NULL, *tmp;
 2176:     int len = 0;
 2177:     int size = 50;
 2178:     xmlChar stop;
 2179:     int count = 0;
 2180: 
 2181:     *id = NULL;
 2182: 
 2183:     if (RAW == '"') {
 2184:         NEXT;
 2185: 	stop = '"';
 2186:     } else if (RAW == '\'') {
 2187:         NEXT;
 2188: 	stop = '\'';
 2189:     } else {
 2190: 	stop = ' ';
 2191:     }
 2192:     buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
 2193:     if (buf == NULL) {
 2194:         xmlCatalogErrMemory("allocating public ID");
 2195: 	return(NULL);
 2196:     }
 2197:     while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
 2198: 	if ((*cur == stop) && (stop != ' '))
 2199: 	    break;
 2200: 	if ((stop == ' ') && (IS_BLANK_CH(*cur)))
 2201: 	    break;
 2202: 	if (len + 1 >= size) {
 2203: 	    size *= 2;
 2204: 	    tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
 2205: 	    if (tmp == NULL) {
 2206: 		xmlCatalogErrMemory("allocating public ID");
 2207: 		xmlFree(buf);
 2208: 		return(NULL);
 2209: 	    }
 2210: 	    buf = tmp;
 2211: 	}
 2212: 	buf[len++] = *cur;
 2213: 	count++;
 2214: 	NEXT;
 2215:     }
 2216:     buf[len] = 0;
 2217:     if (stop == ' ') {
 2218: 	if (!IS_BLANK_CH(*cur)) {
 2219: 	    xmlFree(buf);
 2220: 	    return(NULL);
 2221: 	}
 2222:     } else {
 2223: 	if (*cur != stop) {
 2224: 	    xmlFree(buf);
 2225: 	    return(NULL);
 2226: 	}
 2227: 	NEXT;
 2228:     }
 2229:     *id = buf;
 2230:     return(cur);
 2231: }
 2232: 
 2233: /**
 2234:  * xmlParseSGMLCatalogName:
 2235:  * @cur:  the current character
 2236:  * @name:  the return location
 2237:  *
 2238:  * Parse an SGML catalog name
 2239:  *
 2240:  * Returns new current character and store the value in @name
 2241:  */
 2242: static const xmlChar *
 2243: xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
 2244:     xmlChar buf[XML_MAX_NAMELEN + 5];
 2245:     int len = 0;
 2246:     int c;
 2247: 
 2248:     *name = NULL;
 2249: 
 2250:     /*
 2251:      * Handler for more complex cases
 2252:      */
 2253:     c = *cur;
 2254:     if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
 2255: 	return(NULL);
 2256:     }
 2257: 
 2258:     while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
 2259:             (c == '.') || (c == '-') ||
 2260: 	    (c == '_') || (c == ':'))) {
 2261: 	buf[len++] = c;
 2262: 	cur++;
 2263: 	c = *cur;
 2264: 	if (len >= XML_MAX_NAMELEN)
 2265: 	    return(NULL);
 2266:     }
 2267:     *name = xmlStrndup(buf, len);
 2268:     return(cur);
 2269: }
 2270: 
 2271: /**
 2272:  * xmlGetSGMLCatalogEntryType:
 2273:  * @name:  the entry name
 2274:  *
 2275:  * Get the Catalog entry type for a given SGML Catalog name
 2276:  *
 2277:  * Returns Catalog entry type
 2278:  */
 2279: static xmlCatalogEntryType
 2280: xmlGetSGMLCatalogEntryType(const xmlChar *name) {
 2281:     xmlCatalogEntryType type = XML_CATA_NONE;
 2282:     if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
 2283: 	type = SGML_CATA_SYSTEM;
 2284:     else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
 2285: 	type = SGML_CATA_PUBLIC;
 2286:     else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
 2287: 	type = SGML_CATA_DELEGATE;
 2288:     else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
 2289: 	type = SGML_CATA_ENTITY;
 2290:     else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
 2291: 	type = SGML_CATA_DOCTYPE;
 2292:     else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
 2293: 	type = SGML_CATA_LINKTYPE;
 2294:     else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
 2295: 	type = SGML_CATA_NOTATION;
 2296:     else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
 2297: 	type = SGML_CATA_SGMLDECL;
 2298:     else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
 2299: 	type = SGML_CATA_DOCUMENT;
 2300:     else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
 2301: 	type = SGML_CATA_CATALOG;
 2302:     else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
 2303: 	type = SGML_CATA_BASE;
 2304:     return(type);
 2305: }
 2306: 
 2307: /**
 2308:  * xmlParseSGMLCatalog:
 2309:  * @catal:  the SGML Catalog
 2310:  * @value:  the content of the SGML Catalog serialization
 2311:  * @file:  the filepath for the catalog
 2312:  * @super:  should this be handled as a Super Catalog in which case
 2313:  *          parsing is not recursive
 2314:  *
 2315:  * Parse an SGML catalog content and fill up the @catal hash table with
 2316:  * the new entries found.
 2317:  *
 2318:  * Returns 0 in case of success, -1 in case of error.
 2319:  */
 2320: static int
 2321: xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
 2322: 	            const char *file, int super) {
 2323:     const xmlChar *cur = value;
 2324:     xmlChar *base = NULL;
 2325:     int res;
 2326: 
 2327:     if ((cur == NULL) || (file == NULL))
 2328:         return(-1);
 2329:     base = xmlStrdup((const xmlChar *) file);
 2330: 
 2331:     while ((cur != NULL) && (cur[0] != 0)) {
 2332: 	SKIP_BLANKS;
 2333: 	if (cur[0] == 0)
 2334: 	    break;
 2335: 	if ((cur[0] == '-') && (cur[1] == '-')) {
 2336: 	    cur = xmlParseSGMLCatalogComment(cur);
 2337: 	    if (cur == NULL) {
 2338: 		/* error */
 2339: 		break;
 2340: 	    }
 2341: 	} else {
 2342: 	    xmlChar *sysid = NULL;
 2343: 	    xmlChar *name = NULL;
 2344: 	    xmlCatalogEntryType type = XML_CATA_NONE;
 2345: 
 2346: 	    cur = xmlParseSGMLCatalogName(cur, &name);
 2347: 	    if (name == NULL) {
 2348: 		/* error */
 2349: 		break;
 2350: 	    }
 2351: 	    if (!IS_BLANK_CH(*cur)) {
 2352: 		/* error */
 2353: 		break;
 2354: 	    }
 2355: 	    SKIP_BLANKS;
 2356: 	    if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
 2357:                 type = SGML_CATA_SYSTEM;
 2358: 	    else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
 2359:                 type = SGML_CATA_PUBLIC;
 2360: 	    else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
 2361:                 type = SGML_CATA_DELEGATE;
 2362: 	    else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
 2363:                 type = SGML_CATA_ENTITY;
 2364: 	    else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
 2365:                 type = SGML_CATA_DOCTYPE;
 2366: 	    else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
 2367:                 type = SGML_CATA_LINKTYPE;
 2368: 	    else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
 2369:                 type = SGML_CATA_NOTATION;
 2370: 	    else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
 2371:                 type = SGML_CATA_SGMLDECL;
 2372: 	    else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
 2373:                 type = SGML_CATA_DOCUMENT;
 2374: 	    else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
 2375:                 type = SGML_CATA_CATALOG;
 2376: 	    else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
 2377:                 type = SGML_CATA_BASE;
 2378: 	    else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
 2379: 		xmlFree(name);
 2380: 		cur = xmlParseSGMLCatalogName(cur, &name);
 2381: 		if (name == NULL) {
 2382: 		    /* error */
 2383: 		    break;
 2384: 		}
 2385: 		xmlFree(name);
 2386: 		continue;
 2387: 	    }
 2388: 	    xmlFree(name);
 2389: 	    name = NULL;
 2390: 
 2391: 	    switch(type) {
 2392: 		case SGML_CATA_ENTITY:
 2393: 		    if (*cur == '%')
 2394: 			type = SGML_CATA_PENTITY;
 2395: 		case SGML_CATA_PENTITY:
 2396: 		case SGML_CATA_DOCTYPE:
 2397: 		case SGML_CATA_LINKTYPE:
 2398: 		case SGML_CATA_NOTATION:
 2399: 		    cur = xmlParseSGMLCatalogName(cur, &name);
 2400: 		    if (cur == NULL) {
 2401: 			/* error */
 2402: 			break;
 2403: 		    }
 2404: 		    if (!IS_BLANK_CH(*cur)) {
 2405: 			/* error */
 2406: 			break;
 2407: 		    }
 2408: 		    SKIP_BLANKS;
 2409: 		    cur = xmlParseSGMLCatalogPubid(cur, &sysid);
 2410: 		    if (cur == NULL) {
 2411: 			/* error */
 2412: 			break;
 2413: 		    }
 2414: 		    break;
 2415: 		case SGML_CATA_PUBLIC:
 2416: 		case SGML_CATA_SYSTEM:
 2417: 		case SGML_CATA_DELEGATE:
 2418: 		    cur = xmlParseSGMLCatalogPubid(cur, &name);
 2419: 		    if (cur == NULL) {
 2420: 			/* error */
 2421: 			break;
 2422: 		    }
 2423: 		    if (type != SGML_CATA_SYSTEM) {
 2424: 		        xmlChar *normid;
 2425: 
 2426: 		        normid = xmlCatalogNormalizePublic(name);
 2427: 		        if (normid != NULL) {
 2428: 		            if (name != NULL)
 2429: 		                xmlFree(name);
 2430: 		            if (*normid != 0)
 2431: 		                name = normid;
 2432: 		            else {
 2433: 		                xmlFree(normid);
 2434: 		                name = NULL;
 2435: 		            }
 2436: 		        }
 2437: 		    }
 2438: 		    if (!IS_BLANK_CH(*cur)) {
 2439: 			/* error */
 2440: 			break;
 2441: 		    }
 2442: 		    SKIP_BLANKS;
 2443: 		    cur = xmlParseSGMLCatalogPubid(cur, &sysid);
 2444: 		    if (cur == NULL) {
 2445: 			/* error */
 2446: 			break;
 2447: 		    }
 2448: 		    break;
 2449: 		case SGML_CATA_BASE:
 2450: 		case SGML_CATA_CATALOG:
 2451: 		case SGML_CATA_DOCUMENT:
 2452: 		case SGML_CATA_SGMLDECL:
 2453: 		    cur = xmlParseSGMLCatalogPubid(cur, &sysid);
 2454: 		    if (cur == NULL) {
 2455: 			/* error */
 2456: 			break;
 2457: 		    }
 2458: 		    break;
 2459: 		default:
 2460: 		    break;
 2461: 	    }
 2462: 	    if (cur == NULL) {
 2463: 		if (name != NULL)
 2464: 		    xmlFree(name);
 2465: 		if (sysid != NULL)
 2466: 		    xmlFree(sysid);
 2467: 		break;
 2468: 	    } else if (type == SGML_CATA_BASE) {
 2469: 		if (base != NULL)
 2470: 		    xmlFree(base);
 2471: 		base = xmlStrdup(sysid);
 2472: 	    } else if ((type == SGML_CATA_PUBLIC) ||
 2473: 		       (type == SGML_CATA_SYSTEM)) {
 2474: 		xmlChar *filename;
 2475: 
 2476: 		filename = xmlBuildURI(sysid, base);
 2477: 		if (filename != NULL) {
 2478: 		    xmlCatalogEntryPtr entry;
 2479: 
 2480: 		    entry = xmlNewCatalogEntry(type, name, filename,
 2481: 			                       NULL, XML_CATA_PREFER_NONE, NULL);
 2482: 		    res = xmlHashAddEntry(catal->sgml, name, entry);
 2483: 		    if (res < 0) {
 2484: 			xmlFreeCatalogEntry(entry);
 2485: 		    }
 2486: 		    xmlFree(filename);
 2487: 		}
 2488: 
 2489: 	    } else if (type == SGML_CATA_CATALOG) {
 2490: 		if (super) {
 2491: 		    xmlCatalogEntryPtr entry;
 2492: 
 2493: 		    entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
 2494: 			                       XML_CATA_PREFER_NONE, NULL);
 2495: 		    res = xmlHashAddEntry(catal->sgml, sysid, entry);
 2496: 		    if (res < 0) {
 2497: 			xmlFreeCatalogEntry(entry);
 2498: 		    }
 2499: 		} else {
 2500: 		    xmlChar *filename;
 2501: 
 2502: 		    filename = xmlBuildURI(sysid, base);
 2503: 		    if (filename != NULL) {
 2504: 			xmlExpandCatalog(catal, (const char *)filename);
 2505: 			xmlFree(filename);
 2506: 		    }
 2507: 		}
 2508: 	    }
 2509: 	    /*
 2510: 	     * drop anything else we won't handle it
 2511: 	     */
 2512: 	    if (name != NULL)
 2513: 		xmlFree(name);
 2514: 	    if (sysid != NULL)
 2515: 		xmlFree(sysid);
 2516: 	}
 2517:     }
 2518:     if (base != NULL)
 2519: 	xmlFree(base);
 2520:     if (cur == NULL)
 2521: 	return(-1);
 2522:     return(0);
 2523: }
 2524: 
 2525: /************************************************************************
 2526:  *									*
 2527:  *			SGML Catalog handling				*
 2528:  *									*
 2529:  ************************************************************************/
 2530: 
 2531: /**
 2532:  * xmlCatalogGetSGMLPublic:
 2533:  * @catal:  an SGML catalog hash
 2534:  * @pubID:  the public ID string
 2535:  *
 2536:  * Try to lookup the catalog local reference associated to a public ID
 2537:  *
 2538:  * Returns the local resource if found or NULL otherwise.
 2539:  */
 2540: static const xmlChar *
 2541: xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
 2542:     xmlCatalogEntryPtr entry;
 2543:     xmlChar *normid;
 2544: 
 2545:     if (catal == NULL)
 2546: 	return(NULL);
 2547: 
 2548:     normid = xmlCatalogNormalizePublic(pubID);
 2549:     if (normid != NULL)
 2550:         pubID = (*normid != 0 ? normid : NULL);
 2551: 
 2552:     entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
 2553:     if (entry == NULL) {
 2554: 	if (normid != NULL)
 2555: 	    xmlFree(normid);
 2556: 	return(NULL);
 2557:     }
 2558:     if (entry->type == SGML_CATA_PUBLIC) {
 2559: 	if (normid != NULL)
 2560: 	    xmlFree(normid);
 2561: 	return(entry->URL);
 2562:     }
 2563:     if (normid != NULL)
 2564:         xmlFree(normid);
 2565:     return(NULL);
 2566: }
 2567: 
 2568: /**
 2569:  * xmlCatalogGetSGMLSystem:
 2570:  * @catal:  an SGML catalog hash
 2571:  * @sysID:  the system ID string
 2572:  *
 2573:  * Try to lookup the catalog local reference for a system ID
 2574:  *
 2575:  * Returns the local resource if found or NULL otherwise.
 2576:  */
 2577: static const xmlChar *
 2578: xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
 2579:     xmlCatalogEntryPtr entry;
 2580: 
 2581:     if (catal == NULL)
 2582: 	return(NULL);
 2583: 
 2584:     entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
 2585:     if (entry == NULL)
 2586: 	return(NULL);
 2587:     if (entry->type == SGML_CATA_SYSTEM)
 2588: 	return(entry->URL);
 2589:     return(NULL);
 2590: }
 2591: 
 2592: /**
 2593:  * xmlCatalogSGMLResolve:
 2594:  * @catal:  the SGML catalog
 2595:  * @pubID:  the public ID string
 2596:  * @sysID:  the system ID string
 2597:  *
 2598:  * Do a complete resolution lookup of an External Identifier
 2599:  *
 2600:  * Returns the URI of the resource or NULL if not found
 2601:  */
 2602: static const xmlChar *
 2603: xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
 2604: 	              const xmlChar *sysID) {
 2605:     const xmlChar *ret = NULL;
 2606: 
 2607:     if (catal->sgml == NULL)
 2608: 	return(NULL);
 2609: 
 2610:     if (pubID != NULL)
 2611: 	ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
 2612:     if (ret != NULL)
 2613: 	return(ret);
 2614:     if (sysID != NULL)
 2615: 	ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
 2616:     if (ret != NULL)
 2617: 	return(ret);
 2618:     return(NULL);
 2619: }
 2620: 
 2621: /************************************************************************
 2622:  *									*
 2623:  *			Specific Public interfaces			*
 2624:  *									*
 2625:  ************************************************************************/
 2626: 
 2627: /**
 2628:  * xmlLoadSGMLSuperCatalog:
 2629:  * @filename:  a file path
 2630:  *
 2631:  * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
 2632:  * references. This is only needed for manipulating SGML Super Catalogs
 2633:  * like adding and removing CATALOG or DELEGATE entries.
 2634:  *
 2635:  * Returns the catalog parsed or NULL in case of error
 2636:  */
 2637: xmlCatalogPtr
 2638: xmlLoadSGMLSuperCatalog(const char *filename)
 2639: {
 2640:     xmlChar *content;
 2641:     xmlCatalogPtr catal;
 2642:     int ret;
 2643: 
 2644:     content = xmlLoadFileContent(filename);
 2645:     if (content == NULL)
 2646:         return(NULL);
 2647: 
 2648:     catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
 2649:     if (catal == NULL) {
 2650: 	xmlFree(content);
 2651: 	return(NULL);
 2652:     }
 2653: 
 2654:     ret = xmlParseSGMLCatalog(catal, content, filename, 1);
 2655:     xmlFree(content);
 2656:     if (ret < 0) {
 2657: 	xmlFreeCatalog(catal);
 2658: 	return(NULL);
 2659:     }
 2660:     return (catal);
 2661: }
 2662: 
 2663: /**
 2664:  * xmlLoadACatalog:
 2665:  * @filename:  a file path
 2666:  *
 2667:  * Load the catalog and build the associated data structures.
 2668:  * This can be either an XML Catalog or an SGML Catalog
 2669:  * It will recurse in SGML CATALOG entries. On the other hand XML
 2670:  * Catalogs are not handled recursively.
 2671:  *
 2672:  * Returns the catalog parsed or NULL in case of error
 2673:  */
 2674: xmlCatalogPtr
 2675: xmlLoadACatalog(const char *filename)
 2676: {
 2677:     xmlChar *content;
 2678:     xmlChar *first;
 2679:     xmlCatalogPtr catal;
 2680:     int ret;
 2681: 
 2682:     content = xmlLoadFileContent(filename);
 2683:     if (content == NULL)
 2684:         return(NULL);
 2685: 
 2686: 
 2687:     first = content;
 2688:    
 2689:     while ((*first != 0) && (*first != '-') && (*first != '<') &&
 2690: 	   (!(((*first >= 'A') && (*first <= 'Z')) ||
 2691: 	      ((*first >= 'a') && (*first <= 'z')))))
 2692: 	first++;
 2693: 
 2694:     if (*first != '<') {
 2695: 	catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
 2696: 	if (catal == NULL) {
 2697: 	    xmlFree(content);
 2698: 	    return(NULL);
 2699: 	}
 2700:         ret = xmlParseSGMLCatalog(catal, content, filename, 0);
 2701: 	if (ret < 0) {
 2702: 	    xmlFreeCatalog(catal);
 2703: 	    xmlFree(content);
 2704: 	    return(NULL);
 2705: 	}
 2706:     } else {
 2707: 	catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
 2708: 	if (catal == NULL) {
 2709: 	    xmlFree(content);
 2710: 	    return(NULL);
 2711: 	}
 2712:         catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
 2713: 		       NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
 2714:     }
 2715:     xmlFree(content);
 2716:     return (catal);
 2717: }
 2718: 
 2719: /**
 2720:  * xmlExpandCatalog:
 2721:  * @catal:  a catalog
 2722:  * @filename:  a file path
 2723:  *
 2724:  * Load the catalog and expand the existing catal structure.
 2725:  * This can be either an XML Catalog or an SGML Catalog
 2726:  *
 2727:  * Returns 0 in case of success, -1 in case of error
 2728:  */
 2729: static int
 2730: xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
 2731: {
 2732:     int ret;
 2733: 
 2734:     if ((catal == NULL) || (filename == NULL))
 2735: 	return(-1);
 2736: 
 2737: 
 2738:     if (catal->type == XML_SGML_CATALOG_TYPE) {
 2739: 	xmlChar *content;
 2740: 
 2741: 	content = xmlLoadFileContent(filename);
 2742: 	if (content == NULL)
 2743: 	    return(-1);
 2744: 
 2745:         ret = xmlParseSGMLCatalog(catal, content, filename, 0);
 2746: 	if (ret < 0) {
 2747: 	    xmlFree(content);
 2748: 	    return(-1);
 2749: 	}
 2750: 	xmlFree(content);
 2751:     } else {
 2752: 	xmlCatalogEntryPtr tmp, cur;
 2753: 	tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
 2754: 		       NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
 2755: 
 2756: 	cur = catal->xml;
 2757: 	if (cur == NULL) {
 2758: 	    catal->xml = tmp;
 2759: 	} else {
 2760: 	    while (cur->next != NULL) cur = cur->next;
 2761: 	    cur->next = tmp;
 2762: 	}
 2763:     }
 2764:     return (0);
 2765: }
 2766: 
 2767: /**
 2768:  * xmlACatalogResolveSystem:
 2769:  * @catal:  a Catalog
 2770:  * @sysID:  the system ID string
 2771:  *
 2772:  * Try to lookup the catalog resource for a system ID
 2773:  *
 2774:  * Returns the resource if found or NULL otherwise, the value returned
 2775:  *      must be freed by the caller.
 2776:  */
 2777: xmlChar *
 2778: xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
 2779:     xmlChar *ret = NULL;
 2780: 
 2781:     if ((sysID == NULL) || (catal == NULL))
 2782: 	return(NULL);
 2783:     
 2784:     if (xmlDebugCatalogs)
 2785: 	xmlGenericError(xmlGenericErrorContext,
 2786: 		"Resolve sysID %s\n", sysID);
 2787: 
 2788:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2789: 	ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
 2790: 	if (ret == XML_CATAL_BREAK)
 2791: 	    ret = NULL;
 2792:     } else {
 2793: 	const xmlChar *sgml;
 2794: 
 2795: 	sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
 2796: 	if (sgml != NULL)
 2797: 	    ret = xmlStrdup(sgml);
 2798:     }
 2799:     return(ret);
 2800: }
 2801: 
 2802: /**
 2803:  * xmlACatalogResolvePublic:
 2804:  * @catal:  a Catalog
 2805:  * @pubID:  the public ID string
 2806:  *
 2807:  * Try to lookup the catalog local reference associated to a public ID in that catalog
 2808:  *
 2809:  * Returns the local resource if found or NULL otherwise, the value returned
 2810:  *      must be freed by the caller.
 2811:  */
 2812: xmlChar *
 2813: xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
 2814:     xmlChar *ret = NULL;
 2815: 
 2816:     if ((pubID == NULL) || (catal == NULL))
 2817: 	return(NULL);
 2818:     
 2819:     if (xmlDebugCatalogs)
 2820: 	xmlGenericError(xmlGenericErrorContext,
 2821: 		"Resolve pubID %s\n", pubID);
 2822: 
 2823:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2824: 	ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
 2825: 	if (ret == XML_CATAL_BREAK)
 2826: 	    ret = NULL;
 2827:     } else {
 2828: 	const xmlChar *sgml;
 2829: 
 2830: 	sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
 2831: 	if (sgml != NULL)
 2832: 	    ret = xmlStrdup(sgml);
 2833:     }
 2834:     return(ret);
 2835: }
 2836: 
 2837: /**
 2838:  * xmlACatalogResolve:
 2839:  * @catal:  a Catalog
 2840:  * @pubID:  the public ID string
 2841:  * @sysID:  the system ID string
 2842:  *
 2843:  * Do a complete resolution lookup of an External Identifier
 2844:  *
 2845:  * Returns the URI of the resource or NULL if not found, it must be freed
 2846:  *      by the caller.
 2847:  */
 2848: xmlChar *
 2849: xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
 2850:                    const xmlChar * sysID)
 2851: {
 2852:     xmlChar *ret = NULL;
 2853: 
 2854:     if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
 2855:         return (NULL);
 2856: 
 2857:     if (xmlDebugCatalogs) {
 2858:          if ((pubID != NULL) && (sysID != NULL)) {
 2859:              xmlGenericError(xmlGenericErrorContext,
 2860:                              "Resolve: pubID %s sysID %s\n", pubID, sysID);
 2861:          } else if (pubID != NULL) {
 2862:              xmlGenericError(xmlGenericErrorContext,
 2863:                              "Resolve: pubID %s\n", pubID);
 2864:          } else {
 2865:              xmlGenericError(xmlGenericErrorContext,
 2866:                              "Resolve: sysID %s\n", sysID);
 2867:          }
 2868:     }
 2869: 
 2870:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2871:         ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
 2872: 	if (ret == XML_CATAL_BREAK)
 2873: 	    ret = NULL;
 2874:     } else {
 2875:         const xmlChar *sgml;
 2876: 
 2877:         sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
 2878:         if (sgml != NULL)
 2879:             ret = xmlStrdup(sgml);
 2880:     }
 2881:     return (ret);
 2882: }
 2883: 
 2884: /**
 2885:  * xmlACatalogResolveURI:
 2886:  * @catal:  a Catalog
 2887:  * @URI:  the URI
 2888:  *
 2889:  * Do a complete resolution lookup of an URI
 2890:  *
 2891:  * Returns the URI of the resource or NULL if not found, it must be freed
 2892:  *      by the caller.
 2893:  */
 2894: xmlChar *
 2895: xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
 2896:     xmlChar *ret = NULL;
 2897: 
 2898:     if ((URI == NULL) || (catal == NULL))
 2899: 	return(NULL);
 2900: 
 2901:     if (xmlDebugCatalogs)
 2902: 	xmlGenericError(xmlGenericErrorContext,
 2903: 		"Resolve URI %s\n", URI);
 2904: 
 2905:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2906: 	ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
 2907: 	if (ret == XML_CATAL_BREAK)
 2908: 	    ret = NULL;
 2909:     } else {
 2910: 	const xmlChar *sgml;
 2911: 
 2912: 	sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
 2913: 	if (sgml != NULL)
 2914:             ret = xmlStrdup(sgml);
 2915:     }
 2916:     return(ret);
 2917: }
 2918: 
 2919: #ifdef LIBXML_OUTPUT_ENABLED
 2920: /**
 2921:  * xmlACatalogDump:
 2922:  * @catal:  a Catalog
 2923:  * @out:  the file.
 2924:  *
 2925:  * Dump the given catalog to the given file.
 2926:  */
 2927: void
 2928: xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
 2929:     if ((out == NULL) || (catal == NULL))
 2930: 	return;
 2931: 
 2932:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2933: 	xmlDumpXMLCatalog(out, catal->xml);
 2934:     } else {
 2935: 	xmlHashScan(catal->sgml,
 2936: 		    (xmlHashScanner) xmlCatalogDumpEntry, out);
 2937:     } 
 2938: }
 2939: #endif /* LIBXML_OUTPUT_ENABLED */
 2940: 
 2941: /**
 2942:  * xmlACatalogAdd:
 2943:  * @catal:  a Catalog
 2944:  * @type:  the type of record to add to the catalog
 2945:  * @orig:  the system, public or prefix to match 
 2946:  * @replace:  the replacement value for the match
 2947:  *
 2948:  * Add an entry in the catalog, it may overwrite existing but
 2949:  * different entries.
 2950:  *
 2951:  * Returns 0 if successful, -1 otherwise
 2952:  */
 2953: int
 2954: xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
 2955:               const xmlChar * orig, const xmlChar * replace)
 2956: {
 2957:     int res = -1;
 2958: 
 2959:     if (catal == NULL)
 2960: 	return(-1);
 2961: 
 2962:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2963:         res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
 2964:     } else {
 2965:         xmlCatalogEntryType cattype;
 2966: 
 2967:         cattype = xmlGetSGMLCatalogEntryType(type);
 2968:         if (cattype != XML_CATA_NONE) {
 2969:             xmlCatalogEntryPtr entry;
 2970: 
 2971:             entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
 2972:                                        XML_CATA_PREFER_NONE, NULL);
 2973: 	    if (catal->sgml == NULL)
 2974: 		catal->sgml = xmlHashCreate(10);
 2975:             res = xmlHashAddEntry(catal->sgml, orig, entry);
 2976:         }
 2977:     }
 2978:     return (res);
 2979: }
 2980: 
 2981: /**
 2982:  * xmlACatalogRemove:
 2983:  * @catal:  a Catalog
 2984:  * @value:  the value to remove
 2985:  *
 2986:  * Remove an entry from the catalog
 2987:  *
 2988:  * Returns the number of entries removed if successful, -1 otherwise
 2989:  */
 2990: int
 2991: xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
 2992:     int res = -1;
 2993: 
 2994:     if ((catal == NULL) || (value == NULL))
 2995: 	return(-1);
 2996: 
 2997:     if (catal->type == XML_XML_CATALOG_TYPE) {
 2998: 	res = xmlDelXMLCatalog(catal->xml, value);
 2999:     } else {
 3000: 	res = xmlHashRemoveEntry(catal->sgml, value,
 3001: 		(xmlHashDeallocator) xmlFreeCatalogEntry);
 3002: 	if (res == 0)
 3003: 	    res = 1;
 3004:     } 
 3005:     return(res);
 3006: }
 3007: 
 3008: /**
 3009:  * xmlNewCatalog:
 3010:  * @sgml:  should this create an SGML catalog
 3011:  *
 3012:  * create a new Catalog.
 3013:  *
 3014:  * Returns the xmlCatalogPtr or NULL in case of error
 3015:  */
 3016: xmlCatalogPtr
 3017: xmlNewCatalog(int sgml) {
 3018:     xmlCatalogPtr catal = NULL;
 3019: 
 3020:     if (sgml) {
 3021: 	catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
 3022: 		                    xmlCatalogDefaultPrefer);
 3023:         if ((catal != NULL) && (catal->sgml == NULL))
 3024: 	    catal->sgml = xmlHashCreate(10);
 3025:     } else
 3026: 	catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
 3027: 		                    xmlCatalogDefaultPrefer);
 3028:     return(catal);
 3029: }
 3030: 
 3031: /**
 3032:  * xmlCatalogIsEmpty:
 3033:  * @catal:  should this create an SGML catalog
 3034:  *
 3035:  * Check is a catalog is empty
 3036:  *
 3037:  * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
 3038:  */
 3039: int
 3040: xmlCatalogIsEmpty(xmlCatalogPtr catal) {
 3041:     if (catal == NULL)
 3042: 	return(-1);
 3043: 
 3044:     if (catal->type == XML_XML_CATALOG_TYPE) {
 3045: 	if (catal->xml == NULL)
 3046: 	    return(1);
 3047: 	if ((catal->xml->type != XML_CATA_CATALOG) &&
 3048: 	    (catal->xml->type != XML_CATA_BROKEN_CATALOG))
 3049: 	    return(-1);
 3050: 	if (catal->xml->children == NULL)
 3051: 	    return(1);
 3052:         return(0);
 3053:     } else {
 3054: 	int res;
 3055: 
 3056: 	if (catal->sgml == NULL)
 3057: 	    return(1);
 3058: 	res = xmlHashSize(catal->sgml);
 3059: 	if (res == 0)
 3060: 	    return(1);
 3061: 	if (res < 0)
 3062: 	    return(-1);
 3063:     } 
 3064:     return(0);
 3065: }
 3066: 
 3067: /************************************************************************
 3068:  *									*
 3069:  *   Public interfaces manipulating the global shared default catalog	*
 3070:  *									*
 3071:  ************************************************************************/
 3072: 
 3073: /**
 3074:  * xmlInitializeCatalogData:
 3075:  *
 3076:  * Do the catalog initialization only of global data, doesn't try to load
 3077:  * any catalog actually.
 3078:  * this function is not thread safe, catalog initialization should
 3079:  * preferably be done once at startup
 3080:  */
 3081: static void
 3082: xmlInitializeCatalogData(void) {
 3083:     if (xmlCatalogInitialized != 0)
 3084: 	return;
 3085: 
 3086:     if (getenv("XML_DEBUG_CATALOG")) 
 3087: 	xmlDebugCatalogs = 1;
 3088:     xmlCatalogMutex = xmlNewRMutex();
 3089: 
 3090:     xmlCatalogInitialized = 1;
 3091: }
 3092: /**
 3093:  * xmlInitializeCatalog:
 3094:  *
 3095:  * Do the catalog initialization.
 3096:  * this function is not thread safe, catalog initialization should
 3097:  * preferably be done once at startup
 3098:  */
 3099: void
 3100: xmlInitializeCatalog(void) {
 3101:     if (xmlCatalogInitialized != 0)
 3102: 	return;
 3103: 
 3104:     xmlInitializeCatalogData();
 3105:     xmlRMutexLock(xmlCatalogMutex);
 3106: 
 3107:     if (getenv("XML_DEBUG_CATALOG")) 
 3108: 	xmlDebugCatalogs = 1;
 3109: 
 3110:     if (xmlDefaultCatalog == NULL) {
 3111: 	const char *catalogs;
 3112: 	char *path;
 3113: 	const char *cur, *paths;
 3114: 	xmlCatalogPtr catal;
 3115: 	xmlCatalogEntryPtr *nextent;
 3116: 
 3117: 	catalogs = (const char *) getenv("XML_CATALOG_FILES");
 3118: 	if (catalogs == NULL)
 3119: #if defined(_WIN32) && defined(_MSC_VER)
 3120:     {
 3121: 		void* hmodule;
 3122: 		hmodule = GetModuleHandleA("libxml2.dll");
 3123: 		if (hmodule == NULL)
 3124: 			hmodule = GetModuleHandleA(NULL);
 3125: 		if (hmodule != NULL) {
 3126: 			char buf[256];
 3127: 			unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
 3128: 			if (len != 0) {
 3129: 				char* p = &(buf[len]);
 3130: 				while (*p != '\\' && p > buf) 
 3131: 					p--;
 3132: 				if (p != buf) {
 3133: 					xmlChar* uri;
 3134: 					strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
 3135: 					uri = xmlCanonicPath(buf);
 3136: 					if (uri != NULL) {
 3137: 						strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
 3138: 						xmlFree(uri);
 3139: 					}
 3140: 				}
 3141: 			}
 3142: 		}
 3143: 		catalogs = XML_XML_DEFAULT_CATALOG;
 3144:     }
 3145: #else
 3146: 	    catalogs = XML_XML_DEFAULT_CATALOG;
 3147: #endif
 3148: 
 3149: 	catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 
 3150: 		xmlCatalogDefaultPrefer);
 3151: 	if (catal != NULL) {
 3152: 	    /* the XML_CATALOG_FILES envvar is allowed to contain a 
 3153: 	       space-separated list of entries. */
 3154: 	    cur = catalogs;
 3155: 	    nextent = &catal->xml;
 3156: 	    while (*cur != '\0') {
 3157: 		while (xmlIsBlank_ch(*cur)) 
 3158: 		    cur++;
 3159: 		if (*cur != 0) {
 3160: 		    paths = cur;
 3161: 		    while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
 3162: 			cur++;
 3163: 		    path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
 3164: 		    if (path != NULL) {
 3165: 			*nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
 3166: 				NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
 3167: 			if (*nextent != NULL)
 3168: 			    nextent = &((*nextent)->next);
 3169: 			xmlFree(path);
 3170: 		    }
 3171: 		}
 3172: 	    }
 3173: 	    xmlDefaultCatalog = catal;
 3174: 	}
 3175:     }
 3176: 
 3177:     xmlRMutexUnlock(xmlCatalogMutex);
 3178: }
 3179: 
 3180: 
 3181: /**
 3182:  * xmlLoadCatalog:
 3183:  * @filename:  a file path
 3184:  *
 3185:  * Load the catalog and makes its definitions effective for the default
 3186:  * external entity loader. It will recurse in SGML CATALOG entries.
 3187:  * this function is not thread safe, catalog initialization should
 3188:  * preferably be done once at startup
 3189:  *
 3190:  * Returns 0 in case of success -1 in case of error
 3191:  */
 3192: int
 3193: xmlLoadCatalog(const char *filename)
 3194: {
 3195:     int ret;
 3196:     xmlCatalogPtr catal;
 3197: 
 3198:     if (!xmlCatalogInitialized)
 3199: 	xmlInitializeCatalogData();
 3200: 
 3201:     xmlRMutexLock(xmlCatalogMutex);
 3202: 
 3203:     if (xmlDefaultCatalog == NULL) {
 3204: 	catal = xmlLoadACatalog(filename);
 3205: 	if (catal == NULL) {
 3206: 	    xmlRMutexUnlock(xmlCatalogMutex);
 3207: 	    return(-1);
 3208: 	}
 3209: 
 3210: 	xmlDefaultCatalog = catal;
 3211: 	xmlRMutexUnlock(xmlCatalogMutex);
 3212: 	return(0);
 3213:     }
 3214: 
 3215:     ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
 3216:     xmlRMutexUnlock(xmlCatalogMutex);
 3217:     return(ret);
 3218: }
 3219: 
 3220: /**
 3221:  * xmlLoadCatalogs:
 3222:  * @pathss:  a list of directories separated by a colon or a space.
 3223:  *
 3224:  * Load the catalogs and makes their definitions effective for the default
 3225:  * external entity loader.
 3226:  * this function is not thread safe, catalog initialization should
 3227:  * preferably be done once at startup
 3228:  */
 3229: void
 3230: xmlLoadCatalogs(const char *pathss) {
 3231:     const char *cur;
 3232:     const char *paths;
 3233:     xmlChar *path;
 3234: #ifdef _WIN32
 3235:     int i, iLen;
 3236: #endif
 3237: 
 3238:     if (pathss == NULL)
 3239: 	return;
 3240: 
 3241:     cur = pathss;
 3242:     while (*cur != 0) {
 3243: 	while (xmlIsBlank_ch(*cur)) cur++;
 3244: 	if (*cur != 0) {
 3245: 	    paths = cur;
 3246: 	    while ((*cur != 0) && (*cur != PATH_SEAPARATOR) && (!xmlIsBlank_ch(*cur)))
 3247: 		cur++;
 3248: 	    path = xmlStrndup((const xmlChar *)paths, cur - paths);
 3249: #ifdef _WIN32
 3250:         iLen = strlen(path);
 3251:         for(i = 0; i < iLen; i++) {
 3252:             if(path[i] == '\\') {
 3253:                 path[i] = '/';
 3254:             }
 3255:         }
 3256: #endif
 3257: 	    if (path != NULL) {
 3258: 		xmlLoadCatalog((const char *) path);
 3259: 		xmlFree(path);
 3260: 	    }
 3261: 	}
 3262: 	while (*cur == PATH_SEAPARATOR)
 3263: 	    cur++;
 3264:     }
 3265: }
 3266: 
 3267: /**
 3268:  * xmlCatalogCleanup:
 3269:  *
 3270:  * Free up all the memory associated with catalogs
 3271:  */
 3272: void
 3273: xmlCatalogCleanup(void) {
 3274:     if (xmlCatalogInitialized == 0)
 3275:         return;
 3276: 
 3277:     xmlRMutexLock(xmlCatalogMutex);
 3278:     if (xmlDebugCatalogs)
 3279: 	xmlGenericError(xmlGenericErrorContext,
 3280: 		"Catalogs cleanup\n");
 3281:     if (xmlCatalogXMLFiles != NULL)
 3282: 	xmlHashFree(xmlCatalogXMLFiles, 
 3283: 		    (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
 3284:     xmlCatalogXMLFiles = NULL;
 3285:     if (xmlDefaultCatalog != NULL)
 3286: 	xmlFreeCatalog(xmlDefaultCatalog);
 3287:     xmlDefaultCatalog = NULL;
 3288:     xmlDebugCatalogs = 0;
 3289:     xmlCatalogInitialized = 0;
 3290:     xmlRMutexUnlock(xmlCatalogMutex);
 3291:     xmlFreeRMutex(xmlCatalogMutex);
 3292: }
 3293: 
 3294: /**
 3295:  * xmlCatalogResolveSystem:
 3296:  * @sysID:  the system ID string
 3297:  *
 3298:  * Try to lookup the catalog resource for a system ID
 3299:  *
 3300:  * Returns the resource if found or NULL otherwise, the value returned
 3301:  *      must be freed by the caller.
 3302:  */
 3303: xmlChar *
 3304: xmlCatalogResolveSystem(const xmlChar *sysID) {
 3305:     xmlChar *ret;
 3306: 
 3307:     if (!xmlCatalogInitialized)
 3308: 	xmlInitializeCatalog();
 3309: 
 3310:     ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
 3311:     return(ret);
 3312: }
 3313: 
 3314: /**
 3315:  * xmlCatalogResolvePublic:
 3316:  * @pubID:  the public ID string
 3317:  *
 3318:  * Try to lookup the catalog reference associated to a public ID
 3319:  *
 3320:  * Returns the resource if found or NULL otherwise, the value returned
 3321:  *      must be freed by the caller.
 3322:  */
 3323: xmlChar *
 3324: xmlCatalogResolvePublic(const xmlChar *pubID) {
 3325:     xmlChar *ret;
 3326: 
 3327:     if (!xmlCatalogInitialized)
 3328: 	xmlInitializeCatalog();
 3329: 
 3330:     ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
 3331:     return(ret);
 3332: }
 3333: 
 3334: /**
 3335:  * xmlCatalogResolve:
 3336:  * @pubID:  the public ID string
 3337:  * @sysID:  the system ID string
 3338:  *
 3339:  * Do a complete resolution lookup of an External Identifier
 3340:  *
 3341:  * Returns the URI of the resource or NULL if not found, it must be freed
 3342:  *      by the caller.
 3343:  */
 3344: xmlChar *
 3345: xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
 3346:     xmlChar *ret;
 3347: 
 3348:     if (!xmlCatalogInitialized)
 3349: 	xmlInitializeCatalog();
 3350: 
 3351:     ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
 3352:     return(ret);
 3353: }
 3354: 
 3355: /**
 3356:  * xmlCatalogResolveURI:
 3357:  * @URI:  the URI
 3358:  *
 3359:  * Do a complete resolution lookup of an URI
 3360:  *
 3361:  * Returns the URI of the resource or NULL if not found, it must be freed
 3362:  *      by the caller.
 3363:  */
 3364: xmlChar *
 3365: xmlCatalogResolveURI(const xmlChar *URI) {
 3366:     xmlChar *ret;
 3367: 
 3368:     if (!xmlCatalogInitialized)
 3369: 	xmlInitializeCatalog();
 3370: 
 3371:     ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
 3372:     return(ret);
 3373: }
 3374: 
 3375: #ifdef LIBXML_OUTPUT_ENABLED
 3376: /**
 3377:  * xmlCatalogDump:
 3378:  * @out:  the file.
 3379:  *
 3380:  * Dump all the global catalog content to the given file.
 3381:  */
 3382: void
 3383: xmlCatalogDump(FILE *out) {
 3384:     if (out == NULL)
 3385: 	return;
 3386: 
 3387:     if (!xmlCatalogInitialized)
 3388: 	xmlInitializeCatalog();
 3389: 
 3390:     xmlACatalogDump(xmlDefaultCatalog, out);
 3391: }
 3392: #endif /* LIBXML_OUTPUT_ENABLED */
 3393: 
 3394: /**
 3395:  * xmlCatalogAdd:
 3396:  * @type:  the type of record to add to the catalog
 3397:  * @orig:  the system, public or prefix to match 
 3398:  * @replace:  the replacement value for the match
 3399:  *
 3400:  * Add an entry in the catalog, it may overwrite existing but
 3401:  * different entries.
 3402:  * If called before any other catalog routine, allows to override the
 3403:  * default shared catalog put in place by xmlInitializeCatalog();
 3404:  *
 3405:  * Returns 0 if successful, -1 otherwise
 3406:  */
 3407: int
 3408: xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
 3409:     int res = -1;
 3410: 
 3411:     if (!xmlCatalogInitialized)
 3412: 	xmlInitializeCatalogData();
 3413: 
 3414:     xmlRMutexLock(xmlCatalogMutex);
 3415:     /*
 3416:      * Specific case where one want to override the default catalog
 3417:      * put in place by xmlInitializeCatalog();
 3418:      */
 3419:     if ((xmlDefaultCatalog == NULL) &&
 3420: 	(xmlStrEqual(type, BAD_CAST "catalog"))) {
 3421: 	xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
 3422: 		                          xmlCatalogDefaultPrefer);
 3423: 	xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
 3424: 				    orig, NULL,  xmlCatalogDefaultPrefer, NULL);
 3425: 
 3426: 	xmlRMutexUnlock(xmlCatalogMutex);
 3427: 	return(0);
 3428:     } 
 3429: 
 3430:     res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
 3431:     xmlRMutexUnlock(xmlCatalogMutex);
 3432:     return(res);
 3433: }
 3434: 
 3435: /**
 3436:  * xmlCatalogRemove:
 3437:  * @value:  the value to remove
 3438:  *
 3439:  * Remove an entry from the catalog
 3440:  *
 3441:  * Returns the number of entries removed if successful, -1 otherwise
 3442:  */
 3443: int
 3444: xmlCatalogRemove(const xmlChar *value) {
 3445:     int res;
 3446: 
 3447:     if (!xmlCatalogInitialized)
 3448: 	xmlInitializeCatalog();
 3449: 
 3450:     xmlRMutexLock(xmlCatalogMutex);
 3451:     res = xmlACatalogRemove(xmlDefaultCatalog, value);
 3452:     xmlRMutexUnlock(xmlCatalogMutex);
 3453:     return(res);
 3454: }
 3455: 
 3456: /**
 3457:  * xmlCatalogConvert:
 3458:  *
 3459:  * Convert all the SGML catalog entries as XML ones
 3460:  *
 3461:  * Returns the number of entries converted if successful, -1 otherwise
 3462:  */
 3463: int
 3464: xmlCatalogConvert(void) {
 3465:     int res = -1;
 3466: 
 3467:     if (!xmlCatalogInitialized)
 3468: 	xmlInitializeCatalog();
 3469: 
 3470:     xmlRMutexLock(xmlCatalogMutex);
 3471:     res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
 3472:     xmlRMutexUnlock(xmlCatalogMutex);
 3473:     return(res);
 3474: }
 3475: 
 3476: /************************************************************************
 3477:  *									*
 3478:  *	Public interface manipulating the common preferences		*
 3479:  *									*
 3480:  ************************************************************************/
 3481: 
 3482: /**
 3483:  * xmlCatalogGetDefaults:
 3484:  *
 3485:  * Used to get the user preference w.r.t. to what catalogs should
 3486:  * be accepted
 3487:  *
 3488:  * Returns the current xmlCatalogAllow value
 3489:  */
 3490: xmlCatalogAllow
 3491: xmlCatalogGetDefaults(void) {
 3492:     return(xmlCatalogDefaultAllow);
 3493: }
 3494: 
 3495: /**
 3496:  * xmlCatalogSetDefaults:
 3497:  * @allow:  what catalogs should be accepted
 3498:  *
 3499:  * Used to set the user preference w.r.t. to what catalogs should
 3500:  * be accepted
 3501:  */
 3502: void
 3503: xmlCatalogSetDefaults(xmlCatalogAllow allow) {
 3504:     if (xmlDebugCatalogs) {
 3505: 	switch (allow) {
 3506: 	    case XML_CATA_ALLOW_NONE:
 3507: 		xmlGenericError(xmlGenericErrorContext,
 3508: 			"Disabling catalog usage\n");
 3509: 		break;
 3510: 	    case XML_CATA_ALLOW_GLOBAL:
 3511: 		xmlGenericError(xmlGenericErrorContext,
 3512: 			"Allowing only global catalogs\n");
 3513: 		break;
 3514: 	    case XML_CATA_ALLOW_DOCUMENT:
 3515: 		xmlGenericError(xmlGenericErrorContext,
 3516: 			"Allowing only catalogs from the document\n");
 3517: 		break;
 3518: 	    case XML_CATA_ALLOW_ALL:
 3519: 		xmlGenericError(xmlGenericErrorContext,
 3520: 			"Allowing all catalogs\n");
 3521: 		break;
 3522: 	}
 3523:     }
 3524:     xmlCatalogDefaultAllow = allow;
 3525: }
 3526: 
 3527: /**
 3528:  * xmlCatalogSetDefaultPrefer:
 3529:  * @prefer:  the default preference for delegation
 3530:  *
 3531:  * Allows to set the preference between public and system for deletion
 3532:  * in XML Catalog resolution. C.f. section 4.1.1 of the spec
 3533:  * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
 3534:  *
 3535:  * Returns the previous value of the default preference for delegation
 3536:  */
 3537: xmlCatalogPrefer
 3538: xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
 3539:     xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
 3540: 
 3541:     if (prefer == XML_CATA_PREFER_NONE)
 3542: 	return(ret);
 3543: 
 3544:     if (xmlDebugCatalogs) {
 3545: 	switch (prefer) {
 3546: 	    case XML_CATA_PREFER_PUBLIC:
 3547: 		xmlGenericError(xmlGenericErrorContext,
 3548: 			"Setting catalog preference to PUBLIC\n");
 3549: 		break;
 3550: 	    case XML_CATA_PREFER_SYSTEM:
 3551: 		xmlGenericError(xmlGenericErrorContext,
 3552: 			"Setting catalog preference to SYSTEM\n");
 3553: 		break;
 3554: 	    case XML_CATA_PREFER_NONE:
 3555: 		break;
 3556: 	}
 3557:     }
 3558:     xmlCatalogDefaultPrefer = prefer;
 3559:     return(ret);
 3560: }
 3561: 
 3562: /**
 3563:  * xmlCatalogSetDebug:
 3564:  * @level:  the debug level of catalogs required
 3565:  *
 3566:  * Used to set the debug level for catalog operation, 0 disable
 3567:  * debugging, 1 enable it
 3568:  *
 3569:  * Returns the previous value of the catalog debugging level
 3570:  */
 3571: int
 3572: xmlCatalogSetDebug(int level) {
 3573:     int ret = xmlDebugCatalogs;
 3574: 
 3575:     if (level <= 0)
 3576:         xmlDebugCatalogs = 0;
 3577:     else
 3578: 	xmlDebugCatalogs = level;
 3579:     return(ret);
 3580: }
 3581: 
 3582: /************************************************************************
 3583:  *									*
 3584:  *   Minimal interfaces used for per-document catalogs by the parser	*
 3585:  *									*
 3586:  ************************************************************************/
 3587: 
 3588: /**
 3589:  * xmlCatalogFreeLocal:
 3590:  * @catalogs:  a document's list of catalogs
 3591:  *
 3592:  * Free up the memory associated to the catalog list
 3593:  */
 3594: void
 3595: xmlCatalogFreeLocal(void *catalogs) {
 3596:     xmlCatalogEntryPtr catal;
 3597: 
 3598:     if (!xmlCatalogInitialized)
 3599: 	xmlInitializeCatalog();
 3600: 
 3601:     catal = (xmlCatalogEntryPtr) catalogs;
 3602:     if (catal != NULL)
 3603: 	xmlFreeCatalogEntryList(catal);
 3604: }
 3605: 
 3606: 
 3607: /**
 3608:  * xmlCatalogAddLocal:
 3609:  * @catalogs:  a document's list of catalogs
 3610:  * @URL:  the URL to a new local catalog
 3611:  *
 3612:  * Add the new entry to the catalog list
 3613:  *
 3614:  * Returns the updated list
 3615:  */
 3616: void *	
 3617: xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
 3618:     xmlCatalogEntryPtr catal, add;
 3619: 
 3620:     if (!xmlCatalogInitialized)
 3621: 	xmlInitializeCatalog();
 3622: 
 3623:     if (URL == NULL)
 3624: 	return(catalogs);
 3625: 
 3626:     if (xmlDebugCatalogs)
 3627: 	xmlGenericError(xmlGenericErrorContext,
 3628: 		"Adding document catalog %s\n", URL);
 3629: 
 3630:     add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
 3631: 	                     xmlCatalogDefaultPrefer, NULL);
 3632:     if (add == NULL)
 3633: 	return(catalogs);
 3634: 
 3635:     catal = (xmlCatalogEntryPtr) catalogs;
 3636:     if (catal == NULL) 
 3637: 	return((void *) add);
 3638: 
 3639:     while (catal->next != NULL)
 3640: 	catal = catal->next;
 3641:     catal->next = add;
 3642:     return(catalogs);
 3643: }
 3644: 
 3645: /**
 3646:  * xmlCatalogLocalResolve:
 3647:  * @catalogs:  a document's list of catalogs
 3648:  * @pubID:  the public ID string
 3649:  * @sysID:  the system ID string
 3650:  *
 3651:  * Do a complete resolution lookup of an External Identifier using a 
 3652:  * document's private catalog list
 3653:  *
 3654:  * Returns the URI of the resource or NULL if not found, it must be freed
 3655:  *      by the caller.
 3656:  */
 3657: xmlChar *
 3658: xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
 3659: 	               const xmlChar *sysID) {
 3660:     xmlCatalogEntryPtr catal;
 3661:     xmlChar *ret;
 3662: 
 3663:     if (!xmlCatalogInitialized)
 3664: 	xmlInitializeCatalog();
 3665: 
 3666:     if ((pubID == NULL) && (sysID == NULL))
 3667: 	return(NULL);
 3668: 
 3669:     if (xmlDebugCatalogs) {
 3670:         if ((pubID != NULL) && (sysID != NULL)) {
 3671:             xmlGenericError(xmlGenericErrorContext,
 3672:                             "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
 3673:         } else if (pubID != NULL) {
 3674:             xmlGenericError(xmlGenericErrorContext,
 3675:                             "Local Resolve: pubID %s\n", pubID);
 3676:         } else {
 3677:             xmlGenericError(xmlGenericErrorContext,
 3678:                             "Local Resolve: sysID %s\n", sysID);
 3679:         }
 3680:     }
 3681: 
 3682:     catal = (xmlCatalogEntryPtr) catalogs;
 3683:     if (catal == NULL)
 3684: 	return(NULL);
 3685:     ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
 3686:     if ((ret != NULL) && (ret != XML_CATAL_BREAK))
 3687: 	return(ret);
 3688:     return(NULL);
 3689: }
 3690: 
 3691: /**
 3692:  * xmlCatalogLocalResolveURI:
 3693:  * @catalogs:  a document's list of catalogs
 3694:  * @URI:  the URI
 3695:  *
 3696:  * Do a complete resolution lookup of an URI using a 
 3697:  * document's private catalog list
 3698:  *
 3699:  * Returns the URI of the resource or NULL if not found, it must be freed
 3700:  *      by the caller.
 3701:  */
 3702: xmlChar *
 3703: xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
 3704:     xmlCatalogEntryPtr catal;
 3705:     xmlChar *ret;
 3706: 
 3707:     if (!xmlCatalogInitialized)
 3708: 	xmlInitializeCatalog();
 3709: 
 3710:     if (URI == NULL)
 3711: 	return(NULL);
 3712: 
 3713:     if (xmlDebugCatalogs)
 3714: 	xmlGenericError(xmlGenericErrorContext,
 3715: 		"Resolve URI %s\n", URI);
 3716: 
 3717:     catal = (xmlCatalogEntryPtr) catalogs;
 3718:     if (catal == NULL)
 3719: 	return(NULL);
 3720:     ret = xmlCatalogListXMLResolveURI(catal, URI);
 3721:     if ((ret != NULL) && (ret != XML_CATAL_BREAK))
 3722: 	return(ret);
 3723:     return(NULL);
 3724: }
 3725: 
 3726: /************************************************************************
 3727:  *									*
 3728:  *			Deprecated interfaces				*
 3729:  *									*
 3730:  ************************************************************************/
 3731: /**
 3732:  * xmlCatalogGetSystem:
 3733:  * @sysID:  the system ID string
 3734:  *
 3735:  * Try to lookup the catalog reference associated to a system ID
 3736:  * DEPRECATED, use xmlCatalogResolveSystem()
 3737:  *
 3738:  * Returns the resource if found or NULL otherwise.
 3739:  */
 3740: const xmlChar *
 3741: xmlCatalogGetSystem(const xmlChar *sysID) {
 3742:     xmlChar *ret;
 3743:     static xmlChar result[1000];
 3744:     static int msg = 0;
 3745: 
 3746:     if (!xmlCatalogInitialized)
 3747: 	xmlInitializeCatalog();
 3748: 
 3749:     if (msg == 0) {
 3750: 	xmlGenericError(xmlGenericErrorContext,
 3751: 		"Use of deprecated xmlCatalogGetSystem() call\n");
 3752: 	msg++;
 3753:     }
 3754: 
 3755:     if (sysID == NULL)
 3756: 	return(NULL);
 3757:     
 3758:     /*
 3759:      * Check first the XML catalogs
 3760:      */
 3761:     if (xmlDefaultCatalog != NULL) {
 3762: 	ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
 3763: 	if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
 3764: 	    snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
 3765: 	    result[sizeof(result) - 1] = 0;
 3766: 	    return(result);
 3767: 	}
 3768:     }
 3769: 
 3770:     if (xmlDefaultCatalog != NULL)
 3771: 	return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
 3772:     return(NULL);
 3773: }
 3774: 
 3775: /**
 3776:  * xmlCatalogGetPublic:
 3777:  * @pubID:  the public ID string
 3778:  *
 3779:  * Try to lookup the catalog reference associated to a public ID
 3780:  * DEPRECATED, use xmlCatalogResolvePublic()
 3781:  *
 3782:  * Returns the resource if found or NULL otherwise.
 3783:  */
 3784: const xmlChar *
 3785: xmlCatalogGetPublic(const xmlChar *pubID) {
 3786:     xmlChar *ret;
 3787:     static xmlChar result[1000];
 3788:     static int msg = 0;
 3789: 
 3790:     if (!xmlCatalogInitialized)
 3791: 	xmlInitializeCatalog();
 3792: 
 3793:     if (msg == 0) {
 3794: 	xmlGenericError(xmlGenericErrorContext,
 3795: 		"Use of deprecated xmlCatalogGetPublic() call\n");
 3796: 	msg++;
 3797:     }
 3798: 
 3799:     if (pubID == NULL)
 3800: 	return(NULL);
 3801:     
 3802:     /*
 3803:      * Check first the XML catalogs
 3804:      */
 3805:     if (xmlDefaultCatalog != NULL) {
 3806: 	ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
 3807: 	if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
 3808: 	    snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
 3809: 	    result[sizeof(result) - 1] = 0;
 3810: 	    return(result);
 3811: 	}
 3812:     }
 3813: 
 3814:     if (xmlDefaultCatalog != NULL)
 3815: 	return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
 3816:     return(NULL);
 3817: }
 3818: 
 3819: #define bottom_catalog
 3820: #include "elfgcchack.h"
 3821: #endif /* LIBXML_CATALOG_ENABLED */

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