Annotation of embedaddon/libxml2/catalog.c, revision 1.1

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

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