ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

catalog.c
Go to the documentation of this file.
00001 
00015 #define IN_LIBXML
00016 #include "libxml.h"
00017 
00018 #ifdef LIBXML_CATALOG_ENABLED
00019 #ifdef HAVE_SYS_TYPES_H
00020 #include <sys/types.h>
00021 #endif
00022 #ifdef HAVE_SYS_STAT_H
00023 #include <sys/stat.h>
00024 #endif
00025 #ifdef HAVE_UNISTD_H
00026 #include <unistd.h>
00027 #endif
00028 #ifdef HAVE_FCNTL_H
00029 #include <fcntl.h>
00030 #endif
00031 #ifdef HAVE_STDLIB_H
00032 #include <stdlib.h>
00033 #endif
00034 #include <string.h>
00035 #include <libxml/xmlmemory.h>
00036 #include <libxml/hash.h>
00037 #include <libxml/uri.h>
00038 #include <libxml/parserInternals.h>
00039 #include <libxml/catalog.h>
00040 #include <libxml/xmlerror.h>
00041 #include <libxml/threads.h>
00042 #include <libxml/globals.h>
00043 
00044 #define MAX_DELEGATE    50
00045 #define MAX_CATAL_DEPTH 50
00046 
00047 #ifdef _WIN32
00048 # define PATH_SEAPARATOR ';'
00049 #else
00050 # define PATH_SEAPARATOR ':'
00051 #endif
00052 
00063 #define TODO                                \
00064     xmlGenericError(xmlGenericErrorContext,             \
00065         "Unimplemented block at %s:%d\n",               \
00066             __FILE__, __LINE__);
00067 
00068 #define XML_URN_PUBID "urn:publicid:"
00069 #define XML_CATAL_BREAK ((xmlChar *) -1)
00070 #ifndef XML_XML_DEFAULT_CATALOG
00071 #define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
00072 #endif
00073 #ifndef XML_SGML_DEFAULT_CATALOG
00074 #define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
00075 #endif
00076 
00077 #if defined(_WIN32) && defined(_MSC_VER)
00078 #undef XML_XML_DEFAULT_CATALOG
00079 static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
00080 #if defined(_WIN32_WCE)
00081 /* Windows CE don't have a A variant */
00082 #define GetModuleHandleA GetModuleHandle
00083 #define GetModuleFileNameA GetModuleFileName
00084 #else
00085 void* __stdcall GetModuleHandleA(const char*);
00086 unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
00087 #endif
00088 #endif
00089 
00090 static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
00091 static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
00092 
00093 /************************************************************************
00094  *                                  *
00095  *          Types, all private              *
00096  *                                  *
00097  ************************************************************************/
00098 
00099 typedef enum {
00100     XML_CATA_REMOVED = -1,
00101     XML_CATA_NONE = 0,
00102     XML_CATA_CATALOG,
00103     XML_CATA_BROKEN_CATALOG,
00104     XML_CATA_NEXT_CATALOG,
00105     XML_CATA_GROUP,
00106     XML_CATA_PUBLIC,
00107     XML_CATA_SYSTEM,
00108     XML_CATA_REWRITE_SYSTEM,
00109     XML_CATA_DELEGATE_PUBLIC,
00110     XML_CATA_DELEGATE_SYSTEM,
00111     XML_CATA_URI,
00112     XML_CATA_REWRITE_URI,
00113     XML_CATA_DELEGATE_URI,
00114     SGML_CATA_SYSTEM,
00115     SGML_CATA_PUBLIC,
00116     SGML_CATA_ENTITY,
00117     SGML_CATA_PENTITY,
00118     SGML_CATA_DOCTYPE,
00119     SGML_CATA_LINKTYPE,
00120     SGML_CATA_NOTATION,
00121     SGML_CATA_DELEGATE,
00122     SGML_CATA_BASE,
00123     SGML_CATA_CATALOG,
00124     SGML_CATA_DOCUMENT,
00125     SGML_CATA_SGMLDECL
00126 } xmlCatalogEntryType;
00127 
00128 typedef struct _xmlCatalogEntry xmlCatalogEntry;
00129 typedef xmlCatalogEntry *xmlCatalogEntryPtr;
00130 struct _xmlCatalogEntry {
00131     struct _xmlCatalogEntry *next;
00132     struct _xmlCatalogEntry *parent;
00133     struct _xmlCatalogEntry *children;
00134     xmlCatalogEntryType type;
00135     xmlChar *name;
00136     xmlChar *value;
00137     xmlChar *URL;  /* The expanded URL using the base */
00138     xmlCatalogPrefer prefer;
00139     int dealloc;
00140     int depth;
00141     struct _xmlCatalogEntry *group;
00142 };
00143 
00144 typedef enum {
00145     XML_XML_CATALOG_TYPE = 1,
00146     XML_SGML_CATALOG_TYPE
00147 } xmlCatalogType;
00148 
00149 #define XML_MAX_SGML_CATA_DEPTH 10
00150 struct _xmlCatalog {
00151     xmlCatalogType type;    /* either XML or SGML */
00152 
00153     /*
00154      * SGML Catalogs are stored as a simple hash table of catalog entries
00155      * Catalog stack to check against overflows when building the
00156      * SGML catalog
00157      */
00158     char *catalTab[XML_MAX_SGML_CATA_DEPTH];    /* stack of catals */
00159     int          catalNr;   /* Number of current catal streams */
00160     int          catalMax;  /* Max number of catal streams */
00161     xmlHashTablePtr sgml;
00162 
00163     /*
00164      * XML Catalogs are stored as a tree of Catalog entries
00165      */
00166     xmlCatalogPrefer prefer;
00167     xmlCatalogEntryPtr xml;
00168 };
00169 
00170 /************************************************************************
00171  *                                  *
00172  *          Global variables                *
00173  *                                  *
00174  ************************************************************************/
00175 
00176 /*
00177  * Those are preferences
00178  */
00179 static int xmlDebugCatalogs = 0;   /* used for debugging */
00180 static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
00181 static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
00182 
00183 /*
00184  * Hash table containing all the trees of XML catalogs parsed by
00185  * the application.
00186  */
00187 static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
00188 
00189 /*
00190  * The default catalog in use by the application
00191  */
00192 static xmlCatalogPtr xmlDefaultCatalog = NULL;
00193 
00194 /*
00195  * A mutex for modifying the shared global catalog(s)
00196  * xmlDefaultCatalog tree.
00197  * It also protects xmlCatalogXMLFiles
00198  * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
00199  */
00200 static xmlRMutexPtr xmlCatalogMutex = NULL;
00201 
00202 /*
00203  * Whether the catalog support was initialized.
00204  */
00205 static int xmlCatalogInitialized = 0;
00206 
00207 /************************************************************************
00208  *                                  *
00209  *          Catalog error handlers              *
00210  *                                  *
00211  ************************************************************************/
00212 
00219 static void
00220 xmlCatalogErrMemory(const char *extra)
00221 {
00222     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
00223                     XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
00224             extra, NULL, NULL, 0, 0,
00225             "Memory allocation failed : %s\n", extra);
00226 }
00227 
00237 static void
00238 xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
00239                const char *msg, const xmlChar *str1, const xmlChar *str2,
00240            const xmlChar *str3)
00241 {
00242     __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
00243                     error, XML_ERR_ERROR, NULL, 0,
00244             (const char *) str1, (const char *) str2,
00245             (const char *) str3, 0, 0,
00246             msg, str1, str2, str3);
00247 }
00248 
00249 
00250 /************************************************************************
00251  *                                  *
00252  *          Allocation and Freeing              *
00253  *                                  *
00254  ************************************************************************/
00255 
00269 static xmlCatalogEntryPtr
00270 xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
00271        const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
00272        xmlCatalogEntryPtr group) {
00273     xmlCatalogEntryPtr ret;
00274     xmlChar *normid = NULL;
00275 
00276     ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
00277     if (ret == NULL) {
00278         xmlCatalogErrMemory("allocating catalog entry");
00279     return(NULL);
00280     }
00281     ret->next = NULL;
00282     ret->parent = NULL;
00283     ret->children = NULL;
00284     ret->type = type;
00285     if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
00286         normid = xmlCatalogNormalizePublic(name);
00287         if (normid != NULL)
00288             name = (*normid != 0 ? normid : NULL);
00289     }
00290     if (name != NULL)
00291     ret->name = xmlStrdup(name);
00292     else
00293     ret->name = NULL;
00294     if (normid != NULL)
00295         xmlFree(normid);
00296     if (value != NULL)
00297     ret->value = xmlStrdup(value);
00298     else
00299     ret->value = NULL;
00300     if (URL == NULL)
00301     URL = value;
00302     if (URL != NULL)
00303     ret->URL = xmlStrdup(URL);
00304     else
00305     ret->URL = NULL;
00306     ret->prefer = prefer;
00307     ret->dealloc = 0;
00308     ret->depth = 0;
00309     ret->group = group;
00310     return(ret);
00311 }
00312 
00313 static void
00314 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
00315 
00322 static void
00323 xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
00324     if (ret == NULL)
00325     return;
00326     /*
00327      * Entries stored in the file hash must be deallocated
00328      * only by the file hash cleaner !
00329      */
00330     if (ret->dealloc == 1)
00331     return;
00332 
00333     if (xmlDebugCatalogs) {
00334     if (ret->name != NULL)
00335         xmlGenericError(xmlGenericErrorContext,
00336             "Free catalog entry %s\n", ret->name);
00337     else if (ret->value != NULL)
00338         xmlGenericError(xmlGenericErrorContext,
00339             "Free catalog entry %s\n", ret->value);
00340     else
00341         xmlGenericError(xmlGenericErrorContext,
00342             "Free catalog entry\n");
00343     }
00344 
00345     if (ret->name != NULL)
00346     xmlFree(ret->name);
00347     if (ret->value != NULL)
00348     xmlFree(ret->value);
00349     if (ret->URL != NULL)
00350     xmlFree(ret->URL);
00351     xmlFree(ret);
00352 }
00353 
00360 static void
00361 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
00362     xmlCatalogEntryPtr next;
00363 
00364     while (ret != NULL) {
00365     next = ret->next;
00366     xmlFreeCatalogEntry(ret);
00367     ret = next;
00368     }
00369 }
00370 
00378 static void
00379 xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
00380     xmlCatalogEntryPtr children, next;
00381 
00382     if (catal == NULL)
00383     return;
00384 
00385     children = catal->children;
00386     while (children != NULL) {
00387     next = children->next;
00388     children->dealloc = 0;
00389     children->children = NULL;
00390     xmlFreeCatalogEntry(children);
00391     children = next;
00392     }
00393     catal->dealloc = 0;
00394     xmlFreeCatalogEntry(catal);
00395 }
00396 
00407 static xmlCatalogPtr
00408 xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
00409     xmlCatalogPtr ret;
00410 
00411     ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
00412     if (ret == NULL) {
00413         xmlCatalogErrMemory("allocating catalog");
00414     return(NULL);
00415     }
00416     memset(ret, 0, sizeof(xmlCatalog));
00417     ret->type = type;
00418     ret->catalNr = 0;
00419     ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
00420     ret->prefer = prefer;
00421     if (ret->type == XML_SGML_CATALOG_TYPE)
00422     ret->sgml = xmlHashCreate(10);
00423     return(ret);
00424 }
00425 
00432 void
00433 xmlFreeCatalog(xmlCatalogPtr catal) {
00434     if (catal == NULL)
00435     return;
00436     if (catal->xml != NULL)
00437     xmlFreeCatalogEntryList(catal->xml);
00438     if (catal->sgml != NULL)
00439     xmlHashFree(catal->sgml,
00440         (xmlHashDeallocator) xmlFreeCatalogEntry);
00441     xmlFree(catal);
00442 }
00443 
00444 /************************************************************************
00445  *                                  *
00446  *          Serializing Catalogs                *
00447  *                                  *
00448  ************************************************************************/
00449 
00450 #ifdef LIBXML_OUTPUT_ENABLED
00451 
00458 static void
00459 xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
00460     if ((entry == NULL) || (out == NULL))
00461     return;
00462     switch (entry->type) {
00463     case SGML_CATA_ENTITY:
00464         fprintf(out, "ENTITY "); break;
00465     case SGML_CATA_PENTITY:
00466         fprintf(out, "ENTITY %%"); break;
00467     case SGML_CATA_DOCTYPE:
00468         fprintf(out, "DOCTYPE "); break;
00469     case SGML_CATA_LINKTYPE:
00470         fprintf(out, "LINKTYPE "); break;
00471     case SGML_CATA_NOTATION:
00472         fprintf(out, "NOTATION "); break;
00473     case SGML_CATA_PUBLIC:
00474         fprintf(out, "PUBLIC "); break;
00475     case SGML_CATA_SYSTEM:
00476         fprintf(out, "SYSTEM "); break;
00477     case SGML_CATA_DELEGATE:
00478         fprintf(out, "DELEGATE "); break;
00479     case SGML_CATA_BASE:
00480         fprintf(out, "BASE "); break;
00481     case SGML_CATA_CATALOG:
00482         fprintf(out, "CATALOG "); break;
00483     case SGML_CATA_DOCUMENT:
00484         fprintf(out, "DOCUMENT "); break;
00485     case SGML_CATA_SGMLDECL:
00486         fprintf(out, "SGMLDECL "); break;
00487     default:
00488         return;
00489     }
00490     switch (entry->type) {
00491     case SGML_CATA_ENTITY:
00492     case SGML_CATA_PENTITY:
00493     case SGML_CATA_DOCTYPE:
00494     case SGML_CATA_LINKTYPE:
00495     case SGML_CATA_NOTATION:
00496         fprintf(out, "%s", (const char *) entry->name); break;
00497     case SGML_CATA_PUBLIC:
00498     case SGML_CATA_SYSTEM:
00499     case SGML_CATA_SGMLDECL:
00500     case SGML_CATA_DOCUMENT:
00501     case SGML_CATA_CATALOG:
00502     case SGML_CATA_BASE:
00503     case SGML_CATA_DELEGATE:
00504         fprintf(out, "\"%s\"", entry->name); break;
00505     default:
00506         break;
00507     }
00508     switch (entry->type) {
00509     case SGML_CATA_ENTITY:
00510     case SGML_CATA_PENTITY:
00511     case SGML_CATA_DOCTYPE:
00512     case SGML_CATA_LINKTYPE:
00513     case SGML_CATA_NOTATION:
00514     case SGML_CATA_PUBLIC:
00515     case SGML_CATA_SYSTEM:
00516     case SGML_CATA_DELEGATE:
00517         fprintf(out, " \"%s\"", entry->value); break;
00518     default:
00519         break;
00520     }
00521     fprintf(out, "\n");
00522 }
00523 
00535 static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
00536             xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
00537     xmlNodePtr node;
00538     xmlCatalogEntryPtr cur;
00539     /*
00540      * add all the catalog entries
00541      */
00542     cur = catal;
00543     while (cur != NULL) {
00544         if (cur->group == cgroup) {
00545         switch (cur->type) {
00546             case XML_CATA_REMOVED:
00547             break;
00548             case XML_CATA_BROKEN_CATALOG:
00549             case XML_CATA_CATALOG:
00550             if (cur == catal) {
00551             cur = cur->children;
00552                 continue;
00553             }
00554             break;
00555         case XML_CATA_NEXT_CATALOG:
00556             node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
00557             xmlSetProp(node, BAD_CAST "catalog", cur->value);
00558             xmlAddChild(catalog, node);
00559                     break;
00560         case XML_CATA_NONE:
00561             break;
00562         case XML_CATA_GROUP:
00563             node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
00564             xmlSetProp(node, BAD_CAST "id", cur->name);
00565             if (cur->value != NULL) {
00566                 xmlNsPtr xns;
00567             xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
00568             if (xns != NULL)
00569                 xmlSetNsProp(node, xns, BAD_CAST "base",
00570                          cur->value);
00571             }
00572             switch (cur->prefer) {
00573             case XML_CATA_PREFER_NONE:
00574                     break;
00575             case XML_CATA_PREFER_PUBLIC:
00576                     xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
00577                 break;
00578             case XML_CATA_PREFER_SYSTEM:
00579                     xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
00580                 break;
00581             }
00582             xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
00583             xmlAddChild(catalog, node);
00584                 break;
00585         case XML_CATA_PUBLIC:
00586             node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
00587             xmlSetProp(node, BAD_CAST "publicId", cur->name);
00588             xmlSetProp(node, BAD_CAST "uri", cur->value);
00589             xmlAddChild(catalog, node);
00590             break;
00591         case XML_CATA_SYSTEM:
00592             node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
00593             xmlSetProp(node, BAD_CAST "systemId", cur->name);
00594             xmlSetProp(node, BAD_CAST "uri", cur->value);
00595             xmlAddChild(catalog, node);
00596             break;
00597         case XML_CATA_REWRITE_SYSTEM:
00598             node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
00599             xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
00600             xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
00601             xmlAddChild(catalog, node);
00602             break;
00603         case XML_CATA_DELEGATE_PUBLIC:
00604             node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
00605             xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
00606             xmlSetProp(node, BAD_CAST "catalog", cur->value);
00607             xmlAddChild(catalog, node);
00608             break;
00609         case XML_CATA_DELEGATE_SYSTEM:
00610             node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
00611             xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
00612             xmlSetProp(node, BAD_CAST "catalog", cur->value);
00613             xmlAddChild(catalog, node);
00614             break;
00615         case XML_CATA_URI:
00616             node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
00617             xmlSetProp(node, BAD_CAST "name", cur->name);
00618             xmlSetProp(node, BAD_CAST "uri", cur->value);
00619             xmlAddChild(catalog, node);
00620             break;
00621         case XML_CATA_REWRITE_URI:
00622             node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
00623             xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
00624             xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
00625             xmlAddChild(catalog, node);
00626             break;
00627         case XML_CATA_DELEGATE_URI:
00628             node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
00629             xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
00630             xmlSetProp(node, BAD_CAST "catalog", cur->value);
00631             xmlAddChild(catalog, node);
00632             break;
00633         case SGML_CATA_SYSTEM:
00634         case SGML_CATA_PUBLIC:
00635         case SGML_CATA_ENTITY:
00636         case SGML_CATA_PENTITY:
00637         case SGML_CATA_DOCTYPE:
00638         case SGML_CATA_LINKTYPE:
00639         case SGML_CATA_NOTATION:
00640         case SGML_CATA_DELEGATE:
00641         case SGML_CATA_BASE:
00642         case SGML_CATA_CATALOG:
00643         case SGML_CATA_DOCUMENT:
00644         case SGML_CATA_SGMLDECL:
00645             break;
00646         }
00647         }
00648     cur = cur->next;
00649     }
00650 }
00651 
00652 static int
00653 xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
00654     int ret;
00655     xmlDocPtr doc;
00656     xmlNsPtr ns;
00657     xmlDtdPtr dtd;
00658     xmlNodePtr catalog;
00659     xmlOutputBufferPtr buf;
00660 
00661     /*
00662      * Rebuild a catalog
00663      */
00664     doc = xmlNewDoc(NULL);
00665     if (doc == NULL)
00666     return(-1);
00667     dtd = xmlNewDtd(doc, BAD_CAST "catalog",
00668            BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
00669 BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
00670 
00671     xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
00672 
00673     ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
00674     if (ns == NULL) {
00675     xmlFreeDoc(doc);
00676     return(-1);
00677     }
00678     catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
00679     if (catalog == NULL) {
00680     xmlFreeNs(ns);
00681     xmlFreeDoc(doc);
00682     return(-1);
00683     }
00684     catalog->nsDef = ns;
00685     xmlAddChild((xmlNodePtr) doc, catalog);
00686 
00687     xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
00688     
00689     /*
00690      * reserialize it
00691      */
00692     buf = xmlOutputBufferCreateFile(out, NULL);
00693     if (buf == NULL) {
00694     xmlFreeDoc(doc);
00695     return(-1);
00696     }
00697     ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
00698 
00699     /*
00700      * Free it
00701      */
00702     xmlFreeDoc(doc);
00703 
00704     return(ret);
00705 }
00706 #endif /* LIBXML_OUTPUT_ENABLED */
00707 
00708 /************************************************************************
00709  *                                  *
00710  *          Converting SGML Catalogs to XML         *
00711  *                                  *
00712  ************************************************************************/
00713 
00721 static void
00722 xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
00723     if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
00724     (catal->xml == NULL))
00725     return;
00726     switch (entry->type) {
00727     case SGML_CATA_ENTITY:
00728         entry->type = XML_CATA_PUBLIC;
00729         break;
00730     case SGML_CATA_PENTITY:
00731         entry->type = XML_CATA_PUBLIC;
00732         break;
00733     case SGML_CATA_DOCTYPE:
00734         entry->type = XML_CATA_PUBLIC;
00735         break;
00736     case SGML_CATA_LINKTYPE:
00737         entry->type = XML_CATA_PUBLIC;
00738         break;
00739     case SGML_CATA_NOTATION:
00740         entry->type = XML_CATA_PUBLIC;
00741         break;
00742     case SGML_CATA_PUBLIC:
00743         entry->type = XML_CATA_PUBLIC;
00744         break;
00745     case SGML_CATA_SYSTEM:
00746         entry->type = XML_CATA_SYSTEM;
00747         break;
00748     case SGML_CATA_DELEGATE:
00749         entry->type = XML_CATA_DELEGATE_PUBLIC;
00750         break;
00751     case SGML_CATA_CATALOG:
00752         entry->type = XML_CATA_CATALOG;
00753         break;
00754     default:
00755         xmlHashRemoveEntry(catal->sgml, entry->name,
00756                        (xmlHashDeallocator) xmlFreeCatalogEntry);
00757         return;
00758     }
00759     /*
00760      * Conversion successful, remove from the SGML catalog
00761      * and add it to the default XML one
00762      */
00763     xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
00764     entry->parent = catal->xml;
00765     entry->next = NULL;
00766     if (catal->xml->children == NULL)
00767     catal->xml->children = entry;
00768     else {
00769     xmlCatalogEntryPtr prev;
00770 
00771     prev = catal->xml->children;
00772     while (prev->next != NULL)
00773         prev = prev->next;
00774     prev->next = entry;
00775     }
00776 }
00777 
00786 int
00787 xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
00788 
00789     if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
00790     return(-1);
00791 
00792     if (xmlDebugCatalogs) {
00793     xmlGenericError(xmlGenericErrorContext,
00794         "Converting SGML catalog to XML\n");
00795     }
00796     xmlHashScan(catal->sgml,
00797         (xmlHashScanner) xmlCatalogConvertEntry,
00798         &catal);
00799     return(0);
00800 }
00801 
00802 /************************************************************************
00803  *                                  *
00804  *          Helper function                 *
00805  *                                  *
00806  ************************************************************************/
00807 
00817 static xmlChar *
00818 xmlCatalogUnWrapURN(const xmlChar *urn) {
00819     xmlChar result[2000];
00820     unsigned int i = 0;
00821 
00822     if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
00823     return(NULL);
00824     urn += sizeof(XML_URN_PUBID) - 1;
00825     
00826     while (*urn != 0) {
00827     if (i > sizeof(result) - 4)
00828         break;
00829     if (*urn == '+') {
00830         result[i++] = ' ';
00831         urn++;
00832     } else if (*urn == ':') {
00833         result[i++] = '/';
00834         result[i++] = '/';
00835         urn++;
00836     } else if (*urn == ';') {
00837         result[i++] = ':';
00838         result[i++] = ':';
00839         urn++;
00840     } else if (*urn == '%') {
00841         if ((urn[1] == '2') && (urn[2] == 'B'))
00842         result[i++] = '+';
00843         else if ((urn[1] == '3') && (urn[2] == 'A'))
00844         result[i++] = ':';
00845         else if ((urn[1] == '2') && (urn[2] == 'F'))
00846         result[i++] = '/';
00847         else if ((urn[1] == '3') && (urn[2] == 'B'))
00848         result[i++] = ';';
00849         else if ((urn[1] == '2') && (urn[2] == '7'))
00850         result[i++] = '\'';
00851         else if ((urn[1] == '3') && (urn[2] == 'F'))
00852         result[i++] = '?';
00853         else if ((urn[1] == '2') && (urn[2] == '3'))
00854         result[i++] = '#';
00855         else if ((urn[1] == '2') && (urn[2] == '5'))
00856         result[i++] = '%';
00857         else {
00858         result[i++] = *urn;
00859         urn++;
00860         continue;
00861         }
00862         urn += 3;
00863     } else {
00864         result[i++] = *urn;
00865         urn++;
00866     }
00867     }
00868     result[i] = 0;
00869 
00870     return(xmlStrdup(result));
00871 }
00872 
00883 xmlDocPtr
00884 xmlParseCatalogFile(const char *filename) {
00885     xmlDocPtr ret;
00886     xmlParserCtxtPtr ctxt;
00887     char *directory = NULL;
00888     xmlParserInputPtr inputStream;
00889     xmlParserInputBufferPtr buf;
00890 
00891     ctxt = xmlNewParserCtxt();
00892     if (ctxt == NULL) {
00893 #ifdef LIBXML_SAX1_ENABLED
00894     if (xmlDefaultSAXHandler.error != NULL) {
00895         xmlDefaultSAXHandler.error(NULL, "out of memory\n");
00896     }
00897 #endif
00898     return(NULL);
00899     }
00900 
00901     buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
00902     if (buf == NULL) {
00903     xmlFreeParserCtxt(ctxt);
00904     return(NULL);
00905     }
00906 
00907     inputStream = xmlNewInputStream(ctxt);
00908     if (inputStream == NULL) {
00909     xmlFreeParserCtxt(ctxt);
00910     return(NULL);
00911     }
00912 
00913     inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
00914     inputStream->buf = buf;
00915     inputStream->base = inputStream->buf->buffer->content;
00916     inputStream->cur = inputStream->buf->buffer->content;
00917     inputStream->end = 
00918     &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
00919 
00920     inputPush(ctxt, inputStream);
00921     if ((ctxt->directory == NULL) && (directory == NULL))
00922         directory = xmlParserGetDirectory(filename);
00923     if ((ctxt->directory == NULL) && (directory != NULL))
00924         ctxt->directory = directory;
00925     ctxt->valid = 0;
00926     ctxt->validate = 0;
00927     ctxt->loadsubset = 0;
00928     ctxt->pedantic = 0;
00929     ctxt->dictNames = 1;
00930 
00931     xmlParseDocument(ctxt);
00932 
00933     if (ctxt->wellFormed)
00934     ret = ctxt->myDoc;
00935     else {
00936         ret = NULL;
00937         xmlFreeDoc(ctxt->myDoc);
00938         ctxt->myDoc = NULL;
00939     }
00940     xmlFreeParserCtxt(ctxt);
00941     
00942     return(ret);
00943 }
00944 
00953 static xmlChar *
00954 xmlLoadFileContent(const char *filename)
00955 {
00956 #ifdef HAVE_STAT
00957     int fd;
00958 #else
00959     FILE *fd;
00960 #endif
00961     int len;
00962     long size;
00963 
00964 #ifdef HAVE_STAT
00965     struct stat info;
00966 #endif
00967     xmlChar *content;
00968 
00969     if (filename == NULL)
00970         return (NULL);
00971 
00972 #ifdef HAVE_STAT
00973     if (stat(filename, &info) < 0)
00974         return (NULL);
00975 #endif
00976 
00977 #ifdef HAVE_STAT
00978     if ((fd = open(filename, O_RDONLY)) < 0)
00979 #else
00980     if ((fd = fopen(filename, "rb")) == NULL)
00981 #endif
00982     {
00983         return (NULL);
00984     }
00985 #ifdef HAVE_STAT
00986     size = info.st_size;
00987 #else
00988     if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) {        /* File operations denied? ok, just close and return failure */
00989         fclose(fd);
00990         return (NULL);
00991     }
00992 #endif
00993     content = xmlMallocAtomic(size + 10);
00994     if (content == NULL) {
00995         xmlCatalogErrMemory("allocating catalog data");
00996         return (NULL);
00997     }
00998 #ifdef HAVE_STAT
00999     len = read(fd, content, size);
01000     close(fd);
01001 #else
01002     len = fread(content, 1, size, fd);
01003     fclose(fd);
01004 #endif
01005     if (len < 0) {
01006         xmlFree(content);
01007         return (NULL);
01008     }
01009     content[len] = 0;
01010 
01011     return(content);
01012 }
01013 
01026 static xmlChar *
01027 xmlCatalogNormalizePublic(const xmlChar *pubID)
01028 {
01029     int ok = 1;
01030     int white;
01031     const xmlChar *p;
01032     xmlChar *ret;
01033     xmlChar *q;
01034 
01035     if (pubID == NULL)
01036         return(NULL);
01037 
01038     white = 1;
01039     for (p = pubID;*p != 0 && ok;p++) {
01040         if (!xmlIsBlank_ch(*p))
01041             white = 0;
01042         else if (*p == 0x20 && !white)
01043             white = 1;
01044         else
01045             ok = 0;
01046     }
01047     if (ok && !white)   /* is normalized */
01048         return(NULL);
01049 
01050     ret = xmlStrdup(pubID);
01051     q = ret;
01052     white = 0;
01053     for (p = pubID;*p != 0;p++) {
01054         if (xmlIsBlank_ch(*p)) {
01055             if (q != ret)
01056                 white = 1;
01057         } else {
01058             if (white) {
01059                 *(q++) = 0x20;
01060                 white = 0;
01061             }
01062             *(q++) = *p;
01063         }
01064     }
01065     *q = 0;
01066     return(ret);
01067 }
01068 
01069 /************************************************************************
01070  *                                  *
01071  *          The XML Catalog parser              *
01072  *                                  *
01073  ************************************************************************/
01074 
01075 static xmlCatalogEntryPtr
01076 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
01077 static void
01078 xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
01079                        xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
01080 static xmlChar *
01081 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
01082                   const xmlChar *sysID);
01083 static xmlChar *
01084 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
01085 
01086 
01095 static xmlCatalogEntryType
01096 xmlGetXMLCatalogEntryType(const xmlChar *name) {
01097     xmlCatalogEntryType type = XML_CATA_NONE;
01098     if (xmlStrEqual(name, (const xmlChar *) "system"))
01099     type = XML_CATA_SYSTEM;
01100     else if (xmlStrEqual(name, (const xmlChar *) "public"))
01101     type = XML_CATA_PUBLIC;
01102     else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
01103     type = XML_CATA_REWRITE_SYSTEM;
01104     else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
01105     type = XML_CATA_DELEGATE_PUBLIC;
01106     else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
01107     type = XML_CATA_DELEGATE_SYSTEM;
01108     else if (xmlStrEqual(name, (const xmlChar *) "uri"))
01109     type = XML_CATA_URI;
01110     else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
01111     type = XML_CATA_REWRITE_URI;
01112     else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
01113     type = XML_CATA_DELEGATE_URI;
01114     else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
01115     type = XML_CATA_NEXT_CATALOG;
01116     else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
01117     type = XML_CATA_CATALOG;
01118     return(type);
01119 }
01120 
01136 static xmlCatalogEntryPtr
01137 xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
01138               const xmlChar *name, const xmlChar *attrName,
01139               const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
01140               xmlCatalogEntryPtr cgroup) {
01141     int ok = 1;
01142     xmlChar *uriValue;
01143     xmlChar *nameValue = NULL;
01144     xmlChar *base = NULL;
01145     xmlChar *URL = NULL;
01146     xmlCatalogEntryPtr ret = NULL;
01147 
01148     if (attrName != NULL) {
01149     nameValue = xmlGetProp(cur, attrName);
01150     if (nameValue == NULL) {
01151         xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
01152               "%s entry lacks '%s'\n", name, attrName, NULL);
01153         ok = 0;
01154     }
01155     }
01156     uriValue = xmlGetProp(cur, uriAttrName);
01157     if (uriValue == NULL) {
01158     xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
01159         "%s entry lacks '%s'\n", name, uriAttrName, NULL);
01160     ok = 0;
01161     }
01162     if (!ok) {
01163     if (nameValue != NULL)
01164         xmlFree(nameValue);
01165     if (uriValue != NULL)
01166         xmlFree(uriValue);
01167     return(NULL);
01168     }
01169 
01170     base = xmlNodeGetBase(cur->doc, cur);
01171     URL = xmlBuildURI(uriValue, base);
01172     if (URL != NULL) {
01173     if (xmlDebugCatalogs > 1) {
01174         if (nameValue != NULL)
01175         xmlGenericError(xmlGenericErrorContext,
01176             "Found %s: '%s' '%s'\n", name, nameValue, URL);
01177         else
01178         xmlGenericError(xmlGenericErrorContext,
01179             "Found %s: '%s'\n", name, URL);
01180     }
01181     ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
01182     } else {
01183     xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
01184         "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
01185     }
01186     if (nameValue != NULL)
01187     xmlFree(nameValue);
01188     if (uriValue != NULL)
01189     xmlFree(uriValue);
01190     if (base != NULL)
01191     xmlFree(base);
01192     if (URL != NULL)
01193     xmlFree(URL);
01194     return(ret);
01195 }
01196 
01208 static void
01209 xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
01210                    xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
01211 {
01212     xmlChar *base = NULL;
01213     xmlCatalogEntryPtr entry = NULL;
01214 
01215     if (cur == NULL)
01216         return;
01217     if (xmlStrEqual(cur->name, BAD_CAST "group")) {
01218         xmlChar *prop;
01219     xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
01220 
01221         prop = xmlGetProp(cur, BAD_CAST "prefer");
01222         if (prop != NULL) {
01223             if (xmlStrEqual(prop, BAD_CAST "system")) {
01224                 prefer = XML_CATA_PREFER_SYSTEM;
01225             } else if (xmlStrEqual(prop, BAD_CAST "public")) {
01226                 prefer = XML_CATA_PREFER_PUBLIC;
01227             } else {
01228         xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
01229                               "Invalid value for prefer: '%s'\n",
01230                   prop, NULL, NULL);
01231             }
01232             xmlFree(prop);
01233         pref = prefer;
01234         }
01235     prop = xmlGetProp(cur, BAD_CAST "id");
01236     base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
01237     entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
01238     xmlFree(prop);
01239     } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
01240     entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
01241         BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
01242     } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
01243     entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
01244         BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
01245     } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
01246     entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
01247         BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
01248         BAD_CAST "rewritePrefix", prefer, cgroup);
01249     } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
01250     entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
01251         BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
01252         BAD_CAST "catalog", prefer, cgroup);
01253     } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
01254     entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
01255         BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
01256         BAD_CAST "catalog", prefer, cgroup);
01257     } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
01258     entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
01259         BAD_CAST "uri", BAD_CAST "name",
01260         BAD_CAST "uri", prefer, cgroup);
01261     } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
01262     entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
01263         BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
01264         BAD_CAST "rewritePrefix", prefer, cgroup);
01265     } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
01266     entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
01267         BAD_CAST "delegateURI", BAD_CAST "uriStartString",
01268         BAD_CAST "catalog", prefer, cgroup);
01269     } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
01270     entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
01271         BAD_CAST "nextCatalog", NULL,
01272         BAD_CAST "catalog", prefer, cgroup);
01273     }
01274     if (entry != NULL) {
01275         if (parent != NULL) {
01276         entry->parent = parent;
01277         if (parent->children == NULL)
01278         parent->children = entry;
01279         else {
01280         xmlCatalogEntryPtr prev;
01281 
01282         prev = parent->children;
01283         while (prev->next != NULL)
01284             prev = prev->next;
01285         prev->next = entry;
01286         }
01287     }
01288     if (entry->type == XML_CATA_GROUP) {
01289         /*
01290          * Recurse to propagate prefer to the subtree
01291          * (xml:base handling is automated)
01292          */
01293             xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
01294     }
01295     }
01296     if (base != NULL)
01297     xmlFree(base);
01298 }
01299 
01311 static void
01312 xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
01313                        xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
01314     while (cur != NULL) {
01315     if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
01316         (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
01317         xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
01318     }
01319     cur = cur->next;
01320     }
01321     /* TODO: sort the list according to REWRITE lengths and prefer value */
01322 }
01323 
01334 static xmlCatalogEntryPtr
01335 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
01336     xmlDocPtr doc;
01337     xmlNodePtr cur;
01338     xmlChar *prop;
01339     xmlCatalogEntryPtr parent = NULL;
01340 
01341     if (filename == NULL)
01342         return(NULL);
01343 
01344     doc = xmlParseCatalogFile((const char *) filename);
01345     if (doc == NULL) {
01346     if (xmlDebugCatalogs)
01347         xmlGenericError(xmlGenericErrorContext,
01348             "Failed to parse catalog %s\n", filename);
01349     return(NULL);
01350     }
01351 
01352     if (xmlDebugCatalogs)
01353     xmlGenericError(xmlGenericErrorContext,
01354         "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
01355 
01356     cur = xmlDocGetRootElement(doc);
01357     if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
01358     (cur->ns != NULL) && (cur->ns->href != NULL) &&
01359     (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
01360 
01361     parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
01362                     (const xmlChar *)filename, NULL, prefer, NULL);
01363         if (parent == NULL) {
01364         xmlFreeDoc(doc);
01365         return(NULL);
01366     }
01367 
01368     prop = xmlGetProp(cur, BAD_CAST "prefer");
01369     if (prop != NULL) {
01370         if (xmlStrEqual(prop, BAD_CAST "system")) {
01371         prefer = XML_CATA_PREFER_SYSTEM;
01372         } else if (xmlStrEqual(prop, BAD_CAST "public")) {
01373         prefer = XML_CATA_PREFER_PUBLIC;
01374         } else {
01375         xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
01376                   "Invalid value for prefer: '%s'\n",
01377                   prop, NULL, NULL);
01378         }
01379         xmlFree(prop);
01380     }
01381     cur = cur->children;
01382     xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
01383     } else {
01384     xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
01385               "File %s is not an XML Catalog\n",
01386               filename, NULL, NULL);
01387     xmlFreeDoc(doc);
01388     return(NULL);
01389     }
01390     xmlFreeDoc(doc);
01391     return(parent);
01392 }
01393 
01402 static int
01403 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
01404     xmlCatalogEntryPtr doc;
01405 
01406     if (catal == NULL) 
01407     return(-1);
01408     if (catal->URL == NULL)
01409     return(-1);
01410     if (catal->children != NULL)
01411     return(-1);
01412 
01413     /*
01414      * lock the whole catalog for modification
01415      */
01416     xmlRMutexLock(xmlCatalogMutex);
01417     if (catal->children != NULL) {
01418     /* Okay someone else did it in the meantime */
01419     xmlRMutexUnlock(xmlCatalogMutex);
01420     return(0);
01421     }
01422 
01423     if (xmlCatalogXMLFiles != NULL) {
01424     doc = (xmlCatalogEntryPtr)
01425         xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
01426     if (doc != NULL) {
01427         if (xmlDebugCatalogs)
01428         xmlGenericError(xmlGenericErrorContext,
01429             "Found %s in file hash\n", catal->URL);
01430 
01431         if (catal->type == XML_CATA_CATALOG)
01432         catal->children = doc->children;
01433         else
01434         catal->children = doc;
01435         catal->dealloc = 0;
01436         xmlRMutexUnlock(xmlCatalogMutex);
01437         return(0);
01438     }
01439     if (xmlDebugCatalogs)
01440         xmlGenericError(xmlGenericErrorContext,
01441         "%s not found in file hash\n", catal->URL);
01442     }
01443 
01444     /*
01445      * Fetch and parse. Note that xmlParseXMLCatalogFile does not
01446      * use the existing catalog, there is no recursion allowed at
01447      * that level.
01448      */
01449     doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
01450     if (doc == NULL) {
01451     catal->type = XML_CATA_BROKEN_CATALOG;
01452     xmlRMutexUnlock(xmlCatalogMutex);
01453     return(-1);
01454     }
01455 
01456     if (catal->type == XML_CATA_CATALOG)
01457     catal->children = doc->children;
01458     else
01459     catal->children = doc;
01460 
01461     doc->dealloc = 1;
01462 
01463     if (xmlCatalogXMLFiles == NULL)
01464     xmlCatalogXMLFiles = xmlHashCreate(10);
01465     if (xmlCatalogXMLFiles != NULL) {
01466     if (xmlDebugCatalogs)
01467         xmlGenericError(xmlGenericErrorContext,
01468         "%s added to file hash\n", catal->URL);
01469     xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
01470     }
01471     xmlRMutexUnlock(xmlCatalogMutex);
01472     return(0);
01473 }
01474 
01475 /************************************************************************
01476  *                                  *
01477  *          XML Catalog handling                *
01478  *                                  *
01479  ************************************************************************/
01480 
01493 static int
01494 xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
01495           const xmlChar *orig, const xmlChar *replace) {
01496     xmlCatalogEntryPtr cur;
01497     xmlCatalogEntryType typ;
01498     int doregister = 0;
01499 
01500     if ((catal == NULL) || 
01501     ((catal->type != XML_CATA_CATALOG) &&
01502      (catal->type != XML_CATA_BROKEN_CATALOG)))
01503     return(-1);
01504     if (catal->children == NULL) {
01505     xmlFetchXMLCatalogFile(catal);
01506     }
01507     if (catal->children == NULL)
01508     doregister = 1;
01509 
01510     typ = xmlGetXMLCatalogEntryType(type);
01511     if (typ == XML_CATA_NONE) {
01512     if (xmlDebugCatalogs)
01513         xmlGenericError(xmlGenericErrorContext,
01514             "Failed to add unknown element %s to catalog\n", type);
01515     return(-1);
01516     }
01517 
01518     cur = catal->children;
01519     /*
01520      * Might be a simple "update in place"
01521      */
01522     if (cur != NULL) {
01523     while (cur != NULL) {
01524         if ((orig != NULL) && (cur->type == typ) &&
01525         (xmlStrEqual(orig, cur->name))) {
01526         if (xmlDebugCatalogs)
01527             xmlGenericError(xmlGenericErrorContext,
01528                 "Updating element %s to catalog\n", type);
01529         if (cur->value != NULL)
01530             xmlFree(cur->value);
01531         if (cur->URL != NULL)
01532             xmlFree(cur->URL);
01533         cur->value = xmlStrdup(replace);
01534         cur->URL = xmlStrdup(replace);
01535         return(0);
01536         }
01537         if (cur->next == NULL)
01538         break;
01539         cur = cur->next;
01540     }
01541     }
01542     if (xmlDebugCatalogs)
01543     xmlGenericError(xmlGenericErrorContext,
01544         "Adding element %s to catalog\n", type);
01545     if (cur == NULL)
01546     catal->children = xmlNewCatalogEntry(typ, orig, replace,
01547                                      NULL, catal->prefer, NULL);
01548     else
01549     cur->next = xmlNewCatalogEntry(typ, orig, replace,
01550                                NULL, catal->prefer, NULL);
01551     if (doregister) {
01552         catal->type = XML_CATA_CATALOG;
01553     cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
01554     if (cur != NULL)
01555         cur->children = catal->children;
01556     }
01557 
01558     return(0);
01559 }
01560 
01571 static int
01572 xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
01573     xmlCatalogEntryPtr cur;
01574     int ret = 0;
01575 
01576     if ((catal == NULL) || 
01577     ((catal->type != XML_CATA_CATALOG) &&
01578      (catal->type != XML_CATA_BROKEN_CATALOG)))
01579     return(-1);
01580     if (value == NULL)
01581     return(-1);
01582     if (catal->children == NULL) {
01583     xmlFetchXMLCatalogFile(catal);
01584     }
01585 
01586     /*
01587      * Scan the children
01588      */
01589     cur = catal->children;
01590     while (cur != NULL) {
01591     if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
01592         (xmlStrEqual(value, cur->value))) {
01593         if (xmlDebugCatalogs) {
01594         if (cur->name != NULL)
01595             xmlGenericError(xmlGenericErrorContext,
01596                 "Removing element %s from catalog\n", cur->name);
01597         else
01598             xmlGenericError(xmlGenericErrorContext,
01599                 "Removing element %s from catalog\n", cur->value);
01600         }
01601         cur->type = XML_CATA_REMOVED;
01602     }
01603     cur = cur->next;
01604     }
01605     return(ret);
01606 }
01607 
01622 static xmlChar *
01623 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
01624                   const xmlChar *sysID) {
01625     xmlChar *ret = NULL;
01626     xmlCatalogEntryPtr cur;
01627     int haveDelegate = 0;
01628     int haveNext = 0;
01629 
01630     /*
01631      * protection against loops
01632      */
01633     if (catal->depth > MAX_CATAL_DEPTH) {
01634     xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
01635               "Detected recursion in catalog %s\n",
01636               catal->name, NULL, NULL);
01637     return(NULL);
01638     }
01639     catal->depth++;
01640 
01641     /*
01642      * First tries steps 2/ 3/ 4/ if a system ID is provided.
01643      */
01644     if (sysID != NULL) {
01645     xmlCatalogEntryPtr rewrite = NULL;
01646     int lenrewrite = 0, len;
01647     cur = catal;
01648     haveDelegate = 0;
01649     while (cur != NULL) {
01650         switch (cur->type) {
01651         case XML_CATA_SYSTEM:
01652             if (xmlStrEqual(sysID, cur->name)) {
01653             if (xmlDebugCatalogs)
01654                 xmlGenericError(xmlGenericErrorContext,
01655                     "Found system match %s, using %s\n",
01656                             cur->name, cur->URL);
01657             catal->depth--;
01658             return(xmlStrdup(cur->URL));
01659             }
01660             break;
01661         case XML_CATA_REWRITE_SYSTEM:
01662             len = xmlStrlen(cur->name);
01663             if ((len > lenrewrite) &&
01664             (!xmlStrncmp(sysID, cur->name, len))) {
01665             lenrewrite = len;
01666             rewrite = cur;
01667             }
01668             break;
01669         case XML_CATA_DELEGATE_SYSTEM:
01670             if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
01671             haveDelegate++;
01672             break;
01673         case XML_CATA_NEXT_CATALOG:
01674             haveNext++;
01675             break;
01676         default:
01677             break;
01678         }
01679         cur = cur->next;
01680     }
01681     if (rewrite != NULL) {
01682         if (xmlDebugCatalogs)
01683         xmlGenericError(xmlGenericErrorContext,
01684             "Using rewriting rule %s\n", rewrite->name);
01685         ret = xmlStrdup(rewrite->URL);
01686         if (ret != NULL)
01687         ret = xmlStrcat(ret, &sysID[lenrewrite]);
01688         catal->depth--;
01689         return(ret);
01690     }
01691     if (haveDelegate) {
01692         const xmlChar *delegates[MAX_DELEGATE];
01693         int nbList = 0, i;
01694 
01695         /*
01696          * Assume the entries have been sorted by decreasing substring
01697          * matches when the list was produced.
01698          */
01699         cur = catal;
01700         while (cur != NULL) {
01701         if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
01702             (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
01703             for (i = 0;i < nbList;i++)
01704             if (xmlStrEqual(cur->URL, delegates[i]))
01705                 break;
01706             if (i < nbList) {
01707             cur = cur->next;
01708             continue;
01709             }
01710             if (nbList < MAX_DELEGATE)
01711             delegates[nbList++] = cur->URL;
01712 
01713             if (cur->children == NULL) {
01714             xmlFetchXMLCatalogFile(cur);
01715             }
01716             if (cur->children != NULL) {
01717             if (xmlDebugCatalogs)
01718                 xmlGenericError(xmlGenericErrorContext,
01719                     "Trying system delegate %s\n", cur->URL);
01720             ret = xmlCatalogListXMLResolve(
01721                 cur->children, NULL, sysID);
01722             if (ret != NULL) {
01723                 catal->depth--;
01724                 return(ret);
01725             }
01726             }
01727         }
01728         cur = cur->next;
01729         }
01730         /*
01731          * Apply the cut algorithm explained in 4/
01732          */
01733         catal->depth--;
01734         return(XML_CATAL_BREAK);
01735     }
01736     }
01737     /*
01738      * Then tries 5/ 6/ if a public ID is provided
01739      */
01740     if (pubID != NULL) {
01741     cur = catal;
01742     haveDelegate = 0;
01743     while (cur != NULL) {
01744         switch (cur->type) {
01745         case XML_CATA_PUBLIC:
01746             if (xmlStrEqual(pubID, cur->name)) {
01747             if (xmlDebugCatalogs)
01748                 xmlGenericError(xmlGenericErrorContext,
01749                     "Found public match %s\n", cur->name);
01750             catal->depth--;
01751             return(xmlStrdup(cur->URL));
01752             }
01753             break;
01754         case XML_CATA_DELEGATE_PUBLIC:
01755             if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
01756             (cur->prefer == XML_CATA_PREFER_PUBLIC))
01757             haveDelegate++;
01758             break;
01759         case XML_CATA_NEXT_CATALOG:
01760             if (sysID == NULL)
01761             haveNext++;
01762             break;
01763         default:
01764             break;
01765         }
01766         cur = cur->next;
01767     }
01768     if (haveDelegate) {
01769         const xmlChar *delegates[MAX_DELEGATE];
01770         int nbList = 0, i;
01771 
01772         /*
01773          * Assume the entries have been sorted by decreasing substring
01774          * matches when the list was produced.
01775          */
01776         cur = catal;
01777         while (cur != NULL) {
01778         if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
01779             (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
01780             (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
01781 
01782             for (i = 0;i < nbList;i++)
01783             if (xmlStrEqual(cur->URL, delegates[i]))
01784                 break;
01785             if (i < nbList) {
01786             cur = cur->next;
01787             continue;
01788             }
01789             if (nbList < MAX_DELEGATE)
01790             delegates[nbList++] = cur->URL;
01791                 
01792             if (cur->children == NULL) {
01793             xmlFetchXMLCatalogFile(cur);
01794             }
01795             if (cur->children != NULL) {
01796             if (xmlDebugCatalogs)
01797                 xmlGenericError(xmlGenericErrorContext,
01798                     "Trying public delegate %s\n", cur->URL);
01799             ret = xmlCatalogListXMLResolve(
01800                 cur->children, pubID, NULL);
01801             if (ret != NULL) {
01802                 catal->depth--;
01803                 return(ret);
01804             }
01805             }
01806         }
01807         cur = cur->next;
01808         }
01809         /*
01810          * Apply the cut algorithm explained in 4/
01811          */
01812         catal->depth--;
01813         return(XML_CATAL_BREAK);
01814     }
01815     }
01816     if (haveNext) {
01817     cur = catal;
01818     while (cur != NULL) {
01819         if (cur->type == XML_CATA_NEXT_CATALOG) {
01820         if (cur->children == NULL) {
01821             xmlFetchXMLCatalogFile(cur);
01822         }
01823         if (cur->children != NULL) {
01824             ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
01825             if (ret != NULL) {
01826             catal->depth--;
01827             return(ret);
01828             } else if (catal->depth > MAX_CATAL_DEPTH) {
01829                 return(NULL);
01830             }
01831         }
01832         }
01833         cur = cur->next;
01834     }
01835     }
01836 
01837     catal->depth--;
01838     return(NULL);
01839 }
01840 
01855 static xmlChar *
01856 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
01857     xmlChar *ret = NULL;
01858     xmlCatalogEntryPtr cur;
01859     int haveDelegate = 0;
01860     int haveNext = 0;
01861     xmlCatalogEntryPtr rewrite = NULL;
01862     int lenrewrite = 0, len;
01863 
01864     if (catal == NULL)
01865     return(NULL);
01866 
01867     if (URI == NULL)
01868     return(NULL);
01869 
01870     if (catal->depth > MAX_CATAL_DEPTH) {
01871     xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
01872               "Detected recursion in catalog %s\n",
01873               catal->name, NULL, NULL);
01874     return(NULL);
01875     }
01876 
01877     /*
01878      * First tries steps 2/ 3/ 4/ if a system ID is provided.
01879      */
01880     cur = catal;
01881     haveDelegate = 0;
01882     while (cur != NULL) {
01883     switch (cur->type) {
01884         case XML_CATA_URI:
01885         if (xmlStrEqual(URI, cur->name)) {
01886             if (xmlDebugCatalogs)
01887             xmlGenericError(xmlGenericErrorContext,
01888                 "Found URI match %s\n", cur->name);
01889             return(xmlStrdup(cur->URL));
01890         }
01891         break;
01892         case XML_CATA_REWRITE_URI:
01893         len = xmlStrlen(cur->name);
01894         if ((len > lenrewrite) &&
01895             (!xmlStrncmp(URI, cur->name, len))) {
01896             lenrewrite = len;
01897             rewrite = cur;
01898         }
01899         break;
01900         case XML_CATA_DELEGATE_URI:
01901         if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
01902             haveDelegate++;
01903         break;
01904         case XML_CATA_NEXT_CATALOG:
01905         haveNext++;
01906         break;
01907         default:
01908         break;
01909     }
01910     cur = cur->next;
01911     }
01912     if (rewrite != NULL) {
01913     if (xmlDebugCatalogs)
01914         xmlGenericError(xmlGenericErrorContext,
01915             "Using rewriting rule %s\n", rewrite->name);
01916     ret = xmlStrdup(rewrite->URL);
01917     if (ret != NULL)
01918         ret = xmlStrcat(ret, &URI[lenrewrite]);
01919     return(ret);
01920     }
01921     if (haveDelegate) {
01922     const xmlChar *delegates[MAX_DELEGATE];
01923     int nbList = 0, i;
01924 
01925     /*
01926      * Assume the entries have been sorted by decreasing substring
01927      * matches when the list was produced.
01928      */
01929     cur = catal;
01930     while (cur != NULL) {
01931         if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
01932              (cur->type == XML_CATA_DELEGATE_URI)) &&
01933         (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
01934         for (i = 0;i < nbList;i++)
01935             if (xmlStrEqual(cur->URL, delegates[i]))
01936             break;
01937         if (i < nbList) {
01938             cur = cur->next;
01939             continue;
01940         }
01941         if (nbList < MAX_DELEGATE)
01942             delegates[nbList++] = cur->URL;
01943 
01944         if (cur->children == NULL) {
01945             xmlFetchXMLCatalogFile(cur);
01946         }
01947         if (cur->children != NULL) {
01948             if (xmlDebugCatalogs)
01949             xmlGenericError(xmlGenericErrorContext,
01950                 "Trying URI delegate %s\n", cur->URL);
01951             ret = xmlCatalogListXMLResolveURI(
01952                 cur->children, URI);
01953             if (ret != NULL)
01954             return(ret);
01955         }
01956         }
01957         cur = cur->next;
01958     }
01959     /*
01960      * Apply the cut algorithm explained in 4/
01961      */
01962     return(XML_CATAL_BREAK);
01963     }
01964     if (haveNext) {
01965     cur = catal;
01966     while (cur != NULL) {
01967         if (cur->type == XML_CATA_NEXT_CATALOG) {
01968         if (cur->children == NULL) {
01969             xmlFetchXMLCatalogFile(cur);
01970         }
01971         if (cur->children != NULL) {
01972             ret = xmlCatalogListXMLResolveURI(cur->children, URI);
01973             if (ret != NULL)
01974             return(ret);
01975         }
01976         }
01977         cur = cur->next;
01978     }
01979     }
01980 
01981     return(NULL);
01982 }
01983 
01998 static xmlChar *
01999 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
02000                   const xmlChar *sysID) {
02001     xmlChar *ret = NULL;
02002     xmlChar *urnID = NULL;
02003     xmlChar *normid;
02004     
02005     if (catal == NULL)
02006         return(NULL);
02007     if ((pubID == NULL) && (sysID == NULL))
02008     return(NULL);
02009 
02010     normid = xmlCatalogNormalizePublic(pubID);
02011     if (normid != NULL)
02012         pubID = (*normid != 0 ? normid : NULL);
02013     
02014     if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
02015     urnID = xmlCatalogUnWrapURN(pubID);
02016     if (xmlDebugCatalogs) {
02017         if (urnID == NULL)
02018         xmlGenericError(xmlGenericErrorContext,
02019             "Public URN ID %s expanded to NULL\n", pubID);
02020         else
02021         xmlGenericError(xmlGenericErrorContext,
02022             "Public URN ID expanded to %s\n", urnID);
02023     }
02024     ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
02025     if (urnID != NULL)
02026         xmlFree(urnID);
02027     if (normid != NULL)
02028         xmlFree(normid);
02029     return(ret);
02030     }
02031     if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
02032     urnID = xmlCatalogUnWrapURN(sysID);
02033     if (xmlDebugCatalogs) {
02034         if (urnID == NULL)
02035         xmlGenericError(xmlGenericErrorContext,
02036             "System URN ID %s expanded to NULL\n", sysID);
02037         else
02038         xmlGenericError(xmlGenericErrorContext,
02039             "System URN ID expanded to %s\n", urnID);
02040     }
02041     if (pubID == NULL)
02042         ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
02043     else if (xmlStrEqual(pubID, urnID))
02044         ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
02045     else {
02046         ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
02047     }
02048     if (urnID != NULL)
02049         xmlFree(urnID);
02050     if (normid != NULL)
02051         xmlFree(normid);
02052     return(ret);
02053     }
02054     while (catal != NULL) {
02055     if (catal->type == XML_CATA_CATALOG) {
02056         if (catal->children == NULL) {
02057         xmlFetchXMLCatalogFile(catal);
02058         }
02059         if (catal->children != NULL) {
02060         ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
02061         if (ret != NULL) {
02062             break;
02063                 } else if ((catal->children != NULL) &&
02064                    (catal->children->depth > MAX_CATAL_DEPTH)) {
02065                 ret = NULL;
02066             break;
02067             }
02068         }
02069     }
02070     catal = catal->next;
02071     }
02072     if (normid != NULL)
02073     xmlFree(normid);
02074     return(ret);
02075 }
02076 
02089 static xmlChar *
02090 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
02091     xmlChar *ret = NULL;
02092     xmlChar *urnID = NULL;
02093     
02094     if (catal == NULL)
02095         return(NULL);
02096     if (URI == NULL)
02097     return(NULL);
02098 
02099     if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
02100     urnID = xmlCatalogUnWrapURN(URI);
02101     if (xmlDebugCatalogs) {
02102         if (urnID == NULL)
02103         xmlGenericError(xmlGenericErrorContext,
02104             "URN ID %s expanded to NULL\n", URI);
02105         else
02106         xmlGenericError(xmlGenericErrorContext,
02107             "URN ID expanded to %s\n", urnID);
02108     }
02109     ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
02110     if (urnID != NULL)
02111         xmlFree(urnID);
02112     return(ret);
02113     }
02114     while (catal != NULL) {
02115     if (catal->type == XML_CATA_CATALOG) {
02116         if (catal->children == NULL) {
02117         xmlFetchXMLCatalogFile(catal);
02118         }
02119         if (catal->children != NULL) {
02120         ret = xmlCatalogXMLResolveURI(catal->children, URI);
02121         if (ret != NULL)
02122             return(ret);
02123         }
02124     }
02125     catal = catal->next;
02126     }
02127     return(ret);
02128 }
02129 
02130 /************************************************************************
02131  *                                  *
02132  *          The SGML Catalog parser             *
02133  *                                  *
02134  ************************************************************************/
02135 
02136 
02137 #define RAW *cur
02138 #define NEXT cur++;
02139 #define SKIP(x) cur += x;
02140 
02141 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
02142 
02151 static const xmlChar *
02152 xmlParseSGMLCatalogComment(const xmlChar *cur) {
02153     if ((cur[0] != '-') || (cur[1] != '-')) 
02154     return(cur);
02155     SKIP(2);
02156     while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
02157     NEXT;
02158     if (cur[0] == 0) {
02159     return(NULL);
02160     }
02161     return(cur + 2);
02162 }
02163 
02173 static const xmlChar *
02174 xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
02175     xmlChar *buf = NULL, *tmp;
02176     int len = 0;
02177     int size = 50;
02178     xmlChar stop;
02179     int count = 0;
02180 
02181     *id = NULL;
02182 
02183     if (RAW == '"') {
02184         NEXT;
02185     stop = '"';
02186     } else if (RAW == '\'') {
02187         NEXT;
02188     stop = '\'';
02189     } else {
02190     stop = ' ';
02191     }
02192     buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
02193     if (buf == NULL) {
02194         xmlCatalogErrMemory("allocating public ID");
02195     return(NULL);
02196     }
02197     while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
02198     if ((*cur == stop) && (stop != ' '))
02199         break;
02200     if ((stop == ' ') && (IS_BLANK_CH(*cur)))
02201         break;
02202     if (len + 1 >= size) {
02203         size *= 2;
02204         tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
02205         if (tmp == NULL) {
02206         xmlCatalogErrMemory("allocating public ID");
02207         xmlFree(buf);
02208         return(NULL);
02209         }
02210         buf = tmp;
02211     }
02212     buf[len++] = *cur;
02213     count++;
02214     NEXT;
02215     }
02216     buf[len] = 0;
02217     if (stop == ' ') {
02218     if (!IS_BLANK_CH(*cur)) {
02219         xmlFree(buf);
02220         return(NULL);
02221     }
02222     } else {
02223     if (*cur != stop) {
02224         xmlFree(buf);
02225         return(NULL);
02226     }
02227     NEXT;
02228     }
02229     *id = buf;
02230     return(cur);
02231 }
02232 
02242 static const xmlChar *
02243 xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
02244     xmlChar buf[XML_MAX_NAMELEN + 5];
02245     int len = 0;
02246     int c;
02247 
02248     *name = NULL;
02249 
02250     /*
02251      * Handler for more complex cases
02252      */
02253     c = *cur;
02254     if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
02255     return(NULL);
02256     }
02257 
02258     while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
02259             (c == '.') || (c == '-') ||
02260         (c == '_') || (c == ':'))) {
02261     buf[len++] = c;
02262     cur++;
02263     c = *cur;
02264     if (len >= XML_MAX_NAMELEN)
02265         return(NULL);
02266     }
02267     *name = xmlStrndup(buf, len);
02268     return(cur);
02269 }
02270 
02279 static xmlCatalogEntryType
02280 xmlGetSGMLCatalogEntryType(const xmlChar *name) {
02281     xmlCatalogEntryType type = XML_CATA_NONE;
02282     if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
02283     type = SGML_CATA_SYSTEM;
02284     else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
02285     type = SGML_CATA_PUBLIC;
02286     else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
02287     type = SGML_CATA_DELEGATE;
02288     else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
02289     type = SGML_CATA_ENTITY;
02290     else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
02291     type = SGML_CATA_DOCTYPE;
02292     else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
02293     type = SGML_CATA_LINKTYPE;
02294     else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
02295     type = SGML_CATA_NOTATION;
02296     else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
02297     type = SGML_CATA_SGMLDECL;
02298     else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
02299     type = SGML_CATA_DOCUMENT;
02300     else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
02301     type = SGML_CATA_CATALOG;
02302     else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
02303     type = SGML_CATA_BASE;
02304     return(type);
02305 }
02306 
02320 static int
02321 xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
02322                 const char *file, int super) {
02323     const xmlChar *cur = value;
02324     xmlChar *base = NULL;
02325     int res;
02326 
02327     if ((cur == NULL) || (file == NULL))
02328         return(-1);
02329     base = xmlStrdup((const xmlChar *) file);
02330 
02331     while ((cur != NULL) && (cur[0] != 0)) {
02332     SKIP_BLANKS;
02333     if (cur[0] == 0)
02334         break;
02335     if ((cur[0] == '-') && (cur[1] == '-')) {
02336         cur = xmlParseSGMLCatalogComment(cur);
02337         if (cur == NULL) {
02338         /* error */
02339         break;
02340         }
02341     } else {
02342         xmlChar *sysid = NULL;
02343         xmlChar *name = NULL;
02344         xmlCatalogEntryType type = XML_CATA_NONE;
02345 
02346         cur = xmlParseSGMLCatalogName(cur, &name);
02347         if (name == NULL) {
02348         /* error */
02349         break;
02350         }
02351         if (!IS_BLANK_CH(*cur)) {
02352         /* error */
02353         break;
02354         }
02355         SKIP_BLANKS;
02356         if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
02357                 type = SGML_CATA_SYSTEM;
02358         else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
02359                 type = SGML_CATA_PUBLIC;
02360         else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
02361                 type = SGML_CATA_DELEGATE;
02362         else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
02363                 type = SGML_CATA_ENTITY;
02364         else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
02365                 type = SGML_CATA_DOCTYPE;
02366         else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
02367                 type = SGML_CATA_LINKTYPE;
02368         else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
02369                 type = SGML_CATA_NOTATION;
02370         else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
02371                 type = SGML_CATA_SGMLDECL;
02372         else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
02373                 type = SGML_CATA_DOCUMENT;
02374         else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
02375                 type = SGML_CATA_CATALOG;
02376         else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
02377                 type = SGML_CATA_BASE;
02378         else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
02379         xmlFree(name);
02380         cur = xmlParseSGMLCatalogName(cur, &name);
02381         if (name == NULL) {
02382             /* error */
02383             break;
02384         }
02385         xmlFree(name);
02386         continue;
02387         }
02388         xmlFree(name);
02389         name = NULL;
02390 
02391         switch(type) {
02392         case SGML_CATA_ENTITY:
02393             if (*cur == '%')
02394             type = SGML_CATA_PENTITY;
02395         case SGML_CATA_PENTITY:
02396         case SGML_CATA_DOCTYPE:
02397         case SGML_CATA_LINKTYPE:
02398         case SGML_CATA_NOTATION:
02399             cur = xmlParseSGMLCatalogName(cur, &name);
02400             if (cur == NULL) {
02401             /* error */
02402             break;
02403             }
02404             if (!IS_BLANK_CH(*cur)) {
02405             /* error */
02406             break;
02407             }
02408             SKIP_BLANKS;
02409             cur = xmlParseSGMLCatalogPubid(cur, &sysid);
02410             if (cur == NULL) {
02411             /* error */
02412             break;
02413             }
02414             break;
02415         case SGML_CATA_PUBLIC:
02416         case SGML_CATA_SYSTEM:
02417         case SGML_CATA_DELEGATE:
02418             cur = xmlParseSGMLCatalogPubid(cur, &name);
02419             if (cur == NULL) {
02420             /* error */
02421             break;
02422             }
02423             if (type != SGML_CATA_SYSTEM) {
02424                 xmlChar *normid;
02425 
02426                 normid = xmlCatalogNormalizePublic(name);
02427                 if (normid != NULL) {
02428                     if (name != NULL)
02429                         xmlFree(name);
02430                     if (*normid != 0)
02431                         name = normid;
02432                     else {
02433                         xmlFree(normid);
02434                         name = NULL;
02435                     }
02436                 }
02437             }
02438             if (!IS_BLANK_CH(*cur)) {
02439             /* error */
02440             break;
02441             }
02442             SKIP_BLANKS;
02443             cur = xmlParseSGMLCatalogPubid(cur, &sysid);
02444             if (cur == NULL) {
02445             /* error */
02446             break;
02447             }
02448             break;
02449         case SGML_CATA_BASE:
02450         case SGML_CATA_CATALOG:
02451         case SGML_CATA_DOCUMENT:
02452         case SGML_CATA_SGMLDECL:
02453             cur = xmlParseSGMLCatalogPubid(cur, &sysid);
02454             if (cur == NULL) {
02455             /* error */
02456             break;
02457             }
02458             break;
02459         default:
02460             break;
02461         }
02462         if (cur == NULL) {
02463         if (name != NULL)
02464             xmlFree(name);
02465         if (sysid != NULL)
02466             xmlFree(sysid);
02467         break;
02468         } else if (type == SGML_CATA_BASE) {
02469         if (base != NULL)
02470             xmlFree(base);
02471         base = xmlStrdup(sysid);
02472         } else if ((type == SGML_CATA_PUBLIC) ||
02473                (type == SGML_CATA_SYSTEM)) {
02474         xmlChar *filename;
02475 
02476         filename = xmlBuildURI(sysid, base);
02477         if (filename != NULL) {
02478             xmlCatalogEntryPtr entry;
02479 
02480             entry = xmlNewCatalogEntry(type, name, filename,
02481                                    NULL, XML_CATA_PREFER_NONE, NULL);
02482             res = xmlHashAddEntry(catal->sgml, name, entry);
02483             if (res < 0) {
02484             xmlFreeCatalogEntry(entry);
02485             }
02486             xmlFree(filename);
02487         }
02488 
02489         } else if (type == SGML_CATA_CATALOG) {
02490         if (super) {
02491             xmlCatalogEntryPtr entry;
02492 
02493             entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
02494                                    XML_CATA_PREFER_NONE, NULL);
02495             res = xmlHashAddEntry(catal->sgml, sysid, entry);
02496             if (res < 0) {
02497             xmlFreeCatalogEntry(entry);
02498             }
02499         } else {
02500             xmlChar *filename;
02501 
02502             filename = xmlBuildURI(sysid, base);
02503             if (filename != NULL) {
02504             xmlExpandCatalog(catal, (const char *)filename);
02505             xmlFree(filename);
02506             }
02507         }
02508         }
02509         /*
02510          * drop anything else we won't handle it
02511          */
02512         if (name != NULL)
02513         xmlFree(name);
02514         if (sysid != NULL)
02515         xmlFree(sysid);
02516     }
02517     }
02518     if (base != NULL)
02519     xmlFree(base);
02520     if (cur == NULL)
02521     return(-1);
02522     return(0);
02523 }
02524 
02525 /************************************************************************
02526  *                                  *
02527  *          SGML Catalog handling               *
02528  *                                  *
02529  ************************************************************************/
02530 
02540 static const xmlChar *
02541 xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
02542     xmlCatalogEntryPtr entry;
02543     xmlChar *normid;
02544 
02545     if (catal == NULL)
02546     return(NULL);
02547 
02548     normid = xmlCatalogNormalizePublic(pubID);
02549     if (normid != NULL)
02550         pubID = (*normid != 0 ? normid : NULL);
02551 
02552     entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
02553     if (entry == NULL) {
02554     if (normid != NULL)
02555         xmlFree(normid);
02556     return(NULL);
02557     }
02558     if (entry->type == SGML_CATA_PUBLIC) {
02559     if (normid != NULL)
02560         xmlFree(normid);
02561     return(entry->URL);
02562     }
02563     if (normid != NULL)
02564         xmlFree(normid);
02565     return(NULL);
02566 }
02567 
02577 static const xmlChar *
02578 xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
02579     xmlCatalogEntryPtr entry;
02580 
02581     if (catal == NULL)
02582     return(NULL);
02583 
02584     entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
02585     if (entry == NULL)
02586     return(NULL);
02587     if (entry->type == SGML_CATA_SYSTEM)
02588     return(entry->URL);
02589     return(NULL);
02590 }
02591 
02602 static const xmlChar *
02603 xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
02604                   const xmlChar *sysID) {
02605     const xmlChar *ret = NULL;
02606 
02607     if (catal->sgml == NULL)
02608     return(NULL);
02609 
02610     if (pubID != NULL)
02611     ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
02612     if (ret != NULL)
02613     return(ret);
02614     if (sysID != NULL)
02615     ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
02616     if (ret != NULL)
02617     return(ret);
02618     return(NULL);
02619 }
02620 
02621 /************************************************************************
02622  *                                  *
02623  *          Specific Public interfaces          *
02624  *                                  *
02625  ************************************************************************/
02626 
02637 xmlCatalogPtr
02638 xmlLoadSGMLSuperCatalog(const char *filename)
02639 {
02640     xmlChar *content;
02641     xmlCatalogPtr catal;
02642     int ret;
02643 
02644     content = xmlLoadFileContent(filename);
02645     if (content == NULL)
02646         return(NULL);
02647 
02648     catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
02649     if (catal == NULL) {
02650     xmlFree(content);
02651     return(NULL);
02652     }
02653 
02654     ret = xmlParseSGMLCatalog(catal, content, filename, 1);
02655     xmlFree(content);
02656     if (ret < 0) {
02657     xmlFreeCatalog(catal);
02658     return(NULL);
02659     }
02660     return (catal);
02661 }
02662 
02674 xmlCatalogPtr
02675 xmlLoadACatalog(const char *filename)
02676 {
02677     xmlChar *content;
02678     xmlChar *first;
02679     xmlCatalogPtr catal;
02680     int ret;
02681 
02682     content = xmlLoadFileContent(filename);
02683     if (content == NULL)
02684         return(NULL);
02685 
02686 
02687     first = content;
02688    
02689     while ((*first != 0) && (*first != '-') && (*first != '<') &&
02690        (!(((*first >= 'A') && (*first <= 'Z')) ||
02691           ((*first >= 'a') && (*first <= 'z')))))
02692     first++;
02693 
02694     if (*first != '<') {
02695     catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
02696     if (catal == NULL) {
02697         xmlFree(content);
02698         return(NULL);
02699     }
02700         ret = xmlParseSGMLCatalog(catal, content, filename, 0);
02701     if (ret < 0) {
02702         xmlFreeCatalog(catal);
02703         xmlFree(content);
02704         return(NULL);
02705     }
02706     } else {
02707     catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
02708     if (catal == NULL) {
02709         xmlFree(content);
02710         return(NULL);
02711     }
02712         catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
02713                NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
02714     }
02715     xmlFree(content);
02716     return (catal);
02717 }
02718 
02729 static int
02730 xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
02731 {
02732     int ret;
02733 
02734     if ((catal == NULL) || (filename == NULL))
02735     return(-1);
02736 
02737 
02738     if (catal->type == XML_SGML_CATALOG_TYPE) {
02739     xmlChar *content;
02740 
02741     content = xmlLoadFileContent(filename);
02742     if (content == NULL)
02743         return(-1);
02744 
02745         ret = xmlParseSGMLCatalog(catal, content, filename, 0);
02746     if (ret < 0) {
02747         xmlFree(content);
02748         return(-1);
02749     }
02750     xmlFree(content);
02751     } else {
02752     xmlCatalogEntryPtr tmp, cur;
02753     tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
02754                NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
02755 
02756     cur = catal->xml;
02757     if (cur == NULL) {
02758         catal->xml = tmp;
02759     } else {
02760         while (cur->next != NULL) cur = cur->next;
02761         cur->next = tmp;
02762     }
02763     }
02764     return (0);
02765 }
02766 
02777 xmlChar *
02778 xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
02779     xmlChar *ret = NULL;
02780 
02781     if ((sysID == NULL) || (catal == NULL))
02782     return(NULL);
02783     
02784     if (xmlDebugCatalogs)
02785     xmlGenericError(xmlGenericErrorContext,
02786         "Resolve sysID %s\n", sysID);
02787 
02788     if (catal->type == XML_XML_CATALOG_TYPE) {
02789     ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
02790     if (ret == XML_CATAL_BREAK)
02791         ret = NULL;
02792     } else {
02793     const xmlChar *sgml;
02794 
02795     sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
02796     if (sgml != NULL)
02797         ret = xmlStrdup(sgml);
02798     }
02799     return(ret);
02800 }
02801 
02812 xmlChar *
02813 xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
02814     xmlChar *ret = NULL;
02815 
02816     if ((pubID == NULL) || (catal == NULL))
02817     return(NULL);
02818     
02819     if (xmlDebugCatalogs)
02820     xmlGenericError(xmlGenericErrorContext,
02821         "Resolve pubID %s\n", pubID);
02822 
02823     if (catal->type == XML_XML_CATALOG_TYPE) {
02824     ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
02825     if (ret == XML_CATAL_BREAK)
02826         ret = NULL;
02827     } else {
02828     const xmlChar *sgml;
02829 
02830     sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
02831     if (sgml != NULL)
02832         ret = xmlStrdup(sgml);
02833     }
02834     return(ret);
02835 }
02836 
02848 xmlChar *
02849 xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
02850                    const xmlChar * sysID)
02851 {
02852     xmlChar *ret = NULL;
02853 
02854     if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
02855         return (NULL);
02856 
02857     if (xmlDebugCatalogs) {
02858          if ((pubID != NULL) && (sysID != NULL)) {
02859              xmlGenericError(xmlGenericErrorContext,
02860                              "Resolve: pubID %s sysID %s\n", pubID, sysID);
02861          } else if (pubID != NULL) {
02862              xmlGenericError(xmlGenericErrorContext,
02863                              "Resolve: pubID %s\n", pubID);
02864          } else {
02865              xmlGenericError(xmlGenericErrorContext,
02866                              "Resolve: sysID %s\n", sysID);
02867          }
02868     }
02869 
02870     if (catal->type == XML_XML_CATALOG_TYPE) {
02871         ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
02872     if (ret == XML_CATAL_BREAK)
02873         ret = NULL;
02874     } else {
02875         const xmlChar *sgml;
02876 
02877         sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
02878         if (sgml != NULL)
02879             ret = xmlStrdup(sgml);
02880     }
02881     return (ret);
02882 }
02883 
02894 xmlChar *
02895 xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
02896     xmlChar *ret = NULL;
02897 
02898     if ((URI == NULL) || (catal == NULL))
02899     return(NULL);
02900 
02901     if (xmlDebugCatalogs)
02902     xmlGenericError(xmlGenericErrorContext,
02903         "Resolve URI %s\n", URI);
02904 
02905     if (catal->type == XML_XML_CATALOG_TYPE) {
02906     ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
02907     if (ret == XML_CATAL_BREAK)
02908         ret = NULL;
02909     } else {
02910     const xmlChar *sgml;
02911 
02912     sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
02913     if (sgml != NULL)
02914             ret = xmlStrdup(sgml);
02915     }
02916     return(ret);
02917 }
02918 
02919 #ifdef LIBXML_OUTPUT_ENABLED
02920 
02927 void
02928 xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
02929     if ((out == NULL) || (catal == NULL))
02930     return;
02931 
02932     if (catal->type == XML_XML_CATALOG_TYPE) {
02933     xmlDumpXMLCatalog(out, catal->xml);
02934     } else {
02935     xmlHashScan(catal->sgml,
02936             (xmlHashScanner) xmlCatalogDumpEntry, out);
02937     } 
02938 }
02939 #endif /* LIBXML_OUTPUT_ENABLED */
02940 
02953 int
02954 xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
02955               const xmlChar * orig, const xmlChar * replace)
02956 {
02957     int res = -1;
02958 
02959     if (catal == NULL)
02960     return(-1);
02961 
02962     if (catal->type == XML_XML_CATALOG_TYPE) {
02963         res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
02964     } else {
02965         xmlCatalogEntryType cattype;
02966 
02967         cattype = xmlGetSGMLCatalogEntryType(type);
02968         if (cattype != XML_CATA_NONE) {
02969             xmlCatalogEntryPtr entry;
02970 
02971             entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
02972                                        XML_CATA_PREFER_NONE, NULL);
02973         if (catal->sgml == NULL)
02974         catal->sgml = xmlHashCreate(10);
02975             res = xmlHashAddEntry(catal->sgml, orig, entry);
02976         }
02977     }
02978     return (res);
02979 }
02980 
02990 int
02991 xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
02992     int res = -1;
02993 
02994     if ((catal == NULL) || (value == NULL))
02995     return(-1);
02996 
02997     if (catal->type == XML_XML_CATALOG_TYPE) {
02998     res = xmlDelXMLCatalog(catal->xml, value);
02999     } else {
03000     res = xmlHashRemoveEntry(catal->sgml, value,
03001         (xmlHashDeallocator) xmlFreeCatalogEntry);
03002     if (res == 0)
03003         res = 1;
03004     } 
03005     return(res);
03006 }
03007 
03016 xmlCatalogPtr
03017 xmlNewCatalog(int sgml) {
03018     xmlCatalogPtr catal = NULL;
03019 
03020     if (sgml) {
03021     catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
03022                             xmlCatalogDefaultPrefer);
03023         if ((catal != NULL) && (catal->sgml == NULL))
03024         catal->sgml = xmlHashCreate(10);
03025     } else
03026     catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
03027                             xmlCatalogDefaultPrefer);
03028     return(catal);
03029 }
03030 
03039 int
03040 xmlCatalogIsEmpty(xmlCatalogPtr catal) {
03041     if (catal == NULL)
03042     return(-1);
03043 
03044     if (catal->type == XML_XML_CATALOG_TYPE) {
03045     if (catal->xml == NULL)
03046         return(1);
03047     if ((catal->xml->type != XML_CATA_CATALOG) &&
03048         (catal->xml->type != XML_CATA_BROKEN_CATALOG))
03049         return(-1);
03050     if (catal->xml->children == NULL)
03051         return(1);
03052         return(0);
03053     } else {
03054     int res;
03055 
03056     if (catal->sgml == NULL)
03057         return(1);
03058     res = xmlHashSize(catal->sgml);
03059     if (res == 0)
03060         return(1);
03061     if (res < 0)
03062         return(-1);
03063     } 
03064     return(0);
03065 }
03066 
03067 /************************************************************************
03068  *                                  *
03069  *   Public interfaces manipulating the global shared default catalog   *
03070  *                                  *
03071  ************************************************************************/
03072 
03081 static void
03082 xmlInitializeCatalogData(void) {
03083     if (xmlCatalogInitialized != 0)
03084     return;
03085 
03086     if (getenv("XML_DEBUG_CATALOG")) 
03087     xmlDebugCatalogs = 1;
03088     xmlCatalogMutex = xmlNewRMutex();
03089 
03090     xmlCatalogInitialized = 1;
03091 }
03099 void
03100 xmlInitializeCatalog(void) {
03101     if (xmlCatalogInitialized != 0)
03102     return;
03103 
03104     xmlInitializeCatalogData();
03105     xmlRMutexLock(xmlCatalogMutex);
03106 
03107     if (getenv("XML_DEBUG_CATALOG")) 
03108     xmlDebugCatalogs = 1;
03109 
03110     if (xmlDefaultCatalog == NULL) {
03111     const char *catalogs;
03112     char *path;
03113     const char *cur, *paths;
03114     xmlCatalogPtr catal;
03115     xmlCatalogEntryPtr *nextent;
03116 
03117     catalogs = (const char *) getenv("XML_CATALOG_FILES");
03118     if (catalogs == NULL)
03119 #if defined(_WIN32) && defined(_MSC_VER)
03120     {
03121         void* hmodule;
03122         hmodule = GetModuleHandleA("libxml2.dll");
03123         if (hmodule == NULL)
03124             hmodule = GetModuleHandleA(NULL);
03125         if (hmodule != NULL) {
03126             char buf[256];
03127             unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
03128             if (len != 0) {
03129                 char* p = &(buf[len]);
03130                 while (*p != '\\' && p > buf) 
03131                     p--;
03132                 if (p != buf) {
03133                     xmlChar* uri;
03134                     strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
03135                     uri = xmlCanonicPath(buf);
03136                     if (uri != NULL) {
03137                         strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
03138                         xmlFree(uri);
03139                     }
03140                 }
03141             }
03142         }
03143         catalogs = XML_XML_DEFAULT_CATALOG;
03144     }
03145 #else
03146         catalogs = XML_XML_DEFAULT_CATALOG;
03147 #endif
03148 
03149     catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 
03150         xmlCatalogDefaultPrefer);
03151     if (catal != NULL) {
03152         /* the XML_CATALOG_FILES envvar is allowed to contain a 
03153            space-separated list of entries. */
03154         cur = catalogs;
03155         nextent = &catal->xml;
03156         while (*cur != '\0') {
03157         while (xmlIsBlank_ch(*cur)) 
03158             cur++;
03159         if (*cur != 0) {
03160             paths = cur;
03161             while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
03162             cur++;
03163             path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
03164             if (path != NULL) {
03165             *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
03166                 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
03167             if (*nextent != NULL)
03168                 nextent = &((*nextent)->next);
03169             xmlFree(path);
03170             }
03171         }
03172         }
03173         xmlDefaultCatalog = catal;
03174     }
03175     }
03176 
03177     xmlRMutexUnlock(xmlCatalogMutex);
03178 }
03179 
03180 
03192 int
03193 xmlLoadCatalog(const char *filename)
03194 {
03195     int ret;
03196     xmlCatalogPtr catal;
03197 
03198     if (!xmlCatalogInitialized)
03199     xmlInitializeCatalogData();
03200 
03201     xmlRMutexLock(xmlCatalogMutex);
03202 
03203     if (xmlDefaultCatalog == NULL) {
03204     catal = xmlLoadACatalog(filename);
03205     if (catal == NULL) {
03206         xmlRMutexUnlock(xmlCatalogMutex);
03207         return(-1);
03208     }
03209 
03210     xmlDefaultCatalog = catal;
03211     xmlRMutexUnlock(xmlCatalogMutex);
03212     return(0);
03213     }
03214 
03215     ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
03216     xmlRMutexUnlock(xmlCatalogMutex);
03217     return(ret);
03218 }
03219 
03229 void
03230 xmlLoadCatalogs(const char *pathss) {
03231     const char *cur;
03232     const char *paths;
03233     xmlChar *path;
03234 #ifdef _WIN32
03235     int i, iLen;
03236 #endif
03237 
03238     if (pathss == NULL)
03239     return;
03240 
03241     cur = pathss;
03242     while (*cur != 0) {
03243     while (xmlIsBlank_ch(*cur)) cur++;
03244     if (*cur != 0) {
03245         paths = cur;
03246         while ((*cur != 0) && (*cur != PATH_SEAPARATOR) && (!xmlIsBlank_ch(*cur)))
03247         cur++;
03248         path = xmlStrndup((const xmlChar *)paths, cur - paths);
03249 #ifdef _WIN32
03250         iLen = strlen(path);
03251         for(i = 0; i < iLen; i++) {
03252             if(path[i] == '\\') {
03253                 path[i] = '/';
03254             }
03255         }
03256 #endif
03257         if (path != NULL) {
03258         xmlLoadCatalog((const char *) path);
03259         xmlFree(path);
03260         }
03261     }
03262     while (*cur == PATH_SEAPARATOR)
03263         cur++;
03264     }
03265 }
03266 
03272 void
03273 xmlCatalogCleanup(void) {
03274     if (xmlCatalogInitialized == 0)
03275         return;
03276 
03277     xmlRMutexLock(xmlCatalogMutex);
03278     if (xmlDebugCatalogs)
03279     xmlGenericError(xmlGenericErrorContext,
03280         "Catalogs cleanup\n");
03281     if (xmlCatalogXMLFiles != NULL)
03282     xmlHashFree(xmlCatalogXMLFiles, 
03283             (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
03284     xmlCatalogXMLFiles = NULL;
03285     if (xmlDefaultCatalog != NULL)
03286     xmlFreeCatalog(xmlDefaultCatalog);
03287     xmlDefaultCatalog = NULL;
03288     xmlDebugCatalogs = 0;
03289     xmlCatalogInitialized = 0;
03290     xmlRMutexUnlock(xmlCatalogMutex);
03291     xmlFreeRMutex(xmlCatalogMutex);
03292 }
03293 
03303 xmlChar *
03304 xmlCatalogResolveSystem(const xmlChar *sysID) {
03305     xmlChar *ret;
03306 
03307     if (!xmlCatalogInitialized)
03308     xmlInitializeCatalog();
03309 
03310     ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
03311     return(ret);
03312 }
03313 
03323 xmlChar *
03324 xmlCatalogResolvePublic(const xmlChar *pubID) {
03325     xmlChar *ret;
03326 
03327     if (!xmlCatalogInitialized)
03328     xmlInitializeCatalog();
03329 
03330     ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
03331     return(ret);
03332 }
03333 
03344 xmlChar *
03345 xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
03346     xmlChar *ret;
03347 
03348     if (!xmlCatalogInitialized)
03349     xmlInitializeCatalog();
03350 
03351     ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
03352     return(ret);
03353 }
03354 
03364 xmlChar *
03365 xmlCatalogResolveURI(const xmlChar *URI) {
03366     xmlChar *ret;
03367 
03368     if (!xmlCatalogInitialized)
03369     xmlInitializeCatalog();
03370 
03371     ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
03372     return(ret);
03373 }
03374 
03375 #ifdef LIBXML_OUTPUT_ENABLED
03376 
03382 void
03383 xmlCatalogDump(FILE *out) {
03384     if (out == NULL)
03385     return;
03386 
03387     if (!xmlCatalogInitialized)
03388     xmlInitializeCatalog();
03389 
03390     xmlACatalogDump(xmlDefaultCatalog, out);
03391 }
03392 #endif /* LIBXML_OUTPUT_ENABLED */
03393 
03407 int
03408 xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
03409     int res = -1;
03410 
03411     if (!xmlCatalogInitialized)
03412     xmlInitializeCatalogData();
03413 
03414     xmlRMutexLock(xmlCatalogMutex);
03415     /*
03416      * Specific case where one want to override the default catalog
03417      * put in place by xmlInitializeCatalog();
03418      */
03419     if ((xmlDefaultCatalog == NULL) &&
03420     (xmlStrEqual(type, BAD_CAST "catalog"))) {
03421     xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
03422                                   xmlCatalogDefaultPrefer);
03423     xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
03424                     orig, NULL,  xmlCatalogDefaultPrefer, NULL);
03425 
03426     xmlRMutexUnlock(xmlCatalogMutex);
03427     return(0);
03428     } 
03429 
03430     res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
03431     xmlRMutexUnlock(xmlCatalogMutex);
03432     return(res);
03433 }
03434 
03443 int
03444 xmlCatalogRemove(const xmlChar *value) {
03445     int res;
03446 
03447     if (!xmlCatalogInitialized)
03448     xmlInitializeCatalog();
03449 
03450     xmlRMutexLock(xmlCatalogMutex);
03451     res = xmlACatalogRemove(xmlDefaultCatalog, value);
03452     xmlRMutexUnlock(xmlCatalogMutex);
03453     return(res);
03454 }
03455 
03463 int
03464 xmlCatalogConvert(void) {
03465     int res = -1;
03466 
03467     if (!xmlCatalogInitialized)
03468     xmlInitializeCatalog();
03469 
03470     xmlRMutexLock(xmlCatalogMutex);
03471     res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
03472     xmlRMutexUnlock(xmlCatalogMutex);
03473     return(res);
03474 }
03475 
03476 /************************************************************************
03477  *                                  *
03478  *  Public interface manipulating the common preferences        *
03479  *                                  *
03480  ************************************************************************/
03481 
03490 xmlCatalogAllow
03491 xmlCatalogGetDefaults(void) {
03492     return(xmlCatalogDefaultAllow);
03493 }
03494 
03502 void
03503 xmlCatalogSetDefaults(xmlCatalogAllow allow) {
03504     if (xmlDebugCatalogs) {
03505     switch (allow) {
03506         case XML_CATA_ALLOW_NONE:
03507         xmlGenericError(xmlGenericErrorContext,
03508             "Disabling catalog usage\n");
03509         break;
03510         case XML_CATA_ALLOW_GLOBAL:
03511         xmlGenericError(xmlGenericErrorContext,
03512             "Allowing only global catalogs\n");
03513         break;
03514         case XML_CATA_ALLOW_DOCUMENT:
03515         xmlGenericError(xmlGenericErrorContext,
03516             "Allowing only catalogs from the document\n");
03517         break;
03518         case XML_CATA_ALLOW_ALL:
03519         xmlGenericError(xmlGenericErrorContext,
03520             "Allowing all catalogs\n");
03521         break;
03522     }
03523     }
03524     xmlCatalogDefaultAllow = allow;
03525 }
03526 
03537 xmlCatalogPrefer
03538 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
03539     xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
03540 
03541     if (prefer == XML_CATA_PREFER_NONE)
03542     return(ret);
03543 
03544     if (xmlDebugCatalogs) {
03545     switch (prefer) {
03546         case XML_CATA_PREFER_PUBLIC:
03547         xmlGenericError(xmlGenericErrorContext,
03548             "Setting catalog preference to PUBLIC\n");
03549         break;
03550         case XML_CATA_PREFER_SYSTEM:
03551         xmlGenericError(xmlGenericErrorContext,
03552             "Setting catalog preference to SYSTEM\n");
03553         break;
03554         case XML_CATA_PREFER_NONE:
03555         break;
03556     }
03557     }
03558     xmlCatalogDefaultPrefer = prefer;
03559     return(ret);
03560 }
03561 
03571 int
03572 xmlCatalogSetDebug(int level) {
03573     int ret = xmlDebugCatalogs;
03574 
03575     if (level <= 0)
03576         xmlDebugCatalogs = 0;
03577     else
03578     xmlDebugCatalogs = level;
03579     return(ret);
03580 }
03581 
03582 /************************************************************************
03583  *                                  *
03584  *   Minimal interfaces used for per-document catalogs by the parser    *
03585  *                                  *
03586  ************************************************************************/
03587 
03594 void
03595 xmlCatalogFreeLocal(void *catalogs) {
03596     xmlCatalogEntryPtr catal;
03597 
03598     if (!xmlCatalogInitialized)
03599     xmlInitializeCatalog();
03600 
03601     catal = (xmlCatalogEntryPtr) catalogs;
03602     if (catal != NULL)
03603     xmlFreeCatalogEntryList(catal);
03604 }
03605 
03606 
03616 void *  
03617 xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
03618     xmlCatalogEntryPtr catal, add;
03619 
03620     if (!xmlCatalogInitialized)
03621     xmlInitializeCatalog();
03622 
03623     if (URL == NULL)
03624     return(catalogs);
03625 
03626     if (xmlDebugCatalogs)
03627     xmlGenericError(xmlGenericErrorContext,
03628         "Adding document catalog %s\n", URL);
03629 
03630     add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
03631                          xmlCatalogDefaultPrefer, NULL);
03632     if (add == NULL)
03633     return(catalogs);
03634 
03635     catal = (xmlCatalogEntryPtr) catalogs;
03636     if (catal == NULL) 
03637     return((void *) add);
03638 
03639     while (catal->next != NULL)
03640     catal = catal->next;
03641     catal->next = add;
03642     return(catalogs);
03643 }
03644 
03657 xmlChar *
03658 xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
03659                    const xmlChar *sysID) {
03660     xmlCatalogEntryPtr catal;
03661     xmlChar *ret;
03662 
03663     if (!xmlCatalogInitialized)
03664     xmlInitializeCatalog();
03665 
03666     if ((pubID == NULL) && (sysID == NULL))
03667     return(NULL);
03668 
03669     if (xmlDebugCatalogs) {
03670         if ((pubID != NULL) && (sysID != NULL)) {
03671             xmlGenericError(xmlGenericErrorContext,
03672                             "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
03673         } else if (pubID != NULL) {
03674             xmlGenericError(xmlGenericErrorContext,
03675                             "Local Resolve: pubID %s\n", pubID);
03676         } else {
03677             xmlGenericError(xmlGenericErrorContext,
03678                             "Local Resolve: sysID %s\n", sysID);
03679         }
03680     }
03681 
03682     catal = (xmlCatalogEntryPtr) catalogs;
03683     if (catal == NULL)
03684     return(NULL);
03685     ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
03686     if ((ret != NULL) && (ret != XML_CATAL_BREAK))
03687     return(ret);
03688     return(NULL);
03689 }
03690 
03702 xmlChar *
03703 xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
03704     xmlCatalogEntryPtr catal;
03705     xmlChar *ret;
03706 
03707     if (!xmlCatalogInitialized)
03708     xmlInitializeCatalog();
03709 
03710     if (URI == NULL)
03711     return(NULL);
03712 
03713     if (xmlDebugCatalogs)
03714     xmlGenericError(xmlGenericErrorContext,
03715         "Resolve URI %s\n", URI);
03716 
03717     catal = (xmlCatalogEntryPtr) catalogs;
03718     if (catal == NULL)
03719     return(NULL);
03720     ret = xmlCatalogListXMLResolveURI(catal, URI);
03721     if ((ret != NULL) && (ret != XML_CATAL_BREAK))
03722     return(ret);
03723     return(NULL);
03724 }
03725 
03726 /************************************************************************
03727  *                                  *
03728  *          Deprecated interfaces               *
03729  *                                  *
03730  ************************************************************************/
03740 const xmlChar *
03741 xmlCatalogGetSystem(const xmlChar *sysID) {
03742     xmlChar *ret;
03743     static xmlChar result[1000];
03744     static int msg = 0;
03745 
03746     if (!xmlCatalogInitialized)
03747     xmlInitializeCatalog();
03748 
03749     if (msg == 0) {
03750     xmlGenericError(xmlGenericErrorContext,
03751         "Use of deprecated xmlCatalogGetSystem() call\n");
03752     msg++;
03753     }
03754 
03755     if (sysID == NULL)
03756     return(NULL);
03757     
03758     /*
03759      * Check first the XML catalogs
03760      */
03761     if (xmlDefaultCatalog != NULL) {
03762     ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
03763     if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
03764         snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
03765         result[sizeof(result) - 1] = 0;
03766         return(result);
03767     }
03768     }
03769 
03770     if (xmlDefaultCatalog != NULL)
03771     return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
03772     return(NULL);
03773 }
03774 
03784 const xmlChar *
03785 xmlCatalogGetPublic(const xmlChar *pubID) {
03786     xmlChar *ret;
03787     static xmlChar result[1000];
03788     static int msg = 0;
03789 
03790     if (!xmlCatalogInitialized)
03791     xmlInitializeCatalog();
03792 
03793     if (msg == 0) {
03794     xmlGenericError(xmlGenericErrorContext,
03795         "Use of deprecated xmlCatalogGetPublic() call\n");
03796     msg++;
03797     }
03798 
03799     if (pubID == NULL)
03800     return(NULL);
03801     
03802     /*
03803      * Check first the XML catalogs
03804      */
03805     if (xmlDefaultCatalog != NULL) {
03806     ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
03807     if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
03808         snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
03809         result[sizeof(result) - 1] = 0;
03810         return(result);
03811     }
03812     }
03813 
03814     if (xmlDefaultCatalog != NULL)
03815     return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
03816     return(NULL);
03817 }
03818 
03819 #define bottom_catalog
03820 #include "elfgcchack.h"
03821 #endif /* LIBXML_CATALOG_ENABLED */

Generated on Sun May 27 2012 04:27:07 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.