xref: /reactos/sdk/lib/3rdparty/libxml2/catalog.c (revision fc82f8e2)
1c2c66affSColin Finck /**
2c2c66affSColin Finck  * catalog.c: set of generic Catalog related routines
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Reference:  SGML Open Technical Resolution TR9401:1997.
5c2c66affSColin Finck  *             http://www.jclark.com/sp/catalog.htm
6c2c66affSColin Finck  *
7c2c66affSColin Finck  *             XML Catalogs Working Draft 06 August 2001
8c2c66affSColin Finck  *             http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9c2c66affSColin Finck  *
10c2c66affSColin Finck  * See Copyright for the status of this software.
11c2c66affSColin Finck  *
12c2c66affSColin Finck  * Daniel.Veillard@imag.fr
13c2c66affSColin Finck  */
14c2c66affSColin Finck 
15c2c66affSColin Finck #define IN_LIBXML
16c2c66affSColin Finck #include "libxml.h"
17c2c66affSColin Finck 
18c2c66affSColin Finck #ifdef LIBXML_CATALOG_ENABLED
19c2c66affSColin Finck #ifdef HAVE_SYS_TYPES_H
20c2c66affSColin Finck #include <sys/types.h>
21c2c66affSColin Finck #endif
22c2c66affSColin Finck #ifdef HAVE_SYS_STAT_H
23c2c66affSColin Finck #include <sys/stat.h>
24c2c66affSColin Finck #endif
25c2c66affSColin Finck #ifdef HAVE_UNISTD_H
26c2c66affSColin Finck #include <unistd.h>
27c2c66affSColin Finck #endif
28c2c66affSColin Finck #ifdef HAVE_FCNTL_H
29c2c66affSColin Finck #include <fcntl.h>
30c2c66affSColin Finck #endif
31c2c66affSColin Finck #ifdef HAVE_STDLIB_H
32c2c66affSColin Finck #include <stdlib.h>
33c2c66affSColin Finck #endif
34c2c66affSColin Finck #include <string.h>
35c2c66affSColin Finck #include <libxml/xmlmemory.h>
36c2c66affSColin Finck #include <libxml/hash.h>
37c2c66affSColin Finck #include <libxml/uri.h>
38c2c66affSColin Finck #include <libxml/parserInternals.h>
39c2c66affSColin Finck #include <libxml/catalog.h>
40c2c66affSColin Finck #include <libxml/xmlerror.h>
41c2c66affSColin Finck #include <libxml/threads.h>
42c2c66affSColin Finck #include <libxml/globals.h>
43c2c66affSColin Finck 
44c2c66affSColin Finck #include "buf.h"
45c2c66affSColin Finck 
46c2c66affSColin Finck #define MAX_DELEGATE	50
47c2c66affSColin Finck #define MAX_CATAL_DEPTH	50
48c2c66affSColin Finck 
49c2c66affSColin Finck #ifdef _WIN32
50c2c66affSColin Finck # define PATH_SEPARATOR ';'
51c2c66affSColin Finck #else
52c2c66affSColin Finck # define PATH_SEPARATOR ':'
53c2c66affSColin Finck #endif
54c2c66affSColin Finck 
55c2c66affSColin Finck /**
56c2c66affSColin Finck  * TODO:
57c2c66affSColin Finck  *
58c2c66affSColin Finck  * macro to flag unimplemented blocks
59c2c66affSColin Finck  * XML_CATALOG_PREFER user env to select between system/public prefered
60c2c66affSColin Finck  * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
61c2c66affSColin Finck  *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
62c2c66affSColin Finck  *> values "system" and "public".  I have made the default be "system" to
63c2c66affSColin Finck  *> match yours.
64c2c66affSColin Finck  */
65c2c66affSColin Finck #define TODO								\
66c2c66affSColin Finck     xmlGenericError(xmlGenericErrorContext,				\
67c2c66affSColin Finck 	    "Unimplemented block at %s:%d\n",				\
68c2c66affSColin Finck             __FILE__, __LINE__);
69c2c66affSColin Finck 
70c2c66affSColin Finck #define XML_URN_PUBID "urn:publicid:"
71c2c66affSColin Finck #define XML_CATAL_BREAK ((xmlChar *) -1)
72c2c66affSColin Finck #ifndef XML_XML_DEFAULT_CATALOG
73c2c66affSColin Finck #define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
74c2c66affSColin Finck #endif
75c2c66affSColin Finck #ifndef XML_SGML_DEFAULT_CATALOG
76c2c66affSColin Finck #define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
77c2c66affSColin Finck #endif
78c2c66affSColin Finck 
79c2c66affSColin Finck #if defined(_WIN32) && defined(_MSC_VER)
80c2c66affSColin Finck #undef XML_XML_DEFAULT_CATALOG
81c2c66affSColin Finck static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
82c2c66affSColin Finck #if defined(_WIN32_WCE)
83c2c66affSColin Finck /* Windows CE don't have a A variant */
84c2c66affSColin Finck #define GetModuleHandleA GetModuleHandle
85c2c66affSColin Finck #define GetModuleFileNameA GetModuleFileName
86c2c66affSColin Finck #else
87c2c66affSColin Finck #if !defined(_WINDOWS_)
88c2c66affSColin Finck void* __stdcall GetModuleHandleA(const char*);
89c2c66affSColin Finck unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
90c2c66affSColin Finck #endif
91c2c66affSColin Finck #endif
92c2c66affSColin Finck #endif
93c2c66affSColin Finck 
94c2c66affSColin Finck static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
95c2c66affSColin Finck static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
96c2c66affSColin Finck 
97c2c66affSColin Finck /************************************************************************
98c2c66affSColin Finck  *									*
99c2c66affSColin Finck  *			Types, all private				*
100c2c66affSColin Finck  *									*
101c2c66affSColin Finck  ************************************************************************/
102c2c66affSColin Finck 
103c2c66affSColin Finck typedef enum {
104c2c66affSColin Finck     XML_CATA_REMOVED = -1,
105c2c66affSColin Finck     XML_CATA_NONE = 0,
106c2c66affSColin Finck     XML_CATA_CATALOG,
107c2c66affSColin Finck     XML_CATA_BROKEN_CATALOG,
108c2c66affSColin Finck     XML_CATA_NEXT_CATALOG,
109c2c66affSColin Finck     XML_CATA_GROUP,
110c2c66affSColin Finck     XML_CATA_PUBLIC,
111c2c66affSColin Finck     XML_CATA_SYSTEM,
112c2c66affSColin Finck     XML_CATA_REWRITE_SYSTEM,
113c2c66affSColin Finck     XML_CATA_DELEGATE_PUBLIC,
114c2c66affSColin Finck     XML_CATA_DELEGATE_SYSTEM,
115c2c66affSColin Finck     XML_CATA_URI,
116c2c66affSColin Finck     XML_CATA_REWRITE_URI,
117c2c66affSColin Finck     XML_CATA_DELEGATE_URI,
118c2c66affSColin Finck     SGML_CATA_SYSTEM,
119c2c66affSColin Finck     SGML_CATA_PUBLIC,
120c2c66affSColin Finck     SGML_CATA_ENTITY,
121c2c66affSColin Finck     SGML_CATA_PENTITY,
122c2c66affSColin Finck     SGML_CATA_DOCTYPE,
123c2c66affSColin Finck     SGML_CATA_LINKTYPE,
124c2c66affSColin Finck     SGML_CATA_NOTATION,
125c2c66affSColin Finck     SGML_CATA_DELEGATE,
126c2c66affSColin Finck     SGML_CATA_BASE,
127c2c66affSColin Finck     SGML_CATA_CATALOG,
128c2c66affSColin Finck     SGML_CATA_DOCUMENT,
129c2c66affSColin Finck     SGML_CATA_SGMLDECL
130c2c66affSColin Finck } xmlCatalogEntryType;
131c2c66affSColin Finck 
132c2c66affSColin Finck typedef struct _xmlCatalogEntry xmlCatalogEntry;
133c2c66affSColin Finck typedef xmlCatalogEntry *xmlCatalogEntryPtr;
134c2c66affSColin Finck struct _xmlCatalogEntry {
135c2c66affSColin Finck     struct _xmlCatalogEntry *next;
136c2c66affSColin Finck     struct _xmlCatalogEntry *parent;
137c2c66affSColin Finck     struct _xmlCatalogEntry *children;
138c2c66affSColin Finck     xmlCatalogEntryType type;
139c2c66affSColin Finck     xmlChar *name;
140c2c66affSColin Finck     xmlChar *value;
141c2c66affSColin Finck     xmlChar *URL;  /* The expanded URL using the base */
142c2c66affSColin Finck     xmlCatalogPrefer prefer;
143c2c66affSColin Finck     int dealloc;
144c2c66affSColin Finck     int depth;
145c2c66affSColin Finck     struct _xmlCatalogEntry *group;
146c2c66affSColin Finck };
147c2c66affSColin Finck 
148c2c66affSColin Finck typedef enum {
149c2c66affSColin Finck     XML_XML_CATALOG_TYPE = 1,
150c2c66affSColin Finck     XML_SGML_CATALOG_TYPE
151c2c66affSColin Finck } xmlCatalogType;
152c2c66affSColin Finck 
153c2c66affSColin Finck #define XML_MAX_SGML_CATA_DEPTH 10
154c2c66affSColin Finck struct _xmlCatalog {
155c2c66affSColin Finck     xmlCatalogType type;	/* either XML or SGML */
156c2c66affSColin Finck 
157c2c66affSColin Finck     /*
158c2c66affSColin Finck      * SGML Catalogs are stored as a simple hash table of catalog entries
159c2c66affSColin Finck      * Catalog stack to check against overflows when building the
160c2c66affSColin Finck      * SGML catalog
161c2c66affSColin Finck      */
162c2c66affSColin Finck     char *catalTab[XML_MAX_SGML_CATA_DEPTH];	/* stack of catals */
163c2c66affSColin Finck     int          catalNr;	/* Number of current catal streams */
164c2c66affSColin Finck     int          catalMax;	/* Max number of catal streams */
165c2c66affSColin Finck     xmlHashTablePtr sgml;
166c2c66affSColin Finck 
167c2c66affSColin Finck     /*
168c2c66affSColin Finck      * XML Catalogs are stored as a tree of Catalog entries
169c2c66affSColin Finck      */
170c2c66affSColin Finck     xmlCatalogPrefer prefer;
171c2c66affSColin Finck     xmlCatalogEntryPtr xml;
172c2c66affSColin Finck };
173c2c66affSColin Finck 
174c2c66affSColin Finck /************************************************************************
175c2c66affSColin Finck  *									*
176c2c66affSColin Finck  *			Global variables				*
177c2c66affSColin Finck  *									*
178c2c66affSColin Finck  ************************************************************************/
179c2c66affSColin Finck 
180c2c66affSColin Finck /*
181c2c66affSColin Finck  * Those are preferences
182c2c66affSColin Finck  */
183c2c66affSColin Finck static int xmlDebugCatalogs = 0;   /* used for debugging */
184c2c66affSColin Finck static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
185c2c66affSColin Finck static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
186c2c66affSColin Finck 
187c2c66affSColin Finck /*
188c2c66affSColin Finck  * Hash table containing all the trees of XML catalogs parsed by
189c2c66affSColin Finck  * the application.
190c2c66affSColin Finck  */
191c2c66affSColin Finck static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
192c2c66affSColin Finck 
193c2c66affSColin Finck /*
194c2c66affSColin Finck  * The default catalog in use by the application
195c2c66affSColin Finck  */
196c2c66affSColin Finck static xmlCatalogPtr xmlDefaultCatalog = NULL;
197c2c66affSColin Finck 
198c2c66affSColin Finck /*
199c2c66affSColin Finck  * A mutex for modifying the shared global catalog(s)
200c2c66affSColin Finck  * xmlDefaultCatalog tree.
201c2c66affSColin Finck  * It also protects xmlCatalogXMLFiles
202c2c66affSColin Finck  * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
203c2c66affSColin Finck  */
204c2c66affSColin Finck static xmlRMutexPtr xmlCatalogMutex = NULL;
205c2c66affSColin Finck 
206c2c66affSColin Finck /*
207c2c66affSColin Finck  * Whether the catalog support was initialized.
208c2c66affSColin Finck  */
209c2c66affSColin Finck static int xmlCatalogInitialized = 0;
210c2c66affSColin Finck 
211c2c66affSColin Finck /************************************************************************
212c2c66affSColin Finck  *									*
213c2c66affSColin Finck  *			Catalog error handlers				*
214c2c66affSColin Finck  *									*
215c2c66affSColin Finck  ************************************************************************/
216c2c66affSColin Finck 
217c2c66affSColin Finck /**
218c2c66affSColin Finck  * xmlCatalogErrMemory:
219c2c66affSColin Finck  * @extra:  extra informations
220c2c66affSColin Finck  *
221c2c66affSColin Finck  * Handle an out of memory condition
222c2c66affSColin Finck  */
223c2c66affSColin Finck static void
224c2c66affSColin Finck xmlCatalogErrMemory(const char *extra)
225c2c66affSColin Finck {
226c2c66affSColin Finck     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
227c2c66affSColin Finck                     XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
228c2c66affSColin Finck 		    extra, NULL, NULL, 0, 0,
229c2c66affSColin Finck 		    "Memory allocation failed : %s\n", extra);
230c2c66affSColin Finck }
231c2c66affSColin Finck 
232c2c66affSColin Finck /**
233c2c66affSColin Finck  * xmlCatalogErr:
234c2c66affSColin Finck  * @catal: the Catalog entry
235c2c66affSColin Finck  * @node: the context node
236c2c66affSColin Finck  * @msg:  the error message
237c2c66affSColin Finck  * @extra:  extra informations
238c2c66affSColin Finck  *
239c2c66affSColin Finck  * Handle a catalog error
240c2c66affSColin Finck  */
241c2c66affSColin Finck static void LIBXML_ATTR_FORMAT(4,0)
242c2c66affSColin Finck xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
243c2c66affSColin Finck                const char *msg, const xmlChar *str1, const xmlChar *str2,
244c2c66affSColin Finck 	       const xmlChar *str3)
245c2c66affSColin Finck {
246c2c66affSColin Finck     __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
247c2c66affSColin Finck                     error, XML_ERR_ERROR, NULL, 0,
248c2c66affSColin Finck 		    (const char *) str1, (const char *) str2,
249c2c66affSColin Finck 		    (const char *) str3, 0, 0,
250c2c66affSColin Finck 		    msg, str1, str2, str3);
251c2c66affSColin Finck }
252c2c66affSColin Finck 
253c2c66affSColin Finck 
254c2c66affSColin Finck /************************************************************************
255c2c66affSColin Finck  *									*
256c2c66affSColin Finck  *			Allocation and Freeing				*
257c2c66affSColin Finck  *									*
258c2c66affSColin Finck  ************************************************************************/
259c2c66affSColin Finck 
260c2c66affSColin Finck /**
261c2c66affSColin Finck  * xmlNewCatalogEntry:
262c2c66affSColin Finck  * @type:  type of entry
263c2c66affSColin Finck  * @name:  name of the entry
264c2c66affSColin Finck  * @value:  value of the entry
265c2c66affSColin Finck  * @prefer:  the PUBLIC vs. SYSTEM current preference value
266c2c66affSColin Finck  * @group:  for members of a group, the group entry
267c2c66affSColin Finck  *
268c2c66affSColin Finck  * create a new Catalog entry, this type is shared both by XML and
269c2c66affSColin Finck  * SGML catalogs, but the acceptable types values differs.
270c2c66affSColin Finck  *
271c2c66affSColin Finck  * Returns the xmlCatalogEntryPtr or NULL in case of error
272c2c66affSColin Finck  */
273c2c66affSColin Finck static xmlCatalogEntryPtr
274c2c66affSColin Finck xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
275c2c66affSColin Finck 	   const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
276c2c66affSColin Finck 	   xmlCatalogEntryPtr group) {
277c2c66affSColin Finck     xmlCatalogEntryPtr ret;
278c2c66affSColin Finck     xmlChar *normid = NULL;
279c2c66affSColin Finck 
280c2c66affSColin Finck     ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
281c2c66affSColin Finck     if (ret == NULL) {
282c2c66affSColin Finck         xmlCatalogErrMemory("allocating catalog entry");
283c2c66affSColin Finck 	return(NULL);
284c2c66affSColin Finck     }
285c2c66affSColin Finck     ret->next = NULL;
286c2c66affSColin Finck     ret->parent = NULL;
287c2c66affSColin Finck     ret->children = NULL;
288c2c66affSColin Finck     ret->type = type;
289c2c66affSColin Finck     if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
290c2c66affSColin Finck         normid = xmlCatalogNormalizePublic(name);
291c2c66affSColin Finck         if (normid != NULL)
292c2c66affSColin Finck             name = (*normid != 0 ? normid : NULL);
293c2c66affSColin Finck     }
294c2c66affSColin Finck     if (name != NULL)
295c2c66affSColin Finck 	ret->name = xmlStrdup(name);
296c2c66affSColin Finck     else
297c2c66affSColin Finck 	ret->name = NULL;
298c2c66affSColin Finck     if (normid != NULL)
299c2c66affSColin Finck         xmlFree(normid);
300c2c66affSColin Finck     if (value != NULL)
301c2c66affSColin Finck 	ret->value = xmlStrdup(value);
302c2c66affSColin Finck     else
303c2c66affSColin Finck 	ret->value = NULL;
304c2c66affSColin Finck     if (URL == NULL)
305c2c66affSColin Finck 	URL = value;
306c2c66affSColin Finck     if (URL != NULL)
307c2c66affSColin Finck 	ret->URL = xmlStrdup(URL);
308c2c66affSColin Finck     else
309c2c66affSColin Finck 	ret->URL = NULL;
310c2c66affSColin Finck     ret->prefer = prefer;
311c2c66affSColin Finck     ret->dealloc = 0;
312c2c66affSColin Finck     ret->depth = 0;
313c2c66affSColin Finck     ret->group = group;
314c2c66affSColin Finck     return(ret);
315c2c66affSColin Finck }
316c2c66affSColin Finck 
317c2c66affSColin Finck static void
318c2c66affSColin Finck xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
319c2c66affSColin Finck 
320c2c66affSColin Finck /**
321c2c66affSColin Finck  * xmlFreeCatalogEntry:
322c2c66affSColin Finck  * @ret:  a Catalog entry
323c2c66affSColin Finck  *
324c2c66affSColin Finck  * Free the memory allocated to a Catalog entry
325c2c66affSColin Finck  */
326c2c66affSColin Finck static void
327c2c66affSColin Finck xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
328c2c66affSColin Finck     if (ret == NULL)
329c2c66affSColin Finck 	return;
330c2c66affSColin Finck     /*
331c2c66affSColin Finck      * Entries stored in the file hash must be deallocated
332c2c66affSColin Finck      * only by the file hash cleaner !
333c2c66affSColin Finck      */
334c2c66affSColin Finck     if (ret->dealloc == 1)
335c2c66affSColin Finck 	return;
336c2c66affSColin Finck 
337c2c66affSColin Finck     if (xmlDebugCatalogs) {
338c2c66affSColin Finck 	if (ret->name != NULL)
339c2c66affSColin Finck 	    xmlGenericError(xmlGenericErrorContext,
340c2c66affSColin Finck 		    "Free catalog entry %s\n", ret->name);
341c2c66affSColin Finck 	else if (ret->value != NULL)
342c2c66affSColin Finck 	    xmlGenericError(xmlGenericErrorContext,
343c2c66affSColin Finck 		    "Free catalog entry %s\n", ret->value);
344c2c66affSColin Finck 	else
345c2c66affSColin Finck 	    xmlGenericError(xmlGenericErrorContext,
346c2c66affSColin Finck 		    "Free catalog entry\n");
347c2c66affSColin Finck     }
348c2c66affSColin Finck 
349c2c66affSColin Finck     if (ret->name != NULL)
350c2c66affSColin Finck 	xmlFree(ret->name);
351c2c66affSColin Finck     if (ret->value != NULL)
352c2c66affSColin Finck 	xmlFree(ret->value);
353c2c66affSColin Finck     if (ret->URL != NULL)
354c2c66affSColin Finck 	xmlFree(ret->URL);
355c2c66affSColin Finck     xmlFree(ret);
356c2c66affSColin Finck }
357c2c66affSColin Finck 
358c2c66affSColin Finck /**
359c2c66affSColin Finck  * xmlFreeCatalogEntryList:
360c2c66affSColin Finck  * @ret:  a Catalog entry list
361c2c66affSColin Finck  *
362c2c66affSColin Finck  * Free the memory allocated to a full chained list of Catalog entries
363c2c66affSColin Finck  */
364c2c66affSColin Finck static void
365c2c66affSColin Finck xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
366c2c66affSColin Finck     xmlCatalogEntryPtr next;
367c2c66affSColin Finck 
368c2c66affSColin Finck     while (ret != NULL) {
369c2c66affSColin Finck 	next = ret->next;
370c2c66affSColin Finck 	xmlFreeCatalogEntry(ret);
371c2c66affSColin Finck 	ret = next;
372c2c66affSColin Finck     }
373c2c66affSColin Finck }
374c2c66affSColin Finck 
375c2c66affSColin Finck /**
376c2c66affSColin Finck  * xmlFreeCatalogHashEntryList:
377c2c66affSColin Finck  * @ret:  a Catalog entry list
378c2c66affSColin Finck  *
379c2c66affSColin Finck  * Free the memory allocated to list of Catalog entries from the
380c2c66affSColin Finck  * catalog file hash.
381c2c66affSColin Finck  */
382c2c66affSColin Finck static void
383c2c66affSColin Finck xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
384c2c66affSColin Finck     xmlCatalogEntryPtr children, next;
385c2c66affSColin Finck 
386c2c66affSColin Finck     if (catal == NULL)
387c2c66affSColin Finck 	return;
388c2c66affSColin Finck 
389c2c66affSColin Finck     children = catal->children;
390c2c66affSColin Finck     while (children != NULL) {
391c2c66affSColin Finck 	next = children->next;
392c2c66affSColin Finck 	children->dealloc = 0;
393c2c66affSColin Finck 	children->children = NULL;
394c2c66affSColin Finck 	xmlFreeCatalogEntry(children);
395c2c66affSColin Finck 	children = next;
396c2c66affSColin Finck     }
397c2c66affSColin Finck     catal->dealloc = 0;
398c2c66affSColin Finck     xmlFreeCatalogEntry(catal);
399c2c66affSColin Finck }
400c2c66affSColin Finck 
401c2c66affSColin Finck /**
402c2c66affSColin Finck  * xmlCreateNewCatalog:
403c2c66affSColin Finck  * @type:  type of catalog
404c2c66affSColin Finck  * @prefer:  the PUBLIC vs. SYSTEM current preference value
405c2c66affSColin Finck  *
406c2c66affSColin Finck  * create a new Catalog, this type is shared both by XML and
407c2c66affSColin Finck  * SGML catalogs, but the acceptable types values differs.
408c2c66affSColin Finck  *
409c2c66affSColin Finck  * Returns the xmlCatalogPtr or NULL in case of error
410c2c66affSColin Finck  */
411c2c66affSColin Finck static xmlCatalogPtr
412c2c66affSColin Finck xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
413c2c66affSColin Finck     xmlCatalogPtr ret;
414c2c66affSColin Finck 
415c2c66affSColin Finck     ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
416c2c66affSColin Finck     if (ret == NULL) {
417c2c66affSColin Finck         xmlCatalogErrMemory("allocating catalog");
418c2c66affSColin Finck 	return(NULL);
419c2c66affSColin Finck     }
420c2c66affSColin Finck     memset(ret, 0, sizeof(xmlCatalog));
421c2c66affSColin Finck     ret->type = type;
422c2c66affSColin Finck     ret->catalNr = 0;
423c2c66affSColin Finck     ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
424c2c66affSColin Finck     ret->prefer = prefer;
425c2c66affSColin Finck     if (ret->type == XML_SGML_CATALOG_TYPE)
426c2c66affSColin Finck 	ret->sgml = xmlHashCreate(10);
427c2c66affSColin Finck     return(ret);
428c2c66affSColin Finck }
429c2c66affSColin Finck 
430c2c66affSColin Finck /**
431c2c66affSColin Finck  * xmlFreeCatalog:
432c2c66affSColin Finck  * @catal:  a Catalog
433c2c66affSColin Finck  *
434c2c66affSColin Finck  * Free the memory allocated to a Catalog
435c2c66affSColin Finck  */
436c2c66affSColin Finck void
437c2c66affSColin Finck xmlFreeCatalog(xmlCatalogPtr catal) {
438c2c66affSColin Finck     if (catal == NULL)
439c2c66affSColin Finck 	return;
440c2c66affSColin Finck     if (catal->xml != NULL)
441c2c66affSColin Finck 	xmlFreeCatalogEntryList(catal->xml);
442c2c66affSColin Finck     if (catal->sgml != NULL)
443c2c66affSColin Finck 	xmlHashFree(catal->sgml,
444c2c66affSColin Finck 		(xmlHashDeallocator) xmlFreeCatalogEntry);
445c2c66affSColin Finck     xmlFree(catal);
446c2c66affSColin Finck }
447c2c66affSColin Finck 
448c2c66affSColin Finck /************************************************************************
449c2c66affSColin Finck  *									*
450c2c66affSColin Finck  *			Serializing Catalogs				*
451c2c66affSColin Finck  *									*
452c2c66affSColin Finck  ************************************************************************/
453c2c66affSColin Finck 
454c2c66affSColin Finck #ifdef LIBXML_OUTPUT_ENABLED
455c2c66affSColin Finck /**
456c2c66affSColin Finck  * xmlCatalogDumpEntry:
457c2c66affSColin Finck  * @entry:  the catalog entry
458c2c66affSColin Finck  * @out:  the file.
459c2c66affSColin Finck  *
460c2c66affSColin Finck  * Serialize an SGML Catalog entry
461c2c66affSColin Finck  */
462c2c66affSColin Finck static void
463c2c66affSColin Finck xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
464c2c66affSColin Finck     if ((entry == NULL) || (out == NULL))
465c2c66affSColin Finck 	return;
466c2c66affSColin Finck     switch (entry->type) {
467c2c66affSColin Finck 	case SGML_CATA_ENTITY:
468c2c66affSColin Finck 	    fprintf(out, "ENTITY "); break;
469c2c66affSColin Finck 	case SGML_CATA_PENTITY:
470c2c66affSColin Finck 	    fprintf(out, "ENTITY %%"); break;
471c2c66affSColin Finck 	case SGML_CATA_DOCTYPE:
472c2c66affSColin Finck 	    fprintf(out, "DOCTYPE "); break;
473c2c66affSColin Finck 	case SGML_CATA_LINKTYPE:
474c2c66affSColin Finck 	    fprintf(out, "LINKTYPE "); break;
475c2c66affSColin Finck 	case SGML_CATA_NOTATION:
476c2c66affSColin Finck 	    fprintf(out, "NOTATION "); break;
477c2c66affSColin Finck 	case SGML_CATA_PUBLIC:
478c2c66affSColin Finck 	    fprintf(out, "PUBLIC "); break;
479c2c66affSColin Finck 	case SGML_CATA_SYSTEM:
480c2c66affSColin Finck 	    fprintf(out, "SYSTEM "); break;
481c2c66affSColin Finck 	case SGML_CATA_DELEGATE:
482c2c66affSColin Finck 	    fprintf(out, "DELEGATE "); break;
483c2c66affSColin Finck 	case SGML_CATA_BASE:
484c2c66affSColin Finck 	    fprintf(out, "BASE "); break;
485c2c66affSColin Finck 	case SGML_CATA_CATALOG:
486c2c66affSColin Finck 	    fprintf(out, "CATALOG "); break;
487c2c66affSColin Finck 	case SGML_CATA_DOCUMENT:
488c2c66affSColin Finck 	    fprintf(out, "DOCUMENT "); break;
489c2c66affSColin Finck 	case SGML_CATA_SGMLDECL:
490c2c66affSColin Finck 	    fprintf(out, "SGMLDECL "); break;
491c2c66affSColin Finck 	default:
492c2c66affSColin Finck 	    return;
493c2c66affSColin Finck     }
494c2c66affSColin Finck     switch (entry->type) {
495c2c66affSColin Finck 	case SGML_CATA_ENTITY:
496c2c66affSColin Finck 	case SGML_CATA_PENTITY:
497c2c66affSColin Finck 	case SGML_CATA_DOCTYPE:
498c2c66affSColin Finck 	case SGML_CATA_LINKTYPE:
499c2c66affSColin Finck 	case SGML_CATA_NOTATION:
500c2c66affSColin Finck 	    fprintf(out, "%s", (const char *) entry->name); break;
501c2c66affSColin Finck 	case SGML_CATA_PUBLIC:
502c2c66affSColin Finck 	case SGML_CATA_SYSTEM:
503c2c66affSColin Finck 	case SGML_CATA_SGMLDECL:
504c2c66affSColin Finck 	case SGML_CATA_DOCUMENT:
505c2c66affSColin Finck 	case SGML_CATA_CATALOG:
506c2c66affSColin Finck 	case SGML_CATA_BASE:
507c2c66affSColin Finck 	case SGML_CATA_DELEGATE:
508c2c66affSColin Finck 	    fprintf(out, "\"%s\"", entry->name); break;
509c2c66affSColin Finck 	default:
510c2c66affSColin Finck 	    break;
511c2c66affSColin Finck     }
512c2c66affSColin Finck     switch (entry->type) {
513c2c66affSColin Finck 	case SGML_CATA_ENTITY:
514c2c66affSColin Finck 	case SGML_CATA_PENTITY:
515c2c66affSColin Finck 	case SGML_CATA_DOCTYPE:
516c2c66affSColin Finck 	case SGML_CATA_LINKTYPE:
517c2c66affSColin Finck 	case SGML_CATA_NOTATION:
518c2c66affSColin Finck 	case SGML_CATA_PUBLIC:
519c2c66affSColin Finck 	case SGML_CATA_SYSTEM:
520c2c66affSColin Finck 	case SGML_CATA_DELEGATE:
521c2c66affSColin Finck 	    fprintf(out, " \"%s\"", entry->value); break;
522c2c66affSColin Finck 	default:
523c2c66affSColin Finck 	    break;
524c2c66affSColin Finck     }
525c2c66affSColin Finck     fprintf(out, "\n");
526c2c66affSColin Finck }
527c2c66affSColin Finck 
528c2c66affSColin Finck /**
529c2c66affSColin Finck  * xmlDumpXMLCatalogNode:
530c2c66affSColin Finck  * @catal:  top catalog entry
531c2c66affSColin Finck  * @catalog: pointer to the xml tree
532c2c66affSColin Finck  * @doc: the containing document
533c2c66affSColin Finck  * @ns: the current namespace
534c2c66affSColin Finck  * @cgroup: group node for group members
535c2c66affSColin Finck  *
536c2c66affSColin Finck  * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
537c2c66affSColin Finck  * for group entries
538c2c66affSColin Finck  */
539c2c66affSColin Finck static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
540c2c66affSColin Finck 		    xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
541c2c66affSColin Finck     xmlNodePtr node;
542c2c66affSColin Finck     xmlCatalogEntryPtr cur;
543c2c66affSColin Finck     /*
544c2c66affSColin Finck      * add all the catalog entries
545c2c66affSColin Finck      */
546c2c66affSColin Finck     cur = catal;
547c2c66affSColin Finck     while (cur != NULL) {
548c2c66affSColin Finck         if (cur->group == cgroup) {
549c2c66affSColin Finck 	    switch (cur->type) {
550c2c66affSColin Finck 	        case XML_CATA_REMOVED:
551c2c66affSColin Finck 		    break;
552c2c66affSColin Finck 	        case XML_CATA_BROKEN_CATALOG:
553c2c66affSColin Finck 	        case XML_CATA_CATALOG:
554c2c66affSColin Finck 		    if (cur == catal) {
555c2c66affSColin Finck 			cur = cur->children;
556c2c66affSColin Finck 		        continue;
557c2c66affSColin Finck 		    }
558c2c66affSColin Finck 		    break;
559c2c66affSColin Finck 		case XML_CATA_NEXT_CATALOG:
560c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
561c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "catalog", cur->value);
562c2c66affSColin Finck 		    xmlAddChild(catalog, node);
563c2c66affSColin Finck                     break;
564c2c66affSColin Finck 		case XML_CATA_NONE:
565c2c66affSColin Finck 		    break;
566c2c66affSColin Finck 		case XML_CATA_GROUP:
567c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
568c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "id", cur->name);
569c2c66affSColin Finck 		    if (cur->value != NULL) {
570c2c66affSColin Finck 		        xmlNsPtr xns;
571c2c66affSColin Finck 			xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
572c2c66affSColin Finck 			if (xns != NULL)
573c2c66affSColin Finck 			    xmlSetNsProp(node, xns, BAD_CAST "base",
574c2c66affSColin Finck 					 cur->value);
575c2c66affSColin Finck 		    }
576c2c66affSColin Finck 		    switch (cur->prefer) {
577c2c66affSColin Finck 			case XML_CATA_PREFER_NONE:
578c2c66affSColin Finck 		            break;
579c2c66affSColin Finck 			case XML_CATA_PREFER_PUBLIC:
580c2c66affSColin Finck 		            xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
581c2c66affSColin Finck 			    break;
582c2c66affSColin Finck 			case XML_CATA_PREFER_SYSTEM:
583c2c66affSColin Finck 		            xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
584c2c66affSColin Finck 			    break;
585c2c66affSColin Finck 		    }
586c2c66affSColin Finck 		    xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
587c2c66affSColin Finck 		    xmlAddChild(catalog, node);
588c2c66affSColin Finck 	            break;
589c2c66affSColin Finck 		case XML_CATA_PUBLIC:
590c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
591c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "publicId", cur->name);
592c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "uri", cur->value);
593c2c66affSColin Finck 		    xmlAddChild(catalog, node);
594c2c66affSColin Finck 		    break;
595c2c66affSColin Finck 		case XML_CATA_SYSTEM:
596c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
597c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "systemId", cur->name);
598c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "uri", cur->value);
599c2c66affSColin Finck 		    xmlAddChild(catalog, node);
600c2c66affSColin Finck 		    break;
601c2c66affSColin Finck 		case XML_CATA_REWRITE_SYSTEM:
602c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
603c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
604c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
605c2c66affSColin Finck 		    xmlAddChild(catalog, node);
606c2c66affSColin Finck 		    break;
607c2c66affSColin Finck 		case XML_CATA_DELEGATE_PUBLIC:
608c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
609c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
610c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "catalog", cur->value);
611c2c66affSColin Finck 		    xmlAddChild(catalog, node);
612c2c66affSColin Finck 		    break;
613c2c66affSColin Finck 		case XML_CATA_DELEGATE_SYSTEM:
614c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
615c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
616c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "catalog", cur->value);
617c2c66affSColin Finck 		    xmlAddChild(catalog, node);
618c2c66affSColin Finck 		    break;
619c2c66affSColin Finck 		case XML_CATA_URI:
620c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
621c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "name", cur->name);
622c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "uri", cur->value);
623c2c66affSColin Finck 		    xmlAddChild(catalog, node);
624c2c66affSColin Finck 		    break;
625c2c66affSColin Finck 		case XML_CATA_REWRITE_URI:
626c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
627c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
628c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
629c2c66affSColin Finck 		    xmlAddChild(catalog, node);
630c2c66affSColin Finck 		    break;
631c2c66affSColin Finck 		case XML_CATA_DELEGATE_URI:
632c2c66affSColin Finck 		    node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
633c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
634c2c66affSColin Finck 		    xmlSetProp(node, BAD_CAST "catalog", cur->value);
635c2c66affSColin Finck 		    xmlAddChild(catalog, node);
636c2c66affSColin Finck 		    break;
637c2c66affSColin Finck 		case SGML_CATA_SYSTEM:
638c2c66affSColin Finck 		case SGML_CATA_PUBLIC:
639c2c66affSColin Finck 		case SGML_CATA_ENTITY:
640c2c66affSColin Finck 		case SGML_CATA_PENTITY:
641c2c66affSColin Finck 		case SGML_CATA_DOCTYPE:
642c2c66affSColin Finck 		case SGML_CATA_LINKTYPE:
643c2c66affSColin Finck 		case SGML_CATA_NOTATION:
644c2c66affSColin Finck 		case SGML_CATA_DELEGATE:
645c2c66affSColin Finck 		case SGML_CATA_BASE:
646c2c66affSColin Finck 		case SGML_CATA_CATALOG:
647c2c66affSColin Finck 		case SGML_CATA_DOCUMENT:
648c2c66affSColin Finck 		case SGML_CATA_SGMLDECL:
649c2c66affSColin Finck 		    break;
650c2c66affSColin Finck 	    }
651c2c66affSColin Finck         }
652c2c66affSColin Finck 	cur = cur->next;
653c2c66affSColin Finck     }
654c2c66affSColin Finck }
655c2c66affSColin Finck 
656c2c66affSColin Finck static int
657c2c66affSColin Finck xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
658c2c66affSColin Finck     int ret;
659c2c66affSColin Finck     xmlDocPtr doc;
660c2c66affSColin Finck     xmlNsPtr ns;
661c2c66affSColin Finck     xmlDtdPtr dtd;
662c2c66affSColin Finck     xmlNodePtr catalog;
663c2c66affSColin Finck     xmlOutputBufferPtr buf;
664c2c66affSColin Finck 
665c2c66affSColin Finck     /*
666c2c66affSColin Finck      * Rebuild a catalog
667c2c66affSColin Finck      */
668c2c66affSColin Finck     doc = xmlNewDoc(NULL);
669c2c66affSColin Finck     if (doc == NULL)
670c2c66affSColin Finck 	return(-1);
671c2c66affSColin Finck     dtd = xmlNewDtd(doc, BAD_CAST "catalog",
672c2c66affSColin Finck 	       BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
673c2c66affSColin Finck BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
674c2c66affSColin Finck 
675c2c66affSColin Finck     xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
676c2c66affSColin Finck 
677c2c66affSColin Finck     ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
678c2c66affSColin Finck     if (ns == NULL) {
679c2c66affSColin Finck 	xmlFreeDoc(doc);
680c2c66affSColin Finck 	return(-1);
681c2c66affSColin Finck     }
682c2c66affSColin Finck     catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
683c2c66affSColin Finck     if (catalog == NULL) {
684c2c66affSColin Finck 	xmlFreeNs(ns);
685c2c66affSColin Finck 	xmlFreeDoc(doc);
686c2c66affSColin Finck 	return(-1);
687c2c66affSColin Finck     }
688c2c66affSColin Finck     catalog->nsDef = ns;
689c2c66affSColin Finck     xmlAddChild((xmlNodePtr) doc, catalog);
690c2c66affSColin Finck 
691c2c66affSColin Finck     xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
692c2c66affSColin Finck 
693c2c66affSColin Finck     /*
694c2c66affSColin Finck      * reserialize it
695c2c66affSColin Finck      */
696c2c66affSColin Finck     buf = xmlOutputBufferCreateFile(out, NULL);
697c2c66affSColin Finck     if (buf == NULL) {
698c2c66affSColin Finck 	xmlFreeDoc(doc);
699c2c66affSColin Finck 	return(-1);
700c2c66affSColin Finck     }
701c2c66affSColin Finck     ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
702c2c66affSColin Finck 
703c2c66affSColin Finck     /*
704c2c66affSColin Finck      * Free it
705c2c66affSColin Finck      */
706c2c66affSColin Finck     xmlFreeDoc(doc);
707c2c66affSColin Finck 
708c2c66affSColin Finck     return(ret);
709c2c66affSColin Finck }
710c2c66affSColin Finck #endif /* LIBXML_OUTPUT_ENABLED */
711c2c66affSColin Finck 
712c2c66affSColin Finck /************************************************************************
713c2c66affSColin Finck  *									*
714c2c66affSColin Finck  *			Converting SGML Catalogs to XML			*
715c2c66affSColin Finck  *									*
716c2c66affSColin Finck  ************************************************************************/
717c2c66affSColin Finck 
718c2c66affSColin Finck /**
719c2c66affSColin Finck  * xmlCatalogConvertEntry:
720c2c66affSColin Finck  * @entry:  the entry
721c2c66affSColin Finck  * @catal:  pointer to the catalog being converted
722c2c66affSColin Finck  *
723c2c66affSColin Finck  * Convert one entry from the catalog
724c2c66affSColin Finck  */
725c2c66affSColin Finck static void
726c2c66affSColin Finck xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
727c2c66affSColin Finck     if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
728c2c66affSColin Finck 	(catal->xml == NULL))
729c2c66affSColin Finck 	return;
730c2c66affSColin Finck     switch (entry->type) {
731c2c66affSColin Finck 	case SGML_CATA_ENTITY:
732c2c66affSColin Finck 	    entry->type = XML_CATA_PUBLIC;
733c2c66affSColin Finck 	    break;
734c2c66affSColin Finck 	case SGML_CATA_PENTITY:
735c2c66affSColin Finck 	    entry->type = XML_CATA_PUBLIC;
736c2c66affSColin Finck 	    break;
737c2c66affSColin Finck 	case SGML_CATA_DOCTYPE:
738c2c66affSColin Finck 	    entry->type = XML_CATA_PUBLIC;
739c2c66affSColin Finck 	    break;
740c2c66affSColin Finck 	case SGML_CATA_LINKTYPE:
741c2c66affSColin Finck 	    entry->type = XML_CATA_PUBLIC;
742c2c66affSColin Finck 	    break;
743c2c66affSColin Finck 	case SGML_CATA_NOTATION:
744c2c66affSColin Finck 	    entry->type = XML_CATA_PUBLIC;
745c2c66affSColin Finck 	    break;
746c2c66affSColin Finck 	case SGML_CATA_PUBLIC:
747c2c66affSColin Finck 	    entry->type = XML_CATA_PUBLIC;
748c2c66affSColin Finck 	    break;
749c2c66affSColin Finck 	case SGML_CATA_SYSTEM:
750c2c66affSColin Finck 	    entry->type = XML_CATA_SYSTEM;
751c2c66affSColin Finck 	    break;
752c2c66affSColin Finck 	case SGML_CATA_DELEGATE:
753c2c66affSColin Finck 	    entry->type = XML_CATA_DELEGATE_PUBLIC;
754c2c66affSColin Finck 	    break;
755c2c66affSColin Finck 	case SGML_CATA_CATALOG:
756c2c66affSColin Finck 	    entry->type = XML_CATA_CATALOG;
757c2c66affSColin Finck 	    break;
758c2c66affSColin Finck 	default:
759c2c66affSColin Finck 	    xmlHashRemoveEntry(catal->sgml, entry->name,
760c2c66affSColin Finck 		               (xmlHashDeallocator) xmlFreeCatalogEntry);
761c2c66affSColin Finck 	    return;
762c2c66affSColin Finck     }
763c2c66affSColin Finck     /*
764c2c66affSColin Finck      * Conversion successful, remove from the SGML catalog
765c2c66affSColin Finck      * and add it to the default XML one
766c2c66affSColin Finck      */
767c2c66affSColin Finck     xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
768c2c66affSColin Finck     entry->parent = catal->xml;
769c2c66affSColin Finck     entry->next = NULL;
770c2c66affSColin Finck     if (catal->xml->children == NULL)
771c2c66affSColin Finck 	catal->xml->children = entry;
772c2c66affSColin Finck     else {
773c2c66affSColin Finck 	xmlCatalogEntryPtr prev;
774c2c66affSColin Finck 
775c2c66affSColin Finck 	prev = catal->xml->children;
776c2c66affSColin Finck 	while (prev->next != NULL)
777c2c66affSColin Finck 	    prev = prev->next;
778c2c66affSColin Finck 	prev->next = entry;
779c2c66affSColin Finck     }
780c2c66affSColin Finck }
781c2c66affSColin Finck 
782c2c66affSColin Finck /**
783c2c66affSColin Finck  * xmlConvertSGMLCatalog:
784c2c66affSColin Finck  * @catal: the catalog
785c2c66affSColin Finck  *
786c2c66affSColin Finck  * Convert all the SGML catalog entries as XML ones
787c2c66affSColin Finck  *
788c2c66affSColin Finck  * Returns the number of entries converted if successful, -1 otherwise
789c2c66affSColin Finck  */
790c2c66affSColin Finck int
791c2c66affSColin Finck xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
792c2c66affSColin Finck 
793c2c66affSColin Finck     if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
794c2c66affSColin Finck 	return(-1);
795c2c66affSColin Finck 
796c2c66affSColin Finck     if (xmlDebugCatalogs) {
797c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
798c2c66affSColin Finck 		"Converting SGML catalog to XML\n");
799c2c66affSColin Finck     }
800c2c66affSColin Finck     xmlHashScan(catal->sgml,
801c2c66affSColin Finck 		(xmlHashScanner) xmlCatalogConvertEntry,
802c2c66affSColin Finck 		&catal);
803c2c66affSColin Finck     return(0);
804c2c66affSColin Finck }
805c2c66affSColin Finck 
806c2c66affSColin Finck /************************************************************************
807c2c66affSColin Finck  *									*
808c2c66affSColin Finck  *			Helper function					*
809c2c66affSColin Finck  *									*
810c2c66affSColin Finck  ************************************************************************/
811c2c66affSColin Finck 
812c2c66affSColin Finck /**
813c2c66affSColin Finck  * xmlCatalogUnWrapURN:
814c2c66affSColin Finck  * @urn:  an "urn:publicid:" to unwrap
815c2c66affSColin Finck  *
816c2c66affSColin Finck  * Expand the URN into the equivalent Public Identifier
817c2c66affSColin Finck  *
818c2c66affSColin Finck  * Returns the new identifier or NULL, the string must be deallocated
819c2c66affSColin Finck  *         by the caller.
820c2c66affSColin Finck  */
821c2c66affSColin Finck static xmlChar *
822c2c66affSColin Finck xmlCatalogUnWrapURN(const xmlChar *urn) {
823c2c66affSColin Finck     xmlChar result[2000];
824c2c66affSColin Finck     unsigned int i = 0;
825c2c66affSColin Finck 
826c2c66affSColin Finck     if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
827c2c66affSColin Finck 	return(NULL);
828c2c66affSColin Finck     urn += sizeof(XML_URN_PUBID) - 1;
829c2c66affSColin Finck 
830c2c66affSColin Finck     while (*urn != 0) {
831c2c66affSColin Finck 	if (i > sizeof(result) - 4)
832c2c66affSColin Finck 	    break;
833c2c66affSColin Finck 	if (*urn == '+') {
834c2c66affSColin Finck 	    result[i++] = ' ';
835c2c66affSColin Finck 	    urn++;
836c2c66affSColin Finck 	} else if (*urn == ':') {
837c2c66affSColin Finck 	    result[i++] = '/';
838c2c66affSColin Finck 	    result[i++] = '/';
839c2c66affSColin Finck 	    urn++;
840c2c66affSColin Finck 	} else if (*urn == ';') {
841c2c66affSColin Finck 	    result[i++] = ':';
842c2c66affSColin Finck 	    result[i++] = ':';
843c2c66affSColin Finck 	    urn++;
844c2c66affSColin Finck 	} else if (*urn == '%') {
845c2c66affSColin Finck 	    if ((urn[1] == '2') && (urn[2] == 'B'))
846c2c66affSColin Finck 		result[i++] = '+';
847c2c66affSColin Finck 	    else if ((urn[1] == '3') && (urn[2] == 'A'))
848c2c66affSColin Finck 		result[i++] = ':';
849c2c66affSColin Finck 	    else if ((urn[1] == '2') && (urn[2] == 'F'))
850c2c66affSColin Finck 		result[i++] = '/';
851c2c66affSColin Finck 	    else if ((urn[1] == '3') && (urn[2] == 'B'))
852c2c66affSColin Finck 		result[i++] = ';';
853c2c66affSColin Finck 	    else if ((urn[1] == '2') && (urn[2] == '7'))
854c2c66affSColin Finck 		result[i++] = '\'';
855c2c66affSColin Finck 	    else if ((urn[1] == '3') && (urn[2] == 'F'))
856c2c66affSColin Finck 		result[i++] = '?';
857c2c66affSColin Finck 	    else if ((urn[1] == '2') && (urn[2] == '3'))
858c2c66affSColin Finck 		result[i++] = '#';
859c2c66affSColin Finck 	    else if ((urn[1] == '2') && (urn[2] == '5'))
860c2c66affSColin Finck 		result[i++] = '%';
861c2c66affSColin Finck 	    else {
862c2c66affSColin Finck 		result[i++] = *urn;
863c2c66affSColin Finck 		urn++;
864c2c66affSColin Finck 		continue;
865c2c66affSColin Finck 	    }
866c2c66affSColin Finck 	    urn += 3;
867c2c66affSColin Finck 	} else {
868c2c66affSColin Finck 	    result[i++] = *urn;
869c2c66affSColin Finck 	    urn++;
870c2c66affSColin Finck 	}
871c2c66affSColin Finck     }
872c2c66affSColin Finck     result[i] = 0;
873c2c66affSColin Finck 
874c2c66affSColin Finck     return(xmlStrdup(result));
875c2c66affSColin Finck }
876c2c66affSColin Finck 
877c2c66affSColin Finck /**
878c2c66affSColin Finck  * xmlParseCatalogFile:
879c2c66affSColin Finck  * @filename:  the filename
880c2c66affSColin Finck  *
881c2c66affSColin Finck  * parse an XML file and build a tree. It's like xmlParseFile()
882c2c66affSColin Finck  * except it bypass all catalog lookups.
883c2c66affSColin Finck  *
884c2c66affSColin Finck  * Returns the resulting document tree or NULL in case of error
885c2c66affSColin Finck  */
886c2c66affSColin Finck 
887c2c66affSColin Finck xmlDocPtr
888c2c66affSColin Finck xmlParseCatalogFile(const char *filename) {
889c2c66affSColin Finck     xmlDocPtr ret;
890c2c66affSColin Finck     xmlParserCtxtPtr ctxt;
891c2c66affSColin Finck     char *directory = NULL;
892c2c66affSColin Finck     xmlParserInputPtr inputStream;
893c2c66affSColin Finck     xmlParserInputBufferPtr buf;
894c2c66affSColin Finck 
895c2c66affSColin Finck     ctxt = xmlNewParserCtxt();
896c2c66affSColin Finck     if (ctxt == NULL) {
897c2c66affSColin Finck #ifdef LIBXML_SAX1_ENABLED
898c2c66affSColin Finck 	if (xmlDefaultSAXHandler.error != NULL) {
899c2c66affSColin Finck 	    xmlDefaultSAXHandler.error(NULL, "out of memory\n");
900c2c66affSColin Finck 	}
901c2c66affSColin Finck #endif
902c2c66affSColin Finck 	return(NULL);
903c2c66affSColin Finck     }
904c2c66affSColin Finck 
905c2c66affSColin Finck     buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
906c2c66affSColin Finck     if (buf == NULL) {
907c2c66affSColin Finck 	xmlFreeParserCtxt(ctxt);
908c2c66affSColin Finck 	return(NULL);
909c2c66affSColin Finck     }
910c2c66affSColin Finck 
911c2c66affSColin Finck     inputStream = xmlNewInputStream(ctxt);
912c2c66affSColin Finck     if (inputStream == NULL) {
913c2c66affSColin Finck 	xmlFreeParserCtxt(ctxt);
914c2c66affSColin Finck 	return(NULL);
915c2c66affSColin Finck     }
916c2c66affSColin Finck 
917c2c66affSColin Finck     inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
918c2c66affSColin Finck     inputStream->buf = buf;
919c2c66affSColin Finck     xmlBufResetInput(buf->buffer, inputStream);
920c2c66affSColin Finck 
921c2c66affSColin Finck     inputPush(ctxt, inputStream);
922c2c66affSColin Finck     if ((ctxt->directory == NULL) && (directory == NULL))
923c2c66affSColin Finck         directory = xmlParserGetDirectory(filename);
924c2c66affSColin Finck     if ((ctxt->directory == NULL) && (directory != NULL))
925c2c66affSColin Finck         ctxt->directory = directory;
926c2c66affSColin Finck     ctxt->valid = 0;
927c2c66affSColin Finck     ctxt->validate = 0;
928c2c66affSColin Finck     ctxt->loadsubset = 0;
929c2c66affSColin Finck     ctxt->pedantic = 0;
930c2c66affSColin Finck     ctxt->dictNames = 1;
931c2c66affSColin Finck 
932c2c66affSColin Finck     xmlParseDocument(ctxt);
933c2c66affSColin Finck 
934c2c66affSColin Finck     if (ctxt->wellFormed)
935c2c66affSColin Finck 	ret = ctxt->myDoc;
936c2c66affSColin Finck     else {
937c2c66affSColin Finck         ret = NULL;
938c2c66affSColin Finck         xmlFreeDoc(ctxt->myDoc);
939c2c66affSColin Finck         ctxt->myDoc = NULL;
940c2c66affSColin Finck     }
941c2c66affSColin Finck     xmlFreeParserCtxt(ctxt);
942c2c66affSColin Finck 
943c2c66affSColin Finck     return(ret);
944c2c66affSColin Finck }
945c2c66affSColin Finck 
946c2c66affSColin Finck /**
947c2c66affSColin Finck  * xmlLoadFileContent:
948c2c66affSColin Finck  * @filename:  a file path
949c2c66affSColin Finck  *
950c2c66affSColin Finck  * Load a file content into memory.
951c2c66affSColin Finck  *
952c2c66affSColin Finck  * Returns a pointer to the 0 terminated string or NULL in case of error
953c2c66affSColin Finck  */
954c2c66affSColin Finck static xmlChar *
955c2c66affSColin Finck xmlLoadFileContent(const char *filename)
956c2c66affSColin Finck {
957c2c66affSColin Finck #ifdef HAVE_STAT
958c2c66affSColin Finck     int fd;
959c2c66affSColin Finck #else
960c2c66affSColin Finck     FILE *fd;
961c2c66affSColin Finck #endif
962c2c66affSColin Finck     int len;
963c2c66affSColin Finck     long size;
964c2c66affSColin Finck 
965c2c66affSColin Finck #ifdef HAVE_STAT
966c2c66affSColin Finck     struct stat info;
967c2c66affSColin Finck #endif
968c2c66affSColin Finck     xmlChar *content;
969c2c66affSColin Finck 
970c2c66affSColin Finck     if (filename == NULL)
971c2c66affSColin Finck         return (NULL);
972c2c66affSColin Finck 
973c2c66affSColin Finck #ifdef HAVE_STAT
974c2c66affSColin Finck     if (stat(filename, &info) < 0)
975c2c66affSColin Finck         return (NULL);
976c2c66affSColin Finck #endif
977c2c66affSColin Finck 
978c2c66affSColin Finck #ifdef HAVE_STAT
979c2c66affSColin Finck     if ((fd = open(filename, O_RDONLY)) < 0)
980c2c66affSColin Finck #else
981c2c66affSColin Finck     if ((fd = fopen(filename, "rb")) == NULL)
982c2c66affSColin Finck #endif
983c2c66affSColin Finck     {
984c2c66affSColin Finck         return (NULL);
985c2c66affSColin Finck     }
986c2c66affSColin Finck #ifdef HAVE_STAT
987c2c66affSColin Finck     size = info.st_size;
988c2c66affSColin Finck #else
989c2c66affSColin Finck     if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) {        /* File operations denied? ok, just close and return failure */
990c2c66affSColin Finck         fclose(fd);
991c2c66affSColin Finck         return (NULL);
992c2c66affSColin Finck     }
993c2c66affSColin Finck #endif
994c2c66affSColin Finck     content = (xmlChar*)xmlMallocAtomic(size + 10);
995c2c66affSColin Finck     if (content == NULL) {
996c2c66affSColin Finck         xmlCatalogErrMemory("allocating catalog data");
997c2c66affSColin Finck #ifdef HAVE_STAT
998c2c66affSColin Finck 	close(fd);
999c2c66affSColin Finck #else
1000c2c66affSColin Finck 	fclose(fd);
1001c2c66affSColin Finck #endif
1002c2c66affSColin Finck         return (NULL);
1003c2c66affSColin Finck     }
1004c2c66affSColin Finck #ifdef HAVE_STAT
1005c2c66affSColin Finck     len = read(fd, content, size);
1006c2c66affSColin Finck     close(fd);
1007c2c66affSColin Finck #else
1008c2c66affSColin Finck     len = fread(content, 1, size, fd);
1009c2c66affSColin Finck     fclose(fd);
1010c2c66affSColin Finck #endif
1011c2c66affSColin Finck     if (len < 0) {
1012c2c66affSColin Finck         xmlFree(content);
1013c2c66affSColin Finck         return (NULL);
1014c2c66affSColin Finck     }
1015c2c66affSColin Finck     content[len] = 0;
1016c2c66affSColin Finck 
1017c2c66affSColin Finck     return(content);
1018c2c66affSColin Finck }
1019c2c66affSColin Finck 
1020c2c66affSColin Finck /**
1021c2c66affSColin Finck  * xmlCatalogNormalizePublic:
1022c2c66affSColin Finck  * @pubID:  the public ID string
1023c2c66affSColin Finck  *
1024c2c66affSColin Finck  *  Normalizes the Public Identifier
1025c2c66affSColin Finck  *
1026c2c66affSColin Finck  * Implements 6.2. Public Identifier Normalization
1027c2c66affSColin Finck  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1028c2c66affSColin Finck  *
1029c2c66affSColin Finck  * Returns the new string or NULL, the string must be deallocated
1030c2c66affSColin Finck  *         by the caller.
1031c2c66affSColin Finck  */
1032c2c66affSColin Finck static xmlChar *
1033c2c66affSColin Finck xmlCatalogNormalizePublic(const xmlChar *pubID)
1034c2c66affSColin Finck {
1035c2c66affSColin Finck     int ok = 1;
1036c2c66affSColin Finck     int white;
1037c2c66affSColin Finck     const xmlChar *p;
1038c2c66affSColin Finck     xmlChar *ret;
1039c2c66affSColin Finck     xmlChar *q;
1040c2c66affSColin Finck 
1041c2c66affSColin Finck     if (pubID == NULL)
1042c2c66affSColin Finck         return(NULL);
1043c2c66affSColin Finck 
1044c2c66affSColin Finck     white = 1;
1045c2c66affSColin Finck     for (p = pubID;*p != 0 && ok;p++) {
1046c2c66affSColin Finck         if (!xmlIsBlank_ch(*p))
1047c2c66affSColin Finck             white = 0;
1048c2c66affSColin Finck         else if (*p == 0x20 && !white)
1049c2c66affSColin Finck             white = 1;
1050c2c66affSColin Finck         else
1051c2c66affSColin Finck             ok = 0;
1052c2c66affSColin Finck     }
1053c2c66affSColin Finck     if (ok && !white)	/* is normalized */
1054c2c66affSColin Finck         return(NULL);
1055c2c66affSColin Finck 
1056c2c66affSColin Finck     ret = xmlStrdup(pubID);
1057c2c66affSColin Finck     q = ret;
1058c2c66affSColin Finck     white = 0;
1059c2c66affSColin Finck     for (p = pubID;*p != 0;p++) {
1060c2c66affSColin Finck         if (xmlIsBlank_ch(*p)) {
1061c2c66affSColin Finck             if (q != ret)
1062c2c66affSColin Finck                 white = 1;
1063c2c66affSColin Finck         } else {
1064c2c66affSColin Finck             if (white) {
1065c2c66affSColin Finck                 *(q++) = 0x20;
1066c2c66affSColin Finck                 white = 0;
1067c2c66affSColin Finck             }
1068c2c66affSColin Finck             *(q++) = *p;
1069c2c66affSColin Finck         }
1070c2c66affSColin Finck     }
1071c2c66affSColin Finck     *q = 0;
1072c2c66affSColin Finck     return(ret);
1073c2c66affSColin Finck }
1074c2c66affSColin Finck 
1075c2c66affSColin Finck /************************************************************************
1076c2c66affSColin Finck  *									*
1077c2c66affSColin Finck  *			The XML Catalog parser				*
1078c2c66affSColin Finck  *									*
1079c2c66affSColin Finck  ************************************************************************/
1080c2c66affSColin Finck 
1081c2c66affSColin Finck static xmlCatalogEntryPtr
1082c2c66affSColin Finck xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
1083c2c66affSColin Finck static void
1084c2c66affSColin Finck xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1085c2c66affSColin Finck 	                   xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
1086c2c66affSColin Finck static xmlChar *
1087c2c66affSColin Finck xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1088c2c66affSColin Finck 	              const xmlChar *sysID);
1089c2c66affSColin Finck static xmlChar *
1090c2c66affSColin Finck xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1091c2c66affSColin Finck 
1092c2c66affSColin Finck 
1093c2c66affSColin Finck /**
1094c2c66affSColin Finck  * xmlGetXMLCatalogEntryType:
1095c2c66affSColin Finck  * @name:  the name
1096c2c66affSColin Finck  *
1097c2c66affSColin Finck  * lookup the internal type associated to an XML catalog entry name
1098c2c66affSColin Finck  *
1099c2c66affSColin Finck  * Returns the type associated with that name
1100c2c66affSColin Finck  */
1101c2c66affSColin Finck static xmlCatalogEntryType
1102c2c66affSColin Finck xmlGetXMLCatalogEntryType(const xmlChar *name) {
1103c2c66affSColin Finck     xmlCatalogEntryType type = XML_CATA_NONE;
1104c2c66affSColin Finck     if (xmlStrEqual(name, (const xmlChar *) "system"))
1105c2c66affSColin Finck 	type = XML_CATA_SYSTEM;
1106c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "public"))
1107c2c66affSColin Finck 	type = XML_CATA_PUBLIC;
1108c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1109c2c66affSColin Finck 	type = XML_CATA_REWRITE_SYSTEM;
1110c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1111c2c66affSColin Finck 	type = XML_CATA_DELEGATE_PUBLIC;
1112c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1113c2c66affSColin Finck 	type = XML_CATA_DELEGATE_SYSTEM;
1114c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1115c2c66affSColin Finck 	type = XML_CATA_URI;
1116c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1117c2c66affSColin Finck 	type = XML_CATA_REWRITE_URI;
1118c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1119c2c66affSColin Finck 	type = XML_CATA_DELEGATE_URI;
1120c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1121c2c66affSColin Finck 	type = XML_CATA_NEXT_CATALOG;
1122c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1123c2c66affSColin Finck 	type = XML_CATA_CATALOG;
1124c2c66affSColin Finck     return(type);
1125c2c66affSColin Finck }
1126c2c66affSColin Finck 
1127c2c66affSColin Finck /**
1128c2c66affSColin Finck  * xmlParseXMLCatalogOneNode:
1129c2c66affSColin Finck  * @cur:  the XML node
1130c2c66affSColin Finck  * @type:  the type of Catalog entry
1131c2c66affSColin Finck  * @name:  the name of the node
1132c2c66affSColin Finck  * @attrName:  the attribute holding the value
1133c2c66affSColin Finck  * @uriAttrName:  the attribute holding the URI-Reference
1134c2c66affSColin Finck  * @prefer:  the PUBLIC vs. SYSTEM current preference value
1135c2c66affSColin Finck  * @cgroup:  the group which includes this node
1136c2c66affSColin Finck  *
1137c2c66affSColin Finck  * Finishes the examination of an XML tree node of a catalog and build
1138c2c66affSColin Finck  * a Catalog entry from it.
1139c2c66affSColin Finck  *
1140c2c66affSColin Finck  * Returns the new Catalog entry node or NULL in case of error.
1141c2c66affSColin Finck  */
1142c2c66affSColin Finck static xmlCatalogEntryPtr
1143c2c66affSColin Finck xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1144c2c66affSColin Finck 			  const xmlChar *name, const xmlChar *attrName,
1145c2c66affSColin Finck 			  const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1146c2c66affSColin Finck 			  xmlCatalogEntryPtr cgroup) {
1147c2c66affSColin Finck     int ok = 1;
1148c2c66affSColin Finck     xmlChar *uriValue;
1149c2c66affSColin Finck     xmlChar *nameValue = NULL;
1150c2c66affSColin Finck     xmlChar *base = NULL;
1151c2c66affSColin Finck     xmlChar *URL = NULL;
1152c2c66affSColin Finck     xmlCatalogEntryPtr ret = NULL;
1153c2c66affSColin Finck 
1154c2c66affSColin Finck     if (attrName != NULL) {
1155c2c66affSColin Finck 	nameValue = xmlGetProp(cur, attrName);
1156c2c66affSColin Finck 	if (nameValue == NULL) {
1157c2c66affSColin Finck 	    xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1158c2c66affSColin Finck 			  "%s entry lacks '%s'\n", name, attrName, NULL);
1159c2c66affSColin Finck 	    ok = 0;
1160c2c66affSColin Finck 	}
1161c2c66affSColin Finck     }
1162c2c66affSColin Finck     uriValue = xmlGetProp(cur, uriAttrName);
1163c2c66affSColin Finck     if (uriValue == NULL) {
1164c2c66affSColin Finck 	xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1165c2c66affSColin Finck 		"%s entry lacks '%s'\n", name, uriAttrName, NULL);
1166c2c66affSColin Finck 	ok = 0;
1167c2c66affSColin Finck     }
1168c2c66affSColin Finck     if (!ok) {
1169c2c66affSColin Finck 	if (nameValue != NULL)
1170c2c66affSColin Finck 	    xmlFree(nameValue);
1171c2c66affSColin Finck 	if (uriValue != NULL)
1172c2c66affSColin Finck 	    xmlFree(uriValue);
1173c2c66affSColin Finck 	return(NULL);
1174c2c66affSColin Finck     }
1175c2c66affSColin Finck 
1176c2c66affSColin Finck     base = xmlNodeGetBase(cur->doc, cur);
1177c2c66affSColin Finck     URL = xmlBuildURI(uriValue, base);
1178c2c66affSColin Finck     if (URL != NULL) {
1179c2c66affSColin Finck 	if (xmlDebugCatalogs > 1) {
1180c2c66affSColin Finck 	    if (nameValue != NULL)
1181c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
1182c2c66affSColin Finck 			"Found %s: '%s' '%s'\n", name, nameValue, URL);
1183c2c66affSColin Finck 	    else
1184c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
1185c2c66affSColin Finck 			"Found %s: '%s'\n", name, URL);
1186c2c66affSColin Finck 	}
1187c2c66affSColin Finck 	ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
1188c2c66affSColin Finck     } else {
1189c2c66affSColin Finck 	xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
1190c2c66affSColin Finck 		"%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1191c2c66affSColin Finck     }
1192c2c66affSColin Finck     if (nameValue != NULL)
1193c2c66affSColin Finck 	xmlFree(nameValue);
1194c2c66affSColin Finck     if (uriValue != NULL)
1195c2c66affSColin Finck 	xmlFree(uriValue);
1196c2c66affSColin Finck     if (base != NULL)
1197c2c66affSColin Finck 	xmlFree(base);
1198c2c66affSColin Finck     if (URL != NULL)
1199c2c66affSColin Finck 	xmlFree(URL);
1200c2c66affSColin Finck     return(ret);
1201c2c66affSColin Finck }
1202c2c66affSColin Finck 
1203c2c66affSColin Finck /**
1204c2c66affSColin Finck  * xmlParseXMLCatalogNode:
1205c2c66affSColin Finck  * @cur:  the XML node
1206c2c66affSColin Finck  * @prefer:  the PUBLIC vs. SYSTEM current preference value
1207c2c66affSColin Finck  * @parent:  the parent Catalog entry
1208c2c66affSColin Finck  * @cgroup:  the group which includes this node
1209c2c66affSColin Finck  *
1210c2c66affSColin Finck  * Examines an XML tree node of a catalog and build
1211c2c66affSColin Finck  * a Catalog entry from it adding it to its parent. The examination can
1212c2c66affSColin Finck  * be recursive.
1213c2c66affSColin Finck  */
1214c2c66affSColin Finck static void
1215c2c66affSColin Finck xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1216c2c66affSColin Finck 	               xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
1217c2c66affSColin Finck {
1218c2c66affSColin Finck     xmlChar *base = NULL;
1219c2c66affSColin Finck     xmlCatalogEntryPtr entry = NULL;
1220c2c66affSColin Finck 
1221c2c66affSColin Finck     if (cur == NULL)
1222c2c66affSColin Finck         return;
1223c2c66affSColin Finck     if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1224c2c66affSColin Finck         xmlChar *prop;
1225c2c66affSColin Finck 	xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
1226c2c66affSColin Finck 
1227c2c66affSColin Finck         prop = xmlGetProp(cur, BAD_CAST "prefer");
1228c2c66affSColin Finck         if (prop != NULL) {
1229c2c66affSColin Finck             if (xmlStrEqual(prop, BAD_CAST "system")) {
1230c2c66affSColin Finck                 prefer = XML_CATA_PREFER_SYSTEM;
1231c2c66affSColin Finck             } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1232c2c66affSColin Finck                 prefer = XML_CATA_PREFER_PUBLIC;
1233c2c66affSColin Finck             } else {
1234c2c66affSColin Finck 		xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1235c2c66affSColin Finck                               "Invalid value for prefer: '%s'\n",
1236c2c66affSColin Finck 			      prop, NULL, NULL);
1237c2c66affSColin Finck             }
1238c2c66affSColin Finck             xmlFree(prop);
1239c2c66affSColin Finck 	    pref = prefer;
1240c2c66affSColin Finck         }
1241c2c66affSColin Finck 	prop = xmlGetProp(cur, BAD_CAST "id");
1242c2c66affSColin Finck 	base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1243c2c66affSColin Finck 	entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
1244c2c66affSColin Finck 	xmlFree(prop);
1245c2c66affSColin Finck     } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1246c2c66affSColin Finck 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
1247c2c66affSColin Finck 		BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
1248c2c66affSColin Finck     } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1249c2c66affSColin Finck 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
1250c2c66affSColin Finck 		BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
1251c2c66affSColin Finck     } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1252c2c66affSColin Finck 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1253c2c66affSColin Finck 		BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
1254c2c66affSColin Finck 		BAD_CAST "rewritePrefix", prefer, cgroup);
1255c2c66affSColin Finck     } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1256c2c66affSColin Finck 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1257c2c66affSColin Finck 		BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
1258c2c66affSColin Finck 		BAD_CAST "catalog", prefer, cgroup);
1259c2c66affSColin Finck     } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1260c2c66affSColin Finck 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1261c2c66affSColin Finck 		BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
1262c2c66affSColin Finck 		BAD_CAST "catalog", prefer, cgroup);
1263c2c66affSColin Finck     } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1264c2c66affSColin Finck 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1265c2c66affSColin Finck 		BAD_CAST "uri", BAD_CAST "name",
1266c2c66affSColin Finck 		BAD_CAST "uri", prefer, cgroup);
1267c2c66affSColin Finck     } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1268c2c66affSColin Finck 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1269c2c66affSColin Finck 		BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
1270c2c66affSColin Finck 		BAD_CAST "rewritePrefix", prefer, cgroup);
1271c2c66affSColin Finck     } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1272c2c66affSColin Finck 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1273c2c66affSColin Finck 		BAD_CAST "delegateURI", BAD_CAST "uriStartString",
1274c2c66affSColin Finck 		BAD_CAST "catalog", prefer, cgroup);
1275c2c66affSColin Finck     } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1276c2c66affSColin Finck 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1277c2c66affSColin Finck 		BAD_CAST "nextCatalog", NULL,
1278c2c66affSColin Finck 		BAD_CAST "catalog", prefer, cgroup);
1279c2c66affSColin Finck     }
1280c2c66affSColin Finck     if (entry != NULL) {
1281c2c66affSColin Finck         if (parent != NULL) {
1282c2c66affSColin Finck 	    entry->parent = parent;
1283c2c66affSColin Finck 	    if (parent->children == NULL)
1284c2c66affSColin Finck 		parent->children = entry;
1285c2c66affSColin Finck 	    else {
1286c2c66affSColin Finck 		xmlCatalogEntryPtr prev;
1287c2c66affSColin Finck 
1288c2c66affSColin Finck 		prev = parent->children;
1289c2c66affSColin Finck 		while (prev->next != NULL)
1290c2c66affSColin Finck 		    prev = prev->next;
1291c2c66affSColin Finck 		prev->next = entry;
1292c2c66affSColin Finck 	    }
1293c2c66affSColin Finck 	}
1294c2c66affSColin Finck 	if (entry->type == XML_CATA_GROUP) {
1295c2c66affSColin Finck 	    /*
1296c2c66affSColin Finck 	     * Recurse to propagate prefer to the subtree
1297c2c66affSColin Finck 	     * (xml:base handling is automated)
1298c2c66affSColin Finck 	     */
1299c2c66affSColin Finck             xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1300c2c66affSColin Finck 	}
1301c2c66affSColin Finck     }
1302c2c66affSColin Finck     if (base != NULL)
1303c2c66affSColin Finck 	xmlFree(base);
1304c2c66affSColin Finck }
1305c2c66affSColin Finck 
1306c2c66affSColin Finck /**
1307c2c66affSColin Finck  * xmlParseXMLCatalogNodeList:
1308c2c66affSColin Finck  * @cur:  the XML node list of siblings
1309c2c66affSColin Finck  * @prefer:  the PUBLIC vs. SYSTEM current preference value
1310c2c66affSColin Finck  * @parent:  the parent Catalog entry
1311c2c66affSColin Finck  * @cgroup:  the group which includes this list
1312c2c66affSColin Finck  *
1313c2c66affSColin Finck  * Examines a list of XML sibling nodes of a catalog and build
1314c2c66affSColin Finck  * a list of Catalog entry from it adding it to the parent.
1315c2c66affSColin Finck  * The examination will recurse to examine node subtrees.
1316c2c66affSColin Finck  */
1317c2c66affSColin Finck static void
1318c2c66affSColin Finck xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1319c2c66affSColin Finck 	                   xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
1320c2c66affSColin Finck     while (cur != NULL) {
1321c2c66affSColin Finck 	if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1322c2c66affSColin Finck 	    (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1323c2c66affSColin Finck 	    xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
1324c2c66affSColin Finck 	}
1325c2c66affSColin Finck 	cur = cur->next;
1326c2c66affSColin Finck     }
1327c2c66affSColin Finck     /* TODO: sort the list according to REWRITE lengths and prefer value */
1328c2c66affSColin Finck }
1329c2c66affSColin Finck 
1330c2c66affSColin Finck /**
1331c2c66affSColin Finck  * xmlParseXMLCatalogFile:
1332c2c66affSColin Finck  * @prefer:  the PUBLIC vs. SYSTEM current preference value
1333c2c66affSColin Finck  * @filename:  the filename for the catalog
1334c2c66affSColin Finck  *
1335c2c66affSColin Finck  * Parses the catalog file to extract the XML tree and then analyze the
1336c2c66affSColin Finck  * tree to build a list of Catalog entries corresponding to this catalog
1337c2c66affSColin Finck  *
1338c2c66affSColin Finck  * Returns the resulting Catalog entries list
1339c2c66affSColin Finck  */
1340c2c66affSColin Finck static xmlCatalogEntryPtr
1341c2c66affSColin Finck xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1342c2c66affSColin Finck     xmlDocPtr doc;
1343c2c66affSColin Finck     xmlNodePtr cur;
1344c2c66affSColin Finck     xmlChar *prop;
1345c2c66affSColin Finck     xmlCatalogEntryPtr parent = NULL;
1346c2c66affSColin Finck 
1347c2c66affSColin Finck     if (filename == NULL)
1348c2c66affSColin Finck         return(NULL);
1349c2c66affSColin Finck 
1350c2c66affSColin Finck     doc = xmlParseCatalogFile((const char *) filename);
1351c2c66affSColin Finck     if (doc == NULL) {
1352c2c66affSColin Finck 	if (xmlDebugCatalogs)
1353c2c66affSColin Finck 	    xmlGenericError(xmlGenericErrorContext,
1354c2c66affSColin Finck 		    "Failed to parse catalog %s\n", filename);
1355c2c66affSColin Finck 	return(NULL);
1356c2c66affSColin Finck     }
1357c2c66affSColin Finck 
1358c2c66affSColin Finck     if (xmlDebugCatalogs)
1359c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
1360c2c66affSColin Finck 		"%d Parsing catalog %s\n", xmlGetThreadId(), filename);
1361c2c66affSColin Finck 
1362c2c66affSColin Finck     cur = xmlDocGetRootElement(doc);
1363c2c66affSColin Finck     if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1364c2c66affSColin Finck 	(cur->ns != NULL) && (cur->ns->href != NULL) &&
1365c2c66affSColin Finck 	(xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1366c2c66affSColin Finck 
1367c2c66affSColin Finck 	parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1368c2c66affSColin Finck 				    (const xmlChar *)filename, NULL, prefer, NULL);
1369c2c66affSColin Finck         if (parent == NULL) {
1370c2c66affSColin Finck 	    xmlFreeDoc(doc);
1371c2c66affSColin Finck 	    return(NULL);
1372c2c66affSColin Finck 	}
1373c2c66affSColin Finck 
1374c2c66affSColin Finck 	prop = xmlGetProp(cur, BAD_CAST "prefer");
1375c2c66affSColin Finck 	if (prop != NULL) {
1376c2c66affSColin Finck 	    if (xmlStrEqual(prop, BAD_CAST "system")) {
1377c2c66affSColin Finck 		prefer = XML_CATA_PREFER_SYSTEM;
1378c2c66affSColin Finck 	    } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1379c2c66affSColin Finck 		prefer = XML_CATA_PREFER_PUBLIC;
1380c2c66affSColin Finck 	    } else {
1381c2c66affSColin Finck 		xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1382c2c66affSColin Finck 			      "Invalid value for prefer: '%s'\n",
1383c2c66affSColin Finck 			      prop, NULL, NULL);
1384c2c66affSColin Finck 	    }
1385c2c66affSColin Finck 	    xmlFree(prop);
1386c2c66affSColin Finck 	}
1387c2c66affSColin Finck 	cur = cur->children;
1388c2c66affSColin Finck 	xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
1389c2c66affSColin Finck     } else {
1390c2c66affSColin Finck 	xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1391c2c66affSColin Finck 		      "File %s is not an XML Catalog\n",
1392c2c66affSColin Finck 		      filename, NULL, NULL);
1393c2c66affSColin Finck 	xmlFreeDoc(doc);
1394c2c66affSColin Finck 	return(NULL);
1395c2c66affSColin Finck     }
1396c2c66affSColin Finck     xmlFreeDoc(doc);
1397c2c66affSColin Finck     return(parent);
1398c2c66affSColin Finck }
1399c2c66affSColin Finck 
1400c2c66affSColin Finck /**
1401c2c66affSColin Finck  * xmlFetchXMLCatalogFile:
1402c2c66affSColin Finck  * @catal:  an existing but incomplete catalog entry
1403c2c66affSColin Finck  *
1404c2c66affSColin Finck  * Fetch and parse the subcatalog referenced by an entry
1405c2c66affSColin Finck  *
1406c2c66affSColin Finck  * Returns 0 in case of success, -1 otherwise
1407c2c66affSColin Finck  */
1408c2c66affSColin Finck static int
1409c2c66affSColin Finck xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
1410c2c66affSColin Finck     xmlCatalogEntryPtr doc;
1411c2c66affSColin Finck 
1412c2c66affSColin Finck     if (catal == NULL)
1413c2c66affSColin Finck 	return(-1);
1414c2c66affSColin Finck     if (catal->URL == NULL)
1415c2c66affSColin Finck 	return(-1);
1416c2c66affSColin Finck 
1417c2c66affSColin Finck     /*
1418c2c66affSColin Finck      * lock the whole catalog for modification
1419c2c66affSColin Finck      */
1420c2c66affSColin Finck     xmlRMutexLock(xmlCatalogMutex);
1421c2c66affSColin Finck     if (catal->children != NULL) {
1422c2c66affSColin Finck 	/* Okay someone else did it in the meantime */
1423c2c66affSColin Finck 	xmlRMutexUnlock(xmlCatalogMutex);
1424c2c66affSColin Finck 	return(0);
1425c2c66affSColin Finck     }
1426c2c66affSColin Finck 
1427c2c66affSColin Finck     if (xmlCatalogXMLFiles != NULL) {
1428c2c66affSColin Finck 	doc = (xmlCatalogEntryPtr)
1429c2c66affSColin Finck 	    xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1430c2c66affSColin Finck 	if (doc != NULL) {
1431c2c66affSColin Finck 	    if (xmlDebugCatalogs)
1432c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
1433c2c66affSColin Finck 		    "Found %s in file hash\n", catal->URL);
1434c2c66affSColin Finck 
1435c2c66affSColin Finck 	    if (catal->type == XML_CATA_CATALOG)
1436c2c66affSColin Finck 		catal->children = doc->children;
1437c2c66affSColin Finck 	    else
1438c2c66affSColin Finck 		catal->children = doc;
1439c2c66affSColin Finck 	    catal->dealloc = 0;
1440c2c66affSColin Finck 	    xmlRMutexUnlock(xmlCatalogMutex);
1441c2c66affSColin Finck 	    return(0);
1442c2c66affSColin Finck 	}
1443c2c66affSColin Finck 	if (xmlDebugCatalogs)
1444c2c66affSColin Finck 	    xmlGenericError(xmlGenericErrorContext,
1445c2c66affSColin Finck 		"%s not found in file hash\n", catal->URL);
1446c2c66affSColin Finck     }
1447c2c66affSColin Finck 
1448c2c66affSColin Finck     /*
1449c2c66affSColin Finck      * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1450c2c66affSColin Finck      * use the existing catalog, there is no recursion allowed at
1451c2c66affSColin Finck      * that level.
1452c2c66affSColin Finck      */
1453c2c66affSColin Finck     doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
1454c2c66affSColin Finck     if (doc == NULL) {
1455c2c66affSColin Finck 	catal->type = XML_CATA_BROKEN_CATALOG;
1456c2c66affSColin Finck 	xmlRMutexUnlock(xmlCatalogMutex);
1457c2c66affSColin Finck 	return(-1);
1458c2c66affSColin Finck     }
1459c2c66affSColin Finck 
1460c2c66affSColin Finck     if (catal->type == XML_CATA_CATALOG)
1461c2c66affSColin Finck 	catal->children = doc->children;
1462c2c66affSColin Finck     else
1463c2c66affSColin Finck 	catal->children = doc;
1464c2c66affSColin Finck 
1465c2c66affSColin Finck     doc->dealloc = 1;
1466c2c66affSColin Finck 
1467c2c66affSColin Finck     if (xmlCatalogXMLFiles == NULL)
1468c2c66affSColin Finck 	xmlCatalogXMLFiles = xmlHashCreate(10);
1469c2c66affSColin Finck     if (xmlCatalogXMLFiles != NULL) {
1470c2c66affSColin Finck 	if (xmlDebugCatalogs)
1471c2c66affSColin Finck 	    xmlGenericError(xmlGenericErrorContext,
1472c2c66affSColin Finck 		"%s added to file hash\n", catal->URL);
1473c2c66affSColin Finck 	xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
1474c2c66affSColin Finck     }
1475c2c66affSColin Finck     xmlRMutexUnlock(xmlCatalogMutex);
1476c2c66affSColin Finck     return(0);
1477c2c66affSColin Finck }
1478c2c66affSColin Finck 
1479c2c66affSColin Finck /************************************************************************
1480c2c66affSColin Finck  *									*
1481c2c66affSColin Finck  *			XML Catalog handling				*
1482c2c66affSColin Finck  *									*
1483c2c66affSColin Finck  ************************************************************************/
1484c2c66affSColin Finck 
1485c2c66affSColin Finck /**
1486c2c66affSColin Finck  * xmlAddXMLCatalog:
1487c2c66affSColin Finck  * @catal:  top of an XML catalog
1488c2c66affSColin Finck  * @type:  the type of record to add to the catalog
1489c2c66affSColin Finck  * @orig:  the system, public or prefix to match (or NULL)
1490c2c66affSColin Finck  * @replace:  the replacement value for the match
1491c2c66affSColin Finck  *
1492c2c66affSColin Finck  * Add an entry in the XML catalog, it may overwrite existing but
1493c2c66affSColin Finck  * different entries.
1494c2c66affSColin Finck  *
1495c2c66affSColin Finck  * Returns 0 if successful, -1 otherwise
1496c2c66affSColin Finck  */
1497c2c66affSColin Finck static int
1498c2c66affSColin Finck xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1499c2c66affSColin Finck 	      const xmlChar *orig, const xmlChar *replace) {
1500c2c66affSColin Finck     xmlCatalogEntryPtr cur;
1501c2c66affSColin Finck     xmlCatalogEntryType typ;
1502c2c66affSColin Finck     int doregister = 0;
1503c2c66affSColin Finck 
1504c2c66affSColin Finck     if ((catal == NULL) ||
1505c2c66affSColin Finck 	((catal->type != XML_CATA_CATALOG) &&
1506c2c66affSColin Finck 	 (catal->type != XML_CATA_BROKEN_CATALOG)))
1507c2c66affSColin Finck 	return(-1);
1508c2c66affSColin Finck     if (catal->children == NULL) {
1509c2c66affSColin Finck 	xmlFetchXMLCatalogFile(catal);
1510c2c66affSColin Finck     }
1511c2c66affSColin Finck     if (catal->children == NULL)
1512c2c66affSColin Finck 	doregister = 1;
1513c2c66affSColin Finck 
1514c2c66affSColin Finck     typ = xmlGetXMLCatalogEntryType(type);
1515c2c66affSColin Finck     if (typ == XML_CATA_NONE) {
1516c2c66affSColin Finck 	if (xmlDebugCatalogs)
1517c2c66affSColin Finck 	    xmlGenericError(xmlGenericErrorContext,
1518c2c66affSColin Finck 		    "Failed to add unknown element %s to catalog\n", type);
1519c2c66affSColin Finck 	return(-1);
1520c2c66affSColin Finck     }
1521c2c66affSColin Finck 
1522c2c66affSColin Finck     cur = catal->children;
1523c2c66affSColin Finck     /*
1524c2c66affSColin Finck      * Might be a simple "update in place"
1525c2c66affSColin Finck      */
1526c2c66affSColin Finck     if (cur != NULL) {
1527c2c66affSColin Finck 	while (cur != NULL) {
1528c2c66affSColin Finck 	    if ((orig != NULL) && (cur->type == typ) &&
1529c2c66affSColin Finck 		(xmlStrEqual(orig, cur->name))) {
1530c2c66affSColin Finck 		if (xmlDebugCatalogs)
1531c2c66affSColin Finck 		    xmlGenericError(xmlGenericErrorContext,
1532c2c66affSColin Finck 			    "Updating element %s to catalog\n", type);
1533c2c66affSColin Finck 		if (cur->value != NULL)
1534c2c66affSColin Finck 		    xmlFree(cur->value);
1535c2c66affSColin Finck 		if (cur->URL != NULL)
1536c2c66affSColin Finck 		    xmlFree(cur->URL);
1537c2c66affSColin Finck 		cur->value = xmlStrdup(replace);
1538c2c66affSColin Finck 		cur->URL = xmlStrdup(replace);
1539c2c66affSColin Finck 		return(0);
1540c2c66affSColin Finck 	    }
1541c2c66affSColin Finck 	    if (cur->next == NULL)
1542c2c66affSColin Finck 		break;
1543c2c66affSColin Finck 	    cur = cur->next;
1544c2c66affSColin Finck 	}
1545c2c66affSColin Finck     }
1546c2c66affSColin Finck     if (xmlDebugCatalogs)
1547c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
1548c2c66affSColin Finck 		"Adding element %s to catalog\n", type);
1549c2c66affSColin Finck     if (cur == NULL)
1550c2c66affSColin Finck 	catal->children = xmlNewCatalogEntry(typ, orig, replace,
1551c2c66affSColin Finck 		                             NULL, catal->prefer, NULL);
1552c2c66affSColin Finck     else
1553c2c66affSColin Finck 	cur->next = xmlNewCatalogEntry(typ, orig, replace,
1554c2c66affSColin Finck 		                       NULL, catal->prefer, NULL);
1555c2c66affSColin Finck     if (doregister) {
1556c2c66affSColin Finck         catal->type = XML_CATA_CATALOG;
1557c2c66affSColin Finck 	cur = (xmlCatalogEntryPtr)xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1558c2c66affSColin Finck 	if (cur != NULL)
1559c2c66affSColin Finck 	    cur->children = catal->children;
1560c2c66affSColin Finck     }
1561c2c66affSColin Finck 
1562c2c66affSColin Finck     return(0);
1563c2c66affSColin Finck }
1564c2c66affSColin Finck 
1565c2c66affSColin Finck /**
1566c2c66affSColin Finck  * xmlDelXMLCatalog:
1567c2c66affSColin Finck  * @catal:  top of an XML catalog
1568c2c66affSColin Finck  * @value:  the value to remove from the catalog
1569c2c66affSColin Finck  *
1570c2c66affSColin Finck  * Remove entries in the XML catalog where the value or the URI
1571c2c66affSColin Finck  * is equal to @value
1572c2c66affSColin Finck  *
1573c2c66affSColin Finck  * Returns the number of entries removed if successful, -1 otherwise
1574c2c66affSColin Finck  */
1575c2c66affSColin Finck static int
1576c2c66affSColin Finck xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1577c2c66affSColin Finck     xmlCatalogEntryPtr cur;
1578c2c66affSColin Finck     int ret = 0;
1579c2c66affSColin Finck 
1580c2c66affSColin Finck     if ((catal == NULL) ||
1581c2c66affSColin Finck 	((catal->type != XML_CATA_CATALOG) &&
1582c2c66affSColin Finck 	 (catal->type != XML_CATA_BROKEN_CATALOG)))
1583c2c66affSColin Finck 	return(-1);
1584c2c66affSColin Finck     if (value == NULL)
1585c2c66affSColin Finck 	return(-1);
1586c2c66affSColin Finck     if (catal->children == NULL) {
1587c2c66affSColin Finck 	xmlFetchXMLCatalogFile(catal);
1588c2c66affSColin Finck     }
1589c2c66affSColin Finck 
1590c2c66affSColin Finck     /*
1591c2c66affSColin Finck      * Scan the children
1592c2c66affSColin Finck      */
1593c2c66affSColin Finck     cur = catal->children;
1594c2c66affSColin Finck     while (cur != NULL) {
1595c2c66affSColin Finck 	if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1596c2c66affSColin Finck 	    (xmlStrEqual(value, cur->value))) {
1597c2c66affSColin Finck 	    if (xmlDebugCatalogs) {
1598c2c66affSColin Finck 		if (cur->name != NULL)
1599c2c66affSColin Finck 		    xmlGenericError(xmlGenericErrorContext,
1600c2c66affSColin Finck 			    "Removing element %s from catalog\n", cur->name);
1601c2c66affSColin Finck 		else
1602c2c66affSColin Finck 		    xmlGenericError(xmlGenericErrorContext,
1603c2c66affSColin Finck 			    "Removing element %s from catalog\n", cur->value);
1604c2c66affSColin Finck 	    }
1605c2c66affSColin Finck 	    cur->type = XML_CATA_REMOVED;
1606c2c66affSColin Finck 	}
1607c2c66affSColin Finck 	cur = cur->next;
1608c2c66affSColin Finck     }
1609c2c66affSColin Finck     return(ret);
1610c2c66affSColin Finck }
1611c2c66affSColin Finck 
1612c2c66affSColin Finck /**
1613c2c66affSColin Finck  * xmlCatalogXMLResolve:
1614c2c66affSColin Finck  * @catal:  a catalog list
1615c2c66affSColin Finck  * @pubID:  the public ID string
1616c2c66affSColin Finck  * @sysID:  the system ID string
1617c2c66affSColin Finck  *
1618c2c66affSColin Finck  * Do a complete resolution lookup of an External Identifier for a
1619c2c66affSColin Finck  * list of catalog entries.
1620c2c66affSColin Finck  *
1621c2c66affSColin Finck  * Implements (or tries to) 7.1. External Identifier Resolution
1622c2c66affSColin Finck  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1623c2c66affSColin Finck  *
1624c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found
1625c2c66affSColin Finck  */
1626c2c66affSColin Finck static xmlChar *
1627c2c66affSColin Finck xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1628c2c66affSColin Finck 	              const xmlChar *sysID) {
1629c2c66affSColin Finck     xmlChar *ret = NULL;
1630c2c66affSColin Finck     xmlCatalogEntryPtr cur;
1631c2c66affSColin Finck     int haveDelegate = 0;
1632c2c66affSColin Finck     int haveNext = 0;
1633c2c66affSColin Finck 
1634c2c66affSColin Finck     /*
1635c2c66affSColin Finck      * protection against loops
1636c2c66affSColin Finck      */
1637c2c66affSColin Finck     if (catal->depth > MAX_CATAL_DEPTH) {
1638c2c66affSColin Finck 	xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1639c2c66affSColin Finck 		      "Detected recursion in catalog %s\n",
1640c2c66affSColin Finck 		      catal->name, NULL, NULL);
1641c2c66affSColin Finck 	return(NULL);
1642c2c66affSColin Finck     }
1643c2c66affSColin Finck     catal->depth++;
1644c2c66affSColin Finck 
1645c2c66affSColin Finck     /*
1646c2c66affSColin Finck      * First tries steps 2/ 3/ 4/ if a system ID is provided.
1647c2c66affSColin Finck      */
1648c2c66affSColin Finck     if (sysID != NULL) {
1649c2c66affSColin Finck 	xmlCatalogEntryPtr rewrite = NULL;
1650c2c66affSColin Finck 	int lenrewrite = 0, len;
1651c2c66affSColin Finck 	cur = catal;
1652c2c66affSColin Finck 	haveDelegate = 0;
1653c2c66affSColin Finck 	while (cur != NULL) {
1654c2c66affSColin Finck 	    switch (cur->type) {
1655c2c66affSColin Finck 		case XML_CATA_SYSTEM:
1656c2c66affSColin Finck 		    if (xmlStrEqual(sysID, cur->name)) {
1657c2c66affSColin Finck 			if (xmlDebugCatalogs)
1658c2c66affSColin Finck 			    xmlGenericError(xmlGenericErrorContext,
1659c2c66affSColin Finck 				    "Found system match %s, using %s\n",
1660c2c66affSColin Finck 				            cur->name, cur->URL);
1661c2c66affSColin Finck 			catal->depth--;
1662c2c66affSColin Finck 			return(xmlStrdup(cur->URL));
1663c2c66affSColin Finck 		    }
1664c2c66affSColin Finck 		    break;
1665c2c66affSColin Finck 		case XML_CATA_REWRITE_SYSTEM:
1666c2c66affSColin Finck 		    len = xmlStrlen(cur->name);
1667c2c66affSColin Finck 		    if ((len > lenrewrite) &&
1668c2c66affSColin Finck 			(!xmlStrncmp(sysID, cur->name, len))) {
1669c2c66affSColin Finck 			lenrewrite = len;
1670c2c66affSColin Finck 			rewrite = cur;
1671c2c66affSColin Finck 		    }
1672c2c66affSColin Finck 		    break;
1673c2c66affSColin Finck 		case XML_CATA_DELEGATE_SYSTEM:
1674c2c66affSColin Finck 		    if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1675c2c66affSColin Finck 			haveDelegate++;
1676c2c66affSColin Finck 		    break;
1677c2c66affSColin Finck 		case XML_CATA_NEXT_CATALOG:
1678c2c66affSColin Finck 		    haveNext++;
1679c2c66affSColin Finck 		    break;
1680c2c66affSColin Finck 		default:
1681c2c66affSColin Finck 		    break;
1682c2c66affSColin Finck 	    }
1683c2c66affSColin Finck 	    cur = cur->next;
1684c2c66affSColin Finck 	}
1685c2c66affSColin Finck 	if (rewrite != NULL) {
1686c2c66affSColin Finck 	    if (xmlDebugCatalogs)
1687c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
1688c2c66affSColin Finck 			"Using rewriting rule %s\n", rewrite->name);
1689c2c66affSColin Finck 	    ret = xmlStrdup(rewrite->URL);
1690c2c66affSColin Finck 	    if (ret != NULL)
1691c2c66affSColin Finck 		ret = xmlStrcat(ret, &sysID[lenrewrite]);
1692c2c66affSColin Finck 	    catal->depth--;
1693c2c66affSColin Finck 	    return(ret);
1694c2c66affSColin Finck 	}
1695c2c66affSColin Finck 	if (haveDelegate) {
1696c2c66affSColin Finck 	    const xmlChar *delegates[MAX_DELEGATE];
1697c2c66affSColin Finck 	    int nbList = 0, i;
1698c2c66affSColin Finck 
1699c2c66affSColin Finck 	    /*
1700c2c66affSColin Finck 	     * Assume the entries have been sorted by decreasing substring
1701c2c66affSColin Finck 	     * matches when the list was produced.
1702c2c66affSColin Finck 	     */
1703c2c66affSColin Finck 	    cur = catal;
1704c2c66affSColin Finck 	    while (cur != NULL) {
1705c2c66affSColin Finck 		if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1706c2c66affSColin Finck 		    (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
1707c2c66affSColin Finck 		    for (i = 0;i < nbList;i++)
1708c2c66affSColin Finck 			if (xmlStrEqual(cur->URL, delegates[i]))
1709c2c66affSColin Finck 			    break;
1710c2c66affSColin Finck 		    if (i < nbList) {
1711c2c66affSColin Finck 			cur = cur->next;
1712c2c66affSColin Finck 			continue;
1713c2c66affSColin Finck 		    }
1714c2c66affSColin Finck 		    if (nbList < MAX_DELEGATE)
1715c2c66affSColin Finck 			delegates[nbList++] = cur->URL;
1716c2c66affSColin Finck 
1717c2c66affSColin Finck 		    if (cur->children == NULL) {
1718c2c66affSColin Finck 			xmlFetchXMLCatalogFile(cur);
1719c2c66affSColin Finck 		    }
1720c2c66affSColin Finck 		    if (cur->children != NULL) {
1721c2c66affSColin Finck 			if (xmlDebugCatalogs)
1722c2c66affSColin Finck 			    xmlGenericError(xmlGenericErrorContext,
1723c2c66affSColin Finck 				    "Trying system delegate %s\n", cur->URL);
1724c2c66affSColin Finck 			ret = xmlCatalogListXMLResolve(
1725c2c66affSColin Finck 				cur->children, NULL, sysID);
1726c2c66affSColin Finck 			if (ret != NULL) {
1727c2c66affSColin Finck 			    catal->depth--;
1728c2c66affSColin Finck 			    return(ret);
1729c2c66affSColin Finck 			}
1730c2c66affSColin Finck 		    }
1731c2c66affSColin Finck 		}
1732c2c66affSColin Finck 		cur = cur->next;
1733c2c66affSColin Finck 	    }
1734c2c66affSColin Finck 	    /*
1735c2c66affSColin Finck 	     * Apply the cut algorithm explained in 4/
1736c2c66affSColin Finck 	     */
1737c2c66affSColin Finck 	    catal->depth--;
1738c2c66affSColin Finck 	    return(XML_CATAL_BREAK);
1739c2c66affSColin Finck 	}
1740c2c66affSColin Finck     }
1741c2c66affSColin Finck     /*
1742c2c66affSColin Finck      * Then tries 5/ 6/ if a public ID is provided
1743c2c66affSColin Finck      */
1744c2c66affSColin Finck     if (pubID != NULL) {
1745c2c66affSColin Finck 	cur = catal;
1746c2c66affSColin Finck 	haveDelegate = 0;
1747c2c66affSColin Finck 	while (cur != NULL) {
1748c2c66affSColin Finck 	    switch (cur->type) {
1749c2c66affSColin Finck 		case XML_CATA_PUBLIC:
1750c2c66affSColin Finck 		    if (xmlStrEqual(pubID, cur->name)) {
1751c2c66affSColin Finck 			if (xmlDebugCatalogs)
1752c2c66affSColin Finck 			    xmlGenericError(xmlGenericErrorContext,
1753c2c66affSColin Finck 				    "Found public match %s\n", cur->name);
1754c2c66affSColin Finck 			catal->depth--;
1755c2c66affSColin Finck 			return(xmlStrdup(cur->URL));
1756c2c66affSColin Finck 		    }
1757c2c66affSColin Finck 		    break;
1758c2c66affSColin Finck 		case XML_CATA_DELEGATE_PUBLIC:
1759c2c66affSColin Finck 		    if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1760c2c66affSColin Finck 			(cur->prefer == XML_CATA_PREFER_PUBLIC))
1761c2c66affSColin Finck 			haveDelegate++;
1762c2c66affSColin Finck 		    break;
1763c2c66affSColin Finck 		case XML_CATA_NEXT_CATALOG:
1764c2c66affSColin Finck 		    if (sysID == NULL)
1765c2c66affSColin Finck 			haveNext++;
1766c2c66affSColin Finck 		    break;
1767c2c66affSColin Finck 		default:
1768c2c66affSColin Finck 		    break;
1769c2c66affSColin Finck 	    }
1770c2c66affSColin Finck 	    cur = cur->next;
1771c2c66affSColin Finck 	}
1772c2c66affSColin Finck 	if (haveDelegate) {
1773c2c66affSColin Finck 	    const xmlChar *delegates[MAX_DELEGATE];
1774c2c66affSColin Finck 	    int nbList = 0, i;
1775c2c66affSColin Finck 
1776c2c66affSColin Finck 	    /*
1777c2c66affSColin Finck 	     * Assume the entries have been sorted by decreasing substring
1778c2c66affSColin Finck 	     * matches when the list was produced.
1779c2c66affSColin Finck 	     */
1780c2c66affSColin Finck 	    cur = catal;
1781c2c66affSColin Finck 	    while (cur != NULL) {
1782c2c66affSColin Finck 		if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
1783c2c66affSColin Finck 		    (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1784c2c66affSColin Finck 		    (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
1785c2c66affSColin Finck 
1786c2c66affSColin Finck 		    for (i = 0;i < nbList;i++)
1787c2c66affSColin Finck 			if (xmlStrEqual(cur->URL, delegates[i]))
1788c2c66affSColin Finck 			    break;
1789c2c66affSColin Finck 		    if (i < nbList) {
1790c2c66affSColin Finck 			cur = cur->next;
1791c2c66affSColin Finck 			continue;
1792c2c66affSColin Finck 		    }
1793c2c66affSColin Finck 		    if (nbList < MAX_DELEGATE)
1794c2c66affSColin Finck 			delegates[nbList++] = cur->URL;
1795c2c66affSColin Finck 
1796c2c66affSColin Finck 		    if (cur->children == NULL) {
1797c2c66affSColin Finck 			xmlFetchXMLCatalogFile(cur);
1798c2c66affSColin Finck 		    }
1799c2c66affSColin Finck 		    if (cur->children != NULL) {
1800c2c66affSColin Finck 			if (xmlDebugCatalogs)
1801c2c66affSColin Finck 			    xmlGenericError(xmlGenericErrorContext,
1802c2c66affSColin Finck 				    "Trying public delegate %s\n", cur->URL);
1803c2c66affSColin Finck 			ret = xmlCatalogListXMLResolve(
1804c2c66affSColin Finck 				cur->children, pubID, NULL);
1805c2c66affSColin Finck 			if (ret != NULL) {
1806c2c66affSColin Finck 			    catal->depth--;
1807c2c66affSColin Finck 			    return(ret);
1808c2c66affSColin Finck 			}
1809c2c66affSColin Finck 		    }
1810c2c66affSColin Finck 		}
1811c2c66affSColin Finck 		cur = cur->next;
1812c2c66affSColin Finck 	    }
1813c2c66affSColin Finck 	    /*
1814c2c66affSColin Finck 	     * Apply the cut algorithm explained in 4/
1815c2c66affSColin Finck 	     */
1816c2c66affSColin Finck 	    catal->depth--;
1817c2c66affSColin Finck 	    return(XML_CATAL_BREAK);
1818c2c66affSColin Finck 	}
1819c2c66affSColin Finck     }
1820c2c66affSColin Finck     if (haveNext) {
1821c2c66affSColin Finck 	cur = catal;
1822c2c66affSColin Finck 	while (cur != NULL) {
1823c2c66affSColin Finck 	    if (cur->type == XML_CATA_NEXT_CATALOG) {
1824c2c66affSColin Finck 		if (cur->children == NULL) {
1825c2c66affSColin Finck 		    xmlFetchXMLCatalogFile(cur);
1826c2c66affSColin Finck 		}
1827c2c66affSColin Finck 		if (cur->children != NULL) {
1828c2c66affSColin Finck 		    ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1829c2c66affSColin Finck 		    if (ret != NULL) {
1830c2c66affSColin Finck 			catal->depth--;
1831c2c66affSColin Finck 			return(ret);
1832c2c66affSColin Finck 		    } else if (catal->depth > MAX_CATAL_DEPTH) {
1833c2c66affSColin Finck 		        return(NULL);
1834c2c66affSColin Finck 		    }
1835c2c66affSColin Finck 		}
1836c2c66affSColin Finck 	    }
1837c2c66affSColin Finck 	    cur = cur->next;
1838c2c66affSColin Finck 	}
1839c2c66affSColin Finck     }
1840c2c66affSColin Finck 
1841c2c66affSColin Finck     catal->depth--;
1842c2c66affSColin Finck     return(NULL);
1843c2c66affSColin Finck }
1844c2c66affSColin Finck 
1845c2c66affSColin Finck /**
1846c2c66affSColin Finck  * xmlCatalogXMLResolveURI:
1847c2c66affSColin Finck  * @catal:  a catalog list
1848c2c66affSColin Finck  * @URI:  the URI
1849c2c66affSColin Finck  * @sysID:  the system ID string
1850c2c66affSColin Finck  *
1851c2c66affSColin Finck  * Do a complete resolution lookup of an External Identifier for a
1852c2c66affSColin Finck  * list of catalog entries.
1853c2c66affSColin Finck  *
1854c2c66affSColin Finck  * Implements (or tries to) 7.2.2. URI Resolution
1855c2c66affSColin Finck  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1856c2c66affSColin Finck  *
1857c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found
1858c2c66affSColin Finck  */
1859c2c66affSColin Finck static xmlChar *
1860c2c66affSColin Finck xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1861c2c66affSColin Finck     xmlChar *ret = NULL;
1862c2c66affSColin Finck     xmlCatalogEntryPtr cur;
1863c2c66affSColin Finck     int haveDelegate = 0;
1864c2c66affSColin Finck     int haveNext = 0;
1865c2c66affSColin Finck     xmlCatalogEntryPtr rewrite = NULL;
1866c2c66affSColin Finck     int lenrewrite = 0, len;
1867c2c66affSColin Finck 
1868c2c66affSColin Finck     if (catal == NULL)
1869c2c66affSColin Finck 	return(NULL);
1870c2c66affSColin Finck 
1871c2c66affSColin Finck     if (URI == NULL)
1872c2c66affSColin Finck 	return(NULL);
1873c2c66affSColin Finck 
1874c2c66affSColin Finck     if (catal->depth > MAX_CATAL_DEPTH) {
1875c2c66affSColin Finck 	xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1876c2c66affSColin Finck 		      "Detected recursion in catalog %s\n",
1877c2c66affSColin Finck 		      catal->name, NULL, NULL);
1878c2c66affSColin Finck 	return(NULL);
1879c2c66affSColin Finck     }
1880c2c66affSColin Finck 
1881c2c66affSColin Finck     /*
1882c2c66affSColin Finck      * First tries steps 2/ 3/ 4/ if a system ID is provided.
1883c2c66affSColin Finck      */
1884c2c66affSColin Finck     cur = catal;
1885c2c66affSColin Finck     haveDelegate = 0;
1886c2c66affSColin Finck     while (cur != NULL) {
1887c2c66affSColin Finck 	switch (cur->type) {
1888c2c66affSColin Finck 	    case XML_CATA_URI:
1889c2c66affSColin Finck 		if (xmlStrEqual(URI, cur->name)) {
1890c2c66affSColin Finck 		    if (xmlDebugCatalogs)
1891c2c66affSColin Finck 			xmlGenericError(xmlGenericErrorContext,
1892c2c66affSColin Finck 				"Found URI match %s\n", cur->name);
1893c2c66affSColin Finck 		    return(xmlStrdup(cur->URL));
1894c2c66affSColin Finck 		}
1895c2c66affSColin Finck 		break;
1896c2c66affSColin Finck 	    case XML_CATA_REWRITE_URI:
1897c2c66affSColin Finck 		len = xmlStrlen(cur->name);
1898c2c66affSColin Finck 		if ((len > lenrewrite) &&
1899c2c66affSColin Finck 		    (!xmlStrncmp(URI, cur->name, len))) {
1900c2c66affSColin Finck 		    lenrewrite = len;
1901c2c66affSColin Finck 		    rewrite = cur;
1902c2c66affSColin Finck 		}
1903c2c66affSColin Finck 		break;
1904c2c66affSColin Finck 	    case XML_CATA_DELEGATE_URI:
1905c2c66affSColin Finck 		if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1906c2c66affSColin Finck 		    haveDelegate++;
1907c2c66affSColin Finck 		break;
1908c2c66affSColin Finck 	    case XML_CATA_NEXT_CATALOG:
1909c2c66affSColin Finck 		haveNext++;
1910c2c66affSColin Finck 		break;
1911c2c66affSColin Finck 	    default:
1912c2c66affSColin Finck 		break;
1913c2c66affSColin Finck 	}
1914c2c66affSColin Finck 	cur = cur->next;
1915c2c66affSColin Finck     }
1916c2c66affSColin Finck     if (rewrite != NULL) {
1917c2c66affSColin Finck 	if (xmlDebugCatalogs)
1918c2c66affSColin Finck 	    xmlGenericError(xmlGenericErrorContext,
1919c2c66affSColin Finck 		    "Using rewriting rule %s\n", rewrite->name);
1920c2c66affSColin Finck 	ret = xmlStrdup(rewrite->URL);
1921c2c66affSColin Finck 	if (ret != NULL)
1922c2c66affSColin Finck 	    ret = xmlStrcat(ret, &URI[lenrewrite]);
1923c2c66affSColin Finck 	return(ret);
1924c2c66affSColin Finck     }
1925c2c66affSColin Finck     if (haveDelegate) {
1926c2c66affSColin Finck 	const xmlChar *delegates[MAX_DELEGATE];
1927c2c66affSColin Finck 	int nbList = 0, i;
1928c2c66affSColin Finck 
1929c2c66affSColin Finck 	/*
1930c2c66affSColin Finck 	 * Assume the entries have been sorted by decreasing substring
1931c2c66affSColin Finck 	 * matches when the list was produced.
1932c2c66affSColin Finck 	 */
1933c2c66affSColin Finck 	cur = catal;
1934c2c66affSColin Finck 	while (cur != NULL) {
1935c2c66affSColin Finck 	    if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1936c2c66affSColin Finck 	         (cur->type == XML_CATA_DELEGATE_URI)) &&
1937c2c66affSColin Finck 		(!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
1938c2c66affSColin Finck 		for (i = 0;i < nbList;i++)
1939c2c66affSColin Finck 		    if (xmlStrEqual(cur->URL, delegates[i]))
1940c2c66affSColin Finck 			break;
1941c2c66affSColin Finck 		if (i < nbList) {
1942c2c66affSColin Finck 		    cur = cur->next;
1943c2c66affSColin Finck 		    continue;
1944c2c66affSColin Finck 		}
1945c2c66affSColin Finck 		if (nbList < MAX_DELEGATE)
1946c2c66affSColin Finck 		    delegates[nbList++] = cur->URL;
1947c2c66affSColin Finck 
1948c2c66affSColin Finck 		if (cur->children == NULL) {
1949c2c66affSColin Finck 		    xmlFetchXMLCatalogFile(cur);
1950c2c66affSColin Finck 		}
1951c2c66affSColin Finck 		if (cur->children != NULL) {
1952c2c66affSColin Finck 		    if (xmlDebugCatalogs)
1953c2c66affSColin Finck 			xmlGenericError(xmlGenericErrorContext,
1954c2c66affSColin Finck 				"Trying URI delegate %s\n", cur->URL);
1955c2c66affSColin Finck 		    ret = xmlCatalogListXMLResolveURI(
1956c2c66affSColin Finck 			    cur->children, URI);
1957c2c66affSColin Finck 		    if (ret != NULL)
1958c2c66affSColin Finck 			return(ret);
1959c2c66affSColin Finck 		}
1960c2c66affSColin Finck 	    }
1961c2c66affSColin Finck 	    cur = cur->next;
1962c2c66affSColin Finck 	}
1963c2c66affSColin Finck 	/*
1964c2c66affSColin Finck 	 * Apply the cut algorithm explained in 4/
1965c2c66affSColin Finck 	 */
1966c2c66affSColin Finck 	return(XML_CATAL_BREAK);
1967c2c66affSColin Finck     }
1968c2c66affSColin Finck     if (haveNext) {
1969c2c66affSColin Finck 	cur = catal;
1970c2c66affSColin Finck 	while (cur != NULL) {
1971c2c66affSColin Finck 	    if (cur->type == XML_CATA_NEXT_CATALOG) {
1972c2c66affSColin Finck 		if (cur->children == NULL) {
1973c2c66affSColin Finck 		    xmlFetchXMLCatalogFile(cur);
1974c2c66affSColin Finck 		}
1975c2c66affSColin Finck 		if (cur->children != NULL) {
1976c2c66affSColin Finck 		    ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1977c2c66affSColin Finck 		    if (ret != NULL)
1978c2c66affSColin Finck 			return(ret);
1979c2c66affSColin Finck 		}
1980c2c66affSColin Finck 	    }
1981c2c66affSColin Finck 	    cur = cur->next;
1982c2c66affSColin Finck 	}
1983c2c66affSColin Finck     }
1984c2c66affSColin Finck 
1985c2c66affSColin Finck     return(NULL);
1986c2c66affSColin Finck }
1987c2c66affSColin Finck 
1988c2c66affSColin Finck /**
1989c2c66affSColin Finck  * xmlCatalogListXMLResolve:
1990c2c66affSColin Finck  * @catal:  a catalog list
1991c2c66affSColin Finck  * @pubID:  the public ID string
1992c2c66affSColin Finck  * @sysID:  the system ID string
1993c2c66affSColin Finck  *
1994c2c66affSColin Finck  * Do a complete resolution lookup of an External Identifier for a
1995c2c66affSColin Finck  * list of catalogs
1996c2c66affSColin Finck  *
1997c2c66affSColin Finck  * Implements (or tries to) 7.1. External Identifier Resolution
1998c2c66affSColin Finck  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1999c2c66affSColin Finck  *
2000c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found
2001c2c66affSColin Finck  */
2002c2c66affSColin Finck static xmlChar *
2003c2c66affSColin Finck xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
2004c2c66affSColin Finck 	              const xmlChar *sysID) {
2005c2c66affSColin Finck     xmlChar *ret = NULL;
2006c2c66affSColin Finck     xmlChar *urnID = NULL;
2007c2c66affSColin Finck     xmlChar *normid;
2008c2c66affSColin Finck 
2009c2c66affSColin Finck     if (catal == NULL)
2010c2c66affSColin Finck         return(NULL);
2011c2c66affSColin Finck     if ((pubID == NULL) && (sysID == NULL))
2012c2c66affSColin Finck 	return(NULL);
2013c2c66affSColin Finck 
2014c2c66affSColin Finck     normid = xmlCatalogNormalizePublic(pubID);
2015c2c66affSColin Finck     if (normid != NULL)
2016c2c66affSColin Finck         pubID = (*normid != 0 ? normid : NULL);
2017c2c66affSColin Finck 
2018c2c66affSColin Finck     if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2019c2c66affSColin Finck 	urnID = xmlCatalogUnWrapURN(pubID);
2020c2c66affSColin Finck 	if (xmlDebugCatalogs) {
2021c2c66affSColin Finck 	    if (urnID == NULL)
2022c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
2023c2c66affSColin Finck 			"Public URN ID %s expanded to NULL\n", pubID);
2024c2c66affSColin Finck 	    else
2025c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
2026c2c66affSColin Finck 			"Public URN ID expanded to %s\n", urnID);
2027c2c66affSColin Finck 	}
2028c2c66affSColin Finck 	ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2029c2c66affSColin Finck 	if (urnID != NULL)
2030c2c66affSColin Finck 	    xmlFree(urnID);
2031c2c66affSColin Finck 	if (normid != NULL)
2032c2c66affSColin Finck 	    xmlFree(normid);
2033c2c66affSColin Finck 	return(ret);
2034c2c66affSColin Finck     }
2035c2c66affSColin Finck     if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2036c2c66affSColin Finck 	urnID = xmlCatalogUnWrapURN(sysID);
2037c2c66affSColin Finck 	if (xmlDebugCatalogs) {
2038c2c66affSColin Finck 	    if (urnID == NULL)
2039c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
2040c2c66affSColin Finck 			"System URN ID %s expanded to NULL\n", sysID);
2041c2c66affSColin Finck 	    else
2042c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
2043c2c66affSColin Finck 			"System URN ID expanded to %s\n", urnID);
2044c2c66affSColin Finck 	}
2045c2c66affSColin Finck 	if (pubID == NULL)
2046c2c66affSColin Finck 	    ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2047c2c66affSColin Finck 	else if (xmlStrEqual(pubID, urnID))
2048c2c66affSColin Finck 	    ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2049c2c66affSColin Finck 	else {
2050c2c66affSColin Finck 	    ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
2051c2c66affSColin Finck 	}
2052c2c66affSColin Finck 	if (urnID != NULL)
2053c2c66affSColin Finck 	    xmlFree(urnID);
2054c2c66affSColin Finck 	if (normid != NULL)
2055c2c66affSColin Finck 	    xmlFree(normid);
2056c2c66affSColin Finck 	return(ret);
2057c2c66affSColin Finck     }
2058c2c66affSColin Finck     while (catal != NULL) {
2059c2c66affSColin Finck 	if (catal->type == XML_CATA_CATALOG) {
2060c2c66affSColin Finck 	    if (catal->children == NULL) {
2061c2c66affSColin Finck 		xmlFetchXMLCatalogFile(catal);
2062c2c66affSColin Finck 	    }
2063c2c66affSColin Finck 	    if (catal->children != NULL) {
2064c2c66affSColin Finck 		ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
2065c2c66affSColin Finck 		if (ret != NULL) {
2066c2c66affSColin Finck 		    break;
2067c2c66affSColin Finck                 } else if ((catal->children != NULL) &&
2068c2c66affSColin Finck 		           (catal->children->depth > MAX_CATAL_DEPTH)) {
2069c2c66affSColin Finck 	            ret = NULL;
2070c2c66affSColin Finck 		    break;
2071c2c66affSColin Finck 	        }
2072c2c66affSColin Finck 	    }
2073c2c66affSColin Finck 	}
2074c2c66affSColin Finck 	catal = catal->next;
2075c2c66affSColin Finck     }
2076c2c66affSColin Finck     if (normid != NULL)
2077c2c66affSColin Finck 	xmlFree(normid);
2078c2c66affSColin Finck     return(ret);
2079c2c66affSColin Finck }
2080c2c66affSColin Finck 
2081c2c66affSColin Finck /**
2082c2c66affSColin Finck  * xmlCatalogListXMLResolveURI:
2083c2c66affSColin Finck  * @catal:  a catalog list
2084c2c66affSColin Finck  * @URI:  the URI
2085c2c66affSColin Finck  *
2086c2c66affSColin Finck  * Do a complete resolution lookup of an URI for a list of catalogs
2087c2c66affSColin Finck  *
2088c2c66affSColin Finck  * Implements (or tries to) 7.2. URI Resolution
2089c2c66affSColin Finck  * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2090c2c66affSColin Finck  *
2091c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found
2092c2c66affSColin Finck  */
2093c2c66affSColin Finck static xmlChar *
2094c2c66affSColin Finck xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2095c2c66affSColin Finck     xmlChar *ret = NULL;
2096c2c66affSColin Finck     xmlChar *urnID = NULL;
2097c2c66affSColin Finck 
2098c2c66affSColin Finck     if (catal == NULL)
2099c2c66affSColin Finck         return(NULL);
2100c2c66affSColin Finck     if (URI == NULL)
2101c2c66affSColin Finck 	return(NULL);
2102c2c66affSColin Finck 
2103c2c66affSColin Finck     if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2104c2c66affSColin Finck 	urnID = xmlCatalogUnWrapURN(URI);
2105c2c66affSColin Finck 	if (xmlDebugCatalogs) {
2106c2c66affSColin Finck 	    if (urnID == NULL)
2107c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
2108c2c66affSColin Finck 			"URN ID %s expanded to NULL\n", URI);
2109c2c66affSColin Finck 	    else
2110c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
2111c2c66affSColin Finck 			"URN ID expanded to %s\n", urnID);
2112c2c66affSColin Finck 	}
2113c2c66affSColin Finck 	ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2114c2c66affSColin Finck 	if (urnID != NULL)
2115c2c66affSColin Finck 	    xmlFree(urnID);
2116c2c66affSColin Finck 	return(ret);
2117c2c66affSColin Finck     }
2118c2c66affSColin Finck     while (catal != NULL) {
2119c2c66affSColin Finck 	if (catal->type == XML_CATA_CATALOG) {
2120c2c66affSColin Finck 	    if (catal->children == NULL) {
2121c2c66affSColin Finck 		xmlFetchXMLCatalogFile(catal);
2122c2c66affSColin Finck 	    }
2123c2c66affSColin Finck 	    if (catal->children != NULL) {
2124c2c66affSColin Finck 		ret = xmlCatalogXMLResolveURI(catal->children, URI);
2125c2c66affSColin Finck 		if (ret != NULL)
2126c2c66affSColin Finck 		    return(ret);
2127c2c66affSColin Finck 	    }
2128c2c66affSColin Finck 	}
2129c2c66affSColin Finck 	catal = catal->next;
2130c2c66affSColin Finck     }
2131c2c66affSColin Finck     return(ret);
2132c2c66affSColin Finck }
2133c2c66affSColin Finck 
2134c2c66affSColin Finck /************************************************************************
2135c2c66affSColin Finck  *									*
2136c2c66affSColin Finck  *			The SGML Catalog parser				*
2137c2c66affSColin Finck  *									*
2138c2c66affSColin Finck  ************************************************************************/
2139c2c66affSColin Finck 
2140c2c66affSColin Finck 
2141c2c66affSColin Finck #define RAW *cur
2142c2c66affSColin Finck #define NEXT cur++;
2143c2c66affSColin Finck #define SKIP(x) cur += x;
2144c2c66affSColin Finck 
2145c2c66affSColin Finck #define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2146c2c66affSColin Finck 
2147c2c66affSColin Finck /**
2148c2c66affSColin Finck  * xmlParseSGMLCatalogComment:
2149c2c66affSColin Finck  * @cur:  the current character
2150c2c66affSColin Finck  *
2151c2c66affSColin Finck  * Skip a comment in an SGML catalog
2152c2c66affSColin Finck  *
2153c2c66affSColin Finck  * Returns new current character
2154c2c66affSColin Finck  */
2155c2c66affSColin Finck static const xmlChar *
2156c2c66affSColin Finck xmlParseSGMLCatalogComment(const xmlChar *cur) {
2157c2c66affSColin Finck     if ((cur[0] != '-') || (cur[1] != '-'))
2158c2c66affSColin Finck 	return(cur);
2159c2c66affSColin Finck     SKIP(2);
2160c2c66affSColin Finck     while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2161c2c66affSColin Finck 	NEXT;
2162c2c66affSColin Finck     if (cur[0] == 0) {
2163c2c66affSColin Finck 	return(NULL);
2164c2c66affSColin Finck     }
2165c2c66affSColin Finck     return(cur + 2);
2166c2c66affSColin Finck }
2167c2c66affSColin Finck 
2168c2c66affSColin Finck /**
2169c2c66affSColin Finck  * xmlParseSGMLCatalogPubid:
2170c2c66affSColin Finck  * @cur:  the current character
2171c2c66affSColin Finck  * @id:  the return location
2172c2c66affSColin Finck  *
2173c2c66affSColin Finck  * Parse an SGML catalog ID
2174c2c66affSColin Finck  *
2175c2c66affSColin Finck  * Returns new current character and store the value in @id
2176c2c66affSColin Finck  */
2177c2c66affSColin Finck static const xmlChar *
2178c2c66affSColin Finck xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
2179c2c66affSColin Finck     xmlChar *buf = NULL, *tmp;
2180c2c66affSColin Finck     int len = 0;
2181c2c66affSColin Finck     int size = 50;
2182c2c66affSColin Finck     xmlChar stop;
2183c2c66affSColin Finck     int count = 0;
2184c2c66affSColin Finck 
2185c2c66affSColin Finck     *id = NULL;
2186c2c66affSColin Finck 
2187c2c66affSColin Finck     if (RAW == '"') {
2188c2c66affSColin Finck         NEXT;
2189c2c66affSColin Finck 	stop = '"';
2190c2c66affSColin Finck     } else if (RAW == '\'') {
2191c2c66affSColin Finck         NEXT;
2192c2c66affSColin Finck 	stop = '\'';
2193c2c66affSColin Finck     } else {
2194c2c66affSColin Finck 	stop = ' ';
2195c2c66affSColin Finck     }
2196c2c66affSColin Finck     buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
2197c2c66affSColin Finck     if (buf == NULL) {
2198c2c66affSColin Finck         xmlCatalogErrMemory("allocating public ID");
2199c2c66affSColin Finck 	return(NULL);
2200c2c66affSColin Finck     }
2201c2c66affSColin Finck     while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
2202c2c66affSColin Finck 	if ((*cur == stop) && (stop != ' '))
2203c2c66affSColin Finck 	    break;
2204c2c66affSColin Finck 	if ((stop == ' ') && (IS_BLANK_CH(*cur)))
2205c2c66affSColin Finck 	    break;
2206c2c66affSColin Finck 	if (len + 1 >= size) {
2207c2c66affSColin Finck 	    size *= 2;
2208c2c66affSColin Finck 	    tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2209c2c66affSColin Finck 	    if (tmp == NULL) {
2210c2c66affSColin Finck 		xmlCatalogErrMemory("allocating public ID");
2211c2c66affSColin Finck 		xmlFree(buf);
2212c2c66affSColin Finck 		return(NULL);
2213c2c66affSColin Finck 	    }
2214c2c66affSColin Finck 	    buf = tmp;
2215c2c66affSColin Finck 	}
2216c2c66affSColin Finck 	buf[len++] = *cur;
2217c2c66affSColin Finck 	count++;
2218c2c66affSColin Finck 	NEXT;
2219c2c66affSColin Finck     }
2220c2c66affSColin Finck     buf[len] = 0;
2221c2c66affSColin Finck     if (stop == ' ') {
2222c2c66affSColin Finck 	if (!IS_BLANK_CH(*cur)) {
2223c2c66affSColin Finck 	    xmlFree(buf);
2224c2c66affSColin Finck 	    return(NULL);
2225c2c66affSColin Finck 	}
2226c2c66affSColin Finck     } else {
2227c2c66affSColin Finck 	if (*cur != stop) {
2228c2c66affSColin Finck 	    xmlFree(buf);
2229c2c66affSColin Finck 	    return(NULL);
2230c2c66affSColin Finck 	}
2231c2c66affSColin Finck 	NEXT;
2232c2c66affSColin Finck     }
2233c2c66affSColin Finck     *id = buf;
2234c2c66affSColin Finck     return(cur);
2235c2c66affSColin Finck }
2236c2c66affSColin Finck 
2237c2c66affSColin Finck /**
2238c2c66affSColin Finck  * xmlParseSGMLCatalogName:
2239c2c66affSColin Finck  * @cur:  the current character
2240c2c66affSColin Finck  * @name:  the return location
2241c2c66affSColin Finck  *
2242c2c66affSColin Finck  * Parse an SGML catalog name
2243c2c66affSColin Finck  *
2244c2c66affSColin Finck  * Returns new current character and store the value in @name
2245c2c66affSColin Finck  */
2246c2c66affSColin Finck static const xmlChar *
2247c2c66affSColin Finck xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
2248c2c66affSColin Finck     xmlChar buf[XML_MAX_NAMELEN + 5];
2249c2c66affSColin Finck     int len = 0;
2250c2c66affSColin Finck     int c;
2251c2c66affSColin Finck 
2252c2c66affSColin Finck     *name = NULL;
2253c2c66affSColin Finck 
2254c2c66affSColin Finck     /*
2255c2c66affSColin Finck      * Handler for more complex cases
2256c2c66affSColin Finck      */
2257c2c66affSColin Finck     c = *cur;
2258c2c66affSColin Finck     if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2259c2c66affSColin Finck 	return(NULL);
2260c2c66affSColin Finck     }
2261c2c66affSColin Finck 
2262c2c66affSColin Finck     while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2263c2c66affSColin Finck             (c == '.') || (c == '-') ||
2264c2c66affSColin Finck 	    (c == '_') || (c == ':'))) {
2265c2c66affSColin Finck 	buf[len++] = c;
2266c2c66affSColin Finck 	cur++;
2267c2c66affSColin Finck 	c = *cur;
2268c2c66affSColin Finck 	if (len >= XML_MAX_NAMELEN)
2269c2c66affSColin Finck 	    return(NULL);
2270c2c66affSColin Finck     }
2271c2c66affSColin Finck     *name = xmlStrndup(buf, len);
2272c2c66affSColin Finck     return(cur);
2273c2c66affSColin Finck }
2274c2c66affSColin Finck 
2275c2c66affSColin Finck /**
2276c2c66affSColin Finck  * xmlGetSGMLCatalogEntryType:
2277c2c66affSColin Finck  * @name:  the entry name
2278c2c66affSColin Finck  *
2279c2c66affSColin Finck  * Get the Catalog entry type for a given SGML Catalog name
2280c2c66affSColin Finck  *
2281c2c66affSColin Finck  * Returns Catalog entry type
2282c2c66affSColin Finck  */
2283c2c66affSColin Finck static xmlCatalogEntryType
2284c2c66affSColin Finck xmlGetSGMLCatalogEntryType(const xmlChar *name) {
2285c2c66affSColin Finck     xmlCatalogEntryType type = XML_CATA_NONE;
2286c2c66affSColin Finck     if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2287c2c66affSColin Finck 	type = SGML_CATA_SYSTEM;
2288c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2289c2c66affSColin Finck 	type = SGML_CATA_PUBLIC;
2290c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2291c2c66affSColin Finck 	type = SGML_CATA_DELEGATE;
2292c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2293c2c66affSColin Finck 	type = SGML_CATA_ENTITY;
2294c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2295c2c66affSColin Finck 	type = SGML_CATA_DOCTYPE;
2296c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2297c2c66affSColin Finck 	type = SGML_CATA_LINKTYPE;
2298c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2299c2c66affSColin Finck 	type = SGML_CATA_NOTATION;
2300c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2301c2c66affSColin Finck 	type = SGML_CATA_SGMLDECL;
2302c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2303c2c66affSColin Finck 	type = SGML_CATA_DOCUMENT;
2304c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2305c2c66affSColin Finck 	type = SGML_CATA_CATALOG;
2306c2c66affSColin Finck     else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2307c2c66affSColin Finck 	type = SGML_CATA_BASE;
2308c2c66affSColin Finck     return(type);
2309c2c66affSColin Finck }
2310c2c66affSColin Finck 
2311c2c66affSColin Finck /**
2312c2c66affSColin Finck  * xmlParseSGMLCatalog:
2313c2c66affSColin Finck  * @catal:  the SGML Catalog
2314c2c66affSColin Finck  * @value:  the content of the SGML Catalog serialization
2315c2c66affSColin Finck  * @file:  the filepath for the catalog
2316c2c66affSColin Finck  * @super:  should this be handled as a Super Catalog in which case
2317c2c66affSColin Finck  *          parsing is not recursive
2318c2c66affSColin Finck  *
2319c2c66affSColin Finck  * Parse an SGML catalog content and fill up the @catal hash table with
2320c2c66affSColin Finck  * the new entries found.
2321c2c66affSColin Finck  *
2322c2c66affSColin Finck  * Returns 0 in case of success, -1 in case of error.
2323c2c66affSColin Finck  */
2324c2c66affSColin Finck static int
2325c2c66affSColin Finck xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2326c2c66affSColin Finck 	            const char *file, int super) {
2327c2c66affSColin Finck     const xmlChar *cur = value;
2328c2c66affSColin Finck     xmlChar *base = NULL;
2329c2c66affSColin Finck     int res;
2330c2c66affSColin Finck 
2331c2c66affSColin Finck     if ((cur == NULL) || (file == NULL))
2332c2c66affSColin Finck         return(-1);
2333c2c66affSColin Finck     base = xmlStrdup((const xmlChar *) file);
2334c2c66affSColin Finck 
2335c2c66affSColin Finck     while ((cur != NULL) && (cur[0] != 0)) {
2336c2c66affSColin Finck 	SKIP_BLANKS;
2337c2c66affSColin Finck 	if (cur[0] == 0)
2338c2c66affSColin Finck 	    break;
2339c2c66affSColin Finck 	if ((cur[0] == '-') && (cur[1] == '-')) {
2340c2c66affSColin Finck 	    cur = xmlParseSGMLCatalogComment(cur);
2341c2c66affSColin Finck 	    if (cur == NULL) {
2342c2c66affSColin Finck 		/* error */
2343c2c66affSColin Finck 		break;
2344c2c66affSColin Finck 	    }
2345c2c66affSColin Finck 	} else {
2346c2c66affSColin Finck 	    xmlChar *sysid = NULL;
2347c2c66affSColin Finck 	    xmlChar *name = NULL;
2348c2c66affSColin Finck 	    xmlCatalogEntryType type = XML_CATA_NONE;
2349c2c66affSColin Finck 
2350c2c66affSColin Finck 	    cur = xmlParseSGMLCatalogName(cur, &name);
2351c2c66affSColin Finck 	    if (name == NULL) {
2352c2c66affSColin Finck 		/* error */
2353c2c66affSColin Finck 		break;
2354c2c66affSColin Finck 	    }
2355c2c66affSColin Finck 	    if (!IS_BLANK_CH(*cur)) {
2356c2c66affSColin Finck 		/* error */
2357c2c66affSColin Finck 		break;
2358c2c66affSColin Finck 	    }
2359c2c66affSColin Finck 	    SKIP_BLANKS;
2360c2c66affSColin Finck 	    if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2361c2c66affSColin Finck                 type = SGML_CATA_SYSTEM;
2362c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2363c2c66affSColin Finck                 type = SGML_CATA_PUBLIC;
2364c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2365c2c66affSColin Finck                 type = SGML_CATA_DELEGATE;
2366c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2367c2c66affSColin Finck                 type = SGML_CATA_ENTITY;
2368c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2369c2c66affSColin Finck                 type = SGML_CATA_DOCTYPE;
2370c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2371c2c66affSColin Finck                 type = SGML_CATA_LINKTYPE;
2372c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2373c2c66affSColin Finck                 type = SGML_CATA_NOTATION;
2374c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2375c2c66affSColin Finck                 type = SGML_CATA_SGMLDECL;
2376c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2377c2c66affSColin Finck                 type = SGML_CATA_DOCUMENT;
2378c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2379c2c66affSColin Finck                 type = SGML_CATA_CATALOG;
2380c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2381c2c66affSColin Finck                 type = SGML_CATA_BASE;
2382c2c66affSColin Finck 	    else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2383c2c66affSColin Finck 		xmlFree(name);
2384c2c66affSColin Finck 		cur = xmlParseSGMLCatalogName(cur, &name);
2385c2c66affSColin Finck 		if (name == NULL) {
2386c2c66affSColin Finck 		    /* error */
2387c2c66affSColin Finck 		    break;
2388c2c66affSColin Finck 		}
2389c2c66affSColin Finck 		xmlFree(name);
2390c2c66affSColin Finck 		continue;
2391c2c66affSColin Finck 	    }
2392c2c66affSColin Finck 	    xmlFree(name);
2393c2c66affSColin Finck 	    name = NULL;
2394c2c66affSColin Finck 
2395c2c66affSColin Finck 	    switch(type) {
2396c2c66affSColin Finck 		case SGML_CATA_ENTITY:
2397c2c66affSColin Finck 		    if (*cur == '%')
2398c2c66affSColin Finck 			type = SGML_CATA_PENTITY;
2399*fc82f8e2SThomas Faber                     /* Falls through. */
2400c2c66affSColin Finck 		case SGML_CATA_PENTITY:
2401c2c66affSColin Finck 		case SGML_CATA_DOCTYPE:
2402c2c66affSColin Finck 		case SGML_CATA_LINKTYPE:
2403c2c66affSColin Finck 		case SGML_CATA_NOTATION:
2404c2c66affSColin Finck 		    cur = xmlParseSGMLCatalogName(cur, &name);
2405c2c66affSColin Finck 		    if (cur == NULL) {
2406c2c66affSColin Finck 			/* error */
2407c2c66affSColin Finck 			break;
2408c2c66affSColin Finck 		    }
2409c2c66affSColin Finck 		    if (!IS_BLANK_CH(*cur)) {
2410c2c66affSColin Finck 			/* error */
2411c2c66affSColin Finck 			break;
2412c2c66affSColin Finck 		    }
2413c2c66affSColin Finck 		    SKIP_BLANKS;
2414c2c66affSColin Finck 		    cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2415c2c66affSColin Finck 		    if (cur == NULL) {
2416c2c66affSColin Finck 			/* error */
2417c2c66affSColin Finck 			break;
2418c2c66affSColin Finck 		    }
2419c2c66affSColin Finck 		    break;
2420c2c66affSColin Finck 		case SGML_CATA_PUBLIC:
2421c2c66affSColin Finck 		case SGML_CATA_SYSTEM:
2422c2c66affSColin Finck 		case SGML_CATA_DELEGATE:
2423c2c66affSColin Finck 		    cur = xmlParseSGMLCatalogPubid(cur, &name);
2424c2c66affSColin Finck 		    if (cur == NULL) {
2425c2c66affSColin Finck 			/* error */
2426c2c66affSColin Finck 			break;
2427c2c66affSColin Finck 		    }
2428c2c66affSColin Finck 		    if (type != SGML_CATA_SYSTEM) {
2429c2c66affSColin Finck 		        xmlChar *normid;
2430c2c66affSColin Finck 
2431c2c66affSColin Finck 		        normid = xmlCatalogNormalizePublic(name);
2432c2c66affSColin Finck 		        if (normid != NULL) {
2433c2c66affSColin Finck 		            if (name != NULL)
2434c2c66affSColin Finck 		                xmlFree(name);
2435c2c66affSColin Finck 		            if (*normid != 0)
2436c2c66affSColin Finck 		                name = normid;
2437c2c66affSColin Finck 		            else {
2438c2c66affSColin Finck 		                xmlFree(normid);
2439c2c66affSColin Finck 		                name = NULL;
2440c2c66affSColin Finck 		            }
2441c2c66affSColin Finck 		        }
2442c2c66affSColin Finck 		    }
2443c2c66affSColin Finck 		    if (!IS_BLANK_CH(*cur)) {
2444c2c66affSColin Finck 			/* error */
2445c2c66affSColin Finck 			break;
2446c2c66affSColin Finck 		    }
2447c2c66affSColin Finck 		    SKIP_BLANKS;
2448c2c66affSColin Finck 		    cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2449c2c66affSColin Finck 		    if (cur == NULL) {
2450c2c66affSColin Finck 			/* error */
2451c2c66affSColin Finck 			break;
2452c2c66affSColin Finck 		    }
2453c2c66affSColin Finck 		    break;
2454c2c66affSColin Finck 		case SGML_CATA_BASE:
2455c2c66affSColin Finck 		case SGML_CATA_CATALOG:
2456c2c66affSColin Finck 		case SGML_CATA_DOCUMENT:
2457c2c66affSColin Finck 		case SGML_CATA_SGMLDECL:
2458c2c66affSColin Finck 		    cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2459c2c66affSColin Finck 		    if (cur == NULL) {
2460c2c66affSColin Finck 			/* error */
2461c2c66affSColin Finck 			break;
2462c2c66affSColin Finck 		    }
2463c2c66affSColin Finck 		    break;
2464c2c66affSColin Finck 		default:
2465c2c66affSColin Finck 		    break;
2466c2c66affSColin Finck 	    }
2467c2c66affSColin Finck 	    if (cur == NULL) {
2468c2c66affSColin Finck 		if (name != NULL)
2469c2c66affSColin Finck 		    xmlFree(name);
2470c2c66affSColin Finck 		if (sysid != NULL)
2471c2c66affSColin Finck 		    xmlFree(sysid);
2472c2c66affSColin Finck 		break;
2473c2c66affSColin Finck 	    } else if (type == SGML_CATA_BASE) {
2474c2c66affSColin Finck 		if (base != NULL)
2475c2c66affSColin Finck 		    xmlFree(base);
2476c2c66affSColin Finck 		base = xmlStrdup(sysid);
2477c2c66affSColin Finck 	    } else if ((type == SGML_CATA_PUBLIC) ||
2478c2c66affSColin Finck 		       (type == SGML_CATA_SYSTEM)) {
2479c2c66affSColin Finck 		xmlChar *filename;
2480c2c66affSColin Finck 
2481c2c66affSColin Finck 		filename = xmlBuildURI(sysid, base);
2482c2c66affSColin Finck 		if (filename != NULL) {
2483c2c66affSColin Finck 		    xmlCatalogEntryPtr entry;
2484c2c66affSColin Finck 
2485c2c66affSColin Finck 		    entry = xmlNewCatalogEntry(type, name, filename,
2486c2c66affSColin Finck 			                       NULL, XML_CATA_PREFER_NONE, NULL);
2487c2c66affSColin Finck 		    res = xmlHashAddEntry(catal->sgml, name, entry);
2488c2c66affSColin Finck 		    if (res < 0) {
2489c2c66affSColin Finck 			xmlFreeCatalogEntry(entry);
2490c2c66affSColin Finck 		    }
2491c2c66affSColin Finck 		    xmlFree(filename);
2492c2c66affSColin Finck 		}
2493c2c66affSColin Finck 
2494c2c66affSColin Finck 	    } else if (type == SGML_CATA_CATALOG) {
2495c2c66affSColin Finck 		if (super) {
2496c2c66affSColin Finck 		    xmlCatalogEntryPtr entry;
2497c2c66affSColin Finck 
2498c2c66affSColin Finck 		    entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
2499c2c66affSColin Finck 			                       XML_CATA_PREFER_NONE, NULL);
2500c2c66affSColin Finck 		    res = xmlHashAddEntry(catal->sgml, sysid, entry);
2501c2c66affSColin Finck 		    if (res < 0) {
2502c2c66affSColin Finck 			xmlFreeCatalogEntry(entry);
2503c2c66affSColin Finck 		    }
2504c2c66affSColin Finck 		} else {
2505c2c66affSColin Finck 		    xmlChar *filename;
2506c2c66affSColin Finck 
2507c2c66affSColin Finck 		    filename = xmlBuildURI(sysid, base);
2508c2c66affSColin Finck 		    if (filename != NULL) {
2509c2c66affSColin Finck 			xmlExpandCatalog(catal, (const char *)filename);
2510c2c66affSColin Finck 			xmlFree(filename);
2511c2c66affSColin Finck 		    }
2512c2c66affSColin Finck 		}
2513c2c66affSColin Finck 	    }
2514c2c66affSColin Finck 	    /*
2515c2c66affSColin Finck 	     * drop anything else we won't handle it
2516c2c66affSColin Finck 	     */
2517c2c66affSColin Finck 	    if (name != NULL)
2518c2c66affSColin Finck 		xmlFree(name);
2519c2c66affSColin Finck 	    if (sysid != NULL)
2520c2c66affSColin Finck 		xmlFree(sysid);
2521c2c66affSColin Finck 	}
2522c2c66affSColin Finck     }
2523c2c66affSColin Finck     if (base != NULL)
2524c2c66affSColin Finck 	xmlFree(base);
2525c2c66affSColin Finck     if (cur == NULL)
2526c2c66affSColin Finck 	return(-1);
2527c2c66affSColin Finck     return(0);
2528c2c66affSColin Finck }
2529c2c66affSColin Finck 
2530c2c66affSColin Finck /************************************************************************
2531c2c66affSColin Finck  *									*
2532c2c66affSColin Finck  *			SGML Catalog handling				*
2533c2c66affSColin Finck  *									*
2534c2c66affSColin Finck  ************************************************************************/
2535c2c66affSColin Finck 
2536c2c66affSColin Finck /**
2537c2c66affSColin Finck  * xmlCatalogGetSGMLPublic:
2538c2c66affSColin Finck  * @catal:  an SGML catalog hash
2539c2c66affSColin Finck  * @pubID:  the public ID string
2540c2c66affSColin Finck  *
2541c2c66affSColin Finck  * Try to lookup the catalog local reference associated to a public ID
2542c2c66affSColin Finck  *
2543c2c66affSColin Finck  * Returns the local resource if found or NULL otherwise.
2544c2c66affSColin Finck  */
2545c2c66affSColin Finck static const xmlChar *
2546c2c66affSColin Finck xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2547c2c66affSColin Finck     xmlCatalogEntryPtr entry;
2548c2c66affSColin Finck     xmlChar *normid;
2549c2c66affSColin Finck 
2550c2c66affSColin Finck     if (catal == NULL)
2551c2c66affSColin Finck 	return(NULL);
2552c2c66affSColin Finck 
2553c2c66affSColin Finck     normid = xmlCatalogNormalizePublic(pubID);
2554c2c66affSColin Finck     if (normid != NULL)
2555c2c66affSColin Finck         pubID = (*normid != 0 ? normid : NULL);
2556c2c66affSColin Finck 
2557c2c66affSColin Finck     entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2558c2c66affSColin Finck     if (entry == NULL) {
2559c2c66affSColin Finck 	if (normid != NULL)
2560c2c66affSColin Finck 	    xmlFree(normid);
2561c2c66affSColin Finck 	return(NULL);
2562c2c66affSColin Finck     }
2563c2c66affSColin Finck     if (entry->type == SGML_CATA_PUBLIC) {
2564c2c66affSColin Finck 	if (normid != NULL)
2565c2c66affSColin Finck 	    xmlFree(normid);
2566c2c66affSColin Finck 	return(entry->URL);
2567c2c66affSColin Finck     }
2568c2c66affSColin Finck     if (normid != NULL)
2569c2c66affSColin Finck         xmlFree(normid);
2570c2c66affSColin Finck     return(NULL);
2571c2c66affSColin Finck }
2572c2c66affSColin Finck 
2573c2c66affSColin Finck /**
2574c2c66affSColin Finck  * xmlCatalogGetSGMLSystem:
2575c2c66affSColin Finck  * @catal:  an SGML catalog hash
2576c2c66affSColin Finck  * @sysID:  the system ID string
2577c2c66affSColin Finck  *
2578c2c66affSColin Finck  * Try to lookup the catalog local reference for a system ID
2579c2c66affSColin Finck  *
2580c2c66affSColin Finck  * Returns the local resource if found or NULL otherwise.
2581c2c66affSColin Finck  */
2582c2c66affSColin Finck static const xmlChar *
2583c2c66affSColin Finck xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2584c2c66affSColin Finck     xmlCatalogEntryPtr entry;
2585c2c66affSColin Finck 
2586c2c66affSColin Finck     if (catal == NULL)
2587c2c66affSColin Finck 	return(NULL);
2588c2c66affSColin Finck 
2589c2c66affSColin Finck     entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2590c2c66affSColin Finck     if (entry == NULL)
2591c2c66affSColin Finck 	return(NULL);
2592c2c66affSColin Finck     if (entry->type == SGML_CATA_SYSTEM)
2593c2c66affSColin Finck 	return(entry->URL);
2594c2c66affSColin Finck     return(NULL);
2595c2c66affSColin Finck }
2596c2c66affSColin Finck 
2597c2c66affSColin Finck /**
2598c2c66affSColin Finck  * xmlCatalogSGMLResolve:
2599c2c66affSColin Finck  * @catal:  the SGML catalog
2600c2c66affSColin Finck  * @pubID:  the public ID string
2601c2c66affSColin Finck  * @sysID:  the system ID string
2602c2c66affSColin Finck  *
2603c2c66affSColin Finck  * Do a complete resolution lookup of an External Identifier
2604c2c66affSColin Finck  *
2605c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found
2606c2c66affSColin Finck  */
2607c2c66affSColin Finck static const xmlChar *
2608c2c66affSColin Finck xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2609c2c66affSColin Finck 	              const xmlChar *sysID) {
2610c2c66affSColin Finck     const xmlChar *ret = NULL;
2611c2c66affSColin Finck 
2612c2c66affSColin Finck     if (catal->sgml == NULL)
2613c2c66affSColin Finck 	return(NULL);
2614c2c66affSColin Finck 
2615c2c66affSColin Finck     if (pubID != NULL)
2616c2c66affSColin Finck 	ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2617c2c66affSColin Finck     if (ret != NULL)
2618c2c66affSColin Finck 	return(ret);
2619c2c66affSColin Finck     if (sysID != NULL)
2620c2c66affSColin Finck 	ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2621c2c66affSColin Finck     if (ret != NULL)
2622c2c66affSColin Finck 	return(ret);
2623c2c66affSColin Finck     return(NULL);
2624c2c66affSColin Finck }
2625c2c66affSColin Finck 
2626c2c66affSColin Finck /************************************************************************
2627c2c66affSColin Finck  *									*
2628c2c66affSColin Finck  *			Specific Public interfaces			*
2629c2c66affSColin Finck  *									*
2630c2c66affSColin Finck  ************************************************************************/
2631c2c66affSColin Finck 
2632c2c66affSColin Finck /**
2633c2c66affSColin Finck  * xmlLoadSGMLSuperCatalog:
2634c2c66affSColin Finck  * @filename:  a file path
2635c2c66affSColin Finck  *
2636c2c66affSColin Finck  * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2637c2c66affSColin Finck  * references. This is only needed for manipulating SGML Super Catalogs
2638c2c66affSColin Finck  * like adding and removing CATALOG or DELEGATE entries.
2639c2c66affSColin Finck  *
2640c2c66affSColin Finck  * Returns the catalog parsed or NULL in case of error
2641c2c66affSColin Finck  */
2642c2c66affSColin Finck xmlCatalogPtr
2643c2c66affSColin Finck xmlLoadSGMLSuperCatalog(const char *filename)
2644c2c66affSColin Finck {
2645c2c66affSColin Finck     xmlChar *content;
2646c2c66affSColin Finck     xmlCatalogPtr catal;
2647c2c66affSColin Finck     int ret;
2648c2c66affSColin Finck 
2649c2c66affSColin Finck     content = xmlLoadFileContent(filename);
2650c2c66affSColin Finck     if (content == NULL)
2651c2c66affSColin Finck         return(NULL);
2652c2c66affSColin Finck 
2653c2c66affSColin Finck     catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2654c2c66affSColin Finck     if (catal == NULL) {
2655c2c66affSColin Finck 	xmlFree(content);
2656c2c66affSColin Finck 	return(NULL);
2657c2c66affSColin Finck     }
2658c2c66affSColin Finck 
2659c2c66affSColin Finck     ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2660c2c66affSColin Finck     xmlFree(content);
2661c2c66affSColin Finck     if (ret < 0) {
2662c2c66affSColin Finck 	xmlFreeCatalog(catal);
2663c2c66affSColin Finck 	return(NULL);
2664c2c66affSColin Finck     }
2665c2c66affSColin Finck     return (catal);
2666c2c66affSColin Finck }
2667c2c66affSColin Finck 
2668c2c66affSColin Finck /**
2669c2c66affSColin Finck  * xmlLoadACatalog:
2670c2c66affSColin Finck  * @filename:  a file path
2671c2c66affSColin Finck  *
2672c2c66affSColin Finck  * Load the catalog and build the associated data structures.
2673c2c66affSColin Finck  * This can be either an XML Catalog or an SGML Catalog
2674c2c66affSColin Finck  * It will recurse in SGML CATALOG entries. On the other hand XML
2675c2c66affSColin Finck  * Catalogs are not handled recursively.
2676c2c66affSColin Finck  *
2677c2c66affSColin Finck  * Returns the catalog parsed or NULL in case of error
2678c2c66affSColin Finck  */
2679c2c66affSColin Finck xmlCatalogPtr
2680c2c66affSColin Finck xmlLoadACatalog(const char *filename)
2681c2c66affSColin Finck {
2682c2c66affSColin Finck     xmlChar *content;
2683c2c66affSColin Finck     xmlChar *first;
2684c2c66affSColin Finck     xmlCatalogPtr catal;
2685c2c66affSColin Finck     int ret;
2686c2c66affSColin Finck 
2687c2c66affSColin Finck     content = xmlLoadFileContent(filename);
2688c2c66affSColin Finck     if (content == NULL)
2689c2c66affSColin Finck         return(NULL);
2690c2c66affSColin Finck 
2691c2c66affSColin Finck 
2692c2c66affSColin Finck     first = content;
2693c2c66affSColin Finck 
2694c2c66affSColin Finck     while ((*first != 0) && (*first != '-') && (*first != '<') &&
2695c2c66affSColin Finck 	   (!(((*first >= 'A') && (*first <= 'Z')) ||
2696c2c66affSColin Finck 	      ((*first >= 'a') && (*first <= 'z')))))
2697c2c66affSColin Finck 	first++;
2698c2c66affSColin Finck 
2699c2c66affSColin Finck     if (*first != '<') {
2700c2c66affSColin Finck 	catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2701c2c66affSColin Finck 	if (catal == NULL) {
2702c2c66affSColin Finck 	    xmlFree(content);
2703c2c66affSColin Finck 	    return(NULL);
2704c2c66affSColin Finck 	}
2705c2c66affSColin Finck         ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2706c2c66affSColin Finck 	if (ret < 0) {
2707c2c66affSColin Finck 	    xmlFreeCatalog(catal);
2708c2c66affSColin Finck 	    xmlFree(content);
2709c2c66affSColin Finck 	    return(NULL);
2710c2c66affSColin Finck 	}
2711c2c66affSColin Finck     } else {
2712c2c66affSColin Finck 	catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2713c2c66affSColin Finck 	if (catal == NULL) {
2714c2c66affSColin Finck 	    xmlFree(content);
2715c2c66affSColin Finck 	    return(NULL);
2716c2c66affSColin Finck 	}
2717c2c66affSColin Finck         catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2718c2c66affSColin Finck 		       NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
2719c2c66affSColin Finck     }
2720c2c66affSColin Finck     xmlFree(content);
2721c2c66affSColin Finck     return (catal);
2722c2c66affSColin Finck }
2723c2c66affSColin Finck 
2724c2c66affSColin Finck /**
2725c2c66affSColin Finck  * xmlExpandCatalog:
2726c2c66affSColin Finck  * @catal:  a catalog
2727c2c66affSColin Finck  * @filename:  a file path
2728c2c66affSColin Finck  *
2729c2c66affSColin Finck  * Load the catalog and expand the existing catal structure.
2730c2c66affSColin Finck  * This can be either an XML Catalog or an SGML Catalog
2731c2c66affSColin Finck  *
2732c2c66affSColin Finck  * Returns 0 in case of success, -1 in case of error
2733c2c66affSColin Finck  */
2734c2c66affSColin Finck static int
2735c2c66affSColin Finck xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2736c2c66affSColin Finck {
2737c2c66affSColin Finck     int ret;
2738c2c66affSColin Finck 
2739c2c66affSColin Finck     if ((catal == NULL) || (filename == NULL))
2740c2c66affSColin Finck 	return(-1);
2741c2c66affSColin Finck 
2742c2c66affSColin Finck 
2743c2c66affSColin Finck     if (catal->type == XML_SGML_CATALOG_TYPE) {
2744c2c66affSColin Finck 	xmlChar *content;
2745c2c66affSColin Finck 
2746c2c66affSColin Finck 	content = xmlLoadFileContent(filename);
2747c2c66affSColin Finck 	if (content == NULL)
2748c2c66affSColin Finck 	    return(-1);
2749c2c66affSColin Finck 
2750c2c66affSColin Finck         ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2751c2c66affSColin Finck 	if (ret < 0) {
2752c2c66affSColin Finck 	    xmlFree(content);
2753c2c66affSColin Finck 	    return(-1);
2754c2c66affSColin Finck 	}
2755c2c66affSColin Finck 	xmlFree(content);
2756c2c66affSColin Finck     } else {
2757c2c66affSColin Finck 	xmlCatalogEntryPtr tmp, cur;
2758c2c66affSColin Finck 	tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2759c2c66affSColin Finck 		       NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
2760c2c66affSColin Finck 
2761c2c66affSColin Finck 	cur = catal->xml;
2762c2c66affSColin Finck 	if (cur == NULL) {
2763c2c66affSColin Finck 	    catal->xml = tmp;
2764c2c66affSColin Finck 	} else {
2765c2c66affSColin Finck 	    while (cur->next != NULL) cur = cur->next;
2766c2c66affSColin Finck 	    cur->next = tmp;
2767c2c66affSColin Finck 	}
2768c2c66affSColin Finck     }
2769c2c66affSColin Finck     return (0);
2770c2c66affSColin Finck }
2771c2c66affSColin Finck 
2772c2c66affSColin Finck /**
2773c2c66affSColin Finck  * xmlACatalogResolveSystem:
2774c2c66affSColin Finck  * @catal:  a Catalog
2775c2c66affSColin Finck  * @sysID:  the system ID string
2776c2c66affSColin Finck  *
2777c2c66affSColin Finck  * Try to lookup the catalog resource for a system ID
2778c2c66affSColin Finck  *
2779c2c66affSColin Finck  * Returns the resource if found or NULL otherwise, the value returned
2780c2c66affSColin Finck  *      must be freed by the caller.
2781c2c66affSColin Finck  */
2782c2c66affSColin Finck xmlChar *
2783c2c66affSColin Finck xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2784c2c66affSColin Finck     xmlChar *ret = NULL;
2785c2c66affSColin Finck 
2786c2c66affSColin Finck     if ((sysID == NULL) || (catal == NULL))
2787c2c66affSColin Finck 	return(NULL);
2788c2c66affSColin Finck 
2789c2c66affSColin Finck     if (xmlDebugCatalogs)
2790c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
2791c2c66affSColin Finck 		"Resolve sysID %s\n", sysID);
2792c2c66affSColin Finck 
2793c2c66affSColin Finck     if (catal->type == XML_XML_CATALOG_TYPE) {
2794c2c66affSColin Finck 	ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2795c2c66affSColin Finck 	if (ret == XML_CATAL_BREAK)
2796c2c66affSColin Finck 	    ret = NULL;
2797c2c66affSColin Finck     } else {
2798c2c66affSColin Finck 	const xmlChar *sgml;
2799c2c66affSColin Finck 
2800c2c66affSColin Finck 	sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2801c2c66affSColin Finck 	if (sgml != NULL)
2802c2c66affSColin Finck 	    ret = xmlStrdup(sgml);
2803c2c66affSColin Finck     }
2804c2c66affSColin Finck     return(ret);
2805c2c66affSColin Finck }
2806c2c66affSColin Finck 
2807c2c66affSColin Finck /**
2808c2c66affSColin Finck  * xmlACatalogResolvePublic:
2809c2c66affSColin Finck  * @catal:  a Catalog
2810c2c66affSColin Finck  * @pubID:  the public ID string
2811c2c66affSColin Finck  *
2812c2c66affSColin Finck  * Try to lookup the catalog local reference associated to a public ID in that catalog
2813c2c66affSColin Finck  *
2814c2c66affSColin Finck  * Returns the local resource if found or NULL otherwise, the value returned
2815c2c66affSColin Finck  *      must be freed by the caller.
2816c2c66affSColin Finck  */
2817c2c66affSColin Finck xmlChar *
2818c2c66affSColin Finck xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2819c2c66affSColin Finck     xmlChar *ret = NULL;
2820c2c66affSColin Finck 
2821c2c66affSColin Finck     if ((pubID == NULL) || (catal == NULL))
2822c2c66affSColin Finck 	return(NULL);
2823c2c66affSColin Finck 
2824c2c66affSColin Finck     if (xmlDebugCatalogs)
2825c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
2826c2c66affSColin Finck 		"Resolve pubID %s\n", pubID);
2827c2c66affSColin Finck 
2828c2c66affSColin Finck     if (catal->type == XML_XML_CATALOG_TYPE) {
2829c2c66affSColin Finck 	ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2830c2c66affSColin Finck 	if (ret == XML_CATAL_BREAK)
2831c2c66affSColin Finck 	    ret = NULL;
2832c2c66affSColin Finck     } else {
2833c2c66affSColin Finck 	const xmlChar *sgml;
2834c2c66affSColin Finck 
2835c2c66affSColin Finck 	sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2836c2c66affSColin Finck 	if (sgml != NULL)
2837c2c66affSColin Finck 	    ret = xmlStrdup(sgml);
2838c2c66affSColin Finck     }
2839c2c66affSColin Finck     return(ret);
2840c2c66affSColin Finck }
2841c2c66affSColin Finck 
2842c2c66affSColin Finck /**
2843c2c66affSColin Finck  * xmlACatalogResolve:
2844c2c66affSColin Finck  * @catal:  a Catalog
2845c2c66affSColin Finck  * @pubID:  the public ID string
2846c2c66affSColin Finck  * @sysID:  the system ID string
2847c2c66affSColin Finck  *
2848c2c66affSColin Finck  * Do a complete resolution lookup of an External Identifier
2849c2c66affSColin Finck  *
2850c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found, it must be freed
2851c2c66affSColin Finck  *      by the caller.
2852c2c66affSColin Finck  */
2853c2c66affSColin Finck xmlChar *
2854c2c66affSColin Finck xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2855c2c66affSColin Finck                    const xmlChar * sysID)
2856c2c66affSColin Finck {
2857c2c66affSColin Finck     xmlChar *ret = NULL;
2858c2c66affSColin Finck 
2859c2c66affSColin Finck     if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2860c2c66affSColin Finck         return (NULL);
2861c2c66affSColin Finck 
2862c2c66affSColin Finck     if (xmlDebugCatalogs) {
2863c2c66affSColin Finck          if ((pubID != NULL) && (sysID != NULL)) {
2864c2c66affSColin Finck              xmlGenericError(xmlGenericErrorContext,
2865c2c66affSColin Finck                              "Resolve: pubID %s sysID %s\n", pubID, sysID);
2866c2c66affSColin Finck          } else if (pubID != NULL) {
2867c2c66affSColin Finck              xmlGenericError(xmlGenericErrorContext,
2868c2c66affSColin Finck                              "Resolve: pubID %s\n", pubID);
2869c2c66affSColin Finck          } else {
2870c2c66affSColin Finck              xmlGenericError(xmlGenericErrorContext,
2871c2c66affSColin Finck                              "Resolve: sysID %s\n", sysID);
2872c2c66affSColin Finck          }
2873c2c66affSColin Finck     }
2874c2c66affSColin Finck 
2875c2c66affSColin Finck     if (catal->type == XML_XML_CATALOG_TYPE) {
2876c2c66affSColin Finck         ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2877c2c66affSColin Finck 	if (ret == XML_CATAL_BREAK)
2878c2c66affSColin Finck 	    ret = NULL;
2879c2c66affSColin Finck     } else {
2880c2c66affSColin Finck         const xmlChar *sgml;
2881c2c66affSColin Finck 
2882c2c66affSColin Finck         sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2883c2c66affSColin Finck         if (sgml != NULL)
2884c2c66affSColin Finck             ret = xmlStrdup(sgml);
2885c2c66affSColin Finck     }
2886c2c66affSColin Finck     return (ret);
2887c2c66affSColin Finck }
2888c2c66affSColin Finck 
2889c2c66affSColin Finck /**
2890c2c66affSColin Finck  * xmlACatalogResolveURI:
2891c2c66affSColin Finck  * @catal:  a Catalog
2892c2c66affSColin Finck  * @URI:  the URI
2893c2c66affSColin Finck  *
2894c2c66affSColin Finck  * Do a complete resolution lookup of an URI
2895c2c66affSColin Finck  *
2896c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found, it must be freed
2897c2c66affSColin Finck  *      by the caller.
2898c2c66affSColin Finck  */
2899c2c66affSColin Finck xmlChar *
2900c2c66affSColin Finck xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2901c2c66affSColin Finck     xmlChar *ret = NULL;
2902c2c66affSColin Finck 
2903c2c66affSColin Finck     if ((URI == NULL) || (catal == NULL))
2904c2c66affSColin Finck 	return(NULL);
2905c2c66affSColin Finck 
2906c2c66affSColin Finck     if (xmlDebugCatalogs)
2907c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
2908c2c66affSColin Finck 		"Resolve URI %s\n", URI);
2909c2c66affSColin Finck 
2910c2c66affSColin Finck     if (catal->type == XML_XML_CATALOG_TYPE) {
2911c2c66affSColin Finck 	ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2912c2c66affSColin Finck 	if (ret == XML_CATAL_BREAK)
2913c2c66affSColin Finck 	    ret = NULL;
2914c2c66affSColin Finck     } else {
2915c2c66affSColin Finck 	const xmlChar *sgml;
2916c2c66affSColin Finck 
2917c2c66affSColin Finck 	sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2918c2c66affSColin Finck 	if (sgml != NULL)
2919c2c66affSColin Finck             ret = xmlStrdup(sgml);
2920c2c66affSColin Finck     }
2921c2c66affSColin Finck     return(ret);
2922c2c66affSColin Finck }
2923c2c66affSColin Finck 
2924c2c66affSColin Finck #ifdef LIBXML_OUTPUT_ENABLED
2925c2c66affSColin Finck /**
2926c2c66affSColin Finck  * xmlACatalogDump:
2927c2c66affSColin Finck  * @catal:  a Catalog
2928c2c66affSColin Finck  * @out:  the file.
2929c2c66affSColin Finck  *
2930c2c66affSColin Finck  * Dump the given catalog to the given file.
2931c2c66affSColin Finck  */
2932c2c66affSColin Finck void
2933c2c66affSColin Finck xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
2934c2c66affSColin Finck     if ((out == NULL) || (catal == NULL))
2935c2c66affSColin Finck 	return;
2936c2c66affSColin Finck 
2937c2c66affSColin Finck     if (catal->type == XML_XML_CATALOG_TYPE) {
2938c2c66affSColin Finck 	xmlDumpXMLCatalog(out, catal->xml);
2939c2c66affSColin Finck     } else {
2940c2c66affSColin Finck 	xmlHashScan(catal->sgml,
2941c2c66affSColin Finck 		    (xmlHashScanner) xmlCatalogDumpEntry, out);
2942c2c66affSColin Finck     }
2943c2c66affSColin Finck }
2944c2c66affSColin Finck #endif /* LIBXML_OUTPUT_ENABLED */
2945c2c66affSColin Finck 
2946c2c66affSColin Finck /**
2947c2c66affSColin Finck  * xmlACatalogAdd:
2948c2c66affSColin Finck  * @catal:  a Catalog
2949c2c66affSColin Finck  * @type:  the type of record to add to the catalog
2950c2c66affSColin Finck  * @orig:  the system, public or prefix to match
2951c2c66affSColin Finck  * @replace:  the replacement value for the match
2952c2c66affSColin Finck  *
2953c2c66affSColin Finck  * Add an entry in the catalog, it may overwrite existing but
2954c2c66affSColin Finck  * different entries.
2955c2c66affSColin Finck  *
2956c2c66affSColin Finck  * Returns 0 if successful, -1 otherwise
2957c2c66affSColin Finck  */
2958c2c66affSColin Finck int
2959c2c66affSColin Finck xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2960c2c66affSColin Finck               const xmlChar * orig, const xmlChar * replace)
2961c2c66affSColin Finck {
2962c2c66affSColin Finck     int res = -1;
2963c2c66affSColin Finck 
2964c2c66affSColin Finck     if (catal == NULL)
2965c2c66affSColin Finck 	return(-1);
2966c2c66affSColin Finck 
2967c2c66affSColin Finck     if (catal->type == XML_XML_CATALOG_TYPE) {
2968c2c66affSColin Finck         res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2969c2c66affSColin Finck     } else {
2970c2c66affSColin Finck         xmlCatalogEntryType cattype;
2971c2c66affSColin Finck 
2972c2c66affSColin Finck         cattype = xmlGetSGMLCatalogEntryType(type);
2973c2c66affSColin Finck         if (cattype != XML_CATA_NONE) {
2974c2c66affSColin Finck             xmlCatalogEntryPtr entry;
2975c2c66affSColin Finck 
2976c2c66affSColin Finck             entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
2977c2c66affSColin Finck                                        XML_CATA_PREFER_NONE, NULL);
2978c2c66affSColin Finck 	    if (catal->sgml == NULL)
2979c2c66affSColin Finck 		catal->sgml = xmlHashCreate(10);
2980c2c66affSColin Finck             res = xmlHashAddEntry(catal->sgml, orig, entry);
2981c2c66affSColin Finck         }
2982c2c66affSColin Finck     }
2983c2c66affSColin Finck     return (res);
2984c2c66affSColin Finck }
2985c2c66affSColin Finck 
2986c2c66affSColin Finck /**
2987c2c66affSColin Finck  * xmlACatalogRemove:
2988c2c66affSColin Finck  * @catal:  a Catalog
2989c2c66affSColin Finck  * @value:  the value to remove
2990c2c66affSColin Finck  *
2991c2c66affSColin Finck  * Remove an entry from the catalog
2992c2c66affSColin Finck  *
2993c2c66affSColin Finck  * Returns the number of entries removed if successful, -1 otherwise
2994c2c66affSColin Finck  */
2995c2c66affSColin Finck int
2996c2c66affSColin Finck xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2997c2c66affSColin Finck     int res = -1;
2998c2c66affSColin Finck 
2999c2c66affSColin Finck     if ((catal == NULL) || (value == NULL))
3000c2c66affSColin Finck 	return(-1);
3001c2c66affSColin Finck 
3002c2c66affSColin Finck     if (catal->type == XML_XML_CATALOG_TYPE) {
3003c2c66affSColin Finck 	res = xmlDelXMLCatalog(catal->xml, value);
3004c2c66affSColin Finck     } else {
3005c2c66affSColin Finck 	res = xmlHashRemoveEntry(catal->sgml, value,
3006c2c66affSColin Finck 		(xmlHashDeallocator) xmlFreeCatalogEntry);
3007c2c66affSColin Finck 	if (res == 0)
3008c2c66affSColin Finck 	    res = 1;
3009c2c66affSColin Finck     }
3010c2c66affSColin Finck     return(res);
3011c2c66affSColin Finck }
3012c2c66affSColin Finck 
3013c2c66affSColin Finck /**
3014c2c66affSColin Finck  * xmlNewCatalog:
3015c2c66affSColin Finck  * @sgml:  should this create an SGML catalog
3016c2c66affSColin Finck  *
3017c2c66affSColin Finck  * create a new Catalog.
3018c2c66affSColin Finck  *
3019c2c66affSColin Finck  * Returns the xmlCatalogPtr or NULL in case of error
3020c2c66affSColin Finck  */
3021c2c66affSColin Finck xmlCatalogPtr
3022c2c66affSColin Finck xmlNewCatalog(int sgml) {
3023c2c66affSColin Finck     xmlCatalogPtr catal = NULL;
3024c2c66affSColin Finck 
3025c2c66affSColin Finck     if (sgml) {
3026c2c66affSColin Finck 	catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3027c2c66affSColin Finck 		                    xmlCatalogDefaultPrefer);
3028c2c66affSColin Finck         if ((catal != NULL) && (catal->sgml == NULL))
3029c2c66affSColin Finck 	    catal->sgml = xmlHashCreate(10);
3030c2c66affSColin Finck     } else
3031c2c66affSColin Finck 	catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3032c2c66affSColin Finck 		                    xmlCatalogDefaultPrefer);
3033c2c66affSColin Finck     return(catal);
3034c2c66affSColin Finck }
3035c2c66affSColin Finck 
3036c2c66affSColin Finck /**
3037c2c66affSColin Finck  * xmlCatalogIsEmpty:
3038c2c66affSColin Finck  * @catal:  should this create an SGML catalog
3039c2c66affSColin Finck  *
3040c2c66affSColin Finck  * Check is a catalog is empty
3041c2c66affSColin Finck  *
3042c2c66affSColin Finck  * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3043c2c66affSColin Finck  */
3044c2c66affSColin Finck int
3045c2c66affSColin Finck xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3046c2c66affSColin Finck     if (catal == NULL)
3047c2c66affSColin Finck 	return(-1);
3048c2c66affSColin Finck 
3049c2c66affSColin Finck     if (catal->type == XML_XML_CATALOG_TYPE) {
3050c2c66affSColin Finck 	if (catal->xml == NULL)
3051c2c66affSColin Finck 	    return(1);
3052c2c66affSColin Finck 	if ((catal->xml->type != XML_CATA_CATALOG) &&
3053c2c66affSColin Finck 	    (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3054c2c66affSColin Finck 	    return(-1);
3055c2c66affSColin Finck 	if (catal->xml->children == NULL)
3056c2c66affSColin Finck 	    return(1);
3057c2c66affSColin Finck         return(0);
3058c2c66affSColin Finck     } else {
3059c2c66affSColin Finck 	int res;
3060c2c66affSColin Finck 
3061c2c66affSColin Finck 	if (catal->sgml == NULL)
3062c2c66affSColin Finck 	    return(1);
3063c2c66affSColin Finck 	res = xmlHashSize(catal->sgml);
3064c2c66affSColin Finck 	if (res == 0)
3065c2c66affSColin Finck 	    return(1);
3066c2c66affSColin Finck 	if (res < 0)
3067c2c66affSColin Finck 	    return(-1);
3068c2c66affSColin Finck     }
3069c2c66affSColin Finck     return(0);
3070c2c66affSColin Finck }
3071c2c66affSColin Finck 
3072c2c66affSColin Finck /************************************************************************
3073c2c66affSColin Finck  *									*
3074c2c66affSColin Finck  *   Public interfaces manipulating the global shared default catalog	*
3075c2c66affSColin Finck  *									*
3076c2c66affSColin Finck  ************************************************************************/
3077c2c66affSColin Finck 
3078c2c66affSColin Finck /**
3079c2c66affSColin Finck  * xmlInitializeCatalogData:
3080c2c66affSColin Finck  *
3081c2c66affSColin Finck  * Do the catalog initialization only of global data, doesn't try to load
3082c2c66affSColin Finck  * any catalog actually.
3083c2c66affSColin Finck  * this function is not thread safe, catalog initialization should
3084c2c66affSColin Finck  * preferably be done once at startup
3085c2c66affSColin Finck  */
3086c2c66affSColin Finck static void
3087c2c66affSColin Finck xmlInitializeCatalogData(void) {
3088c2c66affSColin Finck     if (xmlCatalogInitialized != 0)
3089c2c66affSColin Finck 	return;
3090c2c66affSColin Finck 
3091c2c66affSColin Finck     if (getenv("XML_DEBUG_CATALOG"))
3092c2c66affSColin Finck 	xmlDebugCatalogs = 1;
3093c2c66affSColin Finck     xmlCatalogMutex = xmlNewRMutex();
3094c2c66affSColin Finck 
3095c2c66affSColin Finck     xmlCatalogInitialized = 1;
3096c2c66affSColin Finck }
3097c2c66affSColin Finck /**
3098c2c66affSColin Finck  * xmlInitializeCatalog:
3099c2c66affSColin Finck  *
3100c2c66affSColin Finck  * Do the catalog initialization.
3101c2c66affSColin Finck  * this function is not thread safe, catalog initialization should
3102c2c66affSColin Finck  * preferably be done once at startup
3103c2c66affSColin Finck  */
3104c2c66affSColin Finck void
3105c2c66affSColin Finck xmlInitializeCatalog(void) {
3106c2c66affSColin Finck     if (xmlCatalogInitialized != 0)
3107c2c66affSColin Finck 	return;
3108c2c66affSColin Finck 
3109c2c66affSColin Finck     xmlInitializeCatalogData();
3110c2c66affSColin Finck     xmlRMutexLock(xmlCatalogMutex);
3111c2c66affSColin Finck 
3112c2c66affSColin Finck     if (getenv("XML_DEBUG_CATALOG"))
3113c2c66affSColin Finck 	xmlDebugCatalogs = 1;
3114c2c66affSColin Finck 
3115c2c66affSColin Finck     if (xmlDefaultCatalog == NULL) {
3116c2c66affSColin Finck 	const char *catalogs;
3117c2c66affSColin Finck 	char *path;
3118c2c66affSColin Finck 	const char *cur, *paths;
3119c2c66affSColin Finck 	xmlCatalogPtr catal;
3120c2c66affSColin Finck 	xmlCatalogEntryPtr *nextent;
3121c2c66affSColin Finck 
3122c2c66affSColin Finck 	catalogs = (const char *) getenv("XML_CATALOG_FILES");
3123c2c66affSColin Finck 	if (catalogs == NULL)
3124c2c66affSColin Finck #if defined(_WIN32) && defined(_MSC_VER)
3125c2c66affSColin Finck     {
3126c2c66affSColin Finck 		void* hmodule;
3127c2c66affSColin Finck 		hmodule = GetModuleHandleA("libxml2.dll");
3128c2c66affSColin Finck 		if (hmodule == NULL)
3129c2c66affSColin Finck 			hmodule = GetModuleHandleA(NULL);
3130c2c66affSColin Finck 		if (hmodule != NULL) {
3131c2c66affSColin Finck 			char buf[256];
3132c2c66affSColin Finck 			unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3133c2c66affSColin Finck 			if (len != 0) {
3134c2c66affSColin Finck 				char* p = &(buf[len]);
3135c2c66affSColin Finck 				while (*p != '\\' && p > buf)
3136c2c66affSColin Finck 					p--;
3137c2c66affSColin Finck 				if (p != buf) {
3138c2c66affSColin Finck 					xmlChar* uri;
3139c2c66affSColin Finck 					strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3140c2c66affSColin Finck 					uri = xmlCanonicPath((const xmlChar*)buf);
3141c2c66affSColin Finck 					if (uri != NULL) {
3142c2c66affSColin Finck 						strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3143c2c66affSColin Finck 						xmlFree(uri);
3144c2c66affSColin Finck 					}
3145c2c66affSColin Finck 				}
3146c2c66affSColin Finck 			}
3147c2c66affSColin Finck 		}
3148c2c66affSColin Finck 		catalogs = XML_XML_DEFAULT_CATALOG;
3149c2c66affSColin Finck     }
3150c2c66affSColin Finck #else
3151c2c66affSColin Finck 	    catalogs = XML_XML_DEFAULT_CATALOG;
3152c2c66affSColin Finck #endif
3153c2c66affSColin Finck 
3154c2c66affSColin Finck 	catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3155c2c66affSColin Finck 		xmlCatalogDefaultPrefer);
3156c2c66affSColin Finck 	if (catal != NULL) {
3157c2c66affSColin Finck 	    /* the XML_CATALOG_FILES envvar is allowed to contain a
3158c2c66affSColin Finck 	       space-separated list of entries. */
3159c2c66affSColin Finck 	    cur = catalogs;
3160c2c66affSColin Finck 	    nextent = &catal->xml;
3161c2c66affSColin Finck 	    while (*cur != '\0') {
3162c2c66affSColin Finck 		while (xmlIsBlank_ch(*cur))
3163c2c66affSColin Finck 		    cur++;
3164c2c66affSColin Finck 		if (*cur != 0) {
3165c2c66affSColin Finck 		    paths = cur;
3166c2c66affSColin Finck 		    while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
3167c2c66affSColin Finck 			cur++;
3168c2c66affSColin Finck 		    path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
3169c2c66affSColin Finck 		    if (path != NULL) {
3170c2c66affSColin Finck 			*nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3171c2c66affSColin Finck 				NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
3172c2c66affSColin Finck 			if (*nextent != NULL)
3173c2c66affSColin Finck 			    nextent = &((*nextent)->next);
3174c2c66affSColin Finck 			xmlFree(path);
3175c2c66affSColin Finck 		    }
3176c2c66affSColin Finck 		}
3177c2c66affSColin Finck 	    }
3178c2c66affSColin Finck 	    xmlDefaultCatalog = catal;
3179c2c66affSColin Finck 	}
3180c2c66affSColin Finck     }
3181c2c66affSColin Finck 
3182c2c66affSColin Finck     xmlRMutexUnlock(xmlCatalogMutex);
3183c2c66affSColin Finck }
3184c2c66affSColin Finck 
3185c2c66affSColin Finck 
3186c2c66affSColin Finck /**
3187c2c66affSColin Finck  * xmlLoadCatalog:
3188c2c66affSColin Finck  * @filename:  a file path
3189c2c66affSColin Finck  *
3190c2c66affSColin Finck  * Load the catalog and makes its definitions effective for the default
3191c2c66affSColin Finck  * external entity loader. It will recurse in SGML CATALOG entries.
3192c2c66affSColin Finck  * this function is not thread safe, catalog initialization should
3193c2c66affSColin Finck  * preferably be done once at startup
3194c2c66affSColin Finck  *
3195c2c66affSColin Finck  * Returns 0 in case of success -1 in case of error
3196c2c66affSColin Finck  */
3197c2c66affSColin Finck int
3198c2c66affSColin Finck xmlLoadCatalog(const char *filename)
3199c2c66affSColin Finck {
3200c2c66affSColin Finck     int ret;
3201c2c66affSColin Finck     xmlCatalogPtr catal;
3202c2c66affSColin Finck 
3203c2c66affSColin Finck     if (!xmlCatalogInitialized)
3204c2c66affSColin Finck 	xmlInitializeCatalogData();
3205c2c66affSColin Finck 
3206c2c66affSColin Finck     xmlRMutexLock(xmlCatalogMutex);
3207c2c66affSColin Finck 
3208c2c66affSColin Finck     if (xmlDefaultCatalog == NULL) {
3209c2c66affSColin Finck 	catal = xmlLoadACatalog(filename);
3210c2c66affSColin Finck 	if (catal == NULL) {
3211c2c66affSColin Finck 	    xmlRMutexUnlock(xmlCatalogMutex);
3212c2c66affSColin Finck 	    return(-1);
3213c2c66affSColin Finck 	}
3214c2c66affSColin Finck 
3215c2c66affSColin Finck 	xmlDefaultCatalog = catal;
3216c2c66affSColin Finck 	xmlRMutexUnlock(xmlCatalogMutex);
3217c2c66affSColin Finck 	return(0);
3218c2c66affSColin Finck     }
3219c2c66affSColin Finck 
3220c2c66affSColin Finck     ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
3221c2c66affSColin Finck     xmlRMutexUnlock(xmlCatalogMutex);
3222c2c66affSColin Finck     return(ret);
3223c2c66affSColin Finck }
3224c2c66affSColin Finck 
3225c2c66affSColin Finck /**
3226c2c66affSColin Finck  * xmlLoadCatalogs:
3227c2c66affSColin Finck  * @pathss:  a list of directories separated by a colon or a space.
3228c2c66affSColin Finck  *
3229c2c66affSColin Finck  * Load the catalogs and makes their definitions effective for the default
3230c2c66affSColin Finck  * external entity loader.
3231c2c66affSColin Finck  * this function is not thread safe, catalog initialization should
3232c2c66affSColin Finck  * preferably be done once at startup
3233c2c66affSColin Finck  */
3234c2c66affSColin Finck void
3235c2c66affSColin Finck xmlLoadCatalogs(const char *pathss) {
3236c2c66affSColin Finck     const char *cur;
3237c2c66affSColin Finck     const char *paths;
3238c2c66affSColin Finck     xmlChar *path;
3239c2c66affSColin Finck #ifdef _WIN32
3240c2c66affSColin Finck     int i, iLen;
3241c2c66affSColin Finck #endif
3242c2c66affSColin Finck 
3243c2c66affSColin Finck     if (pathss == NULL)
3244c2c66affSColin Finck 	return;
3245c2c66affSColin Finck 
3246c2c66affSColin Finck     cur = pathss;
3247c2c66affSColin Finck     while (*cur != 0) {
3248c2c66affSColin Finck 	while (xmlIsBlank_ch(*cur)) cur++;
3249c2c66affSColin Finck 	if (*cur != 0) {
3250c2c66affSColin Finck 	    paths = cur;
3251c2c66affSColin Finck 	    while ((*cur != 0) && (*cur != PATH_SEPARATOR) && (!xmlIsBlank_ch(*cur)))
3252c2c66affSColin Finck 		cur++;
3253c2c66affSColin Finck 	    path = xmlStrndup((const xmlChar *)paths, cur - paths);
3254c2c66affSColin Finck #ifdef _WIN32
3255c2c66affSColin Finck         iLen = strlen((const char*)path);
3256c2c66affSColin Finck         for(i = 0; i < iLen; i++) {
3257c2c66affSColin Finck             if(path[i] == '\\') {
3258c2c66affSColin Finck                 path[i] = '/';
3259c2c66affSColin Finck             }
3260c2c66affSColin Finck         }
3261c2c66affSColin Finck #endif
3262c2c66affSColin Finck 	    if (path != NULL) {
3263c2c66affSColin Finck 		xmlLoadCatalog((const char *) path);
3264c2c66affSColin Finck 		xmlFree(path);
3265c2c66affSColin Finck 	    }
3266c2c66affSColin Finck 	}
3267c2c66affSColin Finck 	while (*cur == PATH_SEPARATOR)
3268c2c66affSColin Finck 	    cur++;
3269c2c66affSColin Finck     }
3270c2c66affSColin Finck }
3271c2c66affSColin Finck 
3272c2c66affSColin Finck /**
3273c2c66affSColin Finck  * xmlCatalogCleanup:
3274c2c66affSColin Finck  *
3275c2c66affSColin Finck  * Free up all the memory associated with catalogs
3276c2c66affSColin Finck  */
3277c2c66affSColin Finck void
3278c2c66affSColin Finck xmlCatalogCleanup(void) {
3279c2c66affSColin Finck     if (xmlCatalogInitialized == 0)
3280c2c66affSColin Finck         return;
3281c2c66affSColin Finck 
3282c2c66affSColin Finck     xmlRMutexLock(xmlCatalogMutex);
3283c2c66affSColin Finck     if (xmlDebugCatalogs)
3284c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
3285c2c66affSColin Finck 		"Catalogs cleanup\n");
3286c2c66affSColin Finck     if (xmlCatalogXMLFiles != NULL)
3287c2c66affSColin Finck 	xmlHashFree(xmlCatalogXMLFiles,
3288c2c66affSColin Finck 		    (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
3289c2c66affSColin Finck     xmlCatalogXMLFiles = NULL;
3290c2c66affSColin Finck     if (xmlDefaultCatalog != NULL)
3291c2c66affSColin Finck 	xmlFreeCatalog(xmlDefaultCatalog);
3292c2c66affSColin Finck     xmlDefaultCatalog = NULL;
3293c2c66affSColin Finck     xmlDebugCatalogs = 0;
3294c2c66affSColin Finck     xmlCatalogInitialized = 0;
3295c2c66affSColin Finck     xmlRMutexUnlock(xmlCatalogMutex);
3296c2c66affSColin Finck     xmlFreeRMutex(xmlCatalogMutex);
3297c2c66affSColin Finck }
3298c2c66affSColin Finck 
3299c2c66affSColin Finck /**
3300c2c66affSColin Finck  * xmlCatalogResolveSystem:
3301c2c66affSColin Finck  * @sysID:  the system ID string
3302c2c66affSColin Finck  *
3303c2c66affSColin Finck  * Try to lookup the catalog resource for a system ID
3304c2c66affSColin Finck  *
3305c2c66affSColin Finck  * Returns the resource if found or NULL otherwise, the value returned
3306c2c66affSColin Finck  *      must be freed by the caller.
3307c2c66affSColin Finck  */
3308c2c66affSColin Finck xmlChar *
3309c2c66affSColin Finck xmlCatalogResolveSystem(const xmlChar *sysID) {
3310c2c66affSColin Finck     xmlChar *ret;
3311c2c66affSColin Finck 
3312c2c66affSColin Finck     if (!xmlCatalogInitialized)
3313c2c66affSColin Finck 	xmlInitializeCatalog();
3314c2c66affSColin Finck 
3315c2c66affSColin Finck     ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3316c2c66affSColin Finck     return(ret);
3317c2c66affSColin Finck }
3318c2c66affSColin Finck 
3319c2c66affSColin Finck /**
3320c2c66affSColin Finck  * xmlCatalogResolvePublic:
3321c2c66affSColin Finck  * @pubID:  the public ID string
3322c2c66affSColin Finck  *
3323c2c66affSColin Finck  * Try to lookup the catalog reference associated to a public ID
3324c2c66affSColin Finck  *
3325c2c66affSColin Finck  * Returns the resource if found or NULL otherwise, the value returned
3326c2c66affSColin Finck  *      must be freed by the caller.
3327c2c66affSColin Finck  */
3328c2c66affSColin Finck xmlChar *
3329c2c66affSColin Finck xmlCatalogResolvePublic(const xmlChar *pubID) {
3330c2c66affSColin Finck     xmlChar *ret;
3331c2c66affSColin Finck 
3332c2c66affSColin Finck     if (!xmlCatalogInitialized)
3333c2c66affSColin Finck 	xmlInitializeCatalog();
3334c2c66affSColin Finck 
3335c2c66affSColin Finck     ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3336c2c66affSColin Finck     return(ret);
3337c2c66affSColin Finck }
3338c2c66affSColin Finck 
3339c2c66affSColin Finck /**
3340c2c66affSColin Finck  * xmlCatalogResolve:
3341c2c66affSColin Finck  * @pubID:  the public ID string
3342c2c66affSColin Finck  * @sysID:  the system ID string
3343c2c66affSColin Finck  *
3344c2c66affSColin Finck  * Do a complete resolution lookup of an External Identifier
3345c2c66affSColin Finck  *
3346c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found, it must be freed
3347c2c66affSColin Finck  *      by the caller.
3348c2c66affSColin Finck  */
3349c2c66affSColin Finck xmlChar *
3350c2c66affSColin Finck xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
3351c2c66affSColin Finck     xmlChar *ret;
3352c2c66affSColin Finck 
3353c2c66affSColin Finck     if (!xmlCatalogInitialized)
3354c2c66affSColin Finck 	xmlInitializeCatalog();
3355c2c66affSColin Finck 
3356c2c66affSColin Finck     ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3357c2c66affSColin Finck     return(ret);
3358c2c66affSColin Finck }
3359c2c66affSColin Finck 
3360c2c66affSColin Finck /**
3361c2c66affSColin Finck  * xmlCatalogResolveURI:
3362c2c66affSColin Finck  * @URI:  the URI
3363c2c66affSColin Finck  *
3364c2c66affSColin Finck  * Do a complete resolution lookup of an URI
3365c2c66affSColin Finck  *
3366c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found, it must be freed
3367c2c66affSColin Finck  *      by the caller.
3368c2c66affSColin Finck  */
3369c2c66affSColin Finck xmlChar *
3370c2c66affSColin Finck xmlCatalogResolveURI(const xmlChar *URI) {
3371c2c66affSColin Finck     xmlChar *ret;
3372c2c66affSColin Finck 
3373c2c66affSColin Finck     if (!xmlCatalogInitialized)
3374c2c66affSColin Finck 	xmlInitializeCatalog();
3375c2c66affSColin Finck 
3376c2c66affSColin Finck     ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3377c2c66affSColin Finck     return(ret);
3378c2c66affSColin Finck }
3379c2c66affSColin Finck 
3380c2c66affSColin Finck #ifdef LIBXML_OUTPUT_ENABLED
3381c2c66affSColin Finck /**
3382c2c66affSColin Finck  * xmlCatalogDump:
3383c2c66affSColin Finck  * @out:  the file.
3384c2c66affSColin Finck  *
3385c2c66affSColin Finck  * Dump all the global catalog content to the given file.
3386c2c66affSColin Finck  */
3387c2c66affSColin Finck void
3388c2c66affSColin Finck xmlCatalogDump(FILE *out) {
3389c2c66affSColin Finck     if (out == NULL)
3390c2c66affSColin Finck 	return;
3391c2c66affSColin Finck 
3392c2c66affSColin Finck     if (!xmlCatalogInitialized)
3393c2c66affSColin Finck 	xmlInitializeCatalog();
3394c2c66affSColin Finck 
3395c2c66affSColin Finck     xmlACatalogDump(xmlDefaultCatalog, out);
3396c2c66affSColin Finck }
3397c2c66affSColin Finck #endif /* LIBXML_OUTPUT_ENABLED */
3398c2c66affSColin Finck 
3399c2c66affSColin Finck /**
3400c2c66affSColin Finck  * xmlCatalogAdd:
3401c2c66affSColin Finck  * @type:  the type of record to add to the catalog
3402c2c66affSColin Finck  * @orig:  the system, public or prefix to match
3403c2c66affSColin Finck  * @replace:  the replacement value for the match
3404c2c66affSColin Finck  *
3405c2c66affSColin Finck  * Add an entry in the catalog, it may overwrite existing but
3406c2c66affSColin Finck  * different entries.
3407c2c66affSColin Finck  * If called before any other catalog routine, allows to override the
3408c2c66affSColin Finck  * default shared catalog put in place by xmlInitializeCatalog();
3409c2c66affSColin Finck  *
3410c2c66affSColin Finck  * Returns 0 if successful, -1 otherwise
3411c2c66affSColin Finck  */
3412c2c66affSColin Finck int
3413c2c66affSColin Finck xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3414c2c66affSColin Finck     int res = -1;
3415c2c66affSColin Finck 
3416c2c66affSColin Finck     if (!xmlCatalogInitialized)
3417c2c66affSColin Finck 	xmlInitializeCatalogData();
3418c2c66affSColin Finck 
3419c2c66affSColin Finck     xmlRMutexLock(xmlCatalogMutex);
3420c2c66affSColin Finck     /*
3421c2c66affSColin Finck      * Specific case where one want to override the default catalog
3422c2c66affSColin Finck      * put in place by xmlInitializeCatalog();
3423c2c66affSColin Finck      */
3424c2c66affSColin Finck     if ((xmlDefaultCatalog == NULL) &&
3425c2c66affSColin Finck 	(xmlStrEqual(type, BAD_CAST "catalog"))) {
3426c2c66affSColin Finck 	xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3427c2c66affSColin Finck 		                          xmlCatalogDefaultPrefer);
3428c2c66affSColin Finck 	xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3429c2c66affSColin Finck 				    orig, NULL,  xmlCatalogDefaultPrefer, NULL);
3430c2c66affSColin Finck 
3431c2c66affSColin Finck 	xmlRMutexUnlock(xmlCatalogMutex);
3432c2c66affSColin Finck 	return(0);
3433c2c66affSColin Finck     }
3434c2c66affSColin Finck 
3435c2c66affSColin Finck     res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
3436c2c66affSColin Finck     xmlRMutexUnlock(xmlCatalogMutex);
3437c2c66affSColin Finck     return(res);
3438c2c66affSColin Finck }
3439c2c66affSColin Finck 
3440c2c66affSColin Finck /**
3441c2c66affSColin Finck  * xmlCatalogRemove:
3442c2c66affSColin Finck  * @value:  the value to remove
3443c2c66affSColin Finck  *
3444c2c66affSColin Finck  * Remove an entry from the catalog
3445c2c66affSColin Finck  *
3446c2c66affSColin Finck  * Returns the number of entries removed if successful, -1 otherwise
3447c2c66affSColin Finck  */
3448c2c66affSColin Finck int
3449c2c66affSColin Finck xmlCatalogRemove(const xmlChar *value) {
3450c2c66affSColin Finck     int res;
3451c2c66affSColin Finck 
3452c2c66affSColin Finck     if (!xmlCatalogInitialized)
3453c2c66affSColin Finck 	xmlInitializeCatalog();
3454c2c66affSColin Finck 
3455c2c66affSColin Finck     xmlRMutexLock(xmlCatalogMutex);
3456c2c66affSColin Finck     res = xmlACatalogRemove(xmlDefaultCatalog, value);
3457c2c66affSColin Finck     xmlRMutexUnlock(xmlCatalogMutex);
3458c2c66affSColin Finck     return(res);
3459c2c66affSColin Finck }
3460c2c66affSColin Finck 
3461c2c66affSColin Finck /**
3462c2c66affSColin Finck  * xmlCatalogConvert:
3463c2c66affSColin Finck  *
3464c2c66affSColin Finck  * Convert all the SGML catalog entries as XML ones
3465c2c66affSColin Finck  *
3466c2c66affSColin Finck  * Returns the number of entries converted if successful, -1 otherwise
3467c2c66affSColin Finck  */
3468c2c66affSColin Finck int
3469c2c66affSColin Finck xmlCatalogConvert(void) {
3470c2c66affSColin Finck     int res = -1;
3471c2c66affSColin Finck 
3472c2c66affSColin Finck     if (!xmlCatalogInitialized)
3473c2c66affSColin Finck 	xmlInitializeCatalog();
3474c2c66affSColin Finck 
3475c2c66affSColin Finck     xmlRMutexLock(xmlCatalogMutex);
3476c2c66affSColin Finck     res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
3477c2c66affSColin Finck     xmlRMutexUnlock(xmlCatalogMutex);
3478c2c66affSColin Finck     return(res);
3479c2c66affSColin Finck }
3480c2c66affSColin Finck 
3481c2c66affSColin Finck /************************************************************************
3482c2c66affSColin Finck  *									*
3483c2c66affSColin Finck  *	Public interface manipulating the common preferences		*
3484c2c66affSColin Finck  *									*
3485c2c66affSColin Finck  ************************************************************************/
3486c2c66affSColin Finck 
3487c2c66affSColin Finck /**
3488c2c66affSColin Finck  * xmlCatalogGetDefaults:
3489c2c66affSColin Finck  *
3490c2c66affSColin Finck  * Used to get the user preference w.r.t. to what catalogs should
3491c2c66affSColin Finck  * be accepted
3492c2c66affSColin Finck  *
3493c2c66affSColin Finck  * Returns the current xmlCatalogAllow value
3494c2c66affSColin Finck  */
3495c2c66affSColin Finck xmlCatalogAllow
3496c2c66affSColin Finck xmlCatalogGetDefaults(void) {
3497c2c66affSColin Finck     return(xmlCatalogDefaultAllow);
3498c2c66affSColin Finck }
3499c2c66affSColin Finck 
3500c2c66affSColin Finck /**
3501c2c66affSColin Finck  * xmlCatalogSetDefaults:
3502c2c66affSColin Finck  * @allow:  what catalogs should be accepted
3503c2c66affSColin Finck  *
3504c2c66affSColin Finck  * Used to set the user preference w.r.t. to what catalogs should
3505c2c66affSColin Finck  * be accepted
3506c2c66affSColin Finck  */
3507c2c66affSColin Finck void
3508c2c66affSColin Finck xmlCatalogSetDefaults(xmlCatalogAllow allow) {
3509c2c66affSColin Finck     if (xmlDebugCatalogs) {
3510c2c66affSColin Finck 	switch (allow) {
3511c2c66affSColin Finck 	    case XML_CATA_ALLOW_NONE:
3512c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
3513c2c66affSColin Finck 			"Disabling catalog usage\n");
3514c2c66affSColin Finck 		break;
3515c2c66affSColin Finck 	    case XML_CATA_ALLOW_GLOBAL:
3516c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
3517c2c66affSColin Finck 			"Allowing only global catalogs\n");
3518c2c66affSColin Finck 		break;
3519c2c66affSColin Finck 	    case XML_CATA_ALLOW_DOCUMENT:
3520c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
3521c2c66affSColin Finck 			"Allowing only catalogs from the document\n");
3522c2c66affSColin Finck 		break;
3523c2c66affSColin Finck 	    case XML_CATA_ALLOW_ALL:
3524c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
3525c2c66affSColin Finck 			"Allowing all catalogs\n");
3526c2c66affSColin Finck 		break;
3527c2c66affSColin Finck 	}
3528c2c66affSColin Finck     }
3529c2c66affSColin Finck     xmlCatalogDefaultAllow = allow;
3530c2c66affSColin Finck }
3531c2c66affSColin Finck 
3532c2c66affSColin Finck /**
3533c2c66affSColin Finck  * xmlCatalogSetDefaultPrefer:
3534c2c66affSColin Finck  * @prefer:  the default preference for delegation
3535c2c66affSColin Finck  *
3536c2c66affSColin Finck  * Allows to set the preference between public and system for deletion
3537c2c66affSColin Finck  * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3538c2c66affSColin Finck  * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3539c2c66affSColin Finck  *
3540c2c66affSColin Finck  * Returns the previous value of the default preference for delegation
3541c2c66affSColin Finck  */
3542c2c66affSColin Finck xmlCatalogPrefer
3543c2c66affSColin Finck xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3544c2c66affSColin Finck     xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3545c2c66affSColin Finck 
3546c2c66affSColin Finck     if (prefer == XML_CATA_PREFER_NONE)
3547c2c66affSColin Finck 	return(ret);
3548c2c66affSColin Finck 
3549c2c66affSColin Finck     if (xmlDebugCatalogs) {
3550c2c66affSColin Finck 	switch (prefer) {
3551c2c66affSColin Finck 	    case XML_CATA_PREFER_PUBLIC:
3552c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
3553c2c66affSColin Finck 			"Setting catalog preference to PUBLIC\n");
3554c2c66affSColin Finck 		break;
3555c2c66affSColin Finck 	    case XML_CATA_PREFER_SYSTEM:
3556c2c66affSColin Finck 		xmlGenericError(xmlGenericErrorContext,
3557c2c66affSColin Finck 			"Setting catalog preference to SYSTEM\n");
3558c2c66affSColin Finck 		break;
3559c2c66affSColin Finck 	    default:
3560c2c66affSColin Finck 		return(ret);
3561c2c66affSColin Finck 	}
3562c2c66affSColin Finck     }
3563c2c66affSColin Finck     xmlCatalogDefaultPrefer = prefer;
3564c2c66affSColin Finck     return(ret);
3565c2c66affSColin Finck }
3566c2c66affSColin Finck 
3567c2c66affSColin Finck /**
3568c2c66affSColin Finck  * xmlCatalogSetDebug:
3569c2c66affSColin Finck  * @level:  the debug level of catalogs required
3570c2c66affSColin Finck  *
3571c2c66affSColin Finck  * Used to set the debug level for catalog operation, 0 disable
3572c2c66affSColin Finck  * debugging, 1 enable it
3573c2c66affSColin Finck  *
3574c2c66affSColin Finck  * Returns the previous value of the catalog debugging level
3575c2c66affSColin Finck  */
3576c2c66affSColin Finck int
3577c2c66affSColin Finck xmlCatalogSetDebug(int level) {
3578c2c66affSColin Finck     int ret = xmlDebugCatalogs;
3579c2c66affSColin Finck 
3580c2c66affSColin Finck     if (level <= 0)
3581c2c66affSColin Finck         xmlDebugCatalogs = 0;
3582c2c66affSColin Finck     else
3583c2c66affSColin Finck 	xmlDebugCatalogs = level;
3584c2c66affSColin Finck     return(ret);
3585c2c66affSColin Finck }
3586c2c66affSColin Finck 
3587c2c66affSColin Finck /************************************************************************
3588c2c66affSColin Finck  *									*
3589c2c66affSColin Finck  *   Minimal interfaces used for per-document catalogs by the parser	*
3590c2c66affSColin Finck  *									*
3591c2c66affSColin Finck  ************************************************************************/
3592c2c66affSColin Finck 
3593c2c66affSColin Finck /**
3594c2c66affSColin Finck  * xmlCatalogFreeLocal:
3595c2c66affSColin Finck  * @catalogs:  a document's list of catalogs
3596c2c66affSColin Finck  *
3597c2c66affSColin Finck  * Free up the memory associated to the catalog list
3598c2c66affSColin Finck  */
3599c2c66affSColin Finck void
3600c2c66affSColin Finck xmlCatalogFreeLocal(void *catalogs) {
3601c2c66affSColin Finck     xmlCatalogEntryPtr catal;
3602c2c66affSColin Finck 
3603c2c66affSColin Finck     if (!xmlCatalogInitialized)
3604c2c66affSColin Finck 	xmlInitializeCatalog();
3605c2c66affSColin Finck 
3606c2c66affSColin Finck     catal = (xmlCatalogEntryPtr) catalogs;
3607c2c66affSColin Finck     if (catal != NULL)
3608c2c66affSColin Finck 	xmlFreeCatalogEntryList(catal);
3609c2c66affSColin Finck }
3610c2c66affSColin Finck 
3611c2c66affSColin Finck 
3612c2c66affSColin Finck /**
3613c2c66affSColin Finck  * xmlCatalogAddLocal:
3614c2c66affSColin Finck  * @catalogs:  a document's list of catalogs
3615c2c66affSColin Finck  * @URL:  the URL to a new local catalog
3616c2c66affSColin Finck  *
3617c2c66affSColin Finck  * Add the new entry to the catalog list
3618c2c66affSColin Finck  *
3619c2c66affSColin Finck  * Returns the updated list
3620c2c66affSColin Finck  */
3621c2c66affSColin Finck void *
3622c2c66affSColin Finck xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3623c2c66affSColin Finck     xmlCatalogEntryPtr catal, add;
3624c2c66affSColin Finck 
3625c2c66affSColin Finck     if (!xmlCatalogInitialized)
3626c2c66affSColin Finck 	xmlInitializeCatalog();
3627c2c66affSColin Finck 
3628c2c66affSColin Finck     if (URL == NULL)
3629c2c66affSColin Finck 	return(catalogs);
3630c2c66affSColin Finck 
3631c2c66affSColin Finck     if (xmlDebugCatalogs)
3632c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
3633c2c66affSColin Finck 		"Adding document catalog %s\n", URL);
3634c2c66affSColin Finck 
3635c2c66affSColin Finck     add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
3636c2c66affSColin Finck 	                     xmlCatalogDefaultPrefer, NULL);
3637c2c66affSColin Finck     if (add == NULL)
3638c2c66affSColin Finck 	return(catalogs);
3639c2c66affSColin Finck 
3640c2c66affSColin Finck     catal = (xmlCatalogEntryPtr) catalogs;
3641c2c66affSColin Finck     if (catal == NULL)
3642c2c66affSColin Finck 	return((void *) add);
3643c2c66affSColin Finck 
3644c2c66affSColin Finck     while (catal->next != NULL)
3645c2c66affSColin Finck 	catal = catal->next;
3646c2c66affSColin Finck     catal->next = add;
3647c2c66affSColin Finck     return(catalogs);
3648c2c66affSColin Finck }
3649c2c66affSColin Finck 
3650c2c66affSColin Finck /**
3651c2c66affSColin Finck  * xmlCatalogLocalResolve:
3652c2c66affSColin Finck  * @catalogs:  a document's list of catalogs
3653c2c66affSColin Finck  * @pubID:  the public ID string
3654c2c66affSColin Finck  * @sysID:  the system ID string
3655c2c66affSColin Finck  *
3656c2c66affSColin Finck  * Do a complete resolution lookup of an External Identifier using a
3657c2c66affSColin Finck  * document's private catalog list
3658c2c66affSColin Finck  *
3659c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found, it must be freed
3660c2c66affSColin Finck  *      by the caller.
3661c2c66affSColin Finck  */
3662c2c66affSColin Finck xmlChar *
3663c2c66affSColin Finck xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3664c2c66affSColin Finck 	               const xmlChar *sysID) {
3665c2c66affSColin Finck     xmlCatalogEntryPtr catal;
3666c2c66affSColin Finck     xmlChar *ret;
3667c2c66affSColin Finck 
3668c2c66affSColin Finck     if (!xmlCatalogInitialized)
3669c2c66affSColin Finck 	xmlInitializeCatalog();
3670c2c66affSColin Finck 
3671c2c66affSColin Finck     if ((pubID == NULL) && (sysID == NULL))
3672c2c66affSColin Finck 	return(NULL);
3673c2c66affSColin Finck 
3674c2c66affSColin Finck     if (xmlDebugCatalogs) {
3675c2c66affSColin Finck         if ((pubID != NULL) && (sysID != NULL)) {
3676c2c66affSColin Finck             xmlGenericError(xmlGenericErrorContext,
3677c2c66affSColin Finck                             "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3678c2c66affSColin Finck         } else if (pubID != NULL) {
3679c2c66affSColin Finck             xmlGenericError(xmlGenericErrorContext,
3680c2c66affSColin Finck                             "Local Resolve: pubID %s\n", pubID);
3681c2c66affSColin Finck         } else {
3682c2c66affSColin Finck             xmlGenericError(xmlGenericErrorContext,
3683c2c66affSColin Finck                             "Local Resolve: sysID %s\n", sysID);
3684c2c66affSColin Finck         }
3685c2c66affSColin Finck     }
3686c2c66affSColin Finck 
3687c2c66affSColin Finck     catal = (xmlCatalogEntryPtr) catalogs;
3688c2c66affSColin Finck     if (catal == NULL)
3689c2c66affSColin Finck 	return(NULL);
3690c2c66affSColin Finck     ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3691c2c66affSColin Finck     if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3692c2c66affSColin Finck 	return(ret);
3693c2c66affSColin Finck     return(NULL);
3694c2c66affSColin Finck }
3695c2c66affSColin Finck 
3696c2c66affSColin Finck /**
3697c2c66affSColin Finck  * xmlCatalogLocalResolveURI:
3698c2c66affSColin Finck  * @catalogs:  a document's list of catalogs
3699c2c66affSColin Finck  * @URI:  the URI
3700c2c66affSColin Finck  *
3701c2c66affSColin Finck  * Do a complete resolution lookup of an URI using a
3702c2c66affSColin Finck  * document's private catalog list
3703c2c66affSColin Finck  *
3704c2c66affSColin Finck  * Returns the URI of the resource or NULL if not found, it must be freed
3705c2c66affSColin Finck  *      by the caller.
3706c2c66affSColin Finck  */
3707c2c66affSColin Finck xmlChar *
3708c2c66affSColin Finck xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3709c2c66affSColin Finck     xmlCatalogEntryPtr catal;
3710c2c66affSColin Finck     xmlChar *ret;
3711c2c66affSColin Finck 
3712c2c66affSColin Finck     if (!xmlCatalogInitialized)
3713c2c66affSColin Finck 	xmlInitializeCatalog();
3714c2c66affSColin Finck 
3715c2c66affSColin Finck     if (URI == NULL)
3716c2c66affSColin Finck 	return(NULL);
3717c2c66affSColin Finck 
3718c2c66affSColin Finck     if (xmlDebugCatalogs)
3719c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
3720c2c66affSColin Finck 		"Resolve URI %s\n", URI);
3721c2c66affSColin Finck 
3722c2c66affSColin Finck     catal = (xmlCatalogEntryPtr) catalogs;
3723c2c66affSColin Finck     if (catal == NULL)
3724c2c66affSColin Finck 	return(NULL);
3725c2c66affSColin Finck     ret = xmlCatalogListXMLResolveURI(catal, URI);
3726c2c66affSColin Finck     if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3727c2c66affSColin Finck 	return(ret);
3728c2c66affSColin Finck     return(NULL);
3729c2c66affSColin Finck }
3730c2c66affSColin Finck 
3731c2c66affSColin Finck /************************************************************************
3732c2c66affSColin Finck  *									*
3733c2c66affSColin Finck  *			Deprecated interfaces				*
3734c2c66affSColin Finck  *									*
3735c2c66affSColin Finck  ************************************************************************/
3736c2c66affSColin Finck /**
3737c2c66affSColin Finck  * xmlCatalogGetSystem:
3738c2c66affSColin Finck  * @sysID:  the system ID string
3739c2c66affSColin Finck  *
3740c2c66affSColin Finck  * Try to lookup the catalog reference associated to a system ID
3741c2c66affSColin Finck  * DEPRECATED, use xmlCatalogResolveSystem()
3742c2c66affSColin Finck  *
3743c2c66affSColin Finck  * Returns the resource if found or NULL otherwise.
3744c2c66affSColin Finck  */
3745c2c66affSColin Finck const xmlChar *
3746c2c66affSColin Finck xmlCatalogGetSystem(const xmlChar *sysID) {
3747c2c66affSColin Finck     xmlChar *ret;
3748c2c66affSColin Finck     static xmlChar result[1000];
3749c2c66affSColin Finck     static int msg = 0;
3750c2c66affSColin Finck 
3751c2c66affSColin Finck     if (!xmlCatalogInitialized)
3752c2c66affSColin Finck 	xmlInitializeCatalog();
3753c2c66affSColin Finck 
3754c2c66affSColin Finck     if (msg == 0) {
3755c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
3756c2c66affSColin Finck 		"Use of deprecated xmlCatalogGetSystem() call\n");
3757c2c66affSColin Finck 	msg++;
3758c2c66affSColin Finck     }
3759c2c66affSColin Finck 
3760c2c66affSColin Finck     if (sysID == NULL)
3761c2c66affSColin Finck 	return(NULL);
3762c2c66affSColin Finck 
3763c2c66affSColin Finck     /*
3764c2c66affSColin Finck      * Check first the XML catalogs
3765c2c66affSColin Finck      */
3766c2c66affSColin Finck     if (xmlDefaultCatalog != NULL) {
3767c2c66affSColin Finck 	ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3768c2c66affSColin Finck 	if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3769c2c66affSColin Finck 	    snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3770c2c66affSColin Finck 	    result[sizeof(result) - 1] = 0;
3771c2c66affSColin Finck 	    return(result);
3772c2c66affSColin Finck 	}
3773c2c66affSColin Finck     }
3774c2c66affSColin Finck 
3775c2c66affSColin Finck     if (xmlDefaultCatalog != NULL)
3776c2c66affSColin Finck 	return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3777c2c66affSColin Finck     return(NULL);
3778c2c66affSColin Finck }
3779c2c66affSColin Finck 
3780c2c66affSColin Finck /**
3781c2c66affSColin Finck  * xmlCatalogGetPublic:
3782c2c66affSColin Finck  * @pubID:  the public ID string
3783c2c66affSColin Finck  *
3784c2c66affSColin Finck  * Try to lookup the catalog reference associated to a public ID
3785c2c66affSColin Finck  * DEPRECATED, use xmlCatalogResolvePublic()
3786c2c66affSColin Finck  *
3787c2c66affSColin Finck  * Returns the resource if found or NULL otherwise.
3788c2c66affSColin Finck  */
3789c2c66affSColin Finck const xmlChar *
3790c2c66affSColin Finck xmlCatalogGetPublic(const xmlChar *pubID) {
3791c2c66affSColin Finck     xmlChar *ret;
3792c2c66affSColin Finck     static xmlChar result[1000];
3793c2c66affSColin Finck     static int msg = 0;
3794c2c66affSColin Finck 
3795c2c66affSColin Finck     if (!xmlCatalogInitialized)
3796c2c66affSColin Finck 	xmlInitializeCatalog();
3797c2c66affSColin Finck 
3798c2c66affSColin Finck     if (msg == 0) {
3799c2c66affSColin Finck 	xmlGenericError(xmlGenericErrorContext,
3800c2c66affSColin Finck 		"Use of deprecated xmlCatalogGetPublic() call\n");
3801c2c66affSColin Finck 	msg++;
3802c2c66affSColin Finck     }
3803c2c66affSColin Finck 
3804c2c66affSColin Finck     if (pubID == NULL)
3805c2c66affSColin Finck 	return(NULL);
3806c2c66affSColin Finck 
3807c2c66affSColin Finck     /*
3808c2c66affSColin Finck      * Check first the XML catalogs
3809c2c66affSColin Finck      */
3810c2c66affSColin Finck     if (xmlDefaultCatalog != NULL) {
3811c2c66affSColin Finck 	ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3812c2c66affSColin Finck 	if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3813c2c66affSColin Finck 	    snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3814c2c66affSColin Finck 	    result[sizeof(result) - 1] = 0;
3815c2c66affSColin Finck 	    return(result);
3816c2c66affSColin Finck 	}
3817c2c66affSColin Finck     }
3818c2c66affSColin Finck 
3819c2c66affSColin Finck     if (xmlDefaultCatalog != NULL)
3820c2c66affSColin Finck 	return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3821c2c66affSColin Finck     return(NULL);
3822c2c66affSColin Finck }
3823c2c66affSColin Finck 
3824c2c66affSColin Finck #define bottom_catalog
3825c2c66affSColin Finck #include "elfgcchack.h"
3826c2c66affSColin Finck #endif /* LIBXML_CATALOG_ENABLED */
3827