File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / catalog.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:30 2014 UTC (9 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

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

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