2 * catalog.c: set of generic Catalog related routines
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
7 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
10 * See Copyright for the status of this software.
12 * Daniel.Veillard@imag.fr
18 #ifdef LIBXML_CATALOG_ENABLED
19 #ifdef HAVE_SYS_TYPES_H
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_STAT_H
35 #include <libxml/xmlmemory.h>
36 #include <libxml/hash.h>
37 #include <libxml/uri.h>
38 #include <libxml/parserInternals.h>
39 #include <libxml/catalog.h>
40 #include <libxml/xmlerror.h>
41 #include <libxml/threads.h>
42 #include <libxml/globals.h>
44 #define MAX_DELEGATE 50
45 #define MAX_CATAL_DEPTH 50
48 # define PATH_SEAPARATOR ';'
50 # define PATH_SEAPARATOR ':'
56 * macro to flag unimplemented blocks
57 * XML_CATALOG_PREFER user env to select between system/public prefered
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:///etc/xml/catalog"
73 #ifndef XML_SGML_DEFAULT_CATALOG
74 #define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
77 #if defined(_WIN32) && defined(_MSC_VER)
78 #undef XML_XML_DEFAULT_CATALOG
79 static char XML_XML_DEFAULT_CATALOG
[256] = "file:///etc/xml/catalog";
80 #if defined(_WIN32_WCE)
81 /* Windows CE don't have a A variant */
82 #define GetModuleHandleA GetModuleHandle
83 #define GetModuleFileNameA GetModuleFileName
85 void* __stdcall
GetModuleHandleA(const char*);
86 unsigned long __stdcall
GetModuleFileNameA(void*, char*, unsigned long);
90 static xmlChar
*xmlCatalogNormalizePublic(const xmlChar
*pubID
);
91 static int xmlExpandCatalog(xmlCatalogPtr catal
, const char *filename
);
93 /************************************************************************
95 * Types, all private *
97 ************************************************************************/
100 XML_CATA_REMOVED
= -1,
103 XML_CATA_BROKEN_CATALOG
,
104 XML_CATA_NEXT_CATALOG
,
108 XML_CATA_REWRITE_SYSTEM
,
109 XML_CATA_DELEGATE_PUBLIC
,
110 XML_CATA_DELEGATE_SYSTEM
,
112 XML_CATA_REWRITE_URI
,
113 XML_CATA_DELEGATE_URI
,
126 } xmlCatalogEntryType
;
128 typedef struct _xmlCatalogEntry xmlCatalogEntry
;
129 typedef xmlCatalogEntry
*xmlCatalogEntryPtr
;
130 struct _xmlCatalogEntry
{
131 struct _xmlCatalogEntry
*next
;
132 struct _xmlCatalogEntry
*parent
;
133 struct _xmlCatalogEntry
*children
;
134 xmlCatalogEntryType type
;
137 xmlChar
*URL
; /* The expanded URL using the base */
138 xmlCatalogPrefer prefer
;
141 struct _xmlCatalogEntry
*group
;
145 XML_XML_CATALOG_TYPE
= 1,
146 XML_SGML_CATALOG_TYPE
149 #define XML_MAX_SGML_CATA_DEPTH 10
151 xmlCatalogType type
; /* either XML or SGML */
154 * SGML Catalogs are stored as a simple hash table of catalog entries
155 * Catalog stack to check against overflows when building the
158 char *catalTab
[XML_MAX_SGML_CATA_DEPTH
]; /* stack of catals */
159 int catalNr
; /* Number of current catal streams */
160 int catalMax
; /* Max number of catal streams */
161 xmlHashTablePtr sgml
;
164 * XML Catalogs are stored as a tree of Catalog entries
166 xmlCatalogPrefer prefer
;
167 xmlCatalogEntryPtr xml
;
170 /************************************************************************
174 ************************************************************************/
177 * Those are preferences
179 static int xmlDebugCatalogs
= 0; /* used for debugging */
180 static xmlCatalogAllow xmlCatalogDefaultAllow
= XML_CATA_ALLOW_ALL
;
181 static xmlCatalogPrefer xmlCatalogDefaultPrefer
= XML_CATA_PREFER_PUBLIC
;
184 * Hash table containing all the trees of XML catalogs parsed by
187 static xmlHashTablePtr xmlCatalogXMLFiles
= NULL
;
190 * The default catalog in use by the application
192 static xmlCatalogPtr xmlDefaultCatalog
= NULL
;
195 * A mutex for modifying the shared global catalog(s)
196 * xmlDefaultCatalog tree.
197 * It also protects xmlCatalogXMLFiles
198 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
200 static xmlRMutexPtr xmlCatalogMutex
= NULL
;
203 * Whether the catalog support was initialized.
205 static int xmlCatalogInitialized
= 0;
207 /************************************************************************
209 * Catalog error handlers *
211 ************************************************************************/
214 * xmlCatalogErrMemory:
215 * @extra: extra informations
217 * Handle an out of memory condition
220 xmlCatalogErrMemory(const char *extra
)
222 __xmlRaiseError(NULL
, NULL
, NULL
, NULL
, NULL
, XML_FROM_CATALOG
,
223 XML_ERR_NO_MEMORY
, XML_ERR_ERROR
, NULL
, 0,
224 extra
, NULL
, NULL
, 0, 0,
225 "Memory allocation failed : %s\n", extra
);
230 * @catal: the Catalog entry
231 * @node: the context node
232 * @msg: the error message
233 * @extra: extra informations
235 * Handle a catalog error
238 xmlCatalogErr(xmlCatalogEntryPtr catal
, xmlNodePtr node
, int error
,
239 const char *msg
, const xmlChar
*str1
, const xmlChar
*str2
,
242 __xmlRaiseError(NULL
, NULL
, NULL
, catal
, node
, XML_FROM_CATALOG
,
243 error
, XML_ERR_ERROR
, NULL
, 0,
244 (const char *) str1
, (const char *) str2
,
245 (const char *) str3
, 0, 0,
246 msg
, str1
, str2
, str3
);
250 /************************************************************************
252 * Allocation and Freeing *
254 ************************************************************************/
257 * xmlNewCatalogEntry:
258 * @type: type of entry
259 * @name: name of the entry
260 * @value: value of the entry
261 * @prefer: the PUBLIC vs. SYSTEM current preference value
262 * @group: for members of a group, the group entry
264 * create a new Catalog entry, this type is shared both by XML and
265 * SGML catalogs, but the acceptable types values differs.
267 * Returns the xmlCatalogEntryPtr or NULL in case of error
269 static xmlCatalogEntryPtr
270 xmlNewCatalogEntry(xmlCatalogEntryType type
, const xmlChar
*name
,
271 const xmlChar
*value
, const xmlChar
*URL
, xmlCatalogPrefer prefer
,
272 xmlCatalogEntryPtr group
) {
273 xmlCatalogEntryPtr ret
;
274 xmlChar
*normid
= NULL
;
276 ret
= (xmlCatalogEntryPtr
) xmlMalloc(sizeof(xmlCatalogEntry
));
278 xmlCatalogErrMemory("allocating catalog entry");
283 ret
->children
= NULL
;
285 if (type
== XML_CATA_PUBLIC
|| type
== XML_CATA_DELEGATE_PUBLIC
) {
286 normid
= xmlCatalogNormalizePublic(name
);
288 name
= (*normid
!= 0 ? normid
: NULL
);
291 ret
->name
= xmlStrdup(name
);
297 ret
->value
= xmlStrdup(value
);
303 ret
->URL
= xmlStrdup(URL
);
306 ret
->prefer
= prefer
;
314 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret
);
317 * xmlFreeCatalogEntry:
318 * @ret: a Catalog entry
320 * Free the memory allocated to a Catalog entry
323 xmlFreeCatalogEntry(xmlCatalogEntryPtr ret
) {
327 * Entries stored in the file hash must be deallocated
328 * only by the file hash cleaner !
330 if (ret
->dealloc
== 1)
333 if (xmlDebugCatalogs
) {
334 if (ret
->name
!= NULL
)
335 xmlGenericError(xmlGenericErrorContext
,
336 "Free catalog entry %s\n", ret
->name
);
337 else if (ret
->value
!= NULL
)
338 xmlGenericError(xmlGenericErrorContext
,
339 "Free catalog entry %s\n", ret
->value
);
341 xmlGenericError(xmlGenericErrorContext
,
342 "Free catalog entry\n");
345 if (ret
->name
!= NULL
)
347 if (ret
->value
!= NULL
)
349 if (ret
->URL
!= NULL
)
355 * xmlFreeCatalogEntryList:
356 * @ret: a Catalog entry list
358 * Free the memory allocated to a full chained list of Catalog entries
361 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret
) {
362 xmlCatalogEntryPtr next
;
364 while (ret
!= NULL
) {
366 xmlFreeCatalogEntry(ret
);
372 * xmlFreeCatalogHashEntryList:
373 * @ret: a Catalog entry list
375 * Free the memory allocated to list of Catalog entries from the
379 xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal
) {
380 xmlCatalogEntryPtr children
, next
;
385 children
= catal
->children
;
386 while (children
!= NULL
) {
387 next
= children
->next
;
388 children
->dealloc
= 0;
389 children
->children
= NULL
;
390 xmlFreeCatalogEntry(children
);
394 xmlFreeCatalogEntry(catal
);
398 * xmlCreateNewCatalog:
399 * @type: type of catalog
400 * @prefer: the PUBLIC vs. SYSTEM current preference value
402 * create a new Catalog, this type is shared both by XML and
403 * SGML catalogs, but the acceptable types values differs.
405 * Returns the xmlCatalogPtr or NULL in case of error
408 xmlCreateNewCatalog(xmlCatalogType type
, xmlCatalogPrefer prefer
) {
411 ret
= (xmlCatalogPtr
) xmlMalloc(sizeof(xmlCatalog
));
413 xmlCatalogErrMemory("allocating catalog");
416 memset(ret
, 0, sizeof(xmlCatalog
));
419 ret
->catalMax
= XML_MAX_SGML_CATA_DEPTH
;
420 ret
->prefer
= prefer
;
421 if (ret
->type
== XML_SGML_CATALOG_TYPE
)
422 ret
->sgml
= xmlHashCreate(10);
430 * Free the memory allocated to a Catalog
433 xmlFreeCatalog(xmlCatalogPtr catal
) {
436 if (catal
->xml
!= NULL
)
437 xmlFreeCatalogEntryList(catal
->xml
);
438 if (catal
->sgml
!= NULL
)
439 xmlHashFree(catal
->sgml
,
440 (xmlHashDeallocator
) xmlFreeCatalogEntry
);
444 /************************************************************************
446 * Serializing Catalogs *
448 ************************************************************************/
450 #ifdef LIBXML_OUTPUT_ENABLED
452 * xmlCatalogDumpEntry:
453 * @entry: the catalog entry
456 * Serialize an SGML Catalog entry
459 xmlCatalogDumpEntry(xmlCatalogEntryPtr entry
, FILE *out
) {
460 if ((entry
== NULL
) || (out
== NULL
))
462 switch (entry
->type
) {
463 case SGML_CATA_ENTITY
:
464 fprintf(out
, "ENTITY "); break;
465 case SGML_CATA_PENTITY
:
466 fprintf(out
, "ENTITY %%"); break;
467 case SGML_CATA_DOCTYPE
:
468 fprintf(out
, "DOCTYPE "); break;
469 case SGML_CATA_LINKTYPE
:
470 fprintf(out
, "LINKTYPE "); break;
471 case SGML_CATA_NOTATION
:
472 fprintf(out
, "NOTATION "); break;
473 case SGML_CATA_PUBLIC
:
474 fprintf(out
, "PUBLIC "); break;
475 case SGML_CATA_SYSTEM
:
476 fprintf(out
, "SYSTEM "); break;
477 case SGML_CATA_DELEGATE
:
478 fprintf(out
, "DELEGATE "); break;
480 fprintf(out
, "BASE "); break;
481 case SGML_CATA_CATALOG
:
482 fprintf(out
, "CATALOG "); break;
483 case SGML_CATA_DOCUMENT
:
484 fprintf(out
, "DOCUMENT "); break;
485 case SGML_CATA_SGMLDECL
:
486 fprintf(out
, "SGMLDECL "); break;
490 switch (entry
->type
) {
491 case SGML_CATA_ENTITY
:
492 case SGML_CATA_PENTITY
:
493 case SGML_CATA_DOCTYPE
:
494 case SGML_CATA_LINKTYPE
:
495 case SGML_CATA_NOTATION
:
496 fprintf(out
, "%s", (const char *) entry
->name
); break;
497 case SGML_CATA_PUBLIC
:
498 case SGML_CATA_SYSTEM
:
499 case SGML_CATA_SGMLDECL
:
500 case SGML_CATA_DOCUMENT
:
501 case SGML_CATA_CATALOG
:
503 case SGML_CATA_DELEGATE
:
504 fprintf(out
, "\"%s\"", entry
->name
); break;
508 switch (entry
->type
) {
509 case SGML_CATA_ENTITY
:
510 case SGML_CATA_PENTITY
:
511 case SGML_CATA_DOCTYPE
:
512 case SGML_CATA_LINKTYPE
:
513 case SGML_CATA_NOTATION
:
514 case SGML_CATA_PUBLIC
:
515 case SGML_CATA_SYSTEM
:
516 case SGML_CATA_DELEGATE
:
517 fprintf(out
, " \"%s\"", entry
->value
); break;
525 * xmlDumpXMLCatalogNode:
526 * @catal: top catalog entry
527 * @catalog: pointer to the xml tree
528 * @doc: the containing document
529 * @ns: the current namespace
530 * @cgroup: group node for group members
532 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
535 static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal
, xmlNodePtr catalog
,
536 xmlDocPtr doc
, xmlNsPtr ns
, xmlCatalogEntryPtr cgroup
) {
538 xmlCatalogEntryPtr cur
;
540 * add all the catalog entries
543 while (cur
!= NULL
) {
544 if (cur
->group
== cgroup
) {
546 case XML_CATA_REMOVED
:
548 case XML_CATA_BROKEN_CATALOG
:
549 case XML_CATA_CATALOG
:
555 case XML_CATA_NEXT_CATALOG
:
556 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"nextCatalog", NULL
);
557 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
558 xmlAddChild(catalog
, node
);
563 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"group", NULL
);
564 xmlSetProp(node
, BAD_CAST
"id", cur
->name
);
565 if (cur
->value
!= NULL
) {
567 xns
= xmlSearchNsByHref(doc
, node
, XML_XML_NAMESPACE
);
569 xmlSetNsProp(node
, xns
, BAD_CAST
"base",
572 switch (cur
->prefer
) {
573 case XML_CATA_PREFER_NONE
:
575 case XML_CATA_PREFER_PUBLIC
:
576 xmlSetProp(node
, BAD_CAST
"prefer", BAD_CAST
"public");
578 case XML_CATA_PREFER_SYSTEM
:
579 xmlSetProp(node
, BAD_CAST
"prefer", BAD_CAST
"system");
582 xmlDumpXMLCatalogNode(cur
->next
, node
, doc
, ns
, cur
);
583 xmlAddChild(catalog
, node
);
585 case XML_CATA_PUBLIC
:
586 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"public", NULL
);
587 xmlSetProp(node
, BAD_CAST
"publicId", cur
->name
);
588 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
589 xmlAddChild(catalog
, node
);
591 case XML_CATA_SYSTEM
:
592 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"system", NULL
);
593 xmlSetProp(node
, BAD_CAST
"systemId", cur
->name
);
594 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
595 xmlAddChild(catalog
, node
);
597 case XML_CATA_REWRITE_SYSTEM
:
598 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"rewriteSystem", NULL
);
599 xmlSetProp(node
, BAD_CAST
"systemIdStartString", cur
->name
);
600 xmlSetProp(node
, BAD_CAST
"rewritePrefix", cur
->value
);
601 xmlAddChild(catalog
, node
);
603 case XML_CATA_DELEGATE_PUBLIC
:
604 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegatePublic", NULL
);
605 xmlSetProp(node
, BAD_CAST
"publicIdStartString", cur
->name
);
606 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
607 xmlAddChild(catalog
, node
);
609 case XML_CATA_DELEGATE_SYSTEM
:
610 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegateSystem", NULL
);
611 xmlSetProp(node
, BAD_CAST
"systemIdStartString", cur
->name
);
612 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
613 xmlAddChild(catalog
, node
);
616 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"uri", NULL
);
617 xmlSetProp(node
, BAD_CAST
"name", cur
->name
);
618 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
619 xmlAddChild(catalog
, node
);
621 case XML_CATA_REWRITE_URI
:
622 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"rewriteURI", NULL
);
623 xmlSetProp(node
, BAD_CAST
"uriStartString", cur
->name
);
624 xmlSetProp(node
, BAD_CAST
"rewritePrefix", cur
->value
);
625 xmlAddChild(catalog
, node
);
627 case XML_CATA_DELEGATE_URI
:
628 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegateURI", NULL
);
629 xmlSetProp(node
, BAD_CAST
"uriStartString", cur
->name
);
630 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
631 xmlAddChild(catalog
, node
);
633 case SGML_CATA_SYSTEM
:
634 case SGML_CATA_PUBLIC
:
635 case SGML_CATA_ENTITY
:
636 case SGML_CATA_PENTITY
:
637 case SGML_CATA_DOCTYPE
:
638 case SGML_CATA_LINKTYPE
:
639 case SGML_CATA_NOTATION
:
640 case SGML_CATA_DELEGATE
:
642 case SGML_CATA_CATALOG
:
643 case SGML_CATA_DOCUMENT
:
644 case SGML_CATA_SGMLDECL
:
653 xmlDumpXMLCatalog(FILE *out
, xmlCatalogEntryPtr catal
) {
659 xmlOutputBufferPtr buf
;
664 doc
= xmlNewDoc(NULL
);
667 dtd
= xmlNewDtd(doc
, BAD_CAST
"catalog",
668 BAD_CAST
"-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
669 BAD_CAST
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
671 xmlAddChild((xmlNodePtr
) doc
, (xmlNodePtr
) dtd
);
673 ns
= xmlNewNs(NULL
, XML_CATALOGS_NAMESPACE
, NULL
);
678 catalog
= xmlNewDocNode(doc
, ns
, BAD_CAST
"catalog", NULL
);
679 if (catalog
== NULL
) {
685 xmlAddChild((xmlNodePtr
) doc
, catalog
);
687 xmlDumpXMLCatalogNode(catal
, catalog
, doc
, ns
, NULL
);
692 buf
= xmlOutputBufferCreateFile(out
, NULL
);
697 ret
= xmlSaveFormatFileTo(buf
, doc
, NULL
, 1);
706 #endif /* LIBXML_OUTPUT_ENABLED */
708 /************************************************************************
710 * Converting SGML Catalogs to XML *
712 ************************************************************************/
715 * xmlCatalogConvertEntry:
717 * @catal: pointer to the catalog being converted
719 * Convert one entry from the catalog
722 xmlCatalogConvertEntry(xmlCatalogEntryPtr entry
, xmlCatalogPtr catal
) {
723 if ((entry
== NULL
) || (catal
== NULL
) || (catal
->sgml
== NULL
) ||
724 (catal
->xml
== NULL
))
726 switch (entry
->type
) {
727 case SGML_CATA_ENTITY
:
728 entry
->type
= XML_CATA_PUBLIC
;
730 case SGML_CATA_PENTITY
:
731 entry
->type
= XML_CATA_PUBLIC
;
733 case SGML_CATA_DOCTYPE
:
734 entry
->type
= XML_CATA_PUBLIC
;
736 case SGML_CATA_LINKTYPE
:
737 entry
->type
= XML_CATA_PUBLIC
;
739 case SGML_CATA_NOTATION
:
740 entry
->type
= XML_CATA_PUBLIC
;
742 case SGML_CATA_PUBLIC
:
743 entry
->type
= XML_CATA_PUBLIC
;
745 case SGML_CATA_SYSTEM
:
746 entry
->type
= XML_CATA_SYSTEM
;
748 case SGML_CATA_DELEGATE
:
749 entry
->type
= XML_CATA_DELEGATE_PUBLIC
;
751 case SGML_CATA_CATALOG
:
752 entry
->type
= XML_CATA_CATALOG
;
755 xmlHashRemoveEntry(catal
->sgml
, entry
->name
,
756 (xmlHashDeallocator
) xmlFreeCatalogEntry
);
760 * Conversion successful, remove from the SGML catalog
761 * and add it to the default XML one
763 xmlHashRemoveEntry(catal
->sgml
, entry
->name
, NULL
);
764 entry
->parent
= catal
->xml
;
766 if (catal
->xml
->children
== NULL
)
767 catal
->xml
->children
= entry
;
769 xmlCatalogEntryPtr prev
;
771 prev
= catal
->xml
->children
;
772 while (prev
->next
!= NULL
)
779 * xmlConvertSGMLCatalog:
780 * @catal: the catalog
782 * Convert all the SGML catalog entries as XML ones
784 * Returns the number of entries converted if successful, -1 otherwise
787 xmlConvertSGMLCatalog(xmlCatalogPtr catal
) {
789 if ((catal
== NULL
) || (catal
->type
!= XML_SGML_CATALOG_TYPE
))
792 if (xmlDebugCatalogs
) {
793 xmlGenericError(xmlGenericErrorContext
,
794 "Converting SGML catalog to XML\n");
796 xmlHashScan(catal
->sgml
,
797 (xmlHashScanner
) xmlCatalogConvertEntry
,
802 /************************************************************************
806 ************************************************************************/
809 * xmlCatalogUnWrapURN:
810 * @urn: an "urn:publicid:" to unwrap
812 * Expand the URN into the equivalent Public Identifier
814 * Returns the new identifier or NULL, the string must be deallocated
818 xmlCatalogUnWrapURN(const xmlChar
*urn
) {
819 xmlChar result
[2000];
822 if (xmlStrncmp(urn
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1))
824 urn
+= sizeof(XML_URN_PUBID
) - 1;
827 if (i
> sizeof(result
) - 4)
832 } else if (*urn
== ':') {
836 } else if (*urn
== ';') {
840 } else if (*urn
== '%') {
841 if ((urn
[1] == '2') && (urn
[2] == 'B'))
843 else if ((urn
[1] == '3') && (urn
[2] == 'A'))
845 else if ((urn
[1] == '2') && (urn
[2] == 'F'))
847 else if ((urn
[1] == '3') && (urn
[2] == 'B'))
849 else if ((urn
[1] == '2') && (urn
[2] == '7'))
851 else if ((urn
[1] == '3') && (urn
[2] == 'F'))
853 else if ((urn
[1] == '2') && (urn
[2] == '3'))
855 else if ((urn
[1] == '2') && (urn
[2] == '5'))
870 return(xmlStrdup(result
));
874 * xmlParseCatalogFile:
875 * @filename: the filename
877 * parse an XML file and build a tree. It's like xmlParseFile()
878 * except it bypass all catalog lookups.
880 * Returns the resulting document tree or NULL in case of error
884 xmlParseCatalogFile(const char *filename
) {
886 xmlParserCtxtPtr ctxt
;
887 char *directory
= NULL
;
888 xmlParserInputPtr inputStream
;
889 xmlParserInputBufferPtr buf
;
891 ctxt
= xmlNewParserCtxt();
893 #ifdef LIBXML_SAX1_ENABLED
894 if (xmlDefaultSAXHandler
.error
!= NULL
) {
895 xmlDefaultSAXHandler
.error(NULL
, "out of memory\n");
901 buf
= xmlParserInputBufferCreateFilename(filename
, XML_CHAR_ENCODING_NONE
);
903 xmlFreeParserCtxt(ctxt
);
907 inputStream
= xmlNewInputStream(ctxt
);
908 if (inputStream
== NULL
) {
909 xmlFreeParserCtxt(ctxt
);
913 inputStream
->filename
= (char *) xmlCanonicPath((const xmlChar
*)filename
);
914 inputStream
->buf
= buf
;
915 inputStream
->base
= inputStream
->buf
->buffer
->content
;
916 inputStream
->cur
= inputStream
->buf
->buffer
->content
;
918 &inputStream
->buf
->buffer
->content
[inputStream
->buf
->buffer
->use
];
920 inputPush(ctxt
, inputStream
);
921 if ((ctxt
->directory
== NULL
) && (directory
== NULL
))
922 directory
= xmlParserGetDirectory(filename
);
923 if ((ctxt
->directory
== NULL
) && (directory
!= NULL
))
924 ctxt
->directory
= directory
;
927 ctxt
->loadsubset
= 0;
931 xmlParseDocument(ctxt
);
933 if (ctxt
->wellFormed
)
937 xmlFreeDoc(ctxt
->myDoc
);
940 xmlFreeParserCtxt(ctxt
);
946 * xmlLoadFileContent:
947 * @filename: a file path
949 * Load a file content into memory.
951 * Returns a pointer to the 0 terminated string or NULL in case of error
954 xmlLoadFileContent(const char *filename
)
969 if (filename
== NULL
)
973 if (stat(filename
, &info
) < 0)
978 if ((fd
= open(filename
, O_RDONLY
)) < 0)
980 if ((fd
= fopen(filename
, "rb")) == NULL
)
988 if (fseek(fd
, 0, SEEK_END
) || (size
= ftell(fd
)) == EOF
|| fseek(fd
, 0, SEEK_SET
)) { /* File operations denied? ok, just close and return failure */
993 content
= xmlMallocAtomic(size
+ 10);
994 if (content
== NULL
) {
995 xmlCatalogErrMemory("allocating catalog data");
999 len
= read(fd
, content
, size
);
1001 len
= fread(content
, 1, size
, fd
);
1018 * xmlCatalogNormalizePublic:
1019 * @pubID: the public ID string
1021 * Normalizes the Public Identifier
1023 * Implements 6.2. Public Identifier Normalization
1024 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1026 * Returns the new string or NULL, the string must be deallocated
1030 xmlCatalogNormalizePublic(const xmlChar
*pubID
)
1042 for (p
= pubID
;*p
!= 0 && ok
;p
++) {
1043 if (!xmlIsBlank_ch(*p
))
1045 else if (*p
== 0x20 && !white
)
1050 if (ok
&& !white
) /* is normalized */
1053 ret
= xmlStrdup(pubID
);
1056 for (p
= pubID
;*p
!= 0;p
++) {
1057 if (xmlIsBlank_ch(*p
)) {
1072 /************************************************************************
1074 * The XML Catalog parser *
1076 ************************************************************************/
1078 static xmlCatalogEntryPtr
1079 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
);
1081 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1082 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
);
1084 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1085 const xmlChar
*sysID
);
1087 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
);
1091 * xmlGetXMLCatalogEntryType:
1094 * lookup the internal type associated to an XML catalog entry name
1096 * Returns the type associated with that name
1098 static xmlCatalogEntryType
1099 xmlGetXMLCatalogEntryType(const xmlChar
*name
) {
1100 xmlCatalogEntryType type
= XML_CATA_NONE
;
1101 if (xmlStrEqual(name
, (const xmlChar
*) "system"))
1102 type
= XML_CATA_SYSTEM
;
1103 else if (xmlStrEqual(name
, (const xmlChar
*) "public"))
1104 type
= XML_CATA_PUBLIC
;
1105 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteSystem"))
1106 type
= XML_CATA_REWRITE_SYSTEM
;
1107 else if (xmlStrEqual(name
, (const xmlChar
*) "delegatePublic"))
1108 type
= XML_CATA_DELEGATE_PUBLIC
;
1109 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateSystem"))
1110 type
= XML_CATA_DELEGATE_SYSTEM
;
1111 else if (xmlStrEqual(name
, (const xmlChar
*) "uri"))
1112 type
= XML_CATA_URI
;
1113 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteURI"))
1114 type
= XML_CATA_REWRITE_URI
;
1115 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateURI"))
1116 type
= XML_CATA_DELEGATE_URI
;
1117 else if (xmlStrEqual(name
, (const xmlChar
*) "nextCatalog"))
1118 type
= XML_CATA_NEXT_CATALOG
;
1119 else if (xmlStrEqual(name
, (const xmlChar
*) "catalog"))
1120 type
= XML_CATA_CATALOG
;
1125 * xmlParseXMLCatalogOneNode:
1126 * @cur: the XML node
1127 * @type: the type of Catalog entry
1128 * @name: the name of the node
1129 * @attrName: the attribute holding the value
1130 * @uriAttrName: the attribute holding the URI-Reference
1131 * @prefer: the PUBLIC vs. SYSTEM current preference value
1132 * @cgroup: the group which includes this node
1134 * Finishes the examination of an XML tree node of a catalog and build
1135 * a Catalog entry from it.
1137 * Returns the new Catalog entry node or NULL in case of error.
1139 static xmlCatalogEntryPtr
1140 xmlParseXMLCatalogOneNode(xmlNodePtr cur
, xmlCatalogEntryType type
,
1141 const xmlChar
*name
, const xmlChar
*attrName
,
1142 const xmlChar
*uriAttrName
, xmlCatalogPrefer prefer
,
1143 xmlCatalogEntryPtr cgroup
) {
1146 xmlChar
*nameValue
= NULL
;
1147 xmlChar
*base
= NULL
;
1148 xmlChar
*URL
= NULL
;
1149 xmlCatalogEntryPtr ret
= NULL
;
1151 if (attrName
!= NULL
) {
1152 nameValue
= xmlGetProp(cur
, attrName
);
1153 if (nameValue
== NULL
) {
1154 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1155 "%s entry lacks '%s'\n", name
, attrName
, NULL
);
1159 uriValue
= xmlGetProp(cur
, uriAttrName
);
1160 if (uriValue
== NULL
) {
1161 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1162 "%s entry lacks '%s'\n", name
, uriAttrName
, NULL
);
1166 if (nameValue
!= NULL
)
1168 if (uriValue
!= NULL
)
1173 base
= xmlNodeGetBase(cur
->doc
, cur
);
1174 URL
= xmlBuildURI(uriValue
, base
);
1176 if (xmlDebugCatalogs
> 1) {
1177 if (nameValue
!= NULL
)
1178 xmlGenericError(xmlGenericErrorContext
,
1179 "Found %s: '%s' '%s'\n", name
, nameValue
, URL
);
1181 xmlGenericError(xmlGenericErrorContext
,
1182 "Found %s: '%s'\n", name
, URL
);
1184 ret
= xmlNewCatalogEntry(type
, nameValue
, uriValue
, URL
, prefer
, cgroup
);
1186 xmlCatalogErr(ret
, cur
, XML_CATALOG_ENTRY_BROKEN
,
1187 "%s entry '%s' broken ?: %s\n", name
, uriAttrName
, uriValue
);
1189 if (nameValue
!= NULL
)
1191 if (uriValue
!= NULL
)
1201 * xmlParseXMLCatalogNode:
1202 * @cur: the XML node
1203 * @prefer: the PUBLIC vs. SYSTEM current preference value
1204 * @parent: the parent Catalog entry
1205 * @cgroup: the group which includes this node
1207 * Examines an XML tree node of a catalog and build
1208 * a Catalog entry from it adding it to its parent. The examination can
1212 xmlParseXMLCatalogNode(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1213 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
)
1215 xmlChar
*base
= NULL
;
1216 xmlCatalogEntryPtr entry
= NULL
;
1220 if (xmlStrEqual(cur
->name
, BAD_CAST
"group")) {
1222 xmlCatalogPrefer pref
= XML_CATA_PREFER_NONE
;
1224 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1226 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1227 prefer
= XML_CATA_PREFER_SYSTEM
;
1228 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1229 prefer
= XML_CATA_PREFER_PUBLIC
;
1231 xmlCatalogErr(parent
, cur
, XML_CATALOG_PREFER_VALUE
,
1232 "Invalid value for prefer: '%s'\n",
1238 prop
= xmlGetProp(cur
, BAD_CAST
"id");
1239 base
= xmlGetNsProp(cur
, BAD_CAST
"base", XML_XML_NAMESPACE
);
1240 entry
= xmlNewCatalogEntry(XML_CATA_GROUP
, prop
, base
, NULL
, pref
, cgroup
);
1242 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"public")) {
1243 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_PUBLIC
,
1244 BAD_CAST
"public", BAD_CAST
"publicId", BAD_CAST
"uri", prefer
, cgroup
);
1245 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"system")) {
1246 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_SYSTEM
,
1247 BAD_CAST
"system", BAD_CAST
"systemId", BAD_CAST
"uri", prefer
, cgroup
);
1248 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteSystem")) {
1249 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_SYSTEM
,
1250 BAD_CAST
"rewriteSystem", BAD_CAST
"systemIdStartString",
1251 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1252 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegatePublic")) {
1253 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_PUBLIC
,
1254 BAD_CAST
"delegatePublic", BAD_CAST
"publicIdStartString",
1255 BAD_CAST
"catalog", prefer
, cgroup
);
1256 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateSystem")) {
1257 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_SYSTEM
,
1258 BAD_CAST
"delegateSystem", BAD_CAST
"systemIdStartString",
1259 BAD_CAST
"catalog", prefer
, cgroup
);
1260 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"uri")) {
1261 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_URI
,
1262 BAD_CAST
"uri", BAD_CAST
"name",
1263 BAD_CAST
"uri", prefer
, cgroup
);
1264 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteURI")) {
1265 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_URI
,
1266 BAD_CAST
"rewriteURI", BAD_CAST
"uriStartString",
1267 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1268 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateURI")) {
1269 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_URI
,
1270 BAD_CAST
"delegateURI", BAD_CAST
"uriStartString",
1271 BAD_CAST
"catalog", prefer
, cgroup
);
1272 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"nextCatalog")) {
1273 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_NEXT_CATALOG
,
1274 BAD_CAST
"nextCatalog", NULL
,
1275 BAD_CAST
"catalog", prefer
, cgroup
);
1277 if (entry
!= NULL
) {
1278 if (parent
!= NULL
) {
1279 entry
->parent
= parent
;
1280 if (parent
->children
== NULL
)
1281 parent
->children
= entry
;
1283 xmlCatalogEntryPtr prev
;
1285 prev
= parent
->children
;
1286 while (prev
->next
!= NULL
)
1291 if (entry
->type
== XML_CATA_GROUP
) {
1293 * Recurse to propagate prefer to the subtree
1294 * (xml:base handling is automated)
1296 xmlParseXMLCatalogNodeList(cur
->children
, prefer
, parent
, entry
);
1304 * xmlParseXMLCatalogNodeList:
1305 * @cur: the XML node list of siblings
1306 * @prefer: the PUBLIC vs. SYSTEM current preference value
1307 * @parent: the parent Catalog entry
1308 * @cgroup: the group which includes this list
1310 * Examines a list of XML sibling nodes of a catalog and build
1311 * a list of Catalog entry from it adding it to the parent.
1312 * The examination will recurse to examine node subtrees.
1315 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1316 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
) {
1317 while (cur
!= NULL
) {
1318 if ((cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1319 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1320 xmlParseXMLCatalogNode(cur
, prefer
, parent
, cgroup
);
1324 /* TODO: sort the list according to REWRITE lengths and prefer value */
1328 * xmlParseXMLCatalogFile:
1329 * @prefer: the PUBLIC vs. SYSTEM current preference value
1330 * @filename: the filename for the catalog
1332 * Parses the catalog file to extract the XML tree and then analyze the
1333 * tree to build a list of Catalog entries corresponding to this catalog
1335 * Returns the resulting Catalog entries list
1337 static xmlCatalogEntryPtr
1338 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
) {
1342 xmlCatalogEntryPtr parent
= NULL
;
1344 if (filename
== NULL
)
1347 doc
= xmlParseCatalogFile((const char *) filename
);
1349 if (xmlDebugCatalogs
)
1350 xmlGenericError(xmlGenericErrorContext
,
1351 "Failed to parse catalog %s\n", filename
);
1355 if (xmlDebugCatalogs
)
1356 xmlGenericError(xmlGenericErrorContext
,
1357 "%d Parsing catalog %s\n", xmlGetThreadId(), filename
);
1359 cur
= xmlDocGetRootElement(doc
);
1360 if ((cur
!= NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"catalog")) &&
1361 (cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1362 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1364 parent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
1365 (const xmlChar
*)filename
, NULL
, prefer
, NULL
);
1366 if (parent
== NULL
) {
1371 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1373 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1374 prefer
= XML_CATA_PREFER_SYSTEM
;
1375 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1376 prefer
= XML_CATA_PREFER_PUBLIC
;
1378 xmlCatalogErr(NULL
, cur
, XML_CATALOG_PREFER_VALUE
,
1379 "Invalid value for prefer: '%s'\n",
1384 cur
= cur
->children
;
1385 xmlParseXMLCatalogNodeList(cur
, prefer
, parent
, NULL
);
1387 xmlCatalogErr(NULL
, (xmlNodePtr
) doc
, XML_CATALOG_NOT_CATALOG
,
1388 "File %s is not an XML Catalog\n",
1389 filename
, NULL
, NULL
);
1398 * xmlFetchXMLCatalogFile:
1399 * @catal: an existing but incomplete catalog entry
1401 * Fetch and parse the subcatalog referenced by an entry
1403 * Returns 0 in case of success, -1 otherwise
1406 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal
) {
1407 xmlCatalogEntryPtr doc
;
1411 if (catal
->URL
== NULL
)
1413 if (catal
->children
!= NULL
)
1417 * lock the whole catalog for modification
1419 xmlRMutexLock(xmlCatalogMutex
);
1420 if (catal
->children
!= NULL
) {
1421 /* Okay someone else did it in the meantime */
1422 xmlRMutexUnlock(xmlCatalogMutex
);
1426 if (xmlCatalogXMLFiles
!= NULL
) {
1427 doc
= (xmlCatalogEntryPtr
)
1428 xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1430 if (xmlDebugCatalogs
)
1431 xmlGenericError(xmlGenericErrorContext
,
1432 "Found %s in file hash\n", catal
->URL
);
1434 if (catal
->type
== XML_CATA_CATALOG
)
1435 catal
->children
= doc
->children
;
1437 catal
->children
= doc
;
1439 xmlRMutexUnlock(xmlCatalogMutex
);
1442 if (xmlDebugCatalogs
)
1443 xmlGenericError(xmlGenericErrorContext
,
1444 "%s not found in file hash\n", catal
->URL
);
1448 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1449 * use the existing catalog, there is no recursion allowed at
1452 doc
= xmlParseXMLCatalogFile(catal
->prefer
, catal
->URL
);
1454 catal
->type
= XML_CATA_BROKEN_CATALOG
;
1455 xmlRMutexUnlock(xmlCatalogMutex
);
1459 if (catal
->type
== XML_CATA_CATALOG
)
1460 catal
->children
= doc
->children
;
1462 catal
->children
= doc
;
1466 if (xmlCatalogXMLFiles
== NULL
)
1467 xmlCatalogXMLFiles
= xmlHashCreate(10);
1468 if (xmlCatalogXMLFiles
!= NULL
) {
1469 if (xmlDebugCatalogs
)
1470 xmlGenericError(xmlGenericErrorContext
,
1471 "%s added to file hash\n", catal
->URL
);
1472 xmlHashAddEntry(xmlCatalogXMLFiles
, catal
->URL
, doc
);
1474 xmlRMutexUnlock(xmlCatalogMutex
);
1478 /************************************************************************
1480 * XML Catalog handling *
1482 ************************************************************************/
1486 * @catal: top of an XML catalog
1487 * @type: the type of record to add to the catalog
1488 * @orig: the system, public or prefix to match (or NULL)
1489 * @replace: the replacement value for the match
1491 * Add an entry in the XML catalog, it may overwrite existing but
1492 * different entries.
1494 * Returns 0 if successful, -1 otherwise
1497 xmlAddXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*type
,
1498 const xmlChar
*orig
, const xmlChar
*replace
) {
1499 xmlCatalogEntryPtr cur
;
1500 xmlCatalogEntryType typ
;
1503 if ((catal
== NULL
) ||
1504 ((catal
->type
!= XML_CATA_CATALOG
) &&
1505 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1507 if (catal
->children
== NULL
) {
1508 xmlFetchXMLCatalogFile(catal
);
1510 if (catal
->children
== NULL
)
1513 typ
= xmlGetXMLCatalogEntryType(type
);
1514 if (typ
== XML_CATA_NONE
) {
1515 if (xmlDebugCatalogs
)
1516 xmlGenericError(xmlGenericErrorContext
,
1517 "Failed to add unknown element %s to catalog\n", type
);
1521 cur
= catal
->children
;
1523 * Might be a simple "update in place"
1526 while (cur
!= NULL
) {
1527 if ((orig
!= NULL
) && (cur
->type
== typ
) &&
1528 (xmlStrEqual(orig
, cur
->name
))) {
1529 if (xmlDebugCatalogs
)
1530 xmlGenericError(xmlGenericErrorContext
,
1531 "Updating element %s to catalog\n", type
);
1532 if (cur
->value
!= NULL
)
1533 xmlFree(cur
->value
);
1534 if (cur
->URL
!= NULL
)
1536 cur
->value
= xmlStrdup(replace
);
1537 cur
->URL
= xmlStrdup(replace
);
1540 if (cur
->next
== NULL
)
1545 if (xmlDebugCatalogs
)
1546 xmlGenericError(xmlGenericErrorContext
,
1547 "Adding element %s to catalog\n", type
);
1549 catal
->children
= xmlNewCatalogEntry(typ
, orig
, replace
,
1550 NULL
, catal
->prefer
, NULL
);
1552 cur
->next
= xmlNewCatalogEntry(typ
, orig
, replace
,
1553 NULL
, catal
->prefer
, NULL
);
1555 catal
->type
= XML_CATA_CATALOG
;
1556 cur
= xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1558 cur
->children
= catal
->children
;
1566 * @catal: top of an XML catalog
1567 * @value: the value to remove from the catalog
1569 * Remove entries in the XML catalog where the value or the URI
1570 * is equal to @value
1572 * Returns the number of entries removed if successful, -1 otherwise
1575 xmlDelXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*value
) {
1576 xmlCatalogEntryPtr cur
;
1579 if ((catal
== NULL
) ||
1580 ((catal
->type
!= XML_CATA_CATALOG
) &&
1581 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1585 if (catal
->children
== NULL
) {
1586 xmlFetchXMLCatalogFile(catal
);
1592 cur
= catal
->children
;
1593 while (cur
!= NULL
) {
1594 if (((cur
->name
!= NULL
) && (xmlStrEqual(value
, cur
->name
))) ||
1595 (xmlStrEqual(value
, cur
->value
))) {
1596 if (xmlDebugCatalogs
) {
1597 if (cur
->name
!= NULL
)
1598 xmlGenericError(xmlGenericErrorContext
,
1599 "Removing element %s from catalog\n", cur
->name
);
1601 xmlGenericError(xmlGenericErrorContext
,
1602 "Removing element %s from catalog\n", cur
->value
);
1604 cur
->type
= XML_CATA_REMOVED
;
1612 * xmlCatalogXMLResolve:
1613 * @catal: a catalog list
1614 * @pubID: the public ID string
1615 * @sysID: the system ID string
1617 * Do a complete resolution lookup of an External Identifier for a
1618 * list of catalog entries.
1620 * Implements (or tries to) 7.1. External Identifier Resolution
1621 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1623 * Returns the URI of the resource or NULL if not found
1626 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1627 const xmlChar
*sysID
) {
1628 xmlChar
*ret
= NULL
;
1629 xmlCatalogEntryPtr cur
;
1630 int haveDelegate
= 0;
1634 * protection against loops
1636 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1637 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1638 "Detected recursion in catalog %s\n",
1639 catal
->name
, NULL
, NULL
);
1645 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1647 if (sysID
!= NULL
) {
1648 xmlCatalogEntryPtr rewrite
= NULL
;
1649 int lenrewrite
= 0, len
;
1652 while (cur
!= NULL
) {
1653 switch (cur
->type
) {
1654 case XML_CATA_SYSTEM
:
1655 if (xmlStrEqual(sysID
, cur
->name
)) {
1656 if (xmlDebugCatalogs
)
1657 xmlGenericError(xmlGenericErrorContext
,
1658 "Found system match %s, using %s\n",
1659 cur
->name
, cur
->URL
);
1661 return(xmlStrdup(cur
->URL
));
1664 case XML_CATA_REWRITE_SYSTEM
:
1665 len
= xmlStrlen(cur
->name
);
1666 if ((len
> lenrewrite
) &&
1667 (!xmlStrncmp(sysID
, cur
->name
, len
))) {
1672 case XML_CATA_DELEGATE_SYSTEM
:
1673 if (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))
1676 case XML_CATA_NEXT_CATALOG
:
1684 if (rewrite
!= NULL
) {
1685 if (xmlDebugCatalogs
)
1686 xmlGenericError(xmlGenericErrorContext
,
1687 "Using rewriting rule %s\n", rewrite
->name
);
1688 ret
= xmlStrdup(rewrite
->URL
);
1690 ret
= xmlStrcat(ret
, &sysID
[lenrewrite
]);
1695 const xmlChar
*delegates
[MAX_DELEGATE
];
1699 * Assume the entries have been sorted by decreasing substring
1700 * matches when the list was produced.
1703 while (cur
!= NULL
) {
1704 if ((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) &&
1705 (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1706 for (i
= 0;i
< nbList
;i
++)
1707 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1713 if (nbList
< MAX_DELEGATE
)
1714 delegates
[nbList
++] = cur
->URL
;
1716 if (cur
->children
== NULL
) {
1717 xmlFetchXMLCatalogFile(cur
);
1719 if (cur
->children
!= NULL
) {
1720 if (xmlDebugCatalogs
)
1721 xmlGenericError(xmlGenericErrorContext
,
1722 "Trying system delegate %s\n", cur
->URL
);
1723 ret
= xmlCatalogListXMLResolve(
1724 cur
->children
, NULL
, sysID
);
1734 * Apply the cut algorithm explained in 4/
1737 return(XML_CATAL_BREAK
);
1741 * Then tries 5/ 6/ if a public ID is provided
1743 if (pubID
!= NULL
) {
1746 while (cur
!= NULL
) {
1747 switch (cur
->type
) {
1748 case XML_CATA_PUBLIC
:
1749 if (xmlStrEqual(pubID
, cur
->name
)) {
1750 if (xmlDebugCatalogs
)
1751 xmlGenericError(xmlGenericErrorContext
,
1752 "Found public match %s\n", cur
->name
);
1754 return(xmlStrdup(cur
->URL
));
1757 case XML_CATA_DELEGATE_PUBLIC
:
1758 if (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)) &&
1759 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
))
1762 case XML_CATA_NEXT_CATALOG
:
1772 const xmlChar
*delegates
[MAX_DELEGATE
];
1776 * Assume the entries have been sorted by decreasing substring
1777 * matches when the list was produced.
1780 while (cur
!= NULL
) {
1781 if ((cur
->type
== XML_CATA_DELEGATE_PUBLIC
) &&
1782 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
) &&
1783 (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1785 for (i
= 0;i
< nbList
;i
++)
1786 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1792 if (nbList
< MAX_DELEGATE
)
1793 delegates
[nbList
++] = cur
->URL
;
1795 if (cur
->children
== NULL
) {
1796 xmlFetchXMLCatalogFile(cur
);
1798 if (cur
->children
!= NULL
) {
1799 if (xmlDebugCatalogs
)
1800 xmlGenericError(xmlGenericErrorContext
,
1801 "Trying public delegate %s\n", cur
->URL
);
1802 ret
= xmlCatalogListXMLResolve(
1803 cur
->children
, pubID
, NULL
);
1813 * Apply the cut algorithm explained in 4/
1816 return(XML_CATAL_BREAK
);
1821 while (cur
!= NULL
) {
1822 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1823 if (cur
->children
== NULL
) {
1824 xmlFetchXMLCatalogFile(cur
);
1826 if (cur
->children
!= NULL
) {
1827 ret
= xmlCatalogListXMLResolve(cur
->children
, pubID
, sysID
);
1831 } else if (catal
->depth
> MAX_CATAL_DEPTH
) {
1845 * xmlCatalogXMLResolveURI:
1846 * @catal: a catalog list
1848 * @sysID: the system ID string
1850 * Do a complete resolution lookup of an External Identifier for a
1851 * list of catalog entries.
1853 * Implements (or tries to) 7.2.2. URI Resolution
1854 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1856 * Returns the URI of the resource or NULL if not found
1859 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
1860 xmlChar
*ret
= NULL
;
1861 xmlCatalogEntryPtr cur
;
1862 int haveDelegate
= 0;
1864 xmlCatalogEntryPtr rewrite
= NULL
;
1865 int lenrewrite
= 0, len
;
1873 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1874 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1875 "Detected recursion in catalog %s\n",
1876 catal
->name
, NULL
, NULL
);
1881 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1885 while (cur
!= NULL
) {
1886 switch (cur
->type
) {
1888 if (xmlStrEqual(URI
, cur
->name
)) {
1889 if (xmlDebugCatalogs
)
1890 xmlGenericError(xmlGenericErrorContext
,
1891 "Found URI match %s\n", cur
->name
);
1892 return(xmlStrdup(cur
->URL
));
1895 case XML_CATA_REWRITE_URI
:
1896 len
= xmlStrlen(cur
->name
);
1897 if ((len
> lenrewrite
) &&
1898 (!xmlStrncmp(URI
, cur
->name
, len
))) {
1903 case XML_CATA_DELEGATE_URI
:
1904 if (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))
1907 case XML_CATA_NEXT_CATALOG
:
1915 if (rewrite
!= NULL
) {
1916 if (xmlDebugCatalogs
)
1917 xmlGenericError(xmlGenericErrorContext
,
1918 "Using rewriting rule %s\n", rewrite
->name
);
1919 ret
= xmlStrdup(rewrite
->URL
);
1921 ret
= xmlStrcat(ret
, &URI
[lenrewrite
]);
1925 const xmlChar
*delegates
[MAX_DELEGATE
];
1929 * Assume the entries have been sorted by decreasing substring
1930 * matches when the list was produced.
1933 while (cur
!= NULL
) {
1934 if (((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) ||
1935 (cur
->type
== XML_CATA_DELEGATE_URI
)) &&
1936 (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))) {
1937 for (i
= 0;i
< nbList
;i
++)
1938 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1944 if (nbList
< MAX_DELEGATE
)
1945 delegates
[nbList
++] = cur
->URL
;
1947 if (cur
->children
== NULL
) {
1948 xmlFetchXMLCatalogFile(cur
);
1950 if (cur
->children
!= NULL
) {
1951 if (xmlDebugCatalogs
)
1952 xmlGenericError(xmlGenericErrorContext
,
1953 "Trying URI delegate %s\n", cur
->URL
);
1954 ret
= xmlCatalogListXMLResolveURI(
1955 cur
->children
, URI
);
1963 * Apply the cut algorithm explained in 4/
1965 return(XML_CATAL_BREAK
);
1969 while (cur
!= NULL
) {
1970 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1971 if (cur
->children
== NULL
) {
1972 xmlFetchXMLCatalogFile(cur
);
1974 if (cur
->children
!= NULL
) {
1975 ret
= xmlCatalogListXMLResolveURI(cur
->children
, URI
);
1988 * xmlCatalogListXMLResolve:
1989 * @catal: a catalog list
1990 * @pubID: the public ID string
1991 * @sysID: the system ID string
1993 * Do a complete resolution lookup of an External Identifier for a
1996 * Implements (or tries to) 7.1. External Identifier Resolution
1997 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1999 * Returns the URI of the resource or NULL if not found
2002 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
2003 const xmlChar
*sysID
) {
2004 xmlChar
*ret
= NULL
;
2005 xmlChar
*urnID
= NULL
;
2010 if ((pubID
== NULL
) && (sysID
== NULL
))
2013 normid
= xmlCatalogNormalizePublic(pubID
);
2015 pubID
= (*normid
!= 0 ? normid
: NULL
);
2017 if (!xmlStrncmp(pubID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2018 urnID
= xmlCatalogUnWrapURN(pubID
);
2019 if (xmlDebugCatalogs
) {
2021 xmlGenericError(xmlGenericErrorContext
,
2022 "Public URN ID %s expanded to NULL\n", pubID
);
2024 xmlGenericError(xmlGenericErrorContext
,
2025 "Public URN ID expanded to %s\n", urnID
);
2027 ret
= xmlCatalogListXMLResolve(catal
, urnID
, sysID
);
2034 if (!xmlStrncmp(sysID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2035 urnID
= xmlCatalogUnWrapURN(sysID
);
2036 if (xmlDebugCatalogs
) {
2038 xmlGenericError(xmlGenericErrorContext
,
2039 "System URN ID %s expanded to NULL\n", sysID
);
2041 xmlGenericError(xmlGenericErrorContext
,
2042 "System URN ID expanded to %s\n", urnID
);
2045 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2046 else if (xmlStrEqual(pubID
, urnID
))
2047 ret
= xmlCatalogListXMLResolve(catal
, pubID
, NULL
);
2049 ret
= xmlCatalogListXMLResolve(catal
, pubID
, urnID
);
2057 while (catal
!= NULL
) {
2058 if (catal
->type
== XML_CATA_CATALOG
) {
2059 if (catal
->children
== NULL
) {
2060 xmlFetchXMLCatalogFile(catal
);
2062 if (catal
->children
!= NULL
) {
2063 ret
= xmlCatalogXMLResolve(catal
->children
, pubID
, sysID
);
2066 } else if ((catal
->children
!= NULL
) &&
2067 (catal
->children
->depth
> MAX_CATAL_DEPTH
)) {
2073 catal
= catal
->next
;
2081 * xmlCatalogListXMLResolveURI:
2082 * @catal: a catalog list
2085 * Do a complete resolution lookup of an URI for a list of catalogs
2087 * Implements (or tries to) 7.2. URI Resolution
2088 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2090 * Returns the URI of the resource or NULL if not found
2093 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
2094 xmlChar
*ret
= NULL
;
2095 xmlChar
*urnID
= NULL
;
2102 if (!xmlStrncmp(URI
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2103 urnID
= xmlCatalogUnWrapURN(URI
);
2104 if (xmlDebugCatalogs
) {
2106 xmlGenericError(xmlGenericErrorContext
,
2107 "URN ID %s expanded to NULL\n", URI
);
2109 xmlGenericError(xmlGenericErrorContext
,
2110 "URN ID expanded to %s\n", urnID
);
2112 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2117 while (catal
!= NULL
) {
2118 if (catal
->type
== XML_CATA_CATALOG
) {
2119 if (catal
->children
== NULL
) {
2120 xmlFetchXMLCatalogFile(catal
);
2122 if (catal
->children
!= NULL
) {
2123 ret
= xmlCatalogXMLResolveURI(catal
->children
, URI
);
2128 catal
= catal
->next
;
2133 /************************************************************************
2135 * The SGML Catalog parser *
2137 ************************************************************************/
2142 #define SKIP(x) cur += x;
2144 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2147 * xmlParseSGMLCatalogComment:
2148 * @cur: the current character
2150 * Skip a comment in an SGML catalog
2152 * Returns new current character
2154 static const xmlChar
*
2155 xmlParseSGMLCatalogComment(const xmlChar
*cur
) {
2156 if ((cur
[0] != '-') || (cur
[1] != '-'))
2159 while ((cur
[0] != 0) && ((cur
[0] != '-') || ((cur
[1] != '-'))))
2168 * xmlParseSGMLCatalogPubid:
2169 * @cur: the current character
2170 * @id: the return location
2172 * Parse an SGML catalog ID
2174 * Returns new current character and store the value in @id
2176 static const xmlChar
*
2177 xmlParseSGMLCatalogPubid(const xmlChar
*cur
, xmlChar
**id
) {
2178 xmlChar
*buf
= NULL
, *tmp
;
2189 } else if (RAW
== '\'') {
2195 buf
= (xmlChar
*) xmlMallocAtomic(size
* sizeof(xmlChar
));
2197 xmlCatalogErrMemory("allocating public ID");
2200 while (IS_PUBIDCHAR_CH(*cur
) || (*cur
== '?')) {
2201 if ((*cur
== stop
) && (stop
!= ' '))
2203 if ((stop
== ' ') && (IS_BLANK_CH(*cur
)))
2205 if (len
+ 1 >= size
) {
2207 tmp
= (xmlChar
*) xmlRealloc(buf
, size
* sizeof(xmlChar
));
2209 xmlCatalogErrMemory("allocating public ID");
2221 if (!IS_BLANK_CH(*cur
)) {
2237 * xmlParseSGMLCatalogName:
2238 * @cur: the current character
2239 * @name: the return location
2241 * Parse an SGML catalog name
2243 * Returns new current character and store the value in @name
2245 static const xmlChar
*
2246 xmlParseSGMLCatalogName(const xmlChar
*cur
, xmlChar
**name
) {
2247 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
2254 * Handler for more complex cases
2257 if ((!IS_LETTER(c
) && (c
!= '_') && (c
!= ':'))) {
2261 while (((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
2262 (c
== '.') || (c
== '-') ||
2263 (c
== '_') || (c
== ':'))) {
2267 if (len
>= XML_MAX_NAMELEN
)
2270 *name
= xmlStrndup(buf
, len
);
2275 * xmlGetSGMLCatalogEntryType:
2276 * @name: the entry name
2278 * Get the Catalog entry type for a given SGML Catalog name
2280 * Returns Catalog entry type
2282 static xmlCatalogEntryType
2283 xmlGetSGMLCatalogEntryType(const xmlChar
*name
) {
2284 xmlCatalogEntryType type
= XML_CATA_NONE
;
2285 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2286 type
= SGML_CATA_SYSTEM
;
2287 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2288 type
= SGML_CATA_PUBLIC
;
2289 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2290 type
= SGML_CATA_DELEGATE
;
2291 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2292 type
= SGML_CATA_ENTITY
;
2293 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2294 type
= SGML_CATA_DOCTYPE
;
2295 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2296 type
= SGML_CATA_LINKTYPE
;
2297 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2298 type
= SGML_CATA_NOTATION
;
2299 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2300 type
= SGML_CATA_SGMLDECL
;
2301 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2302 type
= SGML_CATA_DOCUMENT
;
2303 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2304 type
= SGML_CATA_CATALOG
;
2305 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2306 type
= SGML_CATA_BASE
;
2311 * xmlParseSGMLCatalog:
2312 * @catal: the SGML Catalog
2313 * @value: the content of the SGML Catalog serialization
2314 * @file: the filepath for the catalog
2315 * @super: should this be handled as a Super Catalog in which case
2316 * parsing is not recursive
2318 * Parse an SGML catalog content and fill up the @catal hash table with
2319 * the new entries found.
2321 * Returns 0 in case of success, -1 in case of error.
2324 xmlParseSGMLCatalog(xmlCatalogPtr catal
, const xmlChar
*value
,
2325 const char *file
, int super
) {
2326 const xmlChar
*cur
= value
;
2327 xmlChar
*base
= NULL
;
2330 if ((cur
== NULL
) || (file
== NULL
))
2332 base
= xmlStrdup((const xmlChar
*) file
);
2334 while ((cur
!= NULL
) && (cur
[0] != 0)) {
2338 if ((cur
[0] == '-') && (cur
[1] == '-')) {
2339 cur
= xmlParseSGMLCatalogComment(cur
);
2345 xmlChar
*sysid
= NULL
;
2346 xmlChar
*name
= NULL
;
2347 xmlCatalogEntryType type
= XML_CATA_NONE
;
2349 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2354 if (!IS_BLANK_CH(*cur
)) {
2359 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2360 type
= SGML_CATA_SYSTEM
;
2361 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2362 type
= SGML_CATA_PUBLIC
;
2363 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2364 type
= SGML_CATA_DELEGATE
;
2365 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2366 type
= SGML_CATA_ENTITY
;
2367 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2368 type
= SGML_CATA_DOCTYPE
;
2369 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2370 type
= SGML_CATA_LINKTYPE
;
2371 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2372 type
= SGML_CATA_NOTATION
;
2373 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2374 type
= SGML_CATA_SGMLDECL
;
2375 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2376 type
= SGML_CATA_DOCUMENT
;
2377 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2378 type
= SGML_CATA_CATALOG
;
2379 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2380 type
= SGML_CATA_BASE
;
2381 else if (xmlStrEqual(name
, (const xmlChar
*) "OVERRIDE")) {
2383 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2395 case SGML_CATA_ENTITY
:
2397 type
= SGML_CATA_PENTITY
;
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
);
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
);
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
,
2939 (xmlHashScanner
) xmlCatalogDumpEntry
, out
);
2942 #endif /* LIBXML_OUTPUT_ENABLED */
2947 * @type: the type of record to add to the catalog
2948 * @orig: the system, public or prefix to match
2949 * @replace: the replacement value for the match
2951 * Add an entry in the catalog, it may overwrite existing but
2952 * different entries.
2954 * Returns 0 if successful, -1 otherwise
2957 xmlACatalogAdd(xmlCatalogPtr catal
, const xmlChar
* type
,
2958 const xmlChar
* orig
, const xmlChar
* replace
)
2965 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2966 res
= xmlAddXMLCatalog(catal
->xml
, type
, orig
, replace
);
2968 xmlCatalogEntryType cattype
;
2970 cattype
= xmlGetSGMLCatalogEntryType(type
);
2971 if (cattype
!= XML_CATA_NONE
) {
2972 xmlCatalogEntryPtr entry
;
2974 entry
= xmlNewCatalogEntry(cattype
, orig
, replace
, NULL
,
2975 XML_CATA_PREFER_NONE
, NULL
);
2976 if (catal
->sgml
== NULL
)
2977 catal
->sgml
= xmlHashCreate(10);
2978 res
= xmlHashAddEntry(catal
->sgml
, orig
, entry
);
2985 * xmlACatalogRemove:
2987 * @value: the value to remove
2989 * Remove an entry from the catalog
2991 * Returns the number of entries removed if successful, -1 otherwise
2994 xmlACatalogRemove(xmlCatalogPtr catal
, const xmlChar
*value
) {
2997 if ((catal
== NULL
) || (value
== NULL
))
3000 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
3001 res
= xmlDelXMLCatalog(catal
->xml
, value
);
3003 res
= xmlHashRemoveEntry(catal
->sgml
, value
,
3004 (xmlHashDeallocator
) xmlFreeCatalogEntry
);
3013 * @sgml: should this create an SGML catalog
3015 * create a new Catalog.
3017 * Returns the xmlCatalogPtr or NULL in case of error
3020 xmlNewCatalog(int sgml
) {
3021 xmlCatalogPtr catal
= NULL
;
3024 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
,
3025 xmlCatalogDefaultPrefer
);
3026 if ((catal
!= NULL
) && (catal
->sgml
== NULL
))
3027 catal
->sgml
= xmlHashCreate(10);
3029 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3030 xmlCatalogDefaultPrefer
);
3035 * xmlCatalogIsEmpty:
3036 * @catal: should this create an SGML catalog
3038 * Check is a catalog is empty
3040 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3043 xmlCatalogIsEmpty(xmlCatalogPtr catal
) {
3047 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
3048 if (catal
->xml
== NULL
)
3050 if ((catal
->xml
->type
!= XML_CATA_CATALOG
) &&
3051 (catal
->xml
->type
!= XML_CATA_BROKEN_CATALOG
))
3053 if (catal
->xml
->children
== NULL
)
3059 if (catal
->sgml
== NULL
)
3061 res
= xmlHashSize(catal
->sgml
);
3070 /************************************************************************
3072 * Public interfaces manipulating the global shared default catalog *
3074 ************************************************************************/
3077 * xmlInitializeCatalogData:
3079 * Do the catalog initialization only of global data, doesn't try to load
3080 * any catalog actually.
3081 * this function is not thread safe, catalog initialization should
3082 * preferably be done once at startup
3085 xmlInitializeCatalogData(void) {
3086 if (xmlCatalogInitialized
!= 0)
3089 if (getenv("XML_DEBUG_CATALOG"))
3090 xmlDebugCatalogs
= 1;
3091 xmlCatalogMutex
= xmlNewRMutex();
3093 xmlCatalogInitialized
= 1;
3096 * xmlInitializeCatalog:
3098 * Do the catalog initialization.
3099 * this function is not thread safe, catalog initialization should
3100 * preferably be done once at startup
3103 xmlInitializeCatalog(void) {
3104 if (xmlCatalogInitialized
!= 0)
3107 xmlInitializeCatalogData();
3108 xmlRMutexLock(xmlCatalogMutex
);
3110 if (getenv("XML_DEBUG_CATALOG"))
3111 xmlDebugCatalogs
= 1;
3113 if (xmlDefaultCatalog
== NULL
) {
3114 const char *catalogs
;
3116 const char *cur
, *paths
;
3117 xmlCatalogPtr catal
;
3118 xmlCatalogEntryPtr
*nextent
;
3120 catalogs
= (const char *) getenv("XML_CATALOG_FILES");
3121 if (catalogs
== NULL
)
3122 #if defined(_WIN32) && defined(_MSC_VER)
3125 hmodule
= GetModuleHandleA("libxml2.dll");
3126 if (hmodule
== NULL
)
3127 hmodule
= GetModuleHandleA(NULL
);
3128 if (hmodule
!= NULL
) {
3130 unsigned long len
= GetModuleFileNameA(hmodule
, buf
, 255);
3132 char* p
= &(buf
[len
]);
3133 while (*p
!= '\\' && p
> buf
)
3137 strncpy(p
, "\\..\\etc\\catalog", 255 - (p
- buf
));
3138 uri
= xmlCanonicPath(buf
);
3140 strncpy(XML_XML_DEFAULT_CATALOG
, uri
, 255);
3146 catalogs
= XML_XML_DEFAULT_CATALOG
;
3149 catalogs
= XML_XML_DEFAULT_CATALOG
;
3152 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3153 xmlCatalogDefaultPrefer
);
3154 if (catal
!= NULL
) {
3155 /* the XML_CATALOG_FILES envvar is allowed to contain a
3156 space-separated list of entries. */
3158 nextent
= &catal
->xml
;
3159 while (*cur
!= '\0') {
3160 while (xmlIsBlank_ch(*cur
))
3164 while ((*cur
!= 0) && (!xmlIsBlank_ch(*cur
)))
3166 path
= (char *) xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3168 *nextent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3169 NULL
, BAD_CAST path
, xmlCatalogDefaultPrefer
, NULL
);
3170 if (*nextent
!= NULL
)
3171 nextent
= &((*nextent
)->next
);
3176 xmlDefaultCatalog
= catal
;
3180 xmlRMutexUnlock(xmlCatalogMutex
);
3186 * @filename: a file path
3188 * Load the catalog and makes its definitions effective for the default
3189 * external entity loader. It will recurse in SGML CATALOG entries.
3190 * this function is not thread safe, catalog initialization should
3191 * preferably be done once at startup
3193 * Returns 0 in case of success -1 in case of error
3196 xmlLoadCatalog(const char *filename
)
3199 xmlCatalogPtr catal
;
3201 if (!xmlCatalogInitialized
)
3202 xmlInitializeCatalogData();
3204 xmlRMutexLock(xmlCatalogMutex
);
3206 if (xmlDefaultCatalog
== NULL
) {
3207 catal
= xmlLoadACatalog(filename
);
3208 if (catal
== NULL
) {
3209 xmlRMutexUnlock(xmlCatalogMutex
);
3213 xmlDefaultCatalog
= catal
;
3214 xmlRMutexUnlock(xmlCatalogMutex
);
3218 ret
= xmlExpandCatalog(xmlDefaultCatalog
, filename
);
3219 xmlRMutexUnlock(xmlCatalogMutex
);
3225 * @pathss: a list of directories separated by a colon or a space.
3227 * Load the catalogs and makes their definitions effective for the default
3228 * external entity loader.
3229 * this function is not thread safe, catalog initialization should
3230 * preferably be done once at startup
3233 xmlLoadCatalogs(const char *pathss
) {
3246 while (xmlIsBlank_ch(*cur
)) cur
++;
3249 while ((*cur
!= 0) && (*cur
!= PATH_SEAPARATOR
) && (!xmlIsBlank_ch(*cur
)))
3251 path
= xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3253 iLen
= strlen(path
);
3254 for(i
= 0; i
< iLen
; i
++) {
3255 if(path
[i
] == '\\') {
3261 xmlLoadCatalog((const char *) path
);
3265 while (*cur
== PATH_SEAPARATOR
)
3271 * xmlCatalogCleanup:
3273 * Free up all the memory associated with catalogs
3276 xmlCatalogCleanup(void) {
3277 if (xmlCatalogInitialized
== 0)
3280 xmlRMutexLock(xmlCatalogMutex
);
3281 if (xmlDebugCatalogs
)
3282 xmlGenericError(xmlGenericErrorContext
,
3283 "Catalogs cleanup\n");
3284 if (xmlCatalogXMLFiles
!= NULL
)
3285 xmlHashFree(xmlCatalogXMLFiles
,
3286 (xmlHashDeallocator
)xmlFreeCatalogHashEntryList
);
3287 xmlCatalogXMLFiles
= NULL
;
3288 if (xmlDefaultCatalog
!= NULL
)
3289 xmlFreeCatalog(xmlDefaultCatalog
);
3290 xmlDefaultCatalog
= NULL
;
3291 xmlDebugCatalogs
= 0;
3292 xmlCatalogInitialized
= 0;
3293 xmlRMutexUnlock(xmlCatalogMutex
);
3294 xmlFreeRMutex(xmlCatalogMutex
);
3298 * xmlCatalogResolveSystem:
3299 * @sysID: the system ID string
3301 * Try to lookup the catalog resource for a system ID
3303 * Returns the resource if found or NULL otherwise, the value returned
3304 * must be freed by the caller.
3307 xmlCatalogResolveSystem(const xmlChar
*sysID
) {
3310 if (!xmlCatalogInitialized
)
3311 xmlInitializeCatalog();
3313 ret
= xmlACatalogResolveSystem(xmlDefaultCatalog
, sysID
);
3318 * xmlCatalogResolvePublic:
3319 * @pubID: the public ID string
3321 * Try to lookup the catalog reference associated to a public ID
3323 * Returns the resource if found or NULL otherwise, the value returned
3324 * must be freed by the caller.
3327 xmlCatalogResolvePublic(const xmlChar
*pubID
) {
3330 if (!xmlCatalogInitialized
)
3331 xmlInitializeCatalog();
3333 ret
= xmlACatalogResolvePublic(xmlDefaultCatalog
, pubID
);
3338 * xmlCatalogResolve:
3339 * @pubID: the public ID string
3340 * @sysID: the system ID string
3342 * Do a complete resolution lookup of an External Identifier
3344 * Returns the URI of the resource or NULL if not found, it must be freed
3348 xmlCatalogResolve(const xmlChar
*pubID
, const xmlChar
*sysID
) {
3351 if (!xmlCatalogInitialized
)
3352 xmlInitializeCatalog();
3354 ret
= xmlACatalogResolve(xmlDefaultCatalog
, pubID
, sysID
);
3359 * xmlCatalogResolveURI:
3362 * Do a complete resolution lookup of an URI
3364 * Returns the URI of the resource or NULL if not found, it must be freed
3368 xmlCatalogResolveURI(const xmlChar
*URI
) {
3371 if (!xmlCatalogInitialized
)
3372 xmlInitializeCatalog();
3374 ret
= xmlACatalogResolveURI(xmlDefaultCatalog
, URI
);
3378 #ifdef LIBXML_OUTPUT_ENABLED
3383 * Dump all the global catalog content to the given file.
3386 xmlCatalogDump(FILE *out
) {
3390 if (!xmlCatalogInitialized
)
3391 xmlInitializeCatalog();
3393 xmlACatalogDump(xmlDefaultCatalog
, out
);
3395 #endif /* LIBXML_OUTPUT_ENABLED */
3399 * @type: the type of record to add to the catalog
3400 * @orig: the system, public or prefix to match
3401 * @replace: the replacement value for the match
3403 * Add an entry in the catalog, it may overwrite existing but
3404 * different entries.
3405 * If called before any other catalog routine, allows to override the
3406 * default shared catalog put in place by xmlInitializeCatalog();
3408 * Returns 0 if successful, -1 otherwise
3411 xmlCatalogAdd(const xmlChar
*type
, const xmlChar
*orig
, const xmlChar
*replace
) {
3414 if (!xmlCatalogInitialized
)
3415 xmlInitializeCatalogData();
3417 xmlRMutexLock(xmlCatalogMutex
);
3419 * Specific case where one want to override the default catalog
3420 * put in place by xmlInitializeCatalog();
3422 if ((xmlDefaultCatalog
== NULL
) &&
3423 (xmlStrEqual(type
, BAD_CAST
"catalog"))) {
3424 xmlDefaultCatalog
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3425 xmlCatalogDefaultPrefer
);
3426 xmlDefaultCatalog
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3427 orig
, NULL
, xmlCatalogDefaultPrefer
, NULL
);
3429 xmlRMutexUnlock(xmlCatalogMutex
);
3433 res
= xmlACatalogAdd(xmlDefaultCatalog
, type
, orig
, replace
);
3434 xmlRMutexUnlock(xmlCatalogMutex
);
3440 * @value: the value to remove
3442 * Remove an entry from the catalog
3444 * Returns the number of entries removed if successful, -1 otherwise
3447 xmlCatalogRemove(const xmlChar
*value
) {
3450 if (!xmlCatalogInitialized
)
3451 xmlInitializeCatalog();
3453 xmlRMutexLock(xmlCatalogMutex
);
3454 res
= xmlACatalogRemove(xmlDefaultCatalog
, value
);
3455 xmlRMutexUnlock(xmlCatalogMutex
);
3460 * xmlCatalogConvert:
3462 * Convert all the SGML catalog entries as XML ones
3464 * Returns the number of entries converted if successful, -1 otherwise
3467 xmlCatalogConvert(void) {
3470 if (!xmlCatalogInitialized
)
3471 xmlInitializeCatalog();
3473 xmlRMutexLock(xmlCatalogMutex
);
3474 res
= xmlConvertSGMLCatalog(xmlDefaultCatalog
);
3475 xmlRMutexUnlock(xmlCatalogMutex
);
3479 /************************************************************************
3481 * Public interface manipulating the common preferences *
3483 ************************************************************************/
3486 * xmlCatalogGetDefaults:
3488 * Used to get the user preference w.r.t. to what catalogs should
3491 * Returns the current xmlCatalogAllow value
3494 xmlCatalogGetDefaults(void) {
3495 return(xmlCatalogDefaultAllow
);
3499 * xmlCatalogSetDefaults:
3500 * @allow: what catalogs should be accepted
3502 * Used to set the user preference w.r.t. to what catalogs should
3506 xmlCatalogSetDefaults(xmlCatalogAllow allow
) {
3507 if (xmlDebugCatalogs
) {
3509 case XML_CATA_ALLOW_NONE
:
3510 xmlGenericError(xmlGenericErrorContext
,
3511 "Disabling catalog usage\n");
3513 case XML_CATA_ALLOW_GLOBAL
:
3514 xmlGenericError(xmlGenericErrorContext
,
3515 "Allowing only global catalogs\n");
3517 case XML_CATA_ALLOW_DOCUMENT
:
3518 xmlGenericError(xmlGenericErrorContext
,
3519 "Allowing only catalogs from the document\n");
3521 case XML_CATA_ALLOW_ALL
:
3522 xmlGenericError(xmlGenericErrorContext
,
3523 "Allowing all catalogs\n");
3527 xmlCatalogDefaultAllow
= allow
;
3531 * xmlCatalogSetDefaultPrefer:
3532 * @prefer: the default preference for delegation
3534 * Allows to set the preference between public and system for deletion
3535 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3536 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3538 * Returns the previous value of the default preference for delegation
3541 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer
) {
3542 xmlCatalogPrefer ret
= xmlCatalogDefaultPrefer
;
3544 if (prefer
== XML_CATA_PREFER_NONE
)
3547 if (xmlDebugCatalogs
) {
3549 case XML_CATA_PREFER_PUBLIC
:
3550 xmlGenericError(xmlGenericErrorContext
,
3551 "Setting catalog preference to PUBLIC\n");
3553 case XML_CATA_PREFER_SYSTEM
:
3554 xmlGenericError(xmlGenericErrorContext
,
3555 "Setting catalog preference to SYSTEM\n");
3557 case XML_CATA_PREFER_NONE
:
3561 xmlCatalogDefaultPrefer
= prefer
;
3566 * xmlCatalogSetDebug:
3567 * @level: the debug level of catalogs required
3569 * Used to set the debug level for catalog operation, 0 disable
3570 * debugging, 1 enable it
3572 * Returns the previous value of the catalog debugging level
3575 xmlCatalogSetDebug(int level
) {
3576 int ret
= xmlDebugCatalogs
;
3579 xmlDebugCatalogs
= 0;
3581 xmlDebugCatalogs
= level
;
3585 /************************************************************************
3587 * Minimal interfaces used for per-document catalogs by the parser *
3589 ************************************************************************/
3592 * xmlCatalogFreeLocal:
3593 * @catalogs: a document's list of catalogs
3595 * Free up the memory associated to the catalog list
3598 xmlCatalogFreeLocal(void *catalogs
) {
3599 xmlCatalogEntryPtr catal
;
3601 if (!xmlCatalogInitialized
)
3602 xmlInitializeCatalog();
3604 catal
= (xmlCatalogEntryPtr
) catalogs
;
3606 xmlFreeCatalogEntryList(catal
);
3611 * xmlCatalogAddLocal:
3612 * @catalogs: a document's list of catalogs
3613 * @URL: the URL to a new local catalog
3615 * Add the new entry to the catalog list
3617 * Returns the updated list
3620 xmlCatalogAddLocal(void *catalogs
, const xmlChar
*URL
) {
3621 xmlCatalogEntryPtr catal
, add
;
3623 if (!xmlCatalogInitialized
)
3624 xmlInitializeCatalog();
3629 if (xmlDebugCatalogs
)
3630 xmlGenericError(xmlGenericErrorContext
,
3631 "Adding document catalog %s\n", URL
);
3633 add
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
, URL
, NULL
,
3634 xmlCatalogDefaultPrefer
, NULL
);
3638 catal
= (xmlCatalogEntryPtr
) catalogs
;
3640 return((void *) add
);
3642 while (catal
->next
!= NULL
)
3643 catal
= catal
->next
;
3649 * xmlCatalogLocalResolve:
3650 * @catalogs: a document's list of catalogs
3651 * @pubID: the public ID string
3652 * @sysID: the system ID string
3654 * Do a complete resolution lookup of an External Identifier using a
3655 * document's private catalog list
3657 * Returns the URI of the resource or NULL if not found, it must be freed
3661 xmlCatalogLocalResolve(void *catalogs
, const xmlChar
*pubID
,
3662 const xmlChar
*sysID
) {
3663 xmlCatalogEntryPtr catal
;
3666 if (!xmlCatalogInitialized
)
3667 xmlInitializeCatalog();
3669 if ((pubID
== NULL
) && (sysID
== NULL
))
3672 if (xmlDebugCatalogs
) {
3673 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
3674 xmlGenericError(xmlGenericErrorContext
,
3675 "Local Resolve: pubID %s sysID %s\n", pubID
, sysID
);
3676 } else if (pubID
!= NULL
) {
3677 xmlGenericError(xmlGenericErrorContext
,
3678 "Local Resolve: pubID %s\n", pubID
);
3680 xmlGenericError(xmlGenericErrorContext
,
3681 "Local Resolve: sysID %s\n", sysID
);
3685 catal
= (xmlCatalogEntryPtr
) catalogs
;
3688 ret
= xmlCatalogListXMLResolve(catal
, pubID
, sysID
);
3689 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3695 * xmlCatalogLocalResolveURI:
3696 * @catalogs: a document's list of catalogs
3699 * Do a complete resolution lookup of an URI using a
3700 * document's private catalog list
3702 * Returns the URI of the resource or NULL if not found, it must be freed
3706 xmlCatalogLocalResolveURI(void *catalogs
, const xmlChar
*URI
) {
3707 xmlCatalogEntryPtr catal
;
3710 if (!xmlCatalogInitialized
)
3711 xmlInitializeCatalog();
3716 if (xmlDebugCatalogs
)
3717 xmlGenericError(xmlGenericErrorContext
,
3718 "Resolve URI %s\n", URI
);
3720 catal
= (xmlCatalogEntryPtr
) catalogs
;
3723 ret
= xmlCatalogListXMLResolveURI(catal
, URI
);
3724 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3729 /************************************************************************
3731 * Deprecated interfaces *
3733 ************************************************************************/
3735 * xmlCatalogGetSystem:
3736 * @sysID: the system ID string
3738 * Try to lookup the catalog reference associated to a system ID
3739 * DEPRECATED, use xmlCatalogResolveSystem()
3741 * Returns the resource if found or NULL otherwise.
3744 xmlCatalogGetSystem(const xmlChar
*sysID
) {
3746 static xmlChar result
[1000];
3749 if (!xmlCatalogInitialized
)
3750 xmlInitializeCatalog();
3753 xmlGenericError(xmlGenericErrorContext
,
3754 "Use of deprecated xmlCatalogGetSystem() call\n");
3762 * Check first the XML catalogs
3764 if (xmlDefaultCatalog
!= NULL
) {
3765 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, NULL
, sysID
);
3766 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3767 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3768 result
[sizeof(result
) - 1] = 0;
3773 if (xmlDefaultCatalog
!= NULL
)
3774 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog
->sgml
, sysID
));
3779 * xmlCatalogGetPublic:
3780 * @pubID: the public ID string
3782 * Try to lookup the catalog reference associated to a public ID
3783 * DEPRECATED, use xmlCatalogResolvePublic()
3785 * Returns the resource if found or NULL otherwise.
3788 xmlCatalogGetPublic(const xmlChar
*pubID
) {
3790 static xmlChar result
[1000];
3793 if (!xmlCatalogInitialized
)
3794 xmlInitializeCatalog();
3797 xmlGenericError(xmlGenericErrorContext
,
3798 "Use of deprecated xmlCatalogGetPublic() call\n");
3806 * Check first the XML catalogs
3808 if (xmlDefaultCatalog
!= NULL
) {
3809 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, pubID
, NULL
);
3810 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3811 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3812 result
[sizeof(result
) - 1] = 0;
3817 if (xmlDefaultCatalog
!= NULL
)
3818 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog
->sgml
, pubID
));
3822 #define bottom_catalog
3823 #include "elfgcchack.h"
3824 #endif /* LIBXML_CATALOG_ENABLED */