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_SEAPARATOR ';'
52 # define PATH_SEAPARATOR ':'
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
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");
1000 len
= read(fd
, content
, size
);
1003 len
= fread(content
, 1, size
, fd
);
1016 * xmlCatalogNormalizePublic:
1017 * @pubID: the public ID string
1019 * Normalizes the Public Identifier
1021 * Implements 6.2. Public Identifier Normalization
1022 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1024 * Returns the new string or NULL, the string must be deallocated
1028 xmlCatalogNormalizePublic(const xmlChar
*pubID
)
1040 for (p
= pubID
;*p
!= 0 && ok
;p
++) {
1041 if (!xmlIsBlank_ch(*p
))
1043 else if (*p
== 0x20 && !white
)
1048 if (ok
&& !white
) /* is normalized */
1051 ret
= xmlStrdup(pubID
);
1054 for (p
= pubID
;*p
!= 0;p
++) {
1055 if (xmlIsBlank_ch(*p
)) {
1070 /************************************************************************
1072 * The XML Catalog parser *
1074 ************************************************************************/
1076 static xmlCatalogEntryPtr
1077 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
);
1079 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1080 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
);
1082 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1083 const xmlChar
*sysID
);
1085 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
);
1089 * xmlGetXMLCatalogEntryType:
1092 * lookup the internal type associated to an XML catalog entry name
1094 * Returns the type associated with that name
1096 static xmlCatalogEntryType
1097 xmlGetXMLCatalogEntryType(const xmlChar
*name
) {
1098 xmlCatalogEntryType type
= XML_CATA_NONE
;
1099 if (xmlStrEqual(name
, (const xmlChar
*) "system"))
1100 type
= XML_CATA_SYSTEM
;
1101 else if (xmlStrEqual(name
, (const xmlChar
*) "public"))
1102 type
= XML_CATA_PUBLIC
;
1103 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteSystem"))
1104 type
= XML_CATA_REWRITE_SYSTEM
;
1105 else if (xmlStrEqual(name
, (const xmlChar
*) "delegatePublic"))
1106 type
= XML_CATA_DELEGATE_PUBLIC
;
1107 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateSystem"))
1108 type
= XML_CATA_DELEGATE_SYSTEM
;
1109 else if (xmlStrEqual(name
, (const xmlChar
*) "uri"))
1110 type
= XML_CATA_URI
;
1111 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteURI"))
1112 type
= XML_CATA_REWRITE_URI
;
1113 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateURI"))
1114 type
= XML_CATA_DELEGATE_URI
;
1115 else if (xmlStrEqual(name
, (const xmlChar
*) "nextCatalog"))
1116 type
= XML_CATA_NEXT_CATALOG
;
1117 else if (xmlStrEqual(name
, (const xmlChar
*) "catalog"))
1118 type
= XML_CATA_CATALOG
;
1123 * xmlParseXMLCatalogOneNode:
1124 * @cur: the XML node
1125 * @type: the type of Catalog entry
1126 * @name: the name of the node
1127 * @attrName: the attribute holding the value
1128 * @uriAttrName: the attribute holding the URI-Reference
1129 * @prefer: the PUBLIC vs. SYSTEM current preference value
1130 * @cgroup: the group which includes this node
1132 * Finishes the examination of an XML tree node of a catalog and build
1133 * a Catalog entry from it.
1135 * Returns the new Catalog entry node or NULL in case of error.
1137 static xmlCatalogEntryPtr
1138 xmlParseXMLCatalogOneNode(xmlNodePtr cur
, xmlCatalogEntryType type
,
1139 const xmlChar
*name
, const xmlChar
*attrName
,
1140 const xmlChar
*uriAttrName
, xmlCatalogPrefer prefer
,
1141 xmlCatalogEntryPtr cgroup
) {
1144 xmlChar
*nameValue
= NULL
;
1145 xmlChar
*base
= NULL
;
1146 xmlChar
*URL
= NULL
;
1147 xmlCatalogEntryPtr ret
= NULL
;
1149 if (attrName
!= NULL
) {
1150 nameValue
= xmlGetProp(cur
, attrName
);
1151 if (nameValue
== NULL
) {
1152 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1153 "%s entry lacks '%s'\n", name
, attrName
, NULL
);
1157 uriValue
= xmlGetProp(cur
, uriAttrName
);
1158 if (uriValue
== NULL
) {
1159 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1160 "%s entry lacks '%s'\n", name
, uriAttrName
, NULL
);
1164 if (nameValue
!= NULL
)
1166 if (uriValue
!= NULL
)
1171 base
= xmlNodeGetBase(cur
->doc
, cur
);
1172 URL
= xmlBuildURI(uriValue
, base
);
1174 if (xmlDebugCatalogs
> 1) {
1175 if (nameValue
!= NULL
)
1176 xmlGenericError(xmlGenericErrorContext
,
1177 "Found %s: '%s' '%s'\n", name
, nameValue
, URL
);
1179 xmlGenericError(xmlGenericErrorContext
,
1180 "Found %s: '%s'\n", name
, URL
);
1182 ret
= xmlNewCatalogEntry(type
, nameValue
, uriValue
, URL
, prefer
, cgroup
);
1184 xmlCatalogErr(ret
, cur
, XML_CATALOG_ENTRY_BROKEN
,
1185 "%s entry '%s' broken ?: %s\n", name
, uriAttrName
, uriValue
);
1187 if (nameValue
!= NULL
)
1189 if (uriValue
!= NULL
)
1199 * xmlParseXMLCatalogNode:
1200 * @cur: the XML node
1201 * @prefer: the PUBLIC vs. SYSTEM current preference value
1202 * @parent: the parent Catalog entry
1203 * @cgroup: the group which includes this node
1205 * Examines an XML tree node of a catalog and build
1206 * a Catalog entry from it adding it to its parent. The examination can
1210 xmlParseXMLCatalogNode(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1211 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
)
1213 xmlChar
*base
= NULL
;
1214 xmlCatalogEntryPtr entry
= NULL
;
1218 if (xmlStrEqual(cur
->name
, BAD_CAST
"group")) {
1220 xmlCatalogPrefer pref
= XML_CATA_PREFER_NONE
;
1222 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1224 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1225 prefer
= XML_CATA_PREFER_SYSTEM
;
1226 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1227 prefer
= XML_CATA_PREFER_PUBLIC
;
1229 xmlCatalogErr(parent
, cur
, XML_CATALOG_PREFER_VALUE
,
1230 "Invalid value for prefer: '%s'\n",
1236 prop
= xmlGetProp(cur
, BAD_CAST
"id");
1237 base
= xmlGetNsProp(cur
, BAD_CAST
"base", XML_XML_NAMESPACE
);
1238 entry
= xmlNewCatalogEntry(XML_CATA_GROUP
, prop
, base
, NULL
, pref
, cgroup
);
1240 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"public")) {
1241 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_PUBLIC
,
1242 BAD_CAST
"public", BAD_CAST
"publicId", BAD_CAST
"uri", prefer
, cgroup
);
1243 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"system")) {
1244 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_SYSTEM
,
1245 BAD_CAST
"system", BAD_CAST
"systemId", BAD_CAST
"uri", prefer
, cgroup
);
1246 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteSystem")) {
1247 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_SYSTEM
,
1248 BAD_CAST
"rewriteSystem", BAD_CAST
"systemIdStartString",
1249 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1250 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegatePublic")) {
1251 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_PUBLIC
,
1252 BAD_CAST
"delegatePublic", BAD_CAST
"publicIdStartString",
1253 BAD_CAST
"catalog", prefer
, cgroup
);
1254 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateSystem")) {
1255 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_SYSTEM
,
1256 BAD_CAST
"delegateSystem", BAD_CAST
"systemIdStartString",
1257 BAD_CAST
"catalog", prefer
, cgroup
);
1258 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"uri")) {
1259 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_URI
,
1260 BAD_CAST
"uri", BAD_CAST
"name",
1261 BAD_CAST
"uri", prefer
, cgroup
);
1262 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteURI")) {
1263 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_URI
,
1264 BAD_CAST
"rewriteURI", BAD_CAST
"uriStartString",
1265 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1266 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateURI")) {
1267 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_URI
,
1268 BAD_CAST
"delegateURI", BAD_CAST
"uriStartString",
1269 BAD_CAST
"catalog", prefer
, cgroup
);
1270 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"nextCatalog")) {
1271 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_NEXT_CATALOG
,
1272 BAD_CAST
"nextCatalog", NULL
,
1273 BAD_CAST
"catalog", prefer
, cgroup
);
1275 if (entry
!= NULL
) {
1276 if (parent
!= NULL
) {
1277 entry
->parent
= parent
;
1278 if (parent
->children
== NULL
)
1279 parent
->children
= entry
;
1281 xmlCatalogEntryPtr prev
;
1283 prev
= parent
->children
;
1284 while (prev
->next
!= NULL
)
1289 if (entry
->type
== XML_CATA_GROUP
) {
1291 * Recurse to propagate prefer to the subtree
1292 * (xml:base handling is automated)
1294 xmlParseXMLCatalogNodeList(cur
->children
, prefer
, parent
, entry
);
1302 * xmlParseXMLCatalogNodeList:
1303 * @cur: the XML node list of siblings
1304 * @prefer: the PUBLIC vs. SYSTEM current preference value
1305 * @parent: the parent Catalog entry
1306 * @cgroup: the group which includes this list
1308 * Examines a list of XML sibling nodes of a catalog and build
1309 * a list of Catalog entry from it adding it to the parent.
1310 * The examination will recurse to examine node subtrees.
1313 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1314 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
) {
1315 while (cur
!= NULL
) {
1316 if ((cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1317 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1318 xmlParseXMLCatalogNode(cur
, prefer
, parent
, cgroup
);
1322 /* TODO: sort the list according to REWRITE lengths and prefer value */
1326 * xmlParseXMLCatalogFile:
1327 * @prefer: the PUBLIC vs. SYSTEM current preference value
1328 * @filename: the filename for the catalog
1330 * Parses the catalog file to extract the XML tree and then analyze the
1331 * tree to build a list of Catalog entries corresponding to this catalog
1333 * Returns the resulting Catalog entries list
1335 static xmlCatalogEntryPtr
1336 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
) {
1340 xmlCatalogEntryPtr parent
= NULL
;
1342 if (filename
== NULL
)
1345 doc
= xmlParseCatalogFile((const char *) filename
);
1347 if (xmlDebugCatalogs
)
1348 xmlGenericError(xmlGenericErrorContext
,
1349 "Failed to parse catalog %s\n", filename
);
1353 if (xmlDebugCatalogs
)
1354 xmlGenericError(xmlGenericErrorContext
,
1355 "%d Parsing catalog %s\n", xmlGetThreadId(), filename
);
1357 cur
= xmlDocGetRootElement(doc
);
1358 if ((cur
!= NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"catalog")) &&
1359 (cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1360 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1362 parent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
1363 (const xmlChar
*)filename
, NULL
, prefer
, NULL
);
1364 if (parent
== NULL
) {
1369 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1371 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1372 prefer
= XML_CATA_PREFER_SYSTEM
;
1373 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1374 prefer
= XML_CATA_PREFER_PUBLIC
;
1376 xmlCatalogErr(NULL
, cur
, XML_CATALOG_PREFER_VALUE
,
1377 "Invalid value for prefer: '%s'\n",
1382 cur
= cur
->children
;
1383 xmlParseXMLCatalogNodeList(cur
, prefer
, parent
, NULL
);
1385 xmlCatalogErr(NULL
, (xmlNodePtr
) doc
, XML_CATALOG_NOT_CATALOG
,
1386 "File %s is not an XML Catalog\n",
1387 filename
, NULL
, NULL
);
1396 * xmlFetchXMLCatalogFile:
1397 * @catal: an existing but incomplete catalog entry
1399 * Fetch and parse the subcatalog referenced by an entry
1401 * Returns 0 in case of success, -1 otherwise
1404 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal
) {
1405 xmlCatalogEntryPtr doc
;
1409 if (catal
->URL
== NULL
)
1413 * lock the whole catalog for modification
1415 xmlRMutexLock(xmlCatalogMutex
);
1416 if (catal
->children
!= NULL
) {
1417 /* Okay someone else did it in the meantime */
1418 xmlRMutexUnlock(xmlCatalogMutex
);
1422 if (xmlCatalogXMLFiles
!= NULL
) {
1423 doc
= (xmlCatalogEntryPtr
)
1424 xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1426 if (xmlDebugCatalogs
)
1427 xmlGenericError(xmlGenericErrorContext
,
1428 "Found %s in file hash\n", catal
->URL
);
1430 if (catal
->type
== XML_CATA_CATALOG
)
1431 catal
->children
= doc
->children
;
1433 catal
->children
= doc
;
1435 xmlRMutexUnlock(xmlCatalogMutex
);
1438 if (xmlDebugCatalogs
)
1439 xmlGenericError(xmlGenericErrorContext
,
1440 "%s not found in file hash\n", catal
->URL
);
1444 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1445 * use the existing catalog, there is no recursion allowed at
1448 doc
= xmlParseXMLCatalogFile(catal
->prefer
, catal
->URL
);
1450 catal
->type
= XML_CATA_BROKEN_CATALOG
;
1451 xmlRMutexUnlock(xmlCatalogMutex
);
1455 if (catal
->type
== XML_CATA_CATALOG
)
1456 catal
->children
= doc
->children
;
1458 catal
->children
= doc
;
1462 if (xmlCatalogXMLFiles
== NULL
)
1463 xmlCatalogXMLFiles
= xmlHashCreate(10);
1464 if (xmlCatalogXMLFiles
!= NULL
) {
1465 if (xmlDebugCatalogs
)
1466 xmlGenericError(xmlGenericErrorContext
,
1467 "%s added to file hash\n", catal
->URL
);
1468 xmlHashAddEntry(xmlCatalogXMLFiles
, catal
->URL
, doc
);
1470 xmlRMutexUnlock(xmlCatalogMutex
);
1474 /************************************************************************
1476 * XML Catalog handling *
1478 ************************************************************************/
1482 * @catal: top of an XML catalog
1483 * @type: the type of record to add to the catalog
1484 * @orig: the system, public or prefix to match (or NULL)
1485 * @replace: the replacement value for the match
1487 * Add an entry in the XML catalog, it may overwrite existing but
1488 * different entries.
1490 * Returns 0 if successful, -1 otherwise
1493 xmlAddXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*type
,
1494 const xmlChar
*orig
, const xmlChar
*replace
) {
1495 xmlCatalogEntryPtr cur
;
1496 xmlCatalogEntryType typ
;
1499 if ((catal
== NULL
) ||
1500 ((catal
->type
!= XML_CATA_CATALOG
) &&
1501 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1503 if (catal
->children
== NULL
) {
1504 xmlFetchXMLCatalogFile(catal
);
1506 if (catal
->children
== NULL
)
1509 typ
= xmlGetXMLCatalogEntryType(type
);
1510 if (typ
== XML_CATA_NONE
) {
1511 if (xmlDebugCatalogs
)
1512 xmlGenericError(xmlGenericErrorContext
,
1513 "Failed to add unknown element %s to catalog\n", type
);
1517 cur
= catal
->children
;
1519 * Might be a simple "update in place"
1522 while (cur
!= NULL
) {
1523 if ((orig
!= NULL
) && (cur
->type
== typ
) &&
1524 (xmlStrEqual(orig
, cur
->name
))) {
1525 if (xmlDebugCatalogs
)
1526 xmlGenericError(xmlGenericErrorContext
,
1527 "Updating element %s to catalog\n", type
);
1528 if (cur
->value
!= NULL
)
1529 xmlFree(cur
->value
);
1530 if (cur
->URL
!= NULL
)
1532 cur
->value
= xmlStrdup(replace
);
1533 cur
->URL
= xmlStrdup(replace
);
1536 if (cur
->next
== NULL
)
1541 if (xmlDebugCatalogs
)
1542 xmlGenericError(xmlGenericErrorContext
,
1543 "Adding element %s to catalog\n", type
);
1545 catal
->children
= xmlNewCatalogEntry(typ
, orig
, replace
,
1546 NULL
, catal
->prefer
, NULL
);
1548 cur
->next
= xmlNewCatalogEntry(typ
, orig
, replace
,
1549 NULL
, catal
->prefer
, NULL
);
1551 catal
->type
= XML_CATA_CATALOG
;
1552 cur
= (xmlCatalogEntryPtr
)xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1554 cur
->children
= catal
->children
;
1562 * @catal: top of an XML catalog
1563 * @value: the value to remove from the catalog
1565 * Remove entries in the XML catalog where the value or the URI
1566 * is equal to @value
1568 * Returns the number of entries removed if successful, -1 otherwise
1571 xmlDelXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*value
) {
1572 xmlCatalogEntryPtr cur
;
1575 if ((catal
== NULL
) ||
1576 ((catal
->type
!= XML_CATA_CATALOG
) &&
1577 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1581 if (catal
->children
== NULL
) {
1582 xmlFetchXMLCatalogFile(catal
);
1588 cur
= catal
->children
;
1589 while (cur
!= NULL
) {
1590 if (((cur
->name
!= NULL
) && (xmlStrEqual(value
, cur
->name
))) ||
1591 (xmlStrEqual(value
, cur
->value
))) {
1592 if (xmlDebugCatalogs
) {
1593 if (cur
->name
!= NULL
)
1594 xmlGenericError(xmlGenericErrorContext
,
1595 "Removing element %s from catalog\n", cur
->name
);
1597 xmlGenericError(xmlGenericErrorContext
,
1598 "Removing element %s from catalog\n", cur
->value
);
1600 cur
->type
= XML_CATA_REMOVED
;
1608 * xmlCatalogXMLResolve:
1609 * @catal: a catalog list
1610 * @pubID: the public ID string
1611 * @sysID: the system ID string
1613 * Do a complete resolution lookup of an External Identifier for a
1614 * list of catalog entries.
1616 * Implements (or tries to) 7.1. External Identifier Resolution
1617 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1619 * Returns the URI of the resource or NULL if not found
1622 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1623 const xmlChar
*sysID
) {
1624 xmlChar
*ret
= NULL
;
1625 xmlCatalogEntryPtr cur
;
1626 int haveDelegate
= 0;
1630 * protection against loops
1632 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1633 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1634 "Detected recursion in catalog %s\n",
1635 catal
->name
, NULL
, NULL
);
1641 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1643 if (sysID
!= NULL
) {
1644 xmlCatalogEntryPtr rewrite
= NULL
;
1645 int lenrewrite
= 0, len
;
1648 while (cur
!= NULL
) {
1649 switch (cur
->type
) {
1650 case XML_CATA_SYSTEM
:
1651 if (xmlStrEqual(sysID
, cur
->name
)) {
1652 if (xmlDebugCatalogs
)
1653 xmlGenericError(xmlGenericErrorContext
,
1654 "Found system match %s, using %s\n",
1655 cur
->name
, cur
->URL
);
1657 return(xmlStrdup(cur
->URL
));
1660 case XML_CATA_REWRITE_SYSTEM
:
1661 len
= xmlStrlen(cur
->name
);
1662 if ((len
> lenrewrite
) &&
1663 (!xmlStrncmp(sysID
, cur
->name
, len
))) {
1668 case XML_CATA_DELEGATE_SYSTEM
:
1669 if (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))
1672 case XML_CATA_NEXT_CATALOG
:
1680 if (rewrite
!= NULL
) {
1681 if (xmlDebugCatalogs
)
1682 xmlGenericError(xmlGenericErrorContext
,
1683 "Using rewriting rule %s\n", rewrite
->name
);
1684 ret
= xmlStrdup(rewrite
->URL
);
1686 ret
= xmlStrcat(ret
, &sysID
[lenrewrite
]);
1691 const xmlChar
*delegates
[MAX_DELEGATE
];
1695 * Assume the entries have been sorted by decreasing substring
1696 * matches when the list was produced.
1699 while (cur
!= NULL
) {
1700 if ((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) &&
1701 (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1702 for (i
= 0;i
< nbList
;i
++)
1703 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1709 if (nbList
< MAX_DELEGATE
)
1710 delegates
[nbList
++] = cur
->URL
;
1712 if (cur
->children
== NULL
) {
1713 xmlFetchXMLCatalogFile(cur
);
1715 if (cur
->children
!= NULL
) {
1716 if (xmlDebugCatalogs
)
1717 xmlGenericError(xmlGenericErrorContext
,
1718 "Trying system delegate %s\n", cur
->URL
);
1719 ret
= xmlCatalogListXMLResolve(
1720 cur
->children
, NULL
, sysID
);
1730 * Apply the cut algorithm explained in 4/
1733 return(XML_CATAL_BREAK
);
1737 * Then tries 5/ 6/ if a public ID is provided
1739 if (pubID
!= NULL
) {
1742 while (cur
!= NULL
) {
1743 switch (cur
->type
) {
1744 case XML_CATA_PUBLIC
:
1745 if (xmlStrEqual(pubID
, cur
->name
)) {
1746 if (xmlDebugCatalogs
)
1747 xmlGenericError(xmlGenericErrorContext
,
1748 "Found public match %s\n", cur
->name
);
1750 return(xmlStrdup(cur
->URL
));
1753 case XML_CATA_DELEGATE_PUBLIC
:
1754 if (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)) &&
1755 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
))
1758 case XML_CATA_NEXT_CATALOG
:
1768 const xmlChar
*delegates
[MAX_DELEGATE
];
1772 * Assume the entries have been sorted by decreasing substring
1773 * matches when the list was produced.
1776 while (cur
!= NULL
) {
1777 if ((cur
->type
== XML_CATA_DELEGATE_PUBLIC
) &&
1778 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
) &&
1779 (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1781 for (i
= 0;i
< nbList
;i
++)
1782 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1788 if (nbList
< MAX_DELEGATE
)
1789 delegates
[nbList
++] = cur
->URL
;
1791 if (cur
->children
== NULL
) {
1792 xmlFetchXMLCatalogFile(cur
);
1794 if (cur
->children
!= NULL
) {
1795 if (xmlDebugCatalogs
)
1796 xmlGenericError(xmlGenericErrorContext
,
1797 "Trying public delegate %s\n", cur
->URL
);
1798 ret
= xmlCatalogListXMLResolve(
1799 cur
->children
, pubID
, NULL
);
1809 * Apply the cut algorithm explained in 4/
1812 return(XML_CATAL_BREAK
);
1817 while (cur
!= NULL
) {
1818 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1819 if (cur
->children
== NULL
) {
1820 xmlFetchXMLCatalogFile(cur
);
1822 if (cur
->children
!= NULL
) {
1823 ret
= xmlCatalogListXMLResolve(cur
->children
, pubID
, sysID
);
1827 } else if (catal
->depth
> MAX_CATAL_DEPTH
) {
1841 * xmlCatalogXMLResolveURI:
1842 * @catal: a catalog list
1844 * @sysID: the system ID string
1846 * Do a complete resolution lookup of an External Identifier for a
1847 * list of catalog entries.
1849 * Implements (or tries to) 7.2.2. URI Resolution
1850 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1852 * Returns the URI of the resource or NULL if not found
1855 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
1856 xmlChar
*ret
= NULL
;
1857 xmlCatalogEntryPtr cur
;
1858 int haveDelegate
= 0;
1860 xmlCatalogEntryPtr rewrite
= NULL
;
1861 int lenrewrite
= 0, len
;
1869 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1870 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1871 "Detected recursion in catalog %s\n",
1872 catal
->name
, NULL
, NULL
);
1877 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1881 while (cur
!= NULL
) {
1882 switch (cur
->type
) {
1884 if (xmlStrEqual(URI
, cur
->name
)) {
1885 if (xmlDebugCatalogs
)
1886 xmlGenericError(xmlGenericErrorContext
,
1887 "Found URI match %s\n", cur
->name
);
1888 return(xmlStrdup(cur
->URL
));
1891 case XML_CATA_REWRITE_URI
:
1892 len
= xmlStrlen(cur
->name
);
1893 if ((len
> lenrewrite
) &&
1894 (!xmlStrncmp(URI
, cur
->name
, len
))) {
1899 case XML_CATA_DELEGATE_URI
:
1900 if (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))
1903 case XML_CATA_NEXT_CATALOG
:
1911 if (rewrite
!= NULL
) {
1912 if (xmlDebugCatalogs
)
1913 xmlGenericError(xmlGenericErrorContext
,
1914 "Using rewriting rule %s\n", rewrite
->name
);
1915 ret
= xmlStrdup(rewrite
->URL
);
1917 ret
= xmlStrcat(ret
, &URI
[lenrewrite
]);
1921 const xmlChar
*delegates
[MAX_DELEGATE
];
1925 * Assume the entries have been sorted by decreasing substring
1926 * matches when the list was produced.
1929 while (cur
!= NULL
) {
1930 if (((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) ||
1931 (cur
->type
== XML_CATA_DELEGATE_URI
)) &&
1932 (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))) {
1933 for (i
= 0;i
< nbList
;i
++)
1934 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1940 if (nbList
< MAX_DELEGATE
)
1941 delegates
[nbList
++] = cur
->URL
;
1943 if (cur
->children
== NULL
) {
1944 xmlFetchXMLCatalogFile(cur
);
1946 if (cur
->children
!= NULL
) {
1947 if (xmlDebugCatalogs
)
1948 xmlGenericError(xmlGenericErrorContext
,
1949 "Trying URI delegate %s\n", cur
->URL
);
1950 ret
= xmlCatalogListXMLResolveURI(
1951 cur
->children
, URI
);
1959 * Apply the cut algorithm explained in 4/
1961 return(XML_CATAL_BREAK
);
1965 while (cur
!= NULL
) {
1966 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1967 if (cur
->children
== NULL
) {
1968 xmlFetchXMLCatalogFile(cur
);
1970 if (cur
->children
!= NULL
) {
1971 ret
= xmlCatalogListXMLResolveURI(cur
->children
, URI
);
1984 * xmlCatalogListXMLResolve:
1985 * @catal: a catalog list
1986 * @pubID: the public ID string
1987 * @sysID: the system ID string
1989 * Do a complete resolution lookup of an External Identifier for a
1992 * Implements (or tries to) 7.1. External Identifier Resolution
1993 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1995 * Returns the URI of the resource or NULL if not found
1998 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1999 const xmlChar
*sysID
) {
2000 xmlChar
*ret
= NULL
;
2001 xmlChar
*urnID
= NULL
;
2006 if ((pubID
== NULL
) && (sysID
== NULL
))
2009 normid
= xmlCatalogNormalizePublic(pubID
);
2011 pubID
= (*normid
!= 0 ? normid
: NULL
);
2013 if (!xmlStrncmp(pubID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2014 urnID
= xmlCatalogUnWrapURN(pubID
);
2015 if (xmlDebugCatalogs
) {
2017 xmlGenericError(xmlGenericErrorContext
,
2018 "Public URN ID %s expanded to NULL\n", pubID
);
2020 xmlGenericError(xmlGenericErrorContext
,
2021 "Public URN ID expanded to %s\n", urnID
);
2023 ret
= xmlCatalogListXMLResolve(catal
, urnID
, sysID
);
2030 if (!xmlStrncmp(sysID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2031 urnID
= xmlCatalogUnWrapURN(sysID
);
2032 if (xmlDebugCatalogs
) {
2034 xmlGenericError(xmlGenericErrorContext
,
2035 "System URN ID %s expanded to NULL\n", sysID
);
2037 xmlGenericError(xmlGenericErrorContext
,
2038 "System URN ID expanded to %s\n", urnID
);
2041 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2042 else if (xmlStrEqual(pubID
, urnID
))
2043 ret
= xmlCatalogListXMLResolve(catal
, pubID
, NULL
);
2045 ret
= xmlCatalogListXMLResolve(catal
, pubID
, urnID
);
2053 while (catal
!= NULL
) {
2054 if (catal
->type
== XML_CATA_CATALOG
) {
2055 if (catal
->children
== NULL
) {
2056 xmlFetchXMLCatalogFile(catal
);
2058 if (catal
->children
!= NULL
) {
2059 ret
= xmlCatalogXMLResolve(catal
->children
, pubID
, sysID
);
2062 } else if ((catal
->children
!= NULL
) &&
2063 (catal
->children
->depth
> MAX_CATAL_DEPTH
)) {
2069 catal
= catal
->next
;
2077 * xmlCatalogListXMLResolveURI:
2078 * @catal: a catalog list
2081 * Do a complete resolution lookup of an URI for a list of catalogs
2083 * Implements (or tries to) 7.2. URI Resolution
2084 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2086 * Returns the URI of the resource or NULL if not found
2089 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
2090 xmlChar
*ret
= NULL
;
2091 xmlChar
*urnID
= NULL
;
2098 if (!xmlStrncmp(URI
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2099 urnID
= xmlCatalogUnWrapURN(URI
);
2100 if (xmlDebugCatalogs
) {
2102 xmlGenericError(xmlGenericErrorContext
,
2103 "URN ID %s expanded to NULL\n", URI
);
2105 xmlGenericError(xmlGenericErrorContext
,
2106 "URN ID expanded to %s\n", urnID
);
2108 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2113 while (catal
!= NULL
) {
2114 if (catal
->type
== XML_CATA_CATALOG
) {
2115 if (catal
->children
== NULL
) {
2116 xmlFetchXMLCatalogFile(catal
);
2118 if (catal
->children
!= NULL
) {
2119 ret
= xmlCatalogXMLResolveURI(catal
->children
, URI
);
2124 catal
= catal
->next
;
2129 /************************************************************************
2131 * The SGML Catalog parser *
2133 ************************************************************************/
2138 #define SKIP(x) cur += x;
2140 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2143 * xmlParseSGMLCatalogComment:
2144 * @cur: the current character
2146 * Skip a comment in an SGML catalog
2148 * Returns new current character
2150 static const xmlChar
*
2151 xmlParseSGMLCatalogComment(const xmlChar
*cur
) {
2152 if ((cur
[0] != '-') || (cur
[1] != '-'))
2155 while ((cur
[0] != 0) && ((cur
[0] != '-') || ((cur
[1] != '-'))))
2164 * xmlParseSGMLCatalogPubid:
2165 * @cur: the current character
2166 * @id: the return location
2168 * Parse an SGML catalog ID
2170 * Returns new current character and store the value in @id
2172 static const xmlChar
*
2173 xmlParseSGMLCatalogPubid(const xmlChar
*cur
, xmlChar
**id
) {
2174 xmlChar
*buf
= NULL
, *tmp
;
2185 } else if (RAW
== '\'') {
2191 buf
= (xmlChar
*) xmlMallocAtomic(size
* sizeof(xmlChar
));
2193 xmlCatalogErrMemory("allocating public ID");
2196 while (IS_PUBIDCHAR_CH(*cur
) || (*cur
== '?')) {
2197 if ((*cur
== stop
) && (stop
!= ' '))
2199 if ((stop
== ' ') && (IS_BLANK_CH(*cur
)))
2201 if (len
+ 1 >= size
) {
2203 tmp
= (xmlChar
*) xmlRealloc(buf
, size
* sizeof(xmlChar
));
2205 xmlCatalogErrMemory("allocating public ID");
2217 if (!IS_BLANK_CH(*cur
)) {
2233 * xmlParseSGMLCatalogName:
2234 * @cur: the current character
2235 * @name: the return location
2237 * Parse an SGML catalog name
2239 * Returns new current character and store the value in @name
2241 static const xmlChar
*
2242 xmlParseSGMLCatalogName(const xmlChar
*cur
, xmlChar
**name
) {
2243 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
2250 * Handler for more complex cases
2253 if ((!IS_LETTER(c
) && (c
!= '_') && (c
!= ':'))) {
2257 while (((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
2258 (c
== '.') || (c
== '-') ||
2259 (c
== '_') || (c
== ':'))) {
2263 if (len
>= XML_MAX_NAMELEN
)
2266 *name
= xmlStrndup(buf
, len
);
2271 * xmlGetSGMLCatalogEntryType:
2272 * @name: the entry name
2274 * Get the Catalog entry type for a given SGML Catalog name
2276 * Returns Catalog entry type
2278 static xmlCatalogEntryType
2279 xmlGetSGMLCatalogEntryType(const xmlChar
*name
) {
2280 xmlCatalogEntryType type
= XML_CATA_NONE
;
2281 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2282 type
= SGML_CATA_SYSTEM
;
2283 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2284 type
= SGML_CATA_PUBLIC
;
2285 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2286 type
= SGML_CATA_DELEGATE
;
2287 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2288 type
= SGML_CATA_ENTITY
;
2289 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2290 type
= SGML_CATA_DOCTYPE
;
2291 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2292 type
= SGML_CATA_LINKTYPE
;
2293 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2294 type
= SGML_CATA_NOTATION
;
2295 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2296 type
= SGML_CATA_SGMLDECL
;
2297 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2298 type
= SGML_CATA_DOCUMENT
;
2299 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2300 type
= SGML_CATA_CATALOG
;
2301 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2302 type
= SGML_CATA_BASE
;
2307 * xmlParseSGMLCatalog:
2308 * @catal: the SGML Catalog
2309 * @value: the content of the SGML Catalog serialization
2310 * @file: the filepath for the catalog
2311 * @super: should this be handled as a Super Catalog in which case
2312 * parsing is not recursive
2314 * Parse an SGML catalog content and fill up the @catal hash table with
2315 * the new entries found.
2317 * Returns 0 in case of success, -1 in case of error.
2320 xmlParseSGMLCatalog(xmlCatalogPtr catal
, const xmlChar
*value
,
2321 const char *file
, int super
) {
2322 const xmlChar
*cur
= value
;
2323 xmlChar
*base
= NULL
;
2326 if ((cur
== NULL
) || (file
== NULL
))
2328 base
= xmlStrdup((const xmlChar
*) file
);
2330 while ((cur
!= NULL
) && (cur
[0] != 0)) {
2334 if ((cur
[0] == '-') && (cur
[1] == '-')) {
2335 cur
= xmlParseSGMLCatalogComment(cur
);
2341 xmlChar
*sysid
= NULL
;
2342 xmlChar
*name
= NULL
;
2343 xmlCatalogEntryType type
= XML_CATA_NONE
;
2345 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2350 if (!IS_BLANK_CH(*cur
)) {
2355 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2356 type
= SGML_CATA_SYSTEM
;
2357 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2358 type
= SGML_CATA_PUBLIC
;
2359 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2360 type
= SGML_CATA_DELEGATE
;
2361 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2362 type
= SGML_CATA_ENTITY
;
2363 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2364 type
= SGML_CATA_DOCTYPE
;
2365 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2366 type
= SGML_CATA_LINKTYPE
;
2367 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2368 type
= SGML_CATA_NOTATION
;
2369 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2370 type
= SGML_CATA_SGMLDECL
;
2371 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2372 type
= SGML_CATA_DOCUMENT
;
2373 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2374 type
= SGML_CATA_CATALOG
;
2375 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2376 type
= SGML_CATA_BASE
;
2377 else if (xmlStrEqual(name
, (const xmlChar
*) "OVERRIDE")) {
2379 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2391 case SGML_CATA_ENTITY
:
2393 type
= SGML_CATA_PENTITY
;
2394 case SGML_CATA_PENTITY
:
2395 case SGML_CATA_DOCTYPE
:
2396 case SGML_CATA_LINKTYPE
:
2397 case SGML_CATA_NOTATION
:
2398 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2403 if (!IS_BLANK_CH(*cur
)) {
2408 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2414 case SGML_CATA_PUBLIC
:
2415 case SGML_CATA_SYSTEM
:
2416 case SGML_CATA_DELEGATE
:
2417 cur
= xmlParseSGMLCatalogPubid(cur
, &name
);
2422 if (type
!= SGML_CATA_SYSTEM
) {
2425 normid
= xmlCatalogNormalizePublic(name
);
2426 if (normid
!= NULL
) {
2437 if (!IS_BLANK_CH(*cur
)) {
2442 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2448 case SGML_CATA_BASE
:
2449 case SGML_CATA_CATALOG
:
2450 case SGML_CATA_DOCUMENT
:
2451 case SGML_CATA_SGMLDECL
:
2452 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2467 } else if (type
== SGML_CATA_BASE
) {
2470 base
= xmlStrdup(sysid
);
2471 } else if ((type
== SGML_CATA_PUBLIC
) ||
2472 (type
== SGML_CATA_SYSTEM
)) {
2475 filename
= xmlBuildURI(sysid
, base
);
2476 if (filename
!= NULL
) {
2477 xmlCatalogEntryPtr entry
;
2479 entry
= xmlNewCatalogEntry(type
, name
, filename
,
2480 NULL
, XML_CATA_PREFER_NONE
, NULL
);
2481 res
= xmlHashAddEntry(catal
->sgml
, name
, entry
);
2483 xmlFreeCatalogEntry(entry
);
2488 } else if (type
== SGML_CATA_CATALOG
) {
2490 xmlCatalogEntryPtr entry
;
2492 entry
= xmlNewCatalogEntry(type
, sysid
, NULL
, NULL
,
2493 XML_CATA_PREFER_NONE
, NULL
);
2494 res
= xmlHashAddEntry(catal
->sgml
, sysid
, entry
);
2496 xmlFreeCatalogEntry(entry
);
2501 filename
= xmlBuildURI(sysid
, base
);
2502 if (filename
!= NULL
) {
2503 xmlExpandCatalog(catal
, (const char *)filename
);
2509 * drop anything else we won't handle it
2524 /************************************************************************
2526 * SGML Catalog handling *
2528 ************************************************************************/
2531 * xmlCatalogGetSGMLPublic:
2532 * @catal: an SGML catalog hash
2533 * @pubID: the public ID string
2535 * Try to lookup the catalog local reference associated to a public ID
2537 * Returns the local resource if found or NULL otherwise.
2539 static const xmlChar
*
2540 xmlCatalogGetSGMLPublic(xmlHashTablePtr catal
, const xmlChar
*pubID
) {
2541 xmlCatalogEntryPtr entry
;
2547 normid
= xmlCatalogNormalizePublic(pubID
);
2549 pubID
= (*normid
!= 0 ? normid
: NULL
);
2551 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, pubID
);
2552 if (entry
== NULL
) {
2557 if (entry
->type
== SGML_CATA_PUBLIC
) {
2568 * xmlCatalogGetSGMLSystem:
2569 * @catal: an SGML catalog hash
2570 * @sysID: the system ID string
2572 * Try to lookup the catalog local reference for a system ID
2574 * Returns the local resource if found or NULL otherwise.
2576 static const xmlChar
*
2577 xmlCatalogGetSGMLSystem(xmlHashTablePtr catal
, const xmlChar
*sysID
) {
2578 xmlCatalogEntryPtr entry
;
2583 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, sysID
);
2586 if (entry
->type
== SGML_CATA_SYSTEM
)
2592 * xmlCatalogSGMLResolve:
2593 * @catal: the SGML catalog
2594 * @pubID: the public ID string
2595 * @sysID: the system ID string
2597 * Do a complete resolution lookup of an External Identifier
2599 * Returns the URI of the resource or NULL if not found
2601 static const xmlChar
*
2602 xmlCatalogSGMLResolve(xmlCatalogPtr catal
, const xmlChar
*pubID
,
2603 const xmlChar
*sysID
) {
2604 const xmlChar
*ret
= NULL
;
2606 if (catal
->sgml
== NULL
)
2610 ret
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2614 ret
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2620 /************************************************************************
2622 * Specific Public interfaces *
2624 ************************************************************************/
2627 * xmlLoadSGMLSuperCatalog:
2628 * @filename: a file path
2630 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2631 * references. This is only needed for manipulating SGML Super Catalogs
2632 * like adding and removing CATALOG or DELEGATE entries.
2634 * Returns the catalog parsed or NULL in case of error
2637 xmlLoadSGMLSuperCatalog(const char *filename
)
2640 xmlCatalogPtr catal
;
2643 content
= xmlLoadFileContent(filename
);
2644 if (content
== NULL
)
2647 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2648 if (catal
== NULL
) {
2653 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 1);
2656 xmlFreeCatalog(catal
);
2664 * @filename: a file path
2666 * Load the catalog and build the associated data structures.
2667 * This can be either an XML Catalog or an SGML Catalog
2668 * It will recurse in SGML CATALOG entries. On the other hand XML
2669 * Catalogs are not handled recursively.
2671 * Returns the catalog parsed or NULL in case of error
2674 xmlLoadACatalog(const char *filename
)
2678 xmlCatalogPtr catal
;
2681 content
= xmlLoadFileContent(filename
);
2682 if (content
== NULL
)
2688 while ((*first
!= 0) && (*first
!= '-') && (*first
!= '<') &&
2689 (!(((*first
>= 'A') && (*first
<= 'Z')) ||
2690 ((*first
>= 'a') && (*first
<= 'z')))))
2693 if (*first
!= '<') {
2694 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2695 if (catal
== NULL
) {
2699 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2701 xmlFreeCatalog(catal
);
2706 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2707 if (catal
== NULL
) {
2711 catal
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2712 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2721 * @filename: a file path
2723 * Load the catalog and expand the existing catal structure.
2724 * This can be either an XML Catalog or an SGML Catalog
2726 * Returns 0 in case of success, -1 in case of error
2729 xmlExpandCatalog(xmlCatalogPtr catal
, const char *filename
)
2733 if ((catal
== NULL
) || (filename
== NULL
))
2737 if (catal
->type
== XML_SGML_CATALOG_TYPE
) {
2740 content
= xmlLoadFileContent(filename
);
2741 if (content
== NULL
)
2744 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2751 xmlCatalogEntryPtr tmp
, cur
;
2752 tmp
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2753 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2759 while (cur
->next
!= NULL
) cur
= cur
->next
;
2767 * xmlACatalogResolveSystem:
2769 * @sysID: the system ID string
2771 * Try to lookup the catalog resource for a system ID
2773 * Returns the resource if found or NULL otherwise, the value returned
2774 * must be freed by the caller.
2777 xmlACatalogResolveSystem(xmlCatalogPtr catal
, const xmlChar
*sysID
) {
2778 xmlChar
*ret
= NULL
;
2780 if ((sysID
== NULL
) || (catal
== NULL
))
2783 if (xmlDebugCatalogs
)
2784 xmlGenericError(xmlGenericErrorContext
,
2785 "Resolve sysID %s\n", sysID
);
2787 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2788 ret
= xmlCatalogListXMLResolve(catal
->xml
, NULL
, sysID
);
2789 if (ret
== XML_CATAL_BREAK
)
2792 const xmlChar
*sgml
;
2794 sgml
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2796 ret
= xmlStrdup(sgml
);
2802 * xmlACatalogResolvePublic:
2804 * @pubID: the public ID string
2806 * Try to lookup the catalog local reference associated to a public ID in that catalog
2808 * Returns the local resource if found or NULL otherwise, the value returned
2809 * must be freed by the caller.
2812 xmlACatalogResolvePublic(xmlCatalogPtr catal
, const xmlChar
*pubID
) {
2813 xmlChar
*ret
= NULL
;
2815 if ((pubID
== NULL
) || (catal
== NULL
))
2818 if (xmlDebugCatalogs
)
2819 xmlGenericError(xmlGenericErrorContext
,
2820 "Resolve pubID %s\n", pubID
);
2822 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2823 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, NULL
);
2824 if (ret
== XML_CATAL_BREAK
)
2827 const xmlChar
*sgml
;
2829 sgml
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2831 ret
= xmlStrdup(sgml
);
2837 * xmlACatalogResolve:
2839 * @pubID: the public ID string
2840 * @sysID: the system ID string
2842 * Do a complete resolution lookup of an External Identifier
2844 * Returns the URI of the resource or NULL if not found, it must be freed
2848 xmlACatalogResolve(xmlCatalogPtr catal
, const xmlChar
* pubID
,
2849 const xmlChar
* sysID
)
2851 xmlChar
*ret
= NULL
;
2853 if (((pubID
== NULL
) && (sysID
== NULL
)) || (catal
== NULL
))
2856 if (xmlDebugCatalogs
) {
2857 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
2858 xmlGenericError(xmlGenericErrorContext
,
2859 "Resolve: pubID %s sysID %s\n", pubID
, sysID
);
2860 } else if (pubID
!= NULL
) {
2861 xmlGenericError(xmlGenericErrorContext
,
2862 "Resolve: pubID %s\n", pubID
);
2864 xmlGenericError(xmlGenericErrorContext
,
2865 "Resolve: sysID %s\n", sysID
);
2869 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2870 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, sysID
);
2871 if (ret
== XML_CATAL_BREAK
)
2874 const xmlChar
*sgml
;
2876 sgml
= xmlCatalogSGMLResolve(catal
, pubID
, sysID
);
2878 ret
= xmlStrdup(sgml
);
2884 * xmlACatalogResolveURI:
2888 * Do a complete resolution lookup of an URI
2890 * Returns the URI of the resource or NULL if not found, it must be freed
2894 xmlACatalogResolveURI(xmlCatalogPtr catal
, const xmlChar
*URI
) {
2895 xmlChar
*ret
= NULL
;
2897 if ((URI
== NULL
) || (catal
== NULL
))
2900 if (xmlDebugCatalogs
)
2901 xmlGenericError(xmlGenericErrorContext
,
2902 "Resolve URI %s\n", URI
);
2904 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2905 ret
= xmlCatalogListXMLResolveURI(catal
->xml
, URI
);
2906 if (ret
== XML_CATAL_BREAK
)
2909 const xmlChar
*sgml
;
2911 sgml
= xmlCatalogSGMLResolve(catal
, NULL
, URI
);
2913 ret
= xmlStrdup(sgml
);
2918 #ifdef LIBXML_OUTPUT_ENABLED
2924 * Dump the given catalog to the given file.
2927 xmlACatalogDump(xmlCatalogPtr catal
, FILE *out
) {
2928 if ((out
== NULL
) || (catal
== NULL
))
2931 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2932 xmlDumpXMLCatalog(out
, catal
->xml
);
2934 xmlHashScan(catal
->sgml
,
2935 (xmlHashScanner
) xmlCatalogDumpEntry
, out
);
2938 #endif /* LIBXML_OUTPUT_ENABLED */
2943 * @type: the type of record to add to the catalog
2944 * @orig: the system, public or prefix to match
2945 * @replace: the replacement value for the match
2947 * Add an entry in the catalog, it may overwrite existing but
2948 * different entries.
2950 * Returns 0 if successful, -1 otherwise
2953 xmlACatalogAdd(xmlCatalogPtr catal
, const xmlChar
* type
,
2954 const xmlChar
* orig
, const xmlChar
* replace
)
2961 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2962 res
= xmlAddXMLCatalog(catal
->xml
, type
, orig
, replace
);
2964 xmlCatalogEntryType cattype
;
2966 cattype
= xmlGetSGMLCatalogEntryType(type
);
2967 if (cattype
!= XML_CATA_NONE
) {
2968 xmlCatalogEntryPtr entry
;
2970 entry
= xmlNewCatalogEntry(cattype
, orig
, replace
, NULL
,
2971 XML_CATA_PREFER_NONE
, NULL
);
2972 if (catal
->sgml
== NULL
)
2973 catal
->sgml
= xmlHashCreate(10);
2974 res
= xmlHashAddEntry(catal
->sgml
, orig
, entry
);
2981 * xmlACatalogRemove:
2983 * @value: the value to remove
2985 * Remove an entry from the catalog
2987 * Returns the number of entries removed if successful, -1 otherwise
2990 xmlACatalogRemove(xmlCatalogPtr catal
, const xmlChar
*value
) {
2993 if ((catal
== NULL
) || (value
== NULL
))
2996 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2997 res
= xmlDelXMLCatalog(catal
->xml
, value
);
2999 res
= xmlHashRemoveEntry(catal
->sgml
, value
,
3000 (xmlHashDeallocator
) xmlFreeCatalogEntry
);
3009 * @sgml: should this create an SGML catalog
3011 * create a new Catalog.
3013 * Returns the xmlCatalogPtr or NULL in case of error
3016 xmlNewCatalog(int sgml
) {
3017 xmlCatalogPtr catal
= NULL
;
3020 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
,
3021 xmlCatalogDefaultPrefer
);
3022 if ((catal
!= NULL
) && (catal
->sgml
== NULL
))
3023 catal
->sgml
= xmlHashCreate(10);
3025 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3026 xmlCatalogDefaultPrefer
);
3031 * xmlCatalogIsEmpty:
3032 * @catal: should this create an SGML catalog
3034 * Check is a catalog is empty
3036 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3039 xmlCatalogIsEmpty(xmlCatalogPtr catal
) {
3043 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
3044 if (catal
->xml
== NULL
)
3046 if ((catal
->xml
->type
!= XML_CATA_CATALOG
) &&
3047 (catal
->xml
->type
!= XML_CATA_BROKEN_CATALOG
))
3049 if (catal
->xml
->children
== NULL
)
3055 if (catal
->sgml
== NULL
)
3057 res
= xmlHashSize(catal
->sgml
);
3066 /************************************************************************
3068 * Public interfaces manipulating the global shared default catalog *
3070 ************************************************************************/
3073 * xmlInitializeCatalogData:
3075 * Do the catalog initialization only of global data, doesn't try to load
3076 * any catalog actually.
3077 * this function is not thread safe, catalog initialization should
3078 * preferably be done once at startup
3081 xmlInitializeCatalogData(void) {
3082 if (xmlCatalogInitialized
!= 0)
3085 if (getenv("XML_DEBUG_CATALOG"))
3086 xmlDebugCatalogs
= 1;
3087 xmlCatalogMutex
= xmlNewRMutex();
3089 xmlCatalogInitialized
= 1;
3092 * xmlInitializeCatalog:
3094 * Do the catalog initialization.
3095 * this function is not thread safe, catalog initialization should
3096 * preferably be done once at startup
3099 xmlInitializeCatalog(void) {
3100 if (xmlCatalogInitialized
!= 0)
3103 xmlInitializeCatalogData();
3104 xmlRMutexLock(xmlCatalogMutex
);
3106 if (getenv("XML_DEBUG_CATALOG"))
3107 xmlDebugCatalogs
= 1;
3109 if (xmlDefaultCatalog
== NULL
) {
3110 const char *catalogs
;
3112 const char *cur
, *paths
;
3113 xmlCatalogPtr catal
;
3114 xmlCatalogEntryPtr
*nextent
;
3116 catalogs
= (const char *) getenv("XML_CATALOG_FILES");
3117 if (catalogs
== NULL
)
3118 #if defined(_WIN32) && defined(_MSC_VER)
3121 hmodule
= GetModuleHandleA("libxml2.dll");
3122 if (hmodule
== NULL
)
3123 hmodule
= GetModuleHandleA(NULL
);
3124 if (hmodule
!= NULL
) {
3126 unsigned long len
= GetModuleFileNameA(hmodule
, buf
, 255);
3128 char* p
= &(buf
[len
]);
3129 while (*p
!= '\\' && p
> buf
)
3133 strncpy(p
, "\\..\\etc\\catalog", 255 - (p
- buf
));
3134 uri
= xmlCanonicPath((const xmlChar
*)buf
);
3136 strncpy(XML_XML_DEFAULT_CATALOG
, uri
, 255);
3142 catalogs
= XML_XML_DEFAULT_CATALOG
;
3145 catalogs
= XML_XML_DEFAULT_CATALOG
;
3148 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3149 xmlCatalogDefaultPrefer
);
3150 if (catal
!= NULL
) {
3151 /* the XML_CATALOG_FILES envvar is allowed to contain a
3152 space-separated list of entries. */
3154 nextent
= &catal
->xml
;
3155 while (*cur
!= '\0') {
3156 while (xmlIsBlank_ch(*cur
))
3160 while ((*cur
!= 0) && (!xmlIsBlank_ch(*cur
)))
3162 path
= (char *) xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3164 *nextent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3165 NULL
, BAD_CAST path
, xmlCatalogDefaultPrefer
, NULL
);
3166 if (*nextent
!= NULL
)
3167 nextent
= &((*nextent
)->next
);
3172 xmlDefaultCatalog
= catal
;
3176 xmlRMutexUnlock(xmlCatalogMutex
);
3182 * @filename: a file path
3184 * Load the catalog and makes its definitions effective for the default
3185 * external entity loader. It will recurse in SGML CATALOG entries.
3186 * this function is not thread safe, catalog initialization should
3187 * preferably be done once at startup
3189 * Returns 0 in case of success -1 in case of error
3192 xmlLoadCatalog(const char *filename
)
3195 xmlCatalogPtr catal
;
3197 if (!xmlCatalogInitialized
)
3198 xmlInitializeCatalogData();
3200 xmlRMutexLock(xmlCatalogMutex
);
3202 if (xmlDefaultCatalog
== NULL
) {
3203 catal
= xmlLoadACatalog(filename
);
3204 if (catal
== NULL
) {
3205 xmlRMutexUnlock(xmlCatalogMutex
);
3209 xmlDefaultCatalog
= catal
;
3210 xmlRMutexUnlock(xmlCatalogMutex
);
3214 ret
= xmlExpandCatalog(xmlDefaultCatalog
, filename
);
3215 xmlRMutexUnlock(xmlCatalogMutex
);
3221 * @pathss: a list of directories separated by a colon or a space.
3223 * Load the catalogs and makes their definitions effective for the default
3224 * external entity loader.
3225 * this function is not thread safe, catalog initialization should
3226 * preferably be done once at startup
3229 xmlLoadCatalogs(const char *pathss
) {
3242 while (xmlIsBlank_ch(*cur
)) cur
++;
3245 while ((*cur
!= 0) && (*cur
!= PATH_SEAPARATOR
) && (!xmlIsBlank_ch(*cur
)))
3247 path
= xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3249 iLen
= strlen((const char*)path
);
3250 for(i
= 0; i
< iLen
; i
++) {
3251 if(path
[i
] == '\\') {
3257 xmlLoadCatalog((const char *) path
);
3261 while (*cur
== PATH_SEAPARATOR
)
3267 * xmlCatalogCleanup:
3269 * Free up all the memory associated with catalogs
3272 xmlCatalogCleanup(void) {
3273 if (xmlCatalogInitialized
== 0)
3276 xmlRMutexLock(xmlCatalogMutex
);
3277 if (xmlDebugCatalogs
)
3278 xmlGenericError(xmlGenericErrorContext
,
3279 "Catalogs cleanup\n");
3280 if (xmlCatalogXMLFiles
!= NULL
)
3281 xmlHashFree(xmlCatalogXMLFiles
,
3282 (xmlHashDeallocator
)xmlFreeCatalogHashEntryList
);
3283 xmlCatalogXMLFiles
= NULL
;
3284 if (xmlDefaultCatalog
!= NULL
)
3285 xmlFreeCatalog(xmlDefaultCatalog
);
3286 xmlDefaultCatalog
= NULL
;
3287 xmlDebugCatalogs
= 0;
3288 xmlCatalogInitialized
= 0;
3289 xmlRMutexUnlock(xmlCatalogMutex
);
3290 xmlFreeRMutex(xmlCatalogMutex
);
3294 * xmlCatalogResolveSystem:
3295 * @sysID: the system ID string
3297 * Try to lookup the catalog resource for a system ID
3299 * Returns the resource if found or NULL otherwise, the value returned
3300 * must be freed by the caller.
3303 xmlCatalogResolveSystem(const xmlChar
*sysID
) {
3306 if (!xmlCatalogInitialized
)
3307 xmlInitializeCatalog();
3309 ret
= xmlACatalogResolveSystem(xmlDefaultCatalog
, sysID
);
3314 * xmlCatalogResolvePublic:
3315 * @pubID: the public ID string
3317 * Try to lookup the catalog reference associated to a public ID
3319 * Returns the resource if found or NULL otherwise, the value returned
3320 * must be freed by the caller.
3323 xmlCatalogResolvePublic(const xmlChar
*pubID
) {
3326 if (!xmlCatalogInitialized
)
3327 xmlInitializeCatalog();
3329 ret
= xmlACatalogResolvePublic(xmlDefaultCatalog
, pubID
);
3334 * xmlCatalogResolve:
3335 * @pubID: the public ID string
3336 * @sysID: the system ID string
3338 * Do a complete resolution lookup of an External Identifier
3340 * Returns the URI of the resource or NULL if not found, it must be freed
3344 xmlCatalogResolve(const xmlChar
*pubID
, const xmlChar
*sysID
) {
3347 if (!xmlCatalogInitialized
)
3348 xmlInitializeCatalog();
3350 ret
= xmlACatalogResolve(xmlDefaultCatalog
, pubID
, sysID
);
3355 * xmlCatalogResolveURI:
3358 * Do a complete resolution lookup of an URI
3360 * Returns the URI of the resource or NULL if not found, it must be freed
3364 xmlCatalogResolveURI(const xmlChar
*URI
) {
3367 if (!xmlCatalogInitialized
)
3368 xmlInitializeCatalog();
3370 ret
= xmlACatalogResolveURI(xmlDefaultCatalog
, URI
);
3374 #ifdef LIBXML_OUTPUT_ENABLED
3379 * Dump all the global catalog content to the given file.
3382 xmlCatalogDump(FILE *out
) {
3386 if (!xmlCatalogInitialized
)
3387 xmlInitializeCatalog();
3389 xmlACatalogDump(xmlDefaultCatalog
, out
);
3391 #endif /* LIBXML_OUTPUT_ENABLED */
3395 * @type: the type of record to add to the catalog
3396 * @orig: the system, public or prefix to match
3397 * @replace: the replacement value for the match
3399 * Add an entry in the catalog, it may overwrite existing but
3400 * different entries.
3401 * If called before any other catalog routine, allows to override the
3402 * default shared catalog put in place by xmlInitializeCatalog();
3404 * Returns 0 if successful, -1 otherwise
3407 xmlCatalogAdd(const xmlChar
*type
, const xmlChar
*orig
, const xmlChar
*replace
) {
3410 if (!xmlCatalogInitialized
)
3411 xmlInitializeCatalogData();
3413 xmlRMutexLock(xmlCatalogMutex
);
3415 * Specific case where one want to override the default catalog
3416 * put in place by xmlInitializeCatalog();
3418 if ((xmlDefaultCatalog
== NULL
) &&
3419 (xmlStrEqual(type
, BAD_CAST
"catalog"))) {
3420 xmlDefaultCatalog
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3421 xmlCatalogDefaultPrefer
);
3422 xmlDefaultCatalog
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3423 orig
, NULL
, xmlCatalogDefaultPrefer
, NULL
);
3425 xmlRMutexUnlock(xmlCatalogMutex
);
3429 res
= xmlACatalogAdd(xmlDefaultCatalog
, type
, orig
, replace
);
3430 xmlRMutexUnlock(xmlCatalogMutex
);
3436 * @value: the value to remove
3438 * Remove an entry from the catalog
3440 * Returns the number of entries removed if successful, -1 otherwise
3443 xmlCatalogRemove(const xmlChar
*value
) {
3446 if (!xmlCatalogInitialized
)
3447 xmlInitializeCatalog();
3449 xmlRMutexLock(xmlCatalogMutex
);
3450 res
= xmlACatalogRemove(xmlDefaultCatalog
, value
);
3451 xmlRMutexUnlock(xmlCatalogMutex
);
3456 * xmlCatalogConvert:
3458 * Convert all the SGML catalog entries as XML ones
3460 * Returns the number of entries converted if successful, -1 otherwise
3463 xmlCatalogConvert(void) {
3466 if (!xmlCatalogInitialized
)
3467 xmlInitializeCatalog();
3469 xmlRMutexLock(xmlCatalogMutex
);
3470 res
= xmlConvertSGMLCatalog(xmlDefaultCatalog
);
3471 xmlRMutexUnlock(xmlCatalogMutex
);
3475 /************************************************************************
3477 * Public interface manipulating the common preferences *
3479 ************************************************************************/
3482 * xmlCatalogGetDefaults:
3484 * Used to get the user preference w.r.t. to what catalogs should
3487 * Returns the current xmlCatalogAllow value
3490 xmlCatalogGetDefaults(void) {
3491 return(xmlCatalogDefaultAllow
);
3495 * xmlCatalogSetDefaults:
3496 * @allow: what catalogs should be accepted
3498 * Used to set the user preference w.r.t. to what catalogs should
3502 xmlCatalogSetDefaults(xmlCatalogAllow allow
) {
3503 if (xmlDebugCatalogs
) {
3505 case XML_CATA_ALLOW_NONE
:
3506 xmlGenericError(xmlGenericErrorContext
,
3507 "Disabling catalog usage\n");
3509 case XML_CATA_ALLOW_GLOBAL
:
3510 xmlGenericError(xmlGenericErrorContext
,
3511 "Allowing only global catalogs\n");
3513 case XML_CATA_ALLOW_DOCUMENT
:
3514 xmlGenericError(xmlGenericErrorContext
,
3515 "Allowing only catalogs from the document\n");
3517 case XML_CATA_ALLOW_ALL
:
3518 xmlGenericError(xmlGenericErrorContext
,
3519 "Allowing all catalogs\n");
3523 xmlCatalogDefaultAllow
= allow
;
3527 * xmlCatalogSetDefaultPrefer:
3528 * @prefer: the default preference for delegation
3530 * Allows to set the preference between public and system for deletion
3531 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3532 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3534 * Returns the previous value of the default preference for delegation
3537 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer
) {
3538 xmlCatalogPrefer ret
= xmlCatalogDefaultPrefer
;
3540 if (prefer
== XML_CATA_PREFER_NONE
)
3543 if (xmlDebugCatalogs
) {
3545 case XML_CATA_PREFER_PUBLIC
:
3546 xmlGenericError(xmlGenericErrorContext
,
3547 "Setting catalog preference to PUBLIC\n");
3549 case XML_CATA_PREFER_SYSTEM
:
3550 xmlGenericError(xmlGenericErrorContext
,
3551 "Setting catalog preference to SYSTEM\n");
3553 case XML_CATA_PREFER_NONE
:
3557 xmlCatalogDefaultPrefer
= prefer
;
3562 * xmlCatalogSetDebug:
3563 * @level: the debug level of catalogs required
3565 * Used to set the debug level for catalog operation, 0 disable
3566 * debugging, 1 enable it
3568 * Returns the previous value of the catalog debugging level
3571 xmlCatalogSetDebug(int level
) {
3572 int ret
= xmlDebugCatalogs
;
3575 xmlDebugCatalogs
= 0;
3577 xmlDebugCatalogs
= level
;
3581 /************************************************************************
3583 * Minimal interfaces used for per-document catalogs by the parser *
3585 ************************************************************************/
3588 * xmlCatalogFreeLocal:
3589 * @catalogs: a document's list of catalogs
3591 * Free up the memory associated to the catalog list
3594 xmlCatalogFreeLocal(void *catalogs
) {
3595 xmlCatalogEntryPtr catal
;
3597 if (!xmlCatalogInitialized
)
3598 xmlInitializeCatalog();
3600 catal
= (xmlCatalogEntryPtr
) catalogs
;
3602 xmlFreeCatalogEntryList(catal
);
3607 * xmlCatalogAddLocal:
3608 * @catalogs: a document's list of catalogs
3609 * @URL: the URL to a new local catalog
3611 * Add the new entry to the catalog list
3613 * Returns the updated list
3616 xmlCatalogAddLocal(void *catalogs
, const xmlChar
*URL
) {
3617 xmlCatalogEntryPtr catal
, add
;
3619 if (!xmlCatalogInitialized
)
3620 xmlInitializeCatalog();
3625 if (xmlDebugCatalogs
)
3626 xmlGenericError(xmlGenericErrorContext
,
3627 "Adding document catalog %s\n", URL
);
3629 add
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
, URL
, NULL
,
3630 xmlCatalogDefaultPrefer
, NULL
);
3634 catal
= (xmlCatalogEntryPtr
) catalogs
;
3636 return((void *) add
);
3638 while (catal
->next
!= NULL
)
3639 catal
= catal
->next
;
3645 * xmlCatalogLocalResolve:
3646 * @catalogs: a document's list of catalogs
3647 * @pubID: the public ID string
3648 * @sysID: the system ID string
3650 * Do a complete resolution lookup of an External Identifier using a
3651 * document's private catalog list
3653 * Returns the URI of the resource or NULL if not found, it must be freed
3657 xmlCatalogLocalResolve(void *catalogs
, const xmlChar
*pubID
,
3658 const xmlChar
*sysID
) {
3659 xmlCatalogEntryPtr catal
;
3662 if (!xmlCatalogInitialized
)
3663 xmlInitializeCatalog();
3665 if ((pubID
== NULL
) && (sysID
== NULL
))
3668 if (xmlDebugCatalogs
) {
3669 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
3670 xmlGenericError(xmlGenericErrorContext
,
3671 "Local Resolve: pubID %s sysID %s\n", pubID
, sysID
);
3672 } else if (pubID
!= NULL
) {
3673 xmlGenericError(xmlGenericErrorContext
,
3674 "Local Resolve: pubID %s\n", pubID
);
3676 xmlGenericError(xmlGenericErrorContext
,
3677 "Local Resolve: sysID %s\n", sysID
);
3681 catal
= (xmlCatalogEntryPtr
) catalogs
;
3684 ret
= xmlCatalogListXMLResolve(catal
, pubID
, sysID
);
3685 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3691 * xmlCatalogLocalResolveURI:
3692 * @catalogs: a document's list of catalogs
3695 * Do a complete resolution lookup of an URI using a
3696 * document's private catalog list
3698 * Returns the URI of the resource or NULL if not found, it must be freed
3702 xmlCatalogLocalResolveURI(void *catalogs
, const xmlChar
*URI
) {
3703 xmlCatalogEntryPtr catal
;
3706 if (!xmlCatalogInitialized
)
3707 xmlInitializeCatalog();
3712 if (xmlDebugCatalogs
)
3713 xmlGenericError(xmlGenericErrorContext
,
3714 "Resolve URI %s\n", URI
);
3716 catal
= (xmlCatalogEntryPtr
) catalogs
;
3719 ret
= xmlCatalogListXMLResolveURI(catal
, URI
);
3720 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3725 /************************************************************************
3727 * Deprecated interfaces *
3729 ************************************************************************/
3731 * xmlCatalogGetSystem:
3732 * @sysID: the system ID string
3734 * Try to lookup the catalog reference associated to a system ID
3735 * DEPRECATED, use xmlCatalogResolveSystem()
3737 * Returns the resource if found or NULL otherwise.
3740 xmlCatalogGetSystem(const xmlChar
*sysID
) {
3742 static xmlChar result
[1000];
3745 if (!xmlCatalogInitialized
)
3746 xmlInitializeCatalog();
3749 xmlGenericError(xmlGenericErrorContext
,
3750 "Use of deprecated xmlCatalogGetSystem() call\n");
3758 * Check first the XML catalogs
3760 if (xmlDefaultCatalog
!= NULL
) {
3761 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, NULL
, sysID
);
3762 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3763 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3764 result
[sizeof(result
) - 1] = 0;
3769 if (xmlDefaultCatalog
!= NULL
)
3770 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog
->sgml
, sysID
));
3775 * xmlCatalogGetPublic:
3776 * @pubID: the public ID string
3778 * Try to lookup the catalog reference associated to a public ID
3779 * DEPRECATED, use xmlCatalogResolvePublic()
3781 * Returns the resource if found or NULL otherwise.
3784 xmlCatalogGetPublic(const xmlChar
*pubID
) {
3786 static xmlChar result
[1000];
3789 if (!xmlCatalogInitialized
)
3790 xmlInitializeCatalog();
3793 xmlGenericError(xmlGenericErrorContext
,
3794 "Use of deprecated xmlCatalogGetPublic() call\n");
3802 * Check first the XML catalogs
3804 if (xmlDefaultCatalog
!= NULL
) {
3805 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, pubID
, NULL
);
3806 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3807 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3808 result
[sizeof(result
) - 1] = 0;
3813 if (xmlDefaultCatalog
!= NULL
)
3814 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog
->sgml
, pubID
));
3818 #define bottom_catalog
3819 #include "elfgcchack.h"
3820 #endif /* LIBXML_CATALOG_ENABLED */