2 * catalog.c: set of generic Catalog related routines
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
7 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
10 * See Copyright for the status of this software.
12 * Daniel.Veillard@imag.fr
18 #ifdef LIBXML_CATALOG_ENABLED
19 #ifdef HAVE_SYS_TYPES_H
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_STAT_H
35 #include <libxml/xmlmemory.h>
36 #include <libxml/hash.h>
37 #include <libxml/uri.h>
38 #include <libxml/parserInternals.h>
39 #include <libxml/catalog.h>
40 #include <libxml/xmlerror.h>
41 #include <libxml/threads.h>
42 #include <libxml/globals.h>
44 #define MAX_DELEGATE 50
45 #define MAX_CATAL_DEPTH 50
48 # define PATH_SEAPARATOR ';'
50 # define PATH_SEAPARATOR ':'
56 * macro to flag unimplemented blocks
57 * XML_CATALOG_PREFER user env to select between system/public prefered
58 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
59 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
60 *> values "system" and "public". I have made the default be "system" to
64 xmlGenericError(xmlGenericErrorContext, \
65 "Unimplemented block at %s:%d\n", \
68 #define XML_URN_PUBID "urn:publicid:"
69 #define XML_CATAL_BREAK ((xmlChar *) -1)
70 #ifndef XML_XML_DEFAULT_CATALOG
71 #define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
73 #ifndef XML_SGML_DEFAULT_CATALOG
74 #define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
77 #if defined(_WIN32) && defined(_MSC_VER)
78 #undef XML_XML_DEFAULT_CATALOG
79 static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
80 #if defined(_WIN32_WCE)
81 /* Windows CE don't have a A variant */
82 #define GetModuleHandleA GetModuleHandle
83 #define GetModuleFileNameA GetModuleFileName
85 void* __stdcall GetModuleHandleA(const char*);
86 unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
90 static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
91 static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
93 /************************************************************************
95 * Types, all private *
97 ************************************************************************/
100 XML_CATA_REMOVED = -1,
103 XML_CATA_BROKEN_CATALOG,
104 XML_CATA_NEXT_CATALOG,
108 XML_CATA_REWRITE_SYSTEM,
109 XML_CATA_DELEGATE_PUBLIC,
110 XML_CATA_DELEGATE_SYSTEM,
112 XML_CATA_REWRITE_URI,
113 XML_CATA_DELEGATE_URI,
126 } xmlCatalogEntryType;
128 typedef struct _xmlCatalogEntry xmlCatalogEntry;
129 typedef xmlCatalogEntry *xmlCatalogEntryPtr;
130 struct _xmlCatalogEntry {
131 struct _xmlCatalogEntry *next;
132 struct _xmlCatalogEntry *parent;
133 struct _xmlCatalogEntry *children;
134 xmlCatalogEntryType type;
137 xmlChar *URL; /* The expanded URL using the base */
138 xmlCatalogPrefer prefer;
141 struct _xmlCatalogEntry *group;
145 XML_XML_CATALOG_TYPE = 1,
146 XML_SGML_CATALOG_TYPE
149 #define XML_MAX_SGML_CATA_DEPTH 10
151 xmlCatalogType type; /* either XML or SGML */
154 * SGML Catalogs are stored as a simple hash table of catalog entries
155 * Catalog stack to check against overflows when building the
158 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
159 int catalNr; /* Number of current catal streams */
160 int catalMax; /* Max number of catal streams */
161 xmlHashTablePtr sgml;
164 * XML Catalogs are stored as a tree of Catalog entries
166 xmlCatalogPrefer prefer;
167 xmlCatalogEntryPtr xml;
170 /************************************************************************
174 ************************************************************************/
177 * Those are preferences
179 static int xmlDebugCatalogs = 0; /* used for debugging */
180 static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
181 static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
184 * Hash table containing all the trees of XML catalogs parsed by
187 static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
190 * The default catalog in use by the application
192 static xmlCatalogPtr xmlDefaultCatalog = NULL;
195 * A mutex for modifying the shared global catalog(s)
196 * xmlDefaultCatalog tree.
197 * It also protects xmlCatalogXMLFiles
198 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
200 static xmlRMutexPtr xmlCatalogMutex = NULL;
203 * Whether the catalog support was initialized.
205 static int xmlCatalogInitialized = 0;
207 /************************************************************************
209 * Catalog error handlers *
211 ************************************************************************/
214 * xmlCatalogErrMemory:
215 * @extra: extra informations
217 * Handle an out of memory condition
220 xmlCatalogErrMemory(const char *extra)
222 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
223 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
224 extra, NULL, NULL, 0, 0,
225 "Memory allocation failed : %s\n", extra);
230 * @catal: the Catalog entry
231 * @node: the context node
232 * @msg: the error message
233 * @extra: extra informations
235 * Handle a catalog error
238 xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
239 const char *msg, const xmlChar *str1, const xmlChar *str2,
242 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
243 error, XML_ERR_ERROR, NULL, 0,
244 (const char *) str1, (const char *) str2,
245 (const char *) str3, 0, 0,
246 msg, str1, str2, str3);
250 /************************************************************************
252 * Allocation and Freeing *
254 ************************************************************************/
257 * xmlNewCatalogEntry:
258 * @type: type of entry
259 * @name: name of the entry
260 * @value: value of the entry
261 * @prefer: the PUBLIC vs. SYSTEM current preference value
262 * @group: for members of a group, the group entry
264 * create a new Catalog entry, this type is shared both by XML and
265 * SGML catalogs, but the acceptable types values differs.
267 * Returns the xmlCatalogEntryPtr or NULL in case of error
269 static xmlCatalogEntryPtr
270 xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
271 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
272 xmlCatalogEntryPtr group) {
273 xmlCatalogEntryPtr ret;
274 xmlChar *normid = NULL;
276 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
278 xmlCatalogErrMemory("allocating catalog entry");
283 ret->children = NULL;
285 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
286 normid = xmlCatalogNormalizePublic(name);
288 name = (*normid != 0 ? normid : NULL);
291 ret->name = xmlStrdup(name);
297 ret->value = xmlStrdup(value);
303 ret->URL = xmlStrdup(URL);
306 ret->prefer = prefer;
314 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
317 * xmlFreeCatalogEntry:
318 * @ret: a Catalog entry
320 * Free the memory allocated to a Catalog entry
323 xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
327 * Entries stored in the file hash must be deallocated
328 * only by the file hash cleaner !
330 if (ret->dealloc == 1)
333 if (xmlDebugCatalogs) {
334 if (ret->name != NULL)
335 xmlGenericError(xmlGenericErrorContext,
336 "Free catalog entry %s\n", ret->name);
337 else if (ret->value != NULL)
338 xmlGenericError(xmlGenericErrorContext,
339 "Free catalog entry %s\n", ret->value);
341 xmlGenericError(xmlGenericErrorContext,
342 "Free catalog entry\n");
345 if (ret->name != NULL)
347 if (ret->value != NULL)
349 if (ret->URL != NULL)
355 * xmlFreeCatalogEntryList:
356 * @ret: a Catalog entry list
358 * Free the memory allocated to a full chained list of Catalog entries
361 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
362 xmlCatalogEntryPtr next;
364 while (ret != NULL) {
366 xmlFreeCatalogEntry(ret);
372 * xmlFreeCatalogHashEntryList:
373 * @ret: a Catalog entry list
375 * Free the memory allocated to list of Catalog entries from the
379 xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
380 xmlCatalogEntryPtr children, next;
385 children = catal->children;
386 while (children != NULL) {
387 next = children->next;
388 children->dealloc = 0;
389 children->children = NULL;
390 xmlFreeCatalogEntry(children);
394 xmlFreeCatalogEntry(catal);
398 * xmlCreateNewCatalog:
399 * @type: type of catalog
400 * @prefer: the PUBLIC vs. SYSTEM current preference value
402 * create a new Catalog, this type is shared both by XML and
403 * SGML catalogs, but the acceptable types values differs.
405 * Returns the xmlCatalogPtr or NULL in case of error
408 xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
411 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
413 xmlCatalogErrMemory("allocating catalog");
416 memset(ret, 0, sizeof(xmlCatalog));
419 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
420 ret->prefer = prefer;
421 if (ret->type == XML_SGML_CATALOG_TYPE)
422 ret->sgml = xmlHashCreate(10);
430 * Free the memory allocated to a Catalog
433 xmlFreeCatalog(xmlCatalogPtr catal) {
436 if (catal->xml != NULL)
437 xmlFreeCatalogEntryList(catal->xml);
438 if (catal->sgml != NULL)
439 xmlHashFree(catal->sgml,
440 (xmlHashDeallocator) xmlFreeCatalogEntry);
444 /************************************************************************
446 * Serializing Catalogs *
448 ************************************************************************/
450 #ifdef LIBXML_OUTPUT_ENABLED
452 * xmlCatalogDumpEntry:
453 * @entry: the catalog entry
456 * Serialize an SGML Catalog entry
459 xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
460 if ((entry == NULL) || (out == NULL))
462 switch (entry->type) {
463 case SGML_CATA_ENTITY:
464 fprintf(out, "ENTITY "); break;
465 case SGML_CATA_PENTITY:
466 fprintf(out, "ENTITY %%"); break;
467 case SGML_CATA_DOCTYPE:
468 fprintf(out, "DOCTYPE "); break;
469 case SGML_CATA_LINKTYPE:
470 fprintf(out, "LINKTYPE "); break;
471 case SGML_CATA_NOTATION:
472 fprintf(out, "NOTATION "); break;
473 case SGML_CATA_PUBLIC:
474 fprintf(out, "PUBLIC "); break;
475 case SGML_CATA_SYSTEM:
476 fprintf(out, "SYSTEM "); break;
477 case SGML_CATA_DELEGATE:
478 fprintf(out, "DELEGATE "); break;
480 fprintf(out, "BASE "); break;
481 case SGML_CATA_CATALOG:
482 fprintf(out, "CATALOG "); break;
483 case SGML_CATA_DOCUMENT:
484 fprintf(out, "DOCUMENT "); break;
485 case SGML_CATA_SGMLDECL:
486 fprintf(out, "SGMLDECL "); break;
490 switch (entry->type) {
491 case SGML_CATA_ENTITY:
492 case SGML_CATA_PENTITY:
493 case SGML_CATA_DOCTYPE:
494 case SGML_CATA_LINKTYPE:
495 case SGML_CATA_NOTATION:
496 fprintf(out, "%s", (const char *) entry->name); break;
497 case SGML_CATA_PUBLIC:
498 case SGML_CATA_SYSTEM:
499 case SGML_CATA_SGMLDECL:
500 case SGML_CATA_DOCUMENT:
501 case SGML_CATA_CATALOG:
503 case SGML_CATA_DELEGATE:
504 fprintf(out, "\"%s\"", entry->name); break;
508 switch (entry->type) {
509 case SGML_CATA_ENTITY:
510 case SGML_CATA_PENTITY:
511 case SGML_CATA_DOCTYPE:
512 case SGML_CATA_LINKTYPE:
513 case SGML_CATA_NOTATION:
514 case SGML_CATA_PUBLIC:
515 case SGML_CATA_SYSTEM:
516 case SGML_CATA_DELEGATE:
517 fprintf(out, " \"%s\"", entry->value); break;
525 * xmlDumpXMLCatalogNode:
526 * @catal: top catalog entry
527 * @catalog: pointer to the xml tree
528 * @doc: the containing document
529 * @ns: the current namespace
530 * @cgroup: group node for group members
532 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
535 static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
536 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
538 xmlCatalogEntryPtr cur;
540 * add all the catalog entries
543 while (cur != NULL) {
544 if (cur->group == cgroup) {
546 case XML_CATA_REMOVED:
548 case XML_CATA_BROKEN_CATALOG:
549 case XML_CATA_CATALOG:
555 case XML_CATA_NEXT_CATALOG:
556 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
557 xmlSetProp(node, BAD_CAST "catalog", cur->value);
558 xmlAddChild(catalog, node);
563 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
564 xmlSetProp(node, BAD_CAST "id", cur->name);
565 if (cur->value != NULL) {
567 xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
569 xmlSetNsProp(node, xns, BAD_CAST "base",
572 switch (cur->prefer) {
573 case XML_CATA_PREFER_NONE:
575 case XML_CATA_PREFER_PUBLIC:
576 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
578 case XML_CATA_PREFER_SYSTEM:
579 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
582 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
583 xmlAddChild(catalog, node);
585 case XML_CATA_PUBLIC:
586 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
587 xmlSetProp(node, BAD_CAST "publicId", cur->name);
588 xmlSetProp(node, BAD_CAST "uri", cur->value);
589 xmlAddChild(catalog, node);
591 case XML_CATA_SYSTEM:
592 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
593 xmlSetProp(node, BAD_CAST "systemId", cur->name);
594 xmlSetProp(node, BAD_CAST "uri", cur->value);
595 xmlAddChild(catalog, node);
597 case XML_CATA_REWRITE_SYSTEM:
598 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
599 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
600 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
601 xmlAddChild(catalog, node);
603 case XML_CATA_DELEGATE_PUBLIC:
604 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
605 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
606 xmlSetProp(node, BAD_CAST "catalog", cur->value);
607 xmlAddChild(catalog, node);
609 case XML_CATA_DELEGATE_SYSTEM:
610 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
611 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
612 xmlSetProp(node, BAD_CAST "catalog", cur->value);
613 xmlAddChild(catalog, node);
616 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
617 xmlSetProp(node, BAD_CAST "name", cur->name);
618 xmlSetProp(node, BAD_CAST "uri", cur->value);
619 xmlAddChild(catalog, node);
621 case XML_CATA_REWRITE_URI:
622 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
623 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
624 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
625 xmlAddChild(catalog, node);
627 case XML_CATA_DELEGATE_URI:
628 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
629 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
630 xmlSetProp(node, BAD_CAST "catalog", cur->value);
631 xmlAddChild(catalog, node);
633 case SGML_CATA_SYSTEM:
634 case SGML_CATA_PUBLIC:
635 case SGML_CATA_ENTITY:
636 case SGML_CATA_PENTITY:
637 case SGML_CATA_DOCTYPE:
638 case SGML_CATA_LINKTYPE:
639 case SGML_CATA_NOTATION:
640 case SGML_CATA_DELEGATE:
642 case SGML_CATA_CATALOG:
643 case SGML_CATA_DOCUMENT:
644 case SGML_CATA_SGMLDECL:
653 xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
659 xmlOutputBufferPtr buf;
664 doc = xmlNewDoc(NULL);
667 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
668 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
669 BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
671 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
673 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
678 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
679 if (catalog == NULL) {
685 xmlAddChild((xmlNodePtr) doc, catalog);
687 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
692 buf = xmlOutputBufferCreateFile(out, NULL);
697 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
706 #endif /* LIBXML_OUTPUT_ENABLED */
708 /************************************************************************
710 * Converting SGML Catalogs to XML *
712 ************************************************************************/
715 * xmlCatalogConvertEntry:
717 * @catal: pointer to the catalog being converted
719 * Convert one entry from the catalog
722 xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
723 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
724 (catal->xml == NULL))
726 switch (entry->type) {
727 case SGML_CATA_ENTITY:
728 entry->type = XML_CATA_PUBLIC;
730 case SGML_CATA_PENTITY:
731 entry->type = XML_CATA_PUBLIC;
733 case SGML_CATA_DOCTYPE:
734 entry->type = XML_CATA_PUBLIC;
736 case SGML_CATA_LINKTYPE:
737 entry->type = XML_CATA_PUBLIC;
739 case SGML_CATA_NOTATION:
740 entry->type = XML_CATA_PUBLIC;
742 case SGML_CATA_PUBLIC:
743 entry->type = XML_CATA_PUBLIC;
745 case SGML_CATA_SYSTEM:
746 entry->type = XML_CATA_SYSTEM;
748 case SGML_CATA_DELEGATE:
749 entry->type = XML_CATA_DELEGATE_PUBLIC;
751 case SGML_CATA_CATALOG:
752 entry->type = XML_CATA_CATALOG;
755 xmlHashRemoveEntry(catal->sgml, entry->name,
756 (xmlHashDeallocator) xmlFreeCatalogEntry);
760 * Conversion successful, remove from the SGML catalog
761 * and add it to the default XML one
763 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
764 entry->parent = catal->xml;
766 if (catal->xml->children == NULL)
767 catal->xml->children = entry;
769 xmlCatalogEntryPtr prev;
771 prev = catal->xml->children;
772 while (prev->next != NULL)
779 * xmlConvertSGMLCatalog:
780 * @catal: the catalog
782 * Convert all the SGML catalog entries as XML ones
784 * Returns the number of entries converted if successful, -1 otherwise
787 xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
789 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
792 if (xmlDebugCatalogs) {
793 xmlGenericError(xmlGenericErrorContext,
794 "Converting SGML catalog to XML\n");
796 xmlHashScan(catal->sgml,
797 (xmlHashScanner) xmlCatalogConvertEntry,
802 /************************************************************************
806 ************************************************************************/
809 * xmlCatalogUnWrapURN:
810 * @urn: an "urn:publicid:" to unwrap
812 * Expand the URN into the equivalent Public Identifier
814 * Returns the new identifier or NULL, the string must be deallocated
818 xmlCatalogUnWrapURN(const xmlChar *urn) {
819 xmlChar result[2000];
822 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
824 urn += sizeof(XML_URN_PUBID) - 1;
827 if (i > sizeof(result) - 4)
832 } else if (*urn == ':') {
836 } else if (*urn == ';') {
840 } else if (*urn == '%') {
841 if ((urn[1] == '2') && (urn[2] == 'B'))
843 else if ((urn[1] == '3') && (urn[2] == 'A'))
845 else if ((urn[1] == '2') && (urn[2] == 'F'))
847 else if ((urn[1] == '3') && (urn[2] == 'B'))
849 else if ((urn[1] == '2') && (urn[2] == '7'))
851 else if ((urn[1] == '3') && (urn[2] == 'F'))
853 else if ((urn[1] == '2') && (urn[2] == '3'))
855 else if ((urn[1] == '2') && (urn[2] == '5'))
870 return(xmlStrdup(result));
874 * xmlParseCatalogFile:
875 * @filename: the filename
877 * parse an XML file and build a tree. It's like xmlParseFile()
878 * except it bypass all catalog lookups.
880 * Returns the resulting document tree or NULL in case of error
884 xmlParseCatalogFile(const char *filename) {
886 xmlParserCtxtPtr ctxt;
887 char *directory = NULL;
888 xmlParserInputPtr inputStream;
889 xmlParserInputBufferPtr buf;
891 ctxt = xmlNewParserCtxt();
893 #ifdef LIBXML_SAX1_ENABLED
894 if (xmlDefaultSAXHandler.error != NULL) {
895 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
901 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
903 xmlFreeParserCtxt(ctxt);
907 inputStream = xmlNewInputStream(ctxt);
908 if (inputStream == NULL) {
909 xmlFreeParserCtxt(ctxt);
913 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
914 inputStream->buf = buf;
915 inputStream->base = inputStream->buf->buffer->content;
916 inputStream->cur = inputStream->buf->buffer->content;
918 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
920 inputPush(ctxt, inputStream);
921 if ((ctxt->directory == NULL) && (directory == NULL))
922 directory = xmlParserGetDirectory(filename);
923 if ((ctxt->directory == NULL) && (directory != NULL))
924 ctxt->directory = directory;
927 ctxt->loadsubset = 0;
931 xmlParseDocument(ctxt);
933 if (ctxt->wellFormed)
937 xmlFreeDoc(ctxt->myDoc);
940 xmlFreeParserCtxt(ctxt);
946 * xmlLoadFileContent:
947 * @filename: a file path
949 * Load a file content into memory.
951 * Returns a pointer to the 0 terminated string or NULL in case of error
954 xmlLoadFileContent(const char *filename)
969 if (filename == NULL)
973 if (stat(filename, &info) < 0)
978 if ((fd = open(filename, O_RDONLY)) < 0)
980 if ((fd = fopen(filename, "rb")) == NULL)
988 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
993 content = xmlMallocAtomic(size + 10);
994 if (content == NULL) {
995 xmlCatalogErrMemory("allocating catalog data");
999 len = read(fd, content, size);
1002 len = fread(content, 1, size, fd);
1015 * xmlCatalogNormalizePublic:
1016 * @pubID: the public ID string
1018 * Normalizes the Public Identifier
1020 * Implements 6.2. Public Identifier Normalization
1021 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1023 * Returns the new string or NULL, the string must be deallocated
1027 xmlCatalogNormalizePublic(const xmlChar *pubID)
1039 for (p = pubID;*p != 0 && ok;p++) {
1040 if (!xmlIsBlank_ch(*p))
1042 else if (*p == 0x20 && !white)
1047 if (ok && !white) /* is normalized */
1050 ret = xmlStrdup(pubID);
1053 for (p = pubID;*p != 0;p++) {
1054 if (xmlIsBlank_ch(*p)) {
1069 /************************************************************************
1071 * The XML Catalog parser *
1073 ************************************************************************/
1075 static xmlCatalogEntryPtr
1076 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
1078 xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1079 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
1081 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1082 const xmlChar *sysID);
1084 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1088 * xmlGetXMLCatalogEntryType:
1091 * lookup the internal type associated to an XML catalog entry name
1093 * Returns the type associated with that name
1095 static xmlCatalogEntryType
1096 xmlGetXMLCatalogEntryType(const xmlChar *name) {
1097 xmlCatalogEntryType type = XML_CATA_NONE;
1098 if (xmlStrEqual(name, (const xmlChar *) "system"))
1099 type = XML_CATA_SYSTEM;
1100 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1101 type = XML_CATA_PUBLIC;
1102 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1103 type = XML_CATA_REWRITE_SYSTEM;
1104 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1105 type = XML_CATA_DELEGATE_PUBLIC;
1106 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1107 type = XML_CATA_DELEGATE_SYSTEM;
1108 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1109 type = XML_CATA_URI;
1110 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1111 type = XML_CATA_REWRITE_URI;
1112 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1113 type = XML_CATA_DELEGATE_URI;
1114 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1115 type = XML_CATA_NEXT_CATALOG;
1116 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1117 type = XML_CATA_CATALOG;
1122 * xmlParseXMLCatalogOneNode:
1123 * @cur: the XML node
1124 * @type: the type of Catalog entry
1125 * @name: the name of the node
1126 * @attrName: the attribute holding the value
1127 * @uriAttrName: the attribute holding the URI-Reference
1128 * @prefer: the PUBLIC vs. SYSTEM current preference value
1129 * @cgroup: the group which includes this node
1131 * Finishes the examination of an XML tree node of a catalog and build
1132 * a Catalog entry from it.
1134 * Returns the new Catalog entry node or NULL in case of error.
1136 static xmlCatalogEntryPtr
1137 xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1138 const xmlChar *name, const xmlChar *attrName,
1139 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1140 xmlCatalogEntryPtr cgroup) {
1143 xmlChar *nameValue = NULL;
1144 xmlChar *base = NULL;
1145 xmlChar *URL = NULL;
1146 xmlCatalogEntryPtr ret = NULL;
1148 if (attrName != NULL) {
1149 nameValue = xmlGetProp(cur, attrName);
1150 if (nameValue == NULL) {
1151 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1152 "%s entry lacks '%s'\n", name, attrName, NULL);
1156 uriValue = xmlGetProp(cur, uriAttrName);
1157 if (uriValue == NULL) {
1158 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1159 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
1163 if (nameValue != NULL)
1165 if (uriValue != NULL)
1170 base = xmlNodeGetBase(cur->doc, cur);
1171 URL = xmlBuildURI(uriValue, base);
1173 if (xmlDebugCatalogs > 1) {
1174 if (nameValue != NULL)
1175 xmlGenericError(xmlGenericErrorContext,
1176 "Found %s: '%s' '%s'\n", name, nameValue, URL);
1178 xmlGenericError(xmlGenericErrorContext,
1179 "Found %s: '%s'\n", name, URL);
1181 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
1183 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
1184 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1186 if (nameValue != NULL)
1188 if (uriValue != NULL)
1198 * xmlParseXMLCatalogNode:
1199 * @cur: the XML node
1200 * @prefer: the PUBLIC vs. SYSTEM current preference value
1201 * @parent: the parent Catalog entry
1202 * @cgroup: the group which includes this node
1204 * Examines an XML tree node of a catalog and build
1205 * a Catalog entry from it adding it to its parent. The examination can
1209 xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1210 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
1212 xmlChar *base = NULL;
1213 xmlCatalogEntryPtr entry = NULL;
1217 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1219 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
1221 prop = xmlGetProp(cur, BAD_CAST "prefer");
1223 if (xmlStrEqual(prop, BAD_CAST "system")) {
1224 prefer = XML_CATA_PREFER_SYSTEM;
1225 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1226 prefer = XML_CATA_PREFER_PUBLIC;
1228 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1229 "Invalid value for prefer: '%s'\n",
1235 prop = xmlGetProp(cur, BAD_CAST "id");
1236 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1237 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
1239 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1240 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
1241 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
1242 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1243 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
1244 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
1245 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1246 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1247 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
1248 BAD_CAST "rewritePrefix", prefer, cgroup);
1249 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1250 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1251 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
1252 BAD_CAST "catalog", prefer, cgroup);
1253 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1254 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1255 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
1256 BAD_CAST "catalog", prefer, cgroup);
1257 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1258 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1259 BAD_CAST "uri", BAD_CAST "name",
1260 BAD_CAST "uri", prefer, cgroup);
1261 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1262 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1263 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
1264 BAD_CAST "rewritePrefix", prefer, cgroup);
1265 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1266 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1267 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
1268 BAD_CAST "catalog", prefer, cgroup);
1269 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1270 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1271 BAD_CAST "nextCatalog", NULL,
1272 BAD_CAST "catalog", prefer, cgroup);
1274 if (entry != NULL) {
1275 if (parent != NULL) {
1276 entry->parent = parent;
1277 if (parent->children == NULL)
1278 parent->children = entry;
1280 xmlCatalogEntryPtr prev;
1282 prev = parent->children;
1283 while (prev->next != NULL)
1288 if (entry->type == XML_CATA_GROUP) {
1290 * Recurse to propagate prefer to the subtree
1291 * (xml:base handling is automated)
1293 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1301 * xmlParseXMLCatalogNodeList:
1302 * @cur: the XML node list of siblings
1303 * @prefer: the PUBLIC vs. SYSTEM current preference value
1304 * @parent: the parent Catalog entry
1305 * @cgroup: the group which includes this list
1307 * Examines a list of XML sibling nodes of a catalog and build
1308 * a list of Catalog entry from it adding it to the parent.
1309 * The examination will recurse to examine node subtrees.
1312 xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1313 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
1314 while (cur != NULL) {
1315 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1316 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1317 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
1321 /* TODO: sort the list according to REWRITE lengths and prefer value */
1325 * xmlParseXMLCatalogFile:
1326 * @prefer: the PUBLIC vs. SYSTEM current preference value
1327 * @filename: the filename for the catalog
1329 * Parses the catalog file to extract the XML tree and then analyze the
1330 * tree to build a list of Catalog entries corresponding to this catalog
1332 * Returns the resulting Catalog entries list
1334 static xmlCatalogEntryPtr
1335 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1339 xmlCatalogEntryPtr parent = NULL;
1341 if (filename == NULL)
1344 doc = xmlParseCatalogFile((const char *) filename);
1346 if (xmlDebugCatalogs)
1347 xmlGenericError(xmlGenericErrorContext,
1348 "Failed to parse catalog %s\n", filename);
1352 if (xmlDebugCatalogs)
1353 xmlGenericError(xmlGenericErrorContext,
1354 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
1356 cur = xmlDocGetRootElement(doc);
1357 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1358 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1359 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1361 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1362 (const xmlChar *)filename, NULL, prefer, NULL);
1363 if (parent == NULL) {
1368 prop = xmlGetProp(cur, BAD_CAST "prefer");
1370 if (xmlStrEqual(prop, BAD_CAST "system")) {
1371 prefer = XML_CATA_PREFER_SYSTEM;
1372 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1373 prefer = XML_CATA_PREFER_PUBLIC;
1375 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1376 "Invalid value for prefer: '%s'\n",
1381 cur = cur->children;
1382 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
1384 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1385 "File %s is not an XML Catalog\n",
1386 filename, NULL, NULL);
1395 * xmlFetchXMLCatalogFile:
1396 * @catal: an existing but incomplete catalog entry
1398 * Fetch and parse the subcatalog referenced by an entry
1400 * Returns 0 in case of success, -1 otherwise
1403 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
1404 xmlCatalogEntryPtr doc;
1408 if (catal->URL == NULL)
1412 * lock the whole catalog for modification
1414 xmlRMutexLock(xmlCatalogMutex);
1415 if (catal->children != NULL) {
1416 /* Okay someone else did it in the meantime */
1417 xmlRMutexUnlock(xmlCatalogMutex);
1421 if (xmlCatalogXMLFiles != NULL) {
1422 doc = (xmlCatalogEntryPtr)
1423 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1425 if (xmlDebugCatalogs)
1426 xmlGenericError(xmlGenericErrorContext,
1427 "Found %s in file hash\n", catal->URL);
1429 if (catal->type == XML_CATA_CATALOG)
1430 catal->children = doc->children;
1432 catal->children = doc;
1434 xmlRMutexUnlock(xmlCatalogMutex);
1437 if (xmlDebugCatalogs)
1438 xmlGenericError(xmlGenericErrorContext,
1439 "%s not found in file hash\n", catal->URL);
1443 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1444 * use the existing catalog, there is no recursion allowed at
1447 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
1449 catal->type = XML_CATA_BROKEN_CATALOG;
1450 xmlRMutexUnlock(xmlCatalogMutex);
1454 if (catal->type == XML_CATA_CATALOG)
1455 catal->children = doc->children;
1457 catal->children = doc;
1461 if (xmlCatalogXMLFiles == NULL)
1462 xmlCatalogXMLFiles = xmlHashCreate(10);
1463 if (xmlCatalogXMLFiles != NULL) {
1464 if (xmlDebugCatalogs)
1465 xmlGenericError(xmlGenericErrorContext,
1466 "%s added to file hash\n", catal->URL);
1467 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
1469 xmlRMutexUnlock(xmlCatalogMutex);
1473 /************************************************************************
1475 * XML Catalog handling *
1477 ************************************************************************/
1481 * @catal: top of an XML catalog
1482 * @type: the type of record to add to the catalog
1483 * @orig: the system, public or prefix to match (or NULL)
1484 * @replace: the replacement value for the match
1486 * Add an entry in the XML catalog, it may overwrite existing but
1487 * different entries.
1489 * Returns 0 if successful, -1 otherwise
1492 xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1493 const xmlChar *orig, const xmlChar *replace) {
1494 xmlCatalogEntryPtr cur;
1495 xmlCatalogEntryType typ;
1498 if ((catal == NULL) ||
1499 ((catal->type != XML_CATA_CATALOG) &&
1500 (catal->type != XML_CATA_BROKEN_CATALOG)))
1502 if (catal->children == NULL) {
1503 xmlFetchXMLCatalogFile(catal);
1505 if (catal->children == NULL)
1508 typ = xmlGetXMLCatalogEntryType(type);
1509 if (typ == XML_CATA_NONE) {
1510 if (xmlDebugCatalogs)
1511 xmlGenericError(xmlGenericErrorContext,
1512 "Failed to add unknown element %s to catalog\n", type);
1516 cur = catal->children;
1518 * Might be a simple "update in place"
1521 while (cur != NULL) {
1522 if ((orig != NULL) && (cur->type == typ) &&
1523 (xmlStrEqual(orig, cur->name))) {
1524 if (xmlDebugCatalogs)
1525 xmlGenericError(xmlGenericErrorContext,
1526 "Updating element %s to catalog\n", type);
1527 if (cur->value != NULL)
1528 xmlFree(cur->value);
1529 if (cur->URL != NULL)
1531 cur->value = xmlStrdup(replace);
1532 cur->URL = xmlStrdup(replace);
1535 if (cur->next == NULL)
1540 if (xmlDebugCatalogs)
1541 xmlGenericError(xmlGenericErrorContext,
1542 "Adding element %s to catalog\n", type);
1544 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1545 NULL, catal->prefer, NULL);
1547 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1548 NULL, catal->prefer, NULL);
1550 catal->type = XML_CATA_CATALOG;
1551 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1553 cur->children = catal->children;
1561 * @catal: top of an XML catalog
1562 * @value: the value to remove from the catalog
1564 * Remove entries in the XML catalog where the value or the URI
1565 * is equal to @value
1567 * Returns the number of entries removed if successful, -1 otherwise
1570 xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1571 xmlCatalogEntryPtr cur;
1574 if ((catal == NULL) ||
1575 ((catal->type != XML_CATA_CATALOG) &&
1576 (catal->type != XML_CATA_BROKEN_CATALOG)))
1580 if (catal->children == NULL) {
1581 xmlFetchXMLCatalogFile(catal);
1587 cur = catal->children;
1588 while (cur != NULL) {
1589 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1590 (xmlStrEqual(value, cur->value))) {
1591 if (xmlDebugCatalogs) {
1592 if (cur->name != NULL)
1593 xmlGenericError(xmlGenericErrorContext,
1594 "Removing element %s from catalog\n", cur->name);
1596 xmlGenericError(xmlGenericErrorContext,
1597 "Removing element %s from catalog\n", cur->value);
1599 cur->type = XML_CATA_REMOVED;
1607 * xmlCatalogXMLResolve:
1608 * @catal: a catalog list
1609 * @pubID: the public ID string
1610 * @sysID: the system ID string
1612 * Do a complete resolution lookup of an External Identifier for a
1613 * list of catalog entries.
1615 * Implements (or tries to) 7.1. External Identifier Resolution
1616 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1618 * Returns the URI of the resource or NULL if not found
1621 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1622 const xmlChar *sysID) {
1623 xmlChar *ret = NULL;
1624 xmlCatalogEntryPtr cur;
1625 int haveDelegate = 0;
1629 * protection against loops
1631 if (catal->depth > MAX_CATAL_DEPTH) {
1632 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1633 "Detected recursion in catalog %s\n",
1634 catal->name, NULL, NULL);
1640 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1642 if (sysID != NULL) {
1643 xmlCatalogEntryPtr rewrite = NULL;
1644 int lenrewrite = 0, len;
1647 while (cur != NULL) {
1648 switch (cur->type) {
1649 case XML_CATA_SYSTEM:
1650 if (xmlStrEqual(sysID, cur->name)) {
1651 if (xmlDebugCatalogs)
1652 xmlGenericError(xmlGenericErrorContext,
1653 "Found system match %s, using %s\n",
1654 cur->name, cur->URL);
1656 return(xmlStrdup(cur->URL));
1659 case XML_CATA_REWRITE_SYSTEM:
1660 len = xmlStrlen(cur->name);
1661 if ((len > lenrewrite) &&
1662 (!xmlStrncmp(sysID, cur->name, len))) {
1667 case XML_CATA_DELEGATE_SYSTEM:
1668 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1671 case XML_CATA_NEXT_CATALOG:
1679 if (rewrite != NULL) {
1680 if (xmlDebugCatalogs)
1681 xmlGenericError(xmlGenericErrorContext,
1682 "Using rewriting rule %s\n", rewrite->name);
1683 ret = xmlStrdup(rewrite->URL);
1685 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1690 const xmlChar *delegates[MAX_DELEGATE];
1694 * Assume the entries have been sorted by decreasing substring
1695 * matches when the list was produced.
1698 while (cur != NULL) {
1699 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1700 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
1701 for (i = 0;i < nbList;i++)
1702 if (xmlStrEqual(cur->URL, delegates[i]))
1708 if (nbList < MAX_DELEGATE)
1709 delegates[nbList++] = cur->URL;
1711 if (cur->children == NULL) {
1712 xmlFetchXMLCatalogFile(cur);
1714 if (cur->children != NULL) {
1715 if (xmlDebugCatalogs)
1716 xmlGenericError(xmlGenericErrorContext,
1717 "Trying system delegate %s\n", cur->URL);
1718 ret = xmlCatalogListXMLResolve(
1719 cur->children, NULL, sysID);
1729 * Apply the cut algorithm explained in 4/
1732 return(XML_CATAL_BREAK);
1736 * Then tries 5/ 6/ if a public ID is provided
1738 if (pubID != NULL) {
1741 while (cur != NULL) {
1742 switch (cur->type) {
1743 case XML_CATA_PUBLIC:
1744 if (xmlStrEqual(pubID, cur->name)) {
1745 if (xmlDebugCatalogs)
1746 xmlGenericError(xmlGenericErrorContext,
1747 "Found public match %s\n", cur->name);
1749 return(xmlStrdup(cur->URL));
1752 case XML_CATA_DELEGATE_PUBLIC:
1753 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1754 (cur->prefer == XML_CATA_PREFER_PUBLIC))
1757 case XML_CATA_NEXT_CATALOG:
1767 const xmlChar *delegates[MAX_DELEGATE];
1771 * Assume the entries have been sorted by decreasing substring
1772 * matches when the list was produced.
1775 while (cur != NULL) {
1776 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
1777 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1778 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
1780 for (i = 0;i < nbList;i++)
1781 if (xmlStrEqual(cur->URL, delegates[i]))
1787 if (nbList < MAX_DELEGATE)
1788 delegates[nbList++] = cur->URL;
1790 if (cur->children == NULL) {
1791 xmlFetchXMLCatalogFile(cur);
1793 if (cur->children != NULL) {
1794 if (xmlDebugCatalogs)
1795 xmlGenericError(xmlGenericErrorContext,
1796 "Trying public delegate %s\n", cur->URL);
1797 ret = xmlCatalogListXMLResolve(
1798 cur->children, pubID, NULL);
1808 * Apply the cut algorithm explained in 4/
1811 return(XML_CATAL_BREAK);
1816 while (cur != NULL) {
1817 if (cur->type == XML_CATA_NEXT_CATALOG) {
1818 if (cur->children == NULL) {
1819 xmlFetchXMLCatalogFile(cur);
1821 if (cur->children != NULL) {
1822 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1826 } else if (catal->depth > MAX_CATAL_DEPTH) {
1840 * xmlCatalogXMLResolveURI:
1841 * @catal: a catalog list
1843 * @sysID: the system ID string
1845 * Do a complete resolution lookup of an External Identifier for a
1846 * list of catalog entries.
1848 * Implements (or tries to) 7.2.2. URI Resolution
1849 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1851 * Returns the URI of the resource or NULL if not found
1854 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1855 xmlChar *ret = NULL;
1856 xmlCatalogEntryPtr cur;
1857 int haveDelegate = 0;
1859 xmlCatalogEntryPtr rewrite = NULL;
1860 int lenrewrite = 0, len;
1868 if (catal->depth > MAX_CATAL_DEPTH) {
1869 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1870 "Detected recursion in catalog %s\n",
1871 catal->name, NULL, NULL);
1876 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1880 while (cur != NULL) {
1881 switch (cur->type) {
1883 if (xmlStrEqual(URI, cur->name)) {
1884 if (xmlDebugCatalogs)
1885 xmlGenericError(xmlGenericErrorContext,
1886 "Found URI match %s\n", cur->name);
1887 return(xmlStrdup(cur->URL));
1890 case XML_CATA_REWRITE_URI:
1891 len = xmlStrlen(cur->name);
1892 if ((len > lenrewrite) &&
1893 (!xmlStrncmp(URI, cur->name, len))) {
1898 case XML_CATA_DELEGATE_URI:
1899 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1902 case XML_CATA_NEXT_CATALOG:
1910 if (rewrite != NULL) {
1911 if (xmlDebugCatalogs)
1912 xmlGenericError(xmlGenericErrorContext,
1913 "Using rewriting rule %s\n", rewrite->name);
1914 ret = xmlStrdup(rewrite->URL);
1916 ret = xmlStrcat(ret, &URI[lenrewrite]);
1920 const xmlChar *delegates[MAX_DELEGATE];
1924 * Assume the entries have been sorted by decreasing substring
1925 * matches when the list was produced.
1928 while (cur != NULL) {
1929 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1930 (cur->type == XML_CATA_DELEGATE_URI)) &&
1931 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
1932 for (i = 0;i < nbList;i++)
1933 if (xmlStrEqual(cur->URL, delegates[i]))
1939 if (nbList < MAX_DELEGATE)
1940 delegates[nbList++] = cur->URL;
1942 if (cur->children == NULL) {
1943 xmlFetchXMLCatalogFile(cur);
1945 if (cur->children != NULL) {
1946 if (xmlDebugCatalogs)
1947 xmlGenericError(xmlGenericErrorContext,
1948 "Trying URI delegate %s\n", cur->URL);
1949 ret = xmlCatalogListXMLResolveURI(
1950 cur->children, URI);
1958 * Apply the cut algorithm explained in 4/
1960 return(XML_CATAL_BREAK);
1964 while (cur != NULL) {
1965 if (cur->type == XML_CATA_NEXT_CATALOG) {
1966 if (cur->children == NULL) {
1967 xmlFetchXMLCatalogFile(cur);
1969 if (cur->children != NULL) {
1970 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1983 * xmlCatalogListXMLResolve:
1984 * @catal: a catalog list
1985 * @pubID: the public ID string
1986 * @sysID: the system ID string
1988 * Do a complete resolution lookup of an External Identifier for a
1991 * Implements (or tries to) 7.1. External Identifier Resolution
1992 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1994 * Returns the URI of the resource or NULL if not found
1997 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1998 const xmlChar *sysID) {
1999 xmlChar *ret = NULL;
2000 xmlChar *urnID = NULL;
2005 if ((pubID == NULL) && (sysID == NULL))
2008 normid = xmlCatalogNormalizePublic(pubID);
2010 pubID = (*normid != 0 ? normid : NULL);
2012 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2013 urnID = xmlCatalogUnWrapURN(pubID);
2014 if (xmlDebugCatalogs) {
2016 xmlGenericError(xmlGenericErrorContext,
2017 "Public URN ID %s expanded to NULL\n", pubID);
2019 xmlGenericError(xmlGenericErrorContext,
2020 "Public URN ID expanded to %s\n", urnID);
2022 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2029 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2030 urnID = xmlCatalogUnWrapURN(sysID);
2031 if (xmlDebugCatalogs) {
2033 xmlGenericError(xmlGenericErrorContext,
2034 "System URN ID %s expanded to NULL\n", sysID);
2036 xmlGenericError(xmlGenericErrorContext,
2037 "System URN ID expanded to %s\n", urnID);
2040 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2041 else if (xmlStrEqual(pubID, urnID))
2042 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2044 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
2052 while (catal != NULL) {
2053 if (catal->type == XML_CATA_CATALOG) {
2054 if (catal->children == NULL) {
2055 xmlFetchXMLCatalogFile(catal);
2057 if (catal->children != NULL) {
2058 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
2061 } else if ((catal->children != NULL) &&
2062 (catal->children->depth > MAX_CATAL_DEPTH)) {
2068 catal = catal->next;
2076 * xmlCatalogListXMLResolveURI:
2077 * @catal: a catalog list
2080 * Do a complete resolution lookup of an URI for a list of catalogs
2082 * Implements (or tries to) 7.2. URI Resolution
2083 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2085 * Returns the URI of the resource or NULL if not found
2088 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2089 xmlChar *ret = NULL;
2090 xmlChar *urnID = NULL;
2097 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2098 urnID = xmlCatalogUnWrapURN(URI);
2099 if (xmlDebugCatalogs) {
2101 xmlGenericError(xmlGenericErrorContext,
2102 "URN ID %s expanded to NULL\n", URI);
2104 xmlGenericError(xmlGenericErrorContext,
2105 "URN ID expanded to %s\n", urnID);
2107 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2112 while (catal != NULL) {
2113 if (catal->type == XML_CATA_CATALOG) {
2114 if (catal->children == NULL) {
2115 xmlFetchXMLCatalogFile(catal);
2117 if (catal->children != NULL) {
2118 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2123 catal = catal->next;
2128 /************************************************************************
2130 * The SGML Catalog parser *
2132 ************************************************************************/
2137 #define SKIP(x) cur += x;
2139 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2142 * xmlParseSGMLCatalogComment:
2143 * @cur: the current character
2145 * Skip a comment in an SGML catalog
2147 * Returns new current character
2149 static const xmlChar *
2150 xmlParseSGMLCatalogComment(const xmlChar *cur) {
2151 if ((cur[0] != '-') || (cur[1] != '-'))
2154 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2163 * xmlParseSGMLCatalogPubid:
2164 * @cur: the current character
2165 * @id: the return location
2167 * Parse an SGML catalog ID
2169 * Returns new current character and store the value in @id
2171 static const xmlChar *
2172 xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
2173 xmlChar *buf = NULL, *tmp;
2184 } else if (RAW == '\'') {
2190 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
2192 xmlCatalogErrMemory("allocating public ID");
2195 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
2196 if ((*cur == stop) && (stop != ' '))
2198 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
2200 if (len + 1 >= size) {
2202 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2204 xmlCatalogErrMemory("allocating public ID");
2216 if (!IS_BLANK_CH(*cur)) {
2232 * xmlParseSGMLCatalogName:
2233 * @cur: the current character
2234 * @name: the return location
2236 * Parse an SGML catalog name
2238 * Returns new current character and store the value in @name
2240 static const xmlChar *
2241 xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
2242 xmlChar buf[XML_MAX_NAMELEN + 5];
2249 * Handler for more complex cases
2252 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2256 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2257 (c == '.') || (c == '-') ||
2258 (c == '_') || (c == ':'))) {
2262 if (len >= XML_MAX_NAMELEN)
2265 *name = xmlStrndup(buf, len);
2270 * xmlGetSGMLCatalogEntryType:
2271 * @name: the entry name
2273 * Get the Catalog entry type for a given SGML Catalog name
2275 * Returns Catalog entry type
2277 static xmlCatalogEntryType
2278 xmlGetSGMLCatalogEntryType(const xmlChar *name) {
2279 xmlCatalogEntryType type = XML_CATA_NONE;
2280 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2281 type = SGML_CATA_SYSTEM;
2282 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2283 type = SGML_CATA_PUBLIC;
2284 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2285 type = SGML_CATA_DELEGATE;
2286 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2287 type = SGML_CATA_ENTITY;
2288 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2289 type = SGML_CATA_DOCTYPE;
2290 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2291 type = SGML_CATA_LINKTYPE;
2292 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2293 type = SGML_CATA_NOTATION;
2294 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2295 type = SGML_CATA_SGMLDECL;
2296 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2297 type = SGML_CATA_DOCUMENT;
2298 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2299 type = SGML_CATA_CATALOG;
2300 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2301 type = SGML_CATA_BASE;
2306 * xmlParseSGMLCatalog:
2307 * @catal: the SGML Catalog
2308 * @value: the content of the SGML Catalog serialization
2309 * @file: the filepath for the catalog
2310 * @super: should this be handled as a Super Catalog in which case
2311 * parsing is not recursive
2313 * Parse an SGML catalog content and fill up the @catal hash table with
2314 * the new entries found.
2316 * Returns 0 in case of success, -1 in case of error.
2319 xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2320 const char *file, int super) {
2321 const xmlChar *cur = value;
2322 xmlChar *base = NULL;
2325 if ((cur == NULL) || (file == NULL))
2327 base = xmlStrdup((const xmlChar *) file);
2329 while ((cur != NULL) && (cur[0] != 0)) {
2333 if ((cur[0] == '-') && (cur[1] == '-')) {
2334 cur = xmlParseSGMLCatalogComment(cur);
2340 xmlChar *sysid = NULL;
2341 xmlChar *name = NULL;
2342 xmlCatalogEntryType type = XML_CATA_NONE;
2344 cur = xmlParseSGMLCatalogName(cur, &name);
2349 if (!IS_BLANK_CH(*cur)) {
2354 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2355 type = SGML_CATA_SYSTEM;
2356 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2357 type = SGML_CATA_PUBLIC;
2358 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2359 type = SGML_CATA_DELEGATE;
2360 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2361 type = SGML_CATA_ENTITY;
2362 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2363 type = SGML_CATA_DOCTYPE;
2364 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2365 type = SGML_CATA_LINKTYPE;
2366 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2367 type = SGML_CATA_NOTATION;
2368 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2369 type = SGML_CATA_SGMLDECL;
2370 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2371 type = SGML_CATA_DOCUMENT;
2372 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2373 type = SGML_CATA_CATALOG;
2374 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2375 type = SGML_CATA_BASE;
2376 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2378 cur = xmlParseSGMLCatalogName(cur, &name);
2390 case SGML_CATA_ENTITY:
2392 type = SGML_CATA_PENTITY;
2393 case SGML_CATA_PENTITY:
2394 case SGML_CATA_DOCTYPE:
2395 case SGML_CATA_LINKTYPE:
2396 case SGML_CATA_NOTATION:
2397 cur = xmlParseSGMLCatalogName(cur, &name);
2402 if (!IS_BLANK_CH(*cur)) {
2407 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2413 case SGML_CATA_PUBLIC:
2414 case SGML_CATA_SYSTEM:
2415 case SGML_CATA_DELEGATE:
2416 cur = xmlParseSGMLCatalogPubid(cur, &name);
2421 if (type != SGML_CATA_SYSTEM) {
2424 normid = xmlCatalogNormalizePublic(name);
2425 if (normid != NULL) {
2436 if (!IS_BLANK_CH(*cur)) {
2441 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2447 case SGML_CATA_BASE:
2448 case SGML_CATA_CATALOG:
2449 case SGML_CATA_DOCUMENT:
2450 case SGML_CATA_SGMLDECL:
2451 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2466 } else if (type == SGML_CATA_BASE) {
2469 base = xmlStrdup(sysid);
2470 } else if ((type == SGML_CATA_PUBLIC) ||
2471 (type == SGML_CATA_SYSTEM)) {
2474 filename = xmlBuildURI(sysid, base);
2475 if (filename != NULL) {
2476 xmlCatalogEntryPtr entry;
2478 entry = xmlNewCatalogEntry(type, name, filename,
2479 NULL, XML_CATA_PREFER_NONE, NULL);
2480 res = xmlHashAddEntry(catal->sgml, name, entry);
2482 xmlFreeCatalogEntry(entry);
2487 } else if (type == SGML_CATA_CATALOG) {
2489 xmlCatalogEntryPtr entry;
2491 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
2492 XML_CATA_PREFER_NONE, NULL);
2493 res = xmlHashAddEntry(catal->sgml, sysid, entry);
2495 xmlFreeCatalogEntry(entry);
2500 filename = xmlBuildURI(sysid, base);
2501 if (filename != NULL) {
2502 xmlExpandCatalog(catal, (const char *)filename);
2508 * drop anything else we won't handle it
2523 /************************************************************************
2525 * SGML Catalog handling *
2527 ************************************************************************/
2530 * xmlCatalogGetSGMLPublic:
2531 * @catal: an SGML catalog hash
2532 * @pubID: the public ID string
2534 * Try to lookup the catalog local reference associated to a public ID
2536 * Returns the local resource if found or NULL otherwise.
2538 static const xmlChar *
2539 xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2540 xmlCatalogEntryPtr entry;
2546 normid = xmlCatalogNormalizePublic(pubID);
2548 pubID = (*normid != 0 ? normid : NULL);
2550 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2551 if (entry == NULL) {
2556 if (entry->type == SGML_CATA_PUBLIC) {
2567 * xmlCatalogGetSGMLSystem:
2568 * @catal: an SGML catalog hash
2569 * @sysID: the system ID string
2571 * Try to lookup the catalog local reference for a system ID
2573 * Returns the local resource if found or NULL otherwise.
2575 static const xmlChar *
2576 xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2577 xmlCatalogEntryPtr entry;
2582 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2585 if (entry->type == SGML_CATA_SYSTEM)
2591 * xmlCatalogSGMLResolve:
2592 * @catal: the SGML catalog
2593 * @pubID: the public ID string
2594 * @sysID: the system ID string
2596 * Do a complete resolution lookup of an External Identifier
2598 * Returns the URI of the resource or NULL if not found
2600 static const xmlChar *
2601 xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2602 const xmlChar *sysID) {
2603 const xmlChar *ret = NULL;
2605 if (catal->sgml == NULL)
2609 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2613 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2619 /************************************************************************
2621 * Specific Public interfaces *
2623 ************************************************************************/
2626 * xmlLoadSGMLSuperCatalog:
2627 * @filename: a file path
2629 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2630 * references. This is only needed for manipulating SGML Super Catalogs
2631 * like adding and removing CATALOG or DELEGATE entries.
2633 * Returns the catalog parsed or NULL in case of error
2636 xmlLoadSGMLSuperCatalog(const char *filename)
2639 xmlCatalogPtr catal;
2642 content = xmlLoadFileContent(filename);
2643 if (content == NULL)
2646 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2647 if (catal == NULL) {
2652 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2655 xmlFreeCatalog(catal);
2663 * @filename: a file path
2665 * Load the catalog and build the associated data structures.
2666 * This can be either an XML Catalog or an SGML Catalog
2667 * It will recurse in SGML CATALOG entries. On the other hand XML
2668 * Catalogs are not handled recursively.
2670 * Returns the catalog parsed or NULL in case of error
2673 xmlLoadACatalog(const char *filename)
2677 xmlCatalogPtr catal;
2680 content = xmlLoadFileContent(filename);
2681 if (content == NULL)
2687 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2688 (!(((*first >= 'A') && (*first <= 'Z')) ||
2689 ((*first >= 'a') && (*first <= 'z')))))
2692 if (*first != '<') {
2693 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2694 if (catal == NULL) {
2698 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2700 xmlFreeCatalog(catal);
2705 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2706 if (catal == NULL) {
2710 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2711 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
2720 * @filename: a file path
2722 * Load the catalog and expand the existing catal structure.
2723 * This can be either an XML Catalog or an SGML Catalog
2725 * Returns 0 in case of success, -1 in case of error
2728 xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2732 if ((catal == NULL) || (filename == NULL))
2736 if (catal->type == XML_SGML_CATALOG_TYPE) {
2739 content = xmlLoadFileContent(filename);
2740 if (content == NULL)
2743 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2750 xmlCatalogEntryPtr tmp, cur;
2751 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2752 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
2758 while (cur->next != NULL) cur = cur->next;
2766 * xmlACatalogResolveSystem:
2768 * @sysID: the system ID string
2770 * Try to lookup the catalog resource for a system ID
2772 * Returns the resource if found or NULL otherwise, the value returned
2773 * must be freed by the caller.
2776 xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2777 xmlChar *ret = NULL;
2779 if ((sysID == NULL) || (catal == NULL))
2782 if (xmlDebugCatalogs)
2783 xmlGenericError(xmlGenericErrorContext,
2784 "Resolve sysID %s\n", sysID);
2786 if (catal->type == XML_XML_CATALOG_TYPE) {
2787 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2788 if (ret == XML_CATAL_BREAK)
2791 const xmlChar *sgml;
2793 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2795 ret = xmlStrdup(sgml);
2801 * xmlACatalogResolvePublic:
2803 * @pubID: the public ID string
2805 * Try to lookup the catalog local reference associated to a public ID in that catalog
2807 * Returns the local resource if found or NULL otherwise, the value returned
2808 * must be freed by the caller.
2811 xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2812 xmlChar *ret = NULL;
2814 if ((pubID == NULL) || (catal == NULL))
2817 if (xmlDebugCatalogs)
2818 xmlGenericError(xmlGenericErrorContext,
2819 "Resolve pubID %s\n", pubID);
2821 if (catal->type == XML_XML_CATALOG_TYPE) {
2822 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2823 if (ret == XML_CATAL_BREAK)
2826 const xmlChar *sgml;
2828 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2830 ret = xmlStrdup(sgml);
2836 * xmlACatalogResolve:
2838 * @pubID: the public ID string
2839 * @sysID: the system ID string
2841 * Do a complete resolution lookup of an External Identifier
2843 * Returns the URI of the resource or NULL if not found, it must be freed
2847 xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2848 const xmlChar * sysID)
2850 xmlChar *ret = NULL;
2852 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2855 if (xmlDebugCatalogs) {
2856 if ((pubID != NULL) && (sysID != NULL)) {
2857 xmlGenericError(xmlGenericErrorContext,
2858 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2859 } else if (pubID != NULL) {
2860 xmlGenericError(xmlGenericErrorContext,
2861 "Resolve: pubID %s\n", pubID);
2863 xmlGenericError(xmlGenericErrorContext,
2864 "Resolve: sysID %s\n", sysID);
2868 if (catal->type == XML_XML_CATALOG_TYPE) {
2869 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2870 if (ret == XML_CATAL_BREAK)
2873 const xmlChar *sgml;
2875 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2877 ret = xmlStrdup(sgml);
2883 * xmlACatalogResolveURI:
2887 * Do a complete resolution lookup of an URI
2889 * Returns the URI of the resource or NULL if not found, it must be freed
2893 xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2894 xmlChar *ret = NULL;
2896 if ((URI == NULL) || (catal == NULL))
2899 if (xmlDebugCatalogs)
2900 xmlGenericError(xmlGenericErrorContext,
2901 "Resolve URI %s\n", URI);
2903 if (catal->type == XML_XML_CATALOG_TYPE) {
2904 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2905 if (ret == XML_CATAL_BREAK)
2908 const xmlChar *sgml;
2910 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2912 ret = xmlStrdup(sgml);
2917 #ifdef LIBXML_OUTPUT_ENABLED
2923 * Dump the given catalog to the given file.
2926 xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
2927 if ((out == NULL) || (catal == NULL))
2930 if (catal->type == XML_XML_CATALOG_TYPE) {
2931 xmlDumpXMLCatalog(out, catal->xml);
2933 xmlHashScan(catal->sgml,
2934 (xmlHashScanner) xmlCatalogDumpEntry, out);
2937 #endif /* LIBXML_OUTPUT_ENABLED */
2942 * @type: the type of record to add to the catalog
2943 * @orig: the system, public or prefix to match
2944 * @replace: the replacement value for the match
2946 * Add an entry in the catalog, it may overwrite existing but
2947 * different entries.
2949 * Returns 0 if successful, -1 otherwise
2952 xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2953 const xmlChar * orig, const xmlChar * replace)
2960 if (catal->type == XML_XML_CATALOG_TYPE) {
2961 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2963 xmlCatalogEntryType cattype;
2965 cattype = xmlGetSGMLCatalogEntryType(type);
2966 if (cattype != XML_CATA_NONE) {
2967 xmlCatalogEntryPtr entry;
2969 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
2970 XML_CATA_PREFER_NONE, NULL);
2971 if (catal->sgml == NULL)
2972 catal->sgml = xmlHashCreate(10);
2973 res = xmlHashAddEntry(catal->sgml, orig, entry);
2980 * xmlACatalogRemove:
2982 * @value: the value to remove
2984 * Remove an entry from the catalog
2986 * Returns the number of entries removed if successful, -1 otherwise
2989 xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2992 if ((catal == NULL) || (value == NULL))
2995 if (catal->type == XML_XML_CATALOG_TYPE) {
2996 res = xmlDelXMLCatalog(catal->xml, value);
2998 res = xmlHashRemoveEntry(catal->sgml, value,
2999 (xmlHashDeallocator) xmlFreeCatalogEntry);
3008 * @sgml: should this create an SGML catalog
3010 * create a new Catalog.
3012 * Returns the xmlCatalogPtr or NULL in case of error
3015 xmlNewCatalog(int sgml) {
3016 xmlCatalogPtr catal = NULL;
3019 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3020 xmlCatalogDefaultPrefer);
3021 if ((catal != NULL) && (catal->sgml == NULL))
3022 catal->sgml = xmlHashCreate(10);
3024 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3025 xmlCatalogDefaultPrefer);
3030 * xmlCatalogIsEmpty:
3031 * @catal: should this create an SGML catalog
3033 * Check is a catalog is empty
3035 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3038 xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3042 if (catal->type == XML_XML_CATALOG_TYPE) {
3043 if (catal->xml == NULL)
3045 if ((catal->xml->type != XML_CATA_CATALOG) &&
3046 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3048 if (catal->xml->children == NULL)
3054 if (catal->sgml == NULL)
3056 res = xmlHashSize(catal->sgml);
3065 /************************************************************************
3067 * Public interfaces manipulating the global shared default catalog *
3069 ************************************************************************/
3072 * xmlInitializeCatalogData:
3074 * Do the catalog initialization only of global data, doesn't try to load
3075 * any catalog actually.
3076 * this function is not thread safe, catalog initialization should
3077 * preferably be done once at startup
3080 xmlInitializeCatalogData(void) {
3081 if (xmlCatalogInitialized != 0)
3084 if (getenv("XML_DEBUG_CATALOG"))
3085 xmlDebugCatalogs = 1;
3086 xmlCatalogMutex = xmlNewRMutex();
3088 xmlCatalogInitialized = 1;
3091 * xmlInitializeCatalog:
3093 * Do the catalog initialization.
3094 * this function is not thread safe, catalog initialization should
3095 * preferably be done once at startup
3098 xmlInitializeCatalog(void) {
3099 if (xmlCatalogInitialized != 0)
3102 xmlInitializeCatalogData();
3103 xmlRMutexLock(xmlCatalogMutex);
3105 if (getenv("XML_DEBUG_CATALOG"))
3106 xmlDebugCatalogs = 1;
3108 if (xmlDefaultCatalog == NULL) {
3109 const char *catalogs;
3111 const char *cur, *paths;
3112 xmlCatalogPtr catal;
3113 xmlCatalogEntryPtr *nextent;
3115 catalogs = (const char *) getenv("XML_CATALOG_FILES");
3116 if (catalogs == NULL)
3117 #if defined(_WIN32) && defined(_MSC_VER)
3120 hmodule = GetModuleHandleA("libxml2.dll");
3121 if (hmodule == NULL)
3122 hmodule = GetModuleHandleA(NULL);
3123 if (hmodule != NULL) {
3125 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3127 char* p = &(buf[len]);
3128 while (*p != '\\' && p > buf)
3132 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3133 uri = xmlCanonicPath(buf);
3135 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3141 catalogs = XML_XML_DEFAULT_CATALOG;
3144 catalogs = XML_XML_DEFAULT_CATALOG;
3147 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3148 xmlCatalogDefaultPrefer);
3149 if (catal != NULL) {
3150 /* the XML_CATALOG_FILES envvar is allowed to contain a
3151 space-separated list of entries. */
3153 nextent = &catal->xml;
3154 while (*cur != '\0') {
3155 while (xmlIsBlank_ch(*cur))
3159 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
3161 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
3163 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3164 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
3165 if (*nextent != NULL)
3166 nextent = &((*nextent)->next);
3171 xmlDefaultCatalog = catal;
3175 xmlRMutexUnlock(xmlCatalogMutex);
3181 * @filename: a file path
3183 * Load the catalog and makes its definitions effective for the default
3184 * external entity loader. It will recurse in SGML CATALOG entries.
3185 * this function is not thread safe, catalog initialization should
3186 * preferably be done once at startup
3188 * Returns 0 in case of success -1 in case of error
3191 xmlLoadCatalog(const char *filename)
3194 xmlCatalogPtr catal;
3196 if (!xmlCatalogInitialized)
3197 xmlInitializeCatalogData();
3199 xmlRMutexLock(xmlCatalogMutex);
3201 if (xmlDefaultCatalog == NULL) {
3202 catal = xmlLoadACatalog(filename);
3203 if (catal == NULL) {
3204 xmlRMutexUnlock(xmlCatalogMutex);
3208 xmlDefaultCatalog = catal;
3209 xmlRMutexUnlock(xmlCatalogMutex);
3213 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
3214 xmlRMutexUnlock(xmlCatalogMutex);
3220 * @pathss: a list of directories separated by a colon or a space.
3222 * Load the catalogs and makes their definitions effective for the default
3223 * external entity loader.
3224 * this function is not thread safe, catalog initialization should
3225 * preferably be done once at startup
3228 xmlLoadCatalogs(const char *pathss) {
3241 while (xmlIsBlank_ch(*cur)) cur++;
3244 while ((*cur != 0) && (*cur != PATH_SEAPARATOR) && (!xmlIsBlank_ch(*cur)))
3246 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3248 iLen = strlen(path);
3249 for(i = 0; i < iLen; i++) {
3250 if(path[i] == '\\') {
3256 xmlLoadCatalog((const char *) path);
3260 while (*cur == PATH_SEAPARATOR)
3266 * xmlCatalogCleanup:
3268 * Free up all the memory associated with catalogs
3271 xmlCatalogCleanup(void) {
3272 if (xmlCatalogInitialized == 0)
3275 xmlRMutexLock(xmlCatalogMutex);
3276 if (xmlDebugCatalogs)
3277 xmlGenericError(xmlGenericErrorContext,
3278 "Catalogs cleanup\n");
3279 if (xmlCatalogXMLFiles != NULL)
3280 xmlHashFree(xmlCatalogXMLFiles,
3281 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
3282 xmlCatalogXMLFiles = NULL;
3283 if (xmlDefaultCatalog != NULL)
3284 xmlFreeCatalog(xmlDefaultCatalog);
3285 xmlDefaultCatalog = NULL;
3286 xmlDebugCatalogs = 0;
3287 xmlCatalogInitialized = 0;
3288 xmlRMutexUnlock(xmlCatalogMutex);
3289 xmlFreeRMutex(xmlCatalogMutex);
3293 * xmlCatalogResolveSystem:
3294 * @sysID: the system ID string
3296 * Try to lookup the catalog resource for a system ID
3298 * Returns the resource if found or NULL otherwise, the value returned
3299 * must be freed by the caller.
3302 xmlCatalogResolveSystem(const xmlChar *sysID) {
3305 if (!xmlCatalogInitialized)
3306 xmlInitializeCatalog();
3308 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3313 * xmlCatalogResolvePublic:
3314 * @pubID: the public ID string
3316 * Try to lookup the catalog reference associated to a public ID
3318 * Returns the resource if found or NULL otherwise, the value returned
3319 * must be freed by the caller.
3322 xmlCatalogResolvePublic(const xmlChar *pubID) {
3325 if (!xmlCatalogInitialized)
3326 xmlInitializeCatalog();
3328 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3333 * xmlCatalogResolve:
3334 * @pubID: the public ID string
3335 * @sysID: the system ID string
3337 * Do a complete resolution lookup of an External Identifier
3339 * Returns the URI of the resource or NULL if not found, it must be freed
3343 xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
3346 if (!xmlCatalogInitialized)
3347 xmlInitializeCatalog();
3349 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3354 * xmlCatalogResolveURI:
3357 * Do a complete resolution lookup of an URI
3359 * Returns the URI of the resource or NULL if not found, it must be freed
3363 xmlCatalogResolveURI(const xmlChar *URI) {
3366 if (!xmlCatalogInitialized)
3367 xmlInitializeCatalog();
3369 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3373 #ifdef LIBXML_OUTPUT_ENABLED
3378 * Dump all the global catalog content to the given file.
3381 xmlCatalogDump(FILE *out) {
3385 if (!xmlCatalogInitialized)
3386 xmlInitializeCatalog();
3388 xmlACatalogDump(xmlDefaultCatalog, out);
3390 #endif /* LIBXML_OUTPUT_ENABLED */
3394 * @type: the type of record to add to the catalog
3395 * @orig: the system, public or prefix to match
3396 * @replace: the replacement value for the match
3398 * Add an entry in the catalog, it may overwrite existing but
3399 * different entries.
3400 * If called before any other catalog routine, allows to override the
3401 * default shared catalog put in place by xmlInitializeCatalog();
3403 * Returns 0 if successful, -1 otherwise
3406 xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3409 if (!xmlCatalogInitialized)
3410 xmlInitializeCatalogData();
3412 xmlRMutexLock(xmlCatalogMutex);
3414 * Specific case where one want to override the default catalog
3415 * put in place by xmlInitializeCatalog();
3417 if ((xmlDefaultCatalog == NULL) &&
3418 (xmlStrEqual(type, BAD_CAST "catalog"))) {
3419 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3420 xmlCatalogDefaultPrefer);
3421 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3422 orig, NULL, xmlCatalogDefaultPrefer, NULL);
3424 xmlRMutexUnlock(xmlCatalogMutex);
3428 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
3429 xmlRMutexUnlock(xmlCatalogMutex);
3435 * @value: the value to remove
3437 * Remove an entry from the catalog
3439 * Returns the number of entries removed if successful, -1 otherwise
3442 xmlCatalogRemove(const xmlChar *value) {
3445 if (!xmlCatalogInitialized)
3446 xmlInitializeCatalog();
3448 xmlRMutexLock(xmlCatalogMutex);
3449 res = xmlACatalogRemove(xmlDefaultCatalog, value);
3450 xmlRMutexUnlock(xmlCatalogMutex);
3455 * xmlCatalogConvert:
3457 * Convert all the SGML catalog entries as XML ones
3459 * Returns the number of entries converted if successful, -1 otherwise
3462 xmlCatalogConvert(void) {
3465 if (!xmlCatalogInitialized)
3466 xmlInitializeCatalog();
3468 xmlRMutexLock(xmlCatalogMutex);
3469 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
3470 xmlRMutexUnlock(xmlCatalogMutex);
3474 /************************************************************************
3476 * Public interface manipulating the common preferences *
3478 ************************************************************************/
3481 * xmlCatalogGetDefaults:
3483 * Used to get the user preference w.r.t. to what catalogs should
3486 * Returns the current xmlCatalogAllow value
3489 xmlCatalogGetDefaults(void) {
3490 return(xmlCatalogDefaultAllow);
3494 * xmlCatalogSetDefaults:
3495 * @allow: what catalogs should be accepted
3497 * Used to set the user preference w.r.t. to what catalogs should
3501 xmlCatalogSetDefaults(xmlCatalogAllow allow) {
3502 if (xmlDebugCatalogs) {
3504 case XML_CATA_ALLOW_NONE:
3505 xmlGenericError(xmlGenericErrorContext,
3506 "Disabling catalog usage\n");
3508 case XML_CATA_ALLOW_GLOBAL:
3509 xmlGenericError(xmlGenericErrorContext,
3510 "Allowing only global catalogs\n");
3512 case XML_CATA_ALLOW_DOCUMENT:
3513 xmlGenericError(xmlGenericErrorContext,
3514 "Allowing only catalogs from the document\n");
3516 case XML_CATA_ALLOW_ALL:
3517 xmlGenericError(xmlGenericErrorContext,
3518 "Allowing all catalogs\n");
3522 xmlCatalogDefaultAllow = allow;
3526 * xmlCatalogSetDefaultPrefer:
3527 * @prefer: the default preference for delegation
3529 * Allows to set the preference between public and system for deletion
3530 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3531 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3533 * Returns the previous value of the default preference for delegation
3536 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3537 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3539 if (prefer == XML_CATA_PREFER_NONE)
3542 if (xmlDebugCatalogs) {
3544 case XML_CATA_PREFER_PUBLIC:
3545 xmlGenericError(xmlGenericErrorContext,
3546 "Setting catalog preference to PUBLIC\n");
3548 case XML_CATA_PREFER_SYSTEM:
3549 xmlGenericError(xmlGenericErrorContext,
3550 "Setting catalog preference to SYSTEM\n");
3552 case XML_CATA_PREFER_NONE:
3556 xmlCatalogDefaultPrefer = prefer;
3561 * xmlCatalogSetDebug:
3562 * @level: the debug level of catalogs required
3564 * Used to set the debug level for catalog operation, 0 disable
3565 * debugging, 1 enable it
3567 * Returns the previous value of the catalog debugging level
3570 xmlCatalogSetDebug(int level) {
3571 int ret = xmlDebugCatalogs;
3574 xmlDebugCatalogs = 0;
3576 xmlDebugCatalogs = level;
3580 /************************************************************************
3582 * Minimal interfaces used for per-document catalogs by the parser *
3584 ************************************************************************/
3587 * xmlCatalogFreeLocal:
3588 * @catalogs: a document's list of catalogs
3590 * Free up the memory associated to the catalog list
3593 xmlCatalogFreeLocal(void *catalogs) {
3594 xmlCatalogEntryPtr catal;
3596 if (!xmlCatalogInitialized)
3597 xmlInitializeCatalog();
3599 catal = (xmlCatalogEntryPtr) catalogs;
3601 xmlFreeCatalogEntryList(catal);
3606 * xmlCatalogAddLocal:
3607 * @catalogs: a document's list of catalogs
3608 * @URL: the URL to a new local catalog
3610 * Add the new entry to the catalog list
3612 * Returns the updated list
3615 xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3616 xmlCatalogEntryPtr catal, add;
3618 if (!xmlCatalogInitialized)
3619 xmlInitializeCatalog();
3624 if (xmlDebugCatalogs)
3625 xmlGenericError(xmlGenericErrorContext,
3626 "Adding document catalog %s\n", URL);
3628 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
3629 xmlCatalogDefaultPrefer, NULL);
3633 catal = (xmlCatalogEntryPtr) catalogs;
3635 return((void *) add);
3637 while (catal->next != NULL)
3638 catal = catal->next;
3644 * xmlCatalogLocalResolve:
3645 * @catalogs: a document's list of catalogs
3646 * @pubID: the public ID string
3647 * @sysID: the system ID string
3649 * Do a complete resolution lookup of an External Identifier using a
3650 * document's private catalog list
3652 * Returns the URI of the resource or NULL if not found, it must be freed
3656 xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3657 const xmlChar *sysID) {
3658 xmlCatalogEntryPtr catal;
3661 if (!xmlCatalogInitialized)
3662 xmlInitializeCatalog();
3664 if ((pubID == NULL) && (sysID == NULL))
3667 if (xmlDebugCatalogs) {
3668 if ((pubID != NULL) && (sysID != NULL)) {
3669 xmlGenericError(xmlGenericErrorContext,
3670 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3671 } else if (pubID != NULL) {
3672 xmlGenericError(xmlGenericErrorContext,
3673 "Local Resolve: pubID %s\n", pubID);
3675 xmlGenericError(xmlGenericErrorContext,
3676 "Local Resolve: sysID %s\n", sysID);
3680 catal = (xmlCatalogEntryPtr) catalogs;
3683 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3684 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3690 * xmlCatalogLocalResolveURI:
3691 * @catalogs: a document's list of catalogs
3694 * Do a complete resolution lookup of an URI using a
3695 * document's private catalog list
3697 * Returns the URI of the resource or NULL if not found, it must be freed
3701 xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3702 xmlCatalogEntryPtr catal;
3705 if (!xmlCatalogInitialized)
3706 xmlInitializeCatalog();
3711 if (xmlDebugCatalogs)
3712 xmlGenericError(xmlGenericErrorContext,
3713 "Resolve URI %s\n", URI);
3715 catal = (xmlCatalogEntryPtr) catalogs;
3718 ret = xmlCatalogListXMLResolveURI(catal, URI);
3719 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3724 /************************************************************************
3726 * Deprecated interfaces *
3728 ************************************************************************/
3730 * xmlCatalogGetSystem:
3731 * @sysID: the system ID string
3733 * Try to lookup the catalog reference associated to a system ID
3734 * DEPRECATED, use xmlCatalogResolveSystem()
3736 * Returns the resource if found or NULL otherwise.
3739 xmlCatalogGetSystem(const xmlChar *sysID) {
3741 static xmlChar result[1000];
3744 if (!xmlCatalogInitialized)
3745 xmlInitializeCatalog();
3748 xmlGenericError(xmlGenericErrorContext,
3749 "Use of deprecated xmlCatalogGetSystem() call\n");
3757 * Check first the XML catalogs
3759 if (xmlDefaultCatalog != NULL) {
3760 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3761 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3762 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3763 result[sizeof(result) - 1] = 0;
3768 if (xmlDefaultCatalog != NULL)
3769 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3774 * xmlCatalogGetPublic:
3775 * @pubID: the public ID string
3777 * Try to lookup the catalog reference associated to a public ID
3778 * DEPRECATED, use xmlCatalogResolvePublic()
3780 * Returns the resource if found or NULL otherwise.
3783 xmlCatalogGetPublic(const xmlChar *pubID) {
3785 static xmlChar result[1000];
3788 if (!xmlCatalogInitialized)
3789 xmlInitializeCatalog();
3792 xmlGenericError(xmlGenericErrorContext,
3793 "Use of deprecated xmlCatalogGetPublic() call\n");
3801 * Check first the XML catalogs
3803 if (xmlDefaultCatalog != NULL) {
3804 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3805 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3806 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3807 result[sizeof(result) - 1] = 0;
3812 if (xmlDefaultCatalog != NULL)
3813 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3817 #define bottom_catalog
3818 #include "elfgcchack.h"
3819 #endif /* LIBXML_CATALOG_ENABLED */