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_STAT_H
26 #elif defined (_WIN32)
32 #include <libxml/xmlmemory.h>
33 #include <libxml/hash.h>
34 #include <libxml/uri.h>
35 #include <libxml/parserInternals.h>
36 #include <libxml/catalog.h>
37 #include <libxml/xmlerror.h>
38 #include <libxml/threads.h>
39 #include <libxml/globals.h>
41 #include "private/buf.h"
42 #include "private/error.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 xmlCatalogErrMemory("allocating parser context");
898 buf
= xmlParserInputBufferCreateFilename(filename
, XML_CHAR_ENCODING_NONE
);
900 xmlFreeParserCtxt(ctxt
);
904 inputStream
= xmlNewInputStream(ctxt
);
905 if (inputStream
== NULL
) {
906 xmlFreeParserInputBuffer(buf
);
907 xmlFreeParserCtxt(ctxt
);
911 inputStream
->filename
= (char *) xmlCanonicPath((const xmlChar
*)filename
);
912 inputStream
->buf
= buf
;
913 xmlBufResetInput(buf
->buffer
, inputStream
);
915 inputPush(ctxt
, inputStream
);
916 if (ctxt
->directory
== NULL
)
917 directory
= xmlParserGetDirectory(filename
);
918 if ((ctxt
->directory
== NULL
) && (directory
!= NULL
))
919 ctxt
->directory
= directory
;
922 ctxt
->loadsubset
= 0;
926 xmlParseDocument(ctxt
);
928 if (ctxt
->wellFormed
)
932 xmlFreeDoc(ctxt
->myDoc
);
935 xmlFreeParserCtxt(ctxt
);
941 * xmlLoadFileContent:
942 * @filename: a file path
944 * Load a file content into memory.
946 * Returns a pointer to the 0 terminated string or NULL in case of error
949 xmlLoadFileContent(const char *filename
)
964 if (filename
== NULL
)
968 if (stat(filename
, &info
) < 0)
973 if ((fd
= open(filename
, O_RDONLY
)) < 0)
975 if ((fd
= fopen(filename
, "rb")) == NULL
)
983 if (fseek(fd
, 0, SEEK_END
) || (size
= ftell(fd
)) == EOF
|| fseek(fd
, 0, SEEK_SET
)) { /* File operations denied? ok, just close and return failure */
988 content
= (xmlChar
*)xmlMallocAtomic(size
+ 10);
989 if (content
== NULL
) {
990 xmlCatalogErrMemory("allocating catalog data");
999 len
= read(fd
, content
, size
);
1002 len
= fread(content
, 1, size
, fd
);
1015 * xmlCatalogNormalizePublic:
1016 * @pubID: the public ID string
1018 * Normalizes the Public Identifier
1020 * Implements 6.2. Public Identifier Normalization
1021 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1023 * Returns the new string or NULL, the string must be deallocated
1027 xmlCatalogNormalizePublic(const xmlChar
*pubID
)
1039 for (p
= pubID
;*p
!= 0 && ok
;p
++) {
1040 if (!xmlIsBlank_ch(*p
))
1042 else if (*p
== 0x20 && !white
)
1047 if (ok
&& !white
) /* is normalized */
1050 ret
= xmlStrdup(pubID
);
1053 for (p
= pubID
;*p
!= 0;p
++) {
1054 if (xmlIsBlank_ch(*p
)) {
1069 /************************************************************************
1071 * The XML Catalog parser *
1073 ************************************************************************/
1075 static xmlCatalogEntryPtr
1076 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
);
1078 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1079 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
);
1081 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1082 const xmlChar
*sysID
);
1084 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
);
1088 * xmlGetXMLCatalogEntryType:
1091 * lookup the internal type associated to an XML catalog entry name
1093 * Returns the type associated with that name
1095 static xmlCatalogEntryType
1096 xmlGetXMLCatalogEntryType(const xmlChar
*name
) {
1097 xmlCatalogEntryType type
= XML_CATA_NONE
;
1098 if (xmlStrEqual(name
, (const xmlChar
*) "system"))
1099 type
= XML_CATA_SYSTEM
;
1100 else if (xmlStrEqual(name
, (const xmlChar
*) "public"))
1101 type
= XML_CATA_PUBLIC
;
1102 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteSystem"))
1103 type
= XML_CATA_REWRITE_SYSTEM
;
1104 else if (xmlStrEqual(name
, (const xmlChar
*) "delegatePublic"))
1105 type
= XML_CATA_DELEGATE_PUBLIC
;
1106 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateSystem"))
1107 type
= XML_CATA_DELEGATE_SYSTEM
;
1108 else if (xmlStrEqual(name
, (const xmlChar
*) "uri"))
1109 type
= XML_CATA_URI
;
1110 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteURI"))
1111 type
= XML_CATA_REWRITE_URI
;
1112 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateURI"))
1113 type
= XML_CATA_DELEGATE_URI
;
1114 else if (xmlStrEqual(name
, (const xmlChar
*) "nextCatalog"))
1115 type
= XML_CATA_NEXT_CATALOG
;
1116 else if (xmlStrEqual(name
, (const xmlChar
*) "catalog"))
1117 type
= XML_CATA_CATALOG
;
1122 * xmlParseXMLCatalogOneNode:
1123 * @cur: the XML node
1124 * @type: the type of Catalog entry
1125 * @name: the name of the node
1126 * @attrName: the attribute holding the value
1127 * @uriAttrName: the attribute holding the URI-Reference
1128 * @prefer: the PUBLIC vs. SYSTEM current preference value
1129 * @cgroup: the group which includes this node
1131 * Finishes the examination of an XML tree node of a catalog and build
1132 * a Catalog entry from it.
1134 * Returns the new Catalog entry node or NULL in case of error.
1136 static xmlCatalogEntryPtr
1137 xmlParseXMLCatalogOneNode(xmlNodePtr cur
, xmlCatalogEntryType type
,
1138 const xmlChar
*name
, const xmlChar
*attrName
,
1139 const xmlChar
*uriAttrName
, xmlCatalogPrefer prefer
,
1140 xmlCatalogEntryPtr cgroup
) {
1143 xmlChar
*nameValue
= NULL
;
1144 xmlChar
*base
= NULL
;
1145 xmlChar
*URL
= NULL
;
1146 xmlCatalogEntryPtr ret
= NULL
;
1148 if (attrName
!= NULL
) {
1149 nameValue
= xmlGetProp(cur
, attrName
);
1150 if (nameValue
== NULL
) {
1151 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1152 "%s entry lacks '%s'\n", name
, attrName
, NULL
);
1156 uriValue
= xmlGetProp(cur
, uriAttrName
);
1157 if (uriValue
== NULL
) {
1158 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1159 "%s entry lacks '%s'\n", name
, uriAttrName
, NULL
);
1163 if (nameValue
!= NULL
)
1165 if (uriValue
!= NULL
)
1170 base
= xmlNodeGetBase(cur
->doc
, cur
);
1171 URL
= xmlBuildURI(uriValue
, base
);
1173 if (xmlDebugCatalogs
> 1) {
1174 if (nameValue
!= NULL
)
1175 xmlGenericError(xmlGenericErrorContext
,
1176 "Found %s: '%s' '%s'\n", name
, nameValue
, URL
);
1178 xmlGenericError(xmlGenericErrorContext
,
1179 "Found %s: '%s'\n", name
, URL
);
1181 ret
= xmlNewCatalogEntry(type
, nameValue
, uriValue
, URL
, prefer
, cgroup
);
1183 xmlCatalogErr(ret
, cur
, XML_CATALOG_ENTRY_BROKEN
,
1184 "%s entry '%s' broken ?: %s\n", name
, uriAttrName
, uriValue
);
1186 if (nameValue
!= NULL
)
1188 if (uriValue
!= NULL
)
1198 * xmlParseXMLCatalogNode:
1199 * @cur: the XML node
1200 * @prefer: the PUBLIC vs. SYSTEM current preference value
1201 * @parent: the parent Catalog entry
1202 * @cgroup: the group which includes this node
1204 * Examines an XML tree node of a catalog and build
1205 * a Catalog entry from it adding it to its parent. The examination can
1209 xmlParseXMLCatalogNode(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1210 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
)
1212 xmlChar
*base
= NULL
;
1213 xmlCatalogEntryPtr entry
= NULL
;
1217 if (xmlStrEqual(cur
->name
, BAD_CAST
"group")) {
1219 xmlCatalogPrefer pref
= XML_CATA_PREFER_NONE
;
1221 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1223 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1224 prefer
= XML_CATA_PREFER_SYSTEM
;
1225 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1226 prefer
= XML_CATA_PREFER_PUBLIC
;
1228 xmlCatalogErr(parent
, cur
, XML_CATALOG_PREFER_VALUE
,
1229 "Invalid value for prefer: '%s'\n",
1235 prop
= xmlGetProp(cur
, BAD_CAST
"id");
1236 base
= xmlGetNsProp(cur
, BAD_CAST
"base", XML_XML_NAMESPACE
);
1237 entry
= xmlNewCatalogEntry(XML_CATA_GROUP
, prop
, base
, NULL
, pref
, cgroup
);
1239 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"public")) {
1240 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_PUBLIC
,
1241 BAD_CAST
"public", BAD_CAST
"publicId", BAD_CAST
"uri", prefer
, cgroup
);
1242 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"system")) {
1243 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_SYSTEM
,
1244 BAD_CAST
"system", BAD_CAST
"systemId", BAD_CAST
"uri", prefer
, cgroup
);
1245 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteSystem")) {
1246 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_SYSTEM
,
1247 BAD_CAST
"rewriteSystem", BAD_CAST
"systemIdStartString",
1248 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1249 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegatePublic")) {
1250 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_PUBLIC
,
1251 BAD_CAST
"delegatePublic", BAD_CAST
"publicIdStartString",
1252 BAD_CAST
"catalog", prefer
, cgroup
);
1253 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateSystem")) {
1254 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_SYSTEM
,
1255 BAD_CAST
"delegateSystem", BAD_CAST
"systemIdStartString",
1256 BAD_CAST
"catalog", prefer
, cgroup
);
1257 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"uri")) {
1258 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_URI
,
1259 BAD_CAST
"uri", BAD_CAST
"name",
1260 BAD_CAST
"uri", prefer
, cgroup
);
1261 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteURI")) {
1262 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_URI
,
1263 BAD_CAST
"rewriteURI", BAD_CAST
"uriStartString",
1264 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1265 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateURI")) {
1266 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_URI
,
1267 BAD_CAST
"delegateURI", BAD_CAST
"uriStartString",
1268 BAD_CAST
"catalog", prefer
, cgroup
);
1269 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"nextCatalog")) {
1270 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_NEXT_CATALOG
,
1271 BAD_CAST
"nextCatalog", NULL
,
1272 BAD_CAST
"catalog", prefer
, cgroup
);
1274 if (entry
!= NULL
) {
1275 if (parent
!= NULL
) {
1276 entry
->parent
= parent
;
1277 if (parent
->children
== NULL
)
1278 parent
->children
= entry
;
1280 xmlCatalogEntryPtr prev
;
1282 prev
= parent
->children
;
1283 while (prev
->next
!= NULL
)
1288 if (entry
->type
== XML_CATA_GROUP
) {
1290 * Recurse to propagate prefer to the subtree
1291 * (xml:base handling is automated)
1293 xmlParseXMLCatalogNodeList(cur
->children
, prefer
, parent
, entry
);
1301 * xmlParseXMLCatalogNodeList:
1302 * @cur: the XML node list of siblings
1303 * @prefer: the PUBLIC vs. SYSTEM current preference value
1304 * @parent: the parent Catalog entry
1305 * @cgroup: the group which includes this list
1307 * Examines a list of XML sibling nodes of a catalog and build
1308 * a list of Catalog entry from it adding it to the parent.
1309 * The examination will recurse to examine node subtrees.
1312 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1313 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
) {
1314 while (cur
!= NULL
) {
1315 if ((cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1316 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1317 xmlParseXMLCatalogNode(cur
, prefer
, parent
, cgroup
);
1321 /* TODO: sort the list according to REWRITE lengths and prefer value */
1325 * xmlParseXMLCatalogFile:
1326 * @prefer: the PUBLIC vs. SYSTEM current preference value
1327 * @filename: the filename for the catalog
1329 * Parses the catalog file to extract the XML tree and then analyze the
1330 * tree to build a list of Catalog entries corresponding to this catalog
1332 * Returns the resulting Catalog entries list
1334 static xmlCatalogEntryPtr
1335 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
) {
1339 xmlCatalogEntryPtr parent
= NULL
;
1341 if (filename
== NULL
)
1344 doc
= xmlParseCatalogFile((const char *) filename
);
1346 if (xmlDebugCatalogs
)
1347 xmlGenericError(xmlGenericErrorContext
,
1348 "Failed to parse catalog %s\n", filename
);
1352 if (xmlDebugCatalogs
)
1353 xmlGenericError(xmlGenericErrorContext
,
1354 "%d Parsing catalog %s\n", xmlGetThreadId(), filename
);
1356 cur
= xmlDocGetRootElement(doc
);
1357 if ((cur
!= NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"catalog")) &&
1358 (cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1359 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1361 parent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
1362 (const xmlChar
*)filename
, NULL
, prefer
, NULL
);
1363 if (parent
== NULL
) {
1368 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1370 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1371 prefer
= XML_CATA_PREFER_SYSTEM
;
1372 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1373 prefer
= XML_CATA_PREFER_PUBLIC
;
1375 xmlCatalogErr(NULL
, cur
, XML_CATALOG_PREFER_VALUE
,
1376 "Invalid value for prefer: '%s'\n",
1381 cur
= cur
->children
;
1382 xmlParseXMLCatalogNodeList(cur
, prefer
, parent
, NULL
);
1384 xmlCatalogErr(NULL
, (xmlNodePtr
) doc
, XML_CATALOG_NOT_CATALOG
,
1385 "File %s is not an XML Catalog\n",
1386 filename
, NULL
, NULL
);
1395 * xmlFetchXMLCatalogFile:
1396 * @catal: an existing but incomplete catalog entry
1398 * Fetch and parse the subcatalog referenced by an entry
1400 * Returns 0 in case of success, -1 otherwise
1403 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal
) {
1404 xmlCatalogEntryPtr doc
;
1408 if (catal
->URL
== NULL
)
1412 * lock the whole catalog for modification
1414 xmlRMutexLock(xmlCatalogMutex
);
1415 if (catal
->children
!= NULL
) {
1416 /* Okay someone else did it in the meantime */
1417 xmlRMutexUnlock(xmlCatalogMutex
);
1421 if (xmlCatalogXMLFiles
!= NULL
) {
1422 doc
= (xmlCatalogEntryPtr
)
1423 xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1425 if (xmlDebugCatalogs
)
1426 xmlGenericError(xmlGenericErrorContext
,
1427 "Found %s in file hash\n", catal
->URL
);
1429 if (catal
->type
== XML_CATA_CATALOG
)
1430 catal
->children
= doc
->children
;
1432 catal
->children
= doc
;
1434 xmlRMutexUnlock(xmlCatalogMutex
);
1437 if (xmlDebugCatalogs
)
1438 xmlGenericError(xmlGenericErrorContext
,
1439 "%s not found in file hash\n", catal
->URL
);
1443 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1444 * use the existing catalog, there is no recursion allowed at
1447 doc
= xmlParseXMLCatalogFile(catal
->prefer
, catal
->URL
);
1449 catal
->type
= XML_CATA_BROKEN_CATALOG
;
1450 xmlRMutexUnlock(xmlCatalogMutex
);
1454 if (catal
->type
== XML_CATA_CATALOG
)
1455 catal
->children
= doc
->children
;
1457 catal
->children
= doc
;
1461 if (xmlCatalogXMLFiles
== NULL
)
1462 xmlCatalogXMLFiles
= xmlHashCreate(10);
1463 if (xmlCatalogXMLFiles
!= NULL
) {
1464 if (xmlDebugCatalogs
)
1465 xmlGenericError(xmlGenericErrorContext
,
1466 "%s added to file hash\n", catal
->URL
);
1467 xmlHashAddEntry(xmlCatalogXMLFiles
, catal
->URL
, doc
);
1469 xmlRMutexUnlock(xmlCatalogMutex
);
1473 /************************************************************************
1475 * XML Catalog handling *
1477 ************************************************************************/
1481 * @catal: top of an XML catalog
1482 * @type: the type of record to add to the catalog
1483 * @orig: the system, public or prefix to match (or NULL)
1484 * @replace: the replacement value for the match
1486 * Add an entry in the XML catalog, it may overwrite existing but
1487 * different entries.
1489 * Returns 0 if successful, -1 otherwise
1492 xmlAddXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*type
,
1493 const xmlChar
*orig
, const xmlChar
*replace
) {
1494 xmlCatalogEntryPtr cur
;
1495 xmlCatalogEntryType typ
;
1498 if ((catal
== NULL
) ||
1499 ((catal
->type
!= XML_CATA_CATALOG
) &&
1500 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1502 if (catal
->children
== NULL
) {
1503 xmlFetchXMLCatalogFile(catal
);
1505 if (catal
->children
== NULL
)
1508 typ
= xmlGetXMLCatalogEntryType(type
);
1509 if (typ
== XML_CATA_NONE
) {
1510 if (xmlDebugCatalogs
)
1511 xmlGenericError(xmlGenericErrorContext
,
1512 "Failed to add unknown element %s to catalog\n", type
);
1516 cur
= catal
->children
;
1518 * Might be a simple "update in place"
1521 while (cur
!= NULL
) {
1522 if ((orig
!= NULL
) && (cur
->type
== typ
) &&
1523 (xmlStrEqual(orig
, cur
->name
))) {
1524 if (xmlDebugCatalogs
)
1525 xmlGenericError(xmlGenericErrorContext
,
1526 "Updating element %s to catalog\n", type
);
1527 if (cur
->value
!= NULL
)
1528 xmlFree(cur
->value
);
1529 if (cur
->URL
!= NULL
)
1531 cur
->value
= xmlStrdup(replace
);
1532 cur
->URL
= xmlStrdup(replace
);
1535 if (cur
->next
== NULL
)
1540 if (xmlDebugCatalogs
)
1541 xmlGenericError(xmlGenericErrorContext
,
1542 "Adding element %s to catalog\n", type
);
1544 catal
->children
= xmlNewCatalogEntry(typ
, orig
, replace
,
1545 NULL
, catal
->prefer
, NULL
);
1547 cur
->next
= xmlNewCatalogEntry(typ
, orig
, replace
,
1548 NULL
, catal
->prefer
, NULL
);
1550 catal
->type
= XML_CATA_CATALOG
;
1551 cur
= (xmlCatalogEntryPtr
)xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1553 cur
->children
= catal
->children
;
1561 * @catal: top of an XML catalog
1562 * @value: the value to remove from the catalog
1564 * Remove entries in the XML catalog where the value or the URI
1565 * is equal to @value
1567 * Returns the number of entries removed if successful, -1 otherwise
1570 xmlDelXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*value
) {
1571 xmlCatalogEntryPtr cur
;
1574 if ((catal
== NULL
) ||
1575 ((catal
->type
!= XML_CATA_CATALOG
) &&
1576 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1580 if (catal
->children
== NULL
) {
1581 xmlFetchXMLCatalogFile(catal
);
1587 cur
= catal
->children
;
1588 while (cur
!= NULL
) {
1589 if (((cur
->name
!= NULL
) && (xmlStrEqual(value
, cur
->name
))) ||
1590 (xmlStrEqual(value
, cur
->value
))) {
1591 if (xmlDebugCatalogs
) {
1592 if (cur
->name
!= NULL
)
1593 xmlGenericError(xmlGenericErrorContext
,
1594 "Removing element %s from catalog\n", cur
->name
);
1596 xmlGenericError(xmlGenericErrorContext
,
1597 "Removing element %s from catalog\n", cur
->value
);
1599 cur
->type
= XML_CATA_REMOVED
;
1607 * xmlCatalogXMLResolve:
1608 * @catal: a catalog list
1609 * @pubID: the public ID string
1610 * @sysID: the system ID string
1612 * Do a complete resolution lookup of an External Identifier for a
1613 * list of catalog entries.
1615 * Implements (or tries to) 7.1. External Identifier Resolution
1616 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1618 * Returns the URI of the resource or NULL if not found
1621 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1622 const xmlChar
*sysID
) {
1623 xmlChar
*ret
= NULL
;
1624 xmlCatalogEntryPtr cur
;
1625 int haveDelegate
= 0;
1629 * protection against loops
1631 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1632 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1633 "Detected recursion in catalog %s\n",
1634 catal
->name
, NULL
, NULL
);
1640 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1642 if (sysID
!= NULL
) {
1643 xmlCatalogEntryPtr rewrite
= NULL
;
1644 int lenrewrite
= 0, len
;
1647 while (cur
!= NULL
) {
1648 switch (cur
->type
) {
1649 case XML_CATA_SYSTEM
:
1650 if (xmlStrEqual(sysID
, cur
->name
)) {
1651 if (xmlDebugCatalogs
)
1652 xmlGenericError(xmlGenericErrorContext
,
1653 "Found system match %s, using %s\n",
1654 cur
->name
, cur
->URL
);
1656 return(xmlStrdup(cur
->URL
));
1659 case XML_CATA_REWRITE_SYSTEM
:
1660 len
= xmlStrlen(cur
->name
);
1661 if ((len
> lenrewrite
) &&
1662 (!xmlStrncmp(sysID
, cur
->name
, len
))) {
1667 case XML_CATA_DELEGATE_SYSTEM
:
1668 if (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))
1671 case XML_CATA_NEXT_CATALOG
:
1679 if (rewrite
!= NULL
) {
1680 if (xmlDebugCatalogs
)
1681 xmlGenericError(xmlGenericErrorContext
,
1682 "Using rewriting rule %s\n", rewrite
->name
);
1683 ret
= xmlStrdup(rewrite
->URL
);
1685 ret
= xmlStrcat(ret
, &sysID
[lenrewrite
]);
1690 const xmlChar
*delegates
[MAX_DELEGATE
];
1694 * Assume the entries have been sorted by decreasing substring
1695 * matches when the list was produced.
1698 while (cur
!= NULL
) {
1699 if ((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) &&
1700 (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1701 for (i
= 0;i
< nbList
;i
++)
1702 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1708 if (nbList
< MAX_DELEGATE
)
1709 delegates
[nbList
++] = cur
->URL
;
1711 if (cur
->children
== NULL
) {
1712 xmlFetchXMLCatalogFile(cur
);
1714 if (cur
->children
!= NULL
) {
1715 if (xmlDebugCatalogs
)
1716 xmlGenericError(xmlGenericErrorContext
,
1717 "Trying system delegate %s\n", cur
->URL
);
1718 ret
= xmlCatalogListXMLResolve(
1719 cur
->children
, NULL
, sysID
);
1729 * Apply the cut algorithm explained in 4/
1732 return(XML_CATAL_BREAK
);
1736 * Then tries 5/ 6/ if a public ID is provided
1738 if (pubID
!= NULL
) {
1741 while (cur
!= NULL
) {
1742 switch (cur
->type
) {
1743 case XML_CATA_PUBLIC
:
1744 if (xmlStrEqual(pubID
, cur
->name
)) {
1745 if (xmlDebugCatalogs
)
1746 xmlGenericError(xmlGenericErrorContext
,
1747 "Found public match %s\n", cur
->name
);
1749 return(xmlStrdup(cur
->URL
));
1752 case XML_CATA_DELEGATE_PUBLIC
:
1753 if (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)) &&
1754 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
))
1757 case XML_CATA_NEXT_CATALOG
:
1767 const xmlChar
*delegates
[MAX_DELEGATE
];
1771 * Assume the entries have been sorted by decreasing substring
1772 * matches when the list was produced.
1775 while (cur
!= NULL
) {
1776 if ((cur
->type
== XML_CATA_DELEGATE_PUBLIC
) &&
1777 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
) &&
1778 (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1780 for (i
= 0;i
< nbList
;i
++)
1781 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1787 if (nbList
< MAX_DELEGATE
)
1788 delegates
[nbList
++] = cur
->URL
;
1790 if (cur
->children
== NULL
) {
1791 xmlFetchXMLCatalogFile(cur
);
1793 if (cur
->children
!= NULL
) {
1794 if (xmlDebugCatalogs
)
1795 xmlGenericError(xmlGenericErrorContext
,
1796 "Trying public delegate %s\n", cur
->URL
);
1797 ret
= xmlCatalogListXMLResolve(
1798 cur
->children
, pubID
, NULL
);
1808 * Apply the cut algorithm explained in 4/
1811 return(XML_CATAL_BREAK
);
1816 while (cur
!= NULL
) {
1817 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1818 if (cur
->children
== NULL
) {
1819 xmlFetchXMLCatalogFile(cur
);
1821 if (cur
->children
!= NULL
) {
1822 ret
= xmlCatalogListXMLResolve(cur
->children
, pubID
, sysID
);
1826 } else if (catal
->depth
> MAX_CATAL_DEPTH
) {
1840 * xmlCatalogXMLResolveURI:
1841 * @catal: a catalog list
1843 * @sysID: the system ID string
1845 * Do a complete resolution lookup of an External Identifier for a
1846 * list of catalog entries.
1848 * Implements (or tries to) 7.2.2. URI Resolution
1849 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1851 * Returns the URI of the resource or NULL if not found
1854 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
1855 xmlChar
*ret
= NULL
;
1856 xmlCatalogEntryPtr cur
;
1857 int haveDelegate
= 0;
1859 xmlCatalogEntryPtr rewrite
= NULL
;
1860 int lenrewrite
= 0, len
;
1868 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1869 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1870 "Detected recursion in catalog %s\n",
1871 catal
->name
, NULL
, NULL
);
1876 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1880 while (cur
!= NULL
) {
1881 switch (cur
->type
) {
1883 if (xmlStrEqual(URI
, cur
->name
)) {
1884 if (xmlDebugCatalogs
)
1885 xmlGenericError(xmlGenericErrorContext
,
1886 "Found URI match %s\n", cur
->name
);
1887 return(xmlStrdup(cur
->URL
));
1890 case XML_CATA_REWRITE_URI
:
1891 len
= xmlStrlen(cur
->name
);
1892 if ((len
> lenrewrite
) &&
1893 (!xmlStrncmp(URI
, cur
->name
, len
))) {
1898 case XML_CATA_DELEGATE_URI
:
1899 if (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))
1902 case XML_CATA_NEXT_CATALOG
:
1910 if (rewrite
!= NULL
) {
1911 if (xmlDebugCatalogs
)
1912 xmlGenericError(xmlGenericErrorContext
,
1913 "Using rewriting rule %s\n", rewrite
->name
);
1914 ret
= xmlStrdup(rewrite
->URL
);
1916 ret
= xmlStrcat(ret
, &URI
[lenrewrite
]);
1920 const xmlChar
*delegates
[MAX_DELEGATE
];
1924 * Assume the entries have been sorted by decreasing substring
1925 * matches when the list was produced.
1928 while (cur
!= NULL
) {
1929 if (((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) ||
1930 (cur
->type
== XML_CATA_DELEGATE_URI
)) &&
1931 (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))) {
1932 for (i
= 0;i
< nbList
;i
++)
1933 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1939 if (nbList
< MAX_DELEGATE
)
1940 delegates
[nbList
++] = cur
->URL
;
1942 if (cur
->children
== NULL
) {
1943 xmlFetchXMLCatalogFile(cur
);
1945 if (cur
->children
!= NULL
) {
1946 if (xmlDebugCatalogs
)
1947 xmlGenericError(xmlGenericErrorContext
,
1948 "Trying URI delegate %s\n", cur
->URL
);
1949 ret
= xmlCatalogListXMLResolveURI(
1950 cur
->children
, URI
);
1958 * Apply the cut algorithm explained in 4/
1960 return(XML_CATAL_BREAK
);
1964 while (cur
!= NULL
) {
1965 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1966 if (cur
->children
== NULL
) {
1967 xmlFetchXMLCatalogFile(cur
);
1969 if (cur
->children
!= NULL
) {
1970 ret
= xmlCatalogListXMLResolveURI(cur
->children
, URI
);
1983 * xmlCatalogListXMLResolve:
1984 * @catal: a catalog list
1985 * @pubID: the public ID string
1986 * @sysID: the system ID string
1988 * Do a complete resolution lookup of an External Identifier for a
1991 * Implements (or tries to) 7.1. External Identifier Resolution
1992 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1994 * Returns the URI of the resource or NULL if not found
1997 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1998 const xmlChar
*sysID
) {
1999 xmlChar
*ret
= NULL
;
2000 xmlChar
*urnID
= NULL
;
2005 if ((pubID
== NULL
) && (sysID
== NULL
))
2008 normid
= xmlCatalogNormalizePublic(pubID
);
2010 pubID
= (*normid
!= 0 ? normid
: NULL
);
2012 if (!xmlStrncmp(pubID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2013 urnID
= xmlCatalogUnWrapURN(pubID
);
2014 if (xmlDebugCatalogs
) {
2016 xmlGenericError(xmlGenericErrorContext
,
2017 "Public URN ID %s expanded to NULL\n", pubID
);
2019 xmlGenericError(xmlGenericErrorContext
,
2020 "Public URN ID expanded to %s\n", urnID
);
2022 ret
= xmlCatalogListXMLResolve(catal
, urnID
, sysID
);
2029 if (!xmlStrncmp(sysID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2030 urnID
= xmlCatalogUnWrapURN(sysID
);
2031 if (xmlDebugCatalogs
) {
2033 xmlGenericError(xmlGenericErrorContext
,
2034 "System URN ID %s expanded to NULL\n", sysID
);
2036 xmlGenericError(xmlGenericErrorContext
,
2037 "System URN ID expanded to %s\n", urnID
);
2040 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2041 else if (xmlStrEqual(pubID
, urnID
))
2042 ret
= xmlCatalogListXMLResolve(catal
, pubID
, NULL
);
2044 ret
= xmlCatalogListXMLResolve(catal
, pubID
, urnID
);
2052 while (catal
!= NULL
) {
2053 if (catal
->type
== XML_CATA_CATALOG
) {
2054 if (catal
->children
== NULL
) {
2055 xmlFetchXMLCatalogFile(catal
);
2057 if (catal
->children
!= NULL
) {
2058 ret
= xmlCatalogXMLResolve(catal
->children
, pubID
, sysID
);
2061 } else if (catal
->children
->depth
> MAX_CATAL_DEPTH
) {
2067 catal
= catal
->next
;
2075 * xmlCatalogListXMLResolveURI:
2076 * @catal: a catalog list
2079 * Do a complete resolution lookup of an URI for a list of catalogs
2081 * Implements (or tries to) 7.2. URI Resolution
2082 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2084 * Returns the URI of the resource or NULL if not found
2087 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
2088 xmlChar
*ret
= NULL
;
2089 xmlChar
*urnID
= NULL
;
2096 if (!xmlStrncmp(URI
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2097 urnID
= xmlCatalogUnWrapURN(URI
);
2098 if (xmlDebugCatalogs
) {
2100 xmlGenericError(xmlGenericErrorContext
,
2101 "URN ID %s expanded to NULL\n", URI
);
2103 xmlGenericError(xmlGenericErrorContext
,
2104 "URN ID expanded to %s\n", urnID
);
2106 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2111 while (catal
!= NULL
) {
2112 if (catal
->type
== XML_CATA_CATALOG
) {
2113 if (catal
->children
== NULL
) {
2114 xmlFetchXMLCatalogFile(catal
);
2116 if (catal
->children
!= NULL
) {
2117 ret
= xmlCatalogXMLResolveURI(catal
->children
, URI
);
2122 catal
= catal
->next
;
2127 /************************************************************************
2129 * The SGML Catalog parser *
2131 ************************************************************************/
2136 #define SKIP(x) cur += x;
2138 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2141 * xmlParseSGMLCatalogComment:
2142 * @cur: the current character
2144 * Skip a comment in an SGML catalog
2146 * Returns new current character
2148 static const xmlChar
*
2149 xmlParseSGMLCatalogComment(const xmlChar
*cur
) {
2150 if ((cur
[0] != '-') || (cur
[1] != '-'))
2153 while ((cur
[0] != 0) && ((cur
[0] != '-') || ((cur
[1] != '-'))))
2162 * xmlParseSGMLCatalogPubid:
2163 * @cur: the current character
2164 * @id: the return location
2166 * Parse an SGML catalog ID
2168 * Returns new current character and store the value in @id
2170 static const xmlChar
*
2171 xmlParseSGMLCatalogPubid(const xmlChar
*cur
, xmlChar
**id
) {
2172 xmlChar
*buf
= NULL
, *tmp
;
2182 } else if (RAW
== '\'') {
2188 buf
= (xmlChar
*) xmlMallocAtomic(size
);
2190 xmlCatalogErrMemory("allocating public ID");
2193 while (IS_PUBIDCHAR_CH(*cur
) || (*cur
== '?')) {
2194 if ((*cur
== stop
) && (stop
!= ' '))
2196 if ((stop
== ' ') && (IS_BLANK_CH(*cur
)))
2198 if (len
+ 1 >= size
) {
2200 tmp
= (xmlChar
*) xmlRealloc(buf
, size
);
2202 xmlCatalogErrMemory("allocating public ID");
2213 if (!IS_BLANK_CH(*cur
)) {
2229 * xmlParseSGMLCatalogName:
2230 * @cur: the current character
2231 * @name: the return location
2233 * Parse an SGML catalog name
2235 * Returns new current character and store the value in @name
2237 static const xmlChar
*
2238 xmlParseSGMLCatalogName(const xmlChar
*cur
, xmlChar
**name
) {
2239 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
2246 * Handler for more complex cases
2249 if ((!IS_LETTER(c
) && (c
!= '_') && (c
!= ':'))) {
2253 while (((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
2254 (c
== '.') || (c
== '-') ||
2255 (c
== '_') || (c
== ':'))) {
2259 if (len
>= XML_MAX_NAMELEN
)
2262 *name
= xmlStrndup(buf
, len
);
2267 * xmlGetSGMLCatalogEntryType:
2268 * @name: the entry name
2270 * Get the Catalog entry type for a given SGML Catalog name
2272 * Returns Catalog entry type
2274 static xmlCatalogEntryType
2275 xmlGetSGMLCatalogEntryType(const xmlChar
*name
) {
2276 xmlCatalogEntryType type
= XML_CATA_NONE
;
2277 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2278 type
= SGML_CATA_SYSTEM
;
2279 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2280 type
= SGML_CATA_PUBLIC
;
2281 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2282 type
= SGML_CATA_DELEGATE
;
2283 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2284 type
= SGML_CATA_ENTITY
;
2285 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2286 type
= SGML_CATA_DOCTYPE
;
2287 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2288 type
= SGML_CATA_LINKTYPE
;
2289 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2290 type
= SGML_CATA_NOTATION
;
2291 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2292 type
= SGML_CATA_SGMLDECL
;
2293 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2294 type
= SGML_CATA_DOCUMENT
;
2295 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2296 type
= SGML_CATA_CATALOG
;
2297 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2298 type
= SGML_CATA_BASE
;
2303 * xmlParseSGMLCatalog:
2304 * @catal: the SGML Catalog
2305 * @value: the content of the SGML Catalog serialization
2306 * @file: the filepath for the catalog
2307 * @super: should this be handled as a Super Catalog in which case
2308 * parsing is not recursive
2310 * Parse an SGML catalog content and fill up the @catal hash table with
2311 * the new entries found.
2313 * Returns 0 in case of success, -1 in case of error.
2316 xmlParseSGMLCatalog(xmlCatalogPtr catal
, const xmlChar
*value
,
2317 const char *file
, int super
) {
2318 const xmlChar
*cur
= value
;
2319 xmlChar
*base
= NULL
;
2322 if ((cur
== NULL
) || (file
== NULL
))
2324 base
= xmlStrdup((const xmlChar
*) file
);
2326 while ((cur
!= NULL
) && (cur
[0] != 0)) {
2330 if ((cur
[0] == '-') && (cur
[1] == '-')) {
2331 cur
= xmlParseSGMLCatalogComment(cur
);
2337 xmlChar
*sysid
= NULL
;
2338 xmlChar
*name
= NULL
;
2339 xmlCatalogEntryType type
= XML_CATA_NONE
;
2341 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2342 if (cur
== NULL
|| name
== NULL
) {
2346 if (!IS_BLANK_CH(*cur
)) {
2352 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2353 type
= SGML_CATA_SYSTEM
;
2354 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2355 type
= SGML_CATA_PUBLIC
;
2356 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2357 type
= SGML_CATA_DELEGATE
;
2358 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2359 type
= SGML_CATA_ENTITY
;
2360 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2361 type
= SGML_CATA_DOCTYPE
;
2362 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2363 type
= SGML_CATA_LINKTYPE
;
2364 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2365 type
= SGML_CATA_NOTATION
;
2366 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2367 type
= SGML_CATA_SGMLDECL
;
2368 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2369 type
= SGML_CATA_DOCUMENT
;
2370 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2371 type
= SGML_CATA_CATALOG
;
2372 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2373 type
= SGML_CATA_BASE
;
2374 else if (xmlStrEqual(name
, (const xmlChar
*) "OVERRIDE")) {
2376 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2388 case SGML_CATA_ENTITY
:
2390 type
= SGML_CATA_PENTITY
;
2391 /* Falls through. */
2392 case SGML_CATA_PENTITY
:
2393 case SGML_CATA_DOCTYPE
:
2394 case SGML_CATA_LINKTYPE
:
2395 case SGML_CATA_NOTATION
:
2396 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2401 if (!IS_BLANK_CH(*cur
)) {
2406 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2412 case SGML_CATA_PUBLIC
:
2413 case SGML_CATA_SYSTEM
:
2414 case SGML_CATA_DELEGATE
:
2415 cur
= xmlParseSGMLCatalogPubid(cur
, &name
);
2420 if (type
!= SGML_CATA_SYSTEM
) {
2423 normid
= xmlCatalogNormalizePublic(name
);
2424 if (normid
!= NULL
) {
2435 if (!IS_BLANK_CH(*cur
)) {
2440 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2446 case SGML_CATA_BASE
:
2447 case SGML_CATA_CATALOG
:
2448 case SGML_CATA_DOCUMENT
:
2449 case SGML_CATA_SGMLDECL
:
2450 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2465 } else if (type
== SGML_CATA_BASE
) {
2468 base
= xmlStrdup(sysid
);
2469 } else if ((type
== SGML_CATA_PUBLIC
) ||
2470 (type
== SGML_CATA_SYSTEM
)) {
2473 filename
= xmlBuildURI(sysid
, base
);
2474 if (filename
!= NULL
) {
2475 xmlCatalogEntryPtr entry
;
2477 entry
= xmlNewCatalogEntry(type
, name
, filename
,
2478 NULL
, XML_CATA_PREFER_NONE
, NULL
);
2479 res
= xmlHashAddEntry(catal
->sgml
, name
, entry
);
2481 xmlFreeCatalogEntry(entry
, NULL
);
2486 } else if (type
== SGML_CATA_CATALOG
) {
2488 xmlCatalogEntryPtr entry
;
2490 entry
= xmlNewCatalogEntry(type
, sysid
, NULL
, NULL
,
2491 XML_CATA_PREFER_NONE
, NULL
);
2492 res
= xmlHashAddEntry(catal
->sgml
, sysid
, entry
);
2494 xmlFreeCatalogEntry(entry
, NULL
);
2499 filename
= xmlBuildURI(sysid
, base
);
2500 if (filename
!= NULL
) {
2501 xmlExpandCatalog(catal
, (const char *)filename
);
2507 * drop anything else we won't handle it
2522 /************************************************************************
2524 * SGML Catalog handling *
2526 ************************************************************************/
2529 * xmlCatalogGetSGMLPublic:
2530 * @catal: an SGML catalog hash
2531 * @pubID: the public ID string
2533 * Try to lookup the catalog local reference associated to a public ID
2535 * Returns the local resource if found or NULL otherwise.
2537 static const xmlChar
*
2538 xmlCatalogGetSGMLPublic(xmlHashTablePtr catal
, const xmlChar
*pubID
) {
2539 xmlCatalogEntryPtr entry
;
2545 normid
= xmlCatalogNormalizePublic(pubID
);
2547 pubID
= (*normid
!= 0 ? normid
: NULL
);
2549 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, pubID
);
2550 if (entry
== NULL
) {
2555 if (entry
->type
== SGML_CATA_PUBLIC
) {
2566 * xmlCatalogGetSGMLSystem:
2567 * @catal: an SGML catalog hash
2568 * @sysID: the system ID string
2570 * Try to lookup the catalog local reference for a system ID
2572 * Returns the local resource if found or NULL otherwise.
2574 static const xmlChar
*
2575 xmlCatalogGetSGMLSystem(xmlHashTablePtr catal
, const xmlChar
*sysID
) {
2576 xmlCatalogEntryPtr entry
;
2581 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, sysID
);
2584 if (entry
->type
== SGML_CATA_SYSTEM
)
2590 * xmlCatalogSGMLResolve:
2591 * @catal: the SGML catalog
2592 * @pubID: the public ID string
2593 * @sysID: the system ID string
2595 * Do a complete resolution lookup of an External Identifier
2597 * Returns the URI of the resource or NULL if not found
2599 static const xmlChar
*
2600 xmlCatalogSGMLResolve(xmlCatalogPtr catal
, const xmlChar
*pubID
,
2601 const xmlChar
*sysID
) {
2602 const xmlChar
*ret
= NULL
;
2604 if (catal
->sgml
== NULL
)
2608 ret
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2612 ret
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2618 /************************************************************************
2620 * Specific Public interfaces *
2622 ************************************************************************/
2625 * xmlLoadSGMLSuperCatalog:
2626 * @filename: a file path
2628 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2629 * references. This is only needed for manipulating SGML Super Catalogs
2630 * like adding and removing CATALOG or DELEGATE entries.
2632 * Returns the catalog parsed or NULL in case of error
2635 xmlLoadSGMLSuperCatalog(const char *filename
)
2638 xmlCatalogPtr catal
;
2641 content
= xmlLoadFileContent(filename
);
2642 if (content
== NULL
)
2645 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2646 if (catal
== NULL
) {
2651 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 1);
2654 xmlFreeCatalog(catal
);
2662 * @filename: a file path
2664 * Load the catalog and build the associated data structures.
2665 * This can be either an XML Catalog or an SGML Catalog
2666 * It will recurse in SGML CATALOG entries. On the other hand XML
2667 * Catalogs are not handled recursively.
2669 * Returns the catalog parsed or NULL in case of error
2672 xmlLoadACatalog(const char *filename
)
2676 xmlCatalogPtr catal
;
2679 content
= xmlLoadFileContent(filename
);
2680 if (content
== NULL
)
2686 while ((*first
!= 0) && (*first
!= '-') && (*first
!= '<') &&
2687 (!(((*first
>= 'A') && (*first
<= 'Z')) ||
2688 ((*first
>= 'a') && (*first
<= 'z')))))
2691 if (*first
!= '<') {
2692 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2693 if (catal
== NULL
) {
2697 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2699 xmlFreeCatalog(catal
);
2704 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2705 if (catal
== NULL
) {
2709 catal
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2710 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2719 * @filename: a file path
2721 * Load the catalog and expand the existing catal structure.
2722 * This can be either an XML Catalog or an SGML Catalog
2724 * Returns 0 in case of success, -1 in case of error
2727 xmlExpandCatalog(xmlCatalogPtr catal
, const char *filename
)
2731 if ((catal
== NULL
) || (filename
== NULL
))
2735 if (catal
->type
== XML_SGML_CATALOG_TYPE
) {
2738 content
= xmlLoadFileContent(filename
);
2739 if (content
== NULL
)
2742 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2749 xmlCatalogEntryPtr tmp
, cur
;
2750 tmp
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2751 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2757 while (cur
->next
!= NULL
) cur
= cur
->next
;
2765 * xmlACatalogResolveSystem:
2767 * @sysID: the system ID string
2769 * Try to lookup the catalog resource for a system ID
2771 * Returns the resource if found or NULL otherwise, the value returned
2772 * must be freed by the caller.
2775 xmlACatalogResolveSystem(xmlCatalogPtr catal
, const xmlChar
*sysID
) {
2776 xmlChar
*ret
= NULL
;
2778 if ((sysID
== NULL
) || (catal
== NULL
))
2781 if (xmlDebugCatalogs
)
2782 xmlGenericError(xmlGenericErrorContext
,
2783 "Resolve sysID %s\n", sysID
);
2785 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2786 ret
= xmlCatalogListXMLResolve(catal
->xml
, NULL
, sysID
);
2787 if (ret
== XML_CATAL_BREAK
)
2790 const xmlChar
*sgml
;
2792 sgml
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2794 ret
= xmlStrdup(sgml
);
2800 * xmlACatalogResolvePublic:
2802 * @pubID: the public ID string
2804 * Try to lookup the catalog local reference associated to a public ID in that catalog
2806 * Returns the local resource if found or NULL otherwise, the value returned
2807 * must be freed by the caller.
2810 xmlACatalogResolvePublic(xmlCatalogPtr catal
, const xmlChar
*pubID
) {
2811 xmlChar
*ret
= NULL
;
2813 if ((pubID
== NULL
) || (catal
== NULL
))
2816 if (xmlDebugCatalogs
)
2817 xmlGenericError(xmlGenericErrorContext
,
2818 "Resolve pubID %s\n", pubID
);
2820 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2821 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, NULL
);
2822 if (ret
== XML_CATAL_BREAK
)
2825 const xmlChar
*sgml
;
2827 sgml
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2829 ret
= xmlStrdup(sgml
);
2835 * xmlACatalogResolve:
2837 * @pubID: the public ID string
2838 * @sysID: the system ID string
2840 * Do a complete resolution lookup of an External Identifier
2842 * Returns the URI of the resource or NULL if not found, it must be freed
2846 xmlACatalogResolve(xmlCatalogPtr catal
, const xmlChar
* pubID
,
2847 const xmlChar
* sysID
)
2849 xmlChar
*ret
= NULL
;
2851 if (((pubID
== NULL
) && (sysID
== NULL
)) || (catal
== NULL
))
2854 if (xmlDebugCatalogs
) {
2855 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
2856 xmlGenericError(xmlGenericErrorContext
,
2857 "Resolve: pubID %s sysID %s\n", pubID
, sysID
);
2858 } else if (pubID
!= NULL
) {
2859 xmlGenericError(xmlGenericErrorContext
,
2860 "Resolve: pubID %s\n", pubID
);
2862 xmlGenericError(xmlGenericErrorContext
,
2863 "Resolve: sysID %s\n", sysID
);
2867 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2868 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, sysID
);
2869 if (ret
== XML_CATAL_BREAK
)
2872 const xmlChar
*sgml
;
2874 sgml
= xmlCatalogSGMLResolve(catal
, pubID
, sysID
);
2876 ret
= xmlStrdup(sgml
);
2882 * xmlACatalogResolveURI:
2886 * Do a complete resolution lookup of an URI
2888 * Returns the URI of the resource or NULL if not found, it must be freed
2892 xmlACatalogResolveURI(xmlCatalogPtr catal
, const xmlChar
*URI
) {
2893 xmlChar
*ret
= NULL
;
2895 if ((URI
== NULL
) || (catal
== NULL
))
2898 if (xmlDebugCatalogs
)
2899 xmlGenericError(xmlGenericErrorContext
,
2900 "Resolve URI %s\n", URI
);
2902 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2903 ret
= xmlCatalogListXMLResolveURI(catal
->xml
, URI
);
2904 if (ret
== XML_CATAL_BREAK
)
2907 const xmlChar
*sgml
;
2909 sgml
= xmlCatalogSGMLResolve(catal
, NULL
, URI
);
2911 ret
= xmlStrdup(sgml
);
2916 #ifdef LIBXML_OUTPUT_ENABLED
2922 * Dump the given catalog to the given file.
2925 xmlACatalogDump(xmlCatalogPtr catal
, FILE *out
) {
2926 if ((out
== NULL
) || (catal
== NULL
))
2929 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2930 xmlDumpXMLCatalog(out
, catal
->xml
);
2932 xmlHashScan(catal
->sgml
, xmlCatalogDumpEntry
, out
);
2935 #endif /* LIBXML_OUTPUT_ENABLED */
2940 * @type: the type of record to add to the catalog
2941 * @orig: the system, public or prefix to match
2942 * @replace: the replacement value for the match
2944 * Add an entry in the catalog, it may overwrite existing but
2945 * different entries.
2947 * Returns 0 if successful, -1 otherwise
2950 xmlACatalogAdd(xmlCatalogPtr catal
, const xmlChar
* type
,
2951 const xmlChar
* orig
, const xmlChar
* replace
)
2958 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2959 res
= xmlAddXMLCatalog(catal
->xml
, type
, orig
, replace
);
2961 xmlCatalogEntryType cattype
;
2963 cattype
= xmlGetSGMLCatalogEntryType(type
);
2964 if (cattype
!= XML_CATA_NONE
) {
2965 xmlCatalogEntryPtr entry
;
2967 entry
= xmlNewCatalogEntry(cattype
, orig
, replace
, NULL
,
2968 XML_CATA_PREFER_NONE
, NULL
);
2969 if (catal
->sgml
== NULL
)
2970 catal
->sgml
= xmlHashCreate(10);
2971 res
= xmlHashAddEntry(catal
->sgml
, orig
, entry
);
2973 xmlFreeCatalogEntry(entry
, NULL
);
2980 * xmlACatalogRemove:
2982 * @value: the value to remove
2984 * Remove an entry from the catalog
2986 * Returns the number of entries removed if successful, -1 otherwise
2989 xmlACatalogRemove(xmlCatalogPtr catal
, const xmlChar
*value
) {
2992 if ((catal
== NULL
) || (value
== NULL
))
2995 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2996 res
= xmlDelXMLCatalog(catal
->xml
, value
);
2998 res
= xmlHashRemoveEntry(catal
->sgml
, value
, xmlFreeCatalogEntry
);
3007 * @sgml: should this create an SGML catalog
3009 * create a new Catalog.
3011 * Returns the xmlCatalogPtr or NULL in case of error
3014 xmlNewCatalog(int sgml
) {
3015 xmlCatalogPtr catal
= NULL
;
3018 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
,
3019 xmlCatalogDefaultPrefer
);
3020 if ((catal
!= NULL
) && (catal
->sgml
== NULL
))
3021 catal
->sgml
= xmlHashCreate(10);
3023 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3024 xmlCatalogDefaultPrefer
);
3029 * xmlCatalogIsEmpty:
3030 * @catal: should this create an SGML catalog
3032 * Check is a catalog is empty
3034 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3037 xmlCatalogIsEmpty(xmlCatalogPtr catal
) {
3041 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
3042 if (catal
->xml
== NULL
)
3044 if ((catal
->xml
->type
!= XML_CATA_CATALOG
) &&
3045 (catal
->xml
->type
!= XML_CATA_BROKEN_CATALOG
))
3047 if (catal
->xml
->children
== NULL
)
3053 if (catal
->sgml
== NULL
)
3055 res
= xmlHashSize(catal
->sgml
);
3064 /************************************************************************
3066 * Public interfaces manipulating the global shared default catalog *
3068 ************************************************************************/
3071 * xmlInitializeCatalogData:
3073 * Do the catalog initialization only of global data, doesn't try to load
3074 * any catalog actually.
3075 * this function is not thread safe, catalog initialization should
3076 * preferably be done once at startup
3079 xmlInitializeCatalogData(void) {
3080 if (xmlCatalogInitialized
!= 0)
3083 if (getenv("XML_DEBUG_CATALOG"))
3084 xmlDebugCatalogs
= 1;
3085 xmlCatalogMutex
= xmlNewRMutex();
3087 xmlCatalogInitialized
= 1;
3090 * xmlInitializeCatalog:
3092 * Do the catalog initialization.
3093 * this function is not thread safe, catalog initialization should
3094 * preferably be done once at startup
3097 xmlInitializeCatalog(void) {
3098 if (xmlCatalogInitialized
!= 0)
3101 xmlInitializeCatalogData();
3102 xmlRMutexLock(xmlCatalogMutex
);
3104 if (getenv("XML_DEBUG_CATALOG"))
3105 xmlDebugCatalogs
= 1;
3107 if (xmlDefaultCatalog
== NULL
) {
3108 const char *catalogs
;
3110 const char *cur
, *paths
;
3111 xmlCatalogPtr catal
;
3112 xmlCatalogEntryPtr
*nextent
;
3114 catalogs
= (const char *) getenv("XML_CATALOG_FILES");
3115 if (catalogs
== NULL
)
3116 #if defined(_WIN32) && defined(_MSC_VER)
3119 hmodule
= GetModuleHandleA("libxml2.dll");
3120 if (hmodule
== NULL
)
3121 hmodule
= GetModuleHandleA(NULL
);
3122 if (hmodule
!= NULL
) {
3124 unsigned long len
= GetModuleFileNameA(hmodule
, buf
, 255);
3126 char* p
= &(buf
[len
]);
3127 while (*p
!= '\\' && p
> buf
)
3131 strncpy(p
, "\\..\\etc\\catalog", 255 - (p
- buf
));
3132 uri
= xmlCanonicPath((const xmlChar
*)buf
);
3134 strncpy(XML_XML_DEFAULT_CATALOG
, (char* )uri
, 255);
3140 catalogs
= XML_XML_DEFAULT_CATALOG
;
3143 catalogs
= XML_XML_DEFAULT_CATALOG
;
3146 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3147 xmlCatalogDefaultPrefer
);
3148 if (catal
!= NULL
) {
3149 /* the XML_CATALOG_FILES envvar is allowed to contain a
3150 space-separated list of entries. */
3152 nextent
= &catal
->xml
;
3153 while (*cur
!= '\0') {
3154 while (xmlIsBlank_ch(*cur
))
3158 while ((*cur
!= 0) && (!xmlIsBlank_ch(*cur
)))
3160 path
= (char *) xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3162 *nextent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3163 NULL
, BAD_CAST path
, xmlCatalogDefaultPrefer
, NULL
);
3164 if (*nextent
!= NULL
)
3165 nextent
= &((*nextent
)->next
);
3170 xmlDefaultCatalog
= catal
;
3174 xmlRMutexUnlock(xmlCatalogMutex
);
3180 * @filename: a file path
3182 * Load the catalog and makes its definitions effective for the default
3183 * external entity loader. It will recurse in SGML CATALOG entries.
3184 * this function is not thread safe, catalog initialization should
3185 * preferably be done once at startup
3187 * Returns 0 in case of success -1 in case of error
3190 xmlLoadCatalog(const char *filename
)
3193 xmlCatalogPtr catal
;
3195 if (!xmlCatalogInitialized
)
3196 xmlInitializeCatalogData();
3198 xmlRMutexLock(xmlCatalogMutex
);
3200 if (xmlDefaultCatalog
== NULL
) {
3201 catal
= xmlLoadACatalog(filename
);
3202 if (catal
== NULL
) {
3203 xmlRMutexUnlock(xmlCatalogMutex
);
3207 xmlDefaultCatalog
= catal
;
3208 xmlRMutexUnlock(xmlCatalogMutex
);
3212 ret
= xmlExpandCatalog(xmlDefaultCatalog
, filename
);
3213 xmlRMutexUnlock(xmlCatalogMutex
);
3219 * @pathss: a list of directories separated by a colon or a space.
3221 * Load the catalogs and makes their definitions effective for the default
3222 * external entity loader.
3223 * this function is not thread safe, catalog initialization should
3224 * preferably be done once at startup
3227 xmlLoadCatalogs(const char *pathss
) {
3240 while (xmlIsBlank_ch(*cur
)) cur
++;
3243 while ((*cur
!= 0) && (*cur
!= PATH_SEPARATOR
) && (!xmlIsBlank_ch(*cur
)))
3245 path
= xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3248 iLen
= strlen((const char*)path
);
3249 for(i
= 0; i
< iLen
; i
++) {
3250 if(path
[i
] == '\\') {
3255 xmlLoadCatalog((const char *) path
);
3259 while (*cur
== PATH_SEPARATOR
)
3265 * xmlCatalogCleanup:
3267 * Free up all the memory associated with catalogs
3270 xmlCatalogCleanup(void) {
3271 if (xmlCatalogInitialized
== 0)
3274 xmlRMutexLock(xmlCatalogMutex
);
3275 if (xmlDebugCatalogs
)
3276 xmlGenericError(xmlGenericErrorContext
,
3277 "Catalogs cleanup\n");
3278 if (xmlCatalogXMLFiles
!= NULL
)
3279 xmlHashFree(xmlCatalogXMLFiles
, xmlFreeCatalogHashEntryList
);
3280 xmlCatalogXMLFiles
= NULL
;
3281 if (xmlDefaultCatalog
!= NULL
)
3282 xmlFreeCatalog(xmlDefaultCatalog
);
3283 xmlDefaultCatalog
= NULL
;
3284 xmlDebugCatalogs
= 0;
3285 xmlCatalogInitialized
= 0;
3286 xmlRMutexUnlock(xmlCatalogMutex
);
3287 xmlFreeRMutex(xmlCatalogMutex
);
3291 * xmlCatalogResolveSystem:
3292 * @sysID: the system ID string
3294 * Try to lookup the catalog resource for a system ID
3296 * Returns the resource if found or NULL otherwise, the value returned
3297 * must be freed by the caller.
3300 xmlCatalogResolveSystem(const xmlChar
*sysID
) {
3303 if (!xmlCatalogInitialized
)
3304 xmlInitializeCatalog();
3306 ret
= xmlACatalogResolveSystem(xmlDefaultCatalog
, sysID
);
3311 * xmlCatalogResolvePublic:
3312 * @pubID: the public ID string
3314 * Try to lookup the catalog reference associated to a public ID
3316 * Returns the resource if found or NULL otherwise, the value returned
3317 * must be freed by the caller.
3320 xmlCatalogResolvePublic(const xmlChar
*pubID
) {
3323 if (!xmlCatalogInitialized
)
3324 xmlInitializeCatalog();
3326 ret
= xmlACatalogResolvePublic(xmlDefaultCatalog
, pubID
);
3331 * xmlCatalogResolve:
3332 * @pubID: the public ID string
3333 * @sysID: the system ID string
3335 * Do a complete resolution lookup of an External Identifier
3337 * Returns the URI of the resource or NULL if not found, it must be freed
3341 xmlCatalogResolve(const xmlChar
*pubID
, const xmlChar
*sysID
) {
3344 if (!xmlCatalogInitialized
)
3345 xmlInitializeCatalog();
3347 ret
= xmlACatalogResolve(xmlDefaultCatalog
, pubID
, sysID
);
3352 * xmlCatalogResolveURI:
3355 * Do a complete resolution lookup of an URI
3357 * Returns the URI of the resource or NULL if not found, it must be freed
3361 xmlCatalogResolveURI(const xmlChar
*URI
) {
3364 if (!xmlCatalogInitialized
)
3365 xmlInitializeCatalog();
3367 ret
= xmlACatalogResolveURI(xmlDefaultCatalog
, URI
);
3371 #ifdef LIBXML_OUTPUT_ENABLED
3376 * Dump all the global catalog content to the given file.
3379 xmlCatalogDump(FILE *out
) {
3383 if (!xmlCatalogInitialized
)
3384 xmlInitializeCatalog();
3386 xmlACatalogDump(xmlDefaultCatalog
, out
);
3388 #endif /* LIBXML_OUTPUT_ENABLED */
3392 * @type: the type of record to add to the catalog
3393 * @orig: the system, public or prefix to match
3394 * @replace: the replacement value for the match
3396 * Add an entry in the catalog, it may overwrite existing but
3397 * different entries.
3398 * If called before any other catalog routine, allows to override the
3399 * default shared catalog put in place by xmlInitializeCatalog();
3401 * Returns 0 if successful, -1 otherwise
3404 xmlCatalogAdd(const xmlChar
*type
, const xmlChar
*orig
, const xmlChar
*replace
) {
3407 if (!xmlCatalogInitialized
)
3408 xmlInitializeCatalogData();
3410 xmlRMutexLock(xmlCatalogMutex
);
3412 * Specific case where one want to override the default catalog
3413 * put in place by xmlInitializeCatalog();
3415 if ((xmlDefaultCatalog
== NULL
) &&
3416 (xmlStrEqual(type
, BAD_CAST
"catalog"))) {
3417 xmlDefaultCatalog
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3418 xmlCatalogDefaultPrefer
);
3419 if (xmlDefaultCatalog
!= NULL
) {
3420 xmlDefaultCatalog
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3421 orig
, NULL
, xmlCatalogDefaultPrefer
, NULL
);
3423 xmlRMutexUnlock(xmlCatalogMutex
);
3427 res
= xmlACatalogAdd(xmlDefaultCatalog
, type
, orig
, replace
);
3428 xmlRMutexUnlock(xmlCatalogMutex
);
3434 * @value: the value to remove
3436 * Remove an entry from the catalog
3438 * Returns the number of entries removed if successful, -1 otherwise
3441 xmlCatalogRemove(const xmlChar
*value
) {
3444 if (!xmlCatalogInitialized
)
3445 xmlInitializeCatalog();
3447 xmlRMutexLock(xmlCatalogMutex
);
3448 res
= xmlACatalogRemove(xmlDefaultCatalog
, value
);
3449 xmlRMutexUnlock(xmlCatalogMutex
);
3454 * xmlCatalogConvert:
3456 * Convert all the SGML catalog entries as XML ones
3458 * Returns the number of entries converted if successful, -1 otherwise
3461 xmlCatalogConvert(void) {
3464 if (!xmlCatalogInitialized
)
3465 xmlInitializeCatalog();
3467 xmlRMutexLock(xmlCatalogMutex
);
3468 res
= xmlConvertSGMLCatalog(xmlDefaultCatalog
);
3469 xmlRMutexUnlock(xmlCatalogMutex
);
3473 /************************************************************************
3475 * Public interface manipulating the common preferences *
3477 ************************************************************************/
3480 * xmlCatalogGetDefaults:
3482 * Used to get the user preference w.r.t. to what catalogs should
3485 * Returns the current xmlCatalogAllow value
3488 xmlCatalogGetDefaults(void) {
3489 return(xmlCatalogDefaultAllow
);
3493 * xmlCatalogSetDefaults:
3494 * @allow: what catalogs should be accepted
3496 * Used to set the user preference w.r.t. to what catalogs should
3500 xmlCatalogSetDefaults(xmlCatalogAllow allow
) {
3501 if (xmlDebugCatalogs
) {
3503 case XML_CATA_ALLOW_NONE
:
3504 xmlGenericError(xmlGenericErrorContext
,
3505 "Disabling catalog usage\n");
3507 case XML_CATA_ALLOW_GLOBAL
:
3508 xmlGenericError(xmlGenericErrorContext
,
3509 "Allowing only global catalogs\n");
3511 case XML_CATA_ALLOW_DOCUMENT
:
3512 xmlGenericError(xmlGenericErrorContext
,
3513 "Allowing only catalogs from the document\n");
3515 case XML_CATA_ALLOW_ALL
:
3516 xmlGenericError(xmlGenericErrorContext
,
3517 "Allowing all catalogs\n");
3521 xmlCatalogDefaultAllow
= allow
;
3525 * xmlCatalogSetDefaultPrefer:
3526 * @prefer: the default preference for delegation
3528 * Allows to set the preference between public and system for deletion
3529 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3530 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3532 * Returns the previous value of the default preference for delegation
3535 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer
) {
3536 xmlCatalogPrefer ret
= xmlCatalogDefaultPrefer
;
3538 if (prefer
== XML_CATA_PREFER_NONE
)
3541 if (xmlDebugCatalogs
) {
3543 case XML_CATA_PREFER_PUBLIC
:
3544 xmlGenericError(xmlGenericErrorContext
,
3545 "Setting catalog preference to PUBLIC\n");
3547 case XML_CATA_PREFER_SYSTEM
:
3548 xmlGenericError(xmlGenericErrorContext
,
3549 "Setting catalog preference to SYSTEM\n");
3555 xmlCatalogDefaultPrefer
= prefer
;
3560 * xmlCatalogSetDebug:
3561 * @level: the debug level of catalogs required
3563 * Used to set the debug level for catalog operation, 0 disable
3564 * debugging, 1 enable it
3566 * Returns the previous value of the catalog debugging level
3569 xmlCatalogSetDebug(int level
) {
3570 int ret
= xmlDebugCatalogs
;
3573 xmlDebugCatalogs
= 0;
3575 xmlDebugCatalogs
= level
;
3579 /************************************************************************
3581 * Minimal interfaces used for per-document catalogs by the parser *
3583 ************************************************************************/
3586 * xmlCatalogFreeLocal:
3587 * @catalogs: a document's list of catalogs
3589 * Free up the memory associated to the catalog list
3592 xmlCatalogFreeLocal(void *catalogs
) {
3593 xmlCatalogEntryPtr catal
;
3595 if (!xmlCatalogInitialized
)
3596 xmlInitializeCatalog();
3598 catal
= (xmlCatalogEntryPtr
) catalogs
;
3600 xmlFreeCatalogEntryList(catal
);
3605 * xmlCatalogAddLocal:
3606 * @catalogs: a document's list of catalogs
3607 * @URL: the URL to a new local catalog
3609 * Add the new entry to the catalog list
3611 * Returns the updated list
3614 xmlCatalogAddLocal(void *catalogs
, const xmlChar
*URL
) {
3615 xmlCatalogEntryPtr catal
, add
;
3617 if (!xmlCatalogInitialized
)
3618 xmlInitializeCatalog();
3623 if (xmlDebugCatalogs
)
3624 xmlGenericError(xmlGenericErrorContext
,
3625 "Adding document catalog %s\n", URL
);
3627 add
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
, URL
, NULL
,
3628 xmlCatalogDefaultPrefer
, NULL
);
3632 catal
= (xmlCatalogEntryPtr
) catalogs
;
3634 return((void *) add
);
3636 while (catal
->next
!= NULL
)
3637 catal
= catal
->next
;
3643 * xmlCatalogLocalResolve:
3644 * @catalogs: a document's list of catalogs
3645 * @pubID: the public ID string
3646 * @sysID: the system ID string
3648 * Do a complete resolution lookup of an External Identifier using a
3649 * document's private catalog list
3651 * Returns the URI of the resource or NULL if not found, it must be freed
3655 xmlCatalogLocalResolve(void *catalogs
, const xmlChar
*pubID
,
3656 const xmlChar
*sysID
) {
3657 xmlCatalogEntryPtr catal
;
3660 if (!xmlCatalogInitialized
)
3661 xmlInitializeCatalog();
3663 if ((pubID
== NULL
) && (sysID
== NULL
))
3666 if (xmlDebugCatalogs
) {
3667 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
3668 xmlGenericError(xmlGenericErrorContext
,
3669 "Local Resolve: pubID %s sysID %s\n", pubID
, sysID
);
3670 } else if (pubID
!= NULL
) {
3671 xmlGenericError(xmlGenericErrorContext
,
3672 "Local Resolve: pubID %s\n", pubID
);
3674 xmlGenericError(xmlGenericErrorContext
,
3675 "Local Resolve: sysID %s\n", sysID
);
3679 catal
= (xmlCatalogEntryPtr
) catalogs
;
3682 ret
= xmlCatalogListXMLResolve(catal
, pubID
, sysID
);
3683 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3689 * xmlCatalogLocalResolveURI:
3690 * @catalogs: a document's list of catalogs
3693 * Do a complete resolution lookup of an URI using a
3694 * document's private catalog list
3696 * Returns the URI of the resource or NULL if not found, it must be freed
3700 xmlCatalogLocalResolveURI(void *catalogs
, const xmlChar
*URI
) {
3701 xmlCatalogEntryPtr catal
;
3704 if (!xmlCatalogInitialized
)
3705 xmlInitializeCatalog();
3710 if (xmlDebugCatalogs
)
3711 xmlGenericError(xmlGenericErrorContext
,
3712 "Resolve URI %s\n", URI
);
3714 catal
= (xmlCatalogEntryPtr
) catalogs
;
3717 ret
= xmlCatalogListXMLResolveURI(catal
, URI
);
3718 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3723 /************************************************************************
3725 * Deprecated interfaces *
3727 ************************************************************************/
3729 * xmlCatalogGetSystem:
3730 * @sysID: the system ID string
3732 * Try to lookup the catalog reference associated to a system ID
3733 * DEPRECATED, use xmlCatalogResolveSystem()
3735 * Returns the resource if found or NULL otherwise.
3738 xmlCatalogGetSystem(const xmlChar
*sysID
) {
3740 static xmlChar result
[1000];
3743 if (!xmlCatalogInitialized
)
3744 xmlInitializeCatalog();
3747 xmlGenericError(xmlGenericErrorContext
,
3748 "Use of deprecated xmlCatalogGetSystem() call\n");
3756 * Check first the XML catalogs
3758 if (xmlDefaultCatalog
!= NULL
) {
3759 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, NULL
, sysID
);
3760 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3761 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3762 result
[sizeof(result
) - 1] = 0;
3767 if (xmlDefaultCatalog
!= NULL
)
3768 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog
->sgml
, sysID
));
3773 * xmlCatalogGetPublic:
3774 * @pubID: the public ID string
3776 * Try to lookup the catalog reference associated to a public ID
3777 * DEPRECATED, use xmlCatalogResolvePublic()
3779 * Returns the resource if found or NULL otherwise.
3782 xmlCatalogGetPublic(const xmlChar
*pubID
) {
3784 static xmlChar result
[1000];
3787 if (!xmlCatalogInitialized
)
3788 xmlInitializeCatalog();
3791 xmlGenericError(xmlGenericErrorContext
,
3792 "Use of deprecated xmlCatalogGetPublic() call\n");
3800 * Check first the XML catalogs
3802 if (xmlDefaultCatalog
!= NULL
) {
3803 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, pubID
, NULL
);
3804 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3805 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3806 result
[sizeof(result
) - 1] = 0;
3811 if (xmlDefaultCatalog
!= NULL
)
3812 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog
->sgml
, pubID
));
3816 #endif /* LIBXML_CATALOG_ENABLED */