blob: 3198fc139fd837c8649635407f98f84d57274d3a [file] [log] [blame]
Daniel Veillarda7374592001-05-10 14:17:55 +00001/**
2 * catalog.c: set of generic Catalog related routines
3 *
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
6 *
Daniel Veillard344cee72001-08-20 00:08:40 +00007 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9 *
Daniel Veillarda7374592001-05-10 14:17:55 +000010 * See Copyright for the status of this software.
11 *
12 * Daniel.Veillard@imag.fr
13 */
14
Daniel Veillard34ce8be2002-03-18 19:37:11 +000015#define IN_LIBXML
Daniel Veillarda7374592001-05-10 14:17:55 +000016#include "libxml.h"
17
18#ifdef LIBXML_CATALOG_ENABLED
19#ifdef HAVE_SYS_TYPES_H
20#include <sys/types.h>
21#endif
22#ifdef HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#ifdef HAVE_FCNTL_H
29#include <fcntl.h>
30#endif
Daniel Veillardc0631a62001-09-20 13:56:06 +000031#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000034#include <string.h>
35#include <libxml/xmlmemory.h>
36#include <libxml/hash.h>
37#include <libxml/uri.h>
38#include <libxml/parserInternals.h>
39#include <libxml/catalog.h>
40#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000041#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000042#include <libxml/globals.h>
Daniel Veillarda7374592001-05-10 14:17:55 +000043
Daniel Veillard6990bf32001-08-23 21:17:48 +000044#define MAX_DELEGATE 50
Daniel Veillard5ee43b02003-08-04 00:58:46 +000045#define MAX_CATAL_DEPTH 50
Daniel Veillard6990bf32001-08-23 21:17:48 +000046
Daniel Veillard344cee72001-08-20 00:08:40 +000047/**
48 * TODO:
49 *
50 * macro to flag unimplemented blocks
Daniel Veillard3e59fc52003-04-18 12:34:58 +000051 * XML_CATALOG_PREFER user env to select between system/public prefered
52 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
53 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
54 *> values "system" and "public". I have made the default be "system" to
55 *> match yours.
Daniel Veillard344cee72001-08-20 00:08:40 +000056 */
57#define TODO \
58 xmlGenericError(xmlGenericErrorContext, \
59 "Unimplemented block at %s:%d\n", \
60 __FILE__, __LINE__);
61
Daniel Veillardcda96922001-08-21 10:56:31 +000062#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000063#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000064#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000065#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000066#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000067#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000068#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000069#endif
70
Daniel Veillardfb382b82004-06-14 12:13:12 +000071#if defined(_WIN32) && defined(_MSC_VER)
72#undef XML_XML_DEFAULT_CATALOG
73static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
74void* __stdcall GetModuleHandleA(const char*);
75unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
76#endif
77
Daniel Veillardc8155052004-07-16 09:03:08 +000078static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
Daniel Veillard85c11fa2001-10-16 21:03:08 +000079static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000080
Daniel Veillarda7374592001-05-10 14:17:55 +000081/************************************************************************
82 * *
83 * Types, all private *
84 * *
85 ************************************************************************/
86
87typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000088 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000089 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000090 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000091 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000092 XML_CATA_NEXT_CATALOG,
William M. Brackb7b54de2004-10-06 16:38:01 +000093 XML_CATA_GROUP,
Daniel Veillard344cee72001-08-20 00:08:40 +000094 XML_CATA_PUBLIC,
95 XML_CATA_SYSTEM,
96 XML_CATA_REWRITE_SYSTEM,
97 XML_CATA_DELEGATE_PUBLIC,
98 XML_CATA_DELEGATE_SYSTEM,
99 XML_CATA_URI,
100 XML_CATA_REWRITE_URI,
101 XML_CATA_DELEGATE_URI,
102 SGML_CATA_SYSTEM,
103 SGML_CATA_PUBLIC,
104 SGML_CATA_ENTITY,
105 SGML_CATA_PENTITY,
106 SGML_CATA_DOCTYPE,
107 SGML_CATA_LINKTYPE,
108 SGML_CATA_NOTATION,
109 SGML_CATA_DELEGATE,
110 SGML_CATA_BASE,
111 SGML_CATA_CATALOG,
112 SGML_CATA_DOCUMENT,
113 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000114} xmlCatalogEntryType;
115
116typedef struct _xmlCatalogEntry xmlCatalogEntry;
117typedef xmlCatalogEntry *xmlCatalogEntryPtr;
118struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000119 struct _xmlCatalogEntry *next;
120 struct _xmlCatalogEntry *parent;
121 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000122 xmlCatalogEntryType type;
123 xmlChar *name;
124 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000125 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000126 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000127 int dealloc;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000128 int depth;
William M. Brackb7b54de2004-10-06 16:38:01 +0000129 struct _xmlCatalogEntry *group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000130};
131
Daniel Veillard75b96822001-10-11 18:59:45 +0000132typedef enum {
133 XML_XML_CATALOG_TYPE = 1,
134 XML_SGML_CATALOG_TYPE
135} xmlCatalogType;
136
137#define XML_MAX_SGML_CATA_DEPTH 10
138struct _xmlCatalog {
139 xmlCatalogType type; /* either XML or SGML */
140
141 /*
142 * SGML Catalogs are stored as a simple hash table of catalog entries
143 * Catalog stack to check against overflows when building the
144 * SGML catalog
145 */
146 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
147 int catalNr; /* Number of current catal streams */
148 int catalMax; /* Max number of catal streams */
149 xmlHashTablePtr sgml;
150
151 /*
152 * XML Catalogs are stored as a tree of Catalog entries
153 */
154 xmlCatalogPrefer prefer;
155 xmlCatalogEntryPtr xml;
156};
157
158/************************************************************************
159 * *
160 * Global variables *
161 * *
162 ************************************************************************/
163
Daniel Veillard81463942001-10-16 12:34:39 +0000164/*
165 * Those are preferences
166 */
167static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000168static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000169static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000170
171/*
172 * Hash table containing all the trees of XML catalogs parsed by
173 * the application.
174 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000175static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000176
177/*
178 * The default catalog in use by the application
179 */
180static xmlCatalogPtr xmlDefaultCatalog = NULL;
181
182/*
Daniel Veillard81463942001-10-16 12:34:39 +0000183 * A mutex for modifying the shared global catalog(s)
184 * xmlDefaultCatalog tree.
185 * It also protects xmlCatalogXMLFiles
186 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
187 */
188static xmlRMutexPtr xmlCatalogMutex = NULL;
189
190/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000191 * Whether the catalog support was initialized.
192 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000193static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000194
Daniel Veillard69d2c172003-10-09 11:46:07 +0000195/************************************************************************
196 * *
197 * Catalog error handlers *
198 * *
199 ************************************************************************/
200
201/**
202 * xmlCatalogErrMemory:
203 * @extra: extra informations
204 *
205 * Handle an out of memory condition
206 */
207static void
208xmlCatalogErrMemory(const char *extra)
209{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000210 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000211 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
212 extra, NULL, NULL, 0, 0,
213 "Memory allocation failed : %s\n", extra);
214}
215
216/**
217 * xmlCatalogErr:
218 * @catal: the Catalog entry
219 * @node: the context node
220 * @msg: the error message
221 * @extra: extra informations
222 *
223 * Handle a catalog error
224 */
225static void
226xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
227 const char *msg, const xmlChar *str1, const xmlChar *str2,
228 const xmlChar *str3)
229{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000230 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000231 error, XML_ERR_ERROR, NULL, 0,
232 (const char *) str1, (const char *) str2,
233 (const char *) str3, 0, 0,
234 msg, str1, str2, str3);
235}
236
Daniel Veillarda7374592001-05-10 14:17:55 +0000237
238/************************************************************************
239 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000240 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000241 * *
242 ************************************************************************/
243
Daniel Veillard75b96822001-10-11 18:59:45 +0000244/**
245 * xmlNewCatalogEntry:
246 * @type: type of entry
247 * @name: name of the entry
248 * @value: value of the entry
249 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +0000250 * @group: for members of a group, the group entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000251 *
252 * create a new Catalog entry, this type is shared both by XML and
253 * SGML catalogs, but the acceptable types values differs.
254 *
255 * Returns the xmlCatalogEntryPtr or NULL in case of error
256 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000257static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000258xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
William M. Brackb7b54de2004-10-06 16:38:01 +0000259 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
260 xmlCatalogEntryPtr group) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000261 xmlCatalogEntryPtr ret;
Daniel Veillardc8155052004-07-16 09:03:08 +0000262 xmlChar *normid = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000263
264 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
265 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000266 xmlCatalogErrMemory("allocating catalog entry");
Daniel Veillarda7374592001-05-10 14:17:55 +0000267 return(NULL);
268 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000269 ret->next = NULL;
270 ret->parent = NULL;
271 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000272 ret->type = type;
Daniel Veillardc8155052004-07-16 09:03:08 +0000273 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
274 normid = xmlCatalogNormalizePublic(name);
275 if (normid != NULL)
276 name = (*normid != 0 ? normid : NULL);
277 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000278 if (name != NULL)
279 ret->name = xmlStrdup(name);
280 else
281 ret->name = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +0000282 if (normid != NULL)
283 xmlFree(normid);
Daniel Veillard344cee72001-08-20 00:08:40 +0000284 if (value != NULL)
285 ret->value = xmlStrdup(value);
286 else
287 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000288 if (URL == NULL)
289 URL = value;
290 if (URL != NULL)
291 ret->URL = xmlStrdup(URL);
292 else
293 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000294 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000295 ret->dealloc = 0;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000296 ret->depth = 0;
William M. Brackb7b54de2004-10-06 16:38:01 +0000297 ret->group = group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000298 return(ret);
299}
300
301static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000302xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
303
Daniel Veillard75b96822001-10-11 18:59:45 +0000304/**
305 * xmlFreeCatalogEntry:
306 * @ret: a Catalog entry
307 *
308 * Free the memory allocated to a Catalog entry
309 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000310static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000311xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
312 if (ret == NULL)
313 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000314 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000315 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000316 * only by the file hash cleaner !
317 */
318 if (ret->dealloc == 1)
319 return;
320
321 if (xmlDebugCatalogs) {
322 if (ret->name != NULL)
323 xmlGenericError(xmlGenericErrorContext,
324 "Free catalog entry %s\n", ret->name);
325 else if (ret->value != NULL)
326 xmlGenericError(xmlGenericErrorContext,
327 "Free catalog entry %s\n", ret->value);
328 else
329 xmlGenericError(xmlGenericErrorContext,
330 "Free catalog entry\n");
331 }
332
Daniel Veillarda7374592001-05-10 14:17:55 +0000333 if (ret->name != NULL)
334 xmlFree(ret->name);
335 if (ret->value != NULL)
336 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000337 if (ret->URL != NULL)
338 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000339 xmlFree(ret);
340}
341
Daniel Veillard75b96822001-10-11 18:59:45 +0000342/**
343 * xmlFreeCatalogEntryList:
344 * @ret: a Catalog entry list
345 *
346 * Free the memory allocated to a full chained list of Catalog entries
347 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000348static void
349xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
350 xmlCatalogEntryPtr next;
351
352 while (ret != NULL) {
353 next = ret->next;
354 xmlFreeCatalogEntry(ret);
355 ret = next;
356 }
357}
358
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000359/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000360 * xmlFreeCatalogHashEntryList:
361 * @ret: a Catalog entry list
362 *
363 * Free the memory allocated to list of Catalog entries from the
364 * catalog file hash.
365 */
366static void
367xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
368 xmlCatalogEntryPtr children, next;
369
370 if (catal == NULL)
371 return;
372
373 children = catal->children;
374 while (children != NULL) {
375 next = children->next;
376 children->dealloc = 0;
377 children->children = NULL;
378 xmlFreeCatalogEntry(children);
379 children = next;
380 }
381 catal->dealloc = 0;
382 xmlFreeCatalogEntry(catal);
383}
384
385/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000386 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000387 * @type: type of catalog
388 * @prefer: the PUBLIC vs. SYSTEM current preference value
389 *
390 * create a new Catalog, this type is shared both by XML and
391 * SGML catalogs, but the acceptable types values differs.
392 *
393 * Returns the xmlCatalogPtr or NULL in case of error
394 */
395static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000396xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000397 xmlCatalogPtr ret;
398
399 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
400 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000401 xmlCatalogErrMemory("allocating catalog");
Daniel Veillard75b96822001-10-11 18:59:45 +0000402 return(NULL);
403 }
404 memset(ret, 0, sizeof(xmlCatalog));
405 ret->type = type;
406 ret->catalNr = 0;
407 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
408 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000409 if (ret->type == XML_SGML_CATALOG_TYPE)
410 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000411 return(ret);
412}
413
414/**
415 * xmlFreeCatalog:
Daniel Veillard06d25242004-02-25 13:01:42 +0000416 * @catal: a Catalog
Daniel Veillard75b96822001-10-11 18:59:45 +0000417 *
418 * Free the memory allocated to a Catalog
419 */
420void
421xmlFreeCatalog(xmlCatalogPtr catal) {
422 if (catal == NULL)
423 return;
424 if (catal->xml != NULL)
425 xmlFreeCatalogEntryList(catal->xml);
426 if (catal->sgml != NULL)
427 xmlHashFree(catal->sgml,
428 (xmlHashDeallocator) xmlFreeCatalogEntry);
429 xmlFree(catal);
430}
431
432/************************************************************************
433 * *
434 * Serializing Catalogs *
435 * *
436 ************************************************************************/
437
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000438#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000439/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000440 * xmlCatalogDumpEntry:
Daniel Veillard06d25242004-02-25 13:01:42 +0000441 * @entry: the catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000442 * @out: the file.
443 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000444 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000445 */
446static void
447xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
448 if ((entry == NULL) || (out == NULL))
449 return;
450 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000451 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000452 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000453 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000454 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000455 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000456 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000457 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000458 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000459 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000460 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000461 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000462 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000463 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000464 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000465 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000466 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000467 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000468 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000469 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000470 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000471 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000472 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000473 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000474 fprintf(out, "SGMLDECL "); break;
475 default:
476 return;
477 }
478 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000479 case SGML_CATA_ENTITY:
480 case SGML_CATA_PENTITY:
481 case SGML_CATA_DOCTYPE:
482 case SGML_CATA_LINKTYPE:
483 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000484 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000485 case SGML_CATA_PUBLIC:
486 case SGML_CATA_SYSTEM:
487 case SGML_CATA_SGMLDECL:
488 case SGML_CATA_DOCUMENT:
489 case SGML_CATA_CATALOG:
490 case SGML_CATA_BASE:
491 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000492 fprintf(out, "\"%s\"", entry->name); break;
493 default:
494 break;
495 }
496 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000497 case SGML_CATA_ENTITY:
498 case SGML_CATA_PENTITY:
499 case SGML_CATA_DOCTYPE:
500 case SGML_CATA_LINKTYPE:
501 case SGML_CATA_NOTATION:
502 case SGML_CATA_PUBLIC:
503 case SGML_CATA_SYSTEM:
504 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000505 fprintf(out, " \"%s\"", entry->value); break;
506 default:
507 break;
508 }
509 fprintf(out, "\n");
510}
511
William M. Brackb7b54de2004-10-06 16:38:01 +0000512/**
513 * xmlDumpXMLCatalogNode:
514 * @catal: top catalog entry
515 * @catalog: pointer to the xml tree
516 * @doc: the containing document
517 * @ns: the current namespace
518 * @cgroup: group node for group members
519 *
520 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
521 * for group entries
522 */
523static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
524 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
525 xmlNodePtr node;
526 xmlCatalogEntryPtr cur;
527 /*
528 * add all the catalog entries
529 */
530 cur = catal;
531 while (cur != NULL) {
532 if (cur->group == cgroup) {
533 switch (cur->type) {
534 case XML_CATA_REMOVED:
535 break;
536 case XML_CATA_BROKEN_CATALOG:
537 case XML_CATA_CATALOG:
538 if (cur == catal) {
539 cur = cur->children;
540 continue;
541 }
542 break;
543 case XML_CATA_NEXT_CATALOG:
544 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
545 xmlSetProp(node, BAD_CAST "catalog", cur->value);
546 xmlAddChild(catalog, node);
547 break;
548 case XML_CATA_NONE:
549 break;
550 case XML_CATA_GROUP:
551 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
552 xmlSetProp(node, BAD_CAST "id", cur->name);
William M. Brack6218b312004-10-06 17:52:32 +0000553 if (cur->value != NULL) {
554 xmlNsPtr xns;
555 xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
556 if (xns != NULL)
557 xmlSetNsProp(node, xns, BAD_CAST "base",
558 cur->value);
559 }
William M. Brackb7b54de2004-10-06 16:38:01 +0000560 switch (cur->prefer) {
561 case XML_CATA_PREFER_NONE:
562 break;
563 case XML_CATA_PREFER_PUBLIC:
564 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
565 break;
566 case XML_CATA_PREFER_SYSTEM:
567 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
568 break;
569 }
570 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
571 xmlAddChild(catalog, node);
572 break;
573 case XML_CATA_PUBLIC:
574 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
575 xmlSetProp(node, BAD_CAST "publicId", cur->name);
576 xmlSetProp(node, BAD_CAST "uri", cur->value);
577 xmlAddChild(catalog, node);
578 break;
579 case XML_CATA_SYSTEM:
580 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
581 xmlSetProp(node, BAD_CAST "systemId", cur->name);
582 xmlSetProp(node, BAD_CAST "uri", cur->value);
583 xmlAddChild(catalog, node);
584 break;
585 case XML_CATA_REWRITE_SYSTEM:
586 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
587 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
588 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
589 xmlAddChild(catalog, node);
590 break;
591 case XML_CATA_DELEGATE_PUBLIC:
592 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
593 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
594 xmlSetProp(node, BAD_CAST "catalog", cur->value);
595 xmlAddChild(catalog, node);
596 break;
597 case XML_CATA_DELEGATE_SYSTEM:
598 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
599 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
600 xmlSetProp(node, BAD_CAST "catalog", cur->value);
601 xmlAddChild(catalog, node);
602 break;
603 case XML_CATA_URI:
604 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
605 xmlSetProp(node, BAD_CAST "name", cur->name);
606 xmlSetProp(node, BAD_CAST "uri", cur->value);
607 xmlAddChild(catalog, node);
608 break;
609 case XML_CATA_REWRITE_URI:
610 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
611 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
612 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
613 xmlAddChild(catalog, node);
614 break;
615 case XML_CATA_DELEGATE_URI:
616 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
617 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
618 xmlSetProp(node, BAD_CAST "catalog", cur->value);
619 xmlAddChild(catalog, node);
620 break;
621 case SGML_CATA_SYSTEM:
622 case SGML_CATA_PUBLIC:
623 case SGML_CATA_ENTITY:
624 case SGML_CATA_PENTITY:
625 case SGML_CATA_DOCTYPE:
626 case SGML_CATA_LINKTYPE:
627 case SGML_CATA_NOTATION:
628 case SGML_CATA_DELEGATE:
629 case SGML_CATA_BASE:
630 case SGML_CATA_CATALOG:
631 case SGML_CATA_DOCUMENT:
632 case SGML_CATA_SGMLDECL:
633 break;
634 }
635 }
636 cur = cur->next;
637 }
638}
639
Daniel Veillard75b96822001-10-11 18:59:45 +0000640static int
641xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
642 int ret;
643 xmlDocPtr doc;
644 xmlNsPtr ns;
645 xmlDtdPtr dtd;
William M. Brackb7b54de2004-10-06 16:38:01 +0000646 xmlNodePtr catalog;
Daniel Veillard75b96822001-10-11 18:59:45 +0000647 xmlOutputBufferPtr buf;
Daniel Veillard75b96822001-10-11 18:59:45 +0000648
649 /*
650 * Rebuild a catalog
651 */
652 doc = xmlNewDoc(NULL);
653 if (doc == NULL)
654 return(-1);
655 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
656 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
657BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
658
659 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
660
661 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
662 if (ns == NULL) {
663 xmlFreeDoc(doc);
664 return(-1);
665 }
666 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
667 if (catalog == NULL) {
668 xmlFreeNs(ns);
669 xmlFreeDoc(doc);
670 return(-1);
671 }
672 catalog->nsDef = ns;
673 xmlAddChild((xmlNodePtr) doc, catalog);
674
William M. Brackb7b54de2004-10-06 16:38:01 +0000675 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
676
Daniel Veillard75b96822001-10-11 18:59:45 +0000677 /*
678 * reserialize it
679 */
680 buf = xmlOutputBufferCreateFile(out, NULL);
681 if (buf == NULL) {
682 xmlFreeDoc(doc);
683 return(-1);
684 }
685 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
686
687 /*
688 * Free it
689 */
690 xmlFreeDoc(doc);
691
692 return(ret);
693}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000694#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000695
696/************************************************************************
697 * *
698 * Converting SGML Catalogs to XML *
699 * *
700 ************************************************************************/
701
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000702/**
703 * xmlCatalogConvertEntry:
704 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000705 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000706 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000707 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000708 */
709static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000710xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
711 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
712 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000713 return;
714 switch (entry->type) {
715 case SGML_CATA_ENTITY:
716 entry->type = XML_CATA_PUBLIC;
717 break;
718 case SGML_CATA_PENTITY:
719 entry->type = XML_CATA_PUBLIC;
720 break;
721 case SGML_CATA_DOCTYPE:
722 entry->type = XML_CATA_PUBLIC;
723 break;
724 case SGML_CATA_LINKTYPE:
725 entry->type = XML_CATA_PUBLIC;
726 break;
727 case SGML_CATA_NOTATION:
728 entry->type = XML_CATA_PUBLIC;
729 break;
730 case SGML_CATA_PUBLIC:
731 entry->type = XML_CATA_PUBLIC;
732 break;
733 case SGML_CATA_SYSTEM:
734 entry->type = XML_CATA_SYSTEM;
735 break;
736 case SGML_CATA_DELEGATE:
737 entry->type = XML_CATA_DELEGATE_PUBLIC;
738 break;
739 case SGML_CATA_CATALOG:
740 entry->type = XML_CATA_CATALOG;
741 break;
742 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000743 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000744 (xmlHashDeallocator) xmlFreeCatalogEntry);
745 return;
746 }
747 /*
748 * Conversion successful, remove from the SGML catalog
749 * and add it to the default XML one
750 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000751 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
752 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000753 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000754 if (catal->xml->children == NULL)
755 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000756 else {
757 xmlCatalogEntryPtr prev;
758
Daniel Veillard75b96822001-10-11 18:59:45 +0000759 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000760 while (prev->next != NULL)
761 prev = prev->next;
762 prev->next = entry;
763 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000764}
765
766/**
767 * xmlConvertSGMLCatalog:
768 * @catal: the catalog
769 *
770 * Convert all the SGML catalog entries as XML ones
771 *
772 * Returns the number of entries converted if successful, -1 otherwise
773 */
774int
775xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
776
777 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
778 return(-1);
779
780 if (xmlDebugCatalogs) {
781 xmlGenericError(xmlGenericErrorContext,
782 "Converting SGML catalog to XML\n");
783 }
784 xmlHashScan(catal->sgml,
785 (xmlHashScanner) xmlCatalogConvertEntry,
786 &catal);
787 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000788}
789
Daniel Veillarda7374592001-05-10 14:17:55 +0000790/************************************************************************
791 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000792 * Helper function *
793 * *
794 ************************************************************************/
795
796/**
797 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000798 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000799 *
800 * Expand the URN into the equivalent Public Identifier
801 *
802 * Returns the new identifier or NULL, the string must be deallocated
803 * by the caller.
804 */
805static xmlChar *
806xmlCatalogUnWrapURN(const xmlChar *urn) {
807 xmlChar result[2000];
808 unsigned int i = 0;
809
810 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
811 return(NULL);
812 urn += sizeof(XML_URN_PUBID) - 1;
813
814 while (*urn != 0) {
Daniel Veillard770075b2004-02-25 10:44:30 +0000815 if (i > sizeof(result) - 4)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000816 break;
817 if (*urn == '+') {
818 result[i++] = ' ';
819 urn++;
820 } else if (*urn == ':') {
821 result[i++] = '/';
822 result[i++] = '/';
823 urn++;
824 } else if (*urn == ';') {
825 result[i++] = ':';
826 result[i++] = ':';
827 urn++;
828 } else if (*urn == '%') {
Daniel Veillard770075b2004-02-25 10:44:30 +0000829 if ((urn[1] == '2') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000830 result[i++] = '+';
Daniel Veillard770075b2004-02-25 10:44:30 +0000831 else if ((urn[1] == '3') && (urn[2] == 'A'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000832 result[i++] = ':';
Daniel Veillard770075b2004-02-25 10:44:30 +0000833 else if ((urn[1] == '2') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000834 result[i++] = '/';
Daniel Veillard770075b2004-02-25 10:44:30 +0000835 else if ((urn[1] == '3') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000836 result[i++] = ';';
Daniel Veillard770075b2004-02-25 10:44:30 +0000837 else if ((urn[1] == '2') && (urn[2] == '7'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000838 result[i++] = '\'';
Daniel Veillard770075b2004-02-25 10:44:30 +0000839 else if ((urn[1] == '3') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000840 result[i++] = '?';
Daniel Veillard770075b2004-02-25 10:44:30 +0000841 else if ((urn[1] == '2') && (urn[2] == '3'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000842 result[i++] = '#';
Daniel Veillard770075b2004-02-25 10:44:30 +0000843 else if ((urn[1] == '2') && (urn[2] == '5'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000844 result[i++] = '%';
845 else {
846 result[i++] = *urn;
847 urn++;
848 continue;
849 }
850 urn += 3;
851 } else {
852 result[i++] = *urn;
853 urn++;
854 }
855 }
856 result[i] = 0;
857
858 return(xmlStrdup(result));
859}
860
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000861/**
862 * xmlParseCatalogFile:
863 * @filename: the filename
864 *
865 * parse an XML file and build a tree. It's like xmlParseFile()
866 * except it bypass all catalog lookups.
867 *
868 * Returns the resulting document tree or NULL in case of error
869 */
870
871xmlDocPtr
872xmlParseCatalogFile(const char *filename) {
873 xmlDocPtr ret;
874 xmlParserCtxtPtr ctxt;
875 char *directory = NULL;
876 xmlParserInputPtr inputStream;
877 xmlParserInputBufferPtr buf;
878
879 ctxt = xmlNewParserCtxt();
880 if (ctxt == NULL) {
881 if (xmlDefaultSAXHandler.error != NULL) {
882 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
883 }
884 return(NULL);
885 }
886
887 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
888 if (buf == NULL) {
889 xmlFreeParserCtxt(ctxt);
890 return(NULL);
891 }
892
893 inputStream = xmlNewInputStream(ctxt);
894 if (inputStream == NULL) {
895 xmlFreeParserCtxt(ctxt);
896 return(NULL);
897 }
898
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000899 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000900 inputStream->buf = buf;
901 inputStream->base = inputStream->buf->buffer->content;
902 inputStream->cur = inputStream->buf->buffer->content;
903 inputStream->end =
904 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
905
906 inputPush(ctxt, inputStream);
907 if ((ctxt->directory == NULL) && (directory == NULL))
908 directory = xmlParserGetDirectory(filename);
909 if ((ctxt->directory == NULL) && (directory != NULL))
910 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000911 ctxt->valid = 0;
912 ctxt->validate = 0;
913 ctxt->loadsubset = 0;
914 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000915
916 xmlParseDocument(ctxt);
917
918 if (ctxt->wellFormed)
919 ret = ctxt->myDoc;
920 else {
921 ret = NULL;
922 xmlFreeDoc(ctxt->myDoc);
923 ctxt->myDoc = NULL;
924 }
925 xmlFreeParserCtxt(ctxt);
926
927 return(ret);
928}
929
Daniel Veillard75b96822001-10-11 18:59:45 +0000930/**
931 * xmlLoadFileContent:
932 * @filename: a file path
933 *
934 * Load a file content into memory.
935 *
936 * Returns a pointer to the 0 terminated string or NULL in case of error
937 */
938static xmlChar *
939xmlLoadFileContent(const char *filename)
940{
941#ifdef HAVE_STAT
942 int fd;
943#else
944 FILE *fd;
945#endif
946 int len;
947 long size;
948
949#ifdef HAVE_STAT
950 struct stat info;
951#endif
952 xmlChar *content;
953
954 if (filename == NULL)
955 return (NULL);
956
957#ifdef HAVE_STAT
958 if (stat(filename, &info) < 0)
959 return (NULL);
960#endif
961
962#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000963 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000964#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000965 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000966#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000967 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000968 return (NULL);
969 }
970#ifdef HAVE_STAT
971 size = info.st_size;
972#else
973 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
974 fclose(fd);
975 return (NULL);
976 }
977#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000978 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000979 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000980 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard75b96822001-10-11 18:59:45 +0000981 return (NULL);
982 }
983#ifdef HAVE_STAT
984 len = read(fd, content, size);
985#else
986 len = fread(content, 1, size, fd);
987#endif
988 if (len < 0) {
989 xmlFree(content);
990 return (NULL);
991 }
992#ifdef HAVE_STAT
993 close(fd);
994#else
995 fclose(fd);
996#endif
997 content[len] = 0;
998
999 return(content);
1000}
1001
Daniel Veillardc8155052004-07-16 09:03:08 +00001002/**
1003 * xmlCatalogNormalizePublic:
1004 * @pubID: the public ID string
1005 *
1006 * Normalizes the Public Identifier
1007 *
1008 * Implements 6.2. Public Identifier Normalization
1009 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1010 *
1011 * Returns the new string or NULL, the string must be deallocated
1012 * by the caller.
1013 */
1014static xmlChar *
1015xmlCatalogNormalizePublic(const xmlChar *pubID)
1016{
1017 int ok = 1;
1018 int white;
1019 const xmlChar *p;
1020 xmlChar *ret;
1021 xmlChar *q;
1022
1023 if (pubID == NULL)
1024 return(NULL);
1025
1026 white = 1;
1027 for (p = pubID;*p != 0 && ok;p++) {
1028 if (!xmlIsBlank_ch(*p))
1029 white = 0;
1030 else if (*p == 0x20 && !white)
1031 white = 1;
1032 else
1033 ok = 0;
1034 }
1035 if (ok && !white) /* is normalized */
1036 return(NULL);
1037
1038 ret = xmlStrdup(pubID);
1039 q = ret;
1040 white = 0;
1041 for (p = pubID;*p != 0;p++) {
1042 if (xmlIsBlank_ch(*p)) {
1043 if (q != ret)
1044 white = 1;
1045 } else {
1046 if (white) {
1047 *(q++) = 0x20;
1048 white = 0;
1049 }
1050 *(q++) = *p;
1051 }
1052 }
1053 *q = 0;
1054 return(ret);
1055}
1056
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001057/************************************************************************
1058 * *
Daniel Veillard344cee72001-08-20 00:08:40 +00001059 * The XML Catalog parser *
1060 * *
1061 ************************************************************************/
1062
1063static xmlCatalogEntryPtr
1064xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001065static void
1066xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001067 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
Daniel Veillardcda96922001-08-21 10:56:31 +00001068static xmlChar *
1069xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1070 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001071static xmlChar *
1072xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1073
Daniel Veillard344cee72001-08-20 00:08:40 +00001074
Daniel Veillard75b96822001-10-11 18:59:45 +00001075/**
1076 * xmlGetXMLCatalogEntryType:
1077 * @name: the name
1078 *
1079 * lookup the internal type associated to an XML catalog entry name
1080 *
Daniel Veillard06d25242004-02-25 13:01:42 +00001081 * Returns the type associated with that name
Daniel Veillard75b96822001-10-11 18:59:45 +00001082 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001083static xmlCatalogEntryType
1084xmlGetXMLCatalogEntryType(const xmlChar *name) {
1085 xmlCatalogEntryType type = XML_CATA_NONE;
1086 if (xmlStrEqual(name, (const xmlChar *) "system"))
1087 type = XML_CATA_SYSTEM;
1088 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1089 type = XML_CATA_PUBLIC;
1090 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1091 type = XML_CATA_REWRITE_SYSTEM;
1092 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1093 type = XML_CATA_DELEGATE_PUBLIC;
1094 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1095 type = XML_CATA_DELEGATE_SYSTEM;
1096 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1097 type = XML_CATA_URI;
1098 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1099 type = XML_CATA_REWRITE_URI;
1100 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1101 type = XML_CATA_DELEGATE_URI;
1102 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1103 type = XML_CATA_NEXT_CATALOG;
1104 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1105 type = XML_CATA_CATALOG;
1106 return(type);
1107}
1108
Daniel Veillard75b96822001-10-11 18:59:45 +00001109/**
1110 * xmlParseXMLCatalogOneNode:
1111 * @cur: the XML node
1112 * @type: the type of Catalog entry
1113 * @name: the name of the node
1114 * @attrName: the attribute holding the value
1115 * @uriAttrName: the attribute holding the URI-Reference
1116 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +00001117 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001118 *
1119 * Finishes the examination of an XML tree node of a catalog and build
1120 * a Catalog entry from it.
1121 *
1122 * Returns the new Catalog entry node or NULL in case of error.
1123 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001124static xmlCatalogEntryPtr
1125xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1126 const xmlChar *name, const xmlChar *attrName,
William M. Brackb7b54de2004-10-06 16:38:01 +00001127 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1128 xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001129 int ok = 1;
1130 xmlChar *uriValue;
1131 xmlChar *nameValue = NULL;
1132 xmlChar *base = NULL;
1133 xmlChar *URL = NULL;
1134 xmlCatalogEntryPtr ret = NULL;
1135
1136 if (attrName != NULL) {
1137 nameValue = xmlGetProp(cur, attrName);
1138 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001139 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1140 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001141 ok = 0;
1142 }
1143 }
1144 uriValue = xmlGetProp(cur, uriAttrName);
1145 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001146 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1147 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001148 ok = 0;
1149 }
1150 if (!ok) {
1151 if (nameValue != NULL)
1152 xmlFree(nameValue);
1153 if (uriValue != NULL)
1154 xmlFree(uriValue);
1155 return(NULL);
1156 }
1157
1158 base = xmlNodeGetBase(cur->doc, cur);
1159 URL = xmlBuildURI(uriValue, base);
1160 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001161 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001162 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001163 xmlGenericError(xmlGenericErrorContext,
1164 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001165 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001166 xmlGenericError(xmlGenericErrorContext,
1167 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001168 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001169 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001170 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001171 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001172 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1173 }
1174 if (nameValue != NULL)
1175 xmlFree(nameValue);
1176 if (uriValue != NULL)
1177 xmlFree(uriValue);
1178 if (base != NULL)
1179 xmlFree(base);
1180 if (URL != NULL)
1181 xmlFree(URL);
1182 return(ret);
1183}
1184
Daniel Veillard75b96822001-10-11 18:59:45 +00001185/**
1186 * xmlParseXMLCatalogNode:
1187 * @cur: the XML node
1188 * @prefer: the PUBLIC vs. SYSTEM current preference value
1189 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001190 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001191 *
1192 * Examines an XML tree node of a catalog and build
1193 * a Catalog entry from it adding it to its parent. The examination can
1194 * be recursive.
1195 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001196static void
1197xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001198 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
Daniel Veillard344cee72001-08-20 00:08:40 +00001199{
1200 xmlChar *uri = NULL;
1201 xmlChar *URL = NULL;
1202 xmlChar *base = NULL;
1203 xmlCatalogEntryPtr entry = NULL;
1204
1205 if (cur == NULL)
1206 return;
1207 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1208 xmlChar *prop;
William M. Brackb7b54de2004-10-06 16:38:01 +00001209 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
Daniel Veillard344cee72001-08-20 00:08:40 +00001210
1211 prop = xmlGetProp(cur, BAD_CAST "prefer");
1212 if (prop != NULL) {
1213 if (xmlStrEqual(prop, BAD_CAST "system")) {
1214 prefer = XML_CATA_PREFER_SYSTEM;
1215 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1216 prefer = XML_CATA_PREFER_PUBLIC;
1217 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001218 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1219 "Invalid value for prefer: '%s'\n",
1220 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001221 }
1222 xmlFree(prop);
William M. Brackb7b54de2004-10-06 16:38:01 +00001223 pref = prefer;
Daniel Veillard344cee72001-08-20 00:08:40 +00001224 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001225 prop = xmlGetProp(cur, BAD_CAST "id");
1226 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1227 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
William M. Brack181a1ca2004-10-06 18:00:29 +00001228 xmlFree(prop);
Daniel Veillard344cee72001-08-20 00:08:40 +00001229 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1230 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
William M. Brackb7b54de2004-10-06 16:38:01 +00001231 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001232 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1233 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
William M. Brackb7b54de2004-10-06 16:38:01 +00001234 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001235 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1236 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1237 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001238 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001239 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1240 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1241 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001242 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001243 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1244 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1245 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001246 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001247 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1248 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1249 BAD_CAST "uri", BAD_CAST "name",
William M. Brackb7b54de2004-10-06 16:38:01 +00001250 BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001251 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1252 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1253 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001254 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001255 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1256 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1257 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001258 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001259 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1260 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1261 BAD_CAST "nextCatalog", NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001262 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001263 }
1264 if ((entry != NULL) && (parent != NULL)) {
1265 entry->parent = parent;
1266 if (parent->children == NULL)
1267 parent->children = entry;
1268 else {
1269 xmlCatalogEntryPtr prev;
1270
1271 prev = parent->children;
1272 while (prev->next != NULL)
1273 prev = prev->next;
1274 prev->next = entry;
1275 }
1276 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001277 if (entry->type == XML_CATA_GROUP) {
1278 /*
1279 * Recurse to propagate prefer to the subtree
1280 * (xml:base handling is automated)
1281 */
1282 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1283 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001284 if (base != NULL)
1285 xmlFree(base);
1286 if (uri != NULL)
1287 xmlFree(uri);
1288 if (URL != NULL)
1289 xmlFree(URL);
1290}
1291
Daniel Veillard75b96822001-10-11 18:59:45 +00001292/**
1293 * xmlParseXMLCatalogNodeList:
1294 * @cur: the XML node list of siblings
1295 * @prefer: the PUBLIC vs. SYSTEM current preference value
1296 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001297 * @cgroup: the group which includes this list
Daniel Veillard75b96822001-10-11 18:59:45 +00001298 *
1299 * Examines a list of XML sibling nodes of a catalog and build
1300 * a list of Catalog entry from it adding it to the parent.
1301 * The examination will recurse to examine node subtrees.
1302 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001303static void
1304xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001305 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001306 while (cur != NULL) {
1307 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1308 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
William M. Brackb7b54de2004-10-06 16:38:01 +00001309 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001310 }
1311 cur = cur->next;
1312 }
1313 /* TODO: sort the list according to REWRITE lengths and prefer value */
1314}
1315
Daniel Veillard75b96822001-10-11 18:59:45 +00001316/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001317 * xmlParseXMLCatalogFile:
1318 * @prefer: the PUBLIC vs. SYSTEM current preference value
1319 * @filename: the filename for the catalog
1320 *
1321 * Parses the catalog file to extract the XML tree and then analyze the
1322 * tree to build a list of Catalog entries corresponding to this catalog
1323 *
1324 * Returns the resulting Catalog entries list
1325 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001326static xmlCatalogEntryPtr
1327xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1328 xmlDocPtr doc;
1329 xmlNodePtr cur;
1330 xmlChar *prop;
1331 xmlCatalogEntryPtr parent = NULL;
1332
1333 if (filename == NULL)
1334 return(NULL);
1335
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001336 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001337 if (doc == NULL) {
1338 if (xmlDebugCatalogs)
1339 xmlGenericError(xmlGenericErrorContext,
1340 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001341 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001342 }
1343
1344 if (xmlDebugCatalogs)
1345 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001346 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001347
1348 cur = xmlDocGetRootElement(doc);
1349 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1350 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1351 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1352
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001353 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001354 (const xmlChar *)filename, NULL, prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001355 if (parent == NULL) {
1356 xmlFreeDoc(doc);
1357 return(NULL);
1358 }
1359
1360 prop = xmlGetProp(cur, BAD_CAST "prefer");
1361 if (prop != NULL) {
1362 if (xmlStrEqual(prop, BAD_CAST "system")) {
1363 prefer = XML_CATA_PREFER_SYSTEM;
1364 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1365 prefer = XML_CATA_PREFER_PUBLIC;
1366 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001367 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1368 "Invalid value for prefer: '%s'\n",
1369 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001370 }
1371 xmlFree(prop);
1372 }
1373 cur = cur->children;
William M. Brackb7b54de2004-10-06 16:38:01 +00001374 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001375 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001376 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1377 "File %s is not an XML Catalog\n",
1378 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001379 xmlFreeDoc(doc);
1380 return(NULL);
1381 }
1382 xmlFreeDoc(doc);
1383 return(parent);
1384}
1385
Daniel Veillardcda96922001-08-21 10:56:31 +00001386/**
1387 * xmlFetchXMLCatalogFile:
1388 * @catal: an existing but incomplete catalog entry
1389 *
1390 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001391 *
1392 * Returns 0 in case of success, -1 otherwise
1393 */
1394static int
1395xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001396 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001397
1398 if (catal == NULL)
1399 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001400 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001401 return(-1);
1402 if (catal->children != NULL)
1403 return(-1);
1404
Daniel Veillard81463942001-10-16 12:34:39 +00001405 /*
1406 * lock the whole catalog for modification
1407 */
1408 xmlRMutexLock(xmlCatalogMutex);
1409 if (catal->children != NULL) {
1410 /* Okay someone else did it in the meantime */
1411 xmlRMutexUnlock(xmlCatalogMutex);
1412 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001413 }
1414
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001415 if (xmlCatalogXMLFiles != NULL) {
1416 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001417 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001418 if (doc != NULL) {
1419 if (xmlDebugCatalogs)
1420 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001421 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001422
1423 if (catal->type == XML_CATA_CATALOG)
1424 catal->children = doc->children;
1425 else
1426 catal->children = doc;
1427 catal->dealloc = 0;
1428 xmlRMutexUnlock(xmlCatalogMutex);
1429 return(0);
1430 }
1431 if (xmlDebugCatalogs)
1432 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001433 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001434 }
1435
Daniel Veillardcda96922001-08-21 10:56:31 +00001436 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001437 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001438 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001439 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001440 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001441 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001442 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001443 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001444 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001445 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001446 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001447
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001448 if (catal->type == XML_CATA_CATALOG)
1449 catal->children = doc->children;
1450 else
1451 catal->children = doc;
1452
1453 doc->dealloc = 1;
1454
Daniel Veillard81463942001-10-16 12:34:39 +00001455 if (xmlCatalogXMLFiles == NULL)
1456 xmlCatalogXMLFiles = xmlHashCreate(10);
1457 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001458 if (xmlDebugCatalogs)
1459 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001460 "%s added to file hash\n", catal->URL);
1461 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001462 }
Daniel Veillard81463942001-10-16 12:34:39 +00001463 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001464 return(0);
1465}
1466
Daniel Veillard75b96822001-10-11 18:59:45 +00001467/************************************************************************
1468 * *
1469 * XML Catalog handling *
1470 * *
1471 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001472
1473/**
1474 * xmlAddXMLCatalog:
1475 * @catal: top of an XML catalog
1476 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001477 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001478 * @replace: the replacement value for the match
1479 *
1480 * Add an entry in the XML catalog, it may overwrite existing but
1481 * different entries.
1482 *
1483 * Returns 0 if successful, -1 otherwise
1484 */
1485static int
1486xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1487 const xmlChar *orig, const xmlChar *replace) {
1488 xmlCatalogEntryPtr cur;
1489 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001490 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001491
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001492 if ((catal == NULL) ||
1493 ((catal->type != XML_CATA_CATALOG) &&
1494 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001495 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001496 if (catal->children == NULL) {
1497 xmlFetchXMLCatalogFile(catal);
1498 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001499 if (catal->children == NULL)
1500 doregister = 1;
1501
Daniel Veillard344cee72001-08-20 00:08:40 +00001502 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001503 if (typ == XML_CATA_NONE) {
1504 if (xmlDebugCatalogs)
1505 xmlGenericError(xmlGenericErrorContext,
1506 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001507 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001508 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001509
1510 cur = catal->children;
1511 /*
1512 * Might be a simple "update in place"
1513 */
1514 if (cur != NULL) {
1515 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001516 if ((orig != NULL) && (cur->type == typ) &&
1517 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001518 if (xmlDebugCatalogs)
1519 xmlGenericError(xmlGenericErrorContext,
1520 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001521 if (cur->value != NULL)
1522 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001523 if (cur->URL != NULL)
1524 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001525 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001526 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001527 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001528 }
1529 if (cur->next == NULL)
1530 break;
1531 cur = cur->next;
1532 }
1533 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001534 if (xmlDebugCatalogs)
1535 xmlGenericError(xmlGenericErrorContext,
1536 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001537 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001538 catal->children = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001539 NULL, catal->prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001540 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001541 cur->next = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001542 NULL, catal->prefer, NULL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001543 if (doregister) {
1544 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1545 if (cur != NULL)
1546 cur->children = catal->children;
1547 }
1548
Daniel Veillardcda96922001-08-21 10:56:31 +00001549 return(0);
1550}
1551
1552/**
1553 * xmlDelXMLCatalog:
1554 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001555 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001556 *
1557 * Remove entries in the XML catalog where the value or the URI
1558 * is equal to @value
1559 *
1560 * Returns the number of entries removed if successful, -1 otherwise
1561 */
1562static int
1563xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001564 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001565 int ret = 0;
1566
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001567 if ((catal == NULL) ||
1568 ((catal->type != XML_CATA_CATALOG) &&
1569 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001570 return(-1);
1571 if (value == NULL)
1572 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001573 if (catal->children == NULL) {
1574 xmlFetchXMLCatalogFile(catal);
1575 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001576
1577 /*
1578 * Scan the children
1579 */
1580 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001581 while (cur != NULL) {
1582 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1583 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001584 if (xmlDebugCatalogs) {
1585 if (cur->name != NULL)
1586 xmlGenericError(xmlGenericErrorContext,
1587 "Removing element %s from catalog\n", cur->name);
1588 else
1589 xmlGenericError(xmlGenericErrorContext,
1590 "Removing element %s from catalog\n", cur->value);
1591 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001592 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001593 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001594 cur = cur->next;
1595 }
1596 return(ret);
1597}
1598
1599/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001600 * xmlCatalogXMLResolve:
1601 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001602 * @pubID: the public ID string
1603 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001604 *
1605 * Do a complete resolution lookup of an External Identifier for a
1606 * list of catalog entries.
1607 *
1608 * Implements (or tries to) 7.1. External Identifier Resolution
1609 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1610 *
1611 * Returns the URI of the resource or NULL if not found
1612 */
1613static xmlChar *
1614xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1615 const xmlChar *sysID) {
1616 xmlChar *ret = NULL;
1617 xmlCatalogEntryPtr cur;
1618 int haveDelegate = 0;
1619 int haveNext = 0;
1620
1621 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001622 * protection against loops
1623 */
1624 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001625 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1626 "Detected recursion in catalog %s\n",
1627 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001628 return(NULL);
1629 }
1630 catal->depth++;
1631
1632 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001633 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1634 */
1635 if (sysID != NULL) {
1636 xmlCatalogEntryPtr rewrite = NULL;
1637 int lenrewrite = 0, len;
1638 cur = catal;
1639 haveDelegate = 0;
1640 while (cur != NULL) {
1641 switch (cur->type) {
1642 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001643 if (xmlStrEqual(sysID, cur->name)) {
1644 if (xmlDebugCatalogs)
1645 xmlGenericError(xmlGenericErrorContext,
1646 "Found system match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001647 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001648 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001649 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001650 break;
1651 case XML_CATA_REWRITE_SYSTEM:
1652 len = xmlStrlen(cur->name);
1653 if ((len > lenrewrite) &&
1654 (!xmlStrncmp(sysID, cur->name, len))) {
1655 lenrewrite = len;
1656 rewrite = cur;
1657 }
1658 break;
1659 case XML_CATA_DELEGATE_SYSTEM:
1660 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1661 haveDelegate++;
1662 break;
1663 case XML_CATA_NEXT_CATALOG:
1664 haveNext++;
1665 break;
1666 default:
1667 break;
1668 }
1669 cur = cur->next;
1670 }
1671 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001672 if (xmlDebugCatalogs)
1673 xmlGenericError(xmlGenericErrorContext,
1674 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001675 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001676 if (ret != NULL)
1677 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001678 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001679 return(ret);
1680 }
1681 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001682 const xmlChar *delegates[MAX_DELEGATE];
1683 int nbList = 0, i;
1684
Daniel Veillardcda96922001-08-21 10:56:31 +00001685 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001686 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001687 * matches when the list was produced.
1688 */
1689 cur = catal;
1690 while (cur != NULL) {
1691 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1692 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001693 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001694 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001695 break;
1696 if (i < nbList) {
1697 cur = cur->next;
1698 continue;
1699 }
1700 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001701 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001702
Daniel Veillardcda96922001-08-21 10:56:31 +00001703 if (cur->children == NULL) {
1704 xmlFetchXMLCatalogFile(cur);
1705 }
1706 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001707 if (xmlDebugCatalogs)
1708 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001709 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001710 ret = xmlCatalogListXMLResolve(
1711 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001712 if (ret != NULL) {
1713 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001714 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001715 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001716 }
1717 }
1718 cur = cur->next;
1719 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001720 /*
1721 * Apply the cut algorithm explained in 4/
1722 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001723 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001724 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001725 }
1726 }
1727 /*
1728 * Then tries 5/ 6/ if a public ID is provided
1729 */
1730 if (pubID != NULL) {
1731 cur = catal;
1732 haveDelegate = 0;
1733 while (cur != NULL) {
1734 switch (cur->type) {
1735 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001736 if (xmlStrEqual(pubID, cur->name)) {
1737 if (xmlDebugCatalogs)
1738 xmlGenericError(xmlGenericErrorContext,
1739 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001740 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001741 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001742 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001743 break;
1744 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001745 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1746 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001747 haveDelegate++;
1748 break;
1749 case XML_CATA_NEXT_CATALOG:
1750 if (sysID == NULL)
1751 haveNext++;
1752 break;
1753 default:
1754 break;
1755 }
1756 cur = cur->next;
1757 }
1758 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001759 const xmlChar *delegates[MAX_DELEGATE];
1760 int nbList = 0, i;
1761
Daniel Veillardcda96922001-08-21 10:56:31 +00001762 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001763 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001764 * matches when the list was produced.
1765 */
1766 cur = catal;
1767 while (cur != NULL) {
1768 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001769 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1770 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001771
1772 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001773 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001774 break;
1775 if (i < nbList) {
1776 cur = cur->next;
1777 continue;
1778 }
1779 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001780 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001781
Daniel Veillardcda96922001-08-21 10:56:31 +00001782 if (cur->children == NULL) {
1783 xmlFetchXMLCatalogFile(cur);
1784 }
1785 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001786 if (xmlDebugCatalogs)
1787 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001788 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001789 ret = xmlCatalogListXMLResolve(
1790 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001791 if (ret != NULL) {
1792 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001793 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001794 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001795 }
1796 }
1797 cur = cur->next;
1798 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001799 /*
1800 * Apply the cut algorithm explained in 4/
1801 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001802 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001803 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001804 }
1805 }
1806 if (haveNext) {
1807 cur = catal;
1808 while (cur != NULL) {
1809 if (cur->type == XML_CATA_NEXT_CATALOG) {
1810 if (cur->children == NULL) {
1811 xmlFetchXMLCatalogFile(cur);
1812 }
1813 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001814 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001815 if (ret != NULL) {
1816 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001817 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001818 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001819 }
1820 }
1821 cur = cur->next;
1822 }
1823 }
1824
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001825 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001826 return(NULL);
1827}
1828
1829/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001830 * xmlCatalogXMLResolveURI:
1831 * @catal: a catalog list
1832 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001833 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001834 *
1835 * Do a complete resolution lookup of an External Identifier for a
1836 * list of catalog entries.
1837 *
1838 * Implements (or tries to) 7.2.2. URI Resolution
1839 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1840 *
1841 * Returns the URI of the resource or NULL if not found
1842 */
1843static xmlChar *
1844xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1845 xmlChar *ret = NULL;
1846 xmlCatalogEntryPtr cur;
1847 int haveDelegate = 0;
1848 int haveNext = 0;
1849 xmlCatalogEntryPtr rewrite = NULL;
1850 int lenrewrite = 0, len;
1851
1852 if (catal == NULL)
1853 return(NULL);
1854
1855 if (URI == NULL)
1856 return(NULL);
1857
1858 /*
1859 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1860 */
1861 cur = catal;
1862 haveDelegate = 0;
1863 while (cur != NULL) {
1864 switch (cur->type) {
1865 case XML_CATA_URI:
1866 if (xmlStrEqual(URI, cur->name)) {
1867 if (xmlDebugCatalogs)
1868 xmlGenericError(xmlGenericErrorContext,
1869 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001870 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001871 }
1872 break;
1873 case XML_CATA_REWRITE_URI:
1874 len = xmlStrlen(cur->name);
1875 if ((len > lenrewrite) &&
1876 (!xmlStrncmp(URI, cur->name, len))) {
1877 lenrewrite = len;
1878 rewrite = cur;
1879 }
1880 break;
1881 case XML_CATA_DELEGATE_URI:
1882 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1883 haveDelegate++;
1884 break;
1885 case XML_CATA_NEXT_CATALOG:
1886 haveNext++;
1887 break;
1888 default:
1889 break;
1890 }
1891 cur = cur->next;
1892 }
1893 if (rewrite != NULL) {
1894 if (xmlDebugCatalogs)
1895 xmlGenericError(xmlGenericErrorContext,
1896 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001897 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001898 if (ret != NULL)
1899 ret = xmlStrcat(ret, &URI[lenrewrite]);
1900 return(ret);
1901 }
1902 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001903 const xmlChar *delegates[MAX_DELEGATE];
1904 int nbList = 0, i;
1905
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001906 /*
1907 * Assume the entries have been sorted by decreasing substring
1908 * matches when the list was produced.
1909 */
1910 cur = catal;
1911 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001912 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1913 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001914 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001915 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001916 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001917 break;
1918 if (i < nbList) {
1919 cur = cur->next;
1920 continue;
1921 }
1922 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001923 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001924
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001925 if (cur->children == NULL) {
1926 xmlFetchXMLCatalogFile(cur);
1927 }
1928 if (cur->children != NULL) {
1929 if (xmlDebugCatalogs)
1930 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001931 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001932 ret = xmlCatalogListXMLResolveURI(
1933 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001934 if (ret != NULL)
1935 return(ret);
1936 }
1937 }
1938 cur = cur->next;
1939 }
1940 /*
1941 * Apply the cut algorithm explained in 4/
1942 */
1943 return(XML_CATAL_BREAK);
1944 }
1945 if (haveNext) {
1946 cur = catal;
1947 while (cur != NULL) {
1948 if (cur->type == XML_CATA_NEXT_CATALOG) {
1949 if (cur->children == NULL) {
1950 xmlFetchXMLCatalogFile(cur);
1951 }
1952 if (cur->children != NULL) {
1953 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1954 if (ret != NULL)
1955 return(ret);
1956 }
1957 }
1958 cur = cur->next;
1959 }
1960 }
1961
1962 return(NULL);
1963}
1964
1965/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001966 * xmlCatalogListXMLResolve:
1967 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001968 * @pubID: the public ID string
1969 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001970 *
1971 * Do a complete resolution lookup of an External Identifier for a
1972 * list of catalogs
1973 *
1974 * Implements (or tries to) 7.1. External Identifier Resolution
1975 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1976 *
1977 * Returns the URI of the resource or NULL if not found
1978 */
1979static xmlChar *
1980xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1981 const xmlChar *sysID) {
1982 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001983 xmlChar *urnID = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +00001984 xmlChar *normid;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001985
1986 if (catal == NULL)
1987 return(NULL);
1988 if ((pubID == NULL) && (sysID == NULL))
1989 return(NULL);
1990
Daniel Veillardc8155052004-07-16 09:03:08 +00001991 normid = xmlCatalogNormalizePublic(pubID);
1992 if (normid != NULL)
1993 pubID = (*normid != 0 ? normid : NULL);
1994
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001995 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1996 urnID = xmlCatalogUnWrapURN(pubID);
1997 if (xmlDebugCatalogs) {
1998 if (urnID == NULL)
1999 xmlGenericError(xmlGenericErrorContext,
2000 "Public URN ID %s expanded to NULL\n", pubID);
2001 else
2002 xmlGenericError(xmlGenericErrorContext,
2003 "Public URN ID expanded to %s\n", urnID);
2004 }
2005 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2006 if (urnID != NULL)
2007 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002008 if (normid != NULL)
2009 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002010 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002011 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002012 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2013 urnID = xmlCatalogUnWrapURN(sysID);
2014 if (xmlDebugCatalogs) {
2015 if (urnID == NULL)
2016 xmlGenericError(xmlGenericErrorContext,
2017 "System URN ID %s expanded to NULL\n", sysID);
2018 else
2019 xmlGenericError(xmlGenericErrorContext,
2020 "System URN ID expanded to %s\n", urnID);
2021 }
2022 if (pubID == NULL)
2023 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2024 else if (xmlStrEqual(pubID, urnID))
2025 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2026 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00002027 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002028 }
2029 if (urnID != NULL)
2030 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002031 if (normid != NULL)
2032 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002033 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002034 }
2035 while (catal != NULL) {
2036 if (catal->type == XML_CATA_CATALOG) {
2037 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002038 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00002039 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002040 if (catal->children != NULL) {
2041 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002042 if (ret != NULL) {
2043 if (normid != NULL)
2044 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002045 return(ret);
Daniel Veillardc8155052004-07-16 09:03:08 +00002046 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002047 }
Daniel Veillardcda96922001-08-21 10:56:31 +00002048 }
2049 catal = catal->next;
2050 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002051 if (normid != NULL)
2052 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002053 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00002054}
2055
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002056/**
2057 * xmlCatalogListXMLResolveURI:
2058 * @catal: a catalog list
2059 * @URI: the URI
2060 *
2061 * Do a complete resolution lookup of an URI for a list of catalogs
2062 *
2063 * Implements (or tries to) 7.2. URI Resolution
2064 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2065 *
2066 * Returns the URI of the resource or NULL if not found
2067 */
2068static xmlChar *
2069xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2070 xmlChar *ret = NULL;
2071 xmlChar *urnID = NULL;
2072
2073 if (catal == NULL)
2074 return(NULL);
2075 if (URI == NULL)
2076 return(NULL);
2077
2078 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2079 urnID = xmlCatalogUnWrapURN(URI);
2080 if (xmlDebugCatalogs) {
2081 if (urnID == NULL)
2082 xmlGenericError(xmlGenericErrorContext,
2083 "URN ID %s expanded to NULL\n", URI);
2084 else
2085 xmlGenericError(xmlGenericErrorContext,
2086 "URN ID expanded to %s\n", urnID);
2087 }
2088 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2089 if (urnID != NULL)
2090 xmlFree(urnID);
2091 return(ret);
2092 }
2093 while (catal != NULL) {
2094 if (catal->type == XML_CATA_CATALOG) {
2095 if (catal->children == NULL) {
2096 xmlFetchXMLCatalogFile(catal);
2097 }
2098 if (catal->children != NULL) {
2099 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2100 if (ret != NULL)
2101 return(ret);
2102 }
2103 }
2104 catal = catal->next;
2105 }
2106 return(ret);
2107}
2108
Daniel Veillard344cee72001-08-20 00:08:40 +00002109/************************************************************************
2110 * *
2111 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00002112 * *
2113 ************************************************************************/
2114
2115
2116#define RAW *cur
2117#define NEXT cur++;
2118#define SKIP(x) cur += x;
2119
William M. Brack272693c2003-11-14 16:20:34 +00002120#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002121
Daniel Veillard75b96822001-10-11 18:59:45 +00002122/**
2123 * xmlParseSGMLCatalogComment:
2124 * @cur: the current character
2125 *
2126 * Skip a comment in an SGML catalog
2127 *
2128 * Returns new current character
2129 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002130static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002131xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002132 if ((cur[0] != '-') || (cur[1] != '-'))
2133 return(cur);
2134 SKIP(2);
2135 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2136 NEXT;
2137 if (cur[0] == 0) {
2138 return(NULL);
2139 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002140 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002141}
2142
Daniel Veillard75b96822001-10-11 18:59:45 +00002143/**
2144 * xmlParseSGMLCatalogPubid:
2145 * @cur: the current character
2146 * @id: the return location
2147 *
2148 * Parse an SGML catalog ID
2149 *
2150 * Returns new current character and store the value in @id
2151 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002152static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002153xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002154 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002155 int len = 0;
2156 int size = 50;
2157 xmlChar stop;
2158 int count = 0;
2159
2160 *id = NULL;
2161
2162 if (RAW == '"') {
2163 NEXT;
2164 stop = '"';
2165 } else if (RAW == '\'') {
2166 NEXT;
2167 stop = '\'';
2168 } else {
2169 stop = ' ';
2170 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002171 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002172 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002173 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002174 return(NULL);
2175 }
William M. Brack76e95df2003-10-18 16:20:14 +00002176 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002177 if ((*cur == stop) && (stop != ' '))
2178 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002179 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002180 break;
2181 if (len + 1 >= size) {
2182 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002183 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2184 if (tmp == NULL) {
2185 xmlCatalogErrMemory("allocating public ID");
2186 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002187 return(NULL);
2188 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002189 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002190 }
2191 buf[len++] = *cur;
2192 count++;
2193 NEXT;
2194 }
2195 buf[len] = 0;
2196 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002197 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002198 xmlFree(buf);
2199 return(NULL);
2200 }
2201 } else {
2202 if (*cur != stop) {
2203 xmlFree(buf);
2204 return(NULL);
2205 }
2206 NEXT;
2207 }
2208 *id = buf;
2209 return(cur);
2210}
2211
Daniel Veillard75b96822001-10-11 18:59:45 +00002212/**
2213 * xmlParseSGMLCatalogName:
2214 * @cur: the current character
2215 * @name: the return location
2216 *
2217 * Parse an SGML catalog name
2218 *
2219 * Returns new current character and store the value in @name
2220 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002221static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002222xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002223 xmlChar buf[XML_MAX_NAMELEN + 5];
2224 int len = 0;
2225 int c;
2226
2227 *name = NULL;
2228
2229 /*
2230 * Handler for more complex cases
2231 */
2232 c = *cur;
2233 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2234 return(NULL);
2235 }
2236
2237 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2238 (c == '.') || (c == '-') ||
2239 (c == '_') || (c == ':'))) {
2240 buf[len++] = c;
2241 cur++;
2242 c = *cur;
2243 if (len >= XML_MAX_NAMELEN)
2244 return(NULL);
2245 }
2246 *name = xmlStrndup(buf, len);
2247 return(cur);
2248}
2249
Daniel Veillard75b96822001-10-11 18:59:45 +00002250/**
2251 * xmlGetSGMLCatalogEntryType:
2252 * @name: the entry name
2253 *
2254 * Get the Catalog entry type for a given SGML Catalog name
2255 *
2256 * Returns Catalog entry type
2257 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002258static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002259xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002260 xmlCatalogEntryType type = XML_CATA_NONE;
2261 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2262 type = SGML_CATA_SYSTEM;
2263 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2264 type = SGML_CATA_PUBLIC;
2265 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2266 type = SGML_CATA_DELEGATE;
2267 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2268 type = SGML_CATA_ENTITY;
2269 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2270 type = SGML_CATA_DOCTYPE;
2271 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2272 type = SGML_CATA_LINKTYPE;
2273 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2274 type = SGML_CATA_NOTATION;
2275 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2276 type = SGML_CATA_SGMLDECL;
2277 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2278 type = SGML_CATA_DOCUMENT;
2279 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2280 type = SGML_CATA_CATALOG;
2281 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2282 type = SGML_CATA_BASE;
Daniel Veillard344cee72001-08-20 00:08:40 +00002283 return(type);
2284}
2285
Daniel Veillard75b96822001-10-11 18:59:45 +00002286/**
2287 * xmlParseSGMLCatalog:
2288 * @catal: the SGML Catalog
2289 * @value: the content of the SGML Catalog serialization
2290 * @file: the filepath for the catalog
2291 * @super: should this be handled as a Super Catalog in which case
2292 * parsing is not recursive
2293 *
2294 * Parse an SGML catalog content and fill up the @catal hash table with
2295 * the new entries found.
2296 *
2297 * Returns 0 in case of success, -1 in case of error.
2298 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002299static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002300xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2301 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002302 const xmlChar *cur = value;
2303 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002304 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002305
2306 if ((cur == NULL) || (file == NULL))
2307 return(-1);
2308 base = xmlStrdup((const xmlChar *) file);
2309
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002310 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002311 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002312 if (cur[0] == 0)
2313 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002314 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002315 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002316 if (cur == NULL) {
2317 /* error */
2318 break;
2319 }
2320 } else {
2321 xmlChar *sysid = NULL;
2322 xmlChar *name = NULL;
2323 xmlCatalogEntryType type = XML_CATA_NONE;
2324
Daniel Veillardcda96922001-08-21 10:56:31 +00002325 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002326 if (name == NULL) {
2327 /* error */
2328 break;
2329 }
William M. Brack76e95df2003-10-18 16:20:14 +00002330 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002331 /* error */
2332 break;
2333 }
2334 SKIP_BLANKS;
2335 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002336 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002337 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002338 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002339 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002340 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002341 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002342 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002343 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002344 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002345 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002346 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002347 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002348 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002349 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002350 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002351 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002352 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002353 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002354 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002355 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002356 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002357 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2358 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002359 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002360 if (name == NULL) {
2361 /* error */
2362 break;
2363 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002364 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002365 continue;
2366 }
2367 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002368 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002369
2370 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002371 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002372 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002373 type = SGML_CATA_PENTITY;
2374 case SGML_CATA_PENTITY:
2375 case SGML_CATA_DOCTYPE:
2376 case SGML_CATA_LINKTYPE:
2377 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002378 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002379 if (cur == NULL) {
2380 /* error */
2381 break;
2382 }
William M. Brack76e95df2003-10-18 16:20:14 +00002383 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002384 /* error */
2385 break;
2386 }
2387 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002388 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002389 if (cur == NULL) {
2390 /* error */
2391 break;
2392 }
2393 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002394 case SGML_CATA_PUBLIC:
2395 case SGML_CATA_SYSTEM:
2396 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002397 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002398 if (cur == NULL) {
2399 /* error */
2400 break;
2401 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002402 if (type != SGML_CATA_SYSTEM) {
2403 xmlChar *normid;
2404
2405 normid = xmlCatalogNormalizePublic(name);
2406 if (normid != NULL) {
2407 if (name != NULL)
2408 xmlFree(name);
2409 if (*normid != 0)
2410 name = normid;
2411 else {
2412 xmlFree(normid);
2413 name = NULL;
2414 }
2415 }
2416 }
William M. Brack76e95df2003-10-18 16:20:14 +00002417 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002418 /* error */
2419 break;
2420 }
2421 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002422 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002423 if (cur == NULL) {
2424 /* error */
2425 break;
2426 }
2427 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002428 case SGML_CATA_BASE:
2429 case SGML_CATA_CATALOG:
2430 case SGML_CATA_DOCUMENT:
2431 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002432 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002433 if (cur == NULL) {
2434 /* error */
2435 break;
2436 }
2437 break;
2438 default:
2439 break;
2440 }
2441 if (cur == NULL) {
2442 if (name != NULL)
2443 xmlFree(name);
2444 if (sysid != NULL)
2445 xmlFree(sysid);
2446 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002447 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002448 if (base != NULL)
2449 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002450 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002451 } else if ((type == SGML_CATA_PUBLIC) ||
2452 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002453 xmlChar *filename;
2454
2455 filename = xmlBuildURI(sysid, base);
2456 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002457 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002458
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002459 entry = xmlNewCatalogEntry(type, name, filename,
William M. Brackb7b54de2004-10-06 16:38:01 +00002460 NULL, XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002461 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002462 if (res < 0) {
2463 xmlFreeCatalogEntry(entry);
2464 }
2465 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002466 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002467
Daniel Veillard344cee72001-08-20 00:08:40 +00002468 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002469 if (super) {
2470 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002471
Daniel Veillardc853b322001-11-06 15:24:37 +00002472 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002473 XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002474 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002475 if (res < 0) {
2476 xmlFreeCatalogEntry(entry);
2477 }
2478 } else {
2479 xmlChar *filename;
2480
2481 filename = xmlBuildURI(sysid, base);
2482 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002483 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002484 xmlFree(filename);
2485 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002486 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002487 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002488 /*
2489 * drop anything else we won't handle it
2490 */
2491 if (name != NULL)
2492 xmlFree(name);
2493 if (sysid != NULL)
2494 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002495 }
2496 }
2497 if (base != NULL)
2498 xmlFree(base);
2499 if (cur == NULL)
2500 return(-1);
2501 return(0);
2502}
2503
Daniel Veillard75b96822001-10-11 18:59:45 +00002504/************************************************************************
2505 * *
2506 * SGML Catalog handling *
2507 * *
2508 ************************************************************************/
2509
Daniel Veillardcda96922001-08-21 10:56:31 +00002510/**
2511 * xmlCatalogGetSGMLPublic:
2512 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002513 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002514 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002515 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002516 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002517 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002518 */
2519static const xmlChar *
2520xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2521 xmlCatalogEntryPtr entry;
Daniel Veillardc8155052004-07-16 09:03:08 +00002522 xmlChar *normid;
Daniel Veillardcda96922001-08-21 10:56:31 +00002523
2524 if (catal == NULL)
2525 return(NULL);
2526
Daniel Veillardc8155052004-07-16 09:03:08 +00002527 normid = xmlCatalogNormalizePublic(pubID);
2528 if (normid != NULL)
2529 pubID = (*normid != 0 ? normid : NULL);
2530
Daniel Veillardcda96922001-08-21 10:56:31 +00002531 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002532 if (entry == NULL) {
2533 if (normid != NULL)
2534 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002535 return(NULL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002536 }
2537 if (entry->type == SGML_CATA_PUBLIC) {
2538 if (normid != NULL)
2539 xmlFree(normid);
Daniel Veillardc853b322001-11-06 15:24:37 +00002540 return(entry->URL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002541 }
2542 if (normid != NULL)
2543 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002544 return(NULL);
2545}
2546
2547/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002548 * xmlCatalogGetSGMLSystem:
2549 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002550 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002551 *
2552 * Try to lookup the catalog local reference for a system ID
2553 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002554 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002555 */
2556static const xmlChar *
2557xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2558 xmlCatalogEntryPtr entry;
2559
2560 if (catal == NULL)
2561 return(NULL);
2562
2563 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2564 if (entry == NULL)
2565 return(NULL);
2566 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002567 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002568 return(NULL);
2569}
2570
2571/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002572 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002573 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002574 * @pubID: the public ID string
2575 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002576 *
2577 * Do a complete resolution lookup of an External Identifier
2578 *
2579 * Returns the URI of the resource or NULL if not found
2580 */
2581static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002582xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2583 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002584 const xmlChar *ret = NULL;
2585
Daniel Veillard75b96822001-10-11 18:59:45 +00002586 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002587 return(NULL);
2588
2589 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002590 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002591 if (ret != NULL)
2592 return(ret);
2593 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002594 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002595 return(NULL);
2596}
2597
Daniel Veillarda7374592001-05-10 14:17:55 +00002598/************************************************************************
2599 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002600 * Specific Public interfaces *
2601 * *
2602 ************************************************************************/
2603
2604/**
2605 * xmlLoadSGMLSuperCatalog:
2606 * @filename: a file path
2607 *
2608 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2609 * references. This is only needed for manipulating SGML Super Catalogs
2610 * like adding and removing CATALOG or DELEGATE entries.
2611 *
2612 * Returns the catalog parsed or NULL in case of error
2613 */
2614xmlCatalogPtr
2615xmlLoadSGMLSuperCatalog(const char *filename)
2616{
2617 xmlChar *content;
2618 xmlCatalogPtr catal;
2619 int ret;
2620
2621 content = xmlLoadFileContent(filename);
2622 if (content == NULL)
2623 return(NULL);
2624
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002625 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002626 if (catal == NULL) {
2627 xmlFree(content);
2628 return(NULL);
2629 }
2630
2631 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2632 xmlFree(content);
2633 if (ret < 0) {
2634 xmlFreeCatalog(catal);
2635 return(NULL);
2636 }
2637 return (catal);
2638}
2639
2640/**
2641 * xmlLoadACatalog:
2642 * @filename: a file path
2643 *
2644 * Load the catalog and build the associated data structures.
2645 * This can be either an XML Catalog or an SGML Catalog
2646 * It will recurse in SGML CATALOG entries. On the other hand XML
2647 * Catalogs are not handled recursively.
2648 *
2649 * Returns the catalog parsed or NULL in case of error
2650 */
2651xmlCatalogPtr
2652xmlLoadACatalog(const char *filename)
2653{
2654 xmlChar *content;
2655 xmlChar *first;
2656 xmlCatalogPtr catal;
2657 int ret;
2658
2659 content = xmlLoadFileContent(filename);
2660 if (content == NULL)
2661 return(NULL);
2662
2663
2664 first = content;
2665
2666 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2667 (!(((*first >= 'A') && (*first <= 'Z')) ||
2668 ((*first >= 'a') && (*first <= 'z')))))
2669 first++;
2670
2671 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002672 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002673 if (catal == NULL) {
2674 xmlFree(content);
2675 return(NULL);
2676 }
2677 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2678 if (ret < 0) {
2679 xmlFreeCatalog(catal);
2680 xmlFree(content);
2681 return(NULL);
2682 }
2683 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002684 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002685 if (catal == NULL) {
2686 xmlFree(content);
2687 return(NULL);
2688 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002689 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002690 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002691 }
2692 xmlFree(content);
2693 return (catal);
2694}
2695
2696/**
2697 * xmlExpandCatalog:
2698 * @catal: a catalog
2699 * @filename: a file path
2700 *
2701 * Load the catalog and expand the existing catal structure.
2702 * This can be either an XML Catalog or an SGML Catalog
2703 *
2704 * Returns 0 in case of success, -1 in case of error
2705 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002706static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002707xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2708{
Daniel Veillard75b96822001-10-11 18:59:45 +00002709 int ret;
2710
2711 if ((catal == NULL) || (filename == NULL))
2712 return(-1);
2713
Daniel Veillard75b96822001-10-11 18:59:45 +00002714
2715 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002716 xmlChar *content;
2717
2718 content = xmlLoadFileContent(filename);
2719 if (content == NULL)
2720 return(-1);
2721
Daniel Veillard75b96822001-10-11 18:59:45 +00002722 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2723 if (ret < 0) {
2724 xmlFree(content);
2725 return(-1);
2726 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002727 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002728 } else {
2729 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002730 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002731 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002732
Daniel Veillard75b96822001-10-11 18:59:45 +00002733 cur = catal->xml;
2734 if (cur == NULL) {
2735 catal->xml = tmp;
2736 } else {
2737 while (cur->next != NULL) cur = cur->next;
2738 cur->next = tmp;
2739 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002740 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002741 return (0);
2742}
2743
2744/**
2745 * xmlACatalogResolveSystem:
2746 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002747 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002748 *
2749 * Try to lookup the catalog resource for a system ID
2750 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002751 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002752 * must be freed by the caller.
2753 */
2754xmlChar *
2755xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2756 xmlChar *ret = NULL;
2757
2758 if ((sysID == NULL) || (catal == NULL))
2759 return(NULL);
2760
2761 if (xmlDebugCatalogs)
2762 xmlGenericError(xmlGenericErrorContext,
2763 "Resolve sysID %s\n", sysID);
2764
2765 if (catal->type == XML_XML_CATALOG_TYPE) {
2766 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2767 if (ret == XML_CATAL_BREAK)
2768 ret = NULL;
2769 } else {
2770 const xmlChar *sgml;
2771
2772 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2773 if (sgml != NULL)
2774 ret = xmlStrdup(sgml);
2775 }
2776 return(ret);
2777}
2778
2779/**
2780 * xmlACatalogResolvePublic:
2781 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002782 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002783 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002784 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002785 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002786 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002787 * must be freed by the caller.
2788 */
2789xmlChar *
2790xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2791 xmlChar *ret = NULL;
2792
2793 if ((pubID == NULL) || (catal == NULL))
2794 return(NULL);
2795
2796 if (xmlDebugCatalogs)
2797 xmlGenericError(xmlGenericErrorContext,
2798 "Resolve pubID %s\n", pubID);
2799
2800 if (catal->type == XML_XML_CATALOG_TYPE) {
2801 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2802 if (ret == XML_CATAL_BREAK)
2803 ret = NULL;
2804 } else {
2805 const xmlChar *sgml;
2806
2807 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2808 if (sgml != NULL)
2809 ret = xmlStrdup(sgml);
2810 }
2811 return(ret);
2812}
2813
2814/**
2815 * xmlACatalogResolve:
2816 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002817 * @pubID: the public ID string
2818 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002819 *
2820 * Do a complete resolution lookup of an External Identifier
2821 *
2822 * Returns the URI of the resource or NULL if not found, it must be freed
2823 * by the caller.
2824 */
2825xmlChar *
2826xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2827 const xmlChar * sysID)
2828{
2829 xmlChar *ret = NULL;
2830
2831 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2832 return (NULL);
2833
2834 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002835 if ((pubID != NULL) && (sysID != NULL)) {
2836 xmlGenericError(xmlGenericErrorContext,
2837 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2838 } else if (pubID != NULL) {
2839 xmlGenericError(xmlGenericErrorContext,
2840 "Resolve: pubID %s\n", pubID);
2841 } else {
2842 xmlGenericError(xmlGenericErrorContext,
2843 "Resolve: sysID %s\n", sysID);
2844 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002845 }
2846
2847 if (catal->type == XML_XML_CATALOG_TYPE) {
2848 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2849 if (ret == XML_CATAL_BREAK)
2850 ret = NULL;
2851 } else {
2852 const xmlChar *sgml;
2853
2854 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2855 if (sgml != NULL)
2856 ret = xmlStrdup(sgml);
2857 }
2858 return (ret);
2859}
2860
2861/**
2862 * xmlACatalogResolveURI:
2863 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002864 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002865 *
2866 * Do a complete resolution lookup of an URI
2867 *
2868 * Returns the URI of the resource or NULL if not found, it must be freed
2869 * by the caller.
2870 */
2871xmlChar *
2872xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2873 xmlChar *ret = NULL;
2874
2875 if ((URI == NULL) || (catal == NULL))
2876 return(NULL);
2877
Daniel Veillardb44025c2001-10-11 22:55:55 +00002878 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002879 xmlGenericError(xmlGenericErrorContext,
2880 "Resolve URI %s\n", URI);
2881
2882 if (catal->type == XML_XML_CATALOG_TYPE) {
2883 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2884 if (ret == XML_CATAL_BREAK)
2885 ret = NULL;
2886 } else {
2887 const xmlChar *sgml;
2888
2889 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2890 if (sgml != NULL)
2891 sgml = xmlStrdup(sgml);
2892 }
2893 return(ret);
2894}
2895
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002896#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002897/**
2898 * xmlACatalogDump:
2899 * @catal: a Catalog
2900 * @out: the file.
2901 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002902 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002903 */
2904void
2905xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002906 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002907 return;
2908
2909 if (catal->type == XML_XML_CATALOG_TYPE) {
2910 xmlDumpXMLCatalog(out, catal->xml);
2911 } else {
2912 xmlHashScan(catal->sgml,
2913 (xmlHashScanner) xmlCatalogDumpEntry, out);
2914 }
2915}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002916#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002917
2918/**
2919 * xmlACatalogAdd:
2920 * @catal: a Catalog
2921 * @type: the type of record to add to the catalog
2922 * @orig: the system, public or prefix to match
2923 * @replace: the replacement value for the match
2924 *
2925 * Add an entry in the catalog, it may overwrite existing but
2926 * different entries.
2927 *
2928 * Returns 0 if successful, -1 otherwise
2929 */
2930int
2931xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2932 const xmlChar * orig, const xmlChar * replace)
2933{
2934 int res = -1;
2935
2936 if (catal == NULL)
2937 return(-1);
2938
2939 if (catal->type == XML_XML_CATALOG_TYPE) {
2940 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2941 } else {
2942 xmlCatalogEntryType cattype;
2943
2944 cattype = xmlGetSGMLCatalogEntryType(type);
2945 if (cattype != XML_CATA_NONE) {
2946 xmlCatalogEntryPtr entry;
2947
Daniel Veillardc853b322001-11-06 15:24:37 +00002948 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002949 XML_CATA_PREFER_NONE, NULL);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002950 if (catal->sgml == NULL)
2951 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002952 res = xmlHashAddEntry(catal->sgml, orig, entry);
2953 }
2954 }
2955 return (res);
2956}
2957
2958/**
2959 * xmlACatalogRemove:
2960 * @catal: a Catalog
2961 * @value: the value to remove
2962 *
2963 * Remove an entry from the catalog
2964 *
2965 * Returns the number of entries removed if successful, -1 otherwise
2966 */
2967int
2968xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2969 int res = -1;
2970
2971 if ((catal == NULL) || (value == NULL))
2972 return(-1);
2973
2974 if (catal->type == XML_XML_CATALOG_TYPE) {
2975 res = xmlDelXMLCatalog(catal->xml, value);
2976 } else {
2977 res = xmlHashRemoveEntry(catal->sgml, value,
2978 (xmlHashDeallocator) xmlFreeCatalogEntry);
2979 if (res == 0)
2980 res = 1;
2981 }
2982 return(res);
2983}
2984
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002985/**
2986 * xmlNewCatalog:
2987 * @sgml: should this create an SGML catalog
2988 *
2989 * create a new Catalog.
2990 *
2991 * Returns the xmlCatalogPtr or NULL in case of error
2992 */
2993xmlCatalogPtr
2994xmlNewCatalog(int sgml) {
2995 xmlCatalogPtr catal = NULL;
2996
2997 if (sgml) {
2998 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2999 xmlCatalogDefaultPrefer);
3000 if ((catal != NULL) && (catal->sgml == NULL))
3001 catal->sgml = xmlHashCreate(10);
3002 } else
3003 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3004 xmlCatalogDefaultPrefer);
3005 return(catal);
3006}
3007
3008/**
3009 * xmlCatalogIsEmpty:
3010 * @catal: should this create an SGML catalog
3011 *
3012 * Check is a catalog is empty
3013 *
3014 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3015 */
3016int
3017xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3018 if (catal == NULL)
3019 return(-1);
3020
3021 if (catal->type == XML_XML_CATALOG_TYPE) {
3022 if (catal->xml == NULL)
3023 return(1);
3024 if ((catal->xml->type != XML_CATA_CATALOG) &&
3025 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3026 return(-1);
3027 if (catal->xml->children == NULL)
3028 return(1);
3029 return(0);
3030 } else {
3031 int res;
3032
3033 if (catal->sgml == NULL)
3034 return(1);
3035 res = xmlHashSize(catal->sgml);
3036 if (res == 0)
3037 return(1);
3038 if (res < 0)
3039 return(-1);
3040 }
3041 return(0);
3042}
3043
Daniel Veillard75b96822001-10-11 18:59:45 +00003044/************************************************************************
3045 * *
3046 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00003047 * *
3048 ************************************************************************/
3049
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003050/**
Daniel Veillard81463942001-10-16 12:34:39 +00003051 * xmlInitializeCatalogData:
3052 *
3053 * Do the catalog initialization only of global data, doesn't try to load
3054 * any catalog actually.
3055 * this function is not thread safe, catalog initialization should
3056 * preferably be done once at startup
3057 */
3058static void
3059xmlInitializeCatalogData(void) {
3060 if (xmlCatalogInitialized != 0)
3061 return;
3062
3063 if (getenv("XML_DEBUG_CATALOG"))
3064 xmlDebugCatalogs = 1;
3065 xmlCatalogMutex = xmlNewRMutex();
3066
3067 xmlCatalogInitialized = 1;
3068}
3069/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003070 * xmlInitializeCatalog:
3071 *
3072 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00003073 * this function is not thread safe, catalog initialization should
3074 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003075 */
3076void
3077xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003078 if (xmlCatalogInitialized != 0)
3079 return;
3080
Daniel Veillard81463942001-10-16 12:34:39 +00003081 xmlInitializeCatalogData();
3082 xmlRMutexLock(xmlCatalogMutex);
3083
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003084 if (getenv("XML_DEBUG_CATALOG"))
3085 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00003086
Daniel Veillard75b96822001-10-11 18:59:45 +00003087 if (xmlDefaultCatalog == NULL) {
3088 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003089 char *path;
3090 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00003091 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003092 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00003093
Daniel Veillardb44025c2001-10-11 22:55:55 +00003094 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003095 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003096#if defined(_WIN32) && defined(_MSC_VER)
3097 {
3098 void* hmodule;
3099 hmodule = GetModuleHandleA("libxml2.dll");
3100 if (hmodule == NULL)
3101 hmodule = GetModuleHandleA(NULL);
3102 if (hmodule != NULL) {
3103 char buf[256];
3104 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3105 if (len != 0) {
3106 char* p = &(buf[len]);
3107 while (*p != '\\' && p > buf)
3108 p--;
3109 if (p != buf) {
3110 xmlChar* uri;
3111 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3112 uri = xmlCanonicPath(buf);
3113 if (uri != NULL) {
3114 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3115 xmlFree(uri);
3116 }
3117 }
3118 }
3119 }
3120 catalogs = XML_XML_DEFAULT_CATALOG;
3121 }
3122#else
Daniel Veillard75b96822001-10-11 18:59:45 +00003123 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00003124#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00003125
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003126 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3127 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003128 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003129 /* the XML_CATALOG_FILES envvar is allowed to contain a
3130 space-separated list of entries. */
3131 cur = catalogs;
3132 nextent = &catal->xml;
3133 while (*cur != '\0') {
William M. Brack68aca052003-10-11 15:22:13 +00003134 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003135 cur++;
3136 if (*cur != 0) {
3137 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003138 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003139 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00003140 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003141 if (path != NULL) {
3142 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003143 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003144 if (*nextent != NULL)
3145 nextent = &((*nextent)->next);
3146 xmlFree(path);
3147 }
3148 }
3149 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003150 xmlDefaultCatalog = catal;
3151 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003152 }
3153
Daniel Veillard81463942001-10-16 12:34:39 +00003154 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003155}
3156
Daniel Veillard82d75332001-10-08 15:01:59 +00003157
3158/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003159 * xmlLoadCatalog:
3160 * @filename: a file path
3161 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003162 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003163 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003164 * this function is not thread safe, catalog initialization should
3165 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003166 *
3167 * Returns 0 in case of success -1 in case of error
3168 */
3169int
Daniel Veillard16756b62001-10-01 07:36:25 +00003170xmlLoadCatalog(const char *filename)
3171{
Daniel Veillard75b96822001-10-11 18:59:45 +00003172 int ret;
3173 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003174
Daniel Veillard81463942001-10-16 12:34:39 +00003175 if (!xmlCatalogInitialized)
3176 xmlInitializeCatalogData();
3177
3178 xmlRMutexLock(xmlCatalogMutex);
3179
Daniel Veillard75b96822001-10-11 18:59:45 +00003180 if (xmlDefaultCatalog == NULL) {
3181 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003182 if (catal == NULL) {
3183 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003184 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003185 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003186
Daniel Veillard75b96822001-10-11 18:59:45 +00003187 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003188 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003189 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003190 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003191
Daniel Veillard75b96822001-10-11 18:59:45 +00003192 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003193 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003194 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003195}
3196
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003197/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003198 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003199 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003200 *
3201 * Load the catalogs and makes their definitions effective for the default
3202 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003203 * this function is not thread safe, catalog initialization should
3204 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003205 */
3206void
3207xmlLoadCatalogs(const char *pathss) {
3208 const char *cur;
3209 const char *paths;
3210 xmlChar *path;
3211
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003212 if (pathss == NULL)
3213 return;
3214
Daniel Veillard81418e32001-05-22 15:08:55 +00003215 cur = pathss;
3216 while ((cur != NULL) && (*cur != 0)) {
William M. Brack68aca052003-10-11 15:22:13 +00003217 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003218 if (*cur != 0) {
3219 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003220 while ((*cur != 0) && (*cur != ':') && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003221 cur++;
3222 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3223 if (path != NULL) {
3224 xmlLoadCatalog((const char *) path);
3225 xmlFree(path);
3226 }
3227 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003228 while (*cur == ':')
3229 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003230 }
3231}
3232
Daniel Veillarda7374592001-05-10 14:17:55 +00003233/**
3234 * xmlCatalogCleanup:
3235 *
3236 * Free up all the memory associated with catalogs
3237 */
3238void
3239xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003240 if (xmlCatalogInitialized == 0)
3241 return;
3242
Daniel Veillard81463942001-10-16 12:34:39 +00003243 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003244 if (xmlDebugCatalogs)
3245 xmlGenericError(xmlGenericErrorContext,
3246 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003247 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003248 xmlHashFree(xmlCatalogXMLFiles,
3249 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003250 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003251 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003252 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003253 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003254 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003255 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003256 xmlRMutexUnlock(xmlCatalogMutex);
3257 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003258}
3259
3260/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003261 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003262 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003263 *
3264 * Try to lookup the catalog resource for a system ID
3265 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003266 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003267 * must be freed by the caller.
3268 */
3269xmlChar *
3270xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003271 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003272
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003273 if (!xmlCatalogInitialized)
3274 xmlInitializeCatalog();
3275
Daniel Veillard75b96822001-10-11 18:59:45 +00003276 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3277 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003278}
3279
3280/**
3281 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003282 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003283 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003284 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003285 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003286 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003287 * must be freed by the caller.
3288 */
3289xmlChar *
3290xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003291 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003292
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003293 if (!xmlCatalogInitialized)
3294 xmlInitializeCatalog();
3295
Daniel Veillard75b96822001-10-11 18:59:45 +00003296 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3297 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003298}
Daniel Veillard344cee72001-08-20 00:08:40 +00003299
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003300/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003301 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003302 * @pubID: the public ID string
3303 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003304 *
3305 * Do a complete resolution lookup of an External Identifier
3306 *
3307 * Returns the URI of the resource or NULL if not found, it must be freed
3308 * by the caller.
3309 */
3310xmlChar *
3311xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003312 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003313
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003314 if (!xmlCatalogInitialized)
3315 xmlInitializeCatalog();
3316
Daniel Veillard75b96822001-10-11 18:59:45 +00003317 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3318 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003319}
3320
3321/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003322 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003323 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003324 *
3325 * Do a complete resolution lookup of an URI
3326 *
3327 * Returns the URI of the resource or NULL if not found, it must be freed
3328 * by the caller.
3329 */
3330xmlChar *
3331xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003332 xmlChar *ret;
3333
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003334 if (!xmlCatalogInitialized)
3335 xmlInitializeCatalog();
3336
Daniel Veillard75b96822001-10-11 18:59:45 +00003337 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3338 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003339}
3340
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003341#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003342/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003343 * xmlCatalogDump:
3344 * @out: the file.
3345 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003346 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003347 */
3348void
3349xmlCatalogDump(FILE *out) {
3350 if (out == NULL)
3351 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003352
Daniel Veillard75b96822001-10-11 18:59:45 +00003353 if (!xmlCatalogInitialized)
3354 xmlInitializeCatalog();
3355
3356 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003357}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003358#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003359
3360/**
3361 * xmlCatalogAdd:
3362 * @type: the type of record to add to the catalog
3363 * @orig: the system, public or prefix to match
3364 * @replace: the replacement value for the match
3365 *
3366 * Add an entry in the catalog, it may overwrite existing but
3367 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003368 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003369 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003370 *
3371 * Returns 0 if successful, -1 otherwise
3372 */
3373int
3374xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3375 int res = -1;
3376
Daniel Veillard81463942001-10-16 12:34:39 +00003377 if (!xmlCatalogInitialized)
3378 xmlInitializeCatalogData();
3379
3380 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003381 /*
3382 * Specific case where one want to override the default catalog
3383 * put in place by xmlInitializeCatalog();
3384 */
3385 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003386 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003387 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003388 xmlCatalogDefaultPrefer);
3389 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003390 orig, NULL, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003391
Daniel Veillard81463942001-10-16 12:34:39 +00003392 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003393 return(0);
3394 }
3395
Daniel Veillard75b96822001-10-11 18:59:45 +00003396 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003397 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003398 return(res);
3399}
3400
3401/**
3402 * xmlCatalogRemove:
3403 * @value: the value to remove
3404 *
3405 * Remove an entry from the catalog
3406 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003407 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003408 */
3409int
3410xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003411 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003412
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003413 if (!xmlCatalogInitialized)
3414 xmlInitializeCatalog();
3415
Daniel Veillard81463942001-10-16 12:34:39 +00003416 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003417 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003418 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003419 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003420}
3421
3422/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003423 * xmlCatalogConvert:
3424 *
3425 * Convert all the SGML catalog entries as XML ones
3426 *
3427 * Returns the number of entries converted if successful, -1 otherwise
3428 */
3429int
3430xmlCatalogConvert(void) {
3431 int res = -1;
3432
3433 if (!xmlCatalogInitialized)
3434 xmlInitializeCatalog();
3435
Daniel Veillard81463942001-10-16 12:34:39 +00003436 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003437 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003438 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003439 return(res);
3440}
3441
Daniel Veillard75b96822001-10-11 18:59:45 +00003442/************************************************************************
3443 * *
3444 * Public interface manipulating the common preferences *
3445 * *
3446 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003447
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003448/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003449 * xmlCatalogGetDefaults:
3450 *
3451 * Used to get the user preference w.r.t. to what catalogs should
3452 * be accepted
3453 *
3454 * Returns the current xmlCatalogAllow value
3455 */
3456xmlCatalogAllow
3457xmlCatalogGetDefaults(void) {
3458 return(xmlCatalogDefaultAllow);
3459}
3460
3461/**
3462 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003463 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003464 *
3465 * Used to set the user preference w.r.t. to what catalogs should
3466 * be accepted
3467 */
3468void
3469xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003470 if (xmlDebugCatalogs) {
3471 switch (allow) {
3472 case XML_CATA_ALLOW_NONE:
3473 xmlGenericError(xmlGenericErrorContext,
3474 "Disabling catalog usage\n");
3475 break;
3476 case XML_CATA_ALLOW_GLOBAL:
3477 xmlGenericError(xmlGenericErrorContext,
3478 "Allowing only global catalogs\n");
3479 break;
3480 case XML_CATA_ALLOW_DOCUMENT:
3481 xmlGenericError(xmlGenericErrorContext,
3482 "Allowing only catalogs from the document\n");
3483 break;
3484 case XML_CATA_ALLOW_ALL:
3485 xmlGenericError(xmlGenericErrorContext,
3486 "Allowing all catalogs\n");
3487 break;
3488 }
3489 }
3490 xmlCatalogDefaultAllow = allow;
3491}
3492
3493/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003494 * xmlCatalogSetDefaultPrefer:
3495 * @prefer: the default preference for delegation
3496 *
3497 * Allows to set the preference between public and system for deletion
3498 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003499 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003500 *
3501 * Returns the previous value of the default preference for delegation
3502 */
3503xmlCatalogPrefer
3504xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3505 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3506
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003507 if (prefer == XML_CATA_PREFER_NONE)
3508 return(ret);
3509
3510 if (xmlDebugCatalogs) {
3511 switch (prefer) {
3512 case XML_CATA_PREFER_PUBLIC:
3513 xmlGenericError(xmlGenericErrorContext,
3514 "Setting catalog preference to PUBLIC\n");
3515 break;
3516 case XML_CATA_PREFER_SYSTEM:
3517 xmlGenericError(xmlGenericErrorContext,
3518 "Setting catalog preference to SYSTEM\n");
3519 break;
3520 case XML_CATA_PREFER_NONE:
3521 break;
3522 }
3523 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003524 xmlCatalogDefaultPrefer = prefer;
3525 return(ret);
3526}
3527
3528/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003529 * xmlCatalogSetDebug:
3530 * @level: the debug level of catalogs required
3531 *
3532 * Used to set the debug level for catalog operation, 0 disable
3533 * debugging, 1 enable it
3534 *
3535 * Returns the previous value of the catalog debugging level
3536 */
3537int
3538xmlCatalogSetDebug(int level) {
3539 int ret = xmlDebugCatalogs;
3540
3541 if (level <= 0)
3542 xmlDebugCatalogs = 0;
3543 else
3544 xmlDebugCatalogs = level;
3545 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003546}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003547
Daniel Veillard75b96822001-10-11 18:59:45 +00003548/************************************************************************
3549 * *
3550 * Minimal interfaces used for per-document catalogs by the parser *
3551 * *
3552 ************************************************************************/
3553
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003554/**
3555 * xmlCatalogFreeLocal:
3556 * @catalogs: a document's list of catalogs
3557 *
3558 * Free up the memory associated to the catalog list
3559 */
3560void
3561xmlCatalogFreeLocal(void *catalogs) {
3562 xmlCatalogEntryPtr catal;
3563
Daniel Veillard81463942001-10-16 12:34:39 +00003564 if (!xmlCatalogInitialized)
3565 xmlInitializeCatalog();
3566
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003567 catal = (xmlCatalogEntryPtr) catalogs;
3568 if (catal != NULL)
3569 xmlFreeCatalogEntryList(catal);
3570}
3571
3572
3573/**
3574 * xmlCatalogAddLocal:
3575 * @catalogs: a document's list of catalogs
3576 * @URL: the URL to a new local catalog
3577 *
3578 * Add the new entry to the catalog list
3579 *
3580 * Returns the updated list
3581 */
3582void *
3583xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3584 xmlCatalogEntryPtr catal, add;
3585
3586 if (!xmlCatalogInitialized)
3587 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003588
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003589 if (URL == NULL)
3590 return(catalogs);
3591
3592 if (xmlDebugCatalogs)
3593 xmlGenericError(xmlGenericErrorContext,
3594 "Adding document catalog %s\n", URL);
3595
Daniel Veillardc853b322001-11-06 15:24:37 +00003596 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003597 xmlCatalogDefaultPrefer, NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003598 if (add == NULL)
3599 return(catalogs);
3600
3601 catal = (xmlCatalogEntryPtr) catalogs;
3602 if (catal == NULL)
3603 return((void *) add);
3604
3605 while (catal->next != NULL)
3606 catal = catal->next;
3607 catal->next = add;
3608 return(catalogs);
3609}
3610
3611/**
3612 * xmlCatalogLocalResolve:
3613 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003614 * @pubID: the public ID string
3615 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003616 *
3617 * Do a complete resolution lookup of an External Identifier using a
3618 * document's private catalog list
3619 *
3620 * Returns the URI of the resource or NULL if not found, it must be freed
3621 * by the caller.
3622 */
3623xmlChar *
3624xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3625 const xmlChar *sysID) {
3626 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003627 xmlChar *ret;
3628
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003629 if (!xmlCatalogInitialized)
3630 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003631
Daniel Veillard81463942001-10-16 12:34:39 +00003632 if ((pubID == NULL) && (sysID == NULL))
3633 return(NULL);
3634
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003635 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003636 if ((pubID != NULL) && (sysID != NULL)) {
3637 xmlGenericError(xmlGenericErrorContext,
3638 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3639 } else if (pubID != NULL) {
3640 xmlGenericError(xmlGenericErrorContext,
3641 "Local Resolve: pubID %s\n", pubID);
3642 } else {
3643 xmlGenericError(xmlGenericErrorContext,
3644 "Local Resolve: sysID %s\n", sysID);
3645 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003646 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003647
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003648 catal = (xmlCatalogEntryPtr) catalogs;
3649 if (catal == NULL)
3650 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003651 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3652 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3653 return(ret);
3654 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003655}
3656
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003657/**
3658 * xmlCatalogLocalResolveURI:
3659 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003660 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003661 *
3662 * Do a complete resolution lookup of an URI using a
3663 * document's private catalog list
3664 *
3665 * Returns the URI of the resource or NULL if not found, it must be freed
3666 * by the caller.
3667 */
3668xmlChar *
3669xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3670 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003671 xmlChar *ret;
3672
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003673 if (!xmlCatalogInitialized)
3674 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003675
Daniel Veillard81463942001-10-16 12:34:39 +00003676 if (URI == NULL)
3677 return(NULL);
3678
Daniel Veillard6990bf32001-08-23 21:17:48 +00003679 if (xmlDebugCatalogs)
3680 xmlGenericError(xmlGenericErrorContext,
3681 "Resolve URI %s\n", URI);
3682
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003683 catal = (xmlCatalogEntryPtr) catalogs;
3684 if (catal == NULL)
3685 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003686 ret = xmlCatalogListXMLResolveURI(catal, URI);
3687 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3688 return(ret);
3689 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003690}
3691
Daniel Veillard75b96822001-10-11 18:59:45 +00003692/************************************************************************
3693 * *
3694 * Deprecated interfaces *
3695 * *
3696 ************************************************************************/
3697/**
3698 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003699 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003700 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003701 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003702 * DEPRECATED, use xmlCatalogResolveSystem()
3703 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003704 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003705 */
3706const xmlChar *
3707xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003708 xmlChar *ret;
3709 static xmlChar result[1000];
3710 static int msg = 0;
3711
3712 if (!xmlCatalogInitialized)
3713 xmlInitializeCatalog();
3714
3715 if (msg == 0) {
3716 xmlGenericError(xmlGenericErrorContext,
3717 "Use of deprecated xmlCatalogGetSystem() call\n");
3718 msg++;
3719 }
3720
3721 if (sysID == NULL)
3722 return(NULL);
3723
3724 /*
3725 * Check first the XML catalogs
3726 */
3727 if (xmlDefaultCatalog != NULL) {
3728 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3729 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3730 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3731 result[sizeof(result) - 1] = 0;
3732 return(result);
3733 }
3734 }
3735
3736 if (xmlDefaultCatalog != NULL)
3737 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3738 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003739}
3740
3741/**
3742 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003743 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003744 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003745 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003746 * DEPRECATED, use xmlCatalogResolvePublic()
3747 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003748 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003749 */
3750const xmlChar *
3751xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003752 xmlChar *ret;
3753 static xmlChar result[1000];
3754 static int msg = 0;
3755
3756 if (!xmlCatalogInitialized)
3757 xmlInitializeCatalog();
3758
3759 if (msg == 0) {
3760 xmlGenericError(xmlGenericErrorContext,
3761 "Use of deprecated xmlCatalogGetPublic() call\n");
3762 msg++;
3763 }
3764
3765 if (pubID == NULL)
3766 return(NULL);
3767
3768 /*
3769 * Check first the XML catalogs
3770 */
3771 if (xmlDefaultCatalog != NULL) {
3772 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3773 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3774 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3775 result[sizeof(result) - 1] = 0;
3776 return(result);
3777 }
3778 }
3779
3780 if (xmlDefaultCatalog != NULL)
3781 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3782 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003783}
3784
Daniel Veillarda7374592001-05-10 14:17:55 +00003785#endif /* LIBXML_CATALOG_ENABLED */