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

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

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