Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
catalog.c
00001 /** 00002 * catalog.c: set of generic Catalog related routines 00003 * 00004 * Reference: SGML Open Technical Resolution TR9401:1997. 00005 * http://www.jclark.com/sp/catalog.htm 00006 * 00007 * XML Catalogs Working Draft 06 August 2001 00008 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 00009 * 00010 * See Copyright for the status of this software. 00011 * 00012 * Daniel.Veillard@imag.fr 00013 */ 00014 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 #include "buf.h" 00045 00046 #define MAX_DELEGATE 50 00047 #define MAX_CATAL_DEPTH 50 00048 00049 #ifdef _WIN32 00050 # define PATH_SEAPARATOR ';' 00051 #else 00052 # define PATH_SEAPARATOR ':' 00053 #endif 00054 00055 /** 00056 * TODO: 00057 * 00058 * macro to flag unimplemented blocks 00059 * XML_CATALOG_PREFER user env to select between system/public prefered 00060 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk> 00061 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with 00062 *> values "system" and "public". I have made the default be "system" to 00063 *> match yours. 00064 */ 00065 #define TODO \ 00066 xmlGenericError(xmlGenericErrorContext, \ 00067 "Unimplemented block at %s:%d\n", \ 00068 __FILE__, __LINE__); 00069 00070 #define XML_URN_PUBID "urn:publicid:" 00071 #define XML_CATAL_BREAK ((xmlChar *) -1) 00072 #ifndef XML_XML_DEFAULT_CATALOG 00073 #define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog" 00074 #endif 00075 #ifndef XML_SGML_DEFAULT_CATALOG 00076 #define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog" 00077 #endif 00078 00079 #if defined(_WIN32) && defined(_MSC_VER) 00080 #undef XML_XML_DEFAULT_CATALOG 00081 static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog"; 00082 #if defined(_WIN32_WCE) 00083 /* Windows CE don't have a A variant */ 00084 #define GetModuleHandleA GetModuleHandle 00085 #define GetModuleFileNameA GetModuleFileName 00086 #else 00087 #if !defined(_WINDOWS_) 00088 void* __stdcall GetModuleHandleA(const char*); 00089 unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long); 00090 #endif 00091 #endif 00092 #endif 00093 00094 static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID); 00095 static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename); 00096 00097 /************************************************************************ 00098 * * 00099 * Types, all private * 00100 * * 00101 ************************************************************************/ 00102 00103 typedef enum { 00104 XML_CATA_REMOVED = -1, 00105 XML_CATA_NONE = 0, 00106 XML_CATA_CATALOG, 00107 XML_CATA_BROKEN_CATALOG, 00108 XML_CATA_NEXT_CATALOG, 00109 XML_CATA_GROUP, 00110 XML_CATA_PUBLIC, 00111 XML_CATA_SYSTEM, 00112 XML_CATA_REWRITE_SYSTEM, 00113 XML_CATA_DELEGATE_PUBLIC, 00114 XML_CATA_DELEGATE_SYSTEM, 00115 XML_CATA_URI, 00116 XML_CATA_REWRITE_URI, 00117 XML_CATA_DELEGATE_URI, 00118 SGML_CATA_SYSTEM, 00119 SGML_CATA_PUBLIC, 00120 SGML_CATA_ENTITY, 00121 SGML_CATA_PENTITY, 00122 SGML_CATA_DOCTYPE, 00123 SGML_CATA_LINKTYPE, 00124 SGML_CATA_NOTATION, 00125 SGML_CATA_DELEGATE, 00126 SGML_CATA_BASE, 00127 SGML_CATA_CATALOG, 00128 SGML_CATA_DOCUMENT, 00129 SGML_CATA_SGMLDECL 00130 } xmlCatalogEntryType; 00131 00132 typedef struct _xmlCatalogEntry xmlCatalogEntry; 00133 typedef xmlCatalogEntry *xmlCatalogEntryPtr; 00134 struct _xmlCatalogEntry { 00135 struct _xmlCatalogEntry *next; 00136 struct _xmlCatalogEntry *parent; 00137 struct _xmlCatalogEntry *children; 00138 xmlCatalogEntryType type; 00139 xmlChar *name; 00140 xmlChar *value; 00141 xmlChar *URL; /* The expanded URL using the base */ 00142 xmlCatalogPrefer prefer; 00143 int dealloc; 00144 int depth; 00145 struct _xmlCatalogEntry *group; 00146 }; 00147 00148 typedef enum { 00149 XML_XML_CATALOG_TYPE = 1, 00150 XML_SGML_CATALOG_TYPE 00151 } xmlCatalogType; 00152 00153 #define XML_MAX_SGML_CATA_DEPTH 10 00154 struct _xmlCatalog { 00155 xmlCatalogType type; /* either XML or SGML */ 00156 00157 /* 00158 * SGML Catalogs are stored as a simple hash table of catalog entries 00159 * Catalog stack to check against overflows when building the 00160 * SGML catalog 00161 */ 00162 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */ 00163 int catalNr; /* Number of current catal streams */ 00164 int catalMax; /* Max number of catal streams */ 00165 xmlHashTablePtr sgml; 00166 00167 /* 00168 * XML Catalogs are stored as a tree of Catalog entries 00169 */ 00170 xmlCatalogPrefer prefer; 00171 xmlCatalogEntryPtr xml; 00172 }; 00173 00174 /************************************************************************ 00175 * * 00176 * Global variables * 00177 * * 00178 ************************************************************************/ 00179 00180 /* 00181 * Those are preferences 00182 */ 00183 static int xmlDebugCatalogs = 0; /* used for debugging */ 00184 static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL; 00185 static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC; 00186 00187 /* 00188 * Hash table containing all the trees of XML catalogs parsed by 00189 * the application. 00190 */ 00191 static xmlHashTablePtr xmlCatalogXMLFiles = NULL; 00192 00193 /* 00194 * The default catalog in use by the application 00195 */ 00196 static xmlCatalogPtr xmlDefaultCatalog = NULL; 00197 00198 /* 00199 * A mutex for modifying the shared global catalog(s) 00200 * xmlDefaultCatalog tree. 00201 * It also protects xmlCatalogXMLFiles 00202 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile() 00203 */ 00204 static xmlRMutexPtr xmlCatalogMutex = NULL; 00205 00206 /* 00207 * Whether the catalog support was initialized. 00208 */ 00209 static int xmlCatalogInitialized = 0; 00210 00211 /************************************************************************ 00212 * * 00213 * Catalog error handlers * 00214 * * 00215 ************************************************************************/ 00216 00217 /** 00218 * xmlCatalogErrMemory: 00219 * @extra: extra informations 00220 * 00221 * Handle an out of memory condition 00222 */ 00223 static void 00224 xmlCatalogErrMemory(const char *extra) 00225 { 00226 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG, 00227 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, 00228 extra, NULL, NULL, 0, 0, 00229 "Memory allocation failed : %s\n", extra); 00230 } 00231 00232 /** 00233 * xmlCatalogErr: 00234 * @catal: the Catalog entry 00235 * @node: the context node 00236 * @msg: the error message 00237 * @extra: extra informations 00238 * 00239 * Handle a catalog error 00240 */ 00241 static void 00242 xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error, 00243 const char *msg, const xmlChar *str1, const xmlChar *str2, 00244 const xmlChar *str3) 00245 { 00246 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG, 00247 error, XML_ERR_ERROR, NULL, 0, 00248 (const char *) str1, (const char *) str2, 00249 (const char *) str3, 0, 0, 00250 msg, str1, str2, str3); 00251 } 00252 00253 00254 /************************************************************************ 00255 * * 00256 * Allocation and Freeing * 00257 * * 00258 ************************************************************************/ 00259 00260 /** 00261 * xmlNewCatalogEntry: 00262 * @type: type of entry 00263 * @name: name of the entry 00264 * @value: value of the entry 00265 * @prefer: the PUBLIC vs. SYSTEM current preference value 00266 * @group: for members of a group, the group entry 00267 * 00268 * create a new Catalog entry, this type is shared both by XML and 00269 * SGML catalogs, but the acceptable types values differs. 00270 * 00271 * Returns the xmlCatalogEntryPtr or NULL in case of error 00272 */ 00273 static xmlCatalogEntryPtr 00274 xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name, 00275 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer, 00276 xmlCatalogEntryPtr group) { 00277 xmlCatalogEntryPtr ret; 00278 xmlChar *normid = NULL; 00279 00280 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry)); 00281 if (ret == NULL) { 00282 xmlCatalogErrMemory("allocating catalog entry"); 00283 return(NULL); 00284 } 00285 ret->next = NULL; 00286 ret->parent = NULL; 00287 ret->children = NULL; 00288 ret->type = type; 00289 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) { 00290 normid = xmlCatalogNormalizePublic(name); 00291 if (normid != NULL) 00292 name = (*normid != 0 ? normid : NULL); 00293 } 00294 if (name != NULL) 00295 ret->name = xmlStrdup(name); 00296 else 00297 ret->name = NULL; 00298 if (normid != NULL) 00299 xmlFree(normid); 00300 if (value != NULL) 00301 ret->value = xmlStrdup(value); 00302 else 00303 ret->value = NULL; 00304 if (URL == NULL) 00305 URL = value; 00306 if (URL != NULL) 00307 ret->URL = xmlStrdup(URL); 00308 else 00309 ret->URL = NULL; 00310 ret->prefer = prefer; 00311 ret->dealloc = 0; 00312 ret->depth = 0; 00313 ret->group = group; 00314 return(ret); 00315 } 00316 00317 static void 00318 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret); 00319 00320 /** 00321 * xmlFreeCatalogEntry: 00322 * @ret: a Catalog entry 00323 * 00324 * Free the memory allocated to a Catalog entry 00325 */ 00326 static void 00327 xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) { 00328 if (ret == NULL) 00329 return; 00330 /* 00331 * Entries stored in the file hash must be deallocated 00332 * only by the file hash cleaner ! 00333 */ 00334 if (ret->dealloc == 1) 00335 return; 00336 00337 if (xmlDebugCatalogs) { 00338 if (ret->name != NULL) 00339 xmlGenericError(xmlGenericErrorContext, 00340 "Free catalog entry %s\n", ret->name); 00341 else if (ret->value != NULL) 00342 xmlGenericError(xmlGenericErrorContext, 00343 "Free catalog entry %s\n", ret->value); 00344 else 00345 xmlGenericError(xmlGenericErrorContext, 00346 "Free catalog entry\n"); 00347 } 00348 00349 if (ret->name != NULL) 00350 xmlFree(ret->name); 00351 if (ret->value != NULL) 00352 xmlFree(ret->value); 00353 if (ret->URL != NULL) 00354 xmlFree(ret->URL); 00355 xmlFree(ret); 00356 } 00357 00358 /** 00359 * xmlFreeCatalogEntryList: 00360 * @ret: a Catalog entry list 00361 * 00362 * Free the memory allocated to a full chained list of Catalog entries 00363 */ 00364 static void 00365 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) { 00366 xmlCatalogEntryPtr next; 00367 00368 while (ret != NULL) { 00369 next = ret->next; 00370 xmlFreeCatalogEntry(ret); 00371 ret = next; 00372 } 00373 } 00374 00375 /** 00376 * xmlFreeCatalogHashEntryList: 00377 * @ret: a Catalog entry list 00378 * 00379 * Free the memory allocated to list of Catalog entries from the 00380 * catalog file hash. 00381 */ 00382 static void 00383 xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) { 00384 xmlCatalogEntryPtr children, next; 00385 00386 if (catal == NULL) 00387 return; 00388 00389 children = catal->children; 00390 while (children != NULL) { 00391 next = children->next; 00392 children->dealloc = 0; 00393 children->children = NULL; 00394 xmlFreeCatalogEntry(children); 00395 children = next; 00396 } 00397 catal->dealloc = 0; 00398 xmlFreeCatalogEntry(catal); 00399 } 00400 00401 /** 00402 * xmlCreateNewCatalog: 00403 * @type: type of catalog 00404 * @prefer: the PUBLIC vs. SYSTEM current preference value 00405 * 00406 * create a new Catalog, this type is shared both by XML and 00407 * SGML catalogs, but the acceptable types values differs. 00408 * 00409 * Returns the xmlCatalogPtr or NULL in case of error 00410 */ 00411 static xmlCatalogPtr 00412 xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) { 00413 xmlCatalogPtr ret; 00414 00415 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog)); 00416 if (ret == NULL) { 00417 xmlCatalogErrMemory("allocating catalog"); 00418 return(NULL); 00419 } 00420 memset(ret, 0, sizeof(xmlCatalog)); 00421 ret->type = type; 00422 ret->catalNr = 0; 00423 ret->catalMax = XML_MAX_SGML_CATA_DEPTH; 00424 ret->prefer = prefer; 00425 if (ret->type == XML_SGML_CATALOG_TYPE) 00426 ret->sgml = xmlHashCreate(10); 00427 return(ret); 00428 } 00429 00430 /** 00431 * xmlFreeCatalog: 00432 * @catal: a Catalog 00433 * 00434 * Free the memory allocated to a Catalog 00435 */ 00436 void 00437 xmlFreeCatalog(xmlCatalogPtr catal) { 00438 if (catal == NULL) 00439 return; 00440 if (catal->xml != NULL) 00441 xmlFreeCatalogEntryList(catal->xml); 00442 if (catal->sgml != NULL) 00443 xmlHashFree(catal->sgml, 00444 (xmlHashDeallocator) xmlFreeCatalogEntry); 00445 xmlFree(catal); 00446 } 00447 00448 /************************************************************************ 00449 * * 00450 * Serializing Catalogs * 00451 * * 00452 ************************************************************************/ 00453 00454 #ifdef LIBXML_OUTPUT_ENABLED 00455 /** 00456 * xmlCatalogDumpEntry: 00457 * @entry: the catalog entry 00458 * @out: the file. 00459 * 00460 * Serialize an SGML Catalog entry 00461 */ 00462 static void 00463 xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) { 00464 if ((entry == NULL) || (out == NULL)) 00465 return; 00466 switch (entry->type) { 00467 case SGML_CATA_ENTITY: 00468 fprintf(out, "ENTITY "); break; 00469 case SGML_CATA_PENTITY: 00470 fprintf(out, "ENTITY %%"); break; 00471 case SGML_CATA_DOCTYPE: 00472 fprintf(out, "DOCTYPE "); break; 00473 case SGML_CATA_LINKTYPE: 00474 fprintf(out, "LINKTYPE "); break; 00475 case SGML_CATA_NOTATION: 00476 fprintf(out, "NOTATION "); break; 00477 case SGML_CATA_PUBLIC: 00478 fprintf(out, "PUBLIC "); break; 00479 case SGML_CATA_SYSTEM: 00480 fprintf(out, "SYSTEM "); break; 00481 case SGML_CATA_DELEGATE: 00482 fprintf(out, "DELEGATE "); break; 00483 case SGML_CATA_BASE: 00484 fprintf(out, "BASE "); break; 00485 case SGML_CATA_CATALOG: 00486 fprintf(out, "CATALOG "); break; 00487 case SGML_CATA_DOCUMENT: 00488 fprintf(out, "DOCUMENT "); break; 00489 case SGML_CATA_SGMLDECL: 00490 fprintf(out, "SGMLDECL "); break; 00491 default: 00492 return; 00493 } 00494 switch (entry->type) { 00495 case SGML_CATA_ENTITY: 00496 case SGML_CATA_PENTITY: 00497 case SGML_CATA_DOCTYPE: 00498 case SGML_CATA_LINKTYPE: 00499 case SGML_CATA_NOTATION: 00500 fprintf(out, "%s", (const char *) entry->name); break; 00501 case SGML_CATA_PUBLIC: 00502 case SGML_CATA_SYSTEM: 00503 case SGML_CATA_SGMLDECL: 00504 case SGML_CATA_DOCUMENT: 00505 case SGML_CATA_CATALOG: 00506 case SGML_CATA_BASE: 00507 case SGML_CATA_DELEGATE: 00508 fprintf(out, "\"%s\"", entry->name); break; 00509 default: 00510 break; 00511 } 00512 switch (entry->type) { 00513 case SGML_CATA_ENTITY: 00514 case SGML_CATA_PENTITY: 00515 case SGML_CATA_DOCTYPE: 00516 case SGML_CATA_LINKTYPE: 00517 case SGML_CATA_NOTATION: 00518 case SGML_CATA_PUBLIC: 00519 case SGML_CATA_SYSTEM: 00520 case SGML_CATA_DELEGATE: 00521 fprintf(out, " \"%s\"", entry->value); break; 00522 default: 00523 break; 00524 } 00525 fprintf(out, "\n"); 00526 } 00527 00528 /** 00529 * xmlDumpXMLCatalogNode: 00530 * @catal: top catalog entry 00531 * @catalog: pointer to the xml tree 00532 * @doc: the containing document 00533 * @ns: the current namespace 00534 * @cgroup: group node for group members 00535 * 00536 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively 00537 * for group entries 00538 */ 00539 static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog, 00540 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) { 00541 xmlNodePtr node; 00542 xmlCatalogEntryPtr cur; 00543 /* 00544 * add all the catalog entries 00545 */ 00546 cur = catal; 00547 while (cur != NULL) { 00548 if (cur->group == cgroup) { 00549 switch (cur->type) { 00550 case XML_CATA_REMOVED: 00551 break; 00552 case XML_CATA_BROKEN_CATALOG: 00553 case XML_CATA_CATALOG: 00554 if (cur == catal) { 00555 cur = cur->children; 00556 continue; 00557 } 00558 break; 00559 case XML_CATA_NEXT_CATALOG: 00560 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL); 00561 xmlSetProp(node, BAD_CAST "catalog", cur->value); 00562 xmlAddChild(catalog, node); 00563 break; 00564 case XML_CATA_NONE: 00565 break; 00566 case XML_CATA_GROUP: 00567 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL); 00568 xmlSetProp(node, BAD_CAST "id", cur->name); 00569 if (cur->value != NULL) { 00570 xmlNsPtr xns; 00571 xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE); 00572 if (xns != NULL) 00573 xmlSetNsProp(node, xns, BAD_CAST "base", 00574 cur->value); 00575 } 00576 switch (cur->prefer) { 00577 case XML_CATA_PREFER_NONE: 00578 break; 00579 case XML_CATA_PREFER_PUBLIC: 00580 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public"); 00581 break; 00582 case XML_CATA_PREFER_SYSTEM: 00583 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system"); 00584 break; 00585 } 00586 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur); 00587 xmlAddChild(catalog, node); 00588 break; 00589 case XML_CATA_PUBLIC: 00590 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL); 00591 xmlSetProp(node, BAD_CAST "publicId", cur->name); 00592 xmlSetProp(node, BAD_CAST "uri", cur->value); 00593 xmlAddChild(catalog, node); 00594 break; 00595 case XML_CATA_SYSTEM: 00596 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL); 00597 xmlSetProp(node, BAD_CAST "systemId", cur->name); 00598 xmlSetProp(node, BAD_CAST "uri", cur->value); 00599 xmlAddChild(catalog, node); 00600 break; 00601 case XML_CATA_REWRITE_SYSTEM: 00602 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL); 00603 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); 00604 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); 00605 xmlAddChild(catalog, node); 00606 break; 00607 case XML_CATA_DELEGATE_PUBLIC: 00608 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL); 00609 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name); 00610 xmlSetProp(node, BAD_CAST "catalog", cur->value); 00611 xmlAddChild(catalog, node); 00612 break; 00613 case XML_CATA_DELEGATE_SYSTEM: 00614 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL); 00615 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); 00616 xmlSetProp(node, BAD_CAST "catalog", cur->value); 00617 xmlAddChild(catalog, node); 00618 break; 00619 case XML_CATA_URI: 00620 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL); 00621 xmlSetProp(node, BAD_CAST "name", cur->name); 00622 xmlSetProp(node, BAD_CAST "uri", cur->value); 00623 xmlAddChild(catalog, node); 00624 break; 00625 case XML_CATA_REWRITE_URI: 00626 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL); 00627 xmlSetProp(node, BAD_CAST "uriStartString", cur->name); 00628 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); 00629 xmlAddChild(catalog, node); 00630 break; 00631 case XML_CATA_DELEGATE_URI: 00632 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL); 00633 xmlSetProp(node, BAD_CAST "uriStartString", cur->name); 00634 xmlSetProp(node, BAD_CAST "catalog", cur->value); 00635 xmlAddChild(catalog, node); 00636 break; 00637 case SGML_CATA_SYSTEM: 00638 case SGML_CATA_PUBLIC: 00639 case SGML_CATA_ENTITY: 00640 case SGML_CATA_PENTITY: 00641 case SGML_CATA_DOCTYPE: 00642 case SGML_CATA_LINKTYPE: 00643 case SGML_CATA_NOTATION: 00644 case SGML_CATA_DELEGATE: 00645 case SGML_CATA_BASE: 00646 case SGML_CATA_CATALOG: 00647 case SGML_CATA_DOCUMENT: 00648 case SGML_CATA_SGMLDECL: 00649 break; 00650 } 00651 } 00652 cur = cur->next; 00653 } 00654 } 00655 00656 static int 00657 xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) { 00658 int ret; 00659 xmlDocPtr doc; 00660 xmlNsPtr ns; 00661 xmlDtdPtr dtd; 00662 xmlNodePtr catalog; 00663 xmlOutputBufferPtr buf; 00664 00665 /* 00666 * Rebuild a catalog 00667 */ 00668 doc = xmlNewDoc(NULL); 00669 if (doc == NULL) 00670 return(-1); 00671 dtd = xmlNewDtd(doc, BAD_CAST "catalog", 00672 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN", 00673 BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"); 00674 00675 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd); 00676 00677 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL); 00678 if (ns == NULL) { 00679 xmlFreeDoc(doc); 00680 return(-1); 00681 } 00682 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL); 00683 if (catalog == NULL) { 00684 xmlFreeNs(ns); 00685 xmlFreeDoc(doc); 00686 return(-1); 00687 } 00688 catalog->nsDef = ns; 00689 xmlAddChild((xmlNodePtr) doc, catalog); 00690 00691 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL); 00692 00693 /* 00694 * reserialize it 00695 */ 00696 buf = xmlOutputBufferCreateFile(out, NULL); 00697 if (buf == NULL) { 00698 xmlFreeDoc(doc); 00699 return(-1); 00700 } 00701 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1); 00702 00703 /* 00704 * Free it 00705 */ 00706 xmlFreeDoc(doc); 00707 00708 return(ret); 00709 } 00710 #endif /* LIBXML_OUTPUT_ENABLED */ 00711 00712 /************************************************************************ 00713 * * 00714 * Converting SGML Catalogs to XML * 00715 * * 00716 ************************************************************************/ 00717 00718 /** 00719 * xmlCatalogConvertEntry: 00720 * @entry: the entry 00721 * @catal: pointer to the catalog being converted 00722 * 00723 * Convert one entry from the catalog 00724 */ 00725 static void 00726 xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) { 00727 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) || 00728 (catal->xml == NULL)) 00729 return; 00730 switch (entry->type) { 00731 case SGML_CATA_ENTITY: 00732 entry->type = XML_CATA_PUBLIC; 00733 break; 00734 case SGML_CATA_PENTITY: 00735 entry->type = XML_CATA_PUBLIC; 00736 break; 00737 case SGML_CATA_DOCTYPE: 00738 entry->type = XML_CATA_PUBLIC; 00739 break; 00740 case SGML_CATA_LINKTYPE: 00741 entry->type = XML_CATA_PUBLIC; 00742 break; 00743 case SGML_CATA_NOTATION: 00744 entry->type = XML_CATA_PUBLIC; 00745 break; 00746 case SGML_CATA_PUBLIC: 00747 entry->type = XML_CATA_PUBLIC; 00748 break; 00749 case SGML_CATA_SYSTEM: 00750 entry->type = XML_CATA_SYSTEM; 00751 break; 00752 case SGML_CATA_DELEGATE: 00753 entry->type = XML_CATA_DELEGATE_PUBLIC; 00754 break; 00755 case SGML_CATA_CATALOG: 00756 entry->type = XML_CATA_CATALOG; 00757 break; 00758 default: 00759 xmlHashRemoveEntry(catal->sgml, entry->name, 00760 (xmlHashDeallocator) xmlFreeCatalogEntry); 00761 return; 00762 } 00763 /* 00764 * Conversion successful, remove from the SGML catalog 00765 * and add it to the default XML one 00766 */ 00767 xmlHashRemoveEntry(catal->sgml, entry->name, NULL); 00768 entry->parent = catal->xml; 00769 entry->next = NULL; 00770 if (catal->xml->children == NULL) 00771 catal->xml->children = entry; 00772 else { 00773 xmlCatalogEntryPtr prev; 00774 00775 prev = catal->xml->children; 00776 while (prev->next != NULL) 00777 prev = prev->next; 00778 prev->next = entry; 00779 } 00780 } 00781 00782 /** 00783 * xmlConvertSGMLCatalog: 00784 * @catal: the catalog 00785 * 00786 * Convert all the SGML catalog entries as XML ones 00787 * 00788 * Returns the number of entries converted if successful, -1 otherwise 00789 */ 00790 int 00791 xmlConvertSGMLCatalog(xmlCatalogPtr catal) { 00792 00793 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE)) 00794 return(-1); 00795 00796 if (xmlDebugCatalogs) { 00797 xmlGenericError(xmlGenericErrorContext, 00798 "Converting SGML catalog to XML\n"); 00799 } 00800 xmlHashScan(catal->sgml, 00801 (xmlHashScanner) xmlCatalogConvertEntry, 00802 &catal); 00803 return(0); 00804 } 00805 00806 /************************************************************************ 00807 * * 00808 * Helper function * 00809 * * 00810 ************************************************************************/ 00811 00812 /** 00813 * xmlCatalogUnWrapURN: 00814 * @urn: an "urn:publicid:" to unwrap 00815 * 00816 * Expand the URN into the equivalent Public Identifier 00817 * 00818 * Returns the new identifier or NULL, the string must be deallocated 00819 * by the caller. 00820 */ 00821 static xmlChar * 00822 xmlCatalogUnWrapURN(const xmlChar *urn) { 00823 xmlChar result[2000]; 00824 unsigned int i = 0; 00825 00826 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) 00827 return(NULL); 00828 urn += sizeof(XML_URN_PUBID) - 1; 00829 00830 while (*urn != 0) { 00831 if (i > sizeof(result) - 4) 00832 break; 00833 if (*urn == '+') { 00834 result[i++] = ' '; 00835 urn++; 00836 } else if (*urn == ':') { 00837 result[i++] = '/'; 00838 result[i++] = '/'; 00839 urn++; 00840 } else if (*urn == ';') { 00841 result[i++] = ':'; 00842 result[i++] = ':'; 00843 urn++; 00844 } else if (*urn == '%') { 00845 if ((urn[1] == '2') && (urn[2] == 'B')) 00846 result[i++] = '+'; 00847 else if ((urn[1] == '3') && (urn[2] == 'A')) 00848 result[i++] = ':'; 00849 else if ((urn[1] == '2') && (urn[2] == 'F')) 00850 result[i++] = '/'; 00851 else if ((urn[1] == '3') && (urn[2] == 'B')) 00852 result[i++] = ';'; 00853 else if ((urn[1] == '2') && (urn[2] == '7')) 00854 result[i++] = '\''; 00855 else if ((urn[1] == '3') && (urn[2] == 'F')) 00856 result[i++] = '?'; 00857 else if ((urn[1] == '2') && (urn[2] == '3')) 00858 result[i++] = '#'; 00859 else if ((urn[1] == '2') && (urn[2] == '5')) 00860 result[i++] = '%'; 00861 else { 00862 result[i++] = *urn; 00863 urn++; 00864 continue; 00865 } 00866 urn += 3; 00867 } else { 00868 result[i++] = *urn; 00869 urn++; 00870 } 00871 } 00872 result[i] = 0; 00873 00874 return(xmlStrdup(result)); 00875 } 00876 00877 /** 00878 * xmlParseCatalogFile: 00879 * @filename: the filename 00880 * 00881 * parse an XML file and build a tree. It's like xmlParseFile() 00882 * except it bypass all catalog lookups. 00883 * 00884 * Returns the resulting document tree or NULL in case of error 00885 */ 00886 00887 xmlDocPtr 00888 xmlParseCatalogFile(const char *filename) { 00889 xmlDocPtr ret; 00890 xmlParserCtxtPtr ctxt; 00891 char *directory = NULL; 00892 xmlParserInputPtr inputStream; 00893 xmlParserInputBufferPtr buf; 00894 00895 ctxt = xmlNewParserCtxt(); 00896 if (ctxt == NULL) { 00897 #ifdef LIBXML_SAX1_ENABLED 00898 if (xmlDefaultSAXHandler.error != NULL) { 00899 xmlDefaultSAXHandler.error(NULL, "out of memory\n"); 00900 } 00901 #endif 00902 return(NULL); 00903 } 00904 00905 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE); 00906 if (buf == NULL) { 00907 xmlFreeParserCtxt(ctxt); 00908 return(NULL); 00909 } 00910 00911 inputStream = xmlNewInputStream(ctxt); 00912 if (inputStream == NULL) { 00913 xmlFreeParserCtxt(ctxt); 00914 return(NULL); 00915 } 00916 00917 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename); 00918 inputStream->buf = buf; 00919 xmlBufResetInput(buf->buffer, inputStream); 00920 00921 inputPush(ctxt, inputStream); 00922 if ((ctxt->directory == NULL) && (directory == NULL)) 00923 directory = xmlParserGetDirectory(filename); 00924 if ((ctxt->directory == NULL) && (directory != NULL)) 00925 ctxt->directory = directory; 00926 ctxt->valid = 0; 00927 ctxt->validate = 0; 00928 ctxt->loadsubset = 0; 00929 ctxt->pedantic = 0; 00930 ctxt->dictNames = 1; 00931 00932 xmlParseDocument(ctxt); 00933 00934 if (ctxt->wellFormed) 00935 ret = ctxt->myDoc; 00936 else { 00937 ret = NULL; 00938 xmlFreeDoc(ctxt->myDoc); 00939 ctxt->myDoc = NULL; 00940 } 00941 xmlFreeParserCtxt(ctxt); 00942 00943 return(ret); 00944 } 00945 00946 /** 00947 * xmlLoadFileContent: 00948 * @filename: a file path 00949 * 00950 * Load a file content into memory. 00951 * 00952 * Returns a pointer to the 0 terminated string or NULL in case of error 00953 */ 00954 static xmlChar * 00955 xmlLoadFileContent(const char *filename) 00956 { 00957 #ifdef HAVE_STAT 00958 int fd; 00959 #else 00960 FILE *fd; 00961 #endif 00962 int len; 00963 long size; 00964 00965 #ifdef HAVE_STAT 00966 struct stat info; 00967 #endif 00968 xmlChar *content; 00969 00970 if (filename == NULL) 00971 return (NULL); 00972 00973 #ifdef HAVE_STAT 00974 if (stat(filename, &info) < 0) 00975 return (NULL); 00976 #endif 00977 00978 #ifdef HAVE_STAT 00979 if ((fd = open(filename, O_RDONLY)) < 0) 00980 #else 00981 if ((fd = fopen(filename, "rb")) == NULL) 00982 #endif 00983 { 00984 return (NULL); 00985 } 00986 #ifdef HAVE_STAT 00987 size = info.st_size; 00988 #else 00989 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */ 00990 fclose(fd); 00991 return (NULL); 00992 } 00993 #endif 00994 content = (xmlChar*)xmlMallocAtomic(size + 10); 00995 if (content == NULL) { 00996 xmlCatalogErrMemory("allocating catalog data"); 00997 #ifdef HAVE_STAT 00998 close(fd); 00999 #else 01000 fclose(fd); 01001 #endif 01002 return (NULL); 01003 } 01004 #ifdef HAVE_STAT 01005 len = read(fd, content, size); 01006 close(fd); 01007 #else 01008 len = fread(content, 1, size, fd); 01009 fclose(fd); 01010 #endif 01011 if (len < 0) { 01012 xmlFree(content); 01013 return (NULL); 01014 } 01015 content[len] = 0; 01016 01017 return(content); 01018 } 01019 01020 /** 01021 * xmlCatalogNormalizePublic: 01022 * @pubID: the public ID string 01023 * 01024 * Normalizes the Public Identifier 01025 * 01026 * Implements 6.2. Public Identifier Normalization 01027 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 01028 * 01029 * Returns the new string or NULL, the string must be deallocated 01030 * by the caller. 01031 */ 01032 static xmlChar * 01033 xmlCatalogNormalizePublic(const xmlChar *pubID) 01034 { 01035 int ok = 1; 01036 int white; 01037 const xmlChar *p; 01038 xmlChar *ret; 01039 xmlChar *q; 01040 01041 if (pubID == NULL) 01042 return(NULL); 01043 01044 white = 1; 01045 for (p = pubID;*p != 0 && ok;p++) { 01046 if (!xmlIsBlank_ch(*p)) 01047 white = 0; 01048 else if (*p == 0x20 && !white) 01049 white = 1; 01050 else 01051 ok = 0; 01052 } 01053 if (ok && !white) /* is normalized */ 01054 return(NULL); 01055 01056 ret = xmlStrdup(pubID); 01057 q = ret; 01058 white = 0; 01059 for (p = pubID;*p != 0;p++) { 01060 if (xmlIsBlank_ch(*p)) { 01061 if (q != ret) 01062 white = 1; 01063 } else { 01064 if (white) { 01065 *(q++) = 0x20; 01066 white = 0; 01067 } 01068 *(q++) = *p; 01069 } 01070 } 01071 *q = 0; 01072 return(ret); 01073 } 01074 01075 /************************************************************************ 01076 * * 01077 * The XML Catalog parser * 01078 * * 01079 ************************************************************************/ 01080 01081 static xmlCatalogEntryPtr 01082 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename); 01083 static void 01084 xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, 01085 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup); 01086 static xmlChar * 01087 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, 01088 const xmlChar *sysID); 01089 static xmlChar * 01090 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI); 01091 01092 01093 /** 01094 * xmlGetXMLCatalogEntryType: 01095 * @name: the name 01096 * 01097 * lookup the internal type associated to an XML catalog entry name 01098 * 01099 * Returns the type associated with that name 01100 */ 01101 static xmlCatalogEntryType 01102 xmlGetXMLCatalogEntryType(const xmlChar *name) { 01103 xmlCatalogEntryType type = XML_CATA_NONE; 01104 if (xmlStrEqual(name, (const xmlChar *) "system")) 01105 type = XML_CATA_SYSTEM; 01106 else if (xmlStrEqual(name, (const xmlChar *) "public")) 01107 type = XML_CATA_PUBLIC; 01108 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem")) 01109 type = XML_CATA_REWRITE_SYSTEM; 01110 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic")) 01111 type = XML_CATA_DELEGATE_PUBLIC; 01112 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem")) 01113 type = XML_CATA_DELEGATE_SYSTEM; 01114 else if (xmlStrEqual(name, (const xmlChar *) "uri")) 01115 type = XML_CATA_URI; 01116 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI")) 01117 type = XML_CATA_REWRITE_URI; 01118 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI")) 01119 type = XML_CATA_DELEGATE_URI; 01120 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog")) 01121 type = XML_CATA_NEXT_CATALOG; 01122 else if (xmlStrEqual(name, (const xmlChar *) "catalog")) 01123 type = XML_CATA_CATALOG; 01124 return(type); 01125 } 01126 01127 /** 01128 * xmlParseXMLCatalogOneNode: 01129 * @cur: the XML node 01130 * @type: the type of Catalog entry 01131 * @name: the name of the node 01132 * @attrName: the attribute holding the value 01133 * @uriAttrName: the attribute holding the URI-Reference 01134 * @prefer: the PUBLIC vs. SYSTEM current preference value 01135 * @cgroup: the group which includes this node 01136 * 01137 * Finishes the examination of an XML tree node of a catalog and build 01138 * a Catalog entry from it. 01139 * 01140 * Returns the new Catalog entry node or NULL in case of error. 01141 */ 01142 static xmlCatalogEntryPtr 01143 xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type, 01144 const xmlChar *name, const xmlChar *attrName, 01145 const xmlChar *uriAttrName, xmlCatalogPrefer prefer, 01146 xmlCatalogEntryPtr cgroup) { 01147 int ok = 1; 01148 xmlChar *uriValue; 01149 xmlChar *nameValue = NULL; 01150 xmlChar *base = NULL; 01151 xmlChar *URL = NULL; 01152 xmlCatalogEntryPtr ret = NULL; 01153 01154 if (attrName != NULL) { 01155 nameValue = xmlGetProp(cur, attrName); 01156 if (nameValue == NULL) { 01157 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR, 01158 "%s entry lacks '%s'\n", name, attrName, NULL); 01159 ok = 0; 01160 } 01161 } 01162 uriValue = xmlGetProp(cur, uriAttrName); 01163 if (uriValue == NULL) { 01164 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR, 01165 "%s entry lacks '%s'\n", name, uriAttrName, NULL); 01166 ok = 0; 01167 } 01168 if (!ok) { 01169 if (nameValue != NULL) 01170 xmlFree(nameValue); 01171 if (uriValue != NULL) 01172 xmlFree(uriValue); 01173 return(NULL); 01174 } 01175 01176 base = xmlNodeGetBase(cur->doc, cur); 01177 URL = xmlBuildURI(uriValue, base); 01178 if (URL != NULL) { 01179 if (xmlDebugCatalogs > 1) { 01180 if (nameValue != NULL) 01181 xmlGenericError(xmlGenericErrorContext, 01182 "Found %s: '%s' '%s'\n", name, nameValue, URL); 01183 else 01184 xmlGenericError(xmlGenericErrorContext, 01185 "Found %s: '%s'\n", name, URL); 01186 } 01187 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup); 01188 } else { 01189 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN, 01190 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue); 01191 } 01192 if (nameValue != NULL) 01193 xmlFree(nameValue); 01194 if (uriValue != NULL) 01195 xmlFree(uriValue); 01196 if (base != NULL) 01197 xmlFree(base); 01198 if (URL != NULL) 01199 xmlFree(URL); 01200 return(ret); 01201 } 01202 01203 /** 01204 * xmlParseXMLCatalogNode: 01205 * @cur: the XML node 01206 * @prefer: the PUBLIC vs. SYSTEM current preference value 01207 * @parent: the parent Catalog entry 01208 * @cgroup: the group which includes this node 01209 * 01210 * Examines an XML tree node of a catalog and build 01211 * a Catalog entry from it adding it to its parent. The examination can 01212 * be recursive. 01213 */ 01214 static void 01215 xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer, 01216 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) 01217 { 01218 xmlChar *base = NULL; 01219 xmlCatalogEntryPtr entry = NULL; 01220 01221 if (cur == NULL) 01222 return; 01223 if (xmlStrEqual(cur->name, BAD_CAST "group")) { 01224 xmlChar *prop; 01225 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE; 01226 01227 prop = xmlGetProp(cur, BAD_CAST "prefer"); 01228 if (prop != NULL) { 01229 if (xmlStrEqual(prop, BAD_CAST "system")) { 01230 prefer = XML_CATA_PREFER_SYSTEM; 01231 } else if (xmlStrEqual(prop, BAD_CAST "public")) { 01232 prefer = XML_CATA_PREFER_PUBLIC; 01233 } else { 01234 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE, 01235 "Invalid value for prefer: '%s'\n", 01236 prop, NULL, NULL); 01237 } 01238 xmlFree(prop); 01239 pref = prefer; 01240 } 01241 prop = xmlGetProp(cur, BAD_CAST "id"); 01242 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); 01243 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup); 01244 xmlFree(prop); 01245 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) { 01246 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC, 01247 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup); 01248 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) { 01249 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM, 01250 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup); 01251 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) { 01252 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM, 01253 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString", 01254 BAD_CAST "rewritePrefix", prefer, cgroup); 01255 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) { 01256 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC, 01257 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString", 01258 BAD_CAST "catalog", prefer, cgroup); 01259 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) { 01260 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM, 01261 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString", 01262 BAD_CAST "catalog", prefer, cgroup); 01263 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) { 01264 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI, 01265 BAD_CAST "uri", BAD_CAST "name", 01266 BAD_CAST "uri", prefer, cgroup); 01267 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) { 01268 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI, 01269 BAD_CAST "rewriteURI", BAD_CAST "uriStartString", 01270 BAD_CAST "rewritePrefix", prefer, cgroup); 01271 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) { 01272 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI, 01273 BAD_CAST "delegateURI", BAD_CAST "uriStartString", 01274 BAD_CAST "catalog", prefer, cgroup); 01275 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) { 01276 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG, 01277 BAD_CAST "nextCatalog", NULL, 01278 BAD_CAST "catalog", prefer, cgroup); 01279 } 01280 if (entry != NULL) { 01281 if (parent != NULL) { 01282 entry->parent = parent; 01283 if (parent->children == NULL) 01284 parent->children = entry; 01285 else { 01286 xmlCatalogEntryPtr prev; 01287 01288 prev = parent->children; 01289 while (prev->next != NULL) 01290 prev = prev->next; 01291 prev->next = entry; 01292 } 01293 } 01294 if (entry->type == XML_CATA_GROUP) { 01295 /* 01296 * Recurse to propagate prefer to the subtree 01297 * (xml:base handling is automated) 01298 */ 01299 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry); 01300 } 01301 } 01302 if (base != NULL) 01303 xmlFree(base); 01304 } 01305 01306 /** 01307 * xmlParseXMLCatalogNodeList: 01308 * @cur: the XML node list of siblings 01309 * @prefer: the PUBLIC vs. SYSTEM current preference value 01310 * @parent: the parent Catalog entry 01311 * @cgroup: the group which includes this list 01312 * 01313 * Examines a list of XML sibling nodes of a catalog and build 01314 * a list of Catalog entry from it adding it to the parent. 01315 * The examination will recurse to examine node subtrees. 01316 */ 01317 static void 01318 xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, 01319 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) { 01320 while (cur != NULL) { 01321 if ((cur->ns != NULL) && (cur->ns->href != NULL) && 01322 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { 01323 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup); 01324 } 01325 cur = cur->next; 01326 } 01327 /* TODO: sort the list according to REWRITE lengths and prefer value */ 01328 } 01329 01330 /** 01331 * xmlParseXMLCatalogFile: 01332 * @prefer: the PUBLIC vs. SYSTEM current preference value 01333 * @filename: the filename for the catalog 01334 * 01335 * Parses the catalog file to extract the XML tree and then analyze the 01336 * tree to build a list of Catalog entries corresponding to this catalog 01337 * 01338 * Returns the resulting Catalog entries list 01339 */ 01340 static xmlCatalogEntryPtr 01341 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) { 01342 xmlDocPtr doc; 01343 xmlNodePtr cur; 01344 xmlChar *prop; 01345 xmlCatalogEntryPtr parent = NULL; 01346 01347 if (filename == NULL) 01348 return(NULL); 01349 01350 doc = xmlParseCatalogFile((const char *) filename); 01351 if (doc == NULL) { 01352 if (xmlDebugCatalogs) 01353 xmlGenericError(xmlGenericErrorContext, 01354 "Failed to parse catalog %s\n", filename); 01355 return(NULL); 01356 } 01357 01358 if (xmlDebugCatalogs) 01359 xmlGenericError(xmlGenericErrorContext, 01360 "%d Parsing catalog %s\n", xmlGetThreadId(), filename); 01361 01362 cur = xmlDocGetRootElement(doc); 01363 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) && 01364 (cur->ns != NULL) && (cur->ns->href != NULL) && 01365 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { 01366 01367 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 01368 (const xmlChar *)filename, NULL, prefer, NULL); 01369 if (parent == NULL) { 01370 xmlFreeDoc(doc); 01371 return(NULL); 01372 } 01373 01374 prop = xmlGetProp(cur, BAD_CAST "prefer"); 01375 if (prop != NULL) { 01376 if (xmlStrEqual(prop, BAD_CAST "system")) { 01377 prefer = XML_CATA_PREFER_SYSTEM; 01378 } else if (xmlStrEqual(prop, BAD_CAST "public")) { 01379 prefer = XML_CATA_PREFER_PUBLIC; 01380 } else { 01381 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE, 01382 "Invalid value for prefer: '%s'\n", 01383 prop, NULL, NULL); 01384 } 01385 xmlFree(prop); 01386 } 01387 cur = cur->children; 01388 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL); 01389 } else { 01390 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG, 01391 "File %s is not an XML Catalog\n", 01392 filename, NULL, NULL); 01393 xmlFreeDoc(doc); 01394 return(NULL); 01395 } 01396 xmlFreeDoc(doc); 01397 return(parent); 01398 } 01399 01400 /** 01401 * xmlFetchXMLCatalogFile: 01402 * @catal: an existing but incomplete catalog entry 01403 * 01404 * Fetch and parse the subcatalog referenced by an entry 01405 * 01406 * Returns 0 in case of success, -1 otherwise 01407 */ 01408 static int 01409 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { 01410 xmlCatalogEntryPtr doc; 01411 01412 if (catal == NULL) 01413 return(-1); 01414 if (catal->URL == NULL) 01415 return(-1); 01416 01417 /* 01418 * lock the whole catalog for modification 01419 */ 01420 xmlRMutexLock(xmlCatalogMutex); 01421 if (catal->children != NULL) { 01422 /* Okay someone else did it in the meantime */ 01423 xmlRMutexUnlock(xmlCatalogMutex); 01424 return(0); 01425 } 01426 01427 if (xmlCatalogXMLFiles != NULL) { 01428 doc = (xmlCatalogEntryPtr) 01429 xmlHashLookup(xmlCatalogXMLFiles, catal->URL); 01430 if (doc != NULL) { 01431 if (xmlDebugCatalogs) 01432 xmlGenericError(xmlGenericErrorContext, 01433 "Found %s in file hash\n", catal->URL); 01434 01435 if (catal->type == XML_CATA_CATALOG) 01436 catal->children = doc->children; 01437 else 01438 catal->children = doc; 01439 catal->dealloc = 0; 01440 xmlRMutexUnlock(xmlCatalogMutex); 01441 return(0); 01442 } 01443 if (xmlDebugCatalogs) 01444 xmlGenericError(xmlGenericErrorContext, 01445 "%s not found in file hash\n", catal->URL); 01446 } 01447 01448 /* 01449 * Fetch and parse. Note that xmlParseXMLCatalogFile does not 01450 * use the existing catalog, there is no recursion allowed at 01451 * that level. 01452 */ 01453 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL); 01454 if (doc == NULL) { 01455 catal->type = XML_CATA_BROKEN_CATALOG; 01456 xmlRMutexUnlock(xmlCatalogMutex); 01457 return(-1); 01458 } 01459 01460 if (catal->type == XML_CATA_CATALOG) 01461 catal->children = doc->children; 01462 else 01463 catal->children = doc; 01464 01465 doc->dealloc = 1; 01466 01467 if (xmlCatalogXMLFiles == NULL) 01468 xmlCatalogXMLFiles = xmlHashCreate(10); 01469 if (xmlCatalogXMLFiles != NULL) { 01470 if (xmlDebugCatalogs) 01471 xmlGenericError(xmlGenericErrorContext, 01472 "%s added to file hash\n", catal->URL); 01473 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc); 01474 } 01475 xmlRMutexUnlock(xmlCatalogMutex); 01476 return(0); 01477 } 01478 01479 /************************************************************************ 01480 * * 01481 * XML Catalog handling * 01482 * * 01483 ************************************************************************/ 01484 01485 /** 01486 * xmlAddXMLCatalog: 01487 * @catal: top of an XML catalog 01488 * @type: the type of record to add to the catalog 01489 * @orig: the system, public or prefix to match (or NULL) 01490 * @replace: the replacement value for the match 01491 * 01492 * Add an entry in the XML catalog, it may overwrite existing but 01493 * different entries. 01494 * 01495 * Returns 0 if successful, -1 otherwise 01496 */ 01497 static int 01498 xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, 01499 const xmlChar *orig, const xmlChar *replace) { 01500 xmlCatalogEntryPtr cur; 01501 xmlCatalogEntryType typ; 01502 int doregister = 0; 01503 01504 if ((catal == NULL) || 01505 ((catal->type != XML_CATA_CATALOG) && 01506 (catal->type != XML_CATA_BROKEN_CATALOG))) 01507 return(-1); 01508 if (catal->children == NULL) { 01509 xmlFetchXMLCatalogFile(catal); 01510 } 01511 if (catal->children == NULL) 01512 doregister = 1; 01513 01514 typ = xmlGetXMLCatalogEntryType(type); 01515 if (typ == XML_CATA_NONE) { 01516 if (xmlDebugCatalogs) 01517 xmlGenericError(xmlGenericErrorContext, 01518 "Failed to add unknown element %s to catalog\n", type); 01519 return(-1); 01520 } 01521 01522 cur = catal->children; 01523 /* 01524 * Might be a simple "update in place" 01525 */ 01526 if (cur != NULL) { 01527 while (cur != NULL) { 01528 if ((orig != NULL) && (cur->type == typ) && 01529 (xmlStrEqual(orig, cur->name))) { 01530 if (xmlDebugCatalogs) 01531 xmlGenericError(xmlGenericErrorContext, 01532 "Updating element %s to catalog\n", type); 01533 if (cur->value != NULL) 01534 xmlFree(cur->value); 01535 if (cur->URL != NULL) 01536 xmlFree(cur->URL); 01537 cur->value = xmlStrdup(replace); 01538 cur->URL = xmlStrdup(replace); 01539 return(0); 01540 } 01541 if (cur->next == NULL) 01542 break; 01543 cur = cur->next; 01544 } 01545 } 01546 if (xmlDebugCatalogs) 01547 xmlGenericError(xmlGenericErrorContext, 01548 "Adding element %s to catalog\n", type); 01549 if (cur == NULL) 01550 catal->children = xmlNewCatalogEntry(typ, orig, replace, 01551 NULL, catal->prefer, NULL); 01552 else 01553 cur->next = xmlNewCatalogEntry(typ, orig, replace, 01554 NULL, catal->prefer, NULL); 01555 if (doregister) { 01556 catal->type = XML_CATA_CATALOG; 01557 cur = (xmlCatalogEntryPtr)xmlHashLookup(xmlCatalogXMLFiles, catal->URL); 01558 if (cur != NULL) 01559 cur->children = catal->children; 01560 } 01561 01562 return(0); 01563 } 01564 01565 /** 01566 * xmlDelXMLCatalog: 01567 * @catal: top of an XML catalog 01568 * @value: the value to remove from the catalog 01569 * 01570 * Remove entries in the XML catalog where the value or the URI 01571 * is equal to @value 01572 * 01573 * Returns the number of entries removed if successful, -1 otherwise 01574 */ 01575 static int 01576 xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) { 01577 xmlCatalogEntryPtr cur; 01578 int ret = 0; 01579 01580 if ((catal == NULL) || 01581 ((catal->type != XML_CATA_CATALOG) && 01582 (catal->type != XML_CATA_BROKEN_CATALOG))) 01583 return(-1); 01584 if (value == NULL) 01585 return(-1); 01586 if (catal->children == NULL) { 01587 xmlFetchXMLCatalogFile(catal); 01588 } 01589 01590 /* 01591 * Scan the children 01592 */ 01593 cur = catal->children; 01594 while (cur != NULL) { 01595 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) || 01596 (xmlStrEqual(value, cur->value))) { 01597 if (xmlDebugCatalogs) { 01598 if (cur->name != NULL) 01599 xmlGenericError(xmlGenericErrorContext, 01600 "Removing element %s from catalog\n", cur->name); 01601 else 01602 xmlGenericError(xmlGenericErrorContext, 01603 "Removing element %s from catalog\n", cur->value); 01604 } 01605 cur->type = XML_CATA_REMOVED; 01606 } 01607 cur = cur->next; 01608 } 01609 return(ret); 01610 } 01611 01612 /** 01613 * xmlCatalogXMLResolve: 01614 * @catal: a catalog list 01615 * @pubID: the public ID string 01616 * @sysID: the system ID string 01617 * 01618 * Do a complete resolution lookup of an External Identifier for a 01619 * list of catalog entries. 01620 * 01621 * Implements (or tries to) 7.1. External Identifier Resolution 01622 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 01623 * 01624 * Returns the URI of the resource or NULL if not found 01625 */ 01626 static xmlChar * 01627 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, 01628 const xmlChar *sysID) { 01629 xmlChar *ret = NULL; 01630 xmlCatalogEntryPtr cur; 01631 int haveDelegate = 0; 01632 int haveNext = 0; 01633 01634 /* 01635 * protection against loops 01636 */ 01637 if (catal->depth > MAX_CATAL_DEPTH) { 01638 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION, 01639 "Detected recursion in catalog %s\n", 01640 catal->name, NULL, NULL); 01641 return(NULL); 01642 } 01643 catal->depth++; 01644 01645 /* 01646 * First tries steps 2/ 3/ 4/ if a system ID is provided. 01647 */ 01648 if (sysID != NULL) { 01649 xmlCatalogEntryPtr rewrite = NULL; 01650 int lenrewrite = 0, len; 01651 cur = catal; 01652 haveDelegate = 0; 01653 while (cur != NULL) { 01654 switch (cur->type) { 01655 case XML_CATA_SYSTEM: 01656 if (xmlStrEqual(sysID, cur->name)) { 01657 if (xmlDebugCatalogs) 01658 xmlGenericError(xmlGenericErrorContext, 01659 "Found system match %s, using %s\n", 01660 cur->name, cur->URL); 01661 catal->depth--; 01662 return(xmlStrdup(cur->URL)); 01663 } 01664 break; 01665 case XML_CATA_REWRITE_SYSTEM: 01666 len = xmlStrlen(cur->name); 01667 if ((len > lenrewrite) && 01668 (!xmlStrncmp(sysID, cur->name, len))) { 01669 lenrewrite = len; 01670 rewrite = cur; 01671 } 01672 break; 01673 case XML_CATA_DELEGATE_SYSTEM: 01674 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name))) 01675 haveDelegate++; 01676 break; 01677 case XML_CATA_NEXT_CATALOG: 01678 haveNext++; 01679 break; 01680 default: 01681 break; 01682 } 01683 cur = cur->next; 01684 } 01685 if (rewrite != NULL) { 01686 if (xmlDebugCatalogs) 01687 xmlGenericError(xmlGenericErrorContext, 01688 "Using rewriting rule %s\n", rewrite->name); 01689 ret = xmlStrdup(rewrite->URL); 01690 if (ret != NULL) 01691 ret = xmlStrcat(ret, &sysID[lenrewrite]); 01692 catal->depth--; 01693 return(ret); 01694 } 01695 if (haveDelegate) { 01696 const xmlChar *delegates[MAX_DELEGATE]; 01697 int nbList = 0, i; 01698 01699 /* 01700 * Assume the entries have been sorted by decreasing substring 01701 * matches when the list was produced. 01702 */ 01703 cur = catal; 01704 while (cur != NULL) { 01705 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) && 01706 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) { 01707 for (i = 0;i < nbList;i++) 01708 if (xmlStrEqual(cur->URL, delegates[i])) 01709 break; 01710 if (i < nbList) { 01711 cur = cur->next; 01712 continue; 01713 } 01714 if (nbList < MAX_DELEGATE) 01715 delegates[nbList++] = cur->URL; 01716 01717 if (cur->children == NULL) { 01718 xmlFetchXMLCatalogFile(cur); 01719 } 01720 if (cur->children != NULL) { 01721 if (xmlDebugCatalogs) 01722 xmlGenericError(xmlGenericErrorContext, 01723 "Trying system delegate %s\n", cur->URL); 01724 ret = xmlCatalogListXMLResolve( 01725 cur->children, NULL, sysID); 01726 if (ret != NULL) { 01727 catal->depth--; 01728 return(ret); 01729 } 01730 } 01731 } 01732 cur = cur->next; 01733 } 01734 /* 01735 * Apply the cut algorithm explained in 4/ 01736 */ 01737 catal->depth--; 01738 return(XML_CATAL_BREAK); 01739 } 01740 } 01741 /* 01742 * Then tries 5/ 6/ if a public ID is provided 01743 */ 01744 if (pubID != NULL) { 01745 cur = catal; 01746 haveDelegate = 0; 01747 while (cur != NULL) { 01748 switch (cur->type) { 01749 case XML_CATA_PUBLIC: 01750 if (xmlStrEqual(pubID, cur->name)) { 01751 if (xmlDebugCatalogs) 01752 xmlGenericError(xmlGenericErrorContext, 01753 "Found public match %s\n", cur->name); 01754 catal->depth--; 01755 return(xmlStrdup(cur->URL)); 01756 } 01757 break; 01758 case XML_CATA_DELEGATE_PUBLIC: 01759 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) && 01760 (cur->prefer == XML_CATA_PREFER_PUBLIC)) 01761 haveDelegate++; 01762 break; 01763 case XML_CATA_NEXT_CATALOG: 01764 if (sysID == NULL) 01765 haveNext++; 01766 break; 01767 default: 01768 break; 01769 } 01770 cur = cur->next; 01771 } 01772 if (haveDelegate) { 01773 const xmlChar *delegates[MAX_DELEGATE]; 01774 int nbList = 0, i; 01775 01776 /* 01777 * Assume the entries have been sorted by decreasing substring 01778 * matches when the list was produced. 01779 */ 01780 cur = catal; 01781 while (cur != NULL) { 01782 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) && 01783 (cur->prefer == XML_CATA_PREFER_PUBLIC) && 01784 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) { 01785 01786 for (i = 0;i < nbList;i++) 01787 if (xmlStrEqual(cur->URL, delegates[i])) 01788 break; 01789 if (i < nbList) { 01790 cur = cur->next; 01791 continue; 01792 } 01793 if (nbList < MAX_DELEGATE) 01794 delegates[nbList++] = cur->URL; 01795 01796 if (cur->children == NULL) { 01797 xmlFetchXMLCatalogFile(cur); 01798 } 01799 if (cur->children != NULL) { 01800 if (xmlDebugCatalogs) 01801 xmlGenericError(xmlGenericErrorContext, 01802 "Trying public delegate %s\n", cur->URL); 01803 ret = xmlCatalogListXMLResolve( 01804 cur->children, pubID, NULL); 01805 if (ret != NULL) { 01806 catal->depth--; 01807 return(ret); 01808 } 01809 } 01810 } 01811 cur = cur->next; 01812 } 01813 /* 01814 * Apply the cut algorithm explained in 4/ 01815 */ 01816 catal->depth--; 01817 return(XML_CATAL_BREAK); 01818 } 01819 } 01820 if (haveNext) { 01821 cur = catal; 01822 while (cur != NULL) { 01823 if (cur->type == XML_CATA_NEXT_CATALOG) { 01824 if (cur->children == NULL) { 01825 xmlFetchXMLCatalogFile(cur); 01826 } 01827 if (cur->children != NULL) { 01828 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID); 01829 if (ret != NULL) { 01830 catal->depth--; 01831 return(ret); 01832 } else if (catal->depth > MAX_CATAL_DEPTH) { 01833 return(NULL); 01834 } 01835 } 01836 } 01837 cur = cur->next; 01838 } 01839 } 01840 01841 catal->depth--; 01842 return(NULL); 01843 } 01844 01845 /** 01846 * xmlCatalogXMLResolveURI: 01847 * @catal: a catalog list 01848 * @URI: the URI 01849 * @sysID: the system ID string 01850 * 01851 * Do a complete resolution lookup of an External Identifier for a 01852 * list of catalog entries. 01853 * 01854 * Implements (or tries to) 7.2.2. URI Resolution 01855 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 01856 * 01857 * Returns the URI of the resource or NULL if not found 01858 */ 01859 static xmlChar * 01860 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { 01861 xmlChar *ret = NULL; 01862 xmlCatalogEntryPtr cur; 01863 int haveDelegate = 0; 01864 int haveNext = 0; 01865 xmlCatalogEntryPtr rewrite = NULL; 01866 int lenrewrite = 0, len; 01867 01868 if (catal == NULL) 01869 return(NULL); 01870 01871 if (URI == NULL) 01872 return(NULL); 01873 01874 if (catal->depth > MAX_CATAL_DEPTH) { 01875 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION, 01876 "Detected recursion in catalog %s\n", 01877 catal->name, NULL, NULL); 01878 return(NULL); 01879 } 01880 01881 /* 01882 * First tries steps 2/ 3/ 4/ if a system ID is provided. 01883 */ 01884 cur = catal; 01885 haveDelegate = 0; 01886 while (cur != NULL) { 01887 switch (cur->type) { 01888 case XML_CATA_URI: 01889 if (xmlStrEqual(URI, cur->name)) { 01890 if (xmlDebugCatalogs) 01891 xmlGenericError(xmlGenericErrorContext, 01892 "Found URI match %s\n", cur->name); 01893 return(xmlStrdup(cur->URL)); 01894 } 01895 break; 01896 case XML_CATA_REWRITE_URI: 01897 len = xmlStrlen(cur->name); 01898 if ((len > lenrewrite) && 01899 (!xmlStrncmp(URI, cur->name, len))) { 01900 lenrewrite = len; 01901 rewrite = cur; 01902 } 01903 break; 01904 case XML_CATA_DELEGATE_URI: 01905 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name))) 01906 haveDelegate++; 01907 break; 01908 case XML_CATA_NEXT_CATALOG: 01909 haveNext++; 01910 break; 01911 default: 01912 break; 01913 } 01914 cur = cur->next; 01915 } 01916 if (rewrite != NULL) { 01917 if (xmlDebugCatalogs) 01918 xmlGenericError(xmlGenericErrorContext, 01919 "Using rewriting rule %s\n", rewrite->name); 01920 ret = xmlStrdup(rewrite->URL); 01921 if (ret != NULL) 01922 ret = xmlStrcat(ret, &URI[lenrewrite]); 01923 return(ret); 01924 } 01925 if (haveDelegate) { 01926 const xmlChar *delegates[MAX_DELEGATE]; 01927 int nbList = 0, i; 01928 01929 /* 01930 * Assume the entries have been sorted by decreasing substring 01931 * matches when the list was produced. 01932 */ 01933 cur = catal; 01934 while (cur != NULL) { 01935 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) || 01936 (cur->type == XML_CATA_DELEGATE_URI)) && 01937 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) { 01938 for (i = 0;i < nbList;i++) 01939 if (xmlStrEqual(cur->URL, delegates[i])) 01940 break; 01941 if (i < nbList) { 01942 cur = cur->next; 01943 continue; 01944 } 01945 if (nbList < MAX_DELEGATE) 01946 delegates[nbList++] = cur->URL; 01947 01948 if (cur->children == NULL) { 01949 xmlFetchXMLCatalogFile(cur); 01950 } 01951 if (cur->children != NULL) { 01952 if (xmlDebugCatalogs) 01953 xmlGenericError(xmlGenericErrorContext, 01954 "Trying URI delegate %s\n", cur->URL); 01955 ret = xmlCatalogListXMLResolveURI( 01956 cur->children, URI); 01957 if (ret != NULL) 01958 return(ret); 01959 } 01960 } 01961 cur = cur->next; 01962 } 01963 /* 01964 * Apply the cut algorithm explained in 4/ 01965 */ 01966 return(XML_CATAL_BREAK); 01967 } 01968 if (haveNext) { 01969 cur = catal; 01970 while (cur != NULL) { 01971 if (cur->type == XML_CATA_NEXT_CATALOG) { 01972 if (cur->children == NULL) { 01973 xmlFetchXMLCatalogFile(cur); 01974 } 01975 if (cur->children != NULL) { 01976 ret = xmlCatalogListXMLResolveURI(cur->children, URI); 01977 if (ret != NULL) 01978 return(ret); 01979 } 01980 } 01981 cur = cur->next; 01982 } 01983 } 01984 01985 return(NULL); 01986 } 01987 01988 /** 01989 * xmlCatalogListXMLResolve: 01990 * @catal: a catalog list 01991 * @pubID: the public ID string 01992 * @sysID: the system ID string 01993 * 01994 * Do a complete resolution lookup of an External Identifier for a 01995 * list of catalogs 01996 * 01997 * Implements (or tries to) 7.1. External Identifier Resolution 01998 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 01999 * 02000 * Returns the URI of the resource or NULL if not found 02001 */ 02002 static xmlChar * 02003 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, 02004 const xmlChar *sysID) { 02005 xmlChar *ret = NULL; 02006 xmlChar *urnID = NULL; 02007 xmlChar *normid; 02008 02009 if (catal == NULL) 02010 return(NULL); 02011 if ((pubID == NULL) && (sysID == NULL)) 02012 return(NULL); 02013 02014 normid = xmlCatalogNormalizePublic(pubID); 02015 if (normid != NULL) 02016 pubID = (*normid != 0 ? normid : NULL); 02017 02018 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { 02019 urnID = xmlCatalogUnWrapURN(pubID); 02020 if (xmlDebugCatalogs) { 02021 if (urnID == NULL) 02022 xmlGenericError(xmlGenericErrorContext, 02023 "Public URN ID %s expanded to NULL\n", pubID); 02024 else 02025 xmlGenericError(xmlGenericErrorContext, 02026 "Public URN ID expanded to %s\n", urnID); 02027 } 02028 ret = xmlCatalogListXMLResolve(catal, urnID, sysID); 02029 if (urnID != NULL) 02030 xmlFree(urnID); 02031 if (normid != NULL) 02032 xmlFree(normid); 02033 return(ret); 02034 } 02035 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { 02036 urnID = xmlCatalogUnWrapURN(sysID); 02037 if (xmlDebugCatalogs) { 02038 if (urnID == NULL) 02039 xmlGenericError(xmlGenericErrorContext, 02040 "System URN ID %s expanded to NULL\n", sysID); 02041 else 02042 xmlGenericError(xmlGenericErrorContext, 02043 "System URN ID expanded to %s\n", urnID); 02044 } 02045 if (pubID == NULL) 02046 ret = xmlCatalogListXMLResolve(catal, urnID, NULL); 02047 else if (xmlStrEqual(pubID, urnID)) 02048 ret = xmlCatalogListXMLResolve(catal, pubID, NULL); 02049 else { 02050 ret = xmlCatalogListXMLResolve(catal, pubID, urnID); 02051 } 02052 if (urnID != NULL) 02053 xmlFree(urnID); 02054 if (normid != NULL) 02055 xmlFree(normid); 02056 return(ret); 02057 } 02058 while (catal != NULL) { 02059 if (catal->type == XML_CATA_CATALOG) { 02060 if (catal->children == NULL) { 02061 xmlFetchXMLCatalogFile(catal); 02062 } 02063 if (catal->children != NULL) { 02064 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID); 02065 if (ret != NULL) { 02066 break; 02067 } else if ((catal->children != NULL) && 02068 (catal->children->depth > MAX_CATAL_DEPTH)) { 02069 ret = NULL; 02070 break; 02071 } 02072 } 02073 } 02074 catal = catal->next; 02075 } 02076 if (normid != NULL) 02077 xmlFree(normid); 02078 return(ret); 02079 } 02080 02081 /** 02082 * xmlCatalogListXMLResolveURI: 02083 * @catal: a catalog list 02084 * @URI: the URI 02085 * 02086 * Do a complete resolution lookup of an URI for a list of catalogs 02087 * 02088 * Implements (or tries to) 7.2. URI Resolution 02089 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html 02090 * 02091 * Returns the URI of the resource or NULL if not found 02092 */ 02093 static xmlChar * 02094 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { 02095 xmlChar *ret = NULL; 02096 xmlChar *urnID = NULL; 02097 02098 if (catal == NULL) 02099 return(NULL); 02100 if (URI == NULL) 02101 return(NULL); 02102 02103 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { 02104 urnID = xmlCatalogUnWrapURN(URI); 02105 if (xmlDebugCatalogs) { 02106 if (urnID == NULL) 02107 xmlGenericError(xmlGenericErrorContext, 02108 "URN ID %s expanded to NULL\n", URI); 02109 else 02110 xmlGenericError(xmlGenericErrorContext, 02111 "URN ID expanded to %s\n", urnID); 02112 } 02113 ret = xmlCatalogListXMLResolve(catal, urnID, NULL); 02114 if (urnID != NULL) 02115 xmlFree(urnID); 02116 return(ret); 02117 } 02118 while (catal != NULL) { 02119 if (catal->type == XML_CATA_CATALOG) { 02120 if (catal->children == NULL) { 02121 xmlFetchXMLCatalogFile(catal); 02122 } 02123 if (catal->children != NULL) { 02124 ret = xmlCatalogXMLResolveURI(catal->children, URI); 02125 if (ret != NULL) 02126 return(ret); 02127 } 02128 } 02129 catal = catal->next; 02130 } 02131 return(ret); 02132 } 02133 02134 /************************************************************************ 02135 * * 02136 * The SGML Catalog parser * 02137 * * 02138 ************************************************************************/ 02139 02140 02141 #define RAW *cur 02142 #define NEXT cur++; 02143 #define SKIP(x) cur += x; 02144 02145 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT; 02146 02147 /** 02148 * xmlParseSGMLCatalogComment: 02149 * @cur: the current character 02150 * 02151 * Skip a comment in an SGML catalog 02152 * 02153 * Returns new current character 02154 */ 02155 static const xmlChar * 02156 xmlParseSGMLCatalogComment(const xmlChar *cur) { 02157 if ((cur[0] != '-') || (cur[1] != '-')) 02158 return(cur); 02159 SKIP(2); 02160 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-')))) 02161 NEXT; 02162 if (cur[0] == 0) { 02163 return(NULL); 02164 } 02165 return(cur + 2); 02166 } 02167 02168 /** 02169 * xmlParseSGMLCatalogPubid: 02170 * @cur: the current character 02171 * @id: the return location 02172 * 02173 * Parse an SGML catalog ID 02174 * 02175 * Returns new current character and store the value in @id 02176 */ 02177 static const xmlChar * 02178 xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) { 02179 xmlChar *buf = NULL, *tmp; 02180 int len = 0; 02181 int size = 50; 02182 xmlChar stop; 02183 int count = 0; 02184 02185 *id = NULL; 02186 02187 if (RAW == '"') { 02188 NEXT; 02189 stop = '"'; 02190 } else if (RAW == '\'') { 02191 NEXT; 02192 stop = '\''; 02193 } else { 02194 stop = ' '; 02195 } 02196 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); 02197 if (buf == NULL) { 02198 xmlCatalogErrMemory("allocating public ID"); 02199 return(NULL); 02200 } 02201 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) { 02202 if ((*cur == stop) && (stop != ' ')) 02203 break; 02204 if ((stop == ' ') && (IS_BLANK_CH(*cur))) 02205 break; 02206 if (len + 1 >= size) { 02207 size *= 2; 02208 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); 02209 if (tmp == NULL) { 02210 xmlCatalogErrMemory("allocating public ID"); 02211 xmlFree(buf); 02212 return(NULL); 02213 } 02214 buf = tmp; 02215 } 02216 buf[len++] = *cur; 02217 count++; 02218 NEXT; 02219 } 02220 buf[len] = 0; 02221 if (stop == ' ') { 02222 if (!IS_BLANK_CH(*cur)) { 02223 xmlFree(buf); 02224 return(NULL); 02225 } 02226 } else { 02227 if (*cur != stop) { 02228 xmlFree(buf); 02229 return(NULL); 02230 } 02231 NEXT; 02232 } 02233 *id = buf; 02234 return(cur); 02235 } 02236 02237 /** 02238 * xmlParseSGMLCatalogName: 02239 * @cur: the current character 02240 * @name: the return location 02241 * 02242 * Parse an SGML catalog name 02243 * 02244 * Returns new current character and store the value in @name 02245 */ 02246 static const xmlChar * 02247 xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) { 02248 xmlChar buf[XML_MAX_NAMELEN + 5]; 02249 int len = 0; 02250 int c; 02251 02252 *name = NULL; 02253 02254 /* 02255 * Handler for more complex cases 02256 */ 02257 c = *cur; 02258 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) { 02259 return(NULL); 02260 } 02261 02262 while (((IS_LETTER(c)) || (IS_DIGIT(c)) || 02263 (c == '.') || (c == '-') || 02264 (c == '_') || (c == ':'))) { 02265 buf[len++] = c; 02266 cur++; 02267 c = *cur; 02268 if (len >= XML_MAX_NAMELEN) 02269 return(NULL); 02270 } 02271 *name = xmlStrndup(buf, len); 02272 return(cur); 02273 } 02274 02275 /** 02276 * xmlGetSGMLCatalogEntryType: 02277 * @name: the entry name 02278 * 02279 * Get the Catalog entry type for a given SGML Catalog name 02280 * 02281 * Returns Catalog entry type 02282 */ 02283 static xmlCatalogEntryType 02284 xmlGetSGMLCatalogEntryType(const xmlChar *name) { 02285 xmlCatalogEntryType type = XML_CATA_NONE; 02286 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) 02287 type = SGML_CATA_SYSTEM; 02288 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) 02289 type = SGML_CATA_PUBLIC; 02290 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 02291 type = SGML_CATA_DELEGATE; 02292 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) 02293 type = SGML_CATA_ENTITY; 02294 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) 02295 type = SGML_CATA_DOCTYPE; 02296 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) 02297 type = SGML_CATA_LINKTYPE; 02298 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) 02299 type = SGML_CATA_NOTATION; 02300 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) 02301 type = SGML_CATA_SGMLDECL; 02302 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) 02303 type = SGML_CATA_DOCUMENT; 02304 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) 02305 type = SGML_CATA_CATALOG; 02306 else if (xmlStrEqual(name, (const xmlChar *) "BASE")) 02307 type = SGML_CATA_BASE; 02308 return(type); 02309 } 02310 02311 /** 02312 * xmlParseSGMLCatalog: 02313 * @catal: the SGML Catalog 02314 * @value: the content of the SGML Catalog serialization 02315 * @file: the filepath for the catalog 02316 * @super: should this be handled as a Super Catalog in which case 02317 * parsing is not recursive 02318 * 02319 * Parse an SGML catalog content and fill up the @catal hash table with 02320 * the new entries found. 02321 * 02322 * Returns 0 in case of success, -1 in case of error. 02323 */ 02324 static int 02325 xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value, 02326 const char *file, int super) { 02327 const xmlChar *cur = value; 02328 xmlChar *base = NULL; 02329 int res; 02330 02331 if ((cur == NULL) || (file == NULL)) 02332 return(-1); 02333 base = xmlStrdup((const xmlChar *) file); 02334 02335 while ((cur != NULL) && (cur[0] != 0)) { 02336 SKIP_BLANKS; 02337 if (cur[0] == 0) 02338 break; 02339 if ((cur[0] == '-') && (cur[1] == '-')) { 02340 cur = xmlParseSGMLCatalogComment(cur); 02341 if (cur == NULL) { 02342 /* error */ 02343 break; 02344 } 02345 } else { 02346 xmlChar *sysid = NULL; 02347 xmlChar *name = NULL; 02348 xmlCatalogEntryType type = XML_CATA_NONE; 02349 02350 cur = xmlParseSGMLCatalogName(cur, &name); 02351 if (name == NULL) { 02352 /* error */ 02353 break; 02354 } 02355 if (!IS_BLANK_CH(*cur)) { 02356 /* error */ 02357 break; 02358 } 02359 SKIP_BLANKS; 02360 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) 02361 type = SGML_CATA_SYSTEM; 02362 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) 02363 type = SGML_CATA_PUBLIC; 02364 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) 02365 type = SGML_CATA_DELEGATE; 02366 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) 02367 type = SGML_CATA_ENTITY; 02368 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) 02369 type = SGML_CATA_DOCTYPE; 02370 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) 02371 type = SGML_CATA_LINKTYPE; 02372 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) 02373 type = SGML_CATA_NOTATION; 02374 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) 02375 type = SGML_CATA_SGMLDECL; 02376 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) 02377 type = SGML_CATA_DOCUMENT; 02378 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) 02379 type = SGML_CATA_CATALOG; 02380 else if (xmlStrEqual(name, (const xmlChar *) "BASE")) 02381 type = SGML_CATA_BASE; 02382 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) { 02383 xmlFree(name); 02384 cur = xmlParseSGMLCatalogName(cur, &name); 02385 if (name == NULL) { 02386 /* error */ 02387 break; 02388 } 02389 xmlFree(name); 02390 continue; 02391 } 02392 xmlFree(name); 02393 name = NULL; 02394 02395 switch(type) { 02396 case SGML_CATA_ENTITY: 02397 if (*cur == '%') 02398 type = SGML_CATA_PENTITY; 02399 case SGML_CATA_PENTITY: 02400 case SGML_CATA_DOCTYPE: 02401 case SGML_CATA_LINKTYPE: 02402 case SGML_CATA_NOTATION: 02403 cur = xmlParseSGMLCatalogName(cur, &name); 02404 if (cur == NULL) { 02405 /* error */ 02406 break; 02407 } 02408 if (!IS_BLANK_CH(*cur)) { 02409 /* error */ 02410 break; 02411 } 02412 SKIP_BLANKS; 02413 cur = xmlParseSGMLCatalogPubid(cur, &sysid); 02414 if (cur == NULL) { 02415 /* error */ 02416 break; 02417 } 02418 break; 02419 case SGML_CATA_PUBLIC: 02420 case SGML_CATA_SYSTEM: 02421 case SGML_CATA_DELEGATE: 02422 cur = xmlParseSGMLCatalogPubid(cur, &name); 02423 if (cur == NULL) { 02424 /* error */ 02425 break; 02426 } 02427 if (type != SGML_CATA_SYSTEM) { 02428 xmlChar *normid; 02429 02430 normid = xmlCatalogNormalizePublic(name); 02431 if (normid != NULL) { 02432 if (name != NULL) 02433 xmlFree(name); 02434 if (*normid != 0) 02435 name = normid; 02436 else { 02437 xmlFree(normid); 02438 name = NULL; 02439 } 02440 } 02441 } 02442 if (!IS_BLANK_CH(*cur)) { 02443 /* error */ 02444 break; 02445 } 02446 SKIP_BLANKS; 02447 cur = xmlParseSGMLCatalogPubid(cur, &sysid); 02448 if (cur == NULL) { 02449 /* error */ 02450 break; 02451 } 02452 break; 02453 case SGML_CATA_BASE: 02454 case SGML_CATA_CATALOG: 02455 case SGML_CATA_DOCUMENT: 02456 case SGML_CATA_SGMLDECL: 02457 cur = xmlParseSGMLCatalogPubid(cur, &sysid); 02458 if (cur == NULL) { 02459 /* error */ 02460 break; 02461 } 02462 break; 02463 default: 02464 break; 02465 } 02466 if (cur == NULL) { 02467 if (name != NULL) 02468 xmlFree(name); 02469 if (sysid != NULL) 02470 xmlFree(sysid); 02471 break; 02472 } else if (type == SGML_CATA_BASE) { 02473 if (base != NULL) 02474 xmlFree(base); 02475 base = xmlStrdup(sysid); 02476 } else if ((type == SGML_CATA_PUBLIC) || 02477 (type == SGML_CATA_SYSTEM)) { 02478 xmlChar *filename; 02479 02480 filename = xmlBuildURI(sysid, base); 02481 if (filename != NULL) { 02482 xmlCatalogEntryPtr entry; 02483 02484 entry = xmlNewCatalogEntry(type, name, filename, 02485 NULL, XML_CATA_PREFER_NONE, NULL); 02486 res = xmlHashAddEntry(catal->sgml, name, entry); 02487 if (res < 0) { 02488 xmlFreeCatalogEntry(entry); 02489 } 02490 xmlFree(filename); 02491 } 02492 02493 } else if (type == SGML_CATA_CATALOG) { 02494 if (super) { 02495 xmlCatalogEntryPtr entry; 02496 02497 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL, 02498 XML_CATA_PREFER_NONE, NULL); 02499 res = xmlHashAddEntry(catal->sgml, sysid, entry); 02500 if (res < 0) { 02501 xmlFreeCatalogEntry(entry); 02502 } 02503 } else { 02504 xmlChar *filename; 02505 02506 filename = xmlBuildURI(sysid, base); 02507 if (filename != NULL) { 02508 xmlExpandCatalog(catal, (const char *)filename); 02509 xmlFree(filename); 02510 } 02511 } 02512 } 02513 /* 02514 * drop anything else we won't handle it 02515 */ 02516 if (name != NULL) 02517 xmlFree(name); 02518 if (sysid != NULL) 02519 xmlFree(sysid); 02520 } 02521 } 02522 if (base != NULL) 02523 xmlFree(base); 02524 if (cur == NULL) 02525 return(-1); 02526 return(0); 02527 } 02528 02529 /************************************************************************ 02530 * * 02531 * SGML Catalog handling * 02532 * * 02533 ************************************************************************/ 02534 02535 /** 02536 * xmlCatalogGetSGMLPublic: 02537 * @catal: an SGML catalog hash 02538 * @pubID: the public ID string 02539 * 02540 * Try to lookup the catalog local reference associated to a public ID 02541 * 02542 * Returns the local resource if found or NULL otherwise. 02543 */ 02544 static const xmlChar * 02545 xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) { 02546 xmlCatalogEntryPtr entry; 02547 xmlChar *normid; 02548 02549 if (catal == NULL) 02550 return(NULL); 02551 02552 normid = xmlCatalogNormalizePublic(pubID); 02553 if (normid != NULL) 02554 pubID = (*normid != 0 ? normid : NULL); 02555 02556 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID); 02557 if (entry == NULL) { 02558 if (normid != NULL) 02559 xmlFree(normid); 02560 return(NULL); 02561 } 02562 if (entry->type == SGML_CATA_PUBLIC) { 02563 if (normid != NULL) 02564 xmlFree(normid); 02565 return(entry->URL); 02566 } 02567 if (normid != NULL) 02568 xmlFree(normid); 02569 return(NULL); 02570 } 02571 02572 /** 02573 * xmlCatalogGetSGMLSystem: 02574 * @catal: an SGML catalog hash 02575 * @sysID: the system ID string 02576 * 02577 * Try to lookup the catalog local reference for a system ID 02578 * 02579 * Returns the local resource if found or NULL otherwise. 02580 */ 02581 static const xmlChar * 02582 xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) { 02583 xmlCatalogEntryPtr entry; 02584 02585 if (catal == NULL) 02586 return(NULL); 02587 02588 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID); 02589 if (entry == NULL) 02590 return(NULL); 02591 if (entry->type == SGML_CATA_SYSTEM) 02592 return(entry->URL); 02593 return(NULL); 02594 } 02595 02596 /** 02597 * xmlCatalogSGMLResolve: 02598 * @catal: the SGML catalog 02599 * @pubID: the public ID string 02600 * @sysID: the system ID string 02601 * 02602 * Do a complete resolution lookup of an External Identifier 02603 * 02604 * Returns the URI of the resource or NULL if not found 02605 */ 02606 static const xmlChar * 02607 xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID, 02608 const xmlChar *sysID) { 02609 const xmlChar *ret = NULL; 02610 02611 if (catal->sgml == NULL) 02612 return(NULL); 02613 02614 if (pubID != NULL) 02615 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID); 02616 if (ret != NULL) 02617 return(ret); 02618 if (sysID != NULL) 02619 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID); 02620 if (ret != NULL) 02621 return(ret); 02622 return(NULL); 02623 } 02624 02625 /************************************************************************ 02626 * * 02627 * Specific Public interfaces * 02628 * * 02629 ************************************************************************/ 02630 02631 /** 02632 * xmlLoadSGMLSuperCatalog: 02633 * @filename: a file path 02634 * 02635 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE 02636 * references. This is only needed for manipulating SGML Super Catalogs 02637 * like adding and removing CATALOG or DELEGATE entries. 02638 * 02639 * Returns the catalog parsed or NULL in case of error 02640 */ 02641 xmlCatalogPtr 02642 xmlLoadSGMLSuperCatalog(const char *filename) 02643 { 02644 xmlChar *content; 02645 xmlCatalogPtr catal; 02646 int ret; 02647 02648 content = xmlLoadFileContent(filename); 02649 if (content == NULL) 02650 return(NULL); 02651 02652 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer); 02653 if (catal == NULL) { 02654 xmlFree(content); 02655 return(NULL); 02656 } 02657 02658 ret = xmlParseSGMLCatalog(catal, content, filename, 1); 02659 xmlFree(content); 02660 if (ret < 0) { 02661 xmlFreeCatalog(catal); 02662 return(NULL); 02663 } 02664 return (catal); 02665 } 02666 02667 /** 02668 * xmlLoadACatalog: 02669 * @filename: a file path 02670 * 02671 * Load the catalog and build the associated data structures. 02672 * This can be either an XML Catalog or an SGML Catalog 02673 * It will recurse in SGML CATALOG entries. On the other hand XML 02674 * Catalogs are not handled recursively. 02675 * 02676 * Returns the catalog parsed or NULL in case of error 02677 */ 02678 xmlCatalogPtr 02679 xmlLoadACatalog(const char *filename) 02680 { 02681 xmlChar *content; 02682 xmlChar *first; 02683 xmlCatalogPtr catal; 02684 int ret; 02685 02686 content = xmlLoadFileContent(filename); 02687 if (content == NULL) 02688 return(NULL); 02689 02690 02691 first = content; 02692 02693 while ((*first != 0) && (*first != '-') && (*first != '<') && 02694 (!(((*first >= 'A') && (*first <= 'Z')) || 02695 ((*first >= 'a') && (*first <= 'z'))))) 02696 first++; 02697 02698 if (*first != '<') { 02699 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer); 02700 if (catal == NULL) { 02701 xmlFree(content); 02702 return(NULL); 02703 } 02704 ret = xmlParseSGMLCatalog(catal, content, filename, 0); 02705 if (ret < 0) { 02706 xmlFreeCatalog(catal); 02707 xmlFree(content); 02708 return(NULL); 02709 } 02710 } else { 02711 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer); 02712 if (catal == NULL) { 02713 xmlFree(content); 02714 return(NULL); 02715 } 02716 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 02717 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL); 02718 } 02719 xmlFree(content); 02720 return (catal); 02721 } 02722 02723 /** 02724 * xmlExpandCatalog: 02725 * @catal: a catalog 02726 * @filename: a file path 02727 * 02728 * Load the catalog and expand the existing catal structure. 02729 * This can be either an XML Catalog or an SGML Catalog 02730 * 02731 * Returns 0 in case of success, -1 in case of error 02732 */ 02733 static int 02734 xmlExpandCatalog(xmlCatalogPtr catal, const char *filename) 02735 { 02736 int ret; 02737 02738 if ((catal == NULL) || (filename == NULL)) 02739 return(-1); 02740 02741 02742 if (catal->type == XML_SGML_CATALOG_TYPE) { 02743 xmlChar *content; 02744 02745 content = xmlLoadFileContent(filename); 02746 if (content == NULL) 02747 return(-1); 02748 02749 ret = xmlParseSGMLCatalog(catal, content, filename, 0); 02750 if (ret < 0) { 02751 xmlFree(content); 02752 return(-1); 02753 } 02754 xmlFree(content); 02755 } else { 02756 xmlCatalogEntryPtr tmp, cur; 02757 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 02758 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL); 02759 02760 cur = catal->xml; 02761 if (cur == NULL) { 02762 catal->xml = tmp; 02763 } else { 02764 while (cur->next != NULL) cur = cur->next; 02765 cur->next = tmp; 02766 } 02767 } 02768 return (0); 02769 } 02770 02771 /** 02772 * xmlACatalogResolveSystem: 02773 * @catal: a Catalog 02774 * @sysID: the system ID string 02775 * 02776 * Try to lookup the catalog resource for a system ID 02777 * 02778 * Returns the resource if found or NULL otherwise, the value returned 02779 * must be freed by the caller. 02780 */ 02781 xmlChar * 02782 xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) { 02783 xmlChar *ret = NULL; 02784 02785 if ((sysID == NULL) || (catal == NULL)) 02786 return(NULL); 02787 02788 if (xmlDebugCatalogs) 02789 xmlGenericError(xmlGenericErrorContext, 02790 "Resolve sysID %s\n", sysID); 02791 02792 if (catal->type == XML_XML_CATALOG_TYPE) { 02793 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID); 02794 if (ret == XML_CATAL_BREAK) 02795 ret = NULL; 02796 } else { 02797 const xmlChar *sgml; 02798 02799 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID); 02800 if (sgml != NULL) 02801 ret = xmlStrdup(sgml); 02802 } 02803 return(ret); 02804 } 02805 02806 /** 02807 * xmlACatalogResolvePublic: 02808 * @catal: a Catalog 02809 * @pubID: the public ID string 02810 * 02811 * Try to lookup the catalog local reference associated to a public ID in that catalog 02812 * 02813 * Returns the local resource if found or NULL otherwise, the value returned 02814 * must be freed by the caller. 02815 */ 02816 xmlChar * 02817 xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) { 02818 xmlChar *ret = NULL; 02819 02820 if ((pubID == NULL) || (catal == NULL)) 02821 return(NULL); 02822 02823 if (xmlDebugCatalogs) 02824 xmlGenericError(xmlGenericErrorContext, 02825 "Resolve pubID %s\n", pubID); 02826 02827 if (catal->type == XML_XML_CATALOG_TYPE) { 02828 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL); 02829 if (ret == XML_CATAL_BREAK) 02830 ret = NULL; 02831 } else { 02832 const xmlChar *sgml; 02833 02834 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID); 02835 if (sgml != NULL) 02836 ret = xmlStrdup(sgml); 02837 } 02838 return(ret); 02839 } 02840 02841 /** 02842 * xmlACatalogResolve: 02843 * @catal: a Catalog 02844 * @pubID: the public ID string 02845 * @sysID: the system ID string 02846 * 02847 * Do a complete resolution lookup of an External Identifier 02848 * 02849 * Returns the URI of the resource or NULL if not found, it must be freed 02850 * by the caller. 02851 */ 02852 xmlChar * 02853 xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID, 02854 const xmlChar * sysID) 02855 { 02856 xmlChar *ret = NULL; 02857 02858 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL)) 02859 return (NULL); 02860 02861 if (xmlDebugCatalogs) { 02862 if ((pubID != NULL) && (sysID != NULL)) { 02863 xmlGenericError(xmlGenericErrorContext, 02864 "Resolve: pubID %s sysID %s\n", pubID, sysID); 02865 } else if (pubID != NULL) { 02866 xmlGenericError(xmlGenericErrorContext, 02867 "Resolve: pubID %s\n", pubID); 02868 } else { 02869 xmlGenericError(xmlGenericErrorContext, 02870 "Resolve: sysID %s\n", sysID); 02871 } 02872 } 02873 02874 if (catal->type == XML_XML_CATALOG_TYPE) { 02875 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID); 02876 if (ret == XML_CATAL_BREAK) 02877 ret = NULL; 02878 } else { 02879 const xmlChar *sgml; 02880 02881 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID); 02882 if (sgml != NULL) 02883 ret = xmlStrdup(sgml); 02884 } 02885 return (ret); 02886 } 02887 02888 /** 02889 * xmlACatalogResolveURI: 02890 * @catal: a Catalog 02891 * @URI: the URI 02892 * 02893 * Do a complete resolution lookup of an URI 02894 * 02895 * Returns the URI of the resource or NULL if not found, it must be freed 02896 * by the caller. 02897 */ 02898 xmlChar * 02899 xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) { 02900 xmlChar *ret = NULL; 02901 02902 if ((URI == NULL) || (catal == NULL)) 02903 return(NULL); 02904 02905 if (xmlDebugCatalogs) 02906 xmlGenericError(xmlGenericErrorContext, 02907 "Resolve URI %s\n", URI); 02908 02909 if (catal->type == XML_XML_CATALOG_TYPE) { 02910 ret = xmlCatalogListXMLResolveURI(catal->xml, URI); 02911 if (ret == XML_CATAL_BREAK) 02912 ret = NULL; 02913 } else { 02914 const xmlChar *sgml; 02915 02916 sgml = xmlCatalogSGMLResolve(catal, NULL, URI); 02917 if (sgml != NULL) 02918 ret = xmlStrdup(sgml); 02919 } 02920 return(ret); 02921 } 02922 02923 #ifdef LIBXML_OUTPUT_ENABLED 02924 /** 02925 * xmlACatalogDump: 02926 * @catal: a Catalog 02927 * @out: the file. 02928 * 02929 * Dump the given catalog to the given file. 02930 */ 02931 void 02932 xmlACatalogDump(xmlCatalogPtr catal, FILE *out) { 02933 if ((out == NULL) || (catal == NULL)) 02934 return; 02935 02936 if (catal->type == XML_XML_CATALOG_TYPE) { 02937 xmlDumpXMLCatalog(out, catal->xml); 02938 } else { 02939 xmlHashScan(catal->sgml, 02940 (xmlHashScanner) xmlCatalogDumpEntry, out); 02941 } 02942 } 02943 #endif /* LIBXML_OUTPUT_ENABLED */ 02944 02945 /** 02946 * xmlACatalogAdd: 02947 * @catal: a Catalog 02948 * @type: the type of record to add to the catalog 02949 * @orig: the system, public or prefix to match 02950 * @replace: the replacement value for the match 02951 * 02952 * Add an entry in the catalog, it may overwrite existing but 02953 * different entries. 02954 * 02955 * Returns 0 if successful, -1 otherwise 02956 */ 02957 int 02958 xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type, 02959 const xmlChar * orig, const xmlChar * replace) 02960 { 02961 int res = -1; 02962 02963 if (catal == NULL) 02964 return(-1); 02965 02966 if (catal->type == XML_XML_CATALOG_TYPE) { 02967 res = xmlAddXMLCatalog(catal->xml, type, orig, replace); 02968 } else { 02969 xmlCatalogEntryType cattype; 02970 02971 cattype = xmlGetSGMLCatalogEntryType(type); 02972 if (cattype != XML_CATA_NONE) { 02973 xmlCatalogEntryPtr entry; 02974 02975 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL, 02976 XML_CATA_PREFER_NONE, NULL); 02977 if (catal->sgml == NULL) 02978 catal->sgml = xmlHashCreate(10); 02979 res = xmlHashAddEntry(catal->sgml, orig, entry); 02980 } 02981 } 02982 return (res); 02983 } 02984 02985 /** 02986 * xmlACatalogRemove: 02987 * @catal: a Catalog 02988 * @value: the value to remove 02989 * 02990 * Remove an entry from the catalog 02991 * 02992 * Returns the number of entries removed if successful, -1 otherwise 02993 */ 02994 int 02995 xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) { 02996 int res = -1; 02997 02998 if ((catal == NULL) || (value == NULL)) 02999 return(-1); 03000 03001 if (catal->type == XML_XML_CATALOG_TYPE) { 03002 res = xmlDelXMLCatalog(catal->xml, value); 03003 } else { 03004 res = xmlHashRemoveEntry(catal->sgml, value, 03005 (xmlHashDeallocator) xmlFreeCatalogEntry); 03006 if (res == 0) 03007 res = 1; 03008 } 03009 return(res); 03010 } 03011 03012 /** 03013 * xmlNewCatalog: 03014 * @sgml: should this create an SGML catalog 03015 * 03016 * create a new Catalog. 03017 * 03018 * Returns the xmlCatalogPtr or NULL in case of error 03019 */ 03020 xmlCatalogPtr 03021 xmlNewCatalog(int sgml) { 03022 xmlCatalogPtr catal = NULL; 03023 03024 if (sgml) { 03025 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, 03026 xmlCatalogDefaultPrefer); 03027 if ((catal != NULL) && (catal->sgml == NULL)) 03028 catal->sgml = xmlHashCreate(10); 03029 } else 03030 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 03031 xmlCatalogDefaultPrefer); 03032 return(catal); 03033 } 03034 03035 /** 03036 * xmlCatalogIsEmpty: 03037 * @catal: should this create an SGML catalog 03038 * 03039 * Check is a catalog is empty 03040 * 03041 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error. 03042 */ 03043 int 03044 xmlCatalogIsEmpty(xmlCatalogPtr catal) { 03045 if (catal == NULL) 03046 return(-1); 03047 03048 if (catal->type == XML_XML_CATALOG_TYPE) { 03049 if (catal->xml == NULL) 03050 return(1); 03051 if ((catal->xml->type != XML_CATA_CATALOG) && 03052 (catal->xml->type != XML_CATA_BROKEN_CATALOG)) 03053 return(-1); 03054 if (catal->xml->children == NULL) 03055 return(1); 03056 return(0); 03057 } else { 03058 int res; 03059 03060 if (catal->sgml == NULL) 03061 return(1); 03062 res = xmlHashSize(catal->sgml); 03063 if (res == 0) 03064 return(1); 03065 if (res < 0) 03066 return(-1); 03067 } 03068 return(0); 03069 } 03070 03071 /************************************************************************ 03072 * * 03073 * Public interfaces manipulating the global shared default catalog * 03074 * * 03075 ************************************************************************/ 03076 03077 /** 03078 * xmlInitializeCatalogData: 03079 * 03080 * Do the catalog initialization only of global data, doesn't try to load 03081 * any catalog actually. 03082 * this function is not thread safe, catalog initialization should 03083 * preferably be done once at startup 03084 */ 03085 static void 03086 xmlInitializeCatalogData(void) { 03087 if (xmlCatalogInitialized != 0) 03088 return; 03089 03090 if (getenv("XML_DEBUG_CATALOG")) 03091 xmlDebugCatalogs = 1; 03092 xmlCatalogMutex = xmlNewRMutex(); 03093 03094 xmlCatalogInitialized = 1; 03095 } 03096 /** 03097 * xmlInitializeCatalog: 03098 * 03099 * Do the catalog initialization. 03100 * this function is not thread safe, catalog initialization should 03101 * preferably be done once at startup 03102 */ 03103 void 03104 xmlInitializeCatalog(void) { 03105 if (xmlCatalogInitialized != 0) 03106 return; 03107 03108 xmlInitializeCatalogData(); 03109 xmlRMutexLock(xmlCatalogMutex); 03110 03111 if (getenv("XML_DEBUG_CATALOG")) 03112 xmlDebugCatalogs = 1; 03113 03114 if (xmlDefaultCatalog == NULL) { 03115 const char *catalogs; 03116 char *path; 03117 const char *cur, *paths; 03118 xmlCatalogPtr catal; 03119 xmlCatalogEntryPtr *nextent; 03120 03121 catalogs = (const char *) getenv("XML_CATALOG_FILES"); 03122 if (catalogs == NULL) 03123 #if defined(_WIN32) && defined(_MSC_VER) 03124 { 03125 void* hmodule; 03126 hmodule = GetModuleHandleA("libxml2.dll"); 03127 if (hmodule == NULL) 03128 hmodule = GetModuleHandleA(NULL); 03129 if (hmodule != NULL) { 03130 char buf[256]; 03131 unsigned long len = GetModuleFileNameA(hmodule, buf, 255); 03132 if (len != 0) { 03133 char* p = &(buf[len]); 03134 while (*p != '\\' && p > buf) 03135 p--; 03136 if (p != buf) { 03137 xmlChar* uri; 03138 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf)); 03139 uri = xmlCanonicPath((const xmlChar*)buf); 03140 if (uri != NULL) { 03141 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255); 03142 xmlFree(uri); 03143 } 03144 } 03145 } 03146 } 03147 catalogs = XML_XML_DEFAULT_CATALOG; 03148 } 03149 #else 03150 catalogs = XML_XML_DEFAULT_CATALOG; 03151 #endif 03152 03153 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 03154 xmlCatalogDefaultPrefer); 03155 if (catal != NULL) { 03156 /* the XML_CATALOG_FILES envvar is allowed to contain a 03157 space-separated list of entries. */ 03158 cur = catalogs; 03159 nextent = &catal->xml; 03160 while (*cur != '\0') { 03161 while (xmlIsBlank_ch(*cur)) 03162 cur++; 03163 if (*cur != 0) { 03164 paths = cur; 03165 while ((*cur != 0) && (!xmlIsBlank_ch(*cur))) 03166 cur++; 03167 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths); 03168 if (path != NULL) { 03169 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 03170 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL); 03171 if (*nextent != NULL) 03172 nextent = &((*nextent)->next); 03173 xmlFree(path); 03174 } 03175 } 03176 } 03177 xmlDefaultCatalog = catal; 03178 } 03179 } 03180 03181 xmlRMutexUnlock(xmlCatalogMutex); 03182 } 03183 03184 03185 /** 03186 * xmlLoadCatalog: 03187 * @filename: a file path 03188 * 03189 * Load the catalog and makes its definitions effective for the default 03190 * external entity loader. It will recurse in SGML CATALOG entries. 03191 * this function is not thread safe, catalog initialization should 03192 * preferably be done once at startup 03193 * 03194 * Returns 0 in case of success -1 in case of error 03195 */ 03196 int 03197 xmlLoadCatalog(const char *filename) 03198 { 03199 int ret; 03200 xmlCatalogPtr catal; 03201 03202 if (!xmlCatalogInitialized) 03203 xmlInitializeCatalogData(); 03204 03205 xmlRMutexLock(xmlCatalogMutex); 03206 03207 if (xmlDefaultCatalog == NULL) { 03208 catal = xmlLoadACatalog(filename); 03209 if (catal == NULL) { 03210 xmlRMutexUnlock(xmlCatalogMutex); 03211 return(-1); 03212 } 03213 03214 xmlDefaultCatalog = catal; 03215 xmlRMutexUnlock(xmlCatalogMutex); 03216 return(0); 03217 } 03218 03219 ret = xmlExpandCatalog(xmlDefaultCatalog, filename); 03220 xmlRMutexUnlock(xmlCatalogMutex); 03221 return(ret); 03222 } 03223 03224 /** 03225 * xmlLoadCatalogs: 03226 * @pathss: a list of directories separated by a colon or a space. 03227 * 03228 * Load the catalogs and makes their definitions effective for the default 03229 * external entity loader. 03230 * this function is not thread safe, catalog initialization should 03231 * preferably be done once at startup 03232 */ 03233 void 03234 xmlLoadCatalogs(const char *pathss) { 03235 const char *cur; 03236 const char *paths; 03237 xmlChar *path; 03238 #ifdef _WIN32 03239 int i, iLen; 03240 #endif 03241 03242 if (pathss == NULL) 03243 return; 03244 03245 cur = pathss; 03246 while (*cur != 0) { 03247 while (xmlIsBlank_ch(*cur)) cur++; 03248 if (*cur != 0) { 03249 paths = cur; 03250 while ((*cur != 0) && (*cur != PATH_SEAPARATOR) && (!xmlIsBlank_ch(*cur))) 03251 cur++; 03252 path = xmlStrndup((const xmlChar *)paths, cur - paths); 03253 #ifdef _WIN32 03254 iLen = strlen((const char*)path); 03255 for(i = 0; i < iLen; i++) { 03256 if(path[i] == '\\') { 03257 path[i] = '/'; 03258 } 03259 } 03260 #endif 03261 if (path != NULL) { 03262 xmlLoadCatalog((const char *) path); 03263 xmlFree(path); 03264 } 03265 } 03266 while (*cur == PATH_SEAPARATOR) 03267 cur++; 03268 } 03269 } 03270 03271 /** 03272 * xmlCatalogCleanup: 03273 * 03274 * Free up all the memory associated with catalogs 03275 */ 03276 void 03277 xmlCatalogCleanup(void) { 03278 if (xmlCatalogInitialized == 0) 03279 return; 03280 03281 xmlRMutexLock(xmlCatalogMutex); 03282 if (xmlDebugCatalogs) 03283 xmlGenericError(xmlGenericErrorContext, 03284 "Catalogs cleanup\n"); 03285 if (xmlCatalogXMLFiles != NULL) 03286 xmlHashFree(xmlCatalogXMLFiles, 03287 (xmlHashDeallocator)xmlFreeCatalogHashEntryList); 03288 xmlCatalogXMLFiles = NULL; 03289 if (xmlDefaultCatalog != NULL) 03290 xmlFreeCatalog(xmlDefaultCatalog); 03291 xmlDefaultCatalog = NULL; 03292 xmlDebugCatalogs = 0; 03293 xmlCatalogInitialized = 0; 03294 xmlRMutexUnlock(xmlCatalogMutex); 03295 xmlFreeRMutex(xmlCatalogMutex); 03296 } 03297 03298 /** 03299 * xmlCatalogResolveSystem: 03300 * @sysID: the system ID string 03301 * 03302 * Try to lookup the catalog resource for a system ID 03303 * 03304 * Returns the resource if found or NULL otherwise, the value returned 03305 * must be freed by the caller. 03306 */ 03307 xmlChar * 03308 xmlCatalogResolveSystem(const xmlChar *sysID) { 03309 xmlChar *ret; 03310 03311 if (!xmlCatalogInitialized) 03312 xmlInitializeCatalog(); 03313 03314 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID); 03315 return(ret); 03316 } 03317 03318 /** 03319 * xmlCatalogResolvePublic: 03320 * @pubID: the public ID string 03321 * 03322 * Try to lookup the catalog reference associated to a public ID 03323 * 03324 * Returns the resource if found or NULL otherwise, the value returned 03325 * must be freed by the caller. 03326 */ 03327 xmlChar * 03328 xmlCatalogResolvePublic(const xmlChar *pubID) { 03329 xmlChar *ret; 03330 03331 if (!xmlCatalogInitialized) 03332 xmlInitializeCatalog(); 03333 03334 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID); 03335 return(ret); 03336 } 03337 03338 /** 03339 * xmlCatalogResolve: 03340 * @pubID: the public ID string 03341 * @sysID: the system ID string 03342 * 03343 * Do a complete resolution lookup of an External Identifier 03344 * 03345 * Returns the URI of the resource or NULL if not found, it must be freed 03346 * by the caller. 03347 */ 03348 xmlChar * 03349 xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) { 03350 xmlChar *ret; 03351 03352 if (!xmlCatalogInitialized) 03353 xmlInitializeCatalog(); 03354 03355 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID); 03356 return(ret); 03357 } 03358 03359 /** 03360 * xmlCatalogResolveURI: 03361 * @URI: the URI 03362 * 03363 * Do a complete resolution lookup of an URI 03364 * 03365 * Returns the URI of the resource or NULL if not found, it must be freed 03366 * by the caller. 03367 */ 03368 xmlChar * 03369 xmlCatalogResolveURI(const xmlChar *URI) { 03370 xmlChar *ret; 03371 03372 if (!xmlCatalogInitialized) 03373 xmlInitializeCatalog(); 03374 03375 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI); 03376 return(ret); 03377 } 03378 03379 #ifdef LIBXML_OUTPUT_ENABLED 03380 /** 03381 * xmlCatalogDump: 03382 * @out: the file. 03383 * 03384 * Dump all the global catalog content to the given file. 03385 */ 03386 void 03387 xmlCatalogDump(FILE *out) { 03388 if (out == NULL) 03389 return; 03390 03391 if (!xmlCatalogInitialized) 03392 xmlInitializeCatalog(); 03393 03394 xmlACatalogDump(xmlDefaultCatalog, out); 03395 } 03396 #endif /* LIBXML_OUTPUT_ENABLED */ 03397 03398 /** 03399 * xmlCatalogAdd: 03400 * @type: the type of record to add to the catalog 03401 * @orig: the system, public or prefix to match 03402 * @replace: the replacement value for the match 03403 * 03404 * Add an entry in the catalog, it may overwrite existing but 03405 * different entries. 03406 * If called before any other catalog routine, allows to override the 03407 * default shared catalog put in place by xmlInitializeCatalog(); 03408 * 03409 * Returns 0 if successful, -1 otherwise 03410 */ 03411 int 03412 xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) { 03413 int res = -1; 03414 03415 if (!xmlCatalogInitialized) 03416 xmlInitializeCatalogData(); 03417 03418 xmlRMutexLock(xmlCatalogMutex); 03419 /* 03420 * Specific case where one want to override the default catalog 03421 * put in place by xmlInitializeCatalog(); 03422 */ 03423 if ((xmlDefaultCatalog == NULL) && 03424 (xmlStrEqual(type, BAD_CAST "catalog"))) { 03425 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, 03426 xmlCatalogDefaultPrefer); 03427 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, 03428 orig, NULL, xmlCatalogDefaultPrefer, NULL); 03429 03430 xmlRMutexUnlock(xmlCatalogMutex); 03431 return(0); 03432 } 03433 03434 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace); 03435 xmlRMutexUnlock(xmlCatalogMutex); 03436 return(res); 03437 } 03438 03439 /** 03440 * xmlCatalogRemove: 03441 * @value: the value to remove 03442 * 03443 * Remove an entry from the catalog 03444 * 03445 * Returns the number of entries removed if successful, -1 otherwise 03446 */ 03447 int 03448 xmlCatalogRemove(const xmlChar *value) { 03449 int res; 03450 03451 if (!xmlCatalogInitialized) 03452 xmlInitializeCatalog(); 03453 03454 xmlRMutexLock(xmlCatalogMutex); 03455 res = xmlACatalogRemove(xmlDefaultCatalog, value); 03456 xmlRMutexUnlock(xmlCatalogMutex); 03457 return(res); 03458 } 03459 03460 /** 03461 * xmlCatalogConvert: 03462 * 03463 * Convert all the SGML catalog entries as XML ones 03464 * 03465 * Returns the number of entries converted if successful, -1 otherwise 03466 */ 03467 int 03468 xmlCatalogConvert(void) { 03469 int res = -1; 03470 03471 if (!xmlCatalogInitialized) 03472 xmlInitializeCatalog(); 03473 03474 xmlRMutexLock(xmlCatalogMutex); 03475 res = xmlConvertSGMLCatalog(xmlDefaultCatalog); 03476 xmlRMutexUnlock(xmlCatalogMutex); 03477 return(res); 03478 } 03479 03480 /************************************************************************ 03481 * * 03482 * Public interface manipulating the common preferences * 03483 * * 03484 ************************************************************************/ 03485 03486 /** 03487 * xmlCatalogGetDefaults: 03488 * 03489 * Used to get the user preference w.r.t. to what catalogs should 03490 * be accepted 03491 * 03492 * Returns the current xmlCatalogAllow value 03493 */ 03494 xmlCatalogAllow 03495 xmlCatalogGetDefaults(void) { 03496 return(xmlCatalogDefaultAllow); 03497 } 03498 03499 /** 03500 * xmlCatalogSetDefaults: 03501 * @allow: what catalogs should be accepted 03502 * 03503 * Used to set the user preference w.r.t. to what catalogs should 03504 * be accepted 03505 */ 03506 void 03507 xmlCatalogSetDefaults(xmlCatalogAllow allow) { 03508 if (xmlDebugCatalogs) { 03509 switch (allow) { 03510 case XML_CATA_ALLOW_NONE: 03511 xmlGenericError(xmlGenericErrorContext, 03512 "Disabling catalog usage\n"); 03513 break; 03514 case XML_CATA_ALLOW_GLOBAL: 03515 xmlGenericError(xmlGenericErrorContext, 03516 "Allowing only global catalogs\n"); 03517 break; 03518 case XML_CATA_ALLOW_DOCUMENT: 03519 xmlGenericError(xmlGenericErrorContext, 03520 "Allowing only catalogs from the document\n"); 03521 break; 03522 case XML_CATA_ALLOW_ALL: 03523 xmlGenericError(xmlGenericErrorContext, 03524 "Allowing all catalogs\n"); 03525 break; 03526 } 03527 } 03528 xmlCatalogDefaultAllow = allow; 03529 } 03530 03531 /** 03532 * xmlCatalogSetDefaultPrefer: 03533 * @prefer: the default preference for delegation 03534 * 03535 * Allows to set the preference between public and system for deletion 03536 * in XML Catalog resolution. C.f. section 4.1.1 of the spec 03537 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM 03538 * 03539 * Returns the previous value of the default preference for delegation 03540 */ 03541 xmlCatalogPrefer 03542 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) { 03543 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer; 03544 03545 if (prefer == XML_CATA_PREFER_NONE) 03546 return(ret); 03547 03548 if (xmlDebugCatalogs) { 03549 switch (prefer) { 03550 case XML_CATA_PREFER_PUBLIC: 03551 xmlGenericError(xmlGenericErrorContext, 03552 "Setting catalog preference to PUBLIC\n"); 03553 break; 03554 case XML_CATA_PREFER_SYSTEM: 03555 xmlGenericError(xmlGenericErrorContext, 03556 "Setting catalog preference to SYSTEM\n"); 03557 break; 03558 default: 03559 return(ret); 03560 } 03561 } 03562 xmlCatalogDefaultPrefer = prefer; 03563 return(ret); 03564 } 03565 03566 /** 03567 * xmlCatalogSetDebug: 03568 * @level: the debug level of catalogs required 03569 * 03570 * Used to set the debug level for catalog operation, 0 disable 03571 * debugging, 1 enable it 03572 * 03573 * Returns the previous value of the catalog debugging level 03574 */ 03575 int 03576 xmlCatalogSetDebug(int level) { 03577 int ret = xmlDebugCatalogs; 03578 03579 if (level <= 0) 03580 xmlDebugCatalogs = 0; 03581 else 03582 xmlDebugCatalogs = level; 03583 return(ret); 03584 } 03585 03586 /************************************************************************ 03587 * * 03588 * Minimal interfaces used for per-document catalogs by the parser * 03589 * * 03590 ************************************************************************/ 03591 03592 /** 03593 * xmlCatalogFreeLocal: 03594 * @catalogs: a document's list of catalogs 03595 * 03596 * Free up the memory associated to the catalog list 03597 */ 03598 void 03599 xmlCatalogFreeLocal(void *catalogs) { 03600 xmlCatalogEntryPtr catal; 03601 03602 if (!xmlCatalogInitialized) 03603 xmlInitializeCatalog(); 03604 03605 catal = (xmlCatalogEntryPtr) catalogs; 03606 if (catal != NULL) 03607 xmlFreeCatalogEntryList(catal); 03608 } 03609 03610 03611 /** 03612 * xmlCatalogAddLocal: 03613 * @catalogs: a document's list of catalogs 03614 * @URL: the URL to a new local catalog 03615 * 03616 * Add the new entry to the catalog list 03617 * 03618 * Returns the updated list 03619 */ 03620 void * 03621 xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) { 03622 xmlCatalogEntryPtr catal, add; 03623 03624 if (!xmlCatalogInitialized) 03625 xmlInitializeCatalog(); 03626 03627 if (URL == NULL) 03628 return(catalogs); 03629 03630 if (xmlDebugCatalogs) 03631 xmlGenericError(xmlGenericErrorContext, 03632 "Adding document catalog %s\n", URL); 03633 03634 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL, 03635 xmlCatalogDefaultPrefer, NULL); 03636 if (add == NULL) 03637 return(catalogs); 03638 03639 catal = (xmlCatalogEntryPtr) catalogs; 03640 if (catal == NULL) 03641 return((void *) add); 03642 03643 while (catal->next != NULL) 03644 catal = catal->next; 03645 catal->next = add; 03646 return(catalogs); 03647 } 03648 03649 /** 03650 * xmlCatalogLocalResolve: 03651 * @catalogs: a document's list of catalogs 03652 * @pubID: the public ID string 03653 * @sysID: the system ID string 03654 * 03655 * Do a complete resolution lookup of an External Identifier using a 03656 * document's private catalog list 03657 * 03658 * Returns the URI of the resource or NULL if not found, it must be freed 03659 * by the caller. 03660 */ 03661 xmlChar * 03662 xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID, 03663 const xmlChar *sysID) { 03664 xmlCatalogEntryPtr catal; 03665 xmlChar *ret; 03666 03667 if (!xmlCatalogInitialized) 03668 xmlInitializeCatalog(); 03669 03670 if ((pubID == NULL) && (sysID == NULL)) 03671 return(NULL); 03672 03673 if (xmlDebugCatalogs) { 03674 if ((pubID != NULL) && (sysID != NULL)) { 03675 xmlGenericError(xmlGenericErrorContext, 03676 "Local Resolve: pubID %s sysID %s\n", pubID, sysID); 03677 } else if (pubID != NULL) { 03678 xmlGenericError(xmlGenericErrorContext, 03679 "Local Resolve: pubID %s\n", pubID); 03680 } else { 03681 xmlGenericError(xmlGenericErrorContext, 03682 "Local Resolve: sysID %s\n", sysID); 03683 } 03684 } 03685 03686 catal = (xmlCatalogEntryPtr) catalogs; 03687 if (catal == NULL) 03688 return(NULL); 03689 ret = xmlCatalogListXMLResolve(catal, pubID, sysID); 03690 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) 03691 return(ret); 03692 return(NULL); 03693 } 03694 03695 /** 03696 * xmlCatalogLocalResolveURI: 03697 * @catalogs: a document's list of catalogs 03698 * @URI: the URI 03699 * 03700 * Do a complete resolution lookup of an URI using a 03701 * document's private catalog list 03702 * 03703 * Returns the URI of the resource or NULL if not found, it must be freed 03704 * by the caller. 03705 */ 03706 xmlChar * 03707 xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) { 03708 xmlCatalogEntryPtr catal; 03709 xmlChar *ret; 03710 03711 if (!xmlCatalogInitialized) 03712 xmlInitializeCatalog(); 03713 03714 if (URI == NULL) 03715 return(NULL); 03716 03717 if (xmlDebugCatalogs) 03718 xmlGenericError(xmlGenericErrorContext, 03719 "Resolve URI %s\n", URI); 03720 03721 catal = (xmlCatalogEntryPtr) catalogs; 03722 if (catal == NULL) 03723 return(NULL); 03724 ret = xmlCatalogListXMLResolveURI(catal, URI); 03725 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) 03726 return(ret); 03727 return(NULL); 03728 } 03729 03730 /************************************************************************ 03731 * * 03732 * Deprecated interfaces * 03733 * * 03734 ************************************************************************/ 03735 /** 03736 * xmlCatalogGetSystem: 03737 * @sysID: the system ID string 03738 * 03739 * Try to lookup the catalog reference associated to a system ID 03740 * DEPRECATED, use xmlCatalogResolveSystem() 03741 * 03742 * Returns the resource if found or NULL otherwise. 03743 */ 03744 const xmlChar * 03745 xmlCatalogGetSystem(const xmlChar *sysID) { 03746 xmlChar *ret; 03747 static xmlChar result[1000]; 03748 static int msg = 0; 03749 03750 if (!xmlCatalogInitialized) 03751 xmlInitializeCatalog(); 03752 03753 if (msg == 0) { 03754 xmlGenericError(xmlGenericErrorContext, 03755 "Use of deprecated xmlCatalogGetSystem() call\n"); 03756 msg++; 03757 } 03758 03759 if (sysID == NULL) 03760 return(NULL); 03761 03762 /* 03763 * Check first the XML catalogs 03764 */ 03765 if (xmlDefaultCatalog != NULL) { 03766 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID); 03767 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { 03768 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); 03769 result[sizeof(result) - 1] = 0; 03770 return(result); 03771 } 03772 } 03773 03774 if (xmlDefaultCatalog != NULL) 03775 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID)); 03776 return(NULL); 03777 } 03778 03779 /** 03780 * xmlCatalogGetPublic: 03781 * @pubID: the public ID string 03782 * 03783 * Try to lookup the catalog reference associated to a public ID 03784 * DEPRECATED, use xmlCatalogResolvePublic() 03785 * 03786 * Returns the resource if found or NULL otherwise. 03787 */ 03788 const xmlChar * 03789 xmlCatalogGetPublic(const xmlChar *pubID) { 03790 xmlChar *ret; 03791 static xmlChar result[1000]; 03792 static int msg = 0; 03793 03794 if (!xmlCatalogInitialized) 03795 xmlInitializeCatalog(); 03796 03797 if (msg == 0) { 03798 xmlGenericError(xmlGenericErrorContext, 03799 "Use of deprecated xmlCatalogGetPublic() call\n"); 03800 msg++; 03801 } 03802 03803 if (pubID == NULL) 03804 return(NULL); 03805 03806 /* 03807 * Check first the XML catalogs 03808 */ 03809 if (xmlDefaultCatalog != NULL) { 03810 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL); 03811 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { 03812 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); 03813 result[sizeof(result) - 1] = 0; 03814 return(result); 03815 } 03816 } 03817 03818 if (xmlDefaultCatalog != NULL) 03819 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID)); 03820 return(NULL); 03821 } 03822 03823 #define bottom_catalog 03824 #include "elfgcchack.h" 03825 #endif /* LIBXML_CATALOG_ENABLED */ 03826
Generated on Thu Jul 14 2022 13:59:07 by
1.7.2