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 preferred
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 information
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 information
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 * @payload: a Catalog entry
324 * Free the memory allocated to a Catalog entry
327 xmlFreeCatalogEntry(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
328 xmlCatalogEntryPtr ret
= (xmlCatalogEntryPtr
) payload
;
332 * Entries stored in the file hash must be deallocated
333 * only by the file hash cleaner !
335 if (ret
->dealloc
== 1)
338 if (xmlDebugCatalogs
) {
339 if (ret
->name
!= NULL
)
340 xmlGenericError(xmlGenericErrorContext
,
341 "Free catalog entry %s\n", ret
->name
);
342 else if (ret
->value
!= NULL
)
343 xmlGenericError(xmlGenericErrorContext
,
344 "Free catalog entry %s\n", ret
->value
);
346 xmlGenericError(xmlGenericErrorContext
,
347 "Free catalog entry\n");
350 if (ret
->name
!= NULL
)
352 if (ret
->value
!= NULL
)
354 if (ret
->URL
!= NULL
)
360 * xmlFreeCatalogEntryList:
361 * @ret: a Catalog entry list
363 * Free the memory allocated to a full chained list of Catalog entries
366 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret
) {
367 xmlCatalogEntryPtr next
;
369 while (ret
!= NULL
) {
371 xmlFreeCatalogEntry(ret
, NULL
);
377 * xmlFreeCatalogHashEntryList:
378 * @payload: a Catalog entry list
380 * Free the memory allocated to list of Catalog entries from the
384 xmlFreeCatalogHashEntryList(void *payload
,
385 const xmlChar
*name ATTRIBUTE_UNUSED
) {
386 xmlCatalogEntryPtr catal
= (xmlCatalogEntryPtr
) payload
;
387 xmlCatalogEntryPtr children
, next
;
392 children
= catal
->children
;
393 while (children
!= NULL
) {
394 next
= children
->next
;
395 children
->dealloc
= 0;
396 children
->children
= NULL
;
397 xmlFreeCatalogEntry(children
, NULL
);
401 xmlFreeCatalogEntry(catal
, NULL
);
405 * xmlCreateNewCatalog:
406 * @type: type of catalog
407 * @prefer: the PUBLIC vs. SYSTEM current preference value
409 * create a new Catalog, this type is shared both by XML and
410 * SGML catalogs, but the acceptable types values differs.
412 * Returns the xmlCatalogPtr or NULL in case of error
415 xmlCreateNewCatalog(xmlCatalogType type
, xmlCatalogPrefer prefer
) {
418 ret
= (xmlCatalogPtr
) xmlMalloc(sizeof(xmlCatalog
));
420 xmlCatalogErrMemory("allocating catalog");
423 memset(ret
, 0, sizeof(xmlCatalog
));
426 ret
->catalMax
= XML_MAX_SGML_CATA_DEPTH
;
427 ret
->prefer
= prefer
;
428 if (ret
->type
== XML_SGML_CATALOG_TYPE
)
429 ret
->sgml
= xmlHashCreate(10);
437 * Free the memory allocated to a Catalog
440 xmlFreeCatalog(xmlCatalogPtr catal
) {
443 if (catal
->xml
!= NULL
)
444 xmlFreeCatalogEntryList(catal
->xml
);
445 if (catal
->sgml
!= NULL
)
446 xmlHashFree(catal
->sgml
, xmlFreeCatalogEntry
);
450 /************************************************************************
452 * Serializing Catalogs *
454 ************************************************************************/
456 #ifdef LIBXML_OUTPUT_ENABLED
458 * xmlCatalogDumpEntry:
459 * @entry: the catalog entry
462 * Serialize an SGML Catalog entry
465 xmlCatalogDumpEntry(void *payload
, void *data
,
466 const xmlChar
*name ATTRIBUTE_UNUSED
) {
467 xmlCatalogEntryPtr entry
= (xmlCatalogEntryPtr
) payload
;
468 FILE *out
= (FILE *) data
;
469 if ((entry
== NULL
) || (out
== NULL
))
471 switch (entry
->type
) {
472 case SGML_CATA_ENTITY
:
473 fprintf(out
, "ENTITY "); break;
474 case SGML_CATA_PENTITY
:
475 fprintf(out
, "ENTITY %%"); break;
476 case SGML_CATA_DOCTYPE
:
477 fprintf(out
, "DOCTYPE "); break;
478 case SGML_CATA_LINKTYPE
:
479 fprintf(out
, "LINKTYPE "); break;
480 case SGML_CATA_NOTATION
:
481 fprintf(out
, "NOTATION "); break;
482 case SGML_CATA_PUBLIC
:
483 fprintf(out
, "PUBLIC "); break;
484 case SGML_CATA_SYSTEM
:
485 fprintf(out
, "SYSTEM "); break;
486 case SGML_CATA_DELEGATE
:
487 fprintf(out
, "DELEGATE "); break;
489 fprintf(out
, "BASE "); break;
490 case SGML_CATA_CATALOG
:
491 fprintf(out
, "CATALOG "); break;
492 case SGML_CATA_DOCUMENT
:
493 fprintf(out
, "DOCUMENT "); break;
494 case SGML_CATA_SGMLDECL
:
495 fprintf(out
, "SGMLDECL "); break;
499 switch (entry
->type
) {
500 case SGML_CATA_ENTITY
:
501 case SGML_CATA_PENTITY
:
502 case SGML_CATA_DOCTYPE
:
503 case SGML_CATA_LINKTYPE
:
504 case SGML_CATA_NOTATION
:
505 fprintf(out
, "%s", (const char *) entry
->name
); break;
506 case SGML_CATA_PUBLIC
:
507 case SGML_CATA_SYSTEM
:
508 case SGML_CATA_SGMLDECL
:
509 case SGML_CATA_DOCUMENT
:
510 case SGML_CATA_CATALOG
:
512 case SGML_CATA_DELEGATE
:
513 fprintf(out
, "\"%s\"", entry
->name
); break;
517 switch (entry
->type
) {
518 case SGML_CATA_ENTITY
:
519 case SGML_CATA_PENTITY
:
520 case SGML_CATA_DOCTYPE
:
521 case SGML_CATA_LINKTYPE
:
522 case SGML_CATA_NOTATION
:
523 case SGML_CATA_PUBLIC
:
524 case SGML_CATA_SYSTEM
:
525 case SGML_CATA_DELEGATE
:
526 fprintf(out
, " \"%s\"", entry
->value
); break;
534 * xmlDumpXMLCatalogNode:
535 * @catal: top catalog entry
536 * @catalog: pointer to the xml tree
537 * @doc: the containing document
538 * @ns: the current namespace
539 * @cgroup: group node for group members
541 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
544 static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal
, xmlNodePtr catalog
,
545 xmlDocPtr doc
, xmlNsPtr ns
, xmlCatalogEntryPtr cgroup
) {
547 xmlCatalogEntryPtr cur
;
549 * add all the catalog entries
552 while (cur
!= NULL
) {
553 if (cur
->group
== cgroup
) {
555 case XML_CATA_REMOVED
:
557 case XML_CATA_BROKEN_CATALOG
:
558 case XML_CATA_CATALOG
:
564 case XML_CATA_NEXT_CATALOG
:
565 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"nextCatalog", NULL
);
566 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
567 xmlAddChild(catalog
, node
);
572 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"group", NULL
);
573 xmlSetProp(node
, BAD_CAST
"id", cur
->name
);
574 if (cur
->value
!= NULL
) {
576 xns
= xmlSearchNsByHref(doc
, node
, XML_XML_NAMESPACE
);
578 xmlSetNsProp(node
, xns
, BAD_CAST
"base",
581 switch (cur
->prefer
) {
582 case XML_CATA_PREFER_NONE
:
584 case XML_CATA_PREFER_PUBLIC
:
585 xmlSetProp(node
, BAD_CAST
"prefer", BAD_CAST
"public");
587 case XML_CATA_PREFER_SYSTEM
:
588 xmlSetProp(node
, BAD_CAST
"prefer", BAD_CAST
"system");
591 xmlDumpXMLCatalogNode(cur
->next
, node
, doc
, ns
, cur
);
592 xmlAddChild(catalog
, node
);
594 case XML_CATA_PUBLIC
:
595 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"public", NULL
);
596 xmlSetProp(node
, BAD_CAST
"publicId", cur
->name
);
597 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
598 xmlAddChild(catalog
, node
);
600 case XML_CATA_SYSTEM
:
601 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"system", NULL
);
602 xmlSetProp(node
, BAD_CAST
"systemId", cur
->name
);
603 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
604 xmlAddChild(catalog
, node
);
606 case XML_CATA_REWRITE_SYSTEM
:
607 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"rewriteSystem", NULL
);
608 xmlSetProp(node
, BAD_CAST
"systemIdStartString", cur
->name
);
609 xmlSetProp(node
, BAD_CAST
"rewritePrefix", cur
->value
);
610 xmlAddChild(catalog
, node
);
612 case XML_CATA_DELEGATE_PUBLIC
:
613 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegatePublic", NULL
);
614 xmlSetProp(node
, BAD_CAST
"publicIdStartString", cur
->name
);
615 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
616 xmlAddChild(catalog
, node
);
618 case XML_CATA_DELEGATE_SYSTEM
:
619 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegateSystem", NULL
);
620 xmlSetProp(node
, BAD_CAST
"systemIdStartString", cur
->name
);
621 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
622 xmlAddChild(catalog
, node
);
625 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"uri", NULL
);
626 xmlSetProp(node
, BAD_CAST
"name", cur
->name
);
627 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
628 xmlAddChild(catalog
, node
);
630 case XML_CATA_REWRITE_URI
:
631 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"rewriteURI", NULL
);
632 xmlSetProp(node
, BAD_CAST
"uriStartString", cur
->name
);
633 xmlSetProp(node
, BAD_CAST
"rewritePrefix", cur
->value
);
634 xmlAddChild(catalog
, node
);
636 case XML_CATA_DELEGATE_URI
:
637 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegateURI", NULL
);
638 xmlSetProp(node
, BAD_CAST
"uriStartString", cur
->name
);
639 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
640 xmlAddChild(catalog
, node
);
642 case SGML_CATA_SYSTEM
:
643 case SGML_CATA_PUBLIC
:
644 case SGML_CATA_ENTITY
:
645 case SGML_CATA_PENTITY
:
646 case SGML_CATA_DOCTYPE
:
647 case SGML_CATA_LINKTYPE
:
648 case SGML_CATA_NOTATION
:
649 case SGML_CATA_DELEGATE
:
651 case SGML_CATA_CATALOG
:
652 case SGML_CATA_DOCUMENT
:
653 case SGML_CATA_SGMLDECL
:
662 xmlDumpXMLCatalog(FILE *out
, xmlCatalogEntryPtr catal
) {
668 xmlOutputBufferPtr buf
;
673 doc
= xmlNewDoc(NULL
);
676 dtd
= xmlNewDtd(doc
, BAD_CAST
"catalog",
677 BAD_CAST
"-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
678 BAD_CAST
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
680 xmlAddChild((xmlNodePtr
) doc
, (xmlNodePtr
) dtd
);
682 ns
= xmlNewNs(NULL
, XML_CATALOGS_NAMESPACE
, NULL
);
687 catalog
= xmlNewDocNode(doc
, ns
, BAD_CAST
"catalog", NULL
);
688 if (catalog
== NULL
) {
694 xmlAddChild((xmlNodePtr
) doc
, catalog
);
696 xmlDumpXMLCatalogNode(catal
, catalog
, doc
, ns
, NULL
);
701 buf
= xmlOutputBufferCreateFile(out
, NULL
);
706 ret
= xmlSaveFormatFileTo(buf
, doc
, NULL
, 1);
715 #endif /* LIBXML_OUTPUT_ENABLED */
717 /************************************************************************
719 * Converting SGML Catalogs to XML *
721 ************************************************************************/
724 * xmlCatalogConvertEntry:
726 * @catal: pointer to the catalog being converted
728 * Convert one entry from the catalog
731 xmlCatalogConvertEntry(void *payload
, void *data
,
732 const xmlChar
*name ATTRIBUTE_UNUSED
) {
733 xmlCatalogEntryPtr entry
= (xmlCatalogEntryPtr
) payload
;
734 xmlCatalogPtr catal
= (xmlCatalogPtr
) data
;
735 if ((entry
== NULL
) || (catal
== NULL
) || (catal
->sgml
== NULL
) ||
736 (catal
->xml
== NULL
))
738 switch (entry
->type
) {
739 case SGML_CATA_ENTITY
:
740 entry
->type
= XML_CATA_PUBLIC
;
742 case SGML_CATA_PENTITY
:
743 entry
->type
= XML_CATA_PUBLIC
;
745 case SGML_CATA_DOCTYPE
:
746 entry
->type
= XML_CATA_PUBLIC
;
748 case SGML_CATA_LINKTYPE
:
749 entry
->type
= XML_CATA_PUBLIC
;
751 case SGML_CATA_NOTATION
:
752 entry
->type
= XML_CATA_PUBLIC
;
754 case SGML_CATA_PUBLIC
:
755 entry
->type
= XML_CATA_PUBLIC
;
757 case SGML_CATA_SYSTEM
:
758 entry
->type
= XML_CATA_SYSTEM
;
760 case SGML_CATA_DELEGATE
:
761 entry
->type
= XML_CATA_DELEGATE_PUBLIC
;
763 case SGML_CATA_CATALOG
:
764 entry
->type
= XML_CATA_CATALOG
;
767 xmlHashRemoveEntry(catal
->sgml
, entry
->name
, xmlFreeCatalogEntry
);
771 * Conversion successful, remove from the SGML catalog
772 * and add it to the default XML one
774 xmlHashRemoveEntry(catal
->sgml
, entry
->name
, NULL
);
775 entry
->parent
= catal
->xml
;
777 if (catal
->xml
->children
== NULL
)
778 catal
->xml
->children
= entry
;
780 xmlCatalogEntryPtr prev
;
782 prev
= catal
->xml
->children
;
783 while (prev
->next
!= NULL
)
790 * xmlConvertSGMLCatalog:
791 * @catal: the catalog
793 * Convert all the SGML catalog entries as XML ones
795 * Returns the number of entries converted if successful, -1 otherwise
798 xmlConvertSGMLCatalog(xmlCatalogPtr catal
) {
800 if ((catal
== NULL
) || (catal
->type
!= XML_SGML_CATALOG_TYPE
))
803 if (xmlDebugCatalogs
) {
804 xmlGenericError(xmlGenericErrorContext
,
805 "Converting SGML catalog to XML\n");
807 xmlHashScan(catal
->sgml
, xmlCatalogConvertEntry
, &catal
);
811 /************************************************************************
815 ************************************************************************/
818 * xmlCatalogUnWrapURN:
819 * @urn: an "urn:publicid:" to unwrap
821 * Expand the URN into the equivalent Public Identifier
823 * Returns the new identifier or NULL, the string must be deallocated
827 xmlCatalogUnWrapURN(const xmlChar
*urn
) {
828 xmlChar result
[2000];
831 if (xmlStrncmp(urn
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1))
833 urn
+= sizeof(XML_URN_PUBID
) - 1;
836 if (i
> sizeof(result
) - 4)
841 } else if (*urn
== ':') {
845 } else if (*urn
== ';') {
849 } else if (*urn
== '%') {
850 if ((urn
[1] == '2') && (urn
[2] == 'B'))
852 else if ((urn
[1] == '3') && (urn
[2] == 'A'))
854 else if ((urn
[1] == '2') && (urn
[2] == 'F'))
856 else if ((urn
[1] == '3') && (urn
[2] == 'B'))
858 else if ((urn
[1] == '2') && (urn
[2] == '7'))
860 else if ((urn
[1] == '3') && (urn
[2] == 'F'))
862 else if ((urn
[1] == '2') && (urn
[2] == '3'))
864 else if ((urn
[1] == '2') && (urn
[2] == '5'))
879 return(xmlStrdup(result
));
883 * xmlParseCatalogFile:
884 * @filename: the filename
886 * parse an XML file and build a tree. It's like xmlParseFile()
887 * except it bypass all catalog lookups.
889 * Returns the resulting document tree or NULL in case of error
893 xmlParseCatalogFile(const char *filename
) {
895 xmlParserCtxtPtr ctxt
;
896 char *directory
= NULL
;
897 xmlParserInputPtr inputStream
;
898 xmlParserInputBufferPtr buf
;
900 ctxt
= xmlNewParserCtxt();
902 #ifdef LIBXML_SAX1_ENABLED
903 if (xmlDefaultSAXHandler
.error
!= NULL
) {
904 xmlDefaultSAXHandler
.error(NULL
, "out of memory\n");
910 buf
= xmlParserInputBufferCreateFilename(filename
, XML_CHAR_ENCODING_NONE
);
912 xmlFreeParserCtxt(ctxt
);
916 inputStream
= xmlNewInputStream(ctxt
);
917 if (inputStream
== NULL
) {
918 xmlFreeParserInputBuffer(buf
);
919 xmlFreeParserCtxt(ctxt
);
923 inputStream
->filename
= (char *) xmlCanonicPath((const xmlChar
*)filename
);
924 inputStream
->buf
= buf
;
925 xmlBufResetInput(buf
->buffer
, inputStream
);
927 inputPush(ctxt
, inputStream
);
928 if (ctxt
->directory
== NULL
)
929 directory
= xmlParserGetDirectory(filename
);
930 if ((ctxt
->directory
== NULL
) && (directory
!= NULL
))
931 ctxt
->directory
= directory
;
934 ctxt
->loadsubset
= 0;
938 xmlParseDocument(ctxt
);
940 if (ctxt
->wellFormed
)
944 xmlFreeDoc(ctxt
->myDoc
);
947 xmlFreeParserCtxt(ctxt
);
953 * xmlLoadFileContent:
954 * @filename: a file path
956 * Load a file content into memory.
958 * Returns a pointer to the 0 terminated string or NULL in case of error
961 xmlLoadFileContent(const char *filename
)
976 if (filename
== NULL
)
980 if (stat(filename
, &info
) < 0)
985 if ((fd
= open(filename
, O_RDONLY
)) < 0)
987 if ((fd
= fopen(filename
, "rb")) == NULL
)
995 if (fseek(fd
, 0, SEEK_END
) || (size
= ftell(fd
)) == EOF
|| fseek(fd
, 0, SEEK_SET
)) { /* File operations denied? ok, just close and return failure */
1000 content
= (xmlChar
*)xmlMallocAtomic(size
+ 10);
1001 if (content
== NULL
) {
1002 xmlCatalogErrMemory("allocating catalog data");
1011 len
= read(fd
, content
, size
);
1014 len
= fread(content
, 1, size
, fd
);
1027 * xmlCatalogNormalizePublic:
1028 * @pubID: the public ID string
1030 * Normalizes the Public Identifier
1032 * Implements 6.2. Public Identifier Normalization
1033 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1035 * Returns the new string or NULL, the string must be deallocated
1039 xmlCatalogNormalizePublic(const xmlChar
*pubID
)
1051 for (p
= pubID
;*p
!= 0 && ok
;p
++) {
1052 if (!xmlIsBlank_ch(*p
))
1054 else if (*p
== 0x20 && !white
)
1059 if (ok
&& !white
) /* is normalized */
1062 ret
= xmlStrdup(pubID
);
1065 for (p
= pubID
;*p
!= 0;p
++) {
1066 if (xmlIsBlank_ch(*p
)) {
1081 /************************************************************************
1083 * The XML Catalog parser *
1085 ************************************************************************/
1087 static xmlCatalogEntryPtr
1088 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
);
1090 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1091 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
);
1093 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1094 const xmlChar
*sysID
);
1096 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
);
1100 * xmlGetXMLCatalogEntryType:
1103 * lookup the internal type associated to an XML catalog entry name
1105 * Returns the type associated with that name
1107 static xmlCatalogEntryType
1108 xmlGetXMLCatalogEntryType(const xmlChar
*name
) {
1109 xmlCatalogEntryType type
= XML_CATA_NONE
;
1110 if (xmlStrEqual(name
, (const xmlChar
*) "system"))
1111 type
= XML_CATA_SYSTEM
;
1112 else if (xmlStrEqual(name
, (const xmlChar
*) "public"))
1113 type
= XML_CATA_PUBLIC
;
1114 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteSystem"))
1115 type
= XML_CATA_REWRITE_SYSTEM
;
1116 else if (xmlStrEqual(name
, (const xmlChar
*) "delegatePublic"))
1117 type
= XML_CATA_DELEGATE_PUBLIC
;
1118 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateSystem"))
1119 type
= XML_CATA_DELEGATE_SYSTEM
;
1120 else if (xmlStrEqual(name
, (const xmlChar
*) "uri"))
1121 type
= XML_CATA_URI
;
1122 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteURI"))
1123 type
= XML_CATA_REWRITE_URI
;
1124 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateURI"))
1125 type
= XML_CATA_DELEGATE_URI
;
1126 else if (xmlStrEqual(name
, (const xmlChar
*) "nextCatalog"))
1127 type
= XML_CATA_NEXT_CATALOG
;
1128 else if (xmlStrEqual(name
, (const xmlChar
*) "catalog"))
1129 type
= XML_CATA_CATALOG
;
1134 * xmlParseXMLCatalogOneNode:
1135 * @cur: the XML node
1136 * @type: the type of Catalog entry
1137 * @name: the name of the node
1138 * @attrName: the attribute holding the value
1139 * @uriAttrName: the attribute holding the URI-Reference
1140 * @prefer: the PUBLIC vs. SYSTEM current preference value
1141 * @cgroup: the group which includes this node
1143 * Finishes the examination of an XML tree node of a catalog and build
1144 * a Catalog entry from it.
1146 * Returns the new Catalog entry node or NULL in case of error.
1148 static xmlCatalogEntryPtr
1149 xmlParseXMLCatalogOneNode(xmlNodePtr cur
, xmlCatalogEntryType type
,
1150 const xmlChar
*name
, const xmlChar
*attrName
,
1151 const xmlChar
*uriAttrName
, xmlCatalogPrefer prefer
,
1152 xmlCatalogEntryPtr cgroup
) {
1155 xmlChar
*nameValue
= NULL
;
1156 xmlChar
*base
= NULL
;
1157 xmlChar
*URL
= NULL
;
1158 xmlCatalogEntryPtr ret
= NULL
;
1160 if (attrName
!= NULL
) {
1161 nameValue
= xmlGetProp(cur
, attrName
);
1162 if (nameValue
== NULL
) {
1163 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1164 "%s entry lacks '%s'\n", name
, attrName
, NULL
);
1168 uriValue
= xmlGetProp(cur
, uriAttrName
);
1169 if (uriValue
== NULL
) {
1170 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1171 "%s entry lacks '%s'\n", name
, uriAttrName
, NULL
);
1175 if (nameValue
!= NULL
)
1177 if (uriValue
!= NULL
)
1182 base
= xmlNodeGetBase(cur
->doc
, cur
);
1183 URL
= xmlBuildURI(uriValue
, base
);
1185 if (xmlDebugCatalogs
> 1) {
1186 if (nameValue
!= NULL
)
1187 xmlGenericError(xmlGenericErrorContext
,
1188 "Found %s: '%s' '%s'\n", name
, nameValue
, URL
);
1190 xmlGenericError(xmlGenericErrorContext
,
1191 "Found %s: '%s'\n", name
, URL
);
1193 ret
= xmlNewCatalogEntry(type
, nameValue
, uriValue
, URL
, prefer
, cgroup
);
1195 xmlCatalogErr(ret
, cur
, XML_CATALOG_ENTRY_BROKEN
,
1196 "%s entry '%s' broken ?: %s\n", name
, uriAttrName
, uriValue
);
1198 if (nameValue
!= NULL
)
1200 if (uriValue
!= NULL
)
1210 * xmlParseXMLCatalogNode:
1211 * @cur: the XML node
1212 * @prefer: the PUBLIC vs. SYSTEM current preference value
1213 * @parent: the parent Catalog entry
1214 * @cgroup: the group which includes this node
1216 * Examines an XML tree node of a catalog and build
1217 * a Catalog entry from it adding it to its parent. The examination can
1221 xmlParseXMLCatalogNode(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1222 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
)
1224 xmlChar
*base
= NULL
;
1225 xmlCatalogEntryPtr entry
= NULL
;
1229 if (xmlStrEqual(cur
->name
, BAD_CAST
"group")) {
1231 xmlCatalogPrefer pref
= XML_CATA_PREFER_NONE
;
1233 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1235 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1236 prefer
= XML_CATA_PREFER_SYSTEM
;
1237 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1238 prefer
= XML_CATA_PREFER_PUBLIC
;
1240 xmlCatalogErr(parent
, cur
, XML_CATALOG_PREFER_VALUE
,
1241 "Invalid value for prefer: '%s'\n",
1247 prop
= xmlGetProp(cur
, BAD_CAST
"id");
1248 base
= xmlGetNsProp(cur
, BAD_CAST
"base", XML_XML_NAMESPACE
);
1249 entry
= xmlNewCatalogEntry(XML_CATA_GROUP
, prop
, base
, NULL
, pref
, cgroup
);
1251 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"public")) {
1252 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_PUBLIC
,
1253 BAD_CAST
"public", BAD_CAST
"publicId", BAD_CAST
"uri", prefer
, cgroup
);
1254 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"system")) {
1255 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_SYSTEM
,
1256 BAD_CAST
"system", BAD_CAST
"systemId", BAD_CAST
"uri", prefer
, cgroup
);
1257 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteSystem")) {
1258 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_SYSTEM
,
1259 BAD_CAST
"rewriteSystem", BAD_CAST
"systemIdStartString",
1260 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1261 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegatePublic")) {
1262 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_PUBLIC
,
1263 BAD_CAST
"delegatePublic", BAD_CAST
"publicIdStartString",
1264 BAD_CAST
"catalog", prefer
, cgroup
);
1265 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateSystem")) {
1266 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_SYSTEM
,
1267 BAD_CAST
"delegateSystem", BAD_CAST
"systemIdStartString",
1268 BAD_CAST
"catalog", prefer
, cgroup
);
1269 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"uri")) {
1270 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_URI
,
1271 BAD_CAST
"uri", BAD_CAST
"name",
1272 BAD_CAST
"uri", prefer
, cgroup
);
1273 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteURI")) {
1274 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_URI
,
1275 BAD_CAST
"rewriteURI", BAD_CAST
"uriStartString",
1276 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1277 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateURI")) {
1278 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_URI
,
1279 BAD_CAST
"delegateURI", BAD_CAST
"uriStartString",
1280 BAD_CAST
"catalog", prefer
, cgroup
);
1281 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"nextCatalog")) {
1282 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_NEXT_CATALOG
,
1283 BAD_CAST
"nextCatalog", NULL
,
1284 BAD_CAST
"catalog", prefer
, cgroup
);
1286 if (entry
!= NULL
) {
1287 if (parent
!= NULL
) {
1288 entry
->parent
= parent
;
1289 if (parent
->children
== NULL
)
1290 parent
->children
= entry
;
1292 xmlCatalogEntryPtr prev
;
1294 prev
= parent
->children
;
1295 while (prev
->next
!= NULL
)
1300 if (entry
->type
== XML_CATA_GROUP
) {
1302 * Recurse to propagate prefer to the subtree
1303 * (xml:base handling is automated)
1305 xmlParseXMLCatalogNodeList(cur
->children
, prefer
, parent
, entry
);
1313 * xmlParseXMLCatalogNodeList:
1314 * @cur: the XML node list of siblings
1315 * @prefer: the PUBLIC vs. SYSTEM current preference value
1316 * @parent: the parent Catalog entry
1317 * @cgroup: the group which includes this list
1319 * Examines a list of XML sibling nodes of a catalog and build
1320 * a list of Catalog entry from it adding it to the parent.
1321 * The examination will recurse to examine node subtrees.
1324 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1325 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
) {
1326 while (cur
!= NULL
) {
1327 if ((cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1328 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1329 xmlParseXMLCatalogNode(cur
, prefer
, parent
, cgroup
);
1333 /* TODO: sort the list according to REWRITE lengths and prefer value */
1337 * xmlParseXMLCatalogFile:
1338 * @prefer: the PUBLIC vs. SYSTEM current preference value
1339 * @filename: the filename for the catalog
1341 * Parses the catalog file to extract the XML tree and then analyze the
1342 * tree to build a list of Catalog entries corresponding to this catalog
1344 * Returns the resulting Catalog entries list
1346 static xmlCatalogEntryPtr
1347 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
) {
1351 xmlCatalogEntryPtr parent
= NULL
;
1353 if (filename
== NULL
)
1356 doc
= xmlParseCatalogFile((const char *) filename
);
1358 if (xmlDebugCatalogs
)
1359 xmlGenericError(xmlGenericErrorContext
,
1360 "Failed to parse catalog %s\n", filename
);
1364 if (xmlDebugCatalogs
)
1365 xmlGenericError(xmlGenericErrorContext
,
1366 "%d Parsing catalog %s\n", xmlGetThreadId(), filename
);
1368 cur
= xmlDocGetRootElement(doc
);
1369 if ((cur
!= NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"catalog")) &&
1370 (cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1371 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1373 parent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
1374 (const xmlChar
*)filename
, NULL
, prefer
, NULL
);
1375 if (parent
== NULL
) {
1380 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1382 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1383 prefer
= XML_CATA_PREFER_SYSTEM
;
1384 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1385 prefer
= XML_CATA_PREFER_PUBLIC
;
1387 xmlCatalogErr(NULL
, cur
, XML_CATALOG_PREFER_VALUE
,
1388 "Invalid value for prefer: '%s'\n",
1393 cur
= cur
->children
;
1394 xmlParseXMLCatalogNodeList(cur
, prefer
, parent
, NULL
);
1396 xmlCatalogErr(NULL
, (xmlNodePtr
) doc
, XML_CATALOG_NOT_CATALOG
,
1397 "File %s is not an XML Catalog\n",
1398 filename
, NULL
, NULL
);
1407 * xmlFetchXMLCatalogFile:
1408 * @catal: an existing but incomplete catalog entry
1410 * Fetch and parse the subcatalog referenced by an entry
1412 * Returns 0 in case of success, -1 otherwise
1415 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal
) {
1416 xmlCatalogEntryPtr doc
;
1420 if (catal
->URL
== NULL
)
1424 * lock the whole catalog for modification
1426 xmlRMutexLock(xmlCatalogMutex
);
1427 if (catal
->children
!= NULL
) {
1428 /* Okay someone else did it in the meantime */
1429 xmlRMutexUnlock(xmlCatalogMutex
);
1433 if (xmlCatalogXMLFiles
!= NULL
) {
1434 doc
= (xmlCatalogEntryPtr
)
1435 xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1437 if (xmlDebugCatalogs
)
1438 xmlGenericError(xmlGenericErrorContext
,
1439 "Found %s in file hash\n", catal
->URL
);
1441 if (catal
->type
== XML_CATA_CATALOG
)
1442 catal
->children
= doc
->children
;
1444 catal
->children
= doc
;
1446 xmlRMutexUnlock(xmlCatalogMutex
);
1449 if (xmlDebugCatalogs
)
1450 xmlGenericError(xmlGenericErrorContext
,
1451 "%s not found in file hash\n", catal
->URL
);
1455 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1456 * use the existing catalog, there is no recursion allowed at
1459 doc
= xmlParseXMLCatalogFile(catal
->prefer
, catal
->URL
);
1461 catal
->type
= XML_CATA_BROKEN_CATALOG
;
1462 xmlRMutexUnlock(xmlCatalogMutex
);
1466 if (catal
->type
== XML_CATA_CATALOG
)
1467 catal
->children
= doc
->children
;
1469 catal
->children
= doc
;
1473 if (xmlCatalogXMLFiles
== NULL
)
1474 xmlCatalogXMLFiles
= xmlHashCreate(10);
1475 if (xmlCatalogXMLFiles
!= NULL
) {
1476 if (xmlDebugCatalogs
)
1477 xmlGenericError(xmlGenericErrorContext
,
1478 "%s added to file hash\n", catal
->URL
);
1479 xmlHashAddEntry(xmlCatalogXMLFiles
, catal
->URL
, doc
);
1481 xmlRMutexUnlock(xmlCatalogMutex
);
1485 /************************************************************************
1487 * XML Catalog handling *
1489 ************************************************************************/
1493 * @catal: top of an XML catalog
1494 * @type: the type of record to add to the catalog
1495 * @orig: the system, public or prefix to match (or NULL)
1496 * @replace: the replacement value for the match
1498 * Add an entry in the XML catalog, it may overwrite existing but
1499 * different entries.
1501 * Returns 0 if successful, -1 otherwise
1504 xmlAddXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*type
,
1505 const xmlChar
*orig
, const xmlChar
*replace
) {
1506 xmlCatalogEntryPtr cur
;
1507 xmlCatalogEntryType typ
;
1510 if ((catal
== NULL
) ||
1511 ((catal
->type
!= XML_CATA_CATALOG
) &&
1512 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1514 if (catal
->children
== NULL
) {
1515 xmlFetchXMLCatalogFile(catal
);
1517 if (catal
->children
== NULL
)
1520 typ
= xmlGetXMLCatalogEntryType(type
);
1521 if (typ
== XML_CATA_NONE
) {
1522 if (xmlDebugCatalogs
)
1523 xmlGenericError(xmlGenericErrorContext
,
1524 "Failed to add unknown element %s to catalog\n", type
);
1528 cur
= catal
->children
;
1530 * Might be a simple "update in place"
1533 while (cur
!= NULL
) {
1534 if ((orig
!= NULL
) && (cur
->type
== typ
) &&
1535 (xmlStrEqual(orig
, cur
->name
))) {
1536 if (xmlDebugCatalogs
)
1537 xmlGenericError(xmlGenericErrorContext
,
1538 "Updating element %s to catalog\n", type
);
1539 if (cur
->value
!= NULL
)
1540 xmlFree(cur
->value
);
1541 if (cur
->URL
!= NULL
)
1543 cur
->value
= xmlStrdup(replace
);
1544 cur
->URL
= xmlStrdup(replace
);
1547 if (cur
->next
== NULL
)
1552 if (xmlDebugCatalogs
)
1553 xmlGenericError(xmlGenericErrorContext
,
1554 "Adding element %s to catalog\n", type
);
1556 catal
->children
= xmlNewCatalogEntry(typ
, orig
, replace
,
1557 NULL
, catal
->prefer
, NULL
);
1559 cur
->next
= xmlNewCatalogEntry(typ
, orig
, replace
,
1560 NULL
, catal
->prefer
, NULL
);
1562 catal
->type
= XML_CATA_CATALOG
;
1563 cur
= (xmlCatalogEntryPtr
)xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1565 cur
->children
= catal
->children
;
1573 * @catal: top of an XML catalog
1574 * @value: the value to remove from the catalog
1576 * Remove entries in the XML catalog where the value or the URI
1577 * is equal to @value
1579 * Returns the number of entries removed if successful, -1 otherwise
1582 xmlDelXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*value
) {
1583 xmlCatalogEntryPtr cur
;
1586 if ((catal
== NULL
) ||
1587 ((catal
->type
!= XML_CATA_CATALOG
) &&
1588 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1592 if (catal
->children
== NULL
) {
1593 xmlFetchXMLCatalogFile(catal
);
1599 cur
= catal
->children
;
1600 while (cur
!= NULL
) {
1601 if (((cur
->name
!= NULL
) && (xmlStrEqual(value
, cur
->name
))) ||
1602 (xmlStrEqual(value
, cur
->value
))) {
1603 if (xmlDebugCatalogs
) {
1604 if (cur
->name
!= NULL
)
1605 xmlGenericError(xmlGenericErrorContext
,
1606 "Removing element %s from catalog\n", cur
->name
);
1608 xmlGenericError(xmlGenericErrorContext
,
1609 "Removing element %s from catalog\n", cur
->value
);
1611 cur
->type
= XML_CATA_REMOVED
;
1619 * xmlCatalogXMLResolve:
1620 * @catal: a catalog list
1621 * @pubID: the public ID string
1622 * @sysID: the system ID string
1624 * Do a complete resolution lookup of an External Identifier for a
1625 * list of catalog entries.
1627 * Implements (or tries to) 7.1. External Identifier Resolution
1628 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1630 * Returns the URI of the resource or NULL if not found
1633 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1634 const xmlChar
*sysID
) {
1635 xmlChar
*ret
= NULL
;
1636 xmlCatalogEntryPtr cur
;
1637 int haveDelegate
= 0;
1641 * protection against loops
1643 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1644 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1645 "Detected recursion in catalog %s\n",
1646 catal
->name
, NULL
, NULL
);
1652 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1654 if (sysID
!= NULL
) {
1655 xmlCatalogEntryPtr rewrite
= NULL
;
1656 int lenrewrite
= 0, len
;
1659 while (cur
!= NULL
) {
1660 switch (cur
->type
) {
1661 case XML_CATA_SYSTEM
:
1662 if (xmlStrEqual(sysID
, cur
->name
)) {
1663 if (xmlDebugCatalogs
)
1664 xmlGenericError(xmlGenericErrorContext
,
1665 "Found system match %s, using %s\n",
1666 cur
->name
, cur
->URL
);
1668 return(xmlStrdup(cur
->URL
));
1671 case XML_CATA_REWRITE_SYSTEM
:
1672 len
= xmlStrlen(cur
->name
);
1673 if ((len
> lenrewrite
) &&
1674 (!xmlStrncmp(sysID
, cur
->name
, len
))) {
1679 case XML_CATA_DELEGATE_SYSTEM
:
1680 if (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))
1683 case XML_CATA_NEXT_CATALOG
:
1691 if (rewrite
!= NULL
) {
1692 if (xmlDebugCatalogs
)
1693 xmlGenericError(xmlGenericErrorContext
,
1694 "Using rewriting rule %s\n", rewrite
->name
);
1695 ret
= xmlStrdup(rewrite
->URL
);
1697 ret
= xmlStrcat(ret
, &sysID
[lenrewrite
]);
1702 const xmlChar
*delegates
[MAX_DELEGATE
];
1706 * Assume the entries have been sorted by decreasing substring
1707 * matches when the list was produced.
1710 while (cur
!= NULL
) {
1711 if ((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) &&
1712 (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1713 for (i
= 0;i
< nbList
;i
++)
1714 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1720 if (nbList
< MAX_DELEGATE
)
1721 delegates
[nbList
++] = cur
->URL
;
1723 if (cur
->children
== NULL
) {
1724 xmlFetchXMLCatalogFile(cur
);
1726 if (cur
->children
!= NULL
) {
1727 if (xmlDebugCatalogs
)
1728 xmlGenericError(xmlGenericErrorContext
,
1729 "Trying system delegate %s\n", cur
->URL
);
1730 ret
= xmlCatalogListXMLResolve(
1731 cur
->children
, NULL
, sysID
);
1741 * Apply the cut algorithm explained in 4/
1744 return(XML_CATAL_BREAK
);
1748 * Then tries 5/ 6/ if a public ID is provided
1750 if (pubID
!= NULL
) {
1753 while (cur
!= NULL
) {
1754 switch (cur
->type
) {
1755 case XML_CATA_PUBLIC
:
1756 if (xmlStrEqual(pubID
, cur
->name
)) {
1757 if (xmlDebugCatalogs
)
1758 xmlGenericError(xmlGenericErrorContext
,
1759 "Found public match %s\n", cur
->name
);
1761 return(xmlStrdup(cur
->URL
));
1764 case XML_CATA_DELEGATE_PUBLIC
:
1765 if (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)) &&
1766 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
))
1769 case XML_CATA_NEXT_CATALOG
:
1779 const xmlChar
*delegates
[MAX_DELEGATE
];
1783 * Assume the entries have been sorted by decreasing substring
1784 * matches when the list was produced.
1787 while (cur
!= NULL
) {
1788 if ((cur
->type
== XML_CATA_DELEGATE_PUBLIC
) &&
1789 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
) &&
1790 (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1792 for (i
= 0;i
< nbList
;i
++)
1793 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1799 if (nbList
< MAX_DELEGATE
)
1800 delegates
[nbList
++] = cur
->URL
;
1802 if (cur
->children
== NULL
) {
1803 xmlFetchXMLCatalogFile(cur
);
1805 if (cur
->children
!= NULL
) {
1806 if (xmlDebugCatalogs
)
1807 xmlGenericError(xmlGenericErrorContext
,
1808 "Trying public delegate %s\n", cur
->URL
);
1809 ret
= xmlCatalogListXMLResolve(
1810 cur
->children
, pubID
, NULL
);
1820 * Apply the cut algorithm explained in 4/
1823 return(XML_CATAL_BREAK
);
1828 while (cur
!= NULL
) {
1829 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1830 if (cur
->children
== NULL
) {
1831 xmlFetchXMLCatalogFile(cur
);
1833 if (cur
->children
!= NULL
) {
1834 ret
= xmlCatalogListXMLResolve(cur
->children
, pubID
, sysID
);
1838 } else if (catal
->depth
> MAX_CATAL_DEPTH
) {
1852 * xmlCatalogXMLResolveURI:
1853 * @catal: a catalog list
1855 * @sysID: the system ID string
1857 * Do a complete resolution lookup of an External Identifier for a
1858 * list of catalog entries.
1860 * Implements (or tries to) 7.2.2. URI Resolution
1861 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1863 * Returns the URI of the resource or NULL if not found
1866 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
1867 xmlChar
*ret
= NULL
;
1868 xmlCatalogEntryPtr cur
;
1869 int haveDelegate
= 0;
1871 xmlCatalogEntryPtr rewrite
= NULL
;
1872 int lenrewrite
= 0, len
;
1880 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1881 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1882 "Detected recursion in catalog %s\n",
1883 catal
->name
, NULL
, NULL
);
1888 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1892 while (cur
!= NULL
) {
1893 switch (cur
->type
) {
1895 if (xmlStrEqual(URI
, cur
->name
)) {
1896 if (xmlDebugCatalogs
)
1897 xmlGenericError(xmlGenericErrorContext
,
1898 "Found URI match %s\n", cur
->name
);
1899 return(xmlStrdup(cur
->URL
));
1902 case XML_CATA_REWRITE_URI
:
1903 len
= xmlStrlen(cur
->name
);
1904 if ((len
> lenrewrite
) &&
1905 (!xmlStrncmp(URI
, cur
->name
, len
))) {
1910 case XML_CATA_DELEGATE_URI
:
1911 if (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))
1914 case XML_CATA_NEXT_CATALOG
:
1922 if (rewrite
!= NULL
) {
1923 if (xmlDebugCatalogs
)
1924 xmlGenericError(xmlGenericErrorContext
,
1925 "Using rewriting rule %s\n", rewrite
->name
);
1926 ret
= xmlStrdup(rewrite
->URL
);
1928 ret
= xmlStrcat(ret
, &URI
[lenrewrite
]);
1932 const xmlChar
*delegates
[MAX_DELEGATE
];
1936 * Assume the entries have been sorted by decreasing substring
1937 * matches when the list was produced.
1940 while (cur
!= NULL
) {
1941 if (((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) ||
1942 (cur
->type
== XML_CATA_DELEGATE_URI
)) &&
1943 (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))) {
1944 for (i
= 0;i
< nbList
;i
++)
1945 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1951 if (nbList
< MAX_DELEGATE
)
1952 delegates
[nbList
++] = cur
->URL
;
1954 if (cur
->children
== NULL
) {
1955 xmlFetchXMLCatalogFile(cur
);
1957 if (cur
->children
!= NULL
) {
1958 if (xmlDebugCatalogs
)
1959 xmlGenericError(xmlGenericErrorContext
,
1960 "Trying URI delegate %s\n", cur
->URL
);
1961 ret
= xmlCatalogListXMLResolveURI(
1962 cur
->children
, URI
);
1970 * Apply the cut algorithm explained in 4/
1972 return(XML_CATAL_BREAK
);
1976 while (cur
!= NULL
) {
1977 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1978 if (cur
->children
== NULL
) {
1979 xmlFetchXMLCatalogFile(cur
);
1981 if (cur
->children
!= NULL
) {
1982 ret
= xmlCatalogListXMLResolveURI(cur
->children
, URI
);
1995 * xmlCatalogListXMLResolve:
1996 * @catal: a catalog list
1997 * @pubID: the public ID string
1998 * @sysID: the system ID string
2000 * Do a complete resolution lookup of an External Identifier for a
2003 * Implements (or tries to) 7.1. External Identifier Resolution
2004 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2006 * Returns the URI of the resource or NULL if not found
2009 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
2010 const xmlChar
*sysID
) {
2011 xmlChar
*ret
= NULL
;
2012 xmlChar
*urnID
= NULL
;
2017 if ((pubID
== NULL
) && (sysID
== NULL
))
2020 normid
= xmlCatalogNormalizePublic(pubID
);
2022 pubID
= (*normid
!= 0 ? normid
: NULL
);
2024 if (!xmlStrncmp(pubID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2025 urnID
= xmlCatalogUnWrapURN(pubID
);
2026 if (xmlDebugCatalogs
) {
2028 xmlGenericError(xmlGenericErrorContext
,
2029 "Public URN ID %s expanded to NULL\n", pubID
);
2031 xmlGenericError(xmlGenericErrorContext
,
2032 "Public URN ID expanded to %s\n", urnID
);
2034 ret
= xmlCatalogListXMLResolve(catal
, urnID
, sysID
);
2041 if (!xmlStrncmp(sysID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2042 urnID
= xmlCatalogUnWrapURN(sysID
);
2043 if (xmlDebugCatalogs
) {
2045 xmlGenericError(xmlGenericErrorContext
,
2046 "System URN ID %s expanded to NULL\n", sysID
);
2048 xmlGenericError(xmlGenericErrorContext
,
2049 "System URN ID expanded to %s\n", urnID
);
2052 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2053 else if (xmlStrEqual(pubID
, urnID
))
2054 ret
= xmlCatalogListXMLResolve(catal
, pubID
, NULL
);
2056 ret
= xmlCatalogListXMLResolve(catal
, pubID
, urnID
);
2064 while (catal
!= NULL
) {
2065 if (catal
->type
== XML_CATA_CATALOG
) {
2066 if (catal
->children
== NULL
) {
2067 xmlFetchXMLCatalogFile(catal
);
2069 if (catal
->children
!= NULL
) {
2070 ret
= xmlCatalogXMLResolve(catal
->children
, pubID
, sysID
);
2073 } else if (catal
->children
->depth
> MAX_CATAL_DEPTH
) {
2079 catal
= catal
->next
;
2087 * xmlCatalogListXMLResolveURI:
2088 * @catal: a catalog list
2091 * Do a complete resolution lookup of an URI for a list of catalogs
2093 * Implements (or tries to) 7.2. URI Resolution
2094 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2096 * Returns the URI of the resource or NULL if not found
2099 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
2100 xmlChar
*ret
= NULL
;
2101 xmlChar
*urnID
= NULL
;
2108 if (!xmlStrncmp(URI
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2109 urnID
= xmlCatalogUnWrapURN(URI
);
2110 if (xmlDebugCatalogs
) {
2112 xmlGenericError(xmlGenericErrorContext
,
2113 "URN ID %s expanded to NULL\n", URI
);
2115 xmlGenericError(xmlGenericErrorContext
,
2116 "URN ID expanded to %s\n", urnID
);
2118 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2123 while (catal
!= NULL
) {
2124 if (catal
->type
== XML_CATA_CATALOG
) {
2125 if (catal
->children
== NULL
) {
2126 xmlFetchXMLCatalogFile(catal
);
2128 if (catal
->children
!= NULL
) {
2129 ret
= xmlCatalogXMLResolveURI(catal
->children
, URI
);
2134 catal
= catal
->next
;
2139 /************************************************************************
2141 * The SGML Catalog parser *
2143 ************************************************************************/
2148 #define SKIP(x) cur += x;
2150 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2153 * xmlParseSGMLCatalogComment:
2154 * @cur: the current character
2156 * Skip a comment in an SGML catalog
2158 * Returns new current character
2160 static const xmlChar
*
2161 xmlParseSGMLCatalogComment(const xmlChar
*cur
) {
2162 if ((cur
[0] != '-') || (cur
[1] != '-'))
2165 while ((cur
[0] != 0) && ((cur
[0] != '-') || ((cur
[1] != '-'))))
2174 * xmlParseSGMLCatalogPubid:
2175 * @cur: the current character
2176 * @id: the return location
2178 * Parse an SGML catalog ID
2180 * Returns new current character and store the value in @id
2182 static const xmlChar
*
2183 xmlParseSGMLCatalogPubid(const xmlChar
*cur
, xmlChar
**id
) {
2184 xmlChar
*buf
= NULL
, *tmp
;
2195 } else if (RAW
== '\'') {
2201 buf
= (xmlChar
*) xmlMallocAtomic(size
* sizeof(xmlChar
));
2203 xmlCatalogErrMemory("allocating public ID");
2206 while (IS_PUBIDCHAR_CH(*cur
) || (*cur
== '?')) {
2207 if ((*cur
== stop
) && (stop
!= ' '))
2209 if ((stop
== ' ') && (IS_BLANK_CH(*cur
)))
2211 if (len
+ 1 >= size
) {
2213 tmp
= (xmlChar
*) xmlRealloc(buf
, size
* sizeof(xmlChar
));
2215 xmlCatalogErrMemory("allocating public ID");
2227 if (!IS_BLANK_CH(*cur
)) {
2243 * xmlParseSGMLCatalogName:
2244 * @cur: the current character
2245 * @name: the return location
2247 * Parse an SGML catalog name
2249 * Returns new current character and store the value in @name
2251 static const xmlChar
*
2252 xmlParseSGMLCatalogName(const xmlChar
*cur
, xmlChar
**name
) {
2253 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
2260 * Handler for more complex cases
2263 if ((!IS_LETTER(c
) && (c
!= '_') && (c
!= ':'))) {
2267 while (((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
2268 (c
== '.') || (c
== '-') ||
2269 (c
== '_') || (c
== ':'))) {
2273 if (len
>= XML_MAX_NAMELEN
)
2276 *name
= xmlStrndup(buf
, len
);
2281 * xmlGetSGMLCatalogEntryType:
2282 * @name: the entry name
2284 * Get the Catalog entry type for a given SGML Catalog name
2286 * Returns Catalog entry type
2288 static xmlCatalogEntryType
2289 xmlGetSGMLCatalogEntryType(const xmlChar
*name
) {
2290 xmlCatalogEntryType type
= XML_CATA_NONE
;
2291 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2292 type
= SGML_CATA_SYSTEM
;
2293 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2294 type
= SGML_CATA_PUBLIC
;
2295 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2296 type
= SGML_CATA_DELEGATE
;
2297 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2298 type
= SGML_CATA_ENTITY
;
2299 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2300 type
= SGML_CATA_DOCTYPE
;
2301 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2302 type
= SGML_CATA_LINKTYPE
;
2303 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2304 type
= SGML_CATA_NOTATION
;
2305 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2306 type
= SGML_CATA_SGMLDECL
;
2307 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2308 type
= SGML_CATA_DOCUMENT
;
2309 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2310 type
= SGML_CATA_CATALOG
;
2311 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2312 type
= SGML_CATA_BASE
;
2317 * xmlParseSGMLCatalog:
2318 * @catal: the SGML Catalog
2319 * @value: the content of the SGML Catalog serialization
2320 * @file: the filepath for the catalog
2321 * @super: should this be handled as a Super Catalog in which case
2322 * parsing is not recursive
2324 * Parse an SGML catalog content and fill up the @catal hash table with
2325 * the new entries found.
2327 * Returns 0 in case of success, -1 in case of error.
2330 xmlParseSGMLCatalog(xmlCatalogPtr catal
, const xmlChar
*value
,
2331 const char *file
, int super
) {
2332 const xmlChar
*cur
= value
;
2333 xmlChar
*base
= NULL
;
2336 if ((cur
== NULL
) || (file
== NULL
))
2338 base
= xmlStrdup((const xmlChar
*) file
);
2340 while ((cur
!= NULL
) && (cur
[0] != 0)) {
2344 if ((cur
[0] == '-') && (cur
[1] == '-')) {
2345 cur
= xmlParseSGMLCatalogComment(cur
);
2351 xmlChar
*sysid
= NULL
;
2352 xmlChar
*name
= NULL
;
2353 xmlCatalogEntryType type
= XML_CATA_NONE
;
2355 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2356 if (cur
== NULL
|| name
== NULL
) {
2360 if (!IS_BLANK_CH(*cur
)) {
2366 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2367 type
= SGML_CATA_SYSTEM
;
2368 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2369 type
= SGML_CATA_PUBLIC
;
2370 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2371 type
= SGML_CATA_DELEGATE
;
2372 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2373 type
= SGML_CATA_ENTITY
;
2374 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2375 type
= SGML_CATA_DOCTYPE
;
2376 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2377 type
= SGML_CATA_LINKTYPE
;
2378 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2379 type
= SGML_CATA_NOTATION
;
2380 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2381 type
= SGML_CATA_SGMLDECL
;
2382 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2383 type
= SGML_CATA_DOCUMENT
;
2384 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2385 type
= SGML_CATA_CATALOG
;
2386 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2387 type
= SGML_CATA_BASE
;
2388 else if (xmlStrEqual(name
, (const xmlChar
*) "OVERRIDE")) {
2390 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2402 case SGML_CATA_ENTITY
:
2404 type
= SGML_CATA_PENTITY
;
2405 /* Falls through. */
2406 case SGML_CATA_PENTITY
:
2407 case SGML_CATA_DOCTYPE
:
2408 case SGML_CATA_LINKTYPE
:
2409 case SGML_CATA_NOTATION
:
2410 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2415 if (!IS_BLANK_CH(*cur
)) {
2420 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2426 case SGML_CATA_PUBLIC
:
2427 case SGML_CATA_SYSTEM
:
2428 case SGML_CATA_DELEGATE
:
2429 cur
= xmlParseSGMLCatalogPubid(cur
, &name
);
2434 if (type
!= SGML_CATA_SYSTEM
) {
2437 normid
= xmlCatalogNormalizePublic(name
);
2438 if (normid
!= NULL
) {
2449 if (!IS_BLANK_CH(*cur
)) {
2454 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2460 case SGML_CATA_BASE
:
2461 case SGML_CATA_CATALOG
:
2462 case SGML_CATA_DOCUMENT
:
2463 case SGML_CATA_SGMLDECL
:
2464 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2479 } else if (type
== SGML_CATA_BASE
) {
2482 base
= xmlStrdup(sysid
);
2483 } else if ((type
== SGML_CATA_PUBLIC
) ||
2484 (type
== SGML_CATA_SYSTEM
)) {
2487 filename
= xmlBuildURI(sysid
, base
);
2488 if (filename
!= NULL
) {
2489 xmlCatalogEntryPtr entry
;
2491 entry
= xmlNewCatalogEntry(type
, name
, filename
,
2492 NULL
, XML_CATA_PREFER_NONE
, NULL
);
2493 res
= xmlHashAddEntry(catal
->sgml
, name
, entry
);
2495 xmlFreeCatalogEntry(entry
, NULL
);
2500 } else if (type
== SGML_CATA_CATALOG
) {
2502 xmlCatalogEntryPtr entry
;
2504 entry
= xmlNewCatalogEntry(type
, sysid
, NULL
, NULL
,
2505 XML_CATA_PREFER_NONE
, NULL
);
2506 res
= xmlHashAddEntry(catal
->sgml
, sysid
, entry
);
2508 xmlFreeCatalogEntry(entry
, NULL
);
2513 filename
= xmlBuildURI(sysid
, base
);
2514 if (filename
!= NULL
) {
2515 xmlExpandCatalog(catal
, (const char *)filename
);
2521 * drop anything else we won't handle it
2536 /************************************************************************
2538 * SGML Catalog handling *
2540 ************************************************************************/
2543 * xmlCatalogGetSGMLPublic:
2544 * @catal: an SGML catalog hash
2545 * @pubID: the public ID string
2547 * Try to lookup the catalog local reference associated to a public ID
2549 * Returns the local resource if found or NULL otherwise.
2551 static const xmlChar
*
2552 xmlCatalogGetSGMLPublic(xmlHashTablePtr catal
, const xmlChar
*pubID
) {
2553 xmlCatalogEntryPtr entry
;
2559 normid
= xmlCatalogNormalizePublic(pubID
);
2561 pubID
= (*normid
!= 0 ? normid
: NULL
);
2563 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, pubID
);
2564 if (entry
== NULL
) {
2569 if (entry
->type
== SGML_CATA_PUBLIC
) {
2580 * xmlCatalogGetSGMLSystem:
2581 * @catal: an SGML catalog hash
2582 * @sysID: the system ID string
2584 * Try to lookup the catalog local reference for a system ID
2586 * Returns the local resource if found or NULL otherwise.
2588 static const xmlChar
*
2589 xmlCatalogGetSGMLSystem(xmlHashTablePtr catal
, const xmlChar
*sysID
) {
2590 xmlCatalogEntryPtr entry
;
2595 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, sysID
);
2598 if (entry
->type
== SGML_CATA_SYSTEM
)
2604 * xmlCatalogSGMLResolve:
2605 * @catal: the SGML catalog
2606 * @pubID: the public ID string
2607 * @sysID: the system ID string
2609 * Do a complete resolution lookup of an External Identifier
2611 * Returns the URI of the resource or NULL if not found
2613 static const xmlChar
*
2614 xmlCatalogSGMLResolve(xmlCatalogPtr catal
, const xmlChar
*pubID
,
2615 const xmlChar
*sysID
) {
2616 const xmlChar
*ret
= NULL
;
2618 if (catal
->sgml
== NULL
)
2622 ret
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2626 ret
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2632 /************************************************************************
2634 * Specific Public interfaces *
2636 ************************************************************************/
2639 * xmlLoadSGMLSuperCatalog:
2640 * @filename: a file path
2642 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2643 * references. This is only needed for manipulating SGML Super Catalogs
2644 * like adding and removing CATALOG or DELEGATE entries.
2646 * Returns the catalog parsed or NULL in case of error
2649 xmlLoadSGMLSuperCatalog(const char *filename
)
2652 xmlCatalogPtr catal
;
2655 content
= xmlLoadFileContent(filename
);
2656 if (content
== NULL
)
2659 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2660 if (catal
== NULL
) {
2665 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 1);
2668 xmlFreeCatalog(catal
);
2676 * @filename: a file path
2678 * Load the catalog and build the associated data structures.
2679 * This can be either an XML Catalog or an SGML Catalog
2680 * It will recurse in SGML CATALOG entries. On the other hand XML
2681 * Catalogs are not handled recursively.
2683 * Returns the catalog parsed or NULL in case of error
2686 xmlLoadACatalog(const char *filename
)
2690 xmlCatalogPtr catal
;
2693 content
= xmlLoadFileContent(filename
);
2694 if (content
== NULL
)
2700 while ((*first
!= 0) && (*first
!= '-') && (*first
!= '<') &&
2701 (!(((*first
>= 'A') && (*first
<= 'Z')) ||
2702 ((*first
>= 'a') && (*first
<= 'z')))))
2705 if (*first
!= '<') {
2706 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2707 if (catal
== NULL
) {
2711 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2713 xmlFreeCatalog(catal
);
2718 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2719 if (catal
== NULL
) {
2723 catal
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2724 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2733 * @filename: a file path
2735 * Load the catalog and expand the existing catal structure.
2736 * This can be either an XML Catalog or an SGML Catalog
2738 * Returns 0 in case of success, -1 in case of error
2741 xmlExpandCatalog(xmlCatalogPtr catal
, const char *filename
)
2745 if ((catal
== NULL
) || (filename
== NULL
))
2749 if (catal
->type
== XML_SGML_CATALOG_TYPE
) {
2752 content
= xmlLoadFileContent(filename
);
2753 if (content
== NULL
)
2756 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2763 xmlCatalogEntryPtr tmp
, cur
;
2764 tmp
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2765 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2771 while (cur
->next
!= NULL
) cur
= cur
->next
;
2779 * xmlACatalogResolveSystem:
2781 * @sysID: the system ID string
2783 * Try to lookup the catalog resource for a system ID
2785 * Returns the resource if found or NULL otherwise, the value returned
2786 * must be freed by the caller.
2789 xmlACatalogResolveSystem(xmlCatalogPtr catal
, const xmlChar
*sysID
) {
2790 xmlChar
*ret
= NULL
;
2792 if ((sysID
== NULL
) || (catal
== NULL
))
2795 if (xmlDebugCatalogs
)
2796 xmlGenericError(xmlGenericErrorContext
,
2797 "Resolve sysID %s\n", sysID
);
2799 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2800 ret
= xmlCatalogListXMLResolve(catal
->xml
, NULL
, sysID
);
2801 if (ret
== XML_CATAL_BREAK
)
2804 const xmlChar
*sgml
;
2806 sgml
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2808 ret
= xmlStrdup(sgml
);
2814 * xmlACatalogResolvePublic:
2816 * @pubID: the public ID string
2818 * Try to lookup the catalog local reference associated to a public ID in that catalog
2820 * Returns the local resource if found or NULL otherwise, the value returned
2821 * must be freed by the caller.
2824 xmlACatalogResolvePublic(xmlCatalogPtr catal
, const xmlChar
*pubID
) {
2825 xmlChar
*ret
= NULL
;
2827 if ((pubID
== NULL
) || (catal
== NULL
))
2830 if (xmlDebugCatalogs
)
2831 xmlGenericError(xmlGenericErrorContext
,
2832 "Resolve pubID %s\n", pubID
);
2834 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2835 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, NULL
);
2836 if (ret
== XML_CATAL_BREAK
)
2839 const xmlChar
*sgml
;
2841 sgml
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2843 ret
= xmlStrdup(sgml
);
2849 * xmlACatalogResolve:
2851 * @pubID: the public ID string
2852 * @sysID: the system ID string
2854 * Do a complete resolution lookup of an External Identifier
2856 * Returns the URI of the resource or NULL if not found, it must be freed
2860 xmlACatalogResolve(xmlCatalogPtr catal
, const xmlChar
* pubID
,
2861 const xmlChar
* sysID
)
2863 xmlChar
*ret
= NULL
;
2865 if (((pubID
== NULL
) && (sysID
== NULL
)) || (catal
== NULL
))
2868 if (xmlDebugCatalogs
) {
2869 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
2870 xmlGenericError(xmlGenericErrorContext
,
2871 "Resolve: pubID %s sysID %s\n", pubID
, sysID
);
2872 } else if (pubID
!= NULL
) {
2873 xmlGenericError(xmlGenericErrorContext
,
2874 "Resolve: pubID %s\n", pubID
);
2876 xmlGenericError(xmlGenericErrorContext
,
2877 "Resolve: sysID %s\n", sysID
);
2881 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2882 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, sysID
);
2883 if (ret
== XML_CATAL_BREAK
)
2886 const xmlChar
*sgml
;
2888 sgml
= xmlCatalogSGMLResolve(catal
, pubID
, sysID
);
2890 ret
= xmlStrdup(sgml
);
2896 * xmlACatalogResolveURI:
2900 * Do a complete resolution lookup of an URI
2902 * Returns the URI of the resource or NULL if not found, it must be freed
2906 xmlACatalogResolveURI(xmlCatalogPtr catal
, const xmlChar
*URI
) {
2907 xmlChar
*ret
= NULL
;
2909 if ((URI
== NULL
) || (catal
== NULL
))
2912 if (xmlDebugCatalogs
)
2913 xmlGenericError(xmlGenericErrorContext
,
2914 "Resolve URI %s\n", URI
);
2916 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2917 ret
= xmlCatalogListXMLResolveURI(catal
->xml
, URI
);
2918 if (ret
== XML_CATAL_BREAK
)
2921 const xmlChar
*sgml
;
2923 sgml
= xmlCatalogSGMLResolve(catal
, NULL
, URI
);
2925 ret
= xmlStrdup(sgml
);
2930 #ifdef LIBXML_OUTPUT_ENABLED
2936 * Dump the given catalog to the given file.
2939 xmlACatalogDump(xmlCatalogPtr catal
, FILE *out
) {
2940 if ((out
== NULL
) || (catal
== NULL
))
2943 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2944 xmlDumpXMLCatalog(out
, catal
->xml
);
2946 xmlHashScan(catal
->sgml
, xmlCatalogDumpEntry
, out
);
2949 #endif /* LIBXML_OUTPUT_ENABLED */
2954 * @type: the type of record to add to the catalog
2955 * @orig: the system, public or prefix to match
2956 * @replace: the replacement value for the match
2958 * Add an entry in the catalog, it may overwrite existing but
2959 * different entries.
2961 * Returns 0 if successful, -1 otherwise
2964 xmlACatalogAdd(xmlCatalogPtr catal
, const xmlChar
* type
,
2965 const xmlChar
* orig
, const xmlChar
* replace
)
2972 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2973 res
= xmlAddXMLCatalog(catal
->xml
, type
, orig
, replace
);
2975 xmlCatalogEntryType cattype
;
2977 cattype
= xmlGetSGMLCatalogEntryType(type
);
2978 if (cattype
!= XML_CATA_NONE
) {
2979 xmlCatalogEntryPtr entry
;
2981 entry
= xmlNewCatalogEntry(cattype
, orig
, replace
, NULL
,
2982 XML_CATA_PREFER_NONE
, NULL
);
2983 if (catal
->sgml
== NULL
)
2984 catal
->sgml
= xmlHashCreate(10);
2985 res
= xmlHashAddEntry(catal
->sgml
, orig
, entry
);
2992 * xmlACatalogRemove:
2994 * @value: the value to remove
2996 * Remove an entry from the catalog
2998 * Returns the number of entries removed if successful, -1 otherwise
3001 xmlACatalogRemove(xmlCatalogPtr catal
, const xmlChar
*value
) {
3004 if ((catal
== NULL
) || (value
== NULL
))
3007 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
3008 res
= xmlDelXMLCatalog(catal
->xml
, value
);
3010 res
= xmlHashRemoveEntry(catal
->sgml
, value
, xmlFreeCatalogEntry
);
3019 * @sgml: should this create an SGML catalog
3021 * create a new Catalog.
3023 * Returns the xmlCatalogPtr or NULL in case of error
3026 xmlNewCatalog(int sgml
) {
3027 xmlCatalogPtr catal
= NULL
;
3030 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
,
3031 xmlCatalogDefaultPrefer
);
3032 if ((catal
!= NULL
) && (catal
->sgml
== NULL
))
3033 catal
->sgml
= xmlHashCreate(10);
3035 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3036 xmlCatalogDefaultPrefer
);
3041 * xmlCatalogIsEmpty:
3042 * @catal: should this create an SGML catalog
3044 * Check is a catalog is empty
3046 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3049 xmlCatalogIsEmpty(xmlCatalogPtr catal
) {
3053 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
3054 if (catal
->xml
== NULL
)
3056 if ((catal
->xml
->type
!= XML_CATA_CATALOG
) &&
3057 (catal
->xml
->type
!= XML_CATA_BROKEN_CATALOG
))
3059 if (catal
->xml
->children
== NULL
)
3065 if (catal
->sgml
== NULL
)
3067 res
= xmlHashSize(catal
->sgml
);
3076 /************************************************************************
3078 * Public interfaces manipulating the global shared default catalog *
3080 ************************************************************************/
3083 * xmlInitializeCatalogData:
3085 * Do the catalog initialization only of global data, doesn't try to load
3086 * any catalog actually.
3087 * this function is not thread safe, catalog initialization should
3088 * preferably be done once at startup
3091 xmlInitializeCatalogData(void) {
3092 if (xmlCatalogInitialized
!= 0)
3095 if (getenv("XML_DEBUG_CATALOG"))
3096 xmlDebugCatalogs
= 1;
3097 xmlCatalogMutex
= xmlNewRMutex();
3099 xmlCatalogInitialized
= 1;
3102 * xmlInitializeCatalog:
3104 * Do the catalog initialization.
3105 * this function is not thread safe, catalog initialization should
3106 * preferably be done once at startup
3109 xmlInitializeCatalog(void) {
3110 if (xmlCatalogInitialized
!= 0)
3113 xmlInitializeCatalogData();
3114 xmlRMutexLock(xmlCatalogMutex
);
3116 if (getenv("XML_DEBUG_CATALOG"))
3117 xmlDebugCatalogs
= 1;
3119 if (xmlDefaultCatalog
== NULL
) {
3120 const char *catalogs
;
3122 const char *cur
, *paths
;
3123 xmlCatalogPtr catal
;
3124 xmlCatalogEntryPtr
*nextent
;
3126 catalogs
= (const char *) getenv("XML_CATALOG_FILES");
3127 if (catalogs
== NULL
)
3128 #if defined(_WIN32) && defined(_MSC_VER)
3131 hmodule
= GetModuleHandleA("libxml2.dll");
3132 if (hmodule
== NULL
)
3133 hmodule
= GetModuleHandleA(NULL
);
3134 if (hmodule
!= NULL
) {
3136 unsigned long len
= GetModuleFileNameA(hmodule
, buf
, 255);
3138 char* p
= &(buf
[len
]);
3139 while (*p
!= '\\' && p
> buf
)
3143 strncpy(p
, "\\..\\etc\\catalog", 255 - (p
- buf
));
3144 uri
= xmlCanonicPath((const xmlChar
*)buf
);
3146 strncpy(XML_XML_DEFAULT_CATALOG
, uri
, 255);
3152 catalogs
= XML_XML_DEFAULT_CATALOG
;
3155 catalogs
= XML_XML_DEFAULT_CATALOG
;
3158 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3159 xmlCatalogDefaultPrefer
);
3160 if (catal
!= NULL
) {
3161 /* the XML_CATALOG_FILES envvar is allowed to contain a
3162 space-separated list of entries. */
3164 nextent
= &catal
->xml
;
3165 while (*cur
!= '\0') {
3166 while (xmlIsBlank_ch(*cur
))
3170 while ((*cur
!= 0) && (!xmlIsBlank_ch(*cur
)))
3172 path
= (char *) xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3174 *nextent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3175 NULL
, BAD_CAST path
, xmlCatalogDefaultPrefer
, NULL
);
3176 if (*nextent
!= NULL
)
3177 nextent
= &((*nextent
)->next
);
3182 xmlDefaultCatalog
= catal
;
3186 xmlRMutexUnlock(xmlCatalogMutex
);
3192 * @filename: a file path
3194 * Load the catalog and makes its definitions effective for the default
3195 * external entity loader. It will recurse in SGML CATALOG entries.
3196 * this function is not thread safe, catalog initialization should
3197 * preferably be done once at startup
3199 * Returns 0 in case of success -1 in case of error
3202 xmlLoadCatalog(const char *filename
)
3205 xmlCatalogPtr catal
;
3207 if (!xmlCatalogInitialized
)
3208 xmlInitializeCatalogData();
3210 xmlRMutexLock(xmlCatalogMutex
);
3212 if (xmlDefaultCatalog
== NULL
) {
3213 catal
= xmlLoadACatalog(filename
);
3214 if (catal
== NULL
) {
3215 xmlRMutexUnlock(xmlCatalogMutex
);
3219 xmlDefaultCatalog
= catal
;
3220 xmlRMutexUnlock(xmlCatalogMutex
);
3224 ret
= xmlExpandCatalog(xmlDefaultCatalog
, filename
);
3225 xmlRMutexUnlock(xmlCatalogMutex
);
3231 * @pathss: a list of directories separated by a colon or a space.
3233 * Load the catalogs and makes their definitions effective for the default
3234 * external entity loader.
3235 * this function is not thread safe, catalog initialization should
3236 * preferably be done once at startup
3239 xmlLoadCatalogs(const char *pathss
) {
3252 while (xmlIsBlank_ch(*cur
)) cur
++;
3255 while ((*cur
!= 0) && (*cur
!= PATH_SEPARATOR
) && (!xmlIsBlank_ch(*cur
)))
3257 path
= xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3260 iLen
= strlen((const char*)path
);
3261 for(i
= 0; i
< iLen
; i
++) {
3262 if(path
[i
] == '\\') {
3267 xmlLoadCatalog((const char *) path
);
3271 while (*cur
== PATH_SEPARATOR
)
3277 * xmlCatalogCleanup:
3279 * Free up all the memory associated with catalogs
3282 xmlCatalogCleanup(void) {
3283 if (xmlCatalogInitialized
== 0)
3286 xmlRMutexLock(xmlCatalogMutex
);
3287 if (xmlDebugCatalogs
)
3288 xmlGenericError(xmlGenericErrorContext
,
3289 "Catalogs cleanup\n");
3290 if (xmlCatalogXMLFiles
!= NULL
)
3291 xmlHashFree(xmlCatalogXMLFiles
, xmlFreeCatalogHashEntryList
);
3292 xmlCatalogXMLFiles
= NULL
;
3293 if (xmlDefaultCatalog
!= NULL
)
3294 xmlFreeCatalog(xmlDefaultCatalog
);
3295 xmlDefaultCatalog
= NULL
;
3296 xmlDebugCatalogs
= 0;
3297 xmlCatalogInitialized
= 0;
3298 xmlRMutexUnlock(xmlCatalogMutex
);
3299 xmlFreeRMutex(xmlCatalogMutex
);
3303 * xmlCatalogResolveSystem:
3304 * @sysID: the system ID string
3306 * Try to lookup the catalog resource for a system ID
3308 * Returns the resource if found or NULL otherwise, the value returned
3309 * must be freed by the caller.
3312 xmlCatalogResolveSystem(const xmlChar
*sysID
) {
3315 if (!xmlCatalogInitialized
)
3316 xmlInitializeCatalog();
3318 ret
= xmlACatalogResolveSystem(xmlDefaultCatalog
, sysID
);
3323 * xmlCatalogResolvePublic:
3324 * @pubID: the public ID string
3326 * Try to lookup the catalog reference associated to a public ID
3328 * Returns the resource if found or NULL otherwise, the value returned
3329 * must be freed by the caller.
3332 xmlCatalogResolvePublic(const xmlChar
*pubID
) {
3335 if (!xmlCatalogInitialized
)
3336 xmlInitializeCatalog();
3338 ret
= xmlACatalogResolvePublic(xmlDefaultCatalog
, pubID
);
3343 * xmlCatalogResolve:
3344 * @pubID: the public ID string
3345 * @sysID: the system ID string
3347 * Do a complete resolution lookup of an External Identifier
3349 * Returns the URI of the resource or NULL if not found, it must be freed
3353 xmlCatalogResolve(const xmlChar
*pubID
, const xmlChar
*sysID
) {
3356 if (!xmlCatalogInitialized
)
3357 xmlInitializeCatalog();
3359 ret
= xmlACatalogResolve(xmlDefaultCatalog
, pubID
, sysID
);
3364 * xmlCatalogResolveURI:
3367 * Do a complete resolution lookup of an URI
3369 * Returns the URI of the resource or NULL if not found, it must be freed
3373 xmlCatalogResolveURI(const xmlChar
*URI
) {
3376 if (!xmlCatalogInitialized
)
3377 xmlInitializeCatalog();
3379 ret
= xmlACatalogResolveURI(xmlDefaultCatalog
, URI
);
3383 #ifdef LIBXML_OUTPUT_ENABLED
3388 * Dump all the global catalog content to the given file.
3391 xmlCatalogDump(FILE *out
) {
3395 if (!xmlCatalogInitialized
)
3396 xmlInitializeCatalog();
3398 xmlACatalogDump(xmlDefaultCatalog
, out
);
3400 #endif /* LIBXML_OUTPUT_ENABLED */
3404 * @type: the type of record to add to the catalog
3405 * @orig: the system, public or prefix to match
3406 * @replace: the replacement value for the match
3408 * Add an entry in the catalog, it may overwrite existing but
3409 * different entries.
3410 * If called before any other catalog routine, allows to override the
3411 * default shared catalog put in place by xmlInitializeCatalog();
3413 * Returns 0 if successful, -1 otherwise
3416 xmlCatalogAdd(const xmlChar
*type
, const xmlChar
*orig
, const xmlChar
*replace
) {
3419 if (!xmlCatalogInitialized
)
3420 xmlInitializeCatalogData();
3422 xmlRMutexLock(xmlCatalogMutex
);
3424 * Specific case where one want to override the default catalog
3425 * put in place by xmlInitializeCatalog();
3427 if ((xmlDefaultCatalog
== NULL
) &&
3428 (xmlStrEqual(type
, BAD_CAST
"catalog"))) {
3429 xmlDefaultCatalog
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3430 xmlCatalogDefaultPrefer
);
3431 if (xmlDefaultCatalog
!= NULL
) {
3432 xmlDefaultCatalog
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3433 orig
, NULL
, xmlCatalogDefaultPrefer
, NULL
);
3435 xmlRMutexUnlock(xmlCatalogMutex
);
3439 res
= xmlACatalogAdd(xmlDefaultCatalog
, type
, orig
, replace
);
3440 xmlRMutexUnlock(xmlCatalogMutex
);
3446 * @value: the value to remove
3448 * Remove an entry from the catalog
3450 * Returns the number of entries removed if successful, -1 otherwise
3453 xmlCatalogRemove(const xmlChar
*value
) {
3456 if (!xmlCatalogInitialized
)
3457 xmlInitializeCatalog();
3459 xmlRMutexLock(xmlCatalogMutex
);
3460 res
= xmlACatalogRemove(xmlDefaultCatalog
, value
);
3461 xmlRMutexUnlock(xmlCatalogMutex
);
3466 * xmlCatalogConvert:
3468 * Convert all the SGML catalog entries as XML ones
3470 * Returns the number of entries converted if successful, -1 otherwise
3473 xmlCatalogConvert(void) {
3476 if (!xmlCatalogInitialized
)
3477 xmlInitializeCatalog();
3479 xmlRMutexLock(xmlCatalogMutex
);
3480 res
= xmlConvertSGMLCatalog(xmlDefaultCatalog
);
3481 xmlRMutexUnlock(xmlCatalogMutex
);
3485 /************************************************************************
3487 * Public interface manipulating the common preferences *
3489 ************************************************************************/
3492 * xmlCatalogGetDefaults:
3494 * Used to get the user preference w.r.t. to what catalogs should
3497 * Returns the current xmlCatalogAllow value
3500 xmlCatalogGetDefaults(void) {
3501 return(xmlCatalogDefaultAllow
);
3505 * xmlCatalogSetDefaults:
3506 * @allow: what catalogs should be accepted
3508 * Used to set the user preference w.r.t. to what catalogs should
3512 xmlCatalogSetDefaults(xmlCatalogAllow allow
) {
3513 if (xmlDebugCatalogs
) {
3515 case XML_CATA_ALLOW_NONE
:
3516 xmlGenericError(xmlGenericErrorContext
,
3517 "Disabling catalog usage\n");
3519 case XML_CATA_ALLOW_GLOBAL
:
3520 xmlGenericError(xmlGenericErrorContext
,
3521 "Allowing only global catalogs\n");
3523 case XML_CATA_ALLOW_DOCUMENT
:
3524 xmlGenericError(xmlGenericErrorContext
,
3525 "Allowing only catalogs from the document\n");
3527 case XML_CATA_ALLOW_ALL
:
3528 xmlGenericError(xmlGenericErrorContext
,
3529 "Allowing all catalogs\n");
3533 xmlCatalogDefaultAllow
= allow
;
3537 * xmlCatalogSetDefaultPrefer:
3538 * @prefer: the default preference for delegation
3540 * Allows to set the preference between public and system for deletion
3541 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3542 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3544 * Returns the previous value of the default preference for delegation
3547 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer
) {
3548 xmlCatalogPrefer ret
= xmlCatalogDefaultPrefer
;
3550 if (prefer
== XML_CATA_PREFER_NONE
)
3553 if (xmlDebugCatalogs
) {
3555 case XML_CATA_PREFER_PUBLIC
:
3556 xmlGenericError(xmlGenericErrorContext
,
3557 "Setting catalog preference to PUBLIC\n");
3559 case XML_CATA_PREFER_SYSTEM
:
3560 xmlGenericError(xmlGenericErrorContext
,
3561 "Setting catalog preference to SYSTEM\n");
3567 xmlCatalogDefaultPrefer
= prefer
;
3572 * xmlCatalogSetDebug:
3573 * @level: the debug level of catalogs required
3575 * Used to set the debug level for catalog operation, 0 disable
3576 * debugging, 1 enable it
3578 * Returns the previous value of the catalog debugging level
3581 xmlCatalogSetDebug(int level
) {
3582 int ret
= xmlDebugCatalogs
;
3585 xmlDebugCatalogs
= 0;
3587 xmlDebugCatalogs
= level
;
3591 /************************************************************************
3593 * Minimal interfaces used for per-document catalogs by the parser *
3595 ************************************************************************/
3598 * xmlCatalogFreeLocal:
3599 * @catalogs: a document's list of catalogs
3601 * Free up the memory associated to the catalog list
3604 xmlCatalogFreeLocal(void *catalogs
) {
3605 xmlCatalogEntryPtr catal
;
3607 if (!xmlCatalogInitialized
)
3608 xmlInitializeCatalog();
3610 catal
= (xmlCatalogEntryPtr
) catalogs
;
3612 xmlFreeCatalogEntryList(catal
);
3617 * xmlCatalogAddLocal:
3618 * @catalogs: a document's list of catalogs
3619 * @URL: the URL to a new local catalog
3621 * Add the new entry to the catalog list
3623 * Returns the updated list
3626 xmlCatalogAddLocal(void *catalogs
, const xmlChar
*URL
) {
3627 xmlCatalogEntryPtr catal
, add
;
3629 if (!xmlCatalogInitialized
)
3630 xmlInitializeCatalog();
3635 if (xmlDebugCatalogs
)
3636 xmlGenericError(xmlGenericErrorContext
,
3637 "Adding document catalog %s\n", URL
);
3639 add
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
, URL
, NULL
,
3640 xmlCatalogDefaultPrefer
, NULL
);
3644 catal
= (xmlCatalogEntryPtr
) catalogs
;
3646 return((void *) add
);
3648 while (catal
->next
!= NULL
)
3649 catal
= catal
->next
;
3655 * xmlCatalogLocalResolve:
3656 * @catalogs: a document's list of catalogs
3657 * @pubID: the public ID string
3658 * @sysID: the system ID string
3660 * Do a complete resolution lookup of an External Identifier using a
3661 * document's private catalog list
3663 * Returns the URI of the resource or NULL if not found, it must be freed
3667 xmlCatalogLocalResolve(void *catalogs
, const xmlChar
*pubID
,
3668 const xmlChar
*sysID
) {
3669 xmlCatalogEntryPtr catal
;
3672 if (!xmlCatalogInitialized
)
3673 xmlInitializeCatalog();
3675 if ((pubID
== NULL
) && (sysID
== NULL
))
3678 if (xmlDebugCatalogs
) {
3679 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
3680 xmlGenericError(xmlGenericErrorContext
,
3681 "Local Resolve: pubID %s sysID %s\n", pubID
, sysID
);
3682 } else if (pubID
!= NULL
) {
3683 xmlGenericError(xmlGenericErrorContext
,
3684 "Local Resolve: pubID %s\n", pubID
);
3686 xmlGenericError(xmlGenericErrorContext
,
3687 "Local Resolve: sysID %s\n", sysID
);
3691 catal
= (xmlCatalogEntryPtr
) catalogs
;
3694 ret
= xmlCatalogListXMLResolve(catal
, pubID
, sysID
);
3695 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3701 * xmlCatalogLocalResolveURI:
3702 * @catalogs: a document's list of catalogs
3705 * Do a complete resolution lookup of an URI using a
3706 * document's private catalog list
3708 * Returns the URI of the resource or NULL if not found, it must be freed
3712 xmlCatalogLocalResolveURI(void *catalogs
, const xmlChar
*URI
) {
3713 xmlCatalogEntryPtr catal
;
3716 if (!xmlCatalogInitialized
)
3717 xmlInitializeCatalog();
3722 if (xmlDebugCatalogs
)
3723 xmlGenericError(xmlGenericErrorContext
,
3724 "Resolve URI %s\n", URI
);
3726 catal
= (xmlCatalogEntryPtr
) catalogs
;
3729 ret
= xmlCatalogListXMLResolveURI(catal
, URI
);
3730 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3735 /************************************************************************
3737 * Deprecated interfaces *
3739 ************************************************************************/
3741 * xmlCatalogGetSystem:
3742 * @sysID: the system ID string
3744 * Try to lookup the catalog reference associated to a system ID
3745 * DEPRECATED, use xmlCatalogResolveSystem()
3747 * Returns the resource if found or NULL otherwise.
3750 xmlCatalogGetSystem(const xmlChar
*sysID
) {
3752 static xmlChar result
[1000];
3755 if (!xmlCatalogInitialized
)
3756 xmlInitializeCatalog();
3759 xmlGenericError(xmlGenericErrorContext
,
3760 "Use of deprecated xmlCatalogGetSystem() call\n");
3768 * Check first the XML catalogs
3770 if (xmlDefaultCatalog
!= NULL
) {
3771 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, NULL
, sysID
);
3772 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3773 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3774 result
[sizeof(result
) - 1] = 0;
3779 if (xmlDefaultCatalog
!= NULL
)
3780 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog
->sgml
, sysID
));
3785 * xmlCatalogGetPublic:
3786 * @pubID: the public ID string
3788 * Try to lookup the catalog reference associated to a public ID
3789 * DEPRECATED, use xmlCatalogResolvePublic()
3791 * Returns the resource if found or NULL otherwise.
3794 xmlCatalogGetPublic(const xmlChar
*pubID
) {
3796 static xmlChar result
[1000];
3799 if (!xmlCatalogInitialized
)
3800 xmlInitializeCatalog();
3803 xmlGenericError(xmlGenericErrorContext
,
3804 "Use of deprecated xmlCatalogGetPublic() call\n");
3812 * Check first the XML catalogs
3814 if (xmlDefaultCatalog
!= NULL
) {
3815 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, pubID
, NULL
);
3816 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3817 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3818 result
[sizeof(result
) - 1] = 0;
3823 if (xmlDefaultCatalog
!= NULL
)
3824 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog
->sgml
, pubID
));
3828 #define bottom_catalog
3829 #include "elfgcchack.h"
3830 #endif /* LIBXML_CATALOG_ENABLED */