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

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

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