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>
46 #define MAX_DELEGATE 50
47 #define MAX_CATAL_DEPTH 50
50 # define PATH_SEPARATOR ';'
52 # define PATH_SEPARATOR ':'
58 * macro to flag unimplemented blocks
59 * XML_CATALOG_PREFER user env to select between system/public prefered
60 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
61 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
62 *> values "system" and "public". I have made the default be "system" to
66 xmlGenericError(xmlGenericErrorContext, \
67 "Unimplemented block at %s:%d\n", \
70 #define XML_URN_PUBID "urn:publicid:"
71 #define XML_CATAL_BREAK ((xmlChar *) -1)
72 #ifndef XML_XML_DEFAULT_CATALOG
73 #define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
75 #ifndef XML_SGML_DEFAULT_CATALOG
76 #define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
79 #if defined(_WIN32) && defined(_MSC_VER)
80 #undef XML_XML_DEFAULT_CATALOG
81 static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
82 #if defined(_WIN32_WCE)
83 /* Windows CE don't have a A variant */
84 #define GetModuleHandleA GetModuleHandle
85 #define GetModuleFileNameA GetModuleFileName
87 #if !defined(_WINDOWS_)
88 void* __stdcall GetModuleHandleA(const char*);
89 unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
94 static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
95 static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
97 /************************************************************************
99 * Types, all private *
101 ************************************************************************/
104 XML_CATA_REMOVED = -1,
107 XML_CATA_BROKEN_CATALOG,
108 XML_CATA_NEXT_CATALOG,
112 XML_CATA_REWRITE_SYSTEM,
113 XML_CATA_DELEGATE_PUBLIC,
114 XML_CATA_DELEGATE_SYSTEM,
116 XML_CATA_REWRITE_URI,
117 XML_CATA_DELEGATE_URI,
130 } xmlCatalogEntryType;
132 typedef struct _xmlCatalogEntry xmlCatalogEntry;
133 typedef xmlCatalogEntry *xmlCatalogEntryPtr;
134 struct _xmlCatalogEntry {
135 struct _xmlCatalogEntry *next;
136 struct _xmlCatalogEntry *parent;
137 struct _xmlCatalogEntry *children;
138 xmlCatalogEntryType type;
141 xmlChar *URL; /* The expanded URL using the base */
142 xmlCatalogPrefer prefer;
145 struct _xmlCatalogEntry *group;
149 XML_XML_CATALOG_TYPE = 1,
150 XML_SGML_CATALOG_TYPE
153 #define XML_MAX_SGML_CATA_DEPTH 10
155 xmlCatalogType type; /* either XML or SGML */
158 * SGML Catalogs are stored as a simple hash table of catalog entries
159 * Catalog stack to check against overflows when building the
162 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
163 int catalNr; /* Number of current catal streams */
164 int catalMax; /* Max number of catal streams */
165 xmlHashTablePtr sgml;
168 * XML Catalogs are stored as a tree of Catalog entries
170 xmlCatalogPrefer prefer;
171 xmlCatalogEntryPtr xml;
174 /************************************************************************
178 ************************************************************************/
181 * Those are preferences
183 static int xmlDebugCatalogs = 0; /* used for debugging */
184 static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
185 static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
188 * Hash table containing all the trees of XML catalogs parsed by
191 static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
194 * The default catalog in use by the application
196 static xmlCatalogPtr xmlDefaultCatalog = NULL;
199 * A mutex for modifying the shared global catalog(s)
200 * xmlDefaultCatalog tree.
201 * It also protects xmlCatalogXMLFiles
202 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
204 static xmlRMutexPtr xmlCatalogMutex = NULL;
207 * Whether the catalog support was initialized.
209 static int xmlCatalogInitialized = 0;
211 /************************************************************************
213 * Catalog error handlers *
215 ************************************************************************/
218 * xmlCatalogErrMemory:
219 * @extra: extra informations
221 * Handle an out of memory condition
224 xmlCatalogErrMemory(const char *extra)
226 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
227 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
228 extra, NULL, NULL, 0, 0,
229 "Memory allocation failed : %s\n", extra);
234 * @catal: the Catalog entry
235 * @node: the context node
236 * @msg: the error message
237 * @extra: extra informations
239 * Handle a catalog error
241 static void LIBXML_ATTR_FORMAT(4,0)
242 xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
243 const char *msg, const xmlChar *str1, const xmlChar *str2,
246 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
247 error, XML_ERR_ERROR, NULL, 0,
248 (const char *) str1, (const char *) str2,
249 (const char *) str3, 0, 0,
250 msg, str1, str2, str3);
254 /************************************************************************
256 * Allocation and Freeing *
258 ************************************************************************/
261 * xmlNewCatalogEntry:
262 * @type: type of entry
263 * @name: name of the entry
264 * @value: value of the entry
265 * @prefer: the PUBLIC vs. SYSTEM current preference value
266 * @group: for members of a group, the group entry
268 * create a new Catalog entry, this type is shared both by XML and
269 * SGML catalogs, but the acceptable types values differs.
271 * Returns the xmlCatalogEntryPtr or NULL in case of error
273 static xmlCatalogEntryPtr
274 xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
275 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
276 xmlCatalogEntryPtr group) {
277 xmlCatalogEntryPtr ret;
278 xmlChar *normid = NULL;
280 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
282 xmlCatalogErrMemory("allocating catalog entry");
287 ret->children = NULL;
289 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
290 normid = xmlCatalogNormalizePublic(name);
292 name = (*normid != 0 ? normid : NULL);
295 ret->name = xmlStrdup(name);
301 ret->value = xmlStrdup(value);
307 ret->URL = xmlStrdup(URL);
310 ret->prefer = prefer;
318 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
321 * xmlFreeCatalogEntry:
322 * @ret: a Catalog entry
324 * Free the memory allocated to a Catalog entry
327 xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
331 * Entries stored in the file hash must be deallocated
332 * only by the file hash cleaner !
334 if (ret->dealloc == 1)
337 if (xmlDebugCatalogs) {
338 if (ret->name != NULL)
339 xmlGenericError(xmlGenericErrorContext,
340 "Free catalog entry %s\n", ret->name);
341 else if (ret->value != NULL)
342 xmlGenericError(xmlGenericErrorContext,
343 "Free catalog entry %s\n", ret->value);
345 xmlGenericError(xmlGenericErrorContext,
346 "Free catalog entry\n");
349 if (ret->name != NULL)
351 if (ret->value != NULL)
353 if (ret->URL != NULL)
359 * xmlFreeCatalogEntryList:
360 * @ret: a Catalog entry list
362 * Free the memory allocated to a full chained list of Catalog entries
365 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
366 xmlCatalogEntryPtr next;
368 while (ret != NULL) {
370 xmlFreeCatalogEntry(ret);
376 * xmlFreeCatalogHashEntryList:
377 * @ret: a Catalog entry list
379 * Free the memory allocated to list of Catalog entries from the
383 xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
384 xmlCatalogEntryPtr children, next;
389 children = catal->children;
390 while (children != NULL) {
391 next = children->next;
392 children->dealloc = 0;
393 children->children = NULL;
394 xmlFreeCatalogEntry(children);
398 xmlFreeCatalogEntry(catal);
402 * xmlCreateNewCatalog:
403 * @type: type of catalog
404 * @prefer: the PUBLIC vs. SYSTEM current preference value
406 * create a new Catalog, this type is shared both by XML and
407 * SGML catalogs, but the acceptable types values differs.
409 * Returns the xmlCatalogPtr or NULL in case of error
412 xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
415 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
417 xmlCatalogErrMemory("allocating catalog");
420 memset(ret, 0, sizeof(xmlCatalog));
423 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
424 ret->prefer = prefer;
425 if (ret->type == XML_SGML_CATALOG_TYPE)
426 ret->sgml = xmlHashCreate(10);
434 * Free the memory allocated to a Catalog
437 xmlFreeCatalog(xmlCatalogPtr catal) {
440 if (catal->xml != NULL)
441 xmlFreeCatalogEntryList(catal->xml);
442 if (catal->sgml != NULL)
443 xmlHashFree(catal->sgml,
444 (xmlHashDeallocator) xmlFreeCatalogEntry);
448 /************************************************************************
450 * Serializing Catalogs *
452 ************************************************************************/
454 #ifdef LIBXML_OUTPUT_ENABLED
456 * xmlCatalogDumpEntry:
457 * @entry: the catalog entry
460 * Serialize an SGML Catalog entry
463 xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
464 if ((entry == NULL) || (out == NULL))
466 switch (entry->type) {
467 case SGML_CATA_ENTITY:
468 fprintf(out, "ENTITY "); break;
469 case SGML_CATA_PENTITY:
470 fprintf(out, "ENTITY %%"); break;
471 case SGML_CATA_DOCTYPE:
472 fprintf(out, "DOCTYPE "); break;
473 case SGML_CATA_LINKTYPE:
474 fprintf(out, "LINKTYPE "); break;
475 case SGML_CATA_NOTATION:
476 fprintf(out, "NOTATION "); break;
477 case SGML_CATA_PUBLIC:
478 fprintf(out, "PUBLIC "); break;
479 case SGML_CATA_SYSTEM:
480 fprintf(out, "SYSTEM "); break;
481 case SGML_CATA_DELEGATE:
482 fprintf(out, "DELEGATE "); break;
484 fprintf(out, "BASE "); break;
485 case SGML_CATA_CATALOG:
486 fprintf(out, "CATALOG "); break;
487 case SGML_CATA_DOCUMENT:
488 fprintf(out, "DOCUMENT "); break;
489 case SGML_CATA_SGMLDECL:
490 fprintf(out, "SGMLDECL "); break;
494 switch (entry->type) {
495 case SGML_CATA_ENTITY:
496 case SGML_CATA_PENTITY:
497 case SGML_CATA_DOCTYPE:
498 case SGML_CATA_LINKTYPE:
499 case SGML_CATA_NOTATION:
500 fprintf(out, "%s", (const char *) entry->name); break;
501 case SGML_CATA_PUBLIC:
502 case SGML_CATA_SYSTEM:
503 case SGML_CATA_SGMLDECL:
504 case SGML_CATA_DOCUMENT:
505 case SGML_CATA_CATALOG:
507 case SGML_CATA_DELEGATE:
508 fprintf(out, "\"%s\"", entry->name); break;
512 switch (entry->type) {
513 case SGML_CATA_ENTITY:
514 case SGML_CATA_PENTITY:
515 case SGML_CATA_DOCTYPE:
516 case SGML_CATA_LINKTYPE:
517 case SGML_CATA_NOTATION:
518 case SGML_CATA_PUBLIC:
519 case SGML_CATA_SYSTEM:
520 case SGML_CATA_DELEGATE:
521 fprintf(out, " \"%s\"", entry->value); break;
529 * xmlDumpXMLCatalogNode:
530 * @catal: top catalog entry
531 * @catalog: pointer to the xml tree
532 * @doc: the containing document
533 * @ns: the current namespace
534 * @cgroup: group node for group members
536 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
539 static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
540 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
542 xmlCatalogEntryPtr cur;
544 * add all the catalog entries
547 while (cur != NULL) {
548 if (cur->group == cgroup) {
550 case XML_CATA_REMOVED:
552 case XML_CATA_BROKEN_CATALOG:
553 case XML_CATA_CATALOG:
559 case XML_CATA_NEXT_CATALOG:
560 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
561 xmlSetProp(node, BAD_CAST "catalog", cur->value);
562 xmlAddChild(catalog, node);
567 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
568 xmlSetProp(node, BAD_CAST "id", cur->name);
569 if (cur->value != NULL) {
571 xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
573 xmlSetNsProp(node, xns, BAD_CAST "base",
576 switch (cur->prefer) {
577 case XML_CATA_PREFER_NONE:
579 case XML_CATA_PREFER_PUBLIC:
580 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
582 case XML_CATA_PREFER_SYSTEM:
583 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
586 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
587 xmlAddChild(catalog, node);
589 case XML_CATA_PUBLIC:
590 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
591 xmlSetProp(node, BAD_CAST "publicId", cur->name);
592 xmlSetProp(node, BAD_CAST "uri", cur->value);
593 xmlAddChild(catalog, node);
595 case XML_CATA_SYSTEM:
596 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
597 xmlSetProp(node, BAD_CAST "systemId", cur->name);
598 xmlSetProp(node, BAD_CAST "uri", cur->value);
599 xmlAddChild(catalog, node);
601 case XML_CATA_REWRITE_SYSTEM:
602 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
603 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
604 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
605 xmlAddChild(catalog, node);
607 case XML_CATA_DELEGATE_PUBLIC:
608 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
609 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
610 xmlSetProp(node, BAD_CAST "catalog", cur->value);
611 xmlAddChild(catalog, node);
613 case XML_CATA_DELEGATE_SYSTEM:
614 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
615 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
616 xmlSetProp(node, BAD_CAST "catalog", cur->value);
617 xmlAddChild(catalog, node);
620 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
621 xmlSetProp(node, BAD_CAST "name", cur->name);
622 xmlSetProp(node, BAD_CAST "uri", cur->value);
623 xmlAddChild(catalog, node);
625 case XML_CATA_REWRITE_URI:
626 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
627 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
628 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
629 xmlAddChild(catalog, node);
631 case XML_CATA_DELEGATE_URI:
632 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
633 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
634 xmlSetProp(node, BAD_CAST "catalog", cur->value);
635 xmlAddChild(catalog, node);
637 case SGML_CATA_SYSTEM:
638 case SGML_CATA_PUBLIC:
639 case SGML_CATA_ENTITY:
640 case SGML_CATA_PENTITY:
641 case SGML_CATA_DOCTYPE:
642 case SGML_CATA_LINKTYPE:
643 case SGML_CATA_NOTATION:
644 case SGML_CATA_DELEGATE:
646 case SGML_CATA_CATALOG:
647 case SGML_CATA_DOCUMENT:
648 case SGML_CATA_SGMLDECL:
657 xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
663 xmlOutputBufferPtr buf;
668 doc = xmlNewDoc(NULL);
671 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
672 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
673 BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
675 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
677 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
682 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
683 if (catalog == NULL) {
689 xmlAddChild((xmlNodePtr) doc, catalog);
691 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
696 buf = xmlOutputBufferCreateFile(out, NULL);
701 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
710 #endif /* LIBXML_OUTPUT_ENABLED */
712 /************************************************************************
714 * Converting SGML Catalogs to XML *
716 ************************************************************************/
719 * xmlCatalogConvertEntry:
721 * @catal: pointer to the catalog being converted
723 * Convert one entry from the catalog
726 xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
727 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
728 (catal->xml == NULL))
730 switch (entry->type) {
731 case SGML_CATA_ENTITY:
732 entry->type = XML_CATA_PUBLIC;
734 case SGML_CATA_PENTITY:
735 entry->type = XML_CATA_PUBLIC;
737 case SGML_CATA_DOCTYPE:
738 entry->type = XML_CATA_PUBLIC;
740 case SGML_CATA_LINKTYPE:
741 entry->type = XML_CATA_PUBLIC;
743 case SGML_CATA_NOTATION:
744 entry->type = XML_CATA_PUBLIC;
746 case SGML_CATA_PUBLIC:
747 entry->type = XML_CATA_PUBLIC;
749 case SGML_CATA_SYSTEM:
750 entry->type = XML_CATA_SYSTEM;
752 case SGML_CATA_DELEGATE:
753 entry->type = XML_CATA_DELEGATE_PUBLIC;
755 case SGML_CATA_CATALOG:
756 entry->type = XML_CATA_CATALOG;
759 xmlHashRemoveEntry(catal->sgml, entry->name,
760 (xmlHashDeallocator) xmlFreeCatalogEntry);
764 * Conversion successful, remove from the SGML catalog
765 * and add it to the default XML one
767 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
768 entry->parent = catal->xml;
770 if (catal->xml->children == NULL)
771 catal->xml->children = entry;
773 xmlCatalogEntryPtr prev;
775 prev = catal->xml->children;
776 while (prev->next != NULL)
783 * xmlConvertSGMLCatalog:
784 * @catal: the catalog
786 * Convert all the SGML catalog entries as XML ones
788 * Returns the number of entries converted if successful, -1 otherwise
791 xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
793 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
796 if (xmlDebugCatalogs) {
797 xmlGenericError(xmlGenericErrorContext,
798 "Converting SGML catalog to XML\n");
800 xmlHashScan(catal->sgml,
801 (xmlHashScanner) xmlCatalogConvertEntry,
806 /************************************************************************
810 ************************************************************************/
813 * xmlCatalogUnWrapURN:
814 * @urn: an "urn:publicid:" to unwrap
816 * Expand the URN into the equivalent Public Identifier
818 * Returns the new identifier or NULL, the string must be deallocated
822 xmlCatalogUnWrapURN(const xmlChar *urn) {
823 xmlChar result[2000];
826 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
828 urn += sizeof(XML_URN_PUBID) - 1;
831 if (i > sizeof(result) - 4)
836 } else if (*urn == ':') {
840 } else if (*urn == ';') {
844 } else if (*urn == '%') {
845 if ((urn[1] == '2') && (urn[2] == 'B'))
847 else if ((urn[1] == '3') && (urn[2] == 'A'))
849 else if ((urn[1] == '2') && (urn[2] == 'F'))
851 else if ((urn[1] == '3') && (urn[2] == 'B'))
853 else if ((urn[1] == '2') && (urn[2] == '7'))
855 else if ((urn[1] == '3') && (urn[2] == 'F'))
857 else if ((urn[1] == '2') && (urn[2] == '3'))
859 else if ((urn[1] == '2') && (urn[2] == '5'))
874 return(xmlStrdup(result));
878 * xmlParseCatalogFile:
879 * @filename: the filename
881 * parse an XML file and build a tree. It's like xmlParseFile()
882 * except it bypass all catalog lookups.
884 * Returns the resulting document tree or NULL in case of error
888 xmlParseCatalogFile(const char *filename) {
890 xmlParserCtxtPtr ctxt;
891 char *directory = NULL;
892 xmlParserInputPtr inputStream;
893 xmlParserInputBufferPtr buf;
895 ctxt = xmlNewParserCtxt();
897 #ifdef LIBXML_SAX1_ENABLED
898 if (xmlDefaultSAXHandler.error != NULL) {
899 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
905 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
907 xmlFreeParserCtxt(ctxt);
911 inputStream = xmlNewInputStream(ctxt);
912 if (inputStream == NULL) {
913 xmlFreeParserCtxt(ctxt);
917 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
918 inputStream->buf = buf;
919 xmlBufResetInput(buf->buffer, inputStream);
921 inputPush(ctxt, inputStream);
922 if ((ctxt->directory == NULL) && (directory == NULL))
923 directory = xmlParserGetDirectory(filename);
924 if ((ctxt->directory == NULL) && (directory != NULL))
925 ctxt->directory = directory;
928 ctxt->loadsubset = 0;
932 xmlParseDocument(ctxt);
934 if (ctxt->wellFormed)
938 xmlFreeDoc(ctxt->myDoc);
941 xmlFreeParserCtxt(ctxt);
947 * xmlLoadFileContent:
948 * @filename: a file path
950 * Load a file content into memory.
952 * Returns a pointer to the 0 terminated string or NULL in case of error
955 xmlLoadFileContent(const char *filename)
970 if (filename == NULL)
974 if (stat(filename, &info) < 0)
979 if ((fd = open(filename, O_RDONLY)) < 0)
981 if ((fd = fopen(filename, "rb")) == NULL)
989 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
994 content = (xmlChar*)xmlMallocAtomic(size + 10);
995 if (content == NULL) {
996 xmlCatalogErrMemory("allocating catalog data");
1005 len = read(fd, content, size);
1008 len = fread(content, 1, size, fd);
1021 * xmlCatalogNormalizePublic:
1022 * @pubID: the public ID string
1024 * Normalizes the Public Identifier
1026 * Implements 6.2. Public Identifier Normalization
1027 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1029 * Returns the new string or NULL, the string must be deallocated
1033 xmlCatalogNormalizePublic(const xmlChar *pubID)
1045 for (p = pubID;*p != 0 && ok;p++) {
1046 if (!xmlIsBlank_ch(*p))
1048 else if (*p == 0x20 && !white)
1053 if (ok && !white) /* is normalized */
1056 ret = xmlStrdup(pubID);
1059 for (p = pubID;*p != 0;p++) {
1060 if (xmlIsBlank_ch(*p)) {
1075 /************************************************************************
1077 * The XML Catalog parser *
1079 ************************************************************************/
1081 static xmlCatalogEntryPtr
1082 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
1084 xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1085 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
1087 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1088 const xmlChar *sysID);
1090 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1094 * xmlGetXMLCatalogEntryType:
1097 * lookup the internal type associated to an XML catalog entry name
1099 * Returns the type associated with that name
1101 static xmlCatalogEntryType
1102 xmlGetXMLCatalogEntryType(const xmlChar *name) {
1103 xmlCatalogEntryType type = XML_CATA_NONE;
1104 if (xmlStrEqual(name, (const xmlChar *) "system"))
1105 type = XML_CATA_SYSTEM;
1106 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1107 type = XML_CATA_PUBLIC;
1108 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1109 type = XML_CATA_REWRITE_SYSTEM;
1110 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1111 type = XML_CATA_DELEGATE_PUBLIC;
1112 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1113 type = XML_CATA_DELEGATE_SYSTEM;
1114 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1115 type = XML_CATA_URI;
1116 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1117 type = XML_CATA_REWRITE_URI;
1118 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1119 type = XML_CATA_DELEGATE_URI;
1120 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1121 type = XML_CATA_NEXT_CATALOG;
1122 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1123 type = XML_CATA_CATALOG;
1128 * xmlParseXMLCatalogOneNode:
1129 * @cur: the XML node
1130 * @type: the type of Catalog entry
1131 * @name: the name of the node
1132 * @attrName: the attribute holding the value
1133 * @uriAttrName: the attribute holding the URI-Reference
1134 * @prefer: the PUBLIC vs. SYSTEM current preference value
1135 * @cgroup: the group which includes this node
1137 * Finishes the examination of an XML tree node of a catalog and build
1138 * a Catalog entry from it.
1140 * Returns the new Catalog entry node or NULL in case of error.
1142 static xmlCatalogEntryPtr
1143 xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1144 const xmlChar *name, const xmlChar *attrName,
1145 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1146 xmlCatalogEntryPtr cgroup) {
1149 xmlChar *nameValue = NULL;
1150 xmlChar *base = NULL;
1151 xmlChar *URL = NULL;
1152 xmlCatalogEntryPtr ret = NULL;
1154 if (attrName != NULL) {
1155 nameValue = xmlGetProp(cur, attrName);
1156 if (nameValue == NULL) {
1157 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1158 "%s entry lacks '%s'\n", name, attrName, NULL);
1162 uriValue = xmlGetProp(cur, uriAttrName);
1163 if (uriValue == NULL) {
1164 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1165 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
1169 if (nameValue != NULL)
1171 if (uriValue != NULL)
1176 base = xmlNodeGetBase(cur->doc, cur);
1177 URL = xmlBuildURI(uriValue, base);
1179 if (xmlDebugCatalogs > 1) {
1180 if (nameValue != NULL)
1181 xmlGenericError(xmlGenericErrorContext,
1182 "Found %s: '%s' '%s'\n", name, nameValue, URL);
1184 xmlGenericError(xmlGenericErrorContext,
1185 "Found %s: '%s'\n", name, URL);
1187 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
1189 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
1190 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1192 if (nameValue != NULL)
1194 if (uriValue != NULL)
1204 * xmlParseXMLCatalogNode:
1205 * @cur: the XML node
1206 * @prefer: the PUBLIC vs. SYSTEM current preference value
1207 * @parent: the parent Catalog entry
1208 * @cgroup: the group which includes this node
1210 * Examines an XML tree node of a catalog and build
1211 * a Catalog entry from it adding it to its parent. The examination can
1215 xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1216 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
1218 xmlChar *base = NULL;
1219 xmlCatalogEntryPtr entry = NULL;
1223 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1225 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
1227 prop = xmlGetProp(cur, BAD_CAST "prefer");
1229 if (xmlStrEqual(prop, BAD_CAST "system")) {
1230 prefer = XML_CATA_PREFER_SYSTEM;
1231 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1232 prefer = XML_CATA_PREFER_PUBLIC;
1234 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1235 "Invalid value for prefer: '%s'\n",
1241 prop = xmlGetProp(cur, BAD_CAST "id");
1242 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1243 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
1245 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1246 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
1247 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
1248 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1249 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
1250 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
1251 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1252 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1253 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
1254 BAD_CAST "rewritePrefix", prefer, cgroup);
1255 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1256 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1257 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
1258 BAD_CAST "catalog", prefer, cgroup);
1259 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1260 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1261 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
1262 BAD_CAST "catalog", prefer, cgroup);
1263 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1264 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1265 BAD_CAST "uri", BAD_CAST "name",
1266 BAD_CAST "uri", prefer, cgroup);
1267 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1268 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1269 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
1270 BAD_CAST "rewritePrefix", prefer, cgroup);
1271 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1272 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1273 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
1274 BAD_CAST "catalog", prefer, cgroup);
1275 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1276 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1277 BAD_CAST "nextCatalog", NULL,
1278 BAD_CAST "catalog", prefer, cgroup);
1280 if (entry != NULL) {
1281 if (parent != NULL) {
1282 entry->parent = parent;
1283 if (parent->children == NULL)
1284 parent->children = entry;
1286 xmlCatalogEntryPtr prev;
1288 prev = parent->children;
1289 while (prev->next != NULL)
1294 if (entry->type == XML_CATA_GROUP) {
1296 * Recurse to propagate prefer to the subtree
1297 * (xml:base handling is automated)
1299 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1307 * xmlParseXMLCatalogNodeList:
1308 * @cur: the XML node list of siblings
1309 * @prefer: the PUBLIC vs. SYSTEM current preference value
1310 * @parent: the parent Catalog entry
1311 * @cgroup: the group which includes this list
1313 * Examines a list of XML sibling nodes of a catalog and build
1314 * a list of Catalog entry from it adding it to the parent.
1315 * The examination will recurse to examine node subtrees.
1318 xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1319 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
1320 while (cur != NULL) {
1321 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1322 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1323 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
1327 /* TODO: sort the list according to REWRITE lengths and prefer value */
1331 * xmlParseXMLCatalogFile:
1332 * @prefer: the PUBLIC vs. SYSTEM current preference value
1333 * @filename: the filename for the catalog
1335 * Parses the catalog file to extract the XML tree and then analyze the
1336 * tree to build a list of Catalog entries corresponding to this catalog
1338 * Returns the resulting Catalog entries list
1340 static xmlCatalogEntryPtr
1341 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1345 xmlCatalogEntryPtr parent = NULL;
1347 if (filename == NULL)
1350 doc = xmlParseCatalogFile((const char *) filename);
1352 if (xmlDebugCatalogs)
1353 xmlGenericError(xmlGenericErrorContext,
1354 "Failed to parse catalog %s\n", filename);
1358 if (xmlDebugCatalogs)
1359 xmlGenericError(xmlGenericErrorContext,
1360 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
1362 cur = xmlDocGetRootElement(doc);
1363 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1364 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1365 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1367 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1368 (const xmlChar *)filename, NULL, prefer, NULL);
1369 if (parent == NULL) {
1374 prop = xmlGetProp(cur, BAD_CAST "prefer");
1376 if (xmlStrEqual(prop, BAD_CAST "system")) {
1377 prefer = XML_CATA_PREFER_SYSTEM;
1378 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1379 prefer = XML_CATA_PREFER_PUBLIC;
1381 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1382 "Invalid value for prefer: '%s'\n",
1387 cur = cur->children;
1388 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
1390 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1391 "File %s is not an XML Catalog\n",
1392 filename, NULL, NULL);
1401 * xmlFetchXMLCatalogFile:
1402 * @catal: an existing but incomplete catalog entry
1404 * Fetch and parse the subcatalog referenced by an entry
1406 * Returns 0 in case of success, -1 otherwise
1409 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
1410 xmlCatalogEntryPtr doc;
1414 if (catal->URL == NULL)
1418 * lock the whole catalog for modification
1420 xmlRMutexLock(xmlCatalogMutex);
1421 if (catal->children != NULL) {
1422 /* Okay someone else did it in the meantime */
1423 xmlRMutexUnlock(xmlCatalogMutex);
1427 if (xmlCatalogXMLFiles != NULL) {
1428 doc = (xmlCatalogEntryPtr)
1429 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1431 if (xmlDebugCatalogs)
1432 xmlGenericError(xmlGenericErrorContext,
1433 "Found %s in file hash\n", catal->URL);
1435 if (catal->type == XML_CATA_CATALOG)
1436 catal->children = doc->children;
1438 catal->children = doc;
1440 xmlRMutexUnlock(xmlCatalogMutex);
1443 if (xmlDebugCatalogs)
1444 xmlGenericError(xmlGenericErrorContext,
1445 "%s not found in file hash\n", catal->URL);
1449 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1450 * use the existing catalog, there is no recursion allowed at
1453 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
1455 catal->type = XML_CATA_BROKEN_CATALOG;
1456 xmlRMutexUnlock(xmlCatalogMutex);
1460 if (catal->type == XML_CATA_CATALOG)
1461 catal->children = doc->children;
1463 catal->children = doc;
1467 if (xmlCatalogXMLFiles == NULL)
1468 xmlCatalogXMLFiles = xmlHashCreate(10);
1469 if (xmlCatalogXMLFiles != NULL) {
1470 if (xmlDebugCatalogs)
1471 xmlGenericError(xmlGenericErrorContext,
1472 "%s added to file hash\n", catal->URL);
1473 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
1475 xmlRMutexUnlock(xmlCatalogMutex);
1479 /************************************************************************
1481 * XML Catalog handling *
1483 ************************************************************************/
1487 * @catal: top of an XML catalog
1488 * @type: the type of record to add to the catalog
1489 * @orig: the system, public or prefix to match (or NULL)
1490 * @replace: the replacement value for the match
1492 * Add an entry in the XML catalog, it may overwrite existing but
1493 * different entries.
1495 * Returns 0 if successful, -1 otherwise
1498 xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1499 const xmlChar *orig, const xmlChar *replace) {
1500 xmlCatalogEntryPtr cur;
1501 xmlCatalogEntryType typ;
1504 if ((catal == NULL) ||
1505 ((catal->type != XML_CATA_CATALOG) &&
1506 (catal->type != XML_CATA_BROKEN_CATALOG)))
1508 if (catal->children == NULL) {
1509 xmlFetchXMLCatalogFile(catal);
1511 if (catal->children == NULL)
1514 typ = xmlGetXMLCatalogEntryType(type);
1515 if (typ == XML_CATA_NONE) {
1516 if (xmlDebugCatalogs)
1517 xmlGenericError(xmlGenericErrorContext,
1518 "Failed to add unknown element %s to catalog\n", type);
1522 cur = catal->children;
1524 * Might be a simple "update in place"
1527 while (cur != NULL) {
1528 if ((orig != NULL) && (cur->type == typ) &&
1529 (xmlStrEqual(orig, cur->name))) {
1530 if (xmlDebugCatalogs)
1531 xmlGenericError(xmlGenericErrorContext,
1532 "Updating element %s to catalog\n", type);
1533 if (cur->value != NULL)
1534 xmlFree(cur->value);
1535 if (cur->URL != NULL)
1537 cur->value = xmlStrdup(replace);
1538 cur->URL = xmlStrdup(replace);
1541 if (cur->next == NULL)
1546 if (xmlDebugCatalogs)
1547 xmlGenericError(xmlGenericErrorContext,
1548 "Adding element %s to catalog\n", type);
1550 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1551 NULL, catal->prefer, NULL);
1553 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1554 NULL, catal->prefer, NULL);
1556 catal->type = XML_CATA_CATALOG;
1557 cur = (xmlCatalogEntryPtr)xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1559 cur->children = catal->children;
1567 * @catal: top of an XML catalog
1568 * @value: the value to remove from the catalog
1570 * Remove entries in the XML catalog where the value or the URI
1571 * is equal to @value
1573 * Returns the number of entries removed if successful, -1 otherwise
1576 xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1577 xmlCatalogEntryPtr cur;
1580 if ((catal == NULL) ||
1581 ((catal->type != XML_CATA_CATALOG) &&
1582 (catal->type != XML_CATA_BROKEN_CATALOG)))
1586 if (catal->children == NULL) {
1587 xmlFetchXMLCatalogFile(catal);
1593 cur = catal->children;
1594 while (cur != NULL) {
1595 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1596 (xmlStrEqual(value, cur->value))) {
1597 if (xmlDebugCatalogs) {
1598 if (cur->name != NULL)
1599 xmlGenericError(xmlGenericErrorContext,
1600 "Removing element %s from catalog\n", cur->name);
1602 xmlGenericError(xmlGenericErrorContext,
1603 "Removing element %s from catalog\n", cur->value);
1605 cur->type = XML_CATA_REMOVED;
1613 * xmlCatalogXMLResolve:
1614 * @catal: a catalog list
1615 * @pubID: the public ID string
1616 * @sysID: the system ID string
1618 * Do a complete resolution lookup of an External Identifier for a
1619 * list of catalog entries.
1621 * Implements (or tries to) 7.1. External Identifier Resolution
1622 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1624 * Returns the URI of the resource or NULL if not found
1627 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1628 const xmlChar *sysID) {
1629 xmlChar *ret = NULL;
1630 xmlCatalogEntryPtr cur;
1631 int haveDelegate = 0;
1635 * protection against loops
1637 if (catal->depth > MAX_CATAL_DEPTH) {
1638 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1639 "Detected recursion in catalog %s\n",
1640 catal->name, NULL, NULL);
1646 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1648 if (sysID != NULL) {
1649 xmlCatalogEntryPtr rewrite = NULL;
1650 int lenrewrite = 0, len;
1653 while (cur != NULL) {
1654 switch (cur->type) {
1655 case XML_CATA_SYSTEM:
1656 if (xmlStrEqual(sysID, cur->name)) {
1657 if (xmlDebugCatalogs)
1658 xmlGenericError(xmlGenericErrorContext,
1659 "Found system match %s, using %s\n",
1660 cur->name, cur->URL);
1662 return(xmlStrdup(cur->URL));
1665 case XML_CATA_REWRITE_SYSTEM:
1666 len = xmlStrlen(cur->name);
1667 if ((len > lenrewrite) &&
1668 (!xmlStrncmp(sysID, cur->name, len))) {
1673 case XML_CATA_DELEGATE_SYSTEM:
1674 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1677 case XML_CATA_NEXT_CATALOG:
1685 if (rewrite != NULL) {
1686 if (xmlDebugCatalogs)
1687 xmlGenericError(xmlGenericErrorContext,
1688 "Using rewriting rule %s\n", rewrite->name);
1689 ret = xmlStrdup(rewrite->URL);
1691 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1696 const xmlChar *delegates[MAX_DELEGATE];
1700 * Assume the entries have been sorted by decreasing substring
1701 * matches when the list was produced.
1704 while (cur != NULL) {
1705 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1706 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
1707 for (i = 0;i < nbList;i++)
1708 if (xmlStrEqual(cur->URL, delegates[i]))
1714 if (nbList < MAX_DELEGATE)
1715 delegates[nbList++] = cur->URL;
1717 if (cur->children == NULL) {
1718 xmlFetchXMLCatalogFile(cur);
1720 if (cur->children != NULL) {
1721 if (xmlDebugCatalogs)
1722 xmlGenericError(xmlGenericErrorContext,
1723 "Trying system delegate %s\n", cur->URL);
1724 ret = xmlCatalogListXMLResolve(
1725 cur->children, NULL, sysID);
1735 * Apply the cut algorithm explained in 4/
1738 return(XML_CATAL_BREAK);
1742 * Then tries 5/ 6/ if a public ID is provided
1744 if (pubID != NULL) {
1747 while (cur != NULL) {
1748 switch (cur->type) {
1749 case XML_CATA_PUBLIC:
1750 if (xmlStrEqual(pubID, cur->name)) {
1751 if (xmlDebugCatalogs)
1752 xmlGenericError(xmlGenericErrorContext,
1753 "Found public match %s\n", cur->name);
1755 return(xmlStrdup(cur->URL));
1758 case XML_CATA_DELEGATE_PUBLIC:
1759 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1760 (cur->prefer == XML_CATA_PREFER_PUBLIC))
1763 case XML_CATA_NEXT_CATALOG:
1773 const xmlChar *delegates[MAX_DELEGATE];
1777 * Assume the entries have been sorted by decreasing substring
1778 * matches when the list was produced.
1781 while (cur != NULL) {
1782 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
1783 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1784 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
1786 for (i = 0;i < nbList;i++)
1787 if (xmlStrEqual(cur->URL, delegates[i]))
1793 if (nbList < MAX_DELEGATE)
1794 delegates[nbList++] = cur->URL;
1796 if (cur->children == NULL) {
1797 xmlFetchXMLCatalogFile(cur);
1799 if (cur->children != NULL) {
1800 if (xmlDebugCatalogs)
1801 xmlGenericError(xmlGenericErrorContext,
1802 "Trying public delegate %s\n", cur->URL);
1803 ret = xmlCatalogListXMLResolve(
1804 cur->children, pubID, NULL);
1814 * Apply the cut algorithm explained in 4/
1817 return(XML_CATAL_BREAK);
1822 while (cur != NULL) {
1823 if (cur->type == XML_CATA_NEXT_CATALOG) {
1824 if (cur->children == NULL) {
1825 xmlFetchXMLCatalogFile(cur);
1827 if (cur->children != NULL) {
1828 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1832 } else if (catal->depth > MAX_CATAL_DEPTH) {
1846 * xmlCatalogXMLResolveURI:
1847 * @catal: a catalog list
1849 * @sysID: the system ID string
1851 * Do a complete resolution lookup of an External Identifier for a
1852 * list of catalog entries.
1854 * Implements (or tries to) 7.2.2. URI Resolution
1855 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1857 * Returns the URI of the resource or NULL if not found
1860 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1861 xmlChar *ret = NULL;
1862 xmlCatalogEntryPtr cur;
1863 int haveDelegate = 0;
1865 xmlCatalogEntryPtr rewrite = NULL;
1866 int lenrewrite = 0, len;
1874 if (catal->depth > MAX_CATAL_DEPTH) {
1875 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1876 "Detected recursion in catalog %s\n",
1877 catal->name, NULL, NULL);
1882 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1886 while (cur != NULL) {
1887 switch (cur->type) {
1889 if (xmlStrEqual(URI, cur->name)) {
1890 if (xmlDebugCatalogs)
1891 xmlGenericError(xmlGenericErrorContext,
1892 "Found URI match %s\n", cur->name);
1893 return(xmlStrdup(cur->URL));
1896 case XML_CATA_REWRITE_URI:
1897 len = xmlStrlen(cur->name);
1898 if ((len > lenrewrite) &&
1899 (!xmlStrncmp(URI, cur->name, len))) {
1904 case XML_CATA_DELEGATE_URI:
1905 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1908 case XML_CATA_NEXT_CATALOG:
1916 if (rewrite != NULL) {
1917 if (xmlDebugCatalogs)
1918 xmlGenericError(xmlGenericErrorContext,
1919 "Using rewriting rule %s\n", rewrite->name);
1920 ret = xmlStrdup(rewrite->URL);
1922 ret = xmlStrcat(ret, &URI[lenrewrite]);
1926 const xmlChar *delegates[MAX_DELEGATE];
1930 * Assume the entries have been sorted by decreasing substring
1931 * matches when the list was produced.
1934 while (cur != NULL) {
1935 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1936 (cur->type == XML_CATA_DELEGATE_URI)) &&
1937 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
1938 for (i = 0;i < nbList;i++)
1939 if (xmlStrEqual(cur->URL, delegates[i]))
1945 if (nbList < MAX_DELEGATE)
1946 delegates[nbList++] = cur->URL;
1948 if (cur->children == NULL) {
1949 xmlFetchXMLCatalogFile(cur);
1951 if (cur->children != NULL) {
1952 if (xmlDebugCatalogs)
1953 xmlGenericError(xmlGenericErrorContext,
1954 "Trying URI delegate %s\n", cur->URL);
1955 ret = xmlCatalogListXMLResolveURI(
1956 cur->children, URI);
1964 * Apply the cut algorithm explained in 4/
1966 return(XML_CATAL_BREAK);
1970 while (cur != NULL) {
1971 if (cur->type == XML_CATA_NEXT_CATALOG) {
1972 if (cur->children == NULL) {
1973 xmlFetchXMLCatalogFile(cur);
1975 if (cur->children != NULL) {
1976 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1989 * xmlCatalogListXMLResolve:
1990 * @catal: a catalog list
1991 * @pubID: the public ID string
1992 * @sysID: the system ID string
1994 * Do a complete resolution lookup of an External Identifier for a
1997 * Implements (or tries to) 7.1. External Identifier Resolution
1998 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2000 * Returns the URI of the resource or NULL if not found
2003 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
2004 const xmlChar *sysID) {
2005 xmlChar *ret = NULL;
2006 xmlChar *urnID = NULL;
2011 if ((pubID == NULL) && (sysID == NULL))
2014 normid = xmlCatalogNormalizePublic(pubID);
2016 pubID = (*normid != 0 ? normid : NULL);
2018 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2019 urnID = xmlCatalogUnWrapURN(pubID);
2020 if (xmlDebugCatalogs) {
2022 xmlGenericError(xmlGenericErrorContext,
2023 "Public URN ID %s expanded to NULL\n", pubID);
2025 xmlGenericError(xmlGenericErrorContext,
2026 "Public URN ID expanded to %s\n", urnID);
2028 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2035 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2036 urnID = xmlCatalogUnWrapURN(sysID);
2037 if (xmlDebugCatalogs) {
2039 xmlGenericError(xmlGenericErrorContext,
2040 "System URN ID %s expanded to NULL\n", sysID);
2042 xmlGenericError(xmlGenericErrorContext,
2043 "System URN ID expanded to %s\n", urnID);
2046 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2047 else if (xmlStrEqual(pubID, urnID))
2048 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2050 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
2058 while (catal != NULL) {
2059 if (catal->type == XML_CATA_CATALOG) {
2060 if (catal->children == NULL) {
2061 xmlFetchXMLCatalogFile(catal);
2063 if (catal->children != NULL) {
2064 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
2067 } else if ((catal->children != NULL) &&
2068 (catal->children->depth > MAX_CATAL_DEPTH)) {
2074 catal = catal->next;
2082 * xmlCatalogListXMLResolveURI:
2083 * @catal: a catalog list
2086 * Do a complete resolution lookup of an URI for a list of catalogs
2088 * Implements (or tries to) 7.2. URI Resolution
2089 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2091 * Returns the URI of the resource or NULL if not found
2094 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2095 xmlChar *ret = NULL;
2096 xmlChar *urnID = NULL;
2103 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2104 urnID = xmlCatalogUnWrapURN(URI);
2105 if (xmlDebugCatalogs) {
2107 xmlGenericError(xmlGenericErrorContext,
2108 "URN ID %s expanded to NULL\n", URI);
2110 xmlGenericError(xmlGenericErrorContext,
2111 "URN ID expanded to %s\n", urnID);
2113 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2118 while (catal != NULL) {
2119 if (catal->type == XML_CATA_CATALOG) {
2120 if (catal->children == NULL) {
2121 xmlFetchXMLCatalogFile(catal);
2123 if (catal->children != NULL) {
2124 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2129 catal = catal->next;
2134 /************************************************************************
2136 * The SGML Catalog parser *
2138 ************************************************************************/
2143 #define SKIP(x) cur += x;
2145 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2148 * xmlParseSGMLCatalogComment:
2149 * @cur: the current character
2151 * Skip a comment in an SGML catalog
2153 * Returns new current character
2155 static const xmlChar *
2156 xmlParseSGMLCatalogComment(const xmlChar *cur) {
2157 if ((cur[0] != '-') || (cur[1] != '-'))
2160 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2169 * xmlParseSGMLCatalogPubid:
2170 * @cur: the current character
2171 * @id: the return location
2173 * Parse an SGML catalog ID
2175 * Returns new current character and store the value in @id
2177 static const xmlChar *
2178 xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
2179 xmlChar *buf = NULL, *tmp;
2190 } else if (RAW == '\'') {
2196 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
2198 xmlCatalogErrMemory("allocating public ID");
2201 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
2202 if ((*cur == stop) && (stop != ' '))
2204 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
2206 if (len + 1 >= size) {
2208 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2210 xmlCatalogErrMemory("allocating public ID");
2222 if (!IS_BLANK_CH(*cur)) {
2238 * xmlParseSGMLCatalogName:
2239 * @cur: the current character
2240 * @name: the return location
2242 * Parse an SGML catalog name
2244 * Returns new current character and store the value in @name
2246 static const xmlChar *
2247 xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
2248 xmlChar buf[XML_MAX_NAMELEN + 5];
2255 * Handler for more complex cases
2258 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2262 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2263 (c == '.') || (c == '-') ||
2264 (c == '_') || (c == ':'))) {
2268 if (len >= XML_MAX_NAMELEN)
2271 *name = xmlStrndup(buf, len);
2276 * xmlGetSGMLCatalogEntryType:
2277 * @name: the entry name
2279 * Get the Catalog entry type for a given SGML Catalog name
2281 * Returns Catalog entry type
2283 static xmlCatalogEntryType
2284 xmlGetSGMLCatalogEntryType(const xmlChar *name) {
2285 xmlCatalogEntryType type = XML_CATA_NONE;
2286 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2287 type = SGML_CATA_SYSTEM;
2288 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2289 type = SGML_CATA_PUBLIC;
2290 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2291 type = SGML_CATA_DELEGATE;
2292 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2293 type = SGML_CATA_ENTITY;
2294 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2295 type = SGML_CATA_DOCTYPE;
2296 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2297 type = SGML_CATA_LINKTYPE;
2298 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2299 type = SGML_CATA_NOTATION;
2300 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2301 type = SGML_CATA_SGMLDECL;
2302 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2303 type = SGML_CATA_DOCUMENT;
2304 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2305 type = SGML_CATA_CATALOG;
2306 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2307 type = SGML_CATA_BASE;
2312 * xmlParseSGMLCatalog:
2313 * @catal: the SGML Catalog
2314 * @value: the content of the SGML Catalog serialization
2315 * @file: the filepath for the catalog
2316 * @super: should this be handled as a Super Catalog in which case
2317 * parsing is not recursive
2319 * Parse an SGML catalog content and fill up the @catal hash table with
2320 * the new entries found.
2322 * Returns 0 in case of success, -1 in case of error.
2325 xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2326 const char *file, int super) {
2327 const xmlChar *cur = value;
2328 xmlChar *base = NULL;
2331 if ((cur == NULL) || (file == NULL))
2333 base = xmlStrdup((const xmlChar *) file);
2335 while ((cur != NULL) && (cur[0] != 0)) {
2339 if ((cur[0] == '-') && (cur[1] == '-')) {
2340 cur = xmlParseSGMLCatalogComment(cur);
2346 xmlChar *sysid = NULL;
2347 xmlChar *name = NULL;
2348 xmlCatalogEntryType type = XML_CATA_NONE;
2350 cur = xmlParseSGMLCatalogName(cur, &name);
2355 if (!IS_BLANK_CH(*cur)) {
2360 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2361 type = SGML_CATA_SYSTEM;
2362 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2363 type = SGML_CATA_PUBLIC;
2364 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2365 type = SGML_CATA_DELEGATE;
2366 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2367 type = SGML_CATA_ENTITY;
2368 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2369 type = SGML_CATA_DOCTYPE;
2370 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2371 type = SGML_CATA_LINKTYPE;
2372 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2373 type = SGML_CATA_NOTATION;
2374 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2375 type = SGML_CATA_SGMLDECL;
2376 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2377 type = SGML_CATA_DOCUMENT;
2378 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2379 type = SGML_CATA_CATALOG;
2380 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2381 type = SGML_CATA_BASE;
2382 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2384 cur = xmlParseSGMLCatalogName(cur, &name);
2396 case SGML_CATA_ENTITY:
2398 type = SGML_CATA_PENTITY;
2399 /* Falls through. */
2400 case SGML_CATA_PENTITY:
2401 case SGML_CATA_DOCTYPE:
2402 case SGML_CATA_LINKTYPE:
2403 case SGML_CATA_NOTATION:
2404 cur = xmlParseSGMLCatalogName(cur, &name);
2409 if (!IS_BLANK_CH(*cur)) {
2414 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2420 case SGML_CATA_PUBLIC:
2421 case SGML_CATA_SYSTEM:
2422 case SGML_CATA_DELEGATE:
2423 cur = xmlParseSGMLCatalogPubid(cur, &name);
2428 if (type != SGML_CATA_SYSTEM) {
2431 normid = xmlCatalogNormalizePublic(name);
2432 if (normid != NULL) {
2443 if (!IS_BLANK_CH(*cur)) {
2448 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2454 case SGML_CATA_BASE:
2455 case SGML_CATA_CATALOG:
2456 case SGML_CATA_DOCUMENT:
2457 case SGML_CATA_SGMLDECL:
2458 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2473 } else if (type == SGML_CATA_BASE) {
2476 base = xmlStrdup(sysid);
2477 } else if ((type == SGML_CATA_PUBLIC) ||
2478 (type == SGML_CATA_SYSTEM)) {
2481 filename = xmlBuildURI(sysid, base);
2482 if (filename != NULL) {
2483 xmlCatalogEntryPtr entry;
2485 entry = xmlNewCatalogEntry(type, name, filename,
2486 NULL, XML_CATA_PREFER_NONE, NULL);
2487 res = xmlHashAddEntry(catal->sgml, name, entry);
2489 xmlFreeCatalogEntry(entry);
2494 } else if (type == SGML_CATA_CATALOG) {
2496 xmlCatalogEntryPtr entry;
2498 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
2499 XML_CATA_PREFER_NONE, NULL);
2500 res = xmlHashAddEntry(catal->sgml, sysid, entry);
2502 xmlFreeCatalogEntry(entry);
2507 filename = xmlBuildURI(sysid, base);
2508 if (filename != NULL) {
2509 xmlExpandCatalog(catal, (const char *)filename);
2515 * drop anything else we won't handle it
2530 /************************************************************************
2532 * SGML Catalog handling *
2534 ************************************************************************/
2537 * xmlCatalogGetSGMLPublic:
2538 * @catal: an SGML catalog hash
2539 * @pubID: the public ID string
2541 * Try to lookup the catalog local reference associated to a public ID
2543 * Returns the local resource if found or NULL otherwise.
2545 static const xmlChar *
2546 xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2547 xmlCatalogEntryPtr entry;
2553 normid = xmlCatalogNormalizePublic(pubID);
2555 pubID = (*normid != 0 ? normid : NULL);
2557 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2558 if (entry == NULL) {
2563 if (entry->type == SGML_CATA_PUBLIC) {
2574 * xmlCatalogGetSGMLSystem:
2575 * @catal: an SGML catalog hash
2576 * @sysID: the system ID string
2578 * Try to lookup the catalog local reference for a system ID
2580 * Returns the local resource if found or NULL otherwise.
2582 static const xmlChar *
2583 xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2584 xmlCatalogEntryPtr entry;
2589 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2592 if (entry->type == SGML_CATA_SYSTEM)
2598 * xmlCatalogSGMLResolve:
2599 * @catal: the SGML catalog
2600 * @pubID: the public ID string
2601 * @sysID: the system ID string
2603 * Do a complete resolution lookup of an External Identifier
2605 * Returns the URI of the resource or NULL if not found
2607 static const xmlChar *
2608 xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2609 const xmlChar *sysID) {
2610 const xmlChar *ret = NULL;
2612 if (catal->sgml == NULL)
2616 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2620 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2626 /************************************************************************
2628 * Specific Public interfaces *
2630 ************************************************************************/
2633 * xmlLoadSGMLSuperCatalog:
2634 * @filename: a file path
2636 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2637 * references. This is only needed for manipulating SGML Super Catalogs
2638 * like adding and removing CATALOG or DELEGATE entries.
2640 * Returns the catalog parsed or NULL in case of error
2643 xmlLoadSGMLSuperCatalog(const char *filename)
2646 xmlCatalogPtr catal;
2649 content = xmlLoadFileContent(filename);
2650 if (content == NULL)
2653 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2654 if (catal == NULL) {
2659 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2662 xmlFreeCatalog(catal);
2670 * @filename: a file path
2672 * Load the catalog and build the associated data structures.
2673 * This can be either an XML Catalog or an SGML Catalog
2674 * It will recurse in SGML CATALOG entries. On the other hand XML
2675 * Catalogs are not handled recursively.
2677 * Returns the catalog parsed or NULL in case of error
2680 xmlLoadACatalog(const char *filename)
2684 xmlCatalogPtr catal;
2687 content = xmlLoadFileContent(filename);
2688 if (content == NULL)
2694 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2695 (!(((*first >= 'A') && (*first <= 'Z')) ||
2696 ((*first >= 'a') && (*first <= 'z')))))
2699 if (*first != '<') {
2700 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2701 if (catal == NULL) {
2705 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2707 xmlFreeCatalog(catal);
2712 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2713 if (catal == NULL) {
2717 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2718 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
2727 * @filename: a file path
2729 * Load the catalog and expand the existing catal structure.
2730 * This can be either an XML Catalog or an SGML Catalog
2732 * Returns 0 in case of success, -1 in case of error
2735 xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2739 if ((catal == NULL) || (filename == NULL))
2743 if (catal->type == XML_SGML_CATALOG_TYPE) {
2746 content = xmlLoadFileContent(filename);
2747 if (content == NULL)
2750 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2757 xmlCatalogEntryPtr tmp, cur;
2758 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2759 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
2765 while (cur->next != NULL) cur = cur->next;
2773 * xmlACatalogResolveSystem:
2775 * @sysID: the system ID string
2777 * Try to lookup the catalog resource for a system ID
2779 * Returns the resource if found or NULL otherwise, the value returned
2780 * must be freed by the caller.
2783 xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2784 xmlChar *ret = NULL;
2786 if ((sysID == NULL) || (catal == NULL))
2789 if (xmlDebugCatalogs)
2790 xmlGenericError(xmlGenericErrorContext,
2791 "Resolve sysID %s\n", sysID);
2793 if (catal->type == XML_XML_CATALOG_TYPE) {
2794 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2795 if (ret == XML_CATAL_BREAK)
2798 const xmlChar *sgml;
2800 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2802 ret = xmlStrdup(sgml);
2808 * xmlACatalogResolvePublic:
2810 * @pubID: the public ID string
2812 * Try to lookup the catalog local reference associated to a public ID in that catalog
2814 * Returns the local resource if found or NULL otherwise, the value returned
2815 * must be freed by the caller.
2818 xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2819 xmlChar *ret = NULL;
2821 if ((pubID == NULL) || (catal == NULL))
2824 if (xmlDebugCatalogs)
2825 xmlGenericError(xmlGenericErrorContext,
2826 "Resolve pubID %s\n", pubID);
2828 if (catal->type == XML_XML_CATALOG_TYPE) {
2829 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2830 if (ret == XML_CATAL_BREAK)
2833 const xmlChar *sgml;
2835 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2837 ret = xmlStrdup(sgml);
2843 * xmlACatalogResolve:
2845 * @pubID: the public ID string
2846 * @sysID: the system ID string
2848 * Do a complete resolution lookup of an External Identifier
2850 * Returns the URI of the resource or NULL if not found, it must be freed
2854 xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2855 const xmlChar * sysID)
2857 xmlChar *ret = NULL;
2859 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2862 if (xmlDebugCatalogs) {
2863 if ((pubID != NULL) && (sysID != NULL)) {
2864 xmlGenericError(xmlGenericErrorContext,
2865 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2866 } else if (pubID != NULL) {
2867 xmlGenericError(xmlGenericErrorContext,
2868 "Resolve: pubID %s\n", pubID);
2870 xmlGenericError(xmlGenericErrorContext,
2871 "Resolve: sysID %s\n", sysID);
2875 if (catal->type == XML_XML_CATALOG_TYPE) {
2876 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2877 if (ret == XML_CATAL_BREAK)
2880 const xmlChar *sgml;
2882 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2884 ret = xmlStrdup(sgml);
2890 * xmlACatalogResolveURI:
2894 * Do a complete resolution lookup of an URI
2896 * Returns the URI of the resource or NULL if not found, it must be freed
2900 xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2901 xmlChar *ret = NULL;
2903 if ((URI == NULL) || (catal == NULL))
2906 if (xmlDebugCatalogs)
2907 xmlGenericError(xmlGenericErrorContext,
2908 "Resolve URI %s\n", URI);
2910 if (catal->type == XML_XML_CATALOG_TYPE) {
2911 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2912 if (ret == XML_CATAL_BREAK)
2915 const xmlChar *sgml;
2917 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2919 ret = xmlStrdup(sgml);
2924 #ifdef LIBXML_OUTPUT_ENABLED
2930 * Dump the given catalog to the given file.
2933 xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
2934 if ((out == NULL) || (catal == NULL))
2937 if (catal->type == XML_XML_CATALOG_TYPE) {
2938 xmlDumpXMLCatalog(out, catal->xml);
2940 xmlHashScan(catal->sgml,
2941 (xmlHashScanner) xmlCatalogDumpEntry, out);
2944 #endif /* LIBXML_OUTPUT_ENABLED */
2949 * @type: the type of record to add to the catalog
2950 * @orig: the system, public or prefix to match
2951 * @replace: the replacement value for the match
2953 * Add an entry in the catalog, it may overwrite existing but
2954 * different entries.
2956 * Returns 0 if successful, -1 otherwise
2959 xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2960 const xmlChar * orig, const xmlChar * replace)
2967 if (catal->type == XML_XML_CATALOG_TYPE) {
2968 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2970 xmlCatalogEntryType cattype;
2972 cattype = xmlGetSGMLCatalogEntryType(type);
2973 if (cattype != XML_CATA_NONE) {
2974 xmlCatalogEntryPtr entry;
2976 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
2977 XML_CATA_PREFER_NONE, NULL);
2978 if (catal->sgml == NULL)
2979 catal->sgml = xmlHashCreate(10);
2980 res = xmlHashAddEntry(catal->sgml, orig, entry);
2987 * xmlACatalogRemove:
2989 * @value: the value to remove
2991 * Remove an entry from the catalog
2993 * Returns the number of entries removed if successful, -1 otherwise
2996 xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2999 if ((catal == NULL) || (value == NULL))
3002 if (catal->type == XML_XML_CATALOG_TYPE) {
3003 res = xmlDelXMLCatalog(catal->xml, value);
3005 res = xmlHashRemoveEntry(catal->sgml, value,
3006 (xmlHashDeallocator) xmlFreeCatalogEntry);
3015 * @sgml: should this create an SGML catalog
3017 * create a new Catalog.
3019 * Returns the xmlCatalogPtr or NULL in case of error
3022 xmlNewCatalog(int sgml) {
3023 xmlCatalogPtr catal = NULL;
3026 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3027 xmlCatalogDefaultPrefer);
3028 if ((catal != NULL) && (catal->sgml == NULL))
3029 catal->sgml = xmlHashCreate(10);
3031 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3032 xmlCatalogDefaultPrefer);
3037 * xmlCatalogIsEmpty:
3038 * @catal: should this create an SGML catalog
3040 * Check is a catalog is empty
3042 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3045 xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3049 if (catal->type == XML_XML_CATALOG_TYPE) {
3050 if (catal->xml == NULL)
3052 if ((catal->xml->type != XML_CATA_CATALOG) &&
3053 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3055 if (catal->xml->children == NULL)
3061 if (catal->sgml == NULL)
3063 res = xmlHashSize(catal->sgml);
3072 /************************************************************************
3074 * Public interfaces manipulating the global shared default catalog *
3076 ************************************************************************/
3079 * xmlInitializeCatalogData:
3081 * Do the catalog initialization only of global data, doesn't try to load
3082 * any catalog actually.
3083 * this function is not thread safe, catalog initialization should
3084 * preferably be done once at startup
3087 xmlInitializeCatalogData(void) {
3088 if (xmlCatalogInitialized != 0)
3091 if (getenv("XML_DEBUG_CATALOG"))
3092 xmlDebugCatalogs = 1;
3093 xmlCatalogMutex = xmlNewRMutex();
3095 xmlCatalogInitialized = 1;
3098 * xmlInitializeCatalog:
3100 * Do the catalog initialization.
3101 * this function is not thread safe, catalog initialization should
3102 * preferably be done once at startup
3105 xmlInitializeCatalog(void) {
3106 if (xmlCatalogInitialized != 0)
3109 xmlInitializeCatalogData();
3110 xmlRMutexLock(xmlCatalogMutex);
3112 if (getenv("XML_DEBUG_CATALOG"))
3113 xmlDebugCatalogs = 1;
3115 if (xmlDefaultCatalog == NULL) {
3116 const char *catalogs;
3118 const char *cur, *paths;
3119 xmlCatalogPtr catal;
3120 xmlCatalogEntryPtr *nextent;
3122 catalogs = (const char *) getenv("XML_CATALOG_FILES");
3123 if (catalogs == NULL)
3124 #if defined(_WIN32) && defined(_MSC_VER)
3127 hmodule = GetModuleHandleA("libxml2.dll");
3128 if (hmodule == NULL)
3129 hmodule = GetModuleHandleA(NULL);
3130 if (hmodule != NULL) {
3132 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3134 char* p = &(buf[len]);
3135 while (*p != '\\' && p > buf)
3139 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3140 uri = xmlCanonicPath((const xmlChar*)buf);
3142 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3148 catalogs = XML_XML_DEFAULT_CATALOG;
3151 catalogs = XML_XML_DEFAULT_CATALOG;
3154 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3155 xmlCatalogDefaultPrefer);
3156 if (catal != NULL) {
3157 /* the XML_CATALOG_FILES envvar is allowed to contain a
3158 space-separated list of entries. */
3160 nextent = &catal->xml;
3161 while (*cur != '\0') {
3162 while (xmlIsBlank_ch(*cur))
3166 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
3168 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
3170 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3171 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
3172 if (*nextent != NULL)
3173 nextent = &((*nextent)->next);
3178 xmlDefaultCatalog = catal;
3182 xmlRMutexUnlock(xmlCatalogMutex);
3188 * @filename: a file path
3190 * Load the catalog and makes its definitions effective for the default
3191 * external entity loader. It will recurse in SGML CATALOG entries.
3192 * this function is not thread safe, catalog initialization should
3193 * preferably be done once at startup
3195 * Returns 0 in case of success -1 in case of error
3198 xmlLoadCatalog(const char *filename)
3201 xmlCatalogPtr catal;
3203 if (!xmlCatalogInitialized)
3204 xmlInitializeCatalogData();
3206 xmlRMutexLock(xmlCatalogMutex);
3208 if (xmlDefaultCatalog == NULL) {
3209 catal = xmlLoadACatalog(filename);
3210 if (catal == NULL) {
3211 xmlRMutexUnlock(xmlCatalogMutex);
3215 xmlDefaultCatalog = catal;
3216 xmlRMutexUnlock(xmlCatalogMutex);
3220 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
3221 xmlRMutexUnlock(xmlCatalogMutex);
3227 * @pathss: a list of directories separated by a colon or a space.
3229 * Load the catalogs and makes their definitions effective for the default
3230 * external entity loader.
3231 * this function is not thread safe, catalog initialization should
3232 * preferably be done once at startup
3235 xmlLoadCatalogs(const char *pathss) {
3248 while (xmlIsBlank_ch(*cur)) cur++;
3251 while ((*cur != 0) && (*cur != PATH_SEPARATOR) && (!xmlIsBlank_ch(*cur)))
3253 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3255 iLen = strlen((const char*)path);
3256 for(i = 0; i < iLen; i++) {
3257 if(path[i] == '\\') {
3263 xmlLoadCatalog((const char *) path);
3267 while (*cur == PATH_SEPARATOR)
3273 * xmlCatalogCleanup:
3275 * Free up all the memory associated with catalogs
3278 xmlCatalogCleanup(void) {
3279 if (xmlCatalogInitialized == 0)
3282 xmlRMutexLock(xmlCatalogMutex);
3283 if (xmlDebugCatalogs)
3284 xmlGenericError(xmlGenericErrorContext,
3285 "Catalogs cleanup\n");
3286 if (xmlCatalogXMLFiles != NULL)
3287 xmlHashFree(xmlCatalogXMLFiles,
3288 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
3289 xmlCatalogXMLFiles = NULL;
3290 if (xmlDefaultCatalog != NULL)
3291 xmlFreeCatalog(xmlDefaultCatalog);
3292 xmlDefaultCatalog = NULL;
3293 xmlDebugCatalogs = 0;
3294 xmlCatalogInitialized = 0;
3295 xmlRMutexUnlock(xmlCatalogMutex);
3296 xmlFreeRMutex(xmlCatalogMutex);
3300 * xmlCatalogResolveSystem:
3301 * @sysID: the system ID string
3303 * Try to lookup the catalog resource for a system ID
3305 * Returns the resource if found or NULL otherwise, the value returned
3306 * must be freed by the caller.
3309 xmlCatalogResolveSystem(const xmlChar *sysID) {
3312 if (!xmlCatalogInitialized)
3313 xmlInitializeCatalog();
3315 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3320 * xmlCatalogResolvePublic:
3321 * @pubID: the public ID string
3323 * Try to lookup the catalog reference associated to a public ID
3325 * Returns the resource if found or NULL otherwise, the value returned
3326 * must be freed by the caller.
3329 xmlCatalogResolvePublic(const xmlChar *pubID) {
3332 if (!xmlCatalogInitialized)
3333 xmlInitializeCatalog();
3335 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3340 * xmlCatalogResolve:
3341 * @pubID: the public ID string
3342 * @sysID: the system ID string
3344 * Do a complete resolution lookup of an External Identifier
3346 * Returns the URI of the resource or NULL if not found, it must be freed
3350 xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
3353 if (!xmlCatalogInitialized)
3354 xmlInitializeCatalog();
3356 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3361 * xmlCatalogResolveURI:
3364 * Do a complete resolution lookup of an URI
3366 * Returns the URI of the resource or NULL if not found, it must be freed
3370 xmlCatalogResolveURI(const xmlChar *URI) {
3373 if (!xmlCatalogInitialized)
3374 xmlInitializeCatalog();
3376 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3380 #ifdef LIBXML_OUTPUT_ENABLED
3385 * Dump all the global catalog content to the given file.
3388 xmlCatalogDump(FILE *out) {
3392 if (!xmlCatalogInitialized)
3393 xmlInitializeCatalog();
3395 xmlACatalogDump(xmlDefaultCatalog, out);
3397 #endif /* LIBXML_OUTPUT_ENABLED */
3401 * @type: the type of record to add to the catalog
3402 * @orig: the system, public or prefix to match
3403 * @replace: the replacement value for the match
3405 * Add an entry in the catalog, it may overwrite existing but
3406 * different entries.
3407 * If called before any other catalog routine, allows to override the
3408 * default shared catalog put in place by xmlInitializeCatalog();
3410 * Returns 0 if successful, -1 otherwise
3413 xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3416 if (!xmlCatalogInitialized)
3417 xmlInitializeCatalogData();
3419 xmlRMutexLock(xmlCatalogMutex);
3421 * Specific case where one want to override the default catalog
3422 * put in place by xmlInitializeCatalog();
3424 if ((xmlDefaultCatalog == NULL) &&
3425 (xmlStrEqual(type, BAD_CAST "catalog"))) {
3426 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3427 xmlCatalogDefaultPrefer);
3428 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3429 orig, NULL, xmlCatalogDefaultPrefer, NULL);
3431 xmlRMutexUnlock(xmlCatalogMutex);
3435 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
3436 xmlRMutexUnlock(xmlCatalogMutex);
3442 * @value: the value to remove
3444 * Remove an entry from the catalog
3446 * Returns the number of entries removed if successful, -1 otherwise
3449 xmlCatalogRemove(const xmlChar *value) {
3452 if (!xmlCatalogInitialized)
3453 xmlInitializeCatalog();
3455 xmlRMutexLock(xmlCatalogMutex);
3456 res = xmlACatalogRemove(xmlDefaultCatalog, value);
3457 xmlRMutexUnlock(xmlCatalogMutex);
3462 * xmlCatalogConvert:
3464 * Convert all the SGML catalog entries as XML ones
3466 * Returns the number of entries converted if successful, -1 otherwise
3469 xmlCatalogConvert(void) {
3472 if (!xmlCatalogInitialized)
3473 xmlInitializeCatalog();
3475 xmlRMutexLock(xmlCatalogMutex);
3476 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
3477 xmlRMutexUnlock(xmlCatalogMutex);
3481 /************************************************************************
3483 * Public interface manipulating the common preferences *
3485 ************************************************************************/
3488 * xmlCatalogGetDefaults:
3490 * Used to get the user preference w.r.t. to what catalogs should
3493 * Returns the current xmlCatalogAllow value
3496 xmlCatalogGetDefaults(void) {
3497 return(xmlCatalogDefaultAllow);
3501 * xmlCatalogSetDefaults:
3502 * @allow: what catalogs should be accepted
3504 * Used to set the user preference w.r.t. to what catalogs should
3508 xmlCatalogSetDefaults(xmlCatalogAllow allow) {
3509 if (xmlDebugCatalogs) {
3511 case XML_CATA_ALLOW_NONE:
3512 xmlGenericError(xmlGenericErrorContext,
3513 "Disabling catalog usage\n");
3515 case XML_CATA_ALLOW_GLOBAL:
3516 xmlGenericError(xmlGenericErrorContext,
3517 "Allowing only global catalogs\n");
3519 case XML_CATA_ALLOW_DOCUMENT:
3520 xmlGenericError(xmlGenericErrorContext,
3521 "Allowing only catalogs from the document\n");
3523 case XML_CATA_ALLOW_ALL:
3524 xmlGenericError(xmlGenericErrorContext,
3525 "Allowing all catalogs\n");
3529 xmlCatalogDefaultAllow = allow;
3533 * xmlCatalogSetDefaultPrefer:
3534 * @prefer: the default preference for delegation
3536 * Allows to set the preference between public and system for deletion
3537 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3538 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3540 * Returns the previous value of the default preference for delegation
3543 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3544 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3546 if (prefer == XML_CATA_PREFER_NONE)
3549 if (xmlDebugCatalogs) {
3551 case XML_CATA_PREFER_PUBLIC:
3552 xmlGenericError(xmlGenericErrorContext,
3553 "Setting catalog preference to PUBLIC\n");
3555 case XML_CATA_PREFER_SYSTEM:
3556 xmlGenericError(xmlGenericErrorContext,
3557 "Setting catalog preference to SYSTEM\n");
3563 xmlCatalogDefaultPrefer = prefer;
3568 * xmlCatalogSetDebug:
3569 * @level: the debug level of catalogs required
3571 * Used to set the debug level for catalog operation, 0 disable
3572 * debugging, 1 enable it
3574 * Returns the previous value of the catalog debugging level
3577 xmlCatalogSetDebug(int level) {
3578 int ret = xmlDebugCatalogs;
3581 xmlDebugCatalogs = 0;
3583 xmlDebugCatalogs = level;
3587 /************************************************************************
3589 * Minimal interfaces used for per-document catalogs by the parser *
3591 ************************************************************************/
3594 * xmlCatalogFreeLocal:
3595 * @catalogs: a document's list of catalogs
3597 * Free up the memory associated to the catalog list
3600 xmlCatalogFreeLocal(void *catalogs) {
3601 xmlCatalogEntryPtr catal;
3603 if (!xmlCatalogInitialized)
3604 xmlInitializeCatalog();
3606 catal = (xmlCatalogEntryPtr) catalogs;
3608 xmlFreeCatalogEntryList(catal);
3613 * xmlCatalogAddLocal:
3614 * @catalogs: a document's list of catalogs
3615 * @URL: the URL to a new local catalog
3617 * Add the new entry to the catalog list
3619 * Returns the updated list
3622 xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3623 xmlCatalogEntryPtr catal, add;
3625 if (!xmlCatalogInitialized)
3626 xmlInitializeCatalog();
3631 if (xmlDebugCatalogs)
3632 xmlGenericError(xmlGenericErrorContext,
3633 "Adding document catalog %s\n", URL);
3635 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
3636 xmlCatalogDefaultPrefer, NULL);
3640 catal = (xmlCatalogEntryPtr) catalogs;
3642 return((void *) add);
3644 while (catal->next != NULL)
3645 catal = catal->next;
3651 * xmlCatalogLocalResolve:
3652 * @catalogs: a document's list of catalogs
3653 * @pubID: the public ID string
3654 * @sysID: the system ID string
3656 * Do a complete resolution lookup of an External Identifier using a
3657 * document's private catalog list
3659 * Returns the URI of the resource or NULL if not found, it must be freed
3663 xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3664 const xmlChar *sysID) {
3665 xmlCatalogEntryPtr catal;
3668 if (!xmlCatalogInitialized)
3669 xmlInitializeCatalog();
3671 if ((pubID == NULL) && (sysID == NULL))
3674 if (xmlDebugCatalogs) {
3675 if ((pubID != NULL) && (sysID != NULL)) {
3676 xmlGenericError(xmlGenericErrorContext,
3677 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3678 } else if (pubID != NULL) {
3679 xmlGenericError(xmlGenericErrorContext,
3680 "Local Resolve: pubID %s\n", pubID);
3682 xmlGenericError(xmlGenericErrorContext,
3683 "Local Resolve: sysID %s\n", sysID);
3687 catal = (xmlCatalogEntryPtr) catalogs;
3690 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3691 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3697 * xmlCatalogLocalResolveURI:
3698 * @catalogs: a document's list of catalogs
3701 * Do a complete resolution lookup of an URI using a
3702 * document's private catalog list
3704 * Returns the URI of the resource or NULL if not found, it must be freed
3708 xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3709 xmlCatalogEntryPtr catal;
3712 if (!xmlCatalogInitialized)
3713 xmlInitializeCatalog();
3718 if (xmlDebugCatalogs)
3719 xmlGenericError(xmlGenericErrorContext,
3720 "Resolve URI %s\n", URI);
3722 catal = (xmlCatalogEntryPtr) catalogs;
3725 ret = xmlCatalogListXMLResolveURI(catal, URI);
3726 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3731 /************************************************************************
3733 * Deprecated interfaces *
3735 ************************************************************************/
3737 * xmlCatalogGetSystem:
3738 * @sysID: the system ID string
3740 * Try to lookup the catalog reference associated to a system ID
3741 * DEPRECATED, use xmlCatalogResolveSystem()
3743 * Returns the resource if found or NULL otherwise.
3746 xmlCatalogGetSystem(const xmlChar *sysID) {
3748 static xmlChar result[1000];
3751 if (!xmlCatalogInitialized)
3752 xmlInitializeCatalog();
3755 xmlGenericError(xmlGenericErrorContext,
3756 "Use of deprecated xmlCatalogGetSystem() call\n");
3764 * Check first the XML catalogs
3766 if (xmlDefaultCatalog != NULL) {
3767 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3768 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3769 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3770 result[sizeof(result) - 1] = 0;
3775 if (xmlDefaultCatalog != NULL)
3776 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3781 * xmlCatalogGetPublic:
3782 * @pubID: the public ID string
3784 * Try to lookup the catalog reference associated to a public ID
3785 * DEPRECATED, use xmlCatalogResolvePublic()
3787 * Returns the resource if found or NULL otherwise.
3790 xmlCatalogGetPublic(const xmlChar *pubID) {
3792 static xmlChar result[1000];
3795 if (!xmlCatalogInitialized)
3796 xmlInitializeCatalog();
3799 xmlGenericError(xmlGenericErrorContext,
3800 "Use of deprecated xmlCatalogGetPublic() call\n");
3808 * Check first the XML catalogs
3810 if (xmlDefaultCatalog != NULL) {
3811 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3812 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3813 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3814 result[sizeof(result) - 1] = 0;
3819 if (xmlDefaultCatalog != NULL)
3820 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3824 #define bottom_catalog
3825 #include "elfgcchack.h"
3826 #endif /* LIBXML_CATALOG_ENABLED */