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
50 * macro to flag unimplemented blocks
51 * XML_CATALOG_PREFER user env to select between system/public prefered
52 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
53 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
54 *> values "system" and "public". I have made the default be "system" to
58 xmlGenericError(xmlGenericErrorContext, \
59 "Unimplemented block at %s:%d\n", \
62 #define XML_URN_PUBID "urn:publicid:"
63 #define XML_CATAL_BREAK ((xmlChar *) -1)
64 #ifndef XML_XML_DEFAULT_CATALOG
65 #define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
67 #ifndef XML_SGML_DEFAULT_CATALOG
68 #define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
71 #if defined(_WIN32) && defined(_MSC_VER)
72 #undef XML_XML_DEFAULT_CATALOG
73 static char XML_XML_DEFAULT_CATALOG
[256] = "file:///etc/xml/catalog";
74 void* __stdcall
GetModuleHandleA(const char*);
75 unsigned long __stdcall
GetModuleFileNameA(void*, char*, unsigned long);
78 static xmlChar
*xmlCatalogNormalizePublic(const xmlChar
*pubID
);
79 static int xmlExpandCatalog(xmlCatalogPtr catal
, const char *filename
);
81 /************************************************************************
83 * Types, all private *
85 ************************************************************************/
88 XML_CATA_REMOVED
= -1,
91 XML_CATA_BROKEN_CATALOG
,
92 XML_CATA_NEXT_CATALOG
,
96 XML_CATA_REWRITE_SYSTEM
,
97 XML_CATA_DELEGATE_PUBLIC
,
98 XML_CATA_DELEGATE_SYSTEM
,
100 XML_CATA_REWRITE_URI
,
101 XML_CATA_DELEGATE_URI
,
114 } xmlCatalogEntryType
;
116 typedef struct _xmlCatalogEntry xmlCatalogEntry
;
117 typedef xmlCatalogEntry
*xmlCatalogEntryPtr
;
118 struct _xmlCatalogEntry
{
119 struct _xmlCatalogEntry
*next
;
120 struct _xmlCatalogEntry
*parent
;
121 struct _xmlCatalogEntry
*children
;
122 xmlCatalogEntryType type
;
125 xmlChar
*URL
; /* The expanded URL using the base */
126 xmlCatalogPrefer prefer
;
129 struct _xmlCatalogEntry
*group
;
133 XML_XML_CATALOG_TYPE
= 1,
134 XML_SGML_CATALOG_TYPE
137 #define XML_MAX_SGML_CATA_DEPTH 10
139 xmlCatalogType type
; /* either XML or SGML */
142 * SGML Catalogs are stored as a simple hash table of catalog entries
143 * Catalog stack to check against overflows when building the
146 char *catalTab
[XML_MAX_SGML_CATA_DEPTH
]; /* stack of catals */
147 int catalNr
; /* Number of current catal streams */
148 int catalMax
; /* Max number of catal streams */
149 xmlHashTablePtr sgml
;
152 * XML Catalogs are stored as a tree of Catalog entries
154 xmlCatalogPrefer prefer
;
155 xmlCatalogEntryPtr xml
;
158 /************************************************************************
162 ************************************************************************/
165 * Those are preferences
167 static int xmlDebugCatalogs
= 0; /* used for debugging */
168 static xmlCatalogAllow xmlCatalogDefaultAllow
= XML_CATA_ALLOW_ALL
;
169 static xmlCatalogPrefer xmlCatalogDefaultPrefer
= XML_CATA_PREFER_PUBLIC
;
172 * Hash table containing all the trees of XML catalogs parsed by
175 static xmlHashTablePtr xmlCatalogXMLFiles
= NULL
;
178 * The default catalog in use by the application
180 static xmlCatalogPtr xmlDefaultCatalog
= NULL
;
183 * A mutex for modifying the shared global catalog(s)
184 * xmlDefaultCatalog tree.
185 * It also protects xmlCatalogXMLFiles
186 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
188 static xmlRMutexPtr xmlCatalogMutex
= NULL
;
191 * Whether the catalog support was initialized.
193 static int xmlCatalogInitialized
= 0;
195 /************************************************************************
197 * Catalog error handlers *
199 ************************************************************************/
202 * xmlCatalogErrMemory:
203 * @extra: extra informations
205 * Handle an out of memory condition
208 xmlCatalogErrMemory(const char *extra
)
210 __xmlRaiseError(NULL
, NULL
, NULL
, NULL
, NULL
, XML_FROM_CATALOG
,
211 XML_ERR_NO_MEMORY
, XML_ERR_ERROR
, NULL
, 0,
212 extra
, NULL
, NULL
, 0, 0,
213 "Memory allocation failed : %s\n", extra
);
218 * @catal: the Catalog entry
219 * @node: the context node
220 * @msg: the error message
221 * @extra: extra informations
223 * Handle a catalog error
226 xmlCatalogErr(xmlCatalogEntryPtr catal
, xmlNodePtr node
, int error
,
227 const char *msg
, const xmlChar
*str1
, const xmlChar
*str2
,
230 __xmlRaiseError(NULL
, NULL
, NULL
, catal
, node
, XML_FROM_CATALOG
,
231 error
, XML_ERR_ERROR
, NULL
, 0,
232 (const char *) str1
, (const char *) str2
,
233 (const char *) str3
, 0, 0,
234 msg
, str1
, str2
, str3
);
238 /************************************************************************
240 * Allocation and Freeing *
242 ************************************************************************/
245 * xmlNewCatalogEntry:
246 * @type: type of entry
247 * @name: name of the entry
248 * @value: value of the entry
249 * @prefer: the PUBLIC vs. SYSTEM current preference value
250 * @group: for members of a group, the group entry
252 * create a new Catalog entry, this type is shared both by XML and
253 * SGML catalogs, but the acceptable types values differs.
255 * Returns the xmlCatalogEntryPtr or NULL in case of error
257 static xmlCatalogEntryPtr
258 xmlNewCatalogEntry(xmlCatalogEntryType type
, const xmlChar
*name
,
259 const xmlChar
*value
, const xmlChar
*URL
, xmlCatalogPrefer prefer
,
260 xmlCatalogEntryPtr group
) {
261 xmlCatalogEntryPtr ret
;
262 xmlChar
*normid
= NULL
;
264 ret
= (xmlCatalogEntryPtr
) xmlMalloc(sizeof(xmlCatalogEntry
));
266 xmlCatalogErrMemory("allocating catalog entry");
271 ret
->children
= NULL
;
273 if (type
== XML_CATA_PUBLIC
|| type
== XML_CATA_DELEGATE_PUBLIC
) {
274 normid
= xmlCatalogNormalizePublic(name
);
276 name
= (*normid
!= 0 ? normid
: NULL
);
279 ret
->name
= xmlStrdup(name
);
285 ret
->value
= xmlStrdup(value
);
291 ret
->URL
= xmlStrdup(URL
);
294 ret
->prefer
= prefer
;
302 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret
);
305 * xmlFreeCatalogEntry:
306 * @ret: a Catalog entry
308 * Free the memory allocated to a Catalog entry
311 xmlFreeCatalogEntry(xmlCatalogEntryPtr ret
) {
315 * Entries stored in the file hash must be deallocated
316 * only by the file hash cleaner !
318 if (ret
->dealloc
== 1)
321 if (xmlDebugCatalogs
) {
322 if (ret
->name
!= NULL
)
323 xmlGenericError(xmlGenericErrorContext
,
324 "Free catalog entry %s\n", ret
->name
);
325 else if (ret
->value
!= NULL
)
326 xmlGenericError(xmlGenericErrorContext
,
327 "Free catalog entry %s\n", ret
->value
);
329 xmlGenericError(xmlGenericErrorContext
,
330 "Free catalog entry\n");
333 if (ret
->name
!= NULL
)
335 if (ret
->value
!= NULL
)
337 if (ret
->URL
!= NULL
)
343 * xmlFreeCatalogEntryList:
344 * @ret: a Catalog entry list
346 * Free the memory allocated to a full chained list of Catalog entries
349 xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret
) {
350 xmlCatalogEntryPtr next
;
352 while (ret
!= NULL
) {
354 xmlFreeCatalogEntry(ret
);
360 * xmlFreeCatalogHashEntryList:
361 * @ret: a Catalog entry list
363 * Free the memory allocated to list of Catalog entries from the
367 xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal
) {
368 xmlCatalogEntryPtr children
, next
;
373 children
= catal
->children
;
374 while (children
!= NULL
) {
375 next
= children
->next
;
376 children
->dealloc
= 0;
377 children
->children
= NULL
;
378 xmlFreeCatalogEntry(children
);
382 xmlFreeCatalogEntry(catal
);
386 * xmlCreateNewCatalog:
387 * @type: type of catalog
388 * @prefer: the PUBLIC vs. SYSTEM current preference value
390 * create a new Catalog, this type is shared both by XML and
391 * SGML catalogs, but the acceptable types values differs.
393 * Returns the xmlCatalogPtr or NULL in case of error
396 xmlCreateNewCatalog(xmlCatalogType type
, xmlCatalogPrefer prefer
) {
399 ret
= (xmlCatalogPtr
) xmlMalloc(sizeof(xmlCatalog
));
401 xmlCatalogErrMemory("allocating catalog");
404 memset(ret
, 0, sizeof(xmlCatalog
));
407 ret
->catalMax
= XML_MAX_SGML_CATA_DEPTH
;
408 ret
->prefer
= prefer
;
409 if (ret
->type
== XML_SGML_CATALOG_TYPE
)
410 ret
->sgml
= xmlHashCreate(10);
418 * Free the memory allocated to a Catalog
421 xmlFreeCatalog(xmlCatalogPtr catal
) {
424 if (catal
->xml
!= NULL
)
425 xmlFreeCatalogEntryList(catal
->xml
);
426 if (catal
->sgml
!= NULL
)
427 xmlHashFree(catal
->sgml
,
428 (xmlHashDeallocator
) xmlFreeCatalogEntry
);
432 /************************************************************************
434 * Serializing Catalogs *
436 ************************************************************************/
438 #ifdef LIBXML_OUTPUT_ENABLED
440 * xmlCatalogDumpEntry:
441 * @entry: the catalog entry
444 * Serialize an SGML Catalog entry
447 xmlCatalogDumpEntry(xmlCatalogEntryPtr entry
, FILE *out
) {
448 if ((entry
== NULL
) || (out
== NULL
))
450 switch (entry
->type
) {
451 case SGML_CATA_ENTITY
:
452 fprintf(out
, "ENTITY "); break;
453 case SGML_CATA_PENTITY
:
454 fprintf(out
, "ENTITY %%"); break;
455 case SGML_CATA_DOCTYPE
:
456 fprintf(out
, "DOCTYPE "); break;
457 case SGML_CATA_LINKTYPE
:
458 fprintf(out
, "LINKTYPE "); break;
459 case SGML_CATA_NOTATION
:
460 fprintf(out
, "NOTATION "); break;
461 case SGML_CATA_PUBLIC
:
462 fprintf(out
, "PUBLIC "); break;
463 case SGML_CATA_SYSTEM
:
464 fprintf(out
, "SYSTEM "); break;
465 case SGML_CATA_DELEGATE
:
466 fprintf(out
, "DELEGATE "); break;
468 fprintf(out
, "BASE "); break;
469 case SGML_CATA_CATALOG
:
470 fprintf(out
, "CATALOG "); break;
471 case SGML_CATA_DOCUMENT
:
472 fprintf(out
, "DOCUMENT "); break;
473 case SGML_CATA_SGMLDECL
:
474 fprintf(out
, "SGMLDECL "); break;
478 switch (entry
->type
) {
479 case SGML_CATA_ENTITY
:
480 case SGML_CATA_PENTITY
:
481 case SGML_CATA_DOCTYPE
:
482 case SGML_CATA_LINKTYPE
:
483 case SGML_CATA_NOTATION
:
484 fprintf(out
, "%s", (const char *) entry
->name
); break;
485 case SGML_CATA_PUBLIC
:
486 case SGML_CATA_SYSTEM
:
487 case SGML_CATA_SGMLDECL
:
488 case SGML_CATA_DOCUMENT
:
489 case SGML_CATA_CATALOG
:
491 case SGML_CATA_DELEGATE
:
492 fprintf(out
, "\"%s\"", entry
->name
); break;
496 switch (entry
->type
) {
497 case SGML_CATA_ENTITY
:
498 case SGML_CATA_PENTITY
:
499 case SGML_CATA_DOCTYPE
:
500 case SGML_CATA_LINKTYPE
:
501 case SGML_CATA_NOTATION
:
502 case SGML_CATA_PUBLIC
:
503 case SGML_CATA_SYSTEM
:
504 case SGML_CATA_DELEGATE
:
505 fprintf(out
, " \"%s\"", entry
->value
); break;
513 * xmlDumpXMLCatalogNode:
514 * @catal: top catalog entry
515 * @catalog: pointer to the xml tree
516 * @doc: the containing document
517 * @ns: the current namespace
518 * @cgroup: group node for group members
520 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
523 static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal
, xmlNodePtr catalog
,
524 xmlDocPtr doc
, xmlNsPtr ns
, xmlCatalogEntryPtr cgroup
) {
526 xmlCatalogEntryPtr cur
;
528 * add all the catalog entries
531 while (cur
!= NULL
) {
532 if (cur
->group
== cgroup
) {
534 case XML_CATA_REMOVED
:
536 case XML_CATA_BROKEN_CATALOG
:
537 case XML_CATA_CATALOG
:
543 case XML_CATA_NEXT_CATALOG
:
544 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"nextCatalog", NULL
);
545 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
546 xmlAddChild(catalog
, node
);
551 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"group", NULL
);
552 xmlSetProp(node
, BAD_CAST
"id", cur
->name
);
553 if (cur
->value
!= NULL
) {
555 xns
= xmlSearchNsByHref(doc
, node
, XML_XML_NAMESPACE
);
557 xmlSetNsProp(node
, xns
, BAD_CAST
"base",
560 switch (cur
->prefer
) {
561 case XML_CATA_PREFER_NONE
:
563 case XML_CATA_PREFER_PUBLIC
:
564 xmlSetProp(node
, BAD_CAST
"prefer", BAD_CAST
"public");
566 case XML_CATA_PREFER_SYSTEM
:
567 xmlSetProp(node
, BAD_CAST
"prefer", BAD_CAST
"system");
570 xmlDumpXMLCatalogNode(cur
->next
, node
, doc
, ns
, cur
);
571 xmlAddChild(catalog
, node
);
573 case XML_CATA_PUBLIC
:
574 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"public", NULL
);
575 xmlSetProp(node
, BAD_CAST
"publicId", cur
->name
);
576 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
577 xmlAddChild(catalog
, node
);
579 case XML_CATA_SYSTEM
:
580 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"system", NULL
);
581 xmlSetProp(node
, BAD_CAST
"systemId", cur
->name
);
582 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
583 xmlAddChild(catalog
, node
);
585 case XML_CATA_REWRITE_SYSTEM
:
586 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"rewriteSystem", NULL
);
587 xmlSetProp(node
, BAD_CAST
"systemIdStartString", cur
->name
);
588 xmlSetProp(node
, BAD_CAST
"rewritePrefix", cur
->value
);
589 xmlAddChild(catalog
, node
);
591 case XML_CATA_DELEGATE_PUBLIC
:
592 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegatePublic", NULL
);
593 xmlSetProp(node
, BAD_CAST
"publicIdStartString", cur
->name
);
594 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
595 xmlAddChild(catalog
, node
);
597 case XML_CATA_DELEGATE_SYSTEM
:
598 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegateSystem", NULL
);
599 xmlSetProp(node
, BAD_CAST
"systemIdStartString", cur
->name
);
600 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
601 xmlAddChild(catalog
, node
);
604 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"uri", NULL
);
605 xmlSetProp(node
, BAD_CAST
"name", cur
->name
);
606 xmlSetProp(node
, BAD_CAST
"uri", cur
->value
);
607 xmlAddChild(catalog
, node
);
609 case XML_CATA_REWRITE_URI
:
610 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"rewriteURI", NULL
);
611 xmlSetProp(node
, BAD_CAST
"uriStartString", cur
->name
);
612 xmlSetProp(node
, BAD_CAST
"rewritePrefix", cur
->value
);
613 xmlAddChild(catalog
, node
);
615 case XML_CATA_DELEGATE_URI
:
616 node
= xmlNewDocNode(doc
, ns
, BAD_CAST
"delegateURI", NULL
);
617 xmlSetProp(node
, BAD_CAST
"uriStartString", cur
->name
);
618 xmlSetProp(node
, BAD_CAST
"catalog", cur
->value
);
619 xmlAddChild(catalog
, node
);
621 case SGML_CATA_SYSTEM
:
622 case SGML_CATA_PUBLIC
:
623 case SGML_CATA_ENTITY
:
624 case SGML_CATA_PENTITY
:
625 case SGML_CATA_DOCTYPE
:
626 case SGML_CATA_LINKTYPE
:
627 case SGML_CATA_NOTATION
:
628 case SGML_CATA_DELEGATE
:
630 case SGML_CATA_CATALOG
:
631 case SGML_CATA_DOCUMENT
:
632 case SGML_CATA_SGMLDECL
:
641 xmlDumpXMLCatalog(FILE *out
, xmlCatalogEntryPtr catal
) {
647 xmlOutputBufferPtr buf
;
652 doc
= xmlNewDoc(NULL
);
655 dtd
= xmlNewDtd(doc
, BAD_CAST
"catalog",
656 BAD_CAST
"-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
657 BAD_CAST
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
659 xmlAddChild((xmlNodePtr
) doc
, (xmlNodePtr
) dtd
);
661 ns
= xmlNewNs(NULL
, XML_CATALOGS_NAMESPACE
, NULL
);
666 catalog
= xmlNewDocNode(doc
, ns
, BAD_CAST
"catalog", NULL
);
667 if (catalog
== NULL
) {
673 xmlAddChild((xmlNodePtr
) doc
, catalog
);
675 xmlDumpXMLCatalogNode(catal
, catalog
, doc
, ns
, NULL
);
680 buf
= xmlOutputBufferCreateFile(out
, NULL
);
685 ret
= xmlSaveFormatFileTo(buf
, doc
, NULL
, 1);
694 #endif /* LIBXML_OUTPUT_ENABLED */
696 /************************************************************************
698 * Converting SGML Catalogs to XML *
700 ************************************************************************/
703 * xmlCatalogConvertEntry:
705 * @catal: pointer to the catalog being converted
707 * Convert one entry from the catalog
710 xmlCatalogConvertEntry(xmlCatalogEntryPtr entry
, xmlCatalogPtr catal
) {
711 if ((entry
== NULL
) || (catal
== NULL
) || (catal
->sgml
== NULL
) ||
712 (catal
->xml
== NULL
))
714 switch (entry
->type
) {
715 case SGML_CATA_ENTITY
:
716 entry
->type
= XML_CATA_PUBLIC
;
718 case SGML_CATA_PENTITY
:
719 entry
->type
= XML_CATA_PUBLIC
;
721 case SGML_CATA_DOCTYPE
:
722 entry
->type
= XML_CATA_PUBLIC
;
724 case SGML_CATA_LINKTYPE
:
725 entry
->type
= XML_CATA_PUBLIC
;
727 case SGML_CATA_NOTATION
:
728 entry
->type
= XML_CATA_PUBLIC
;
730 case SGML_CATA_PUBLIC
:
731 entry
->type
= XML_CATA_PUBLIC
;
733 case SGML_CATA_SYSTEM
:
734 entry
->type
= XML_CATA_SYSTEM
;
736 case SGML_CATA_DELEGATE
:
737 entry
->type
= XML_CATA_DELEGATE_PUBLIC
;
739 case SGML_CATA_CATALOG
:
740 entry
->type
= XML_CATA_CATALOG
;
743 xmlHashRemoveEntry(catal
->sgml
, entry
->name
,
744 (xmlHashDeallocator
) xmlFreeCatalogEntry
);
748 * Conversion successful, remove from the SGML catalog
749 * and add it to the default XML one
751 xmlHashRemoveEntry(catal
->sgml
, entry
->name
, NULL
);
752 entry
->parent
= catal
->xml
;
754 if (catal
->xml
->children
== NULL
)
755 catal
->xml
->children
= entry
;
757 xmlCatalogEntryPtr prev
;
759 prev
= catal
->xml
->children
;
760 while (prev
->next
!= NULL
)
767 * xmlConvertSGMLCatalog:
768 * @catal: the catalog
770 * Convert all the SGML catalog entries as XML ones
772 * Returns the number of entries converted if successful, -1 otherwise
775 xmlConvertSGMLCatalog(xmlCatalogPtr catal
) {
777 if ((catal
== NULL
) || (catal
->type
!= XML_SGML_CATALOG_TYPE
))
780 if (xmlDebugCatalogs
) {
781 xmlGenericError(xmlGenericErrorContext
,
782 "Converting SGML catalog to XML\n");
784 xmlHashScan(catal
->sgml
,
785 (xmlHashScanner
) xmlCatalogConvertEntry
,
790 /************************************************************************
794 ************************************************************************/
797 * xmlCatalogUnWrapURN:
798 * @urn: an "urn:publicid:" to unwrap
800 * Expand the URN into the equivalent Public Identifier
802 * Returns the new identifier or NULL, the string must be deallocated
806 xmlCatalogUnWrapURN(const xmlChar
*urn
) {
807 xmlChar result
[2000];
810 if (xmlStrncmp(urn
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1))
812 urn
+= sizeof(XML_URN_PUBID
) - 1;
815 if (i
> sizeof(result
) - 4)
820 } else if (*urn
== ':') {
824 } else if (*urn
== ';') {
828 } else if (*urn
== '%') {
829 if ((urn
[1] == '2') && (urn
[2] == 'B'))
831 else if ((urn
[1] == '3') && (urn
[2] == 'A'))
833 else if ((urn
[1] == '2') && (urn
[2] == 'F'))
835 else if ((urn
[1] == '3') && (urn
[2] == 'B'))
837 else if ((urn
[1] == '2') && (urn
[2] == '7'))
839 else if ((urn
[1] == '3') && (urn
[2] == 'F'))
841 else if ((urn
[1] == '2') && (urn
[2] == '3'))
843 else if ((urn
[1] == '2') && (urn
[2] == '5'))
858 return(xmlStrdup(result
));
862 * xmlParseCatalogFile:
863 * @filename: the filename
865 * parse an XML file and build a tree. It's like xmlParseFile()
866 * except it bypass all catalog lookups.
868 * Returns the resulting document tree or NULL in case of error
872 xmlParseCatalogFile(const char *filename
) {
874 xmlParserCtxtPtr ctxt
;
875 char *directory
= NULL
;
876 xmlParserInputPtr inputStream
;
877 xmlParserInputBufferPtr buf
;
879 ctxt
= xmlNewParserCtxt();
881 #ifdef LIBXML_SAX1_ENABLED
882 if (xmlDefaultSAXHandler
.error
!= NULL
) {
883 xmlDefaultSAXHandler
.error(NULL
, "out of memory\n");
889 buf
= xmlParserInputBufferCreateFilename(filename
, XML_CHAR_ENCODING_NONE
);
891 xmlFreeParserCtxt(ctxt
);
895 inputStream
= xmlNewInputStream(ctxt
);
896 if (inputStream
== NULL
) {
897 xmlFreeParserCtxt(ctxt
);
901 inputStream
->filename
= (char *) xmlCanonicPath((const xmlChar
*)filename
);
902 inputStream
->buf
= buf
;
903 inputStream
->base
= inputStream
->buf
->buffer
->content
;
904 inputStream
->cur
= inputStream
->buf
->buffer
->content
;
906 &inputStream
->buf
->buffer
->content
[inputStream
->buf
->buffer
->use
];
908 inputPush(ctxt
, inputStream
);
909 if ((ctxt
->directory
== NULL
) && (directory
== NULL
))
910 directory
= xmlParserGetDirectory(filename
);
911 if ((ctxt
->directory
== NULL
) && (directory
!= NULL
))
912 ctxt
->directory
= directory
;
915 ctxt
->loadsubset
= 0;
919 xmlParseDocument(ctxt
);
921 if (ctxt
->wellFormed
)
925 xmlFreeDoc(ctxt
->myDoc
);
928 xmlFreeParserCtxt(ctxt
);
934 * xmlLoadFileContent:
935 * @filename: a file path
937 * Load a file content into memory.
939 * Returns a pointer to the 0 terminated string or NULL in case of error
942 xmlLoadFileContent(const char *filename
)
957 if (filename
== NULL
)
961 if (stat(filename
, &info
) < 0)
966 if ((fd
= open(filename
, O_RDONLY
)) < 0)
968 if ((fd
= fopen(filename
, "rb")) == NULL
)
976 if (fseek(fd
, 0, SEEK_END
) || (size
= ftell(fd
)) == EOF
|| fseek(fd
, 0, SEEK_SET
)) { /* File operations denied? ok, just close and return failure */
981 content
= xmlMallocAtomic(size
+ 10);
982 if (content
== NULL
) {
983 xmlCatalogErrMemory("allocating catalog data");
987 len
= read(fd
, content
, size
);
989 len
= fread(content
, 1, size
, fd
);
1006 * xmlCatalogNormalizePublic:
1007 * @pubID: the public ID string
1009 * Normalizes the Public Identifier
1011 * Implements 6.2. Public Identifier Normalization
1012 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1014 * Returns the new string or NULL, the string must be deallocated
1018 xmlCatalogNormalizePublic(const xmlChar
*pubID
)
1030 for (p
= pubID
;*p
!= 0 && ok
;p
++) {
1031 if (!xmlIsBlank_ch(*p
))
1033 else if (*p
== 0x20 && !white
)
1038 if (ok
&& !white
) /* is normalized */
1041 ret
= xmlStrdup(pubID
);
1044 for (p
= pubID
;*p
!= 0;p
++) {
1045 if (xmlIsBlank_ch(*p
)) {
1060 /************************************************************************
1062 * The XML Catalog parser *
1064 ************************************************************************/
1066 static xmlCatalogEntryPtr
1067 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
);
1069 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1070 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
);
1072 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1073 const xmlChar
*sysID
);
1075 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
);
1079 * xmlGetXMLCatalogEntryType:
1082 * lookup the internal type associated to an XML catalog entry name
1084 * Returns the type associated with that name
1086 static xmlCatalogEntryType
1087 xmlGetXMLCatalogEntryType(const xmlChar
*name
) {
1088 xmlCatalogEntryType type
= XML_CATA_NONE
;
1089 if (xmlStrEqual(name
, (const xmlChar
*) "system"))
1090 type
= XML_CATA_SYSTEM
;
1091 else if (xmlStrEqual(name
, (const xmlChar
*) "public"))
1092 type
= XML_CATA_PUBLIC
;
1093 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteSystem"))
1094 type
= XML_CATA_REWRITE_SYSTEM
;
1095 else if (xmlStrEqual(name
, (const xmlChar
*) "delegatePublic"))
1096 type
= XML_CATA_DELEGATE_PUBLIC
;
1097 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateSystem"))
1098 type
= XML_CATA_DELEGATE_SYSTEM
;
1099 else if (xmlStrEqual(name
, (const xmlChar
*) "uri"))
1100 type
= XML_CATA_URI
;
1101 else if (xmlStrEqual(name
, (const xmlChar
*) "rewriteURI"))
1102 type
= XML_CATA_REWRITE_URI
;
1103 else if (xmlStrEqual(name
, (const xmlChar
*) "delegateURI"))
1104 type
= XML_CATA_DELEGATE_URI
;
1105 else if (xmlStrEqual(name
, (const xmlChar
*) "nextCatalog"))
1106 type
= XML_CATA_NEXT_CATALOG
;
1107 else if (xmlStrEqual(name
, (const xmlChar
*) "catalog"))
1108 type
= XML_CATA_CATALOG
;
1113 * xmlParseXMLCatalogOneNode:
1114 * @cur: the XML node
1115 * @type: the type of Catalog entry
1116 * @name: the name of the node
1117 * @attrName: the attribute holding the value
1118 * @uriAttrName: the attribute holding the URI-Reference
1119 * @prefer: the PUBLIC vs. SYSTEM current preference value
1120 * @cgroup: the group which includes this node
1122 * Finishes the examination of an XML tree node of a catalog and build
1123 * a Catalog entry from it.
1125 * Returns the new Catalog entry node or NULL in case of error.
1127 static xmlCatalogEntryPtr
1128 xmlParseXMLCatalogOneNode(xmlNodePtr cur
, xmlCatalogEntryType type
,
1129 const xmlChar
*name
, const xmlChar
*attrName
,
1130 const xmlChar
*uriAttrName
, xmlCatalogPrefer prefer
,
1131 xmlCatalogEntryPtr cgroup
) {
1134 xmlChar
*nameValue
= NULL
;
1135 xmlChar
*base
= NULL
;
1136 xmlChar
*URL
= NULL
;
1137 xmlCatalogEntryPtr ret
= NULL
;
1139 if (attrName
!= NULL
) {
1140 nameValue
= xmlGetProp(cur
, attrName
);
1141 if (nameValue
== NULL
) {
1142 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1143 "%s entry lacks '%s'\n", name
, attrName
, NULL
);
1147 uriValue
= xmlGetProp(cur
, uriAttrName
);
1148 if (uriValue
== NULL
) {
1149 xmlCatalogErr(ret
, cur
, XML_CATALOG_MISSING_ATTR
,
1150 "%s entry lacks '%s'\n", name
, uriAttrName
, NULL
);
1154 if (nameValue
!= NULL
)
1156 if (uriValue
!= NULL
)
1161 base
= xmlNodeGetBase(cur
->doc
, cur
);
1162 URL
= xmlBuildURI(uriValue
, base
);
1164 if (xmlDebugCatalogs
> 1) {
1165 if (nameValue
!= NULL
)
1166 xmlGenericError(xmlGenericErrorContext
,
1167 "Found %s: '%s' '%s'\n", name
, nameValue
, URL
);
1169 xmlGenericError(xmlGenericErrorContext
,
1170 "Found %s: '%s'\n", name
, URL
);
1172 ret
= xmlNewCatalogEntry(type
, nameValue
, uriValue
, URL
, prefer
, cgroup
);
1174 xmlCatalogErr(ret
, cur
, XML_CATALOG_ENTRY_BROKEN
,
1175 "%s entry '%s' broken ?: %s\n", name
, uriAttrName
, uriValue
);
1177 if (nameValue
!= NULL
)
1179 if (uriValue
!= NULL
)
1189 * xmlParseXMLCatalogNode:
1190 * @cur: the XML node
1191 * @prefer: the PUBLIC vs. SYSTEM current preference value
1192 * @parent: the parent Catalog entry
1193 * @cgroup: the group which includes this node
1195 * Examines an XML tree node of a catalog and build
1196 * a Catalog entry from it adding it to its parent. The examination can
1200 xmlParseXMLCatalogNode(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1201 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
)
1203 xmlChar
*uri
= NULL
;
1204 xmlChar
*URL
= NULL
;
1205 xmlChar
*base
= NULL
;
1206 xmlCatalogEntryPtr entry
= NULL
;
1210 if (xmlStrEqual(cur
->name
, BAD_CAST
"group")) {
1212 xmlCatalogPrefer pref
= XML_CATA_PREFER_NONE
;
1214 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1216 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1217 prefer
= XML_CATA_PREFER_SYSTEM
;
1218 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1219 prefer
= XML_CATA_PREFER_PUBLIC
;
1221 xmlCatalogErr(parent
, cur
, XML_CATALOG_PREFER_VALUE
,
1222 "Invalid value for prefer: '%s'\n",
1228 prop
= xmlGetProp(cur
, BAD_CAST
"id");
1229 base
= xmlGetNsProp(cur
, BAD_CAST
"base", XML_XML_NAMESPACE
);
1230 entry
= xmlNewCatalogEntry(XML_CATA_GROUP
, prop
, base
, NULL
, pref
, cgroup
);
1232 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"public")) {
1233 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_PUBLIC
,
1234 BAD_CAST
"public", BAD_CAST
"publicId", BAD_CAST
"uri", prefer
, cgroup
);
1235 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"system")) {
1236 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_SYSTEM
,
1237 BAD_CAST
"system", BAD_CAST
"systemId", BAD_CAST
"uri", prefer
, cgroup
);
1238 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteSystem")) {
1239 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_SYSTEM
,
1240 BAD_CAST
"rewriteSystem", BAD_CAST
"systemIdStartString",
1241 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1242 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegatePublic")) {
1243 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_PUBLIC
,
1244 BAD_CAST
"delegatePublic", BAD_CAST
"publicIdStartString",
1245 BAD_CAST
"catalog", prefer
, cgroup
);
1246 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateSystem")) {
1247 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_SYSTEM
,
1248 BAD_CAST
"delegateSystem", BAD_CAST
"systemIdStartString",
1249 BAD_CAST
"catalog", prefer
, cgroup
);
1250 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"uri")) {
1251 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_URI
,
1252 BAD_CAST
"uri", BAD_CAST
"name",
1253 BAD_CAST
"uri", prefer
, cgroup
);
1254 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"rewriteURI")) {
1255 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_REWRITE_URI
,
1256 BAD_CAST
"rewriteURI", BAD_CAST
"uriStartString",
1257 BAD_CAST
"rewritePrefix", prefer
, cgroup
);
1258 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"delegateURI")) {
1259 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_DELEGATE_URI
,
1260 BAD_CAST
"delegateURI", BAD_CAST
"uriStartString",
1261 BAD_CAST
"catalog", prefer
, cgroup
);
1262 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"nextCatalog")) {
1263 entry
= xmlParseXMLCatalogOneNode(cur
, XML_CATA_NEXT_CATALOG
,
1264 BAD_CAST
"nextCatalog", NULL
,
1265 BAD_CAST
"catalog", prefer
, cgroup
);
1267 if (entry
!= NULL
) {
1268 if (parent
!= NULL
) {
1269 entry
->parent
= parent
;
1270 if (parent
->children
== NULL
)
1271 parent
->children
= entry
;
1273 xmlCatalogEntryPtr prev
;
1275 prev
= parent
->children
;
1276 while (prev
->next
!= NULL
)
1281 if (entry
->type
== XML_CATA_GROUP
) {
1283 * Recurse to propagate prefer to the subtree
1284 * (xml:base handling is automated)
1286 xmlParseXMLCatalogNodeList(cur
->children
, prefer
, parent
, entry
);
1298 * xmlParseXMLCatalogNodeList:
1299 * @cur: the XML node list of siblings
1300 * @prefer: the PUBLIC vs. SYSTEM current preference value
1301 * @parent: the parent Catalog entry
1302 * @cgroup: the group which includes this list
1304 * Examines a list of XML sibling nodes of a catalog and build
1305 * a list of Catalog entry from it adding it to the parent.
1306 * The examination will recurse to examine node subtrees.
1309 xmlParseXMLCatalogNodeList(xmlNodePtr cur
, xmlCatalogPrefer prefer
,
1310 xmlCatalogEntryPtr parent
, xmlCatalogEntryPtr cgroup
) {
1311 while (cur
!= NULL
) {
1312 if ((cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1313 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1314 xmlParseXMLCatalogNode(cur
, prefer
, parent
, cgroup
);
1318 /* TODO: sort the list according to REWRITE lengths and prefer value */
1322 * xmlParseXMLCatalogFile:
1323 * @prefer: the PUBLIC vs. SYSTEM current preference value
1324 * @filename: the filename for the catalog
1326 * Parses the catalog file to extract the XML tree and then analyze the
1327 * tree to build a list of Catalog entries corresponding to this catalog
1329 * Returns the resulting Catalog entries list
1331 static xmlCatalogEntryPtr
1332 xmlParseXMLCatalogFile(xmlCatalogPrefer prefer
, const xmlChar
*filename
) {
1336 xmlCatalogEntryPtr parent
= NULL
;
1338 if (filename
== NULL
)
1341 doc
= xmlParseCatalogFile((const char *) filename
);
1343 if (xmlDebugCatalogs
)
1344 xmlGenericError(xmlGenericErrorContext
,
1345 "Failed to parse catalog %s\n", filename
);
1349 if (xmlDebugCatalogs
)
1350 xmlGenericError(xmlGenericErrorContext
,
1351 "%d Parsing catalog %s\n", xmlGetThreadId(), filename
);
1353 cur
= xmlDocGetRootElement(doc
);
1354 if ((cur
!= NULL
) && (xmlStrEqual(cur
->name
, BAD_CAST
"catalog")) &&
1355 (cur
->ns
!= NULL
) && (cur
->ns
->href
!= NULL
) &&
1356 (xmlStrEqual(cur
->ns
->href
, XML_CATALOGS_NAMESPACE
))) {
1358 parent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
1359 (const xmlChar
*)filename
, NULL
, prefer
, NULL
);
1360 if (parent
== NULL
) {
1365 prop
= xmlGetProp(cur
, BAD_CAST
"prefer");
1367 if (xmlStrEqual(prop
, BAD_CAST
"system")) {
1368 prefer
= XML_CATA_PREFER_SYSTEM
;
1369 } else if (xmlStrEqual(prop
, BAD_CAST
"public")) {
1370 prefer
= XML_CATA_PREFER_PUBLIC
;
1372 xmlCatalogErr(NULL
, cur
, XML_CATALOG_PREFER_VALUE
,
1373 "Invalid value for prefer: '%s'\n",
1378 cur
= cur
->children
;
1379 xmlParseXMLCatalogNodeList(cur
, prefer
, parent
, NULL
);
1381 xmlCatalogErr(NULL
, (xmlNodePtr
) doc
, XML_CATALOG_NOT_CATALOG
,
1382 "File %s is not an XML Catalog\n",
1383 filename
, NULL
, NULL
);
1392 * xmlFetchXMLCatalogFile:
1393 * @catal: an existing but incomplete catalog entry
1395 * Fetch and parse the subcatalog referenced by an entry
1397 * Returns 0 in case of success, -1 otherwise
1400 xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal
) {
1401 xmlCatalogEntryPtr doc
;
1405 if (catal
->URL
== NULL
)
1407 if (catal
->children
!= NULL
)
1411 * lock the whole catalog for modification
1413 xmlRMutexLock(xmlCatalogMutex
);
1414 if (catal
->children
!= NULL
) {
1415 /* Okay someone else did it in the meantime */
1416 xmlRMutexUnlock(xmlCatalogMutex
);
1420 if (xmlCatalogXMLFiles
!= NULL
) {
1421 doc
= (xmlCatalogEntryPtr
)
1422 xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1424 if (xmlDebugCatalogs
)
1425 xmlGenericError(xmlGenericErrorContext
,
1426 "Found %s in file hash\n", catal
->URL
);
1428 if (catal
->type
== XML_CATA_CATALOG
)
1429 catal
->children
= doc
->children
;
1431 catal
->children
= doc
;
1433 xmlRMutexUnlock(xmlCatalogMutex
);
1436 if (xmlDebugCatalogs
)
1437 xmlGenericError(xmlGenericErrorContext
,
1438 "%s not found in file hash\n", catal
->URL
);
1442 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1443 * use the existing catalog, there is no recursion allowed at
1446 doc
= xmlParseXMLCatalogFile(catal
->prefer
, catal
->URL
);
1448 catal
->type
= XML_CATA_BROKEN_CATALOG
;
1449 xmlRMutexUnlock(xmlCatalogMutex
);
1453 if (catal
->type
== XML_CATA_CATALOG
)
1454 catal
->children
= doc
->children
;
1456 catal
->children
= doc
;
1460 if (xmlCatalogXMLFiles
== NULL
)
1461 xmlCatalogXMLFiles
= xmlHashCreate(10);
1462 if (xmlCatalogXMLFiles
!= NULL
) {
1463 if (xmlDebugCatalogs
)
1464 xmlGenericError(xmlGenericErrorContext
,
1465 "%s added to file hash\n", catal
->URL
);
1466 xmlHashAddEntry(xmlCatalogXMLFiles
, catal
->URL
, doc
);
1468 xmlRMutexUnlock(xmlCatalogMutex
);
1472 /************************************************************************
1474 * XML Catalog handling *
1476 ************************************************************************/
1480 * @catal: top of an XML catalog
1481 * @type: the type of record to add to the catalog
1482 * @orig: the system, public or prefix to match (or NULL)
1483 * @replace: the replacement value for the match
1485 * Add an entry in the XML catalog, it may overwrite existing but
1486 * different entries.
1488 * Returns 0 if successful, -1 otherwise
1491 xmlAddXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*type
,
1492 const xmlChar
*orig
, const xmlChar
*replace
) {
1493 xmlCatalogEntryPtr cur
;
1494 xmlCatalogEntryType typ
;
1497 if ((catal
== NULL
) ||
1498 ((catal
->type
!= XML_CATA_CATALOG
) &&
1499 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1501 if (catal
->children
== NULL
) {
1502 xmlFetchXMLCatalogFile(catal
);
1504 if (catal
->children
== NULL
)
1507 typ
= xmlGetXMLCatalogEntryType(type
);
1508 if (typ
== XML_CATA_NONE
) {
1509 if (xmlDebugCatalogs
)
1510 xmlGenericError(xmlGenericErrorContext
,
1511 "Failed to add unknown element %s to catalog\n", type
);
1515 cur
= catal
->children
;
1517 * Might be a simple "update in place"
1520 while (cur
!= NULL
) {
1521 if ((orig
!= NULL
) && (cur
->type
== typ
) &&
1522 (xmlStrEqual(orig
, cur
->name
))) {
1523 if (xmlDebugCatalogs
)
1524 xmlGenericError(xmlGenericErrorContext
,
1525 "Updating element %s to catalog\n", type
);
1526 if (cur
->value
!= NULL
)
1527 xmlFree(cur
->value
);
1528 if (cur
->URL
!= NULL
)
1530 cur
->value
= xmlStrdup(replace
);
1531 cur
->URL
= xmlStrdup(replace
);
1534 if (cur
->next
== NULL
)
1539 if (xmlDebugCatalogs
)
1540 xmlGenericError(xmlGenericErrorContext
,
1541 "Adding element %s to catalog\n", type
);
1543 catal
->children
= xmlNewCatalogEntry(typ
, orig
, replace
,
1544 NULL
, catal
->prefer
, NULL
);
1546 cur
->next
= xmlNewCatalogEntry(typ
, orig
, replace
,
1547 NULL
, catal
->prefer
, NULL
);
1549 cur
= xmlHashLookup(xmlCatalogXMLFiles
, catal
->URL
);
1551 cur
->children
= catal
->children
;
1559 * @catal: top of an XML catalog
1560 * @value: the value to remove from the catalog
1562 * Remove entries in the XML catalog where the value or the URI
1563 * is equal to @value
1565 * Returns the number of entries removed if successful, -1 otherwise
1568 xmlDelXMLCatalog(xmlCatalogEntryPtr catal
, const xmlChar
*value
) {
1569 xmlCatalogEntryPtr cur
;
1572 if ((catal
== NULL
) ||
1573 ((catal
->type
!= XML_CATA_CATALOG
) &&
1574 (catal
->type
!= XML_CATA_BROKEN_CATALOG
)))
1578 if (catal
->children
== NULL
) {
1579 xmlFetchXMLCatalogFile(catal
);
1585 cur
= catal
->children
;
1586 while (cur
!= NULL
) {
1587 if (((cur
->name
!= NULL
) && (xmlStrEqual(value
, cur
->name
))) ||
1588 (xmlStrEqual(value
, cur
->value
))) {
1589 if (xmlDebugCatalogs
) {
1590 if (cur
->name
!= NULL
)
1591 xmlGenericError(xmlGenericErrorContext
,
1592 "Removing element %s from catalog\n", cur
->name
);
1594 xmlGenericError(xmlGenericErrorContext
,
1595 "Removing element %s from catalog\n", cur
->value
);
1597 cur
->type
= XML_CATA_REMOVED
;
1605 * xmlCatalogXMLResolve:
1606 * @catal: a catalog list
1607 * @pubID: the public ID string
1608 * @sysID: the system ID string
1610 * Do a complete resolution lookup of an External Identifier for a
1611 * list of catalog entries.
1613 * Implements (or tries to) 7.1. External Identifier Resolution
1614 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1616 * Returns the URI of the resource or NULL if not found
1619 xmlCatalogXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1620 const xmlChar
*sysID
) {
1621 xmlChar
*ret
= NULL
;
1622 xmlCatalogEntryPtr cur
;
1623 int haveDelegate
= 0;
1627 * protection against loops
1629 if (catal
->depth
> MAX_CATAL_DEPTH
) {
1630 xmlCatalogErr(catal
, NULL
, XML_CATALOG_RECURSION
,
1631 "Detected recursion in catalog %s\n",
1632 catal
->name
, NULL
, NULL
);
1638 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1640 if (sysID
!= NULL
) {
1641 xmlCatalogEntryPtr rewrite
= NULL
;
1642 int lenrewrite
= 0, len
;
1645 while (cur
!= NULL
) {
1646 switch (cur
->type
) {
1647 case XML_CATA_SYSTEM
:
1648 if (xmlStrEqual(sysID
, cur
->name
)) {
1649 if (xmlDebugCatalogs
)
1650 xmlGenericError(xmlGenericErrorContext
,
1651 "Found system match %s\n", cur
->name
);
1653 return(xmlStrdup(cur
->URL
));
1656 case XML_CATA_REWRITE_SYSTEM
:
1657 len
= xmlStrlen(cur
->name
);
1658 if ((len
> lenrewrite
) &&
1659 (!xmlStrncmp(sysID
, cur
->name
, len
))) {
1664 case XML_CATA_DELEGATE_SYSTEM
:
1665 if (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))
1668 case XML_CATA_NEXT_CATALOG
:
1676 if (rewrite
!= NULL
) {
1677 if (xmlDebugCatalogs
)
1678 xmlGenericError(xmlGenericErrorContext
,
1679 "Using rewriting rule %s\n", rewrite
->name
);
1680 ret
= xmlStrdup(rewrite
->URL
);
1682 ret
= xmlStrcat(ret
, &sysID
[lenrewrite
]);
1687 const xmlChar
*delegates
[MAX_DELEGATE
];
1691 * Assume the entries have been sorted by decreasing substring
1692 * matches when the list was produced.
1695 while (cur
!= NULL
) {
1696 if ((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) &&
1697 (!xmlStrncmp(sysID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1698 for (i
= 0;i
< nbList
;i
++)
1699 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1705 if (nbList
< MAX_DELEGATE
)
1706 delegates
[nbList
++] = cur
->URL
;
1708 if (cur
->children
== NULL
) {
1709 xmlFetchXMLCatalogFile(cur
);
1711 if (cur
->children
!= NULL
) {
1712 if (xmlDebugCatalogs
)
1713 xmlGenericError(xmlGenericErrorContext
,
1714 "Trying system delegate %s\n", cur
->URL
);
1715 ret
= xmlCatalogListXMLResolve(
1716 cur
->children
, NULL
, sysID
);
1726 * Apply the cut algorithm explained in 4/
1729 return(XML_CATAL_BREAK
);
1733 * Then tries 5/ 6/ if a public ID is provided
1735 if (pubID
!= NULL
) {
1738 while (cur
!= NULL
) {
1739 switch (cur
->type
) {
1740 case XML_CATA_PUBLIC
:
1741 if (xmlStrEqual(pubID
, cur
->name
)) {
1742 if (xmlDebugCatalogs
)
1743 xmlGenericError(xmlGenericErrorContext
,
1744 "Found public match %s\n", cur
->name
);
1746 return(xmlStrdup(cur
->URL
));
1749 case XML_CATA_DELEGATE_PUBLIC
:
1750 if (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)) &&
1751 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
))
1754 case XML_CATA_NEXT_CATALOG
:
1764 const xmlChar
*delegates
[MAX_DELEGATE
];
1768 * Assume the entries have been sorted by decreasing substring
1769 * matches when the list was produced.
1772 while (cur
!= NULL
) {
1773 if ((cur
->type
== XML_CATA_DELEGATE_PUBLIC
) &&
1774 (cur
->prefer
== XML_CATA_PREFER_PUBLIC
) &&
1775 (!xmlStrncmp(pubID
, cur
->name
, xmlStrlen(cur
->name
)))) {
1777 for (i
= 0;i
< nbList
;i
++)
1778 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1784 if (nbList
< MAX_DELEGATE
)
1785 delegates
[nbList
++] = cur
->URL
;
1787 if (cur
->children
== NULL
) {
1788 xmlFetchXMLCatalogFile(cur
);
1790 if (cur
->children
!= NULL
) {
1791 if (xmlDebugCatalogs
)
1792 xmlGenericError(xmlGenericErrorContext
,
1793 "Trying public delegate %s\n", cur
->URL
);
1794 ret
= xmlCatalogListXMLResolve(
1795 cur
->children
, pubID
, NULL
);
1805 * Apply the cut algorithm explained in 4/
1808 return(XML_CATAL_BREAK
);
1813 while (cur
!= NULL
) {
1814 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1815 if (cur
->children
== NULL
) {
1816 xmlFetchXMLCatalogFile(cur
);
1818 if (cur
->children
!= NULL
) {
1819 ret
= xmlCatalogListXMLResolve(cur
->children
, pubID
, sysID
);
1835 * xmlCatalogXMLResolveURI:
1836 * @catal: a catalog list
1838 * @sysID: the system ID string
1840 * Do a complete resolution lookup of an External Identifier for a
1841 * list of catalog entries.
1843 * Implements (or tries to) 7.2.2. URI Resolution
1844 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1846 * Returns the URI of the resource or NULL if not found
1849 xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
1850 xmlChar
*ret
= NULL
;
1851 xmlCatalogEntryPtr cur
;
1852 int haveDelegate
= 0;
1854 xmlCatalogEntryPtr rewrite
= NULL
;
1855 int lenrewrite
= 0, len
;
1864 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1868 while (cur
!= NULL
) {
1869 switch (cur
->type
) {
1871 if (xmlStrEqual(URI
, cur
->name
)) {
1872 if (xmlDebugCatalogs
)
1873 xmlGenericError(xmlGenericErrorContext
,
1874 "Found URI match %s\n", cur
->name
);
1875 return(xmlStrdup(cur
->URL
));
1878 case XML_CATA_REWRITE_URI
:
1879 len
= xmlStrlen(cur
->name
);
1880 if ((len
> lenrewrite
) &&
1881 (!xmlStrncmp(URI
, cur
->name
, len
))) {
1886 case XML_CATA_DELEGATE_URI
:
1887 if (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))
1890 case XML_CATA_NEXT_CATALOG
:
1898 if (rewrite
!= NULL
) {
1899 if (xmlDebugCatalogs
)
1900 xmlGenericError(xmlGenericErrorContext
,
1901 "Using rewriting rule %s\n", rewrite
->name
);
1902 ret
= xmlStrdup(rewrite
->URL
);
1904 ret
= xmlStrcat(ret
, &URI
[lenrewrite
]);
1908 const xmlChar
*delegates
[MAX_DELEGATE
];
1912 * Assume the entries have been sorted by decreasing substring
1913 * matches when the list was produced.
1916 while (cur
!= NULL
) {
1917 if (((cur
->type
== XML_CATA_DELEGATE_SYSTEM
) ||
1918 (cur
->type
== XML_CATA_DELEGATE_URI
)) &&
1919 (!xmlStrncmp(URI
, cur
->name
, xmlStrlen(cur
->name
)))) {
1920 for (i
= 0;i
< nbList
;i
++)
1921 if (xmlStrEqual(cur
->URL
, delegates
[i
]))
1927 if (nbList
< MAX_DELEGATE
)
1928 delegates
[nbList
++] = cur
->URL
;
1930 if (cur
->children
== NULL
) {
1931 xmlFetchXMLCatalogFile(cur
);
1933 if (cur
->children
!= NULL
) {
1934 if (xmlDebugCatalogs
)
1935 xmlGenericError(xmlGenericErrorContext
,
1936 "Trying URI delegate %s\n", cur
->URL
);
1937 ret
= xmlCatalogListXMLResolveURI(
1938 cur
->children
, URI
);
1946 * Apply the cut algorithm explained in 4/
1948 return(XML_CATAL_BREAK
);
1952 while (cur
!= NULL
) {
1953 if (cur
->type
== XML_CATA_NEXT_CATALOG
) {
1954 if (cur
->children
== NULL
) {
1955 xmlFetchXMLCatalogFile(cur
);
1957 if (cur
->children
!= NULL
) {
1958 ret
= xmlCatalogListXMLResolveURI(cur
->children
, URI
);
1971 * xmlCatalogListXMLResolve:
1972 * @catal: a catalog list
1973 * @pubID: the public ID string
1974 * @sysID: the system ID string
1976 * Do a complete resolution lookup of an External Identifier for a
1979 * Implements (or tries to) 7.1. External Identifier Resolution
1980 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1982 * Returns the URI of the resource or NULL if not found
1985 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal
, const xmlChar
*pubID
,
1986 const xmlChar
*sysID
) {
1987 xmlChar
*ret
= NULL
;
1988 xmlChar
*urnID
= NULL
;
1993 if ((pubID
== NULL
) && (sysID
== NULL
))
1996 normid
= xmlCatalogNormalizePublic(pubID
);
1998 pubID
= (*normid
!= 0 ? normid
: NULL
);
2000 if (!xmlStrncmp(pubID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2001 urnID
= xmlCatalogUnWrapURN(pubID
);
2002 if (xmlDebugCatalogs
) {
2004 xmlGenericError(xmlGenericErrorContext
,
2005 "Public URN ID %s expanded to NULL\n", pubID
);
2007 xmlGenericError(xmlGenericErrorContext
,
2008 "Public URN ID expanded to %s\n", urnID
);
2010 ret
= xmlCatalogListXMLResolve(catal
, urnID
, sysID
);
2017 if (!xmlStrncmp(sysID
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2018 urnID
= xmlCatalogUnWrapURN(sysID
);
2019 if (xmlDebugCatalogs
) {
2021 xmlGenericError(xmlGenericErrorContext
,
2022 "System URN ID %s expanded to NULL\n", sysID
);
2024 xmlGenericError(xmlGenericErrorContext
,
2025 "System URN ID expanded to %s\n", urnID
);
2028 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2029 else if (xmlStrEqual(pubID
, urnID
))
2030 ret
= xmlCatalogListXMLResolve(catal
, pubID
, NULL
);
2032 ret
= xmlCatalogListXMLResolve(catal
, pubID
, urnID
);
2040 while (catal
!= NULL
) {
2041 if (catal
->type
== XML_CATA_CATALOG
) {
2042 if (catal
->children
== NULL
) {
2043 xmlFetchXMLCatalogFile(catal
);
2045 if (catal
->children
!= NULL
) {
2046 ret
= xmlCatalogXMLResolve(catal
->children
, pubID
, sysID
);
2054 catal
= catal
->next
;
2062 * xmlCatalogListXMLResolveURI:
2063 * @catal: a catalog list
2066 * Do a complete resolution lookup of an URI for a list of catalogs
2068 * Implements (or tries to) 7.2. URI Resolution
2069 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2071 * Returns the URI of the resource or NULL if not found
2074 xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal
, const xmlChar
*URI
) {
2075 xmlChar
*ret
= NULL
;
2076 xmlChar
*urnID
= NULL
;
2083 if (!xmlStrncmp(URI
, BAD_CAST XML_URN_PUBID
, sizeof(XML_URN_PUBID
) - 1)) {
2084 urnID
= xmlCatalogUnWrapURN(URI
);
2085 if (xmlDebugCatalogs
) {
2087 xmlGenericError(xmlGenericErrorContext
,
2088 "URN ID %s expanded to NULL\n", URI
);
2090 xmlGenericError(xmlGenericErrorContext
,
2091 "URN ID expanded to %s\n", urnID
);
2093 ret
= xmlCatalogListXMLResolve(catal
, urnID
, NULL
);
2098 while (catal
!= NULL
) {
2099 if (catal
->type
== XML_CATA_CATALOG
) {
2100 if (catal
->children
== NULL
) {
2101 xmlFetchXMLCatalogFile(catal
);
2103 if (catal
->children
!= NULL
) {
2104 ret
= xmlCatalogXMLResolveURI(catal
->children
, URI
);
2109 catal
= catal
->next
;
2114 /************************************************************************
2116 * The SGML Catalog parser *
2118 ************************************************************************/
2123 #define SKIP(x) cur += x;
2125 #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2128 * xmlParseSGMLCatalogComment:
2129 * @cur: the current character
2131 * Skip a comment in an SGML catalog
2133 * Returns new current character
2135 static const xmlChar
*
2136 xmlParseSGMLCatalogComment(const xmlChar
*cur
) {
2137 if ((cur
[0] != '-') || (cur
[1] != '-'))
2140 while ((cur
[0] != 0) && ((cur
[0] != '-') || ((cur
[1] != '-'))))
2149 * xmlParseSGMLCatalogPubid:
2150 * @cur: the current character
2151 * @id: the return location
2153 * Parse an SGML catalog ID
2155 * Returns new current character and store the value in @id
2157 static const xmlChar
*
2158 xmlParseSGMLCatalogPubid(const xmlChar
*cur
, xmlChar
**id
) {
2159 xmlChar
*buf
= NULL
, *tmp
;
2170 } else if (RAW
== '\'') {
2176 buf
= (xmlChar
*) xmlMallocAtomic(size
* sizeof(xmlChar
));
2178 xmlCatalogErrMemory("allocating public ID");
2181 while (IS_PUBIDCHAR_CH(*cur
) || (*cur
== '?')) {
2182 if ((*cur
== stop
) && (stop
!= ' '))
2184 if ((stop
== ' ') && (IS_BLANK_CH(*cur
)))
2186 if (len
+ 1 >= size
) {
2188 tmp
= (xmlChar
*) xmlRealloc(buf
, size
* sizeof(xmlChar
));
2190 xmlCatalogErrMemory("allocating public ID");
2202 if (!IS_BLANK_CH(*cur
)) {
2218 * xmlParseSGMLCatalogName:
2219 * @cur: the current character
2220 * @name: the return location
2222 * Parse an SGML catalog name
2224 * Returns new current character and store the value in @name
2226 static const xmlChar
*
2227 xmlParseSGMLCatalogName(const xmlChar
*cur
, xmlChar
**name
) {
2228 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
2235 * Handler for more complex cases
2238 if ((!IS_LETTER(c
) && (c
!= '_') && (c
!= ':'))) {
2242 while (((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
2243 (c
== '.') || (c
== '-') ||
2244 (c
== '_') || (c
== ':'))) {
2248 if (len
>= XML_MAX_NAMELEN
)
2251 *name
= xmlStrndup(buf
, len
);
2256 * xmlGetSGMLCatalogEntryType:
2257 * @name: the entry name
2259 * Get the Catalog entry type for a given SGML Catalog name
2261 * Returns Catalog entry type
2263 static xmlCatalogEntryType
2264 xmlGetSGMLCatalogEntryType(const xmlChar
*name
) {
2265 xmlCatalogEntryType type
= XML_CATA_NONE
;
2266 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2267 type
= SGML_CATA_SYSTEM
;
2268 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2269 type
= SGML_CATA_PUBLIC
;
2270 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2271 type
= SGML_CATA_DELEGATE
;
2272 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2273 type
= SGML_CATA_ENTITY
;
2274 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2275 type
= SGML_CATA_DOCTYPE
;
2276 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2277 type
= SGML_CATA_LINKTYPE
;
2278 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2279 type
= SGML_CATA_NOTATION
;
2280 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2281 type
= SGML_CATA_SGMLDECL
;
2282 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2283 type
= SGML_CATA_DOCUMENT
;
2284 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2285 type
= SGML_CATA_CATALOG
;
2286 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2287 type
= SGML_CATA_BASE
;
2292 * xmlParseSGMLCatalog:
2293 * @catal: the SGML Catalog
2294 * @value: the content of the SGML Catalog serialization
2295 * @file: the filepath for the catalog
2296 * @super: should this be handled as a Super Catalog in which case
2297 * parsing is not recursive
2299 * Parse an SGML catalog content and fill up the @catal hash table with
2300 * the new entries found.
2302 * Returns 0 in case of success, -1 in case of error.
2305 xmlParseSGMLCatalog(xmlCatalogPtr catal
, const xmlChar
*value
,
2306 const char *file
, int super
) {
2307 const xmlChar
*cur
= value
;
2308 xmlChar
*base
= NULL
;
2311 if ((cur
== NULL
) || (file
== NULL
))
2313 base
= xmlStrdup((const xmlChar
*) file
);
2315 while ((cur
!= NULL
) && (cur
[0] != 0)) {
2319 if ((cur
[0] == '-') && (cur
[1] == '-')) {
2320 cur
= xmlParseSGMLCatalogComment(cur
);
2326 xmlChar
*sysid
= NULL
;
2327 xmlChar
*name
= NULL
;
2328 xmlCatalogEntryType type
= XML_CATA_NONE
;
2330 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2335 if (!IS_BLANK_CH(*cur
)) {
2340 if (xmlStrEqual(name
, (const xmlChar
*) "SYSTEM"))
2341 type
= SGML_CATA_SYSTEM
;
2342 else if (xmlStrEqual(name
, (const xmlChar
*) "PUBLIC"))
2343 type
= SGML_CATA_PUBLIC
;
2344 else if (xmlStrEqual(name
, (const xmlChar
*) "DELEGATE"))
2345 type
= SGML_CATA_DELEGATE
;
2346 else if (xmlStrEqual(name
, (const xmlChar
*) "ENTITY"))
2347 type
= SGML_CATA_ENTITY
;
2348 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCTYPE"))
2349 type
= SGML_CATA_DOCTYPE
;
2350 else if (xmlStrEqual(name
, (const xmlChar
*) "LINKTYPE"))
2351 type
= SGML_CATA_LINKTYPE
;
2352 else if (xmlStrEqual(name
, (const xmlChar
*) "NOTATION"))
2353 type
= SGML_CATA_NOTATION
;
2354 else if (xmlStrEqual(name
, (const xmlChar
*) "SGMLDECL"))
2355 type
= SGML_CATA_SGMLDECL
;
2356 else if (xmlStrEqual(name
, (const xmlChar
*) "DOCUMENT"))
2357 type
= SGML_CATA_DOCUMENT
;
2358 else if (xmlStrEqual(name
, (const xmlChar
*) "CATALOG"))
2359 type
= SGML_CATA_CATALOG
;
2360 else if (xmlStrEqual(name
, (const xmlChar
*) "BASE"))
2361 type
= SGML_CATA_BASE
;
2362 else if (xmlStrEqual(name
, (const xmlChar
*) "OVERRIDE")) {
2364 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2376 case SGML_CATA_ENTITY
:
2378 type
= SGML_CATA_PENTITY
;
2379 case SGML_CATA_PENTITY
:
2380 case SGML_CATA_DOCTYPE
:
2381 case SGML_CATA_LINKTYPE
:
2382 case SGML_CATA_NOTATION
:
2383 cur
= xmlParseSGMLCatalogName(cur
, &name
);
2388 if (!IS_BLANK_CH(*cur
)) {
2393 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2399 case SGML_CATA_PUBLIC
:
2400 case SGML_CATA_SYSTEM
:
2401 case SGML_CATA_DELEGATE
:
2402 cur
= xmlParseSGMLCatalogPubid(cur
, &name
);
2407 if (type
!= SGML_CATA_SYSTEM
) {
2410 normid
= xmlCatalogNormalizePublic(name
);
2411 if (normid
!= NULL
) {
2422 if (!IS_BLANK_CH(*cur
)) {
2427 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2433 case SGML_CATA_BASE
:
2434 case SGML_CATA_CATALOG
:
2435 case SGML_CATA_DOCUMENT
:
2436 case SGML_CATA_SGMLDECL
:
2437 cur
= xmlParseSGMLCatalogPubid(cur
, &sysid
);
2452 } else if (type
== SGML_CATA_BASE
) {
2455 base
= xmlStrdup(sysid
);
2456 } else if ((type
== SGML_CATA_PUBLIC
) ||
2457 (type
== SGML_CATA_SYSTEM
)) {
2460 filename
= xmlBuildURI(sysid
, base
);
2461 if (filename
!= NULL
) {
2462 xmlCatalogEntryPtr entry
;
2464 entry
= xmlNewCatalogEntry(type
, name
, filename
,
2465 NULL
, XML_CATA_PREFER_NONE
, NULL
);
2466 res
= xmlHashAddEntry(catal
->sgml
, name
, entry
);
2468 xmlFreeCatalogEntry(entry
);
2473 } else if (type
== SGML_CATA_CATALOG
) {
2475 xmlCatalogEntryPtr entry
;
2477 entry
= xmlNewCatalogEntry(type
, sysid
, NULL
, NULL
,
2478 XML_CATA_PREFER_NONE
, NULL
);
2479 res
= xmlHashAddEntry(catal
->sgml
, sysid
, entry
);
2481 xmlFreeCatalogEntry(entry
);
2486 filename
= xmlBuildURI(sysid
, base
);
2487 if (filename
!= NULL
) {
2488 xmlExpandCatalog(catal
, (const char *)filename
);
2494 * drop anything else we won't handle it
2509 /************************************************************************
2511 * SGML Catalog handling *
2513 ************************************************************************/
2516 * xmlCatalogGetSGMLPublic:
2517 * @catal: an SGML catalog hash
2518 * @pubID: the public ID string
2520 * Try to lookup the catalog local reference associated to a public ID
2522 * Returns the local resource if found or NULL otherwise.
2524 static const xmlChar
*
2525 xmlCatalogGetSGMLPublic(xmlHashTablePtr catal
, const xmlChar
*pubID
) {
2526 xmlCatalogEntryPtr entry
;
2532 normid
= xmlCatalogNormalizePublic(pubID
);
2534 pubID
= (*normid
!= 0 ? normid
: NULL
);
2536 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, pubID
);
2537 if (entry
== NULL
) {
2542 if (entry
->type
== SGML_CATA_PUBLIC
) {
2553 * xmlCatalogGetSGMLSystem:
2554 * @catal: an SGML catalog hash
2555 * @sysID: the system ID string
2557 * Try to lookup the catalog local reference for a system ID
2559 * Returns the local resource if found or NULL otherwise.
2561 static const xmlChar
*
2562 xmlCatalogGetSGMLSystem(xmlHashTablePtr catal
, const xmlChar
*sysID
) {
2563 xmlCatalogEntryPtr entry
;
2568 entry
= (xmlCatalogEntryPtr
) xmlHashLookup(catal
, sysID
);
2571 if (entry
->type
== SGML_CATA_SYSTEM
)
2577 * xmlCatalogSGMLResolve:
2578 * @catal: the SGML catalog
2579 * @pubID: the public ID string
2580 * @sysID: the system ID string
2582 * Do a complete resolution lookup of an External Identifier
2584 * Returns the URI of the resource or NULL if not found
2586 static const xmlChar
*
2587 xmlCatalogSGMLResolve(xmlCatalogPtr catal
, const xmlChar
*pubID
,
2588 const xmlChar
*sysID
) {
2589 const xmlChar
*ret
= NULL
;
2591 if (catal
->sgml
== NULL
)
2595 ret
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2599 ret
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2603 /************************************************************************
2605 * Specific Public interfaces *
2607 ************************************************************************/
2610 * xmlLoadSGMLSuperCatalog:
2611 * @filename: a file path
2613 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2614 * references. This is only needed for manipulating SGML Super Catalogs
2615 * like adding and removing CATALOG or DELEGATE entries.
2617 * Returns the catalog parsed or NULL in case of error
2620 xmlLoadSGMLSuperCatalog(const char *filename
)
2623 xmlCatalogPtr catal
;
2626 content
= xmlLoadFileContent(filename
);
2627 if (content
== NULL
)
2630 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2631 if (catal
== NULL
) {
2636 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 1);
2639 xmlFreeCatalog(catal
);
2647 * @filename: a file path
2649 * Load the catalog and build the associated data structures.
2650 * This can be either an XML Catalog or an SGML Catalog
2651 * It will recurse in SGML CATALOG entries. On the other hand XML
2652 * Catalogs are not handled recursively.
2654 * Returns the catalog parsed or NULL in case of error
2657 xmlLoadACatalog(const char *filename
)
2661 xmlCatalogPtr catal
;
2664 content
= xmlLoadFileContent(filename
);
2665 if (content
== NULL
)
2671 while ((*first
!= 0) && (*first
!= '-') && (*first
!= '<') &&
2672 (!(((*first
>= 'A') && (*first
<= 'Z')) ||
2673 ((*first
>= 'a') && (*first
<= 'z')))))
2676 if (*first
!= '<') {
2677 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2678 if (catal
== NULL
) {
2682 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2684 xmlFreeCatalog(catal
);
2689 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
, xmlCatalogDefaultPrefer
);
2690 if (catal
== NULL
) {
2694 catal
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2695 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2704 * @filename: a file path
2706 * Load the catalog and expand the existing catal structure.
2707 * This can be either an XML Catalog or an SGML Catalog
2709 * Returns 0 in case of success, -1 in case of error
2712 xmlExpandCatalog(xmlCatalogPtr catal
, const char *filename
)
2716 if ((catal
== NULL
) || (filename
== NULL
))
2720 if (catal
->type
== XML_SGML_CATALOG_TYPE
) {
2723 content
= xmlLoadFileContent(filename
);
2724 if (content
== NULL
)
2727 ret
= xmlParseSGMLCatalog(catal
, content
, filename
, 0);
2734 xmlCatalogEntryPtr tmp
, cur
;
2735 tmp
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
2736 NULL
, BAD_CAST filename
, xmlCatalogDefaultPrefer
, NULL
);
2742 while (cur
->next
!= NULL
) cur
= cur
->next
;
2750 * xmlACatalogResolveSystem:
2752 * @sysID: the system ID string
2754 * Try to lookup the catalog resource for a system ID
2756 * Returns the resource if found or NULL otherwise, the value returned
2757 * must be freed by the caller.
2760 xmlACatalogResolveSystem(xmlCatalogPtr catal
, const xmlChar
*sysID
) {
2761 xmlChar
*ret
= NULL
;
2763 if ((sysID
== NULL
) || (catal
== NULL
))
2766 if (xmlDebugCatalogs
)
2767 xmlGenericError(xmlGenericErrorContext
,
2768 "Resolve sysID %s\n", sysID
);
2770 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2771 ret
= xmlCatalogListXMLResolve(catal
->xml
, NULL
, sysID
);
2772 if (ret
== XML_CATAL_BREAK
)
2775 const xmlChar
*sgml
;
2777 sgml
= xmlCatalogGetSGMLSystem(catal
->sgml
, sysID
);
2779 ret
= xmlStrdup(sgml
);
2785 * xmlACatalogResolvePublic:
2787 * @pubID: the public ID string
2789 * Try to lookup the catalog local reference associated to a public ID in that catalog
2791 * Returns the local resource if found or NULL otherwise, the value returned
2792 * must be freed by the caller.
2795 xmlACatalogResolvePublic(xmlCatalogPtr catal
, const xmlChar
*pubID
) {
2796 xmlChar
*ret
= NULL
;
2798 if ((pubID
== NULL
) || (catal
== NULL
))
2801 if (xmlDebugCatalogs
)
2802 xmlGenericError(xmlGenericErrorContext
,
2803 "Resolve pubID %s\n", pubID
);
2805 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2806 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, NULL
);
2807 if (ret
== XML_CATAL_BREAK
)
2810 const xmlChar
*sgml
;
2812 sgml
= xmlCatalogGetSGMLPublic(catal
->sgml
, pubID
);
2814 ret
= xmlStrdup(sgml
);
2820 * xmlACatalogResolve:
2822 * @pubID: the public ID string
2823 * @sysID: the system ID string
2825 * Do a complete resolution lookup of an External Identifier
2827 * Returns the URI of the resource or NULL if not found, it must be freed
2831 xmlACatalogResolve(xmlCatalogPtr catal
, const xmlChar
* pubID
,
2832 const xmlChar
* sysID
)
2834 xmlChar
*ret
= NULL
;
2836 if (((pubID
== NULL
) && (sysID
== NULL
)) || (catal
== NULL
))
2839 if (xmlDebugCatalogs
) {
2840 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
2841 xmlGenericError(xmlGenericErrorContext
,
2842 "Resolve: pubID %s sysID %s\n", pubID
, sysID
);
2843 } else if (pubID
!= NULL
) {
2844 xmlGenericError(xmlGenericErrorContext
,
2845 "Resolve: pubID %s\n", pubID
);
2847 xmlGenericError(xmlGenericErrorContext
,
2848 "Resolve: sysID %s\n", sysID
);
2852 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2853 ret
= xmlCatalogListXMLResolve(catal
->xml
, pubID
, sysID
);
2854 if (ret
== XML_CATAL_BREAK
)
2857 const xmlChar
*sgml
;
2859 sgml
= xmlCatalogSGMLResolve(catal
, pubID
, sysID
);
2861 ret
= xmlStrdup(sgml
);
2867 * xmlACatalogResolveURI:
2871 * Do a complete resolution lookup of an URI
2873 * Returns the URI of the resource or NULL if not found, it must be freed
2877 xmlACatalogResolveURI(xmlCatalogPtr catal
, const xmlChar
*URI
) {
2878 xmlChar
*ret
= NULL
;
2880 if ((URI
== NULL
) || (catal
== NULL
))
2883 if (xmlDebugCatalogs
)
2884 xmlGenericError(xmlGenericErrorContext
,
2885 "Resolve URI %s\n", URI
);
2887 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2888 ret
= xmlCatalogListXMLResolveURI(catal
->xml
, URI
);
2889 if (ret
== XML_CATAL_BREAK
)
2892 const xmlChar
*sgml
;
2894 sgml
= xmlCatalogSGMLResolve(catal
, NULL
, URI
);
2896 sgml
= xmlStrdup(sgml
);
2901 #ifdef LIBXML_OUTPUT_ENABLED
2907 * Dump the given catalog to the given file.
2910 xmlACatalogDump(xmlCatalogPtr catal
, FILE *out
) {
2911 if ((out
== NULL
) || (catal
== NULL
))
2914 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2915 xmlDumpXMLCatalog(out
, catal
->xml
);
2917 xmlHashScan(catal
->sgml
,
2918 (xmlHashScanner
) xmlCatalogDumpEntry
, out
);
2921 #endif /* LIBXML_OUTPUT_ENABLED */
2926 * @type: the type of record to add to the catalog
2927 * @orig: the system, public or prefix to match
2928 * @replace: the replacement value for the match
2930 * Add an entry in the catalog, it may overwrite existing but
2931 * different entries.
2933 * Returns 0 if successful, -1 otherwise
2936 xmlACatalogAdd(xmlCatalogPtr catal
, const xmlChar
* type
,
2937 const xmlChar
* orig
, const xmlChar
* replace
)
2944 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2945 res
= xmlAddXMLCatalog(catal
->xml
, type
, orig
, replace
);
2947 xmlCatalogEntryType cattype
;
2949 cattype
= xmlGetSGMLCatalogEntryType(type
);
2950 if (cattype
!= XML_CATA_NONE
) {
2951 xmlCatalogEntryPtr entry
;
2953 entry
= xmlNewCatalogEntry(cattype
, orig
, replace
, NULL
,
2954 XML_CATA_PREFER_NONE
, NULL
);
2955 if (catal
->sgml
== NULL
)
2956 catal
->sgml
= xmlHashCreate(10);
2957 res
= xmlHashAddEntry(catal
->sgml
, orig
, entry
);
2964 * xmlACatalogRemove:
2966 * @value: the value to remove
2968 * Remove an entry from the catalog
2970 * Returns the number of entries removed if successful, -1 otherwise
2973 xmlACatalogRemove(xmlCatalogPtr catal
, const xmlChar
*value
) {
2976 if ((catal
== NULL
) || (value
== NULL
))
2979 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
2980 res
= xmlDelXMLCatalog(catal
->xml
, value
);
2982 res
= xmlHashRemoveEntry(catal
->sgml
, value
,
2983 (xmlHashDeallocator
) xmlFreeCatalogEntry
);
2992 * @sgml: should this create an SGML catalog
2994 * create a new Catalog.
2996 * Returns the xmlCatalogPtr or NULL in case of error
2999 xmlNewCatalog(int sgml
) {
3000 xmlCatalogPtr catal
= NULL
;
3003 catal
= xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE
,
3004 xmlCatalogDefaultPrefer
);
3005 if ((catal
!= NULL
) && (catal
->sgml
== NULL
))
3006 catal
->sgml
= xmlHashCreate(10);
3008 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3009 xmlCatalogDefaultPrefer
);
3014 * xmlCatalogIsEmpty:
3015 * @catal: should this create an SGML catalog
3017 * Check is a catalog is empty
3019 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3022 xmlCatalogIsEmpty(xmlCatalogPtr catal
) {
3026 if (catal
->type
== XML_XML_CATALOG_TYPE
) {
3027 if (catal
->xml
== NULL
)
3029 if ((catal
->xml
->type
!= XML_CATA_CATALOG
) &&
3030 (catal
->xml
->type
!= XML_CATA_BROKEN_CATALOG
))
3032 if (catal
->xml
->children
== NULL
)
3038 if (catal
->sgml
== NULL
)
3040 res
= xmlHashSize(catal
->sgml
);
3049 /************************************************************************
3051 * Public interfaces manipulating the global shared default catalog *
3053 ************************************************************************/
3056 * xmlInitializeCatalogData:
3058 * Do the catalog initialization only of global data, doesn't try to load
3059 * any catalog actually.
3060 * this function is not thread safe, catalog initialization should
3061 * preferably be done once at startup
3064 xmlInitializeCatalogData(void) {
3065 if (xmlCatalogInitialized
!= 0)
3068 if (getenv("XML_DEBUG_CATALOG"))
3069 xmlDebugCatalogs
= 1;
3070 xmlCatalogMutex
= xmlNewRMutex();
3072 xmlCatalogInitialized
= 1;
3075 * xmlInitializeCatalog:
3077 * Do the catalog initialization.
3078 * this function is not thread safe, catalog initialization should
3079 * preferably be done once at startup
3082 xmlInitializeCatalog(void) {
3083 if (xmlCatalogInitialized
!= 0)
3086 xmlInitializeCatalogData();
3087 xmlRMutexLock(xmlCatalogMutex
);
3089 if (getenv("XML_DEBUG_CATALOG"))
3090 xmlDebugCatalogs
= 1;
3092 if (xmlDefaultCatalog
== NULL
) {
3093 const char *catalogs
;
3095 const char *cur
, *paths
;
3096 xmlCatalogPtr catal
;
3097 xmlCatalogEntryPtr
*nextent
;
3099 catalogs
= (const char *) getenv("XML_CATALOG_FILES");
3100 if (catalogs
== NULL
)
3101 #if defined(_WIN32) && defined(_MSC_VER)
3104 hmodule
= GetModuleHandleA("libxml2.dll");
3105 if (hmodule
== NULL
)
3106 hmodule
= GetModuleHandleA(NULL
);
3107 if (hmodule
!= NULL
) {
3109 unsigned long len
= GetModuleFileNameA(hmodule
, buf
, 255);
3111 char* p
= &(buf
[len
]);
3112 while (*p
!= '\\' && p
> buf
)
3116 strncpy(p
, "\\..\\etc\\catalog", 255 - (p
- buf
));
3117 uri
= xmlCanonicPath(buf
);
3119 strncpy(XML_XML_DEFAULT_CATALOG
, uri
, 255);
3125 catalogs
= XML_XML_DEFAULT_CATALOG
;
3128 catalogs
= XML_XML_DEFAULT_CATALOG
;
3131 catal
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3132 xmlCatalogDefaultPrefer
);
3133 if (catal
!= NULL
) {
3134 /* the XML_CATALOG_FILES envvar is allowed to contain a
3135 space-separated list of entries. */
3137 nextent
= &catal
->xml
;
3138 while (*cur
!= '\0') {
3139 while (xmlIsBlank_ch(*cur
))
3143 while ((*cur
!= 0) && (!xmlIsBlank_ch(*cur
)))
3145 path
= (char *) xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3147 *nextent
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3148 NULL
, BAD_CAST path
, xmlCatalogDefaultPrefer
, NULL
);
3149 if (*nextent
!= NULL
)
3150 nextent
= &((*nextent
)->next
);
3155 xmlDefaultCatalog
= catal
;
3159 xmlRMutexUnlock(xmlCatalogMutex
);
3165 * @filename: a file path
3167 * Load the catalog and makes its definitions effective for the default
3168 * external entity loader. It will recurse in SGML CATALOG entries.
3169 * this function is not thread safe, catalog initialization should
3170 * preferably be done once at startup
3172 * Returns 0 in case of success -1 in case of error
3175 xmlLoadCatalog(const char *filename
)
3178 xmlCatalogPtr catal
;
3180 if (!xmlCatalogInitialized
)
3181 xmlInitializeCatalogData();
3183 xmlRMutexLock(xmlCatalogMutex
);
3185 if (xmlDefaultCatalog
== NULL
) {
3186 catal
= xmlLoadACatalog(filename
);
3187 if (catal
== NULL
) {
3188 xmlRMutexUnlock(xmlCatalogMutex
);
3192 xmlDefaultCatalog
= catal
;
3193 xmlRMutexUnlock(xmlCatalogMutex
);
3197 ret
= xmlExpandCatalog(xmlDefaultCatalog
, filename
);
3198 xmlRMutexUnlock(xmlCatalogMutex
);
3204 * @pathss: a list of directories separated by a colon or a space.
3206 * Load the catalogs and makes their definitions effective for the default
3207 * external entity loader.
3208 * this function is not thread safe, catalog initialization should
3209 * preferably be done once at startup
3212 xmlLoadCatalogs(const char *pathss
) {
3221 while ((cur
!= NULL
) && (*cur
!= 0)) {
3222 while (xmlIsBlank_ch(*cur
)) cur
++;
3225 while ((*cur
!= 0) && (*cur
!= ':') && (!xmlIsBlank_ch(*cur
)))
3227 path
= xmlStrndup((const xmlChar
*)paths
, cur
- paths
);
3229 xmlLoadCatalog((const char *) path
);
3239 * xmlCatalogCleanup:
3241 * Free up all the memory associated with catalogs
3244 xmlCatalogCleanup(void) {
3245 if (xmlCatalogInitialized
== 0)
3248 xmlRMutexLock(xmlCatalogMutex
);
3249 if (xmlDebugCatalogs
)
3250 xmlGenericError(xmlGenericErrorContext
,
3251 "Catalogs cleanup\n");
3252 if (xmlCatalogXMLFiles
!= NULL
)
3253 xmlHashFree(xmlCatalogXMLFiles
,
3254 (xmlHashDeallocator
)xmlFreeCatalogHashEntryList
);
3255 xmlCatalogXMLFiles
= NULL
;
3256 if (xmlDefaultCatalog
!= NULL
)
3257 xmlFreeCatalog(xmlDefaultCatalog
);
3258 xmlDefaultCatalog
= NULL
;
3259 xmlDebugCatalogs
= 0;
3260 xmlCatalogInitialized
= 0;
3261 xmlRMutexUnlock(xmlCatalogMutex
);
3262 xmlFreeRMutex(xmlCatalogMutex
);
3266 * xmlCatalogResolveSystem:
3267 * @sysID: the system ID string
3269 * Try to lookup the catalog resource for a system ID
3271 * Returns the resource if found or NULL otherwise, the value returned
3272 * must be freed by the caller.
3275 xmlCatalogResolveSystem(const xmlChar
*sysID
) {
3278 if (!xmlCatalogInitialized
)
3279 xmlInitializeCatalog();
3281 ret
= xmlACatalogResolveSystem(xmlDefaultCatalog
, sysID
);
3286 * xmlCatalogResolvePublic:
3287 * @pubID: the public ID string
3289 * Try to lookup the catalog reference associated to a public ID
3291 * Returns the resource if found or NULL otherwise, the value returned
3292 * must be freed by the caller.
3295 xmlCatalogResolvePublic(const xmlChar
*pubID
) {
3298 if (!xmlCatalogInitialized
)
3299 xmlInitializeCatalog();
3301 ret
= xmlACatalogResolvePublic(xmlDefaultCatalog
, pubID
);
3306 * xmlCatalogResolve:
3307 * @pubID: the public ID string
3308 * @sysID: the system ID string
3310 * Do a complete resolution lookup of an External Identifier
3312 * Returns the URI of the resource or NULL if not found, it must be freed
3316 xmlCatalogResolve(const xmlChar
*pubID
, const xmlChar
*sysID
) {
3319 if (!xmlCatalogInitialized
)
3320 xmlInitializeCatalog();
3322 ret
= xmlACatalogResolve(xmlDefaultCatalog
, pubID
, sysID
);
3327 * xmlCatalogResolveURI:
3330 * Do a complete resolution lookup of an URI
3332 * Returns the URI of the resource or NULL if not found, it must be freed
3336 xmlCatalogResolveURI(const xmlChar
*URI
) {
3339 if (!xmlCatalogInitialized
)
3340 xmlInitializeCatalog();
3342 ret
= xmlACatalogResolveURI(xmlDefaultCatalog
, URI
);
3346 #ifdef LIBXML_OUTPUT_ENABLED
3351 * Dump all the global catalog content to the given file.
3354 xmlCatalogDump(FILE *out
) {
3358 if (!xmlCatalogInitialized
)
3359 xmlInitializeCatalog();
3361 xmlACatalogDump(xmlDefaultCatalog
, out
);
3363 #endif /* LIBXML_OUTPUT_ENABLED */
3367 * @type: the type of record to add to the catalog
3368 * @orig: the system, public or prefix to match
3369 * @replace: the replacement value for the match
3371 * Add an entry in the catalog, it may overwrite existing but
3372 * different entries.
3373 * If called before any other catalog routine, allows to override the
3374 * default shared catalog put in place by xmlInitializeCatalog();
3376 * Returns 0 if successful, -1 otherwise
3379 xmlCatalogAdd(const xmlChar
*type
, const xmlChar
*orig
, const xmlChar
*replace
) {
3382 if (!xmlCatalogInitialized
)
3383 xmlInitializeCatalogData();
3385 xmlRMutexLock(xmlCatalogMutex
);
3387 * Specific case where one want to override the default catalog
3388 * put in place by xmlInitializeCatalog();
3390 if ((xmlDefaultCatalog
== NULL
) &&
3391 (xmlStrEqual(type
, BAD_CAST
"catalog"))) {
3392 xmlDefaultCatalog
= xmlCreateNewCatalog(XML_XML_CATALOG_TYPE
,
3393 xmlCatalogDefaultPrefer
);
3394 xmlDefaultCatalog
->xml
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
,
3395 orig
, NULL
, xmlCatalogDefaultPrefer
, NULL
);
3397 xmlRMutexUnlock(xmlCatalogMutex
);
3401 res
= xmlACatalogAdd(xmlDefaultCatalog
, type
, orig
, replace
);
3402 xmlRMutexUnlock(xmlCatalogMutex
);
3408 * @value: the value to remove
3410 * Remove an entry from the catalog
3412 * Returns the number of entries removed if successful, -1 otherwise
3415 xmlCatalogRemove(const xmlChar
*value
) {
3418 if (!xmlCatalogInitialized
)
3419 xmlInitializeCatalog();
3421 xmlRMutexLock(xmlCatalogMutex
);
3422 res
= xmlACatalogRemove(xmlDefaultCatalog
, value
);
3423 xmlRMutexUnlock(xmlCatalogMutex
);
3428 * xmlCatalogConvert:
3430 * Convert all the SGML catalog entries as XML ones
3432 * Returns the number of entries converted if successful, -1 otherwise
3435 xmlCatalogConvert(void) {
3438 if (!xmlCatalogInitialized
)
3439 xmlInitializeCatalog();
3441 xmlRMutexLock(xmlCatalogMutex
);
3442 res
= xmlConvertSGMLCatalog(xmlDefaultCatalog
);
3443 xmlRMutexUnlock(xmlCatalogMutex
);
3447 /************************************************************************
3449 * Public interface manipulating the common preferences *
3451 ************************************************************************/
3454 * xmlCatalogGetDefaults:
3456 * Used to get the user preference w.r.t. to what catalogs should
3459 * Returns the current xmlCatalogAllow value
3462 xmlCatalogGetDefaults(void) {
3463 return(xmlCatalogDefaultAllow
);
3467 * xmlCatalogSetDefaults:
3468 * @allow: what catalogs should be accepted
3470 * Used to set the user preference w.r.t. to what catalogs should
3474 xmlCatalogSetDefaults(xmlCatalogAllow allow
) {
3475 if (xmlDebugCatalogs
) {
3477 case XML_CATA_ALLOW_NONE
:
3478 xmlGenericError(xmlGenericErrorContext
,
3479 "Disabling catalog usage\n");
3481 case XML_CATA_ALLOW_GLOBAL
:
3482 xmlGenericError(xmlGenericErrorContext
,
3483 "Allowing only global catalogs\n");
3485 case XML_CATA_ALLOW_DOCUMENT
:
3486 xmlGenericError(xmlGenericErrorContext
,
3487 "Allowing only catalogs from the document\n");
3489 case XML_CATA_ALLOW_ALL
:
3490 xmlGenericError(xmlGenericErrorContext
,
3491 "Allowing all catalogs\n");
3495 xmlCatalogDefaultAllow
= allow
;
3499 * xmlCatalogSetDefaultPrefer:
3500 * @prefer: the default preference for delegation
3502 * Allows to set the preference between public and system for deletion
3503 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3504 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3506 * Returns the previous value of the default preference for delegation
3509 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer
) {
3510 xmlCatalogPrefer ret
= xmlCatalogDefaultPrefer
;
3512 if (prefer
== XML_CATA_PREFER_NONE
)
3515 if (xmlDebugCatalogs
) {
3517 case XML_CATA_PREFER_PUBLIC
:
3518 xmlGenericError(xmlGenericErrorContext
,
3519 "Setting catalog preference to PUBLIC\n");
3521 case XML_CATA_PREFER_SYSTEM
:
3522 xmlGenericError(xmlGenericErrorContext
,
3523 "Setting catalog preference to SYSTEM\n");
3525 case XML_CATA_PREFER_NONE
:
3529 xmlCatalogDefaultPrefer
= prefer
;
3534 * xmlCatalogSetDebug:
3535 * @level: the debug level of catalogs required
3537 * Used to set the debug level for catalog operation, 0 disable
3538 * debugging, 1 enable it
3540 * Returns the previous value of the catalog debugging level
3543 xmlCatalogSetDebug(int level
) {
3544 int ret
= xmlDebugCatalogs
;
3547 xmlDebugCatalogs
= 0;
3549 xmlDebugCatalogs
= level
;
3553 /************************************************************************
3555 * Minimal interfaces used for per-document catalogs by the parser *
3557 ************************************************************************/
3560 * xmlCatalogFreeLocal:
3561 * @catalogs: a document's list of catalogs
3563 * Free up the memory associated to the catalog list
3566 xmlCatalogFreeLocal(void *catalogs
) {
3567 xmlCatalogEntryPtr catal
;
3569 if (!xmlCatalogInitialized
)
3570 xmlInitializeCatalog();
3572 catal
= (xmlCatalogEntryPtr
) catalogs
;
3574 xmlFreeCatalogEntryList(catal
);
3579 * xmlCatalogAddLocal:
3580 * @catalogs: a document's list of catalogs
3581 * @URL: the URL to a new local catalog
3583 * Add the new entry to the catalog list
3585 * Returns the updated list
3588 xmlCatalogAddLocal(void *catalogs
, const xmlChar
*URL
) {
3589 xmlCatalogEntryPtr catal
, add
;
3591 if (!xmlCatalogInitialized
)
3592 xmlInitializeCatalog();
3597 if (xmlDebugCatalogs
)
3598 xmlGenericError(xmlGenericErrorContext
,
3599 "Adding document catalog %s\n", URL
);
3601 add
= xmlNewCatalogEntry(XML_CATA_CATALOG
, NULL
, URL
, NULL
,
3602 xmlCatalogDefaultPrefer
, NULL
);
3606 catal
= (xmlCatalogEntryPtr
) catalogs
;
3608 return((void *) add
);
3610 while (catal
->next
!= NULL
)
3611 catal
= catal
->next
;
3617 * xmlCatalogLocalResolve:
3618 * @catalogs: a document's list of catalogs
3619 * @pubID: the public ID string
3620 * @sysID: the system ID string
3622 * Do a complete resolution lookup of an External Identifier using a
3623 * document's private catalog list
3625 * Returns the URI of the resource or NULL if not found, it must be freed
3629 xmlCatalogLocalResolve(void *catalogs
, const xmlChar
*pubID
,
3630 const xmlChar
*sysID
) {
3631 xmlCatalogEntryPtr catal
;
3634 if (!xmlCatalogInitialized
)
3635 xmlInitializeCatalog();
3637 if ((pubID
== NULL
) && (sysID
== NULL
))
3640 if (xmlDebugCatalogs
) {
3641 if ((pubID
!= NULL
) && (sysID
!= NULL
)) {
3642 xmlGenericError(xmlGenericErrorContext
,
3643 "Local Resolve: pubID %s sysID %s\n", pubID
, sysID
);
3644 } else if (pubID
!= NULL
) {
3645 xmlGenericError(xmlGenericErrorContext
,
3646 "Local Resolve: pubID %s\n", pubID
);
3648 xmlGenericError(xmlGenericErrorContext
,
3649 "Local Resolve: sysID %s\n", sysID
);
3653 catal
= (xmlCatalogEntryPtr
) catalogs
;
3656 ret
= xmlCatalogListXMLResolve(catal
, pubID
, sysID
);
3657 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3663 * xmlCatalogLocalResolveURI:
3664 * @catalogs: a document's list of catalogs
3667 * Do a complete resolution lookup of an URI using a
3668 * document's private catalog list
3670 * Returns the URI of the resource or NULL if not found, it must be freed
3674 xmlCatalogLocalResolveURI(void *catalogs
, const xmlChar
*URI
) {
3675 xmlCatalogEntryPtr catal
;
3678 if (!xmlCatalogInitialized
)
3679 xmlInitializeCatalog();
3684 if (xmlDebugCatalogs
)
3685 xmlGenericError(xmlGenericErrorContext
,
3686 "Resolve URI %s\n", URI
);
3688 catal
= (xmlCatalogEntryPtr
) catalogs
;
3691 ret
= xmlCatalogListXMLResolveURI(catal
, URI
);
3692 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
))
3697 /************************************************************************
3699 * Deprecated interfaces *
3701 ************************************************************************/
3703 * xmlCatalogGetSystem:
3704 * @sysID: the system ID string
3706 * Try to lookup the catalog reference associated to a system ID
3707 * DEPRECATED, use xmlCatalogResolveSystem()
3709 * Returns the resource if found or NULL otherwise.
3712 xmlCatalogGetSystem(const xmlChar
*sysID
) {
3714 static xmlChar result
[1000];
3717 if (!xmlCatalogInitialized
)
3718 xmlInitializeCatalog();
3721 xmlGenericError(xmlGenericErrorContext
,
3722 "Use of deprecated xmlCatalogGetSystem() call\n");
3730 * Check first the XML catalogs
3732 if (xmlDefaultCatalog
!= NULL
) {
3733 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, NULL
, sysID
);
3734 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3735 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3736 result
[sizeof(result
) - 1] = 0;
3741 if (xmlDefaultCatalog
!= NULL
)
3742 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog
->sgml
, sysID
));
3747 * xmlCatalogGetPublic:
3748 * @pubID: the public ID string
3750 * Try to lookup the catalog reference associated to a public ID
3751 * DEPRECATED, use xmlCatalogResolvePublic()
3753 * Returns the resource if found or NULL otherwise.
3756 xmlCatalogGetPublic(const xmlChar
*pubID
) {
3758 static xmlChar result
[1000];
3761 if (!xmlCatalogInitialized
)
3762 xmlInitializeCatalog();
3765 xmlGenericError(xmlGenericErrorContext
,
3766 "Use of deprecated xmlCatalogGetPublic() call\n");
3774 * Check first the XML catalogs
3776 if (xmlDefaultCatalog
!= NULL
) {
3777 ret
= xmlCatalogListXMLResolve(xmlDefaultCatalog
->xml
, pubID
, NULL
);
3778 if ((ret
!= NULL
) && (ret
!= XML_CATAL_BREAK
)) {
3779 snprintf((char *) result
, sizeof(result
) - 1, "%s", (char *) ret
);
3780 result
[sizeof(result
) - 1] = 0;
3785 if (xmlDefaultCatalog
!= NULL
)
3786 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog
->sgml
, pubID
));
3790 #define bottom_catalog
3791 #include "elfgcchack.h"
3792 #endif /* LIBXML_CATALOG_ENABLED */