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
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
24 #ifdef HAVE_SYS_STAT_H
33 #include <libxml/xmlmemory.h>
34 #include <libxml/hash.h>
35 #include <libxml/uri.h>
36 #include <libxml/parserInternals.h>
37 #include <libxml/catalog.h>
38 #include <libxml/xmlerror.h>
39 #include <libxml/threads.h>
40 #include <libxml/globals.h>
44 #define MAX_DELEGATE 50
45 #define MAX_CATAL_DEPTH 50
48 # define PATH_SEPARATOR ';'
50 # define PATH_SEPARATOR ':'
56 * macro to flag unimplemented blocks
57 * XML_CATALOG_PREFER user env to select between system/public preferred
58 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
59 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
60 *> values "system" and "public". I have made the default be "system" to
64 xmlGenericError(xmlGenericErrorContext, \
65 "Unimplemented block at %s:%d\n", \
68 #define XML_URN_PUBID "urn:publicid:"
69 #define XML_CATAL_BREAK ((xmlChar *) -1)
70 #ifndef XML_XML_DEFAULT_CATALOG
71 #define XML_XML_DEFAULT_CATALOG "file://" SYSCONFDIR "/xml/catalog"
73 #ifndef XML_SGML_DEFAULT_CATALOG
74 #define XML_SGML_DEFAULT_CATALOG "file://" SYSCONFDIR "/sgml/catalog"
77 #if defined(_WIN32) && defined(_MSC_VER)
78 #undef XML_XML_DEFAULT_CATALOG
79 static char XML_XML_DEFAULT_CATALOG
[256] = "file://" SYSCONFDIR
"/xml/catalog";
80 #if !defined(_WINDOWS_)
81 void* __stdcall
GetModuleHandleA(const char*);
82 unsigned long __stdcall
GetModuleFileNameA(void*, char*, unsigned long);
86 static xmlChar
*xmlCatalogNormalizePublic(const xmlChar
*pubID
);
87 static int xmlExpandCatalog(xmlCatalogPtr catal
, const char *filename
);
89 /************************************************************************
91 * Types, all private *
93 ************************************************************************/
96 XML_CATA_REMOVED
= -1,
99 XML_CATA_BROKEN_CATALOG
,
100 XML_CATA_NEXT_CATALOG
,
104 XML_CATA_REWRITE_SYSTEM
,
105 XML_CATA_DELEGATE_PUBLIC
,
106 XML_CATA_DELEGATE_SYSTEM
,
108 XML_CATA_REWRITE_URI
,
109 XML_CATA_DELEGATE_URI
,
122 } xmlCatalogEntryType
;
124 typedef struct _xmlCatalogEntry xmlCatalogEntry
;
125 typedef xmlCatalogEntry
*xmlCatalogEntryPtr
;
126 struct _xmlCatalogEntry
{
127 struct _xmlCatalogEntry
*next
;
128 struct _xmlCatalogEntry
*parent
;
129 struct _xmlCatalogEntry
*children
;
130 xmlCatalogEntryType type
;
133 xmlChar
*URL
; /* The expanded URL using the base */
134 xmlCatalogPrefer prefer
;
137 struct _xmlCatalogEntry
*group
;
141 XML_XML_CATALOG_TYPE
= 1,
142 XML_SGML_CATALOG_TYPE
145 #define XML_MAX_SGML_CATA_DEPTH 10
147 xmlCatalogType type
; /* either XML or SGML */
150 * SGML Catalogs are stored as a simple hash table of catalog entries
151 * Catalog stack to check against overflows when building the
154 char *catalTab
[XML_MAX_SGML_CATA_DEPTH
]; /* stack of catals */
155 int catalNr
; /* Number of current catal streams */
156 int catalMax
; /* Max number of catal streams */
157 xmlHashTablePtr sgml
;
160 * XML Catalogs are stored as a tree of Catalog entries
162 xmlCatalogPrefer prefer
;
163 xmlCatalogEntryPtr xml
;
166 /************************************************************************
170 ************************************************************************/
173 * Those are preferences
175 static int xmlDebugCatalogs
= 0; /* used for debugging */
176 static xmlCatalogAllow xmlCatalogDefaultAllow
= XML_CATA_ALLOW_ALL
;
177 static xmlCatalogPrefer xmlCatalogDefaultPrefer
= XML_CATA_PREFER_PUBLIC
;
180 * Hash table containing all the trees of XML catalogs parsed by
183 static xmlHashTablePtr xmlCatalogXMLFiles
= NULL
;
186 * The default catalog in use by the application
188 static xmlCatalogPtr xmlDefaultCatalog
= NULL
;
191 * A mutex for modifying the shared global catalog(s)
192 * xmlDefaultCatalog tree.
193 * It also protects xmlCatalogXMLFiles
194 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
196 static xmlRMutexPtr xmlCatalogMutex
= NULL
;
199 * Whether the catalog support was initialized.
201 static int xmlCatalogInitialized
= 0;
203 /************************************************************************
205 * Catalog error handlers *
207 ************************************************************************/
210 * xmlCatalogErrMemory:
211 * @extra: extra information
213 * Handle an out of memory condition
216 xmlCatalogErrMemory(const char *extra
)
218 __xmlRaiseError(NULL
, NULL
, NULL
, NULL
, NULL
, XML_FROM_CATALOG
,
219 XML_ERR_NO_MEMORY
, XML_ERR_ERROR
, NULL
, 0,
220 extra
, NULL
, NULL
, 0, 0,
221 "Memory allocation failed : %s\n", extra
);
226 * @catal: the Catalog entry
227 * @node: the context node
228 * @msg: the error message
229 * @extra: extra information
231 * Handle a catalog error
233 static void LIBXML_ATTR_FORMAT(4,0)
234 xmlCatalogErr(xmlCatalogEntryPtr catal
, xmlNodePtr node
, int error
,
235 const char *msg
, const xmlChar
*str1
, const xmlChar
*str2
,
238 __xmlRaiseError(NULL
, NULL
, NULL
, catal
, node
, XML_FROM_CATALOG
,
239 error
, XML_ERR_ERROR
, NULL
, 0,
240 (const char *) str1
, (const char *) str2
,
241 (const char *) str3
, 0, 0,
242 msg
, str1
, str2
, str3
);
246 /************************************************************************
248 * Allocation and Freeing *
250 ************************************************************************/
253 * xmlNewCatalogEntry:
254 * @type: type of entry
255 * @name: name of the entry
256 * @value: value of the entry
257 * @prefer: the PUBLIC vs. SYSTEM current preference value
258 * @group: for members of a group, the group entry
260 * create a new Catalog entry, this type is shared both by XML and
261 * SGML catalogs, but the acceptable types values differs.
263 * Returns the xmlCatalogEntryPtr or NULL in case of error
265 static xmlCatalogEntryPtr
266 xmlNewCatalogEntry(xmlCatalogEntryType type
, const xmlChar
*name
,
267 const xmlChar
*value
, const xmlChar
*URL
, xmlCatalogPrefer prefer
,
268 xmlCatalogEntryPtr group
) {
269 xmlCatalogEntryPtr ret
;
270 xmlChar
*normid
= NULL
;
272 ret
= (xmlCatalogEntryPtr
) xmlMalloc(sizeof(xmlCatalogEntry
));
274 xmlCatalogErrMemory("allocating catalog entry");
279 ret
->children
= NULL
;
281 if (type
== XML_CATA_PUBLIC
|| type
== XML_CATA_DELEGATE_PUBLIC
) {
282 normid
= xmlCatalogNormalizePublic(name
);
284 name
= (*normid
!= 0 ? normid
: NULL
);
287 ret
->name
= xmlStrdup(name
);
293 ret
->value
= xmlStrdup(value
);
299 ret
->URL
= xmlStrdup(URL
);
302 ret
->prefer
= prefer
;
310 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret
);
313 * xmlFreeCatalogEntry:
314 * @payload: a Catalog entry
316 * Free the memory allocated to a Catalog entry
319 xmlFreeCatalogEntry(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
320 xmlCatalogEntryPtr ret
= (xmlCatalogEntryPtr
) payload
;
324 * Entries stored in the file hash must be deallocated
325 * only by the file hash cleaner !
327 if (ret
->dealloc
== 1)
330 if (xmlDebugCatalogs
) {
331 if (ret
->name
!= NULL
)
332 xmlGenericError(xmlGenericErrorContext
,
333 "Free catalog entry %s\n", ret
->name
);
334 else if (ret
->value
!= NULL
)
335 xmlGenericError(xmlGenericErrorContext
,
336 "Free catalog entry %s\n", ret
->value
);
338 xmlGenericError(xmlGenericErrorContext
,
339 "Free catalog entry\n");
342 if (ret
->name
!= NULL
)
344 if (ret
->value
!= NULL
)
346 if (ret
->URL
!= NULL
)
352 * xmlFreeCatalogEntryList:
353 * @ret: a Catalog entry list
355 * Free the memory allocated to a full chained list of Catalog entries
358 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret
) {
359 xmlCatalogEntryPtr next
;
361 while (ret
!= NULL
) {
363 xmlFreeCatalogEntry(ret
, NULL
);
369 * xmlFreeCatalogHashEntryList:
370 * @payload: a Catalog entry list
372 * Free the memory allocated to list of Catalog entries from the
376 xmlFreeCatalogHashEntryList(void *payload
,
377 const xmlChar
*name ATTRIBUTE_UNUSED
) {
378 xmlCatalogEntryPtr catal
= (xmlCatalogEntryPtr
) payload
;
379 xmlCatalogEntryPtr children
, next
;
384 children
= catal
->children
;
385 while (children
!= NULL
) {
386 next
= children
->next
;
387 children
->dealloc
= 0;
388 children
->children
= NULL
;
389 xmlFreeCatalogEntry(children
, NULL
);
393 xmlFreeCatalogEntry(catal
, NULL
);
397 * xmlCreateNewCatalog:
398 * @type: type of catalog
399 * @prefer: the PUBLIC vs. SYSTEM current preference value
401 * create a new Catalog, this type is shared both by XML and
402 * SGML catalogs, but the acceptable types values differs.
404 * Returns the xmlCatalogPtr or NULL in case of error
407 xmlCreateNewCatalog(xmlCatalogType type
, xmlCatalogPrefer prefer
) {
410 ret
= (xmlCatalogPtr
) xmlMalloc(sizeof(xmlCatalog
));
412 xmlCatalogErrMemory("allocating catalog");
415 memset(ret
, 0, sizeof(xmlCatalog
));
418 ret
->catalMax
= XML_MAX_SGML_CATA_DEPTH
;
419 ret
->prefer
= prefer
;
420 if (ret
->type
== XML_SGML_CATALOG_TYPE
)
421 ret
->sgml
= xmlHashCreate(10);
429 * Free the memory allocated to a Catalog
432 xmlFreeCatalog(xmlCatalogPtr catal
) {
435 if (catal
->xml
!= NULL
)
436 xmlFreeCatalogEntryList(catal
->xml
);
437 if (catal
->sgml
!= NULL
)
438 xmlHashFree(catal
->sgml
, xmlFreeCatalogEntry
);
442 /************************************************************************
444 * Serializing Catalogs *
446 ************************************************************************/
448 #ifdef LIBXML_OUTPUT_ENABLED
450 * xmlCatalogDumpEntry:
451 * @entry: the catalog entry
454 * Serialize an SGML Catalog entry
457 xmlCatalogDumpEntry(void *payload
, void *data
,
458 const xmlChar
*name ATTRIBUTE_UNUSED
) {
459 xmlCatalogEntryPtr entry
= (xmlCatalogEntryPtr
) payload
;
460 FILE *out
= (FILE *) data
;
461 if ((entry
== NULL
) || (out
== NULL
))
463 switch (entry
->type
) {
464 case SGML_CATA_ENTITY
:
465 fprintf(out
, "ENTITY "); break;
466 case SGML_CATA_PENTITY
:
467 fprintf(out
, "ENTITY %%"); break;
468 case SGML_CATA_DOCTYPE
:
469 fprintf(out
, "DOCTYPE "); break;
470 case SGML_CATA_LINKTYPE
:
471 fprintf(out
, "LINKTYPE "); break;
472 case SGML_CATA_NOTATION
:
473 fprintf(out
, "NOTATION "); break;
474 case SGML_CATA_PUBLIC
:
475 fprintf(out
, "PUBLIC "); break;
476 case SGML_CATA_SYSTEM
:
477 fprintf(out
, "SYSTEM "); break;
478 case SGML_CATA_DELEGATE
:
479 fprintf(out
, "DELEGATE "); break;
481 fprintf(out
, "BASE "); break;
482 case SGML_CATA_CATALOG
:
483 fprintf(out
, "CATALOG "); break;
484 case SGML_CATA_DOCUMENT
:
485 fprintf(out
, "DOCUMENT "); break;
486 case SGML_CATA_SGMLDECL
:
487 fprintf(out
, "SGMLDECL "); break;
491 switch (entry
->type
) {
492 case SGML_CATA_ENTITY
:
493 case SGML_CATA_PENTITY
:
494 case SGML_CATA_DOCTYPE
:
495 case SGML_CATA_LINKTYPE
:
496 case SGML_CATA_NOTATION
:
497 fprintf(out
, "%s", (const char *) entry
->name
); break;
498 case SGML_CATA_PUBLIC
:
499 case SGML_CATA_SYSTEM
:
500 case SGML_CATA_SGMLDECL
:
501 case SGML_CATA_DOCUMENT
:
502 case SGML_CATA_CATALOG
:
504 case SGML_CATA_DELEGATE
:
505 fprintf(out
, "\"%s\"", entry
->name
); break;
509 switch (entry
->type
) {
510 case SGML_CATA_ENTITY
:
511 case SGML_CATA_PENTITY
:
512 case SGML_CATA_DOCTYPE
:
513 case SGML_CATA_LINKTYPE
:
514 case SGML_CATA_NOTATION
:
515 case SGML_CATA_PUBLIC
:
516 case SGML_CATA_SYSTEM
:
517 case SGML_CATA_DELEGATE
:
518 fprintf(out
, " \"%s\"", entry
->value
); break;
526 * xmlDumpXMLCatalogNode:
527 * @catal: top catalog entry
528 * @catalog: pointer to the xml tree
529 * @doc: the containing document
530 * @ns: the current namespace
531 * @cgroup: group node for group members
533 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
536 static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal
, xmlNodePtr catalog
,
537 xmlDocPtr doc
, xmlNsPtr ns
, xmlCatalogEntryPtr cgroup
) {
539 xmlCatalogEntryPtr cur
;
541 * add all the catalog entries
544 while (cur
!= NULL
) {
545 if (cur
->group
== cgroup
) {
547 case XML_CATA_REMOVED
:
549 case XML_CATA_BROKEN_CATALOG
:
550 case XML_CATA_CATALOG
:
556 case XML_CATA_NEXT_CATALOG
:
557 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"nextCatalog", NULL
);
558 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
559 xmlAddChild(catalog
, node
);
564 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"group", NULL
);
565 xmlSetProp(node
, BAD_CAST
"id", cur
->name
);
566 if (cur
->value
!= NULL
) {
568 xns
= xmlSearchNsByHref(doc
, node
, XML_XML_NAMESPACE
);
570 xmlSetNsProp(node
, xns
, BAD_CAST
"base",
573 switch (cur
->prefer
) {
574 case XML_CATA_PREFER_NONE
:
576 case XML_CATA_PREFER_PUBLIC
:
577 xmlSetProp(node
, BAD_CAST
"prefer", BAD_CAST
"public");
579 case XML_CATA_PREFER_SYSTEM
:
580 xmlSetProp(node
, BAD_CAST
"prefer", BAD_CAST
"system");
583 xmlDumpXMLCatalogNode(cur
->next
, node
, doc
, ns
, cur
);
584 xmlAddChild(catalog
, node
);
586 case XML_CATA_PUBLIC
:
587 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"public", NULL
);
588 xmlSetProp(node
, BAD_CAST
"publicId", cur
->name
);
589 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
590 xmlAddChild(catalog
, node
);
592 case XML_CATA_SYSTEM
:
593 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"system", NULL
);
594 xmlSetProp(node
, BAD_CAST
"systemId", cur
->name
);
595 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
596 xmlAddChild(catalog
, node
);
598 case XML_CATA_REWRITE_SYSTEM
:
599 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"rewriteSystem", NULL
);
600 xmlSetProp(node
, BAD_CAST
"systemIdStartString", cur
->name
);
601 xmlSetProp(node
, BAD_CAST
"rewritePrefix", cur
->value
);
602 xmlAddChild(catalog
, node
);
604 case XML_CATA_DELEGATE_PUBLIC
:
605 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegatePublic", NULL
);
606 xmlSetProp(node
, BAD_CAST
"publicIdStartString", cur
->name
);
607 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
608 xmlAddChild(catalog
, node
);
610 case XML_CATA_DELEGATE_SYSTEM
:
611 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegateSystem", NULL
);
612 xmlSetProp(node
, BAD_CAST
"systemIdStartString", cur
->name
);
613 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
614 xmlAddChild(catalog
, node
);
617 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"uri", NULL
);
618 xmlSetProp(node
, BAD_CAST
"name", cur
->name
);
619 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
620 xmlAddChild(catalog
, node
);
622 case XML_CATA_REWRITE_URI
:
623 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"rewriteURI", NULL
);
624 xmlSetProp(node
, BAD_CAST
"uriStartString", cur
->name
);
625 xmlSetProp(node
, BAD_CAST
"rewritePrefix", cur
->value
);
626 xmlAddChild(catalog
, node
);
628 case XML_CATA_DELEGATE_URI
:
629 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegateURI", NULL
);
630 xmlSetProp(node
, BAD_CAST
"uriStartString", cur
->name
);
631 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
632 xmlAddChild(catalog
, node
);
634 case SGML_CATA_SYSTEM
:
635 case SGML_CATA_PUBLIC
:
636 case SGML_CATA_ENTITY
:
637 case SGML_CATA_PENTITY
:
638 case SGML_CATA_DOCTYPE
:
639 case SGML_CATA_LINKTYPE
:
640 case SGML_CATA_NOTATION
:
641 case SGML_CATA_DELEGATE
:
643 case SGML_CATA_CATALOG
:
644 case SGML_CATA_DOCUMENT
:
645 case SGML_CATA_SGMLDECL
:
654 xmlDumpXMLCatalog(FILE *out
, xmlCatalogEntryPtr catal
) {
660 xmlOutputBufferPtr buf
;
665 doc
= xmlNewDoc(NULL
);
668 dtd
= xmlNewDtd(doc
, BAD_CAST
"catalog",
669 BAD_CAST
"-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
670 BAD_CAST
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
672 xmlAddChild((xmlNodePtr
) doc
, (xmlNodePtr
) dtd
);
674 ns
= xmlNewNs(NULL
, XML_CATALOGS_NAMESPACE
, NULL
);
679 catalog
= xmlNewDocNode(doc
, ns
, BAD_CAST
"catalog", NULL
);
680 if (catalog
== NULL
) {
686 xmlAddChild((xmlNodePtr
) doc
, catalog
);
688 xmlDumpXMLCatalogNode(catal
, catalog
, doc
, ns
, NULL
);
693 buf
= xmlOutputBufferCreateFile(out
, NULL
);
698 ret
= xmlSaveFormatFileTo(buf
, doc
, NULL
, 1);
707 #endif /* LIBXML_OUTPUT_ENABLED */
709 /************************************************************************
711 * Converting SGML Catalogs to XML *
713 ************************************************************************/
716 * xmlCatalogConvertEntry:
718 * @catal: pointer to the catalog being converted
720 * Convert one entry from the catalog
723 xmlCatalogConvertEntry(void *payload
, void *data
,
724 const xmlChar
*name ATTRIBUTE_UNUSED
) {
725 xmlCatalogEntryPtr entry
= (xmlCatalogEntryPtr
) payload
;
726 xmlCatalogPtr catal
= (xmlCatalogPtr
) data
;
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
, xmlFreeCatalogEntry
);
763 * Conversion successful, remove from the SGML catalog
764 * and add it to the default XML one
766 xmlHashRemoveEntry(catal
->sgml
, entry
->name
, NULL
);
767 entry
->parent
= catal
->xml
;
769 if (catal
->xml
->children
== NULL
)
770 catal
->xml
->children
= entry
;
772 xmlCatalogEntryPtr prev
;
774 prev
= catal
->xml
->children
;
775 while (prev
->next
!= NULL
)
782 * xmlConvertSGMLCatalog:
783 * @catal: the catalog
785 * Convert all the SGML catalog entries as XML ones
787 * Returns the number of entries converted if successful, -1 otherwise
790 xmlConvertSGMLCatalog(xmlCatalogPtr catal
) {
792 if ((catal
== NULL
) || (catal
->type
!= XML_SGML_CATALOG_TYPE
))
795 if (xmlDebugCatalogs
) {
796 xmlGenericError(xmlGenericErrorContext
,
797 "Converting SGML catalog to XML\n");
799 xmlHashScan(catal
->sgml
, xmlCatalogConvertEntry
, &catal
);
803 /************************************************************************
807 ************************************************************************/
810 * xmlCatalogUnWrapURN:
811 * @urn: an "urn:publicid:" to unwrap
813 * Expand the URN into the equivalent Public Identifier
815 * Returns the new identifier or NULL, the string must be deallocated
819 xmlCatalogUnWrapURN(const xmlChar
*urn
) {
820 xmlChar result
[2000];
823 if (xmlStrncmp(urn
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1))
825 urn
+= sizeof(XML_URN_PUBID
) - 1;
828 if (i
> sizeof(result
) - 4)
833 } else if (*urn
== ':') {
837 } else if (*urn
== ';') {
841 } else if (*urn
== '%') {
842 if ((urn
[1] == '2') && (urn
[2] == 'B'))
844 else if ((urn
[1] == '3') && (urn
[2] == 'A'))
846 else if ((urn
[1] == '2') && (urn
[2] == 'F'))
848 else if ((urn
[1] == '3') && (urn
[2] == 'B'))
850 else if ((urn
[1] == '2') && (urn
[2] == '7'))
852 else if ((urn
[1] == '3') && (urn
[2] == 'F'))
854 else if ((urn
[1] == '2') && (urn
[2] == '3'))
856 else if ((urn
[1] == '2') && (urn
[2] == '5'))
871 return(xmlStrdup(result
));
875 * xmlParseCatalogFile:
876 * @filename: the filename
878 * parse an XML file and build a tree. It's like xmlParseFile()
879 * except it bypass all catalog lookups.
881 * Returns the resulting document tree or NULL in case of error
885 xmlParseCatalogFile(const char *filename
) {
887 xmlParserCtxtPtr ctxt
;
888 char *directory
= NULL
;
889 xmlParserInputPtr inputStream
;
890 xmlParserInputBufferPtr buf
;
892 ctxt
= xmlNewParserCtxt();
894 #ifdef LIBXML_SAX1_ENABLED
895 if (xmlDefaultSAXHandler
.error
!= NULL
) {
896 xmlDefaultSAXHandler
.error(NULL
, "out of memory\n");
902 buf
= xmlParserInputBufferCreateFilename(filename
, XML_CHAR_ENCODING_NONE
);
904 xmlFreeParserCtxt(ctxt
);
908 inputStream
= xmlNewInputStream(ctxt
);
909 if (inputStream
== NULL
) {
910 xmlFreeParserInputBuffer(buf
);
911 xmlFreeParserCtxt(ctxt
);
915 inputStream
->filename
= (char *) xmlCanonicPath((const xmlChar
*)filename
);
916 inputStream
->buf
= buf
;
917 xmlBufResetInput(buf
->buffer
, inputStream
);
919 inputPush(ctxt
, inputStream
);
920 if (ctxt
->directory
== NULL
)
921 directory
= xmlParserGetDirectory(filename
);
922 if ((ctxt
->directory
== NULL
) && (directory
!= NULL
))
923 ctxt
->directory
= directory
;
926 ctxt
->loadsubset
= 0;
930 xmlParseDocument(ctxt
);
932 if (ctxt
->wellFormed
)
936 xmlFreeDoc(ctxt
->myDoc
);
939 xmlFreeParserCtxt(ctxt
);
945 * xmlLoadFileContent:
946 * @filename: a file path
948 * Load a file content into memory.
950 * Returns a pointer to the 0 terminated string or NULL in case of error
953 xmlLoadFileContent(const char *filename
)
968 if (filename
== NULL
)
972 if (stat(filename
, &info
) < 0)
977 if ((fd
= open(filename
, O_RDONLY
)) < 0)
979 if ((fd
= fopen(filename
, "rb")) == NULL
)
987 if (fseek(fd
, 0, SEEK_END
) || (size
= ftell(fd
)) == EOF
|| fseek(fd
, 0, SEEK_SET
)) { /* File operations denied? ok, just close and return failure */
992 content
= (xmlChar
*)xmlMallocAtomic(size
+ 10);
993 if (content
== NULL
) {
994 xmlCatalogErrMemory("allocating catalog data");
1003 len
= read(fd
, content
, size
);
1006 len
= fread(content
, 1, size
, fd
);
1019 * xmlCatalogNormalizePublic:
1020 * @pubID: the public ID string
1022 * Normalizes the Public Identifier
1024 * Implements 6.2. Public Identifier Normalization
1025 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1027 * Returns the new string or NULL, the string must be deallocated
1031 xmlCatalogNormalizePublic(const xmlChar
*pubID
)
1043 for (p
= pubID
;*p
!= 0 && ok
;p
++) {
1044 if (!xmlIsBlank_ch(*p
))
1046 else if (*p
== 0x20 && !white
)
1051 if (ok
&& !white
) /* is normalized */
1054 ret
= xmlStrdup(pubID
);
1057 for (p
= pubID
;*p
!= 0;p
++) {
1058 if (xmlIsBlank_ch(*p
)) {
1073 /************************************************************************
1075 * The XML Catalog parser *
1077 ************************************************************************/
1079 static xmlCatalogEntryPtr
1080 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
);
1082 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1083 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
);
1085 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1086 const xmlChar
*sysID
);
1088 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
);
1092 * xmlGetXMLCatalogEntryType:
1095 * lookup the internal type associated to an XML catalog entry name
1097 * Returns the type associated with that name
1099 static xmlCatalogEntryType
1100 xmlGetXMLCatalogEntryType(const xmlChar
*name
) {
1101 xmlCatalogEntryType type
= XML_CATA_NONE
;
1102 if (xmlStrEqual(name
, (const xmlChar
*) "system"))
1103 type
= XML_CATA_SYSTEM
;
1104 else if (xmlStrEqual(name
, (const xmlChar
*) "public"))
1105 type
= XML_CATA_PUBLIC
;
1106 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteSystem"))
1107 type
= XML_CATA_REWRITE_SYSTEM
;
1108 else if (xmlStrEqual(name
, (const xmlChar
*) "delegatePublic"))
1109 type
= XML_CATA_DELEGATE_PUBLIC
;
1110 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateSystem"))
1111 type
= XML_CATA_DELEGATE_SYSTEM
;
1112 else if (xmlStrEqual(name
, (const xmlChar
*) "uri"))
1113 type
= XML_CATA_URI
;
1114 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteURI"))
1115 type
= XML_CATA_REWRITE_URI
;
1116 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateURI"))
1117 type
= XML_CATA_DELEGATE_URI
;
1118 else if (xmlStrEqual(name
, (const xmlChar
*) "nextCatalog"))
1119 type
= XML_CATA_NEXT_CATALOG
;
1120 else if (xmlStrEqual(name
, (const xmlChar
*) "catalog"))
1121 type
= XML_CATA_CATALOG
;
1126 * xmlParseXMLCatalogOneNode:
1127 * @cur: the XML node
1128 * @type: the type of Catalog entry
1129 * @name: the name of the node
1130 * @attrName: the attribute holding the value
1131 * @uriAttrName: the attribute holding the URI-Reference
1132 * @prefer: the PUBLIC vs. SYSTEM current preference value
1133 * @cgroup: the group which includes this node
1135 * Finishes the examination of an XML tree node of a catalog and build
1136 * a Catalog entry from it.
1138 * Returns the new Catalog entry node or NULL in case of error.
1140 static xmlCatalogEntryPtr
1141 xmlParseXMLCatalogOneNode(xmlNodePtr cur
, xmlCatalogEntryType type
,
1142 const xmlChar
*name
, const xmlChar
*attrName
,
1143 const xmlChar
*uriAttrName
, xmlCatalogPrefer prefer
,
1144 xmlCatalogEntryPtr cgroup
) {
1147 xmlChar
*nameValue
= NULL
;
1148 xmlChar
*base
= NULL
;
1149 xmlChar
*URL
= NULL
;
1150 xmlCatalogEntryPtr ret
= NULL
;
1152 if (attrName
!= NULL
) {
1153 nameValue
= xmlGetProp(cur
, attrName
);
1154 if (nameValue
== NULL
) {
1155 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1156 "%s entry lacks '%s'\n", name
, attrName
, NULL
);
1160 uriValue
= xmlGetProp(cur
, uriAttrName
);
1161 if (uriValue
== NULL
) {
1162 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1163 "%s entry lacks '%s'\n", name
, uriAttrName
, NULL
);
1167 if (nameValue
!= NULL
)
1169 if (uriValue
!= NULL
)
1174 base
= xmlNodeGetBase(cur
->doc
, cur
);
1175 URL
= xmlBuildURI(uriValue
, base
);
1177 if (xmlDebugCatalogs
> 1) {
1178 if (nameValue
!= NULL
)
1179 xmlGenericError(xmlGenericErrorContext
,
1180 "Found %s: '%s' '%s'\n", name
, nameValue
, URL
);
1182 xmlGenericError(xmlGenericErrorContext
,
1183 "Found %s: '%s'\n", name
, URL
);
1185 ret
= xmlNewCatalogEntry(type
, nameValue
, uriValue
, URL
, prefer
, cgroup
);
1187 xmlCatalogErr(ret
, cur
, XML_CATALOG_ENTRY_BROKEN
,
1188 "%s entry '%s' broken ?: %s\n", name
, uriAttrName
, uriValue
);
1190 if (nameValue
!= NULL
)
1192 if (uriValue
!= NULL
)
1202 * xmlParseXMLCatalogNode:
1203 * @cur: the XML node
1204 * @prefer: the PUBLIC vs. SYSTEM current preference value
1205 * @parent: the parent Catalog entry
1206 * @cgroup: the group which includes this node
1208 * Examines an XML tree node of a catalog and build
1209 * a Catalog entry from it adding it to its parent. The examination can
1213 xmlParseXMLCatalogNode(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1214 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
)
1216 xmlChar
*base
= NULL
;
1217 xmlCatalogEntryPtr entry
= NULL
;
1221 if (xmlStrEqual(cur
->name
, BAD_CAST
"group")) {
1223 xmlCatalogPrefer pref
= XML_CATA_PREFER_NONE
;
1225 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1227 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1228 prefer
= XML_CATA_PREFER_SYSTEM
;
1229 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1230 prefer
= XML_CATA_PREFER_PUBLIC
;
1232 xmlCatalogErr(parent
, cur
, XML_CATALOG_PREFER_VALUE
,
1233 "Invalid value for prefer: '%s'\n",
1239 prop
= xmlGetProp(cur
, BAD_CAST
"id");
1240 base
= xmlGetNsProp(cur
, BAD_CAST
"base", XML_XML_NAMESPACE
);
1241 entry
= xmlNewCatalogEntry(XML_CATA_GROUP
, prop
, base
, NULL
, pref
, cgroup
);
1243 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"public")) {
1244 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_PUBLIC
,
1245 BAD_CAST
"public", BAD_CAST
"publicId", BAD_CAST
"uri", prefer
, cgroup
);
1246 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"system")) {
1247 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_SYSTEM
,
1248 BAD_CAST
"system", BAD_CAST
"systemId", BAD_CAST
"uri", prefer
, cgroup
);
1249 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteSystem")) {
1250 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_SYSTEM
,
1251 BAD_CAST
"rewriteSystem", BAD_CAST
"systemIdStartString",
1252 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1253 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegatePublic")) {
1254 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_PUBLIC
,
1255 BAD_CAST
"delegatePublic", BAD_CAST
"publicIdStartString",
1256 BAD_CAST
"catalog", prefer
, cgroup
);
1257 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateSystem")) {
1258 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_SYSTEM
,
1259 BAD_CAST
"delegateSystem", BAD_CAST
"systemIdStartString",
1260 BAD_CAST
"catalog", prefer
, cgroup
);
1261 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"uri")) {
1262 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_URI
,
1263 BAD_CAST
"uri", BAD_CAST
"name",
1264 BAD_CAST
"uri", prefer
, cgroup
);
1265 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteURI")) {
1266 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_URI
,
1267 BAD_CAST
"rewriteURI", BAD_CAST
"uriStartString",
1268 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1269 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateURI")) {
1270 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_URI
,
1271 BAD_CAST
"delegateURI", BAD_CAST
"uriStartString",
1272 BAD_CAST
"catalog", prefer
, cgroup
);
1273 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"nextCatalog")) {
1274 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_NEXT_CATALOG
,
1275 BAD_CAST
"nextCatalog", NULL
,
1276 BAD_CAST
"catalog", prefer
, cgroup
);
1278 if (entry
!= NULL
) {
1279 if (parent
!= NULL
) {
1280 entry
->parent
= parent
;
1281 if (parent
->children
== NULL
)
1282 parent
->children
= entry
;
1284 xmlCatalogEntryPtr prev
;
1286 prev
= parent
->children
;
1287 while (prev
->next
!= NULL
)
1292 if (entry
->type
== XML_CATA_GROUP
) {
1294 * Recurse to propagate prefer to the subtree
1295 * (xml:base handling is automated)
1297 xmlParseXMLCatalogNodeList(cur
->children
, prefer
, parent
, entry
);
1305 * xmlParseXMLCatalogNodeList:
1306 * @cur: the XML node list of siblings
1307 * @prefer: the PUBLIC vs. SYSTEM current preference value
1308 * @parent: the parent Catalog entry
1309 * @cgroup: the group which includes this list
1311 * Examines a list of XML sibling nodes of a catalog and build
1312 * a list of Catalog entry from it adding it to the parent.
1313 * The examination will recurse to examine node subtrees.
1316 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1317 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
) {
1318 while (cur
!= NULL
) {
1319 if ((cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1320 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1321 xmlParseXMLCatalogNode(cur
, prefer
, parent
, cgroup
);
1325 /* TODO: sort the list according to REWRITE lengths and prefer value */
1329 * xmlParseXMLCatalogFile:
1330 * @prefer: the PUBLIC vs. SYSTEM current preference value
1331 * @filename: the filename for the catalog
1333 * Parses the catalog file to extract the XML tree and then analyze the
1334 * tree to build a list of Catalog entries corresponding to this catalog
1336 * Returns the resulting Catalog entries list
1338 static xmlCatalogEntryPtr
1339 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
) {
1343 xmlCatalogEntryPtr parent
= NULL
;
1345 if (filename
== NULL
)
1348 doc
= xmlParseCatalogFile((const char *) filename
);
1350 if (xmlDebugCatalogs
)
1351 xmlGenericError(xmlGenericErrorContext
,
1352 "Failed to parse catalog %s\n", filename
);
1356 if (xmlDebugCatalogs
)
1357 xmlGenericError(xmlGenericErrorContext
,
1358 "%d Parsing catalog %s\n", xmlGetThreadId(), filename
);
1360 cur
= xmlDocGetRootElement(doc
);
1361 if ((cur
!= NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"catalog")) &&
1362 (cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1363 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1365 parent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
1366 (const xmlChar
*)filename
, NULL
, prefer
, NULL
);
1367 if (parent
== NULL
) {
1372 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1374 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1375 prefer
= XML_CATA_PREFER_SYSTEM
;
1376 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1377 prefer
= XML_CATA_PREFER_PUBLIC
;
1379 xmlCatalogErr(NULL
, cur
, XML_CATALOG_PREFER_VALUE
,
1380 "Invalid value for prefer: '%s'\n",
1385 cur
= cur
->children
;
1386 xmlParseXMLCatalogNodeList(cur
, prefer
, parent
, NULL
);
1388 xmlCatalogErr(NULL
, (xmlNodePtr
) doc
, XML_CATALOG_NOT_CATALOG
,
1389 "File %s is not an XML Catalog\n",
1390 filename
, NULL
, NULL
);
1399 * xmlFetchXMLCatalogFile:
1400 * @catal: an existing but incomplete catalog entry
1402 * Fetch and parse the subcatalog referenced by an entry
1404 * Returns 0 in case of success, -1 otherwise
1407 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal
) {
1408 xmlCatalogEntryPtr doc
;
1412 if (catal
->URL
== NULL
)
1416 * lock the whole catalog for modification
1418 xmlRMutexLock(xmlCatalogMutex
);
1419 if (catal
->children
!= NULL
) {
1420 /* Okay someone else did it in the meantime */
1421 xmlRMutexUnlock(xmlCatalogMutex
);
1425 if (xmlCatalogXMLFiles
!= NULL
) {
1426 doc
= (xmlCatalogEntryPtr
)
1427 xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1429 if (xmlDebugCatalogs
)
1430 xmlGenericError(xmlGenericErrorContext
,
1431 "Found %s in file hash\n", catal
->URL
);
1433 if (catal
->type
== XML_CATA_CATALOG
)
1434 catal
->children
= doc
->children
;
1436 catal
->children
= doc
;
1438 xmlRMutexUnlock(xmlCatalogMutex
);
1441 if (xmlDebugCatalogs
)
1442 xmlGenericError(xmlGenericErrorContext
,
1443 "%s not found in file hash\n", catal
->URL
);
1447 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1448 * use the existing catalog, there is no recursion allowed at
1451 doc
= xmlParseXMLCatalogFile(catal
->prefer
, catal
->URL
);
1453 catal
->type
= XML_CATA_BROKEN_CATALOG
;
1454 xmlRMutexUnlock(xmlCatalogMutex
);
1458 if (catal
->type
== XML_CATA_CATALOG
)
1459 catal
->children
= doc
->children
;
1461 catal
->children
= doc
;
1465 if (xmlCatalogXMLFiles
== NULL
)
1466 xmlCatalogXMLFiles
= xmlHashCreate(10);
1467 if (xmlCatalogXMLFiles
!= NULL
) {
1468 if (xmlDebugCatalogs
)
1469 xmlGenericError(xmlGenericErrorContext
,
1470 "%s added to file hash\n", catal
->URL
);
1471 xmlHashAddEntry(xmlCatalogXMLFiles
, catal
->URL
, doc
);
1473 xmlRMutexUnlock(xmlCatalogMutex
);
1477 /************************************************************************
1479 * XML Catalog handling *
1481 ************************************************************************/
1485 * @catal: top of an XML catalog
1486 * @type: the type of record to add to the catalog
1487 * @orig: the system, public or prefix to match (or NULL)
1488 * @replace: the replacement value for the match
1490 * Add an entry in the XML catalog, it may overwrite existing but
1491 * different entries.
1493 * Returns 0 if successful, -1 otherwise
1496 xmlAddXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*type
,
1497 const xmlChar
*orig
, const xmlChar
*replace
) {
1498 xmlCatalogEntryPtr cur
;
1499 xmlCatalogEntryType typ
;
1502 if ((catal
== NULL
) ||
1503 ((catal
->type
!= XML_CATA_CATALOG
) &&
1504 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1506 if (catal
->children
== NULL
) {
1507 xmlFetchXMLCatalogFile(catal
);
1509 if (catal
->children
== NULL
)
1512 typ
= xmlGetXMLCatalogEntryType(type
);
1513 if (typ
== XML_CATA_NONE
) {
1514 if (xmlDebugCatalogs
)
1515 xmlGenericError(xmlGenericErrorContext
,
1516 "Failed to add unknown element %s to catalog\n", type
);
1520 cur
= catal
->children
;
1522 * Might be a simple "update in place"
1525 while (cur
!= NULL
) {
1526 if ((orig
!= NULL
) && (cur
->type
== typ
) &&
1527 (xmlStrEqual(orig
, cur
->name
))) {
1528 if (xmlDebugCatalogs
)
1529 xmlGenericError(xmlGenericErrorContext
,
1530 "Updating element %s to catalog\n", type
);
1531 if (cur
->value
!= NULL
)
1532 xmlFree(cur
->value
);
1533 if (cur
->URL
!= NULL
)
1535 cur
->value
= xmlStrdup(replace
);
1536 cur
->URL
= xmlStrdup(replace
);
1539 if (cur
->next
== NULL
)
1544 if (xmlDebugCatalogs
)
1545 xmlGenericError(xmlGenericErrorContext
,
1546 "Adding element %s to catalog\n", type
);
1548 catal
->children
= xmlNewCatalogEntry(typ
, orig
, replace
,
1549 NULL
, catal
->prefer
, NULL
);
1551 cur
->next
= xmlNewCatalogEntry(typ
, orig
, replace
,
1552 NULL
, catal
->prefer
, NULL
);
1554 catal
->type
= XML_CATA_CATALOG
;
1555 cur
= (xmlCatalogEntryPtr
)xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1557 cur
->children
= catal
->children
;
1565 * @catal: top of an XML catalog
1566 * @value: the value to remove from the catalog
1568 * Remove entries in the XML catalog where the value or the URI
1569 * is equal to @value
1571 * Returns the number of entries removed if successful, -1 otherwise
1574 xmlDelXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*value
) {
1575 xmlCatalogEntryPtr cur
;
1578 if ((catal
== NULL
) ||
1579 ((catal
->type
!= XML_CATA_CATALOG
) &&
1580 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1584 if (catal
->children
== NULL
) {
1585 xmlFetchXMLCatalogFile(catal
);
1591 cur
= catal
->children
;
1592 while (cur
!= NULL
) {
1593 if (((cur
->name
!= NULL
) && (xmlStrEqual(value
, cur
->name
))) ||
1594 (xmlStrEqual(value
, cur
->value
))) {
1595 if (xmlDebugCatalogs
) {
1596 if (cur
->name
!= NULL
)
1597 xmlGenericError(xmlGenericErrorContext
,
1598 "Removing element %s from catalog\n", cur
->name
);
1600 xmlGenericError(xmlGenericErrorContext
,
1601 "Removing element %s from catalog\n", cur
->value
);
1603 cur
->type
= XML_CATA_REMOVED
;
1611 * xmlCatalogXMLResolve:
1612 * @catal: a catalog list
1613 * @pubID: the public ID string
1614 * @sysID: the system ID string
1616 * Do a complete resolution lookup of an External Identifier for a
1617 * list of catalog entries.
1619 * Implements (or tries to) 7.1. External Identifier Resolution
1620 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1622 * Returns the URI of the resource or NULL if not found
1625 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1626 const xmlChar
*sysID
) {
1627 xmlChar
*ret
= NULL
;
1628 xmlCatalogEntryPtr cur
;
1629 int haveDelegate
= 0;
1633 * protection against loops
1635 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1636 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1637 "Detected recursion in catalog %s\n",
1638 catal
->name
, NULL
, NULL
);
1644 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1646 if (sysID
!= NULL
) {
1647 xmlCatalogEntryPtr rewrite
= NULL
;
1648 int lenrewrite
= 0, len
;
1651 while (cur
!= NULL
) {
1652 switch (cur
->type
) {
1653 case XML_CATA_SYSTEM
:
1654 if (xmlStrEqual(sysID
, cur
->name
)) {
1655 if (xmlDebugCatalogs
)
1656 xmlGenericError(xmlGenericErrorContext
,
1657 "Found system match %s, using %s\n",
1658 cur
->name
, cur
->URL
);
1660 return(xmlStrdup(cur
->URL
));
1663 case XML_CATA_REWRITE_SYSTEM
:
1664 len
= xmlStrlen(cur
->name
);
1665 if ((len
> lenrewrite
) &&
1666 (!xmlStrncmp(sysID
, cur
->name
, len
))) {
1671 case XML_CATA_DELEGATE_SYSTEM
:
1672 if (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))
1675 case XML_CATA_NEXT_CATALOG
:
1683 if (rewrite
!= NULL
) {
1684 if (xmlDebugCatalogs
)
1685 xmlGenericError(xmlGenericErrorContext
,
1686 "Using rewriting rule %s\n", rewrite
->name
);
1687 ret
= xmlStrdup(rewrite
->URL
);
1689 ret
= xmlStrcat(ret
, &sysID
[lenrewrite
]);
1694 const xmlChar
*delegates
[MAX_DELEGATE
];
1698 * Assume the entries have been sorted by decreasing substring
1699 * matches when the list was produced.
1702 while (cur
!= NULL
) {
1703 if ((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) &&
1704 (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1705 for (i
= 0;i
< nbList
;i
++)
1706 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1712 if (nbList
< MAX_DELEGATE
)
1713 delegates
[nbList
++] = cur
->URL
;
1715 if (cur
->children
== NULL
) {
1716 xmlFetchXMLCatalogFile(cur
);
1718 if (cur
->children
!= NULL
) {
1719 if (xmlDebugCatalogs
)
1720 xmlGenericError(xmlGenericErrorContext
,
1721 "Trying system delegate %s\n", cur
->URL
);
1722 ret
= xmlCatalogListXMLResolve(
1723 cur
->children
, NULL
, sysID
);
1733 * Apply the cut algorithm explained in 4/
1736 return(XML_CATAL_BREAK
);
1740 * Then tries 5/ 6/ if a public ID is provided
1742 if (pubID
!= NULL
) {
1745 while (cur
!= NULL
) {
1746 switch (cur
->type
) {
1747 case XML_CATA_PUBLIC
:
1748 if (xmlStrEqual(pubID
, cur
->name
)) {
1749 if (xmlDebugCatalogs
)
1750 xmlGenericError(xmlGenericErrorContext
,
1751 "Found public match %s\n", cur
->name
);
1753 return(xmlStrdup(cur
->URL
));
1756 case XML_CATA_DELEGATE_PUBLIC
:
1757 if (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)) &&
1758 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
))
1761 case XML_CATA_NEXT_CATALOG
:
1771 const xmlChar
*delegates
[MAX_DELEGATE
];
1775 * Assume the entries have been sorted by decreasing substring
1776 * matches when the list was produced.
1779 while (cur
!= NULL
) {
1780 if ((cur
->type
== XML_CATA_DELEGATE_PUBLIC
) &&
1781 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
) &&
1782 (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1784 for (i
= 0;i
< nbList
;i
++)
1785 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1791 if (nbList
< MAX_DELEGATE
)
1792 delegates
[nbList
++] = cur
->URL
;
1794 if (cur
->children
== NULL
) {
1795 xmlFetchXMLCatalogFile(cur
);
1797 if (cur
->children
!= NULL
) {
1798 if (xmlDebugCatalogs
)
1799 xmlGenericError(xmlGenericErrorContext
,
1800 "Trying public delegate %s\n", cur
->URL
);
1801 ret
= xmlCatalogListXMLResolve(
1802 cur
->children
, pubID
, NULL
);
1812 * Apply the cut algorithm explained in 4/
1815 return(XML_CATAL_BREAK
);
1820 while (cur
!= NULL
) {
1821 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1822 if (cur
->children
== NULL
) {
1823 xmlFetchXMLCatalogFile(cur
);
1825 if (cur
->children
!= NULL
) {
1826 ret
= xmlCatalogListXMLResolve(cur
->children
, pubID
, sysID
);
1830 } else if (catal
->depth
> MAX_CATAL_DEPTH
) {
1844 * xmlCatalogXMLResolveURI:
1845 * @catal: a catalog list
1847 * @sysID: the system ID string
1849 * Do a complete resolution lookup of an External Identifier for a
1850 * list of catalog entries.
1852 * Implements (or tries to) 7.2.2. URI Resolution
1853 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1855 * Returns the URI of the resource or NULL if not found
1858 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
1859 xmlChar
*ret
= NULL
;
1860 xmlCatalogEntryPtr cur
;
1861 int haveDelegate
= 0;
1863 xmlCatalogEntryPtr rewrite
= NULL
;
1864 int lenrewrite
= 0, len
;
1872 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1873 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1874 "Detected recursion in catalog %s\n",
1875 catal
->name
, NULL
, NULL
);
1880 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1884 while (cur
!= NULL
) {
1885 switch (cur
->type
) {
1887 if (xmlStrEqual(URI
, cur
->name
)) {
1888 if (xmlDebugCatalogs
)
1889 xmlGenericError(xmlGenericErrorContext
,
1890 "Found URI match %s\n", cur
->name
);
1891 return(xmlStrdup(cur
->URL
));
1894 case XML_CATA_REWRITE_URI
:
1895 len
= xmlStrlen(cur
->name
);
1896 if ((len
> lenrewrite
) &&
1897 (!xmlStrncmp(URI
, cur
->name
, len
))) {
1902 case XML_CATA_DELEGATE_URI
:
1903 if (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))
1906 case XML_CATA_NEXT_CATALOG
:
1914 if (rewrite
!= NULL
) {
1915 if (xmlDebugCatalogs
)
1916 xmlGenericError(xmlGenericErrorContext
,
1917 "Using rewriting rule %s\n", rewrite
->name
);
1918 ret
= xmlStrdup(rewrite
->URL
);
1920 ret
= xmlStrcat(ret
, &URI
[lenrewrite
]);
1924 const xmlChar
*delegates
[MAX_DELEGATE
];
1928 * Assume the entries have been sorted by decreasing substring
1929 * matches when the list was produced.
1932 while (cur
!= NULL
) {
1933 if (((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) ||
1934 (cur
->type
== XML_CATA_DELEGATE_URI
)) &&
1935 (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))) {
1936 for (i
= 0;i
< nbList
;i
++)
1937 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1943 if (nbList
< MAX_DELEGATE
)
1944 delegates
[nbList
++] = cur
->URL
;
1946 if (cur
->children
== NULL
) {
1947 xmlFetchXMLCatalogFile(cur
);
1949 if (cur
->children
!= NULL
) {
1950 if (xmlDebugCatalogs
)
1951 xmlGenericError(xmlGenericErrorContext
,
1952 "Trying URI delegate %s\n", cur
->URL
);
1953 ret
= xmlCatalogListXMLResolveURI(
1954 cur
->children
, URI
);
1962 * Apply the cut algorithm explained in 4/
1964 return(XML_CATAL_BREAK
);
1968 while (cur
!= NULL
) {
1969 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1970 if (cur
->children
== NULL
) {
1971 xmlFetchXMLCatalogFile(cur
);
1973 if (cur
->children
!= NULL
) {
1974 ret
= xmlCatalogListXMLResolveURI(cur
->children
, URI
);
1987 * xmlCatalogListXMLResolve:
1988 * @catal: a catalog list
1989 * @pubID: the public ID string
1990 * @sysID: the system ID string
1992 * Do a complete resolution lookup of an External Identifier for a
1995 * Implements (or tries to) 7.1. External Identifier Resolution
1996 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1998 * Returns the URI of the resource or NULL if not found
2001 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
2002 const xmlChar
*sysID
) {
2003 xmlChar
*ret
= NULL
;
2004 xmlChar
*urnID
= NULL
;
2009 if ((pubID
== NULL
) && (sysID
== NULL
))
2012 normid
= xmlCatalogNormalizePublic(pubID
);
2014 pubID
= (*normid
!= 0 ? normid
: NULL
);
2016 if (!xmlStrncmp(pubID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2017 urnID
= xmlCatalogUnWrapURN(pubID
);
2018 if (xmlDebugCatalogs
) {
2020 xmlGenericError(xmlGenericErrorContext
,
2021 "Public URN ID %s expanded to NULL\n", pubID
);
2023 xmlGenericError(xmlGenericErrorContext
,
2024 "Public URN ID expanded to %s\n", urnID
);
2026 ret
= xmlCatalogListXMLResolve(catal
, urnID
, sysID
);
2033 if (!xmlStrncmp(sysID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2034 urnID
= xmlCatalogUnWrapURN(sysID
);
2035 if (xmlDebugCatalogs
) {
2037 xmlGenericError(xmlGenericErrorContext
,
2038 "System URN ID %s expanded to NULL\n", sysID
);
2040 xmlGenericError(xmlGenericErrorContext
,
2041 "System URN ID expanded to %s\n", urnID
);
2044 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2045 else if (xmlStrEqual(pubID
, urnID
))
2046 ret
= xmlCatalogListXMLResolve(catal
, pubID
, NULL
);
2048 ret
= xmlCatalogListXMLResolve(catal
, pubID
, urnID
);
2056 while (catal
!= NULL
) {
2057 if (catal
->type
== XML_CATA_CATALOG
) {
2058 if (catal
->children
== NULL
) {
2059 xmlFetchXMLCatalogFile(catal
);
2061 if (catal
->children
!= NULL
) {
2062 ret
= xmlCatalogXMLResolve(catal
->children
, pubID
, sysID
);
2065 } else if (catal
->children
->depth
> MAX_CATAL_DEPTH
) {
2071 catal
= catal
->next
;
2079 * xmlCatalogListXMLResolveURI:
2080 * @catal: a catalog list
2083 * Do a complete resolution lookup of an URI for a list of catalogs
2085 * Implements (or tries to) 7.2. URI Resolution
2086 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2088 * Returns the URI of the resource or NULL if not found
2091 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
2092 xmlChar
*ret
= NULL
;
2093 xmlChar
*urnID
= NULL
;
2100 if (!xmlStrncmp(URI
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2101 urnID
= xmlCatalogUnWrapURN(URI
);
2102 if (xmlDebugCatalogs
) {
2104 xmlGenericError(xmlGenericErrorContext
,
2105 "URN ID %s expanded to NULL\n", URI
);
2107 xmlGenericError(xmlGenericErrorContext
,
2108 "URN ID expanded to %s\n", urnID
);
2110 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2115 while (catal
!= NULL
) {
2116 if (catal
->type
== XML_CATA_CATALOG
) {
2117 if (catal
->children
== NULL
) {
2118 xmlFetchXMLCatalogFile(catal
);
2120 if (catal
->children
!= NULL
) {
2121 ret
= xmlCatalogXMLResolveURI(catal
->children
, URI
);
2126 catal
= catal
->next
;
2131 /************************************************************************
2133 * The SGML Catalog parser *
2135 ************************************************************************/
2140 #define SKIP(x) cur += x;
2142 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2145 * xmlParseSGMLCatalogComment:
2146 * @cur: the current character
2148 * Skip a comment in an SGML catalog
2150 * Returns new current character
2152 static const xmlChar
*
2153 xmlParseSGMLCatalogComment(const xmlChar
*cur
) {
2154 if ((cur
[0] != '-') || (cur
[1] != '-'))
2157 while ((cur
[0] != 0) && ((cur
[0] != '-') || ((cur
[1] != '-'))))
2166 * xmlParseSGMLCatalogPubid:
2167 * @cur: the current character
2168 * @id: the return location
2170 * Parse an SGML catalog ID
2172 * Returns new current character and store the value in @id
2174 static const xmlChar
*
2175 xmlParseSGMLCatalogPubid(const xmlChar
*cur
, xmlChar
**id
) {
2176 xmlChar
*buf
= NULL
, *tmp
;
2187 } else if (RAW
== '\'') {
2193 buf
= (xmlChar
*) xmlMallocAtomic(size
* sizeof(xmlChar
));
2195 xmlCatalogErrMemory("allocating public ID");
2198 while (IS_PUBIDCHAR_CH(*cur
) || (*cur
== '?')) {
2199 if ((*cur
== stop
) && (stop
!= ' '))
2201 if ((stop
== ' ') && (IS_BLANK_CH(*cur
)))
2203 if (len
+ 1 >= size
) {
2205 tmp
= (xmlChar
*) xmlRealloc(buf
, size
* sizeof(xmlChar
));
2207 xmlCatalogErrMemory("allocating public ID");
2219 if (!IS_BLANK_CH(*cur
)) {
2235 * xmlParseSGMLCatalogName:
2236 * @cur: the current character
2237 * @name: the return location
2239 * Parse an SGML catalog name
2241 * Returns new current character and store the value in @name
2243 static const xmlChar
*
2244 xmlParseSGMLCatalogName(const xmlChar
*cur
, xmlChar
**name
) {
2245 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
2252 * Handler for more complex cases
2255 if ((!IS_LETTER(c
) && (c
!= '_') && (c
!= ':'))) {
2259 while (((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
2260 (c
== '.') || (c
== '-') ||
2261 (c
== '_') || (c
== ':'))) {
2265 if (len
>= XML_MAX_NAMELEN
)
2268 *name
= xmlStrndup(buf
, len
);
2273 * xmlGetSGMLCatalogEntryType:
2274 * @name: the entry name
2276 * Get the Catalog entry type for a given SGML Catalog name
2278 * Returns Catalog entry type
2280 static xmlCatalogEntryType
2281 xmlGetSGMLCatalogEntryType(const xmlChar
*name
) {
2282 xmlCatalogEntryType type
= XML_CATA_NONE
;
2283 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2284 type
= SGML_CATA_SYSTEM
;
2285 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2286 type
= SGML_CATA_PUBLIC
;
2287 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2288 type
= SGML_CATA_DELEGATE
;
2289 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2290 type
= SGML_CATA_ENTITY
;
2291 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2292 type
= SGML_CATA_DOCTYPE
;
2293 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2294 type
= SGML_CATA_LINKTYPE
;
2295 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2296 type
= SGML_CATA_NOTATION
;
2297 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2298 type
= SGML_CATA_SGMLDECL
;
2299 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2300 type
= SGML_CATA_DOCUMENT
;
2301 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2302 type
= SGML_CATA_CATALOG
;
2303 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2304 type
= SGML_CATA_BASE
;
2309 * xmlParseSGMLCatalog:
2310 * @catal: the SGML Catalog
2311 * @value: the content of the SGML Catalog serialization
2312 * @file: the filepath for the catalog
2313 * @super: should this be handled as a Super Catalog in which case
2314 * parsing is not recursive
2316 * Parse an SGML catalog content and fill up the @catal hash table with
2317 * the new entries found.
2319 * Returns 0 in case of success, -1 in case of error.
2322 xmlParseSGMLCatalog(xmlCatalogPtr catal
, const xmlChar
*value
,
2323 const char *file
, int super
) {
2324 const xmlChar
*cur
= value
;
2325 xmlChar
*base
= NULL
;
2328 if ((cur
== NULL
) || (file
== NULL
))
2330 base
= xmlStrdup((const xmlChar
*) file
);
2332 while ((cur
!= NULL
) && (cur
[0] != 0)) {
2336 if ((cur
[0] == '-') && (cur
[1] == '-')) {
2337 cur
= xmlParseSGMLCatalogComment(cur
);
2343 xmlChar
*sysid
= NULL
;
2344 xmlChar
*name
= NULL
;
2345 xmlCatalogEntryType type
= XML_CATA_NONE
;
2347 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2348 if (cur
== NULL
|| name
== NULL
) {
2352 if (!IS_BLANK_CH(*cur
)) {
2358 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2359 type
= SGML_CATA_SYSTEM
;
2360 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2361 type
= SGML_CATA_PUBLIC
;
2362 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2363 type
= SGML_CATA_DELEGATE
;
2364 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2365 type
= SGML_CATA_ENTITY
;
2366 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2367 type
= SGML_CATA_DOCTYPE
;
2368 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2369 type
= SGML_CATA_LINKTYPE
;
2370 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2371 type
= SGML_CATA_NOTATION
;
2372 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2373 type
= SGML_CATA_SGMLDECL
;
2374 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2375 type
= SGML_CATA_DOCUMENT
;
2376 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2377 type
= SGML_CATA_CATALOG
;
2378 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2379 type
= SGML_CATA_BASE
;
2380 else if (xmlStrEqual(name
, (const xmlChar
*) "OVERRIDE")) {
2382 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2394 case SGML_CATA_ENTITY
:
2396 type
= SGML_CATA_PENTITY
;
2397 /* Falls through. */
2398 case SGML_CATA_PENTITY
:
2399 case SGML_CATA_DOCTYPE
:
2400 case SGML_CATA_LINKTYPE
:
2401 case SGML_CATA_NOTATION
:
2402 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2407 if (!IS_BLANK_CH(*cur
)) {
2412 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2418 case SGML_CATA_PUBLIC
:
2419 case SGML_CATA_SYSTEM
:
2420 case SGML_CATA_DELEGATE
:
2421 cur
= xmlParseSGMLCatalogPubid(cur
, &name
);
2426 if (type
!= SGML_CATA_SYSTEM
) {
2429 normid
= xmlCatalogNormalizePublic(name
);
2430 if (normid
!= NULL
) {
2441 if (!IS_BLANK_CH(*cur
)) {
2446 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2452 case SGML_CATA_BASE
:
2453 case SGML_CATA_CATALOG
:
2454 case SGML_CATA_DOCUMENT
:
2455 case SGML_CATA_SGMLDECL
:
2456 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2471 } else if (type
== SGML_CATA_BASE
) {
2474 base
= xmlStrdup(sysid
);
2475 } else if ((type
== SGML_CATA_PUBLIC
) ||
2476 (type
== SGML_CATA_SYSTEM
)) {
2479 filename
= xmlBuildURI(sysid
, base
);
2480 if (filename
!= NULL
) {
2481 xmlCatalogEntryPtr entry
;
2483 entry
= xmlNewCatalogEntry(type
, name
, filename
,
2484 NULL
, XML_CATA_PREFER_NONE
, NULL
);
2485 res
= xmlHashAddEntry(catal
->sgml
, name
, entry
);
2487 xmlFreeCatalogEntry(entry
, NULL
);
2492 } else if (type
== SGML_CATA_CATALOG
) {
2494 xmlCatalogEntryPtr entry
;
2496 entry
= xmlNewCatalogEntry(type
, sysid
, NULL
, NULL
,
2497 XML_CATA_PREFER_NONE
, NULL
);
2498 res
= xmlHashAddEntry(catal
->sgml
, sysid
, entry
);
2500 xmlFreeCatalogEntry(entry
, NULL
);
2505 filename
= xmlBuildURI(sysid
, base
);
2506 if (filename
!= NULL
) {
2507 xmlExpandCatalog(catal
, (const char *)filename
);
2513 * drop anything else we won't handle it
2528 /************************************************************************
2530 * SGML Catalog handling *
2532 ************************************************************************/
2535 * xmlCatalogGetSGMLPublic:
2536 * @catal: an SGML catalog hash
2537 * @pubID: the public ID string
2539 * Try to lookup the catalog local reference associated to a public ID
2541 * Returns the local resource if found or NULL otherwise.
2543 static const xmlChar
*
2544 xmlCatalogGetSGMLPublic(xmlHashTablePtr catal
, const xmlChar
*pubID
) {
2545 xmlCatalogEntryPtr entry
;
2551 normid
= xmlCatalogNormalizePublic(pubID
);
2553 pubID
= (*normid
!= 0 ? normid
: NULL
);
2555 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, pubID
);
2556 if (entry
== NULL
) {
2561 if (entry
->type
== SGML_CATA_PUBLIC
) {
2572 * xmlCatalogGetSGMLSystem:
2573 * @catal: an SGML catalog hash
2574 * @sysID: the system ID string
2576 * Try to lookup the catalog local reference for a system ID
2578 * Returns the local resource if found or NULL otherwise.
2580 static const xmlChar
*
2581 xmlCatalogGetSGMLSystem(xmlHashTablePtr catal
, const xmlChar
*sysID
) {
2582 xmlCatalogEntryPtr entry
;
2587 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, sysID
);
2590 if (entry
->type
== SGML_CATA_SYSTEM
)
2596 * xmlCatalogSGMLResolve:
2597 * @catal: the SGML catalog
2598 * @pubID: the public ID string
2599 * @sysID: the system ID string
2601 * Do a complete resolution lookup of an External Identifier
2603 * Returns the URI of the resource or NULL if not found
2605 static const xmlChar
*
2606 xmlCatalogSGMLResolve(xmlCatalogPtr catal
, const xmlChar
*pubID
,
2607 const xmlChar
*sysID
) {
2608 const xmlChar
*ret
= NULL
;
2610 if (catal
->sgml
== NULL
)
2614 ret
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2618 ret
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2624 /************************************************************************
2626 * Specific Public interfaces *
2628 ************************************************************************/
2631 * xmlLoadSGMLSuperCatalog:
2632 * @filename: a file path
2634 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2635 * references. This is only needed for manipulating SGML Super Catalogs
2636 * like adding and removing CATALOG or DELEGATE entries.
2638 * Returns the catalog parsed or NULL in case of error
2641 xmlLoadSGMLSuperCatalog(const char *filename
)
2644 xmlCatalogPtr catal
;
2647 content
= xmlLoadFileContent(filename
);
2648 if (content
== NULL
)
2651 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2652 if (catal
== NULL
) {
2657 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 1);
2660 xmlFreeCatalog(catal
);
2668 * @filename: a file path
2670 * Load the catalog and build the associated data structures.
2671 * This can be either an XML Catalog or an SGML Catalog
2672 * It will recurse in SGML CATALOG entries. On the other hand XML
2673 * Catalogs are not handled recursively.
2675 * Returns the catalog parsed or NULL in case of error
2678 xmlLoadACatalog(const char *filename
)
2682 xmlCatalogPtr catal
;
2685 content
= xmlLoadFileContent(filename
);
2686 if (content
== NULL
)
2692 while ((*first
!= 0) && (*first
!= '-') && (*first
!= '<') &&
2693 (!(((*first
>= 'A') && (*first
<= 'Z')) ||
2694 ((*first
>= 'a') && (*first
<= 'z')))))
2697 if (*first
!= '<') {
2698 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2699 if (catal
== NULL
) {
2703 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2705 xmlFreeCatalog(catal
);
2710 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2711 if (catal
== NULL
) {
2715 catal
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2716 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2725 * @filename: a file path
2727 * Load the catalog and expand the existing catal structure.
2728 * This can be either an XML Catalog or an SGML Catalog
2730 * Returns 0 in case of success, -1 in case of error
2733 xmlExpandCatalog(xmlCatalogPtr catal
, const char *filename
)
2737 if ((catal
== NULL
) || (filename
== NULL
))
2741 if (catal
->type
== XML_SGML_CATALOG_TYPE
) {
2744 content
= xmlLoadFileContent(filename
);
2745 if (content
== NULL
)
2748 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2755 xmlCatalogEntryPtr tmp
, cur
;
2756 tmp
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2757 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2763 while (cur
->next
!= NULL
) cur
= cur
->next
;
2771 * xmlACatalogResolveSystem:
2773 * @sysID: the system ID string
2775 * Try to lookup the catalog resource for a system ID
2777 * Returns the resource if found or NULL otherwise, the value returned
2778 * must be freed by the caller.
2781 xmlACatalogResolveSystem(xmlCatalogPtr catal
, const xmlChar
*sysID
) {
2782 xmlChar
*ret
= NULL
;
2784 if ((sysID
== NULL
) || (catal
== NULL
))
2787 if (xmlDebugCatalogs
)
2788 xmlGenericError(xmlGenericErrorContext
,
2789 "Resolve sysID %s\n", sysID
);
2791 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2792 ret
= xmlCatalogListXMLResolve(catal
->xml
, NULL
, sysID
);
2793 if (ret
== XML_CATAL_BREAK
)
2796 const xmlChar
*sgml
;
2798 sgml
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2800 ret
= xmlStrdup(sgml
);
2806 * xmlACatalogResolvePublic:
2808 * @pubID: the public ID string
2810 * Try to lookup the catalog local reference associated to a public ID in that catalog
2812 * Returns the local resource if found or NULL otherwise, the value returned
2813 * must be freed by the caller.
2816 xmlACatalogResolvePublic(xmlCatalogPtr catal
, const xmlChar
*pubID
) {
2817 xmlChar
*ret
= NULL
;
2819 if ((pubID
== NULL
) || (catal
== NULL
))
2822 if (xmlDebugCatalogs
)
2823 xmlGenericError(xmlGenericErrorContext
,
2824 "Resolve pubID %s\n", pubID
);
2826 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2827 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, NULL
);
2828 if (ret
== XML_CATAL_BREAK
)
2831 const xmlChar
*sgml
;
2833 sgml
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2835 ret
= xmlStrdup(sgml
);
2841 * xmlACatalogResolve:
2843 * @pubID: the public ID string
2844 * @sysID: the system ID string
2846 * Do a complete resolution lookup of an External Identifier
2848 * Returns the URI of the resource or NULL if not found, it must be freed
2852 xmlACatalogResolve(xmlCatalogPtr catal
, const xmlChar
* pubID
,
2853 const xmlChar
* sysID
)
2855 xmlChar
*ret
= NULL
;
2857 if (((pubID
== NULL
) && (sysID
== NULL
)) || (catal
== NULL
))
2860 if (xmlDebugCatalogs
) {
2861 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
2862 xmlGenericError(xmlGenericErrorContext
,
2863 "Resolve: pubID %s sysID %s\n", pubID
, sysID
);
2864 } else if (pubID
!= NULL
) {
2865 xmlGenericError(xmlGenericErrorContext
,
2866 "Resolve: pubID %s\n", pubID
);
2868 xmlGenericError(xmlGenericErrorContext
,
2869 "Resolve: sysID %s\n", sysID
);
2873 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2874 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, sysID
);
2875 if (ret
== XML_CATAL_BREAK
)
2878 const xmlChar
*sgml
;
2880 sgml
= xmlCatalogSGMLResolve(catal
, pubID
, sysID
);
2882 ret
= xmlStrdup(sgml
);
2888 * xmlACatalogResolveURI:
2892 * Do a complete resolution lookup of an URI
2894 * Returns the URI of the resource or NULL if not found, it must be freed
2898 xmlACatalogResolveURI(xmlCatalogPtr catal
, const xmlChar
*URI
) {
2899 xmlChar
*ret
= NULL
;
2901 if ((URI
== NULL
) || (catal
== NULL
))
2904 if (xmlDebugCatalogs
)
2905 xmlGenericError(xmlGenericErrorContext
,
2906 "Resolve URI %s\n", URI
);
2908 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2909 ret
= xmlCatalogListXMLResolveURI(catal
->xml
, URI
);
2910 if (ret
== XML_CATAL_BREAK
)
2913 const xmlChar
*sgml
;
2915 sgml
= xmlCatalogSGMLResolve(catal
, NULL
, URI
);
2917 ret
= xmlStrdup(sgml
);
2922 #ifdef LIBXML_OUTPUT_ENABLED
2928 * Dump the given catalog to the given file.
2931 xmlACatalogDump(xmlCatalogPtr catal
, FILE *out
) {
2932 if ((out
== NULL
) || (catal
== NULL
))
2935 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2936 xmlDumpXMLCatalog(out
, catal
->xml
);
2938 xmlHashScan(catal
->sgml
, xmlCatalogDumpEntry
, out
);
2941 #endif /* LIBXML_OUTPUT_ENABLED */
2946 * @type: the type of record to add to the catalog
2947 * @orig: the system, public or prefix to match
2948 * @replace: the replacement value for the match
2950 * Add an entry in the catalog, it may overwrite existing but
2951 * different entries.
2953 * Returns 0 if successful, -1 otherwise
2956 xmlACatalogAdd(xmlCatalogPtr catal
, const xmlChar
* type
,
2957 const xmlChar
* orig
, const xmlChar
* replace
)
2964 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2965 res
= xmlAddXMLCatalog(catal
->xml
, type
, orig
, replace
);
2967 xmlCatalogEntryType cattype
;
2969 cattype
= xmlGetSGMLCatalogEntryType(type
);
2970 if (cattype
!= XML_CATA_NONE
) {
2971 xmlCatalogEntryPtr entry
;
2973 entry
= xmlNewCatalogEntry(cattype
, orig
, replace
, NULL
,
2974 XML_CATA_PREFER_NONE
, NULL
);
2975 if (catal
->sgml
== NULL
)
2976 catal
->sgml
= xmlHashCreate(10);
2977 res
= xmlHashAddEntry(catal
->sgml
, orig
, entry
);
2984 * xmlACatalogRemove:
2986 * @value: the value to remove
2988 * Remove an entry from the catalog
2990 * Returns the number of entries removed if successful, -1 otherwise
2993 xmlACatalogRemove(xmlCatalogPtr catal
, const xmlChar
*value
) {
2996 if ((catal
== NULL
) || (value
== NULL
))
2999 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
3000 res
= xmlDelXMLCatalog(catal
->xml
, value
);
3002 res
= xmlHashRemoveEntry(catal
->sgml
, value
, xmlFreeCatalogEntry
);
3011 * @sgml: should this create an SGML catalog
3013 * create a new Catalog.
3015 * Returns the xmlCatalogPtr or NULL in case of error
3018 xmlNewCatalog(int sgml
) {
3019 xmlCatalogPtr catal
= NULL
;
3022 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
,
3023 xmlCatalogDefaultPrefer
);
3024 if ((catal
!= NULL
) && (catal
->sgml
== NULL
))
3025 catal
->sgml
= xmlHashCreate(10);
3027 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3028 xmlCatalogDefaultPrefer
);
3033 * xmlCatalogIsEmpty:
3034 * @catal: should this create an SGML catalog
3036 * Check is a catalog is empty
3038 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3041 xmlCatalogIsEmpty(xmlCatalogPtr catal
) {
3045 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
3046 if (catal
->xml
== NULL
)
3048 if ((catal
->xml
->type
!= XML_CATA_CATALOG
) &&
3049 (catal
->xml
->type
!= XML_CATA_BROKEN_CATALOG
))
3051 if (catal
->xml
->children
== NULL
)
3057 if (catal
->sgml
== NULL
)
3059 res
= xmlHashSize(catal
->sgml
);
3068 /************************************************************************
3070 * Public interfaces manipulating the global shared default catalog *
3072 ************************************************************************/
3075 * xmlInitializeCatalogData:
3077 * Do the catalog initialization only of global data, doesn't try to load
3078 * any catalog actually.
3079 * this function is not thread safe, catalog initialization should
3080 * preferably be done once at startup
3083 xmlInitializeCatalogData(void) {
3084 if (xmlCatalogInitialized
!= 0)
3087 if (getenv("XML_DEBUG_CATALOG"))
3088 xmlDebugCatalogs
= 1;
3089 xmlCatalogMutex
= xmlNewRMutex();
3091 xmlCatalogInitialized
= 1;
3094 * xmlInitializeCatalog:
3096 * Do the catalog initialization.
3097 * this function is not thread safe, catalog initialization should
3098 * preferably be done once at startup
3101 xmlInitializeCatalog(void) {
3102 if (xmlCatalogInitialized
!= 0)
3105 xmlInitializeCatalogData();
3106 xmlRMutexLock(xmlCatalogMutex
);
3108 if (getenv("XML_DEBUG_CATALOG"))
3109 xmlDebugCatalogs
= 1;
3111 if (xmlDefaultCatalog
== NULL
) {
3112 const char *catalogs
;
3114 const char *cur
, *paths
;
3115 xmlCatalogPtr catal
;
3116 xmlCatalogEntryPtr
*nextent
;
3118 catalogs
= (const char *) getenv("XML_CATALOG_FILES");
3119 if (catalogs
== NULL
)
3120 #if defined(_WIN32) && defined(_MSC_VER)
3123 hmodule
= GetModuleHandleA("libxml2.dll");
3124 if (hmodule
== NULL
)
3125 hmodule
= GetModuleHandleA(NULL
);
3126 if (hmodule
!= NULL
) {
3128 unsigned long len
= GetModuleFileNameA(hmodule
, buf
, 255);
3130 char* p
= &(buf
[len
]);
3131 while (*p
!= '\\' && p
> buf
)
3135 strncpy(p
, "\\..\\etc\\catalog", 255 - (p
- buf
));
3136 uri
= xmlCanonicPath((const xmlChar
*)buf
);
3138 strncpy(XML_XML_DEFAULT_CATALOG
, uri
, 255);
3144 catalogs
= XML_XML_DEFAULT_CATALOG
;
3147 catalogs
= XML_XML_DEFAULT_CATALOG
;
3150 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3151 xmlCatalogDefaultPrefer
);
3152 if (catal
!= NULL
) {
3153 /* the XML_CATALOG_FILES envvar is allowed to contain a
3154 space-separated list of entries. */
3156 nextent
= &catal
->xml
;
3157 while (*cur
!= '\0') {
3158 while (xmlIsBlank_ch(*cur
))
3162 while ((*cur
!= 0) && (!xmlIsBlank_ch(*cur
)))
3164 path
= (char *) xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3166 *nextent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3167 NULL
, BAD_CAST path
, xmlCatalogDefaultPrefer
, NULL
);
3168 if (*nextent
!= NULL
)
3169 nextent
= &((*nextent
)->next
);
3174 xmlDefaultCatalog
= catal
;
3178 xmlRMutexUnlock(xmlCatalogMutex
);
3184 * @filename: a file path
3186 * Load the catalog and makes its definitions effective for the default
3187 * external entity loader. It will recurse in SGML CATALOG entries.
3188 * this function is not thread safe, catalog initialization should
3189 * preferably be done once at startup
3191 * Returns 0 in case of success -1 in case of error
3194 xmlLoadCatalog(const char *filename
)
3197 xmlCatalogPtr catal
;
3199 if (!xmlCatalogInitialized
)
3200 xmlInitializeCatalogData();
3202 xmlRMutexLock(xmlCatalogMutex
);
3204 if (xmlDefaultCatalog
== NULL
) {
3205 catal
= xmlLoadACatalog(filename
);
3206 if (catal
== NULL
) {
3207 xmlRMutexUnlock(xmlCatalogMutex
);
3211 xmlDefaultCatalog
= catal
;
3212 xmlRMutexUnlock(xmlCatalogMutex
);
3216 ret
= xmlExpandCatalog(xmlDefaultCatalog
, filename
);
3217 xmlRMutexUnlock(xmlCatalogMutex
);
3223 * @pathss: a list of directories separated by a colon or a space.
3225 * Load the catalogs and makes their definitions effective for the default
3226 * external entity loader.
3227 * this function is not thread safe, catalog initialization should
3228 * preferably be done once at startup
3231 xmlLoadCatalogs(const char *pathss
) {
3244 while (xmlIsBlank_ch(*cur
)) cur
++;
3247 while ((*cur
!= 0) && (*cur
!= PATH_SEPARATOR
) && (!xmlIsBlank_ch(*cur
)))
3249 path
= xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3252 iLen
= strlen((const char*)path
);
3253 for(i
= 0; i
< iLen
; i
++) {
3254 if(path
[i
] == '\\') {
3259 xmlLoadCatalog((const char *) path
);
3263 while (*cur
== PATH_SEPARATOR
)
3269 * xmlCatalogCleanup:
3271 * Free up all the memory associated with catalogs
3274 xmlCatalogCleanup(void) {
3275 if (xmlCatalogInitialized
== 0)
3278 xmlRMutexLock(xmlCatalogMutex
);
3279 if (xmlDebugCatalogs
)
3280 xmlGenericError(xmlGenericErrorContext
,
3281 "Catalogs cleanup\n");
3282 if (xmlCatalogXMLFiles
!= NULL
)
3283 xmlHashFree(xmlCatalogXMLFiles
, xmlFreeCatalogHashEntryList
);
3284 xmlCatalogXMLFiles
= NULL
;
3285 if (xmlDefaultCatalog
!= NULL
)
3286 xmlFreeCatalog(xmlDefaultCatalog
);
3287 xmlDefaultCatalog
= NULL
;
3288 xmlDebugCatalogs
= 0;
3289 xmlCatalogInitialized
= 0;
3290 xmlRMutexUnlock(xmlCatalogMutex
);
3291 xmlFreeRMutex(xmlCatalogMutex
);
3295 * xmlCatalogResolveSystem:
3296 * @sysID: the system ID string
3298 * Try to lookup the catalog resource for a system ID
3300 * Returns the resource if found or NULL otherwise, the value returned
3301 * must be freed by the caller.
3304 xmlCatalogResolveSystem(const xmlChar
*sysID
) {
3307 if (!xmlCatalogInitialized
)
3308 xmlInitializeCatalog();
3310 ret
= xmlACatalogResolveSystem(xmlDefaultCatalog
, sysID
);
3315 * xmlCatalogResolvePublic:
3316 * @pubID: the public ID string
3318 * Try to lookup the catalog reference associated to a public ID
3320 * Returns the resource if found or NULL otherwise, the value returned
3321 * must be freed by the caller.
3324 xmlCatalogResolvePublic(const xmlChar
*pubID
) {
3327 if (!xmlCatalogInitialized
)
3328 xmlInitializeCatalog();
3330 ret
= xmlACatalogResolvePublic(xmlDefaultCatalog
, pubID
);
3335 * xmlCatalogResolve:
3336 * @pubID: the public ID string
3337 * @sysID: the system ID string
3339 * Do a complete resolution lookup of an External Identifier
3341 * Returns the URI of the resource or NULL if not found, it must be freed
3345 xmlCatalogResolve(const xmlChar
*pubID
, const xmlChar
*sysID
) {
3348 if (!xmlCatalogInitialized
)
3349 xmlInitializeCatalog();
3351 ret
= xmlACatalogResolve(xmlDefaultCatalog
, pubID
, sysID
);
3356 * xmlCatalogResolveURI:
3359 * Do a complete resolution lookup of an URI
3361 * Returns the URI of the resource or NULL if not found, it must be freed
3365 xmlCatalogResolveURI(const xmlChar
*URI
) {
3368 if (!xmlCatalogInitialized
)
3369 xmlInitializeCatalog();
3371 ret
= xmlACatalogResolveURI(xmlDefaultCatalog
, URI
);
3375 #ifdef LIBXML_OUTPUT_ENABLED
3380 * Dump all the global catalog content to the given file.
3383 xmlCatalogDump(FILE *out
) {
3387 if (!xmlCatalogInitialized
)
3388 xmlInitializeCatalog();
3390 xmlACatalogDump(xmlDefaultCatalog
, out
);
3392 #endif /* LIBXML_OUTPUT_ENABLED */
3396 * @type: the type of record to add to the catalog
3397 * @orig: the system, public or prefix to match
3398 * @replace: the replacement value for the match
3400 * Add an entry in the catalog, it may overwrite existing but
3401 * different entries.
3402 * If called before any other catalog routine, allows to override the
3403 * default shared catalog put in place by xmlInitializeCatalog();
3405 * Returns 0 if successful, -1 otherwise
3408 xmlCatalogAdd(const xmlChar
*type
, const xmlChar
*orig
, const xmlChar
*replace
) {
3411 if (!xmlCatalogInitialized
)
3412 xmlInitializeCatalogData();
3414 xmlRMutexLock(xmlCatalogMutex
);
3416 * Specific case where one want to override the default catalog
3417 * put in place by xmlInitializeCatalog();
3419 if ((xmlDefaultCatalog
== NULL
) &&
3420 (xmlStrEqual(type
, BAD_CAST
"catalog"))) {
3421 xmlDefaultCatalog
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3422 xmlCatalogDefaultPrefer
);
3423 if (xmlDefaultCatalog
!= NULL
) {
3424 xmlDefaultCatalog
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3425 orig
, NULL
, xmlCatalogDefaultPrefer
, NULL
);
3427 xmlRMutexUnlock(xmlCatalogMutex
);
3431 res
= xmlACatalogAdd(xmlDefaultCatalog
, type
, orig
, replace
);
3432 xmlRMutexUnlock(xmlCatalogMutex
);
3438 * @value: the value to remove
3440 * Remove an entry from the catalog
3442 * Returns the number of entries removed if successful, -1 otherwise
3445 xmlCatalogRemove(const xmlChar
*value
) {
3448 if (!xmlCatalogInitialized
)
3449 xmlInitializeCatalog();
3451 xmlRMutexLock(xmlCatalogMutex
);
3452 res
= xmlACatalogRemove(xmlDefaultCatalog
, value
);
3453 xmlRMutexUnlock(xmlCatalogMutex
);
3458 * xmlCatalogConvert:
3460 * Convert all the SGML catalog entries as XML ones
3462 * Returns the number of entries converted if successful, -1 otherwise
3465 xmlCatalogConvert(void) {
3468 if (!xmlCatalogInitialized
)
3469 xmlInitializeCatalog();
3471 xmlRMutexLock(xmlCatalogMutex
);
3472 res
= xmlConvertSGMLCatalog(xmlDefaultCatalog
);
3473 xmlRMutexUnlock(xmlCatalogMutex
);
3477 /************************************************************************
3479 * Public interface manipulating the common preferences *
3481 ************************************************************************/
3484 * xmlCatalogGetDefaults:
3486 * Used to get the user preference w.r.t. to what catalogs should
3489 * Returns the current xmlCatalogAllow value
3492 xmlCatalogGetDefaults(void) {
3493 return(xmlCatalogDefaultAllow
);
3497 * xmlCatalogSetDefaults:
3498 * @allow: what catalogs should be accepted
3500 * Used to set the user preference w.r.t. to what catalogs should
3504 xmlCatalogSetDefaults(xmlCatalogAllow allow
) {
3505 if (xmlDebugCatalogs
) {
3507 case XML_CATA_ALLOW_NONE
:
3508 xmlGenericError(xmlGenericErrorContext
,
3509 "Disabling catalog usage\n");
3511 case XML_CATA_ALLOW_GLOBAL
:
3512 xmlGenericError(xmlGenericErrorContext
,
3513 "Allowing only global catalogs\n");
3515 case XML_CATA_ALLOW_DOCUMENT
:
3516 xmlGenericError(xmlGenericErrorContext
,
3517 "Allowing only catalogs from the document\n");
3519 case XML_CATA_ALLOW_ALL
:
3520 xmlGenericError(xmlGenericErrorContext
,
3521 "Allowing all catalogs\n");
3525 xmlCatalogDefaultAllow
= allow
;
3529 * xmlCatalogSetDefaultPrefer:
3530 * @prefer: the default preference for delegation
3532 * Allows to set the preference between public and system for deletion
3533 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3534 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3536 * Returns the previous value of the default preference for delegation
3539 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer
) {
3540 xmlCatalogPrefer ret
= xmlCatalogDefaultPrefer
;
3542 if (prefer
== XML_CATA_PREFER_NONE
)
3545 if (xmlDebugCatalogs
) {
3547 case XML_CATA_PREFER_PUBLIC
:
3548 xmlGenericError(xmlGenericErrorContext
,
3549 "Setting catalog preference to PUBLIC\n");
3551 case XML_CATA_PREFER_SYSTEM
:
3552 xmlGenericError(xmlGenericErrorContext
,
3553 "Setting catalog preference to SYSTEM\n");
3559 xmlCatalogDefaultPrefer
= prefer
;
3564 * xmlCatalogSetDebug:
3565 * @level: the debug level of catalogs required
3567 * Used to set the debug level for catalog operation, 0 disable
3568 * debugging, 1 enable it
3570 * Returns the previous value of the catalog debugging level
3573 xmlCatalogSetDebug(int level
) {
3574 int ret
= xmlDebugCatalogs
;
3577 xmlDebugCatalogs
= 0;
3579 xmlDebugCatalogs
= level
;
3583 /************************************************************************
3585 * Minimal interfaces used for per-document catalogs by the parser *
3587 ************************************************************************/
3590 * xmlCatalogFreeLocal:
3591 * @catalogs: a document's list of catalogs
3593 * Free up the memory associated to the catalog list
3596 xmlCatalogFreeLocal(void *catalogs
) {
3597 xmlCatalogEntryPtr catal
;
3599 if (!xmlCatalogInitialized
)
3600 xmlInitializeCatalog();
3602 catal
= (xmlCatalogEntryPtr
) catalogs
;
3604 xmlFreeCatalogEntryList(catal
);
3609 * xmlCatalogAddLocal:
3610 * @catalogs: a document's list of catalogs
3611 * @URL: the URL to a new local catalog
3613 * Add the new entry to the catalog list
3615 * Returns the updated list
3618 xmlCatalogAddLocal(void *catalogs
, const xmlChar
*URL
) {
3619 xmlCatalogEntryPtr catal
, add
;
3621 if (!xmlCatalogInitialized
)
3622 xmlInitializeCatalog();
3627 if (xmlDebugCatalogs
)
3628 xmlGenericError(xmlGenericErrorContext
,
3629 "Adding document catalog %s\n", URL
);
3631 add
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
, URL
, NULL
,
3632 xmlCatalogDefaultPrefer
, NULL
);
3636 catal
= (xmlCatalogEntryPtr
) catalogs
;
3638 return((void *) add
);
3640 while (catal
->next
!= NULL
)
3641 catal
= catal
->next
;
3647 * xmlCatalogLocalResolve:
3648 * @catalogs: a document's list of catalogs
3649 * @pubID: the public ID string
3650 * @sysID: the system ID string
3652 * Do a complete resolution lookup of an External Identifier using a
3653 * document's private catalog list
3655 * Returns the URI of the resource or NULL if not found, it must be freed
3659 xmlCatalogLocalResolve(void *catalogs
, const xmlChar
*pubID
,
3660 const xmlChar
*sysID
) {
3661 xmlCatalogEntryPtr catal
;
3664 if (!xmlCatalogInitialized
)
3665 xmlInitializeCatalog();
3667 if ((pubID
== NULL
) && (sysID
== NULL
))
3670 if (xmlDebugCatalogs
) {
3671 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
3672 xmlGenericError(xmlGenericErrorContext
,
3673 "Local Resolve: pubID %s sysID %s\n", pubID
, sysID
);
3674 } else if (pubID
!= NULL
) {
3675 xmlGenericError(xmlGenericErrorContext
,
3676 "Local Resolve: pubID %s\n", pubID
);
3678 xmlGenericError(xmlGenericErrorContext
,
3679 "Local Resolve: sysID %s\n", sysID
);
3683 catal
= (xmlCatalogEntryPtr
) catalogs
;
3686 ret
= xmlCatalogListXMLResolve(catal
, pubID
, sysID
);
3687 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3693 * xmlCatalogLocalResolveURI:
3694 * @catalogs: a document's list of catalogs
3697 * Do a complete resolution lookup of an URI using a
3698 * document's private catalog list
3700 * Returns the URI of the resource or NULL if not found, it must be freed
3704 xmlCatalogLocalResolveURI(void *catalogs
, const xmlChar
*URI
) {
3705 xmlCatalogEntryPtr catal
;
3708 if (!xmlCatalogInitialized
)
3709 xmlInitializeCatalog();
3714 if (xmlDebugCatalogs
)
3715 xmlGenericError(xmlGenericErrorContext
,
3716 "Resolve URI %s\n", URI
);
3718 catal
= (xmlCatalogEntryPtr
) catalogs
;
3721 ret
= xmlCatalogListXMLResolveURI(catal
, URI
);
3722 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3727 /************************************************************************
3729 * Deprecated interfaces *
3731 ************************************************************************/
3733 * xmlCatalogGetSystem:
3734 * @sysID: the system ID string
3736 * Try to lookup the catalog reference associated to a system ID
3737 * DEPRECATED, use xmlCatalogResolveSystem()
3739 * Returns the resource if found or NULL otherwise.
3742 xmlCatalogGetSystem(const xmlChar
*sysID
) {
3744 static xmlChar result
[1000];
3747 if (!xmlCatalogInitialized
)
3748 xmlInitializeCatalog();
3751 xmlGenericError(xmlGenericErrorContext
,
3752 "Use of deprecated xmlCatalogGetSystem() call\n");
3760 * Check first the XML catalogs
3762 if (xmlDefaultCatalog
!= NULL
) {
3763 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, NULL
, sysID
);
3764 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3765 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3766 result
[sizeof(result
) - 1] = 0;
3771 if (xmlDefaultCatalog
!= NULL
)
3772 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog
->sgml
, sysID
));
3777 * xmlCatalogGetPublic:
3778 * @pubID: the public ID string
3780 * Try to lookup the catalog reference associated to a public ID
3781 * DEPRECATED, use xmlCatalogResolvePublic()
3783 * Returns the resource if found or NULL otherwise.
3786 xmlCatalogGetPublic(const xmlChar
*pubID
) {
3788 static xmlChar result
[1000];
3791 if (!xmlCatalogInitialized
)
3792 xmlInitializeCatalog();
3795 xmlGenericError(xmlGenericErrorContext
,
3796 "Use of deprecated xmlCatalogGetPublic() call\n");
3804 * Check first the XML catalogs
3806 if (xmlDefaultCatalog
!= NULL
) {
3807 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, pubID
, NULL
);
3808 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3809 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3810 result
[sizeof(result
) - 1] = 0;
3815 if (xmlDefaultCatalog
!= NULL
)
3816 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog
->sgml
, pubID
));
3820 #endif /* LIBXML_CATALOG_ENABLED */