blob: 06dbb52e5ab7ccefdea51e424315182660271cf1 [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 Veillard85c11fa2001-10-16 21:03:08 +000071static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000072
Daniel Veillarda7374592001-05-10 14:17:55 +000073/************************************************************************
74 * *
75 * Types, all private *
76 * *
77 ************************************************************************/
78
79typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000080 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000081 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000082 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000083 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000084 XML_CATA_NEXT_CATALOG,
85 XML_CATA_PUBLIC,
86 XML_CATA_SYSTEM,
87 XML_CATA_REWRITE_SYSTEM,
88 XML_CATA_DELEGATE_PUBLIC,
89 XML_CATA_DELEGATE_SYSTEM,
90 XML_CATA_URI,
91 XML_CATA_REWRITE_URI,
92 XML_CATA_DELEGATE_URI,
93 SGML_CATA_SYSTEM,
94 SGML_CATA_PUBLIC,
95 SGML_CATA_ENTITY,
96 SGML_CATA_PENTITY,
97 SGML_CATA_DOCTYPE,
98 SGML_CATA_LINKTYPE,
99 SGML_CATA_NOTATION,
100 SGML_CATA_DELEGATE,
101 SGML_CATA_BASE,
102 SGML_CATA_CATALOG,
103 SGML_CATA_DOCUMENT,
104 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000105} xmlCatalogEntryType;
106
107typedef struct _xmlCatalogEntry xmlCatalogEntry;
108typedef xmlCatalogEntry *xmlCatalogEntryPtr;
109struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000110 struct _xmlCatalogEntry *next;
111 struct _xmlCatalogEntry *parent;
112 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000113 xmlCatalogEntryType type;
114 xmlChar *name;
115 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000116 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000117 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000118 int dealloc;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000119 int depth;
Daniel Veillarda7374592001-05-10 14:17:55 +0000120};
121
Daniel Veillard75b96822001-10-11 18:59:45 +0000122typedef enum {
123 XML_XML_CATALOG_TYPE = 1,
124 XML_SGML_CATALOG_TYPE
125} xmlCatalogType;
126
127#define XML_MAX_SGML_CATA_DEPTH 10
128struct _xmlCatalog {
129 xmlCatalogType type; /* either XML or SGML */
130
131 /*
132 * SGML Catalogs are stored as a simple hash table of catalog entries
133 * Catalog stack to check against overflows when building the
134 * SGML catalog
135 */
136 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
137 int catalNr; /* Number of current catal streams */
138 int catalMax; /* Max number of catal streams */
139 xmlHashTablePtr sgml;
140
141 /*
142 * XML Catalogs are stored as a tree of Catalog entries
143 */
144 xmlCatalogPrefer prefer;
145 xmlCatalogEntryPtr xml;
146};
147
148/************************************************************************
149 * *
150 * Global variables *
151 * *
152 ************************************************************************/
153
Daniel Veillard81463942001-10-16 12:34:39 +0000154/*
155 * Those are preferences
156 */
157static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000158static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000159static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000160
161/*
162 * Hash table containing all the trees of XML catalogs parsed by
163 * the application.
164 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000165static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000166
167/*
168 * The default catalog in use by the application
169 */
170static xmlCatalogPtr xmlDefaultCatalog = NULL;
171
172/*
Daniel Veillard81463942001-10-16 12:34:39 +0000173 * A mutex for modifying the shared global catalog(s)
174 * xmlDefaultCatalog tree.
175 * It also protects xmlCatalogXMLFiles
176 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
177 */
178static xmlRMutexPtr xmlCatalogMutex = NULL;
179
180/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000181 * Whether the catalog support was initialized.
182 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000183static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000184
Daniel Veillard69d2c172003-10-09 11:46:07 +0000185/************************************************************************
186 * *
187 * Catalog error handlers *
188 * *
189 ************************************************************************/
190
191/**
192 * xmlCatalogErrMemory:
193 * @extra: extra informations
194 *
195 * Handle an out of memory condition
196 */
197static void
198xmlCatalogErrMemory(const char *extra)
199{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000200 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000201 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
202 extra, NULL, NULL, 0, 0,
203 "Memory allocation failed : %s\n", extra);
204}
205
206/**
207 * xmlCatalogErr:
208 * @catal: the Catalog entry
209 * @node: the context node
210 * @msg: the error message
211 * @extra: extra informations
212 *
213 * Handle a catalog error
214 */
215static void
216xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
217 const char *msg, const xmlChar *str1, const xmlChar *str2,
218 const xmlChar *str3)
219{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000220 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000221 error, XML_ERR_ERROR, NULL, 0,
222 (const char *) str1, (const char *) str2,
223 (const char *) str3, 0, 0,
224 msg, str1, str2, str3);
225}
226
Daniel Veillarda7374592001-05-10 14:17:55 +0000227
228/************************************************************************
229 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000230 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000231 * *
232 ************************************************************************/
233
Daniel Veillard75b96822001-10-11 18:59:45 +0000234/**
235 * xmlNewCatalogEntry:
236 * @type: type of entry
237 * @name: name of the entry
238 * @value: value of the entry
239 * @prefer: the PUBLIC vs. SYSTEM current preference value
240 *
241 * create a new Catalog entry, this type is shared both by XML and
242 * SGML catalogs, but the acceptable types values differs.
243 *
244 * Returns the xmlCatalogEntryPtr or NULL in case of error
245 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000246static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000247xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillardc853b322001-11-06 15:24:37 +0000248 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000249 xmlCatalogEntryPtr ret;
250
251 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
252 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000253 xmlCatalogErrMemory("allocating catalog entry");
Daniel Veillarda7374592001-05-10 14:17:55 +0000254 return(NULL);
255 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000256 ret->next = NULL;
257 ret->parent = NULL;
258 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000259 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000260 if (name != NULL)
261 ret->name = xmlStrdup(name);
262 else
263 ret->name = NULL;
264 if (value != NULL)
265 ret->value = xmlStrdup(value);
266 else
267 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000268 if (URL == NULL)
269 URL = value;
270 if (URL != NULL)
271 ret->URL = xmlStrdup(URL);
272 else
273 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000274 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000275 ret->dealloc = 0;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000276 ret->depth = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +0000277 return(ret);
278}
279
280static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000281xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
282
Daniel Veillard75b96822001-10-11 18:59:45 +0000283/**
284 * xmlFreeCatalogEntry:
285 * @ret: a Catalog entry
286 *
287 * Free the memory allocated to a Catalog entry
288 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000289static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000290xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
291 if (ret == NULL)
292 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000293 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000294 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000295 * only by the file hash cleaner !
296 */
297 if (ret->dealloc == 1)
298 return;
299
300 if (xmlDebugCatalogs) {
301 if (ret->name != NULL)
302 xmlGenericError(xmlGenericErrorContext,
303 "Free catalog entry %s\n", ret->name);
304 else if (ret->value != NULL)
305 xmlGenericError(xmlGenericErrorContext,
306 "Free catalog entry %s\n", ret->value);
307 else
308 xmlGenericError(xmlGenericErrorContext,
309 "Free catalog entry\n");
310 }
311
Daniel Veillarda7374592001-05-10 14:17:55 +0000312 if (ret->name != NULL)
313 xmlFree(ret->name);
314 if (ret->value != NULL)
315 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000316 if (ret->URL != NULL)
317 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000318 xmlFree(ret);
319}
320
Daniel Veillard75b96822001-10-11 18:59:45 +0000321/**
322 * xmlFreeCatalogEntryList:
323 * @ret: a Catalog entry list
324 *
325 * Free the memory allocated to a full chained list of Catalog entries
326 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000327static void
328xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
329 xmlCatalogEntryPtr next;
330
331 while (ret != NULL) {
332 next = ret->next;
333 xmlFreeCatalogEntry(ret);
334 ret = next;
335 }
336}
337
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000338/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000339 * xmlFreeCatalogHashEntryList:
340 * @ret: a Catalog entry list
341 *
342 * Free the memory allocated to list of Catalog entries from the
343 * catalog file hash.
344 */
345static void
346xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
347 xmlCatalogEntryPtr children, next;
348
349 if (catal == NULL)
350 return;
351
352 children = catal->children;
353 while (children != NULL) {
354 next = children->next;
355 children->dealloc = 0;
356 children->children = NULL;
357 xmlFreeCatalogEntry(children);
358 children = next;
359 }
360 catal->dealloc = 0;
361 xmlFreeCatalogEntry(catal);
362}
363
364/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000365 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000366 * @type: type of catalog
367 * @prefer: the PUBLIC vs. SYSTEM current preference value
368 *
369 * create a new Catalog, this type is shared both by XML and
370 * SGML catalogs, but the acceptable types values differs.
371 *
372 * Returns the xmlCatalogPtr or NULL in case of error
373 */
374static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000375xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000376 xmlCatalogPtr ret;
377
378 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
379 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000380 xmlCatalogErrMemory("allocating catalog");
Daniel Veillard75b96822001-10-11 18:59:45 +0000381 return(NULL);
382 }
383 memset(ret, 0, sizeof(xmlCatalog));
384 ret->type = type;
385 ret->catalNr = 0;
386 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
387 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000388 if (ret->type == XML_SGML_CATALOG_TYPE)
389 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000390 return(ret);
391}
392
393/**
394 * xmlFreeCatalog:
395 * @catal: a Catalog entry
396 *
397 * Free the memory allocated to a Catalog
398 */
399void
400xmlFreeCatalog(xmlCatalogPtr catal) {
401 if (catal == NULL)
402 return;
403 if (catal->xml != NULL)
404 xmlFreeCatalogEntryList(catal->xml);
405 if (catal->sgml != NULL)
406 xmlHashFree(catal->sgml,
407 (xmlHashDeallocator) xmlFreeCatalogEntry);
408 xmlFree(catal);
409}
410
411/************************************************************************
412 * *
413 * Serializing Catalogs *
414 * *
415 ************************************************************************/
416
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000417#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000418/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000419 * xmlCatalogDumpEntry:
420 * @entry: the
421 * @out: the file.
422 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000423 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000424 */
425static void
426xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
427 if ((entry == NULL) || (out == NULL))
428 return;
429 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000430 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000431 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000432 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000433 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000434 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000435 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000436 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000437 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000438 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000439 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000440 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000441 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000442 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000443 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000444 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000445 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000446 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000447 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000448 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000449 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000450 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000451 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000452 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000453 fprintf(out, "SGMLDECL "); break;
454 default:
455 return;
456 }
457 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000458 case SGML_CATA_ENTITY:
459 case SGML_CATA_PENTITY:
460 case SGML_CATA_DOCTYPE:
461 case SGML_CATA_LINKTYPE:
462 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000463 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000464 case SGML_CATA_PUBLIC:
465 case SGML_CATA_SYSTEM:
466 case SGML_CATA_SGMLDECL:
467 case SGML_CATA_DOCUMENT:
468 case SGML_CATA_CATALOG:
469 case SGML_CATA_BASE:
470 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000471 fprintf(out, "\"%s\"", entry->name); break;
472 default:
473 break;
474 }
475 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000476 case SGML_CATA_ENTITY:
477 case SGML_CATA_PENTITY:
478 case SGML_CATA_DOCTYPE:
479 case SGML_CATA_LINKTYPE:
480 case SGML_CATA_NOTATION:
481 case SGML_CATA_PUBLIC:
482 case SGML_CATA_SYSTEM:
483 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000484 fprintf(out, " \"%s\"", entry->value); break;
485 default:
486 break;
487 }
488 fprintf(out, "\n");
489}
490
Daniel Veillard75b96822001-10-11 18:59:45 +0000491static int
492xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
493 int ret;
494 xmlDocPtr doc;
495 xmlNsPtr ns;
496 xmlDtdPtr dtd;
497 xmlNodePtr node, catalog;
498 xmlOutputBufferPtr buf;
499 xmlCatalogEntryPtr cur;
500
501 /*
502 * Rebuild a catalog
503 */
504 doc = xmlNewDoc(NULL);
505 if (doc == NULL)
506 return(-1);
507 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
508 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
509BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
510
511 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
512
513 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
514 if (ns == NULL) {
515 xmlFreeDoc(doc);
516 return(-1);
517 }
518 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
519 if (catalog == NULL) {
520 xmlFreeNs(ns);
521 xmlFreeDoc(doc);
522 return(-1);
523 }
524 catalog->nsDef = ns;
525 xmlAddChild((xmlNodePtr) doc, catalog);
526
527 /*
528 * add all the catalog entries
529 */
530 cur = catal;
531 while (cur != NULL) {
532 switch (cur->type) {
Daniel Veillardc853b322001-11-06 15:24:37 +0000533 case XML_CATA_REMOVED:
534 break;
Daniel Veillard75b96822001-10-11 18:59:45 +0000535 case XML_CATA_BROKEN_CATALOG:
536 case XML_CATA_CATALOG:
537 if (cur == catal) {
538 cur = cur->children;
539 continue;
540 }
541 break;
542 case XML_CATA_NEXT_CATALOG:
543 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
544 xmlSetProp(node, BAD_CAST "catalog", cur->value);
545 xmlAddChild(catalog, node);
546 break;
547 case XML_CATA_NONE:
548 break;
549 case XML_CATA_PUBLIC:
550 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
551 xmlSetProp(node, BAD_CAST "publicId", cur->name);
552 xmlSetProp(node, BAD_CAST "uri", cur->value);
553 xmlAddChild(catalog, node);
554 break;
555 case XML_CATA_SYSTEM:
556 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
557 xmlSetProp(node, BAD_CAST "systemId", cur->name);
558 xmlSetProp(node, BAD_CAST "uri", cur->value);
559 xmlAddChild(catalog, node);
560 break;
561 case XML_CATA_REWRITE_SYSTEM:
562 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
563 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
564 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
565 xmlAddChild(catalog, node);
566 break;
567 case XML_CATA_DELEGATE_PUBLIC:
568 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
569 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
570 xmlSetProp(node, BAD_CAST "catalog", cur->value);
571 xmlAddChild(catalog, node);
572 break;
573 case XML_CATA_DELEGATE_SYSTEM:
574 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
575 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
576 xmlSetProp(node, BAD_CAST "catalog", cur->value);
577 xmlAddChild(catalog, node);
578 break;
579 case XML_CATA_URI:
580 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
581 xmlSetProp(node, BAD_CAST "name", cur->name);
582 xmlSetProp(node, BAD_CAST "uri", cur->value);
583 xmlAddChild(catalog, node);
584 break;
585 case XML_CATA_REWRITE_URI:
586 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
587 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
588 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
589 xmlAddChild(catalog, node);
590 break;
591 case XML_CATA_DELEGATE_URI:
592 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
593 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
594 xmlSetProp(node, BAD_CAST "catalog", cur->value);
595 xmlAddChild(catalog, node);
596 break;
597 case SGML_CATA_SYSTEM:
598 case SGML_CATA_PUBLIC:
599 case SGML_CATA_ENTITY:
600 case SGML_CATA_PENTITY:
601 case SGML_CATA_DOCTYPE:
602 case SGML_CATA_LINKTYPE:
603 case SGML_CATA_NOTATION:
604 case SGML_CATA_DELEGATE:
605 case SGML_CATA_BASE:
606 case SGML_CATA_CATALOG:
607 case SGML_CATA_DOCUMENT:
608 case SGML_CATA_SGMLDECL:
609 break;
610 }
611 cur = cur->next;
612 }
613
614 /*
615 * reserialize it
616 */
617 buf = xmlOutputBufferCreateFile(out, NULL);
618 if (buf == NULL) {
619 xmlFreeDoc(doc);
620 return(-1);
621 }
622 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
623
624 /*
625 * Free it
626 */
627 xmlFreeDoc(doc);
628
629 return(ret);
630}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000631#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000632
633/************************************************************************
634 * *
635 * Converting SGML Catalogs to XML *
636 * *
637 ************************************************************************/
638
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000639/**
640 * xmlCatalogConvertEntry:
641 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000642 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000643 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000644 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000645 */
646static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000647xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
648 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
649 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000650 return;
651 switch (entry->type) {
652 case SGML_CATA_ENTITY:
653 entry->type = XML_CATA_PUBLIC;
654 break;
655 case SGML_CATA_PENTITY:
656 entry->type = XML_CATA_PUBLIC;
657 break;
658 case SGML_CATA_DOCTYPE:
659 entry->type = XML_CATA_PUBLIC;
660 break;
661 case SGML_CATA_LINKTYPE:
662 entry->type = XML_CATA_PUBLIC;
663 break;
664 case SGML_CATA_NOTATION:
665 entry->type = XML_CATA_PUBLIC;
666 break;
667 case SGML_CATA_PUBLIC:
668 entry->type = XML_CATA_PUBLIC;
669 break;
670 case SGML_CATA_SYSTEM:
671 entry->type = XML_CATA_SYSTEM;
672 break;
673 case SGML_CATA_DELEGATE:
674 entry->type = XML_CATA_DELEGATE_PUBLIC;
675 break;
676 case SGML_CATA_CATALOG:
677 entry->type = XML_CATA_CATALOG;
678 break;
679 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000680 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000681 (xmlHashDeallocator) xmlFreeCatalogEntry);
682 return;
683 }
684 /*
685 * Conversion successful, remove from the SGML catalog
686 * and add it to the default XML one
687 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000688 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
689 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000690 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000691 if (catal->xml->children == NULL)
692 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000693 else {
694 xmlCatalogEntryPtr prev;
695
Daniel Veillard75b96822001-10-11 18:59:45 +0000696 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000697 while (prev->next != NULL)
698 prev = prev->next;
699 prev->next = entry;
700 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000701}
702
703/**
704 * xmlConvertSGMLCatalog:
705 * @catal: the catalog
706 *
707 * Convert all the SGML catalog entries as XML ones
708 *
709 * Returns the number of entries converted if successful, -1 otherwise
710 */
711int
712xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
713
714 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
715 return(-1);
716
717 if (xmlDebugCatalogs) {
718 xmlGenericError(xmlGenericErrorContext,
719 "Converting SGML catalog to XML\n");
720 }
721 xmlHashScan(catal->sgml,
722 (xmlHashScanner) xmlCatalogConvertEntry,
723 &catal);
724 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000725}
726
Daniel Veillarda7374592001-05-10 14:17:55 +0000727/************************************************************************
728 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000729 * Helper function *
730 * *
731 ************************************************************************/
732
733/**
734 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000735 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000736 *
737 * Expand the URN into the equivalent Public Identifier
738 *
739 * Returns the new identifier or NULL, the string must be deallocated
740 * by the caller.
741 */
742static xmlChar *
743xmlCatalogUnWrapURN(const xmlChar *urn) {
744 xmlChar result[2000];
745 unsigned int i = 0;
746
747 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
748 return(NULL);
749 urn += sizeof(XML_URN_PUBID) - 1;
750
751 while (*urn != 0) {
752 if (i > sizeof(result) - 3)
753 break;
754 if (*urn == '+') {
755 result[i++] = ' ';
756 urn++;
757 } else if (*urn == ':') {
758 result[i++] = '/';
759 result[i++] = '/';
760 urn++;
761 } else if (*urn == ';') {
762 result[i++] = ':';
763 result[i++] = ':';
764 urn++;
765 } else if (*urn == '%') {
766 if ((urn[1] == '2') && (urn[1] == 'B'))
767 result[i++] = '+';
768 else if ((urn[1] == '3') && (urn[1] == 'A'))
769 result[i++] = ':';
770 else if ((urn[1] == '2') && (urn[1] == 'F'))
771 result[i++] = '/';
772 else if ((urn[1] == '3') && (urn[1] == 'B'))
773 result[i++] = ';';
774 else if ((urn[1] == '2') && (urn[1] == '7'))
775 result[i++] = '\'';
776 else if ((urn[1] == '3') && (urn[1] == 'F'))
777 result[i++] = '?';
778 else if ((urn[1] == '2') && (urn[1] == '3'))
779 result[i++] = '#';
780 else if ((urn[1] == '2') && (urn[1] == '5'))
781 result[i++] = '%';
782 else {
783 result[i++] = *urn;
784 urn++;
785 continue;
786 }
787 urn += 3;
788 } else {
789 result[i++] = *urn;
790 urn++;
791 }
792 }
793 result[i] = 0;
794
795 return(xmlStrdup(result));
796}
797
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000798/**
799 * xmlParseCatalogFile:
800 * @filename: the filename
801 *
802 * parse an XML file and build a tree. It's like xmlParseFile()
803 * except it bypass all catalog lookups.
804 *
805 * Returns the resulting document tree or NULL in case of error
806 */
807
808xmlDocPtr
809xmlParseCatalogFile(const char *filename) {
810 xmlDocPtr ret;
811 xmlParserCtxtPtr ctxt;
812 char *directory = NULL;
813 xmlParserInputPtr inputStream;
814 xmlParserInputBufferPtr buf;
815
816 ctxt = xmlNewParserCtxt();
817 if (ctxt == NULL) {
818 if (xmlDefaultSAXHandler.error != NULL) {
819 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
820 }
821 return(NULL);
822 }
823
824 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
825 if (buf == NULL) {
826 xmlFreeParserCtxt(ctxt);
827 return(NULL);
828 }
829
830 inputStream = xmlNewInputStream(ctxt);
831 if (inputStream == NULL) {
832 xmlFreeParserCtxt(ctxt);
833 return(NULL);
834 }
835
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000836 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000837 inputStream->buf = buf;
838 inputStream->base = inputStream->buf->buffer->content;
839 inputStream->cur = inputStream->buf->buffer->content;
840 inputStream->end =
841 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
842
843 inputPush(ctxt, inputStream);
844 if ((ctxt->directory == NULL) && (directory == NULL))
845 directory = xmlParserGetDirectory(filename);
846 if ((ctxt->directory == NULL) && (directory != NULL))
847 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000848 ctxt->valid = 0;
849 ctxt->validate = 0;
850 ctxt->loadsubset = 0;
851 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000852
853 xmlParseDocument(ctxt);
854
855 if (ctxt->wellFormed)
856 ret = ctxt->myDoc;
857 else {
858 ret = NULL;
859 xmlFreeDoc(ctxt->myDoc);
860 ctxt->myDoc = NULL;
861 }
862 xmlFreeParserCtxt(ctxt);
863
864 return(ret);
865}
866
Daniel Veillard75b96822001-10-11 18:59:45 +0000867/**
868 * xmlLoadFileContent:
869 * @filename: a file path
870 *
871 * Load a file content into memory.
872 *
873 * Returns a pointer to the 0 terminated string or NULL in case of error
874 */
875static xmlChar *
876xmlLoadFileContent(const char *filename)
877{
878#ifdef HAVE_STAT
879 int fd;
880#else
881 FILE *fd;
882#endif
883 int len;
884 long size;
885
886#ifdef HAVE_STAT
887 struct stat info;
888#endif
889 xmlChar *content;
890
891 if (filename == NULL)
892 return (NULL);
893
894#ifdef HAVE_STAT
895 if (stat(filename, &info) < 0)
896 return (NULL);
897#endif
898
899#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000900 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000901#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000902 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000903#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000904 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000905 return (NULL);
906 }
907#ifdef HAVE_STAT
908 size = info.st_size;
909#else
910 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
911 fclose(fd);
912 return (NULL);
913 }
914#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000915 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000916 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000917 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard75b96822001-10-11 18:59:45 +0000918 return (NULL);
919 }
920#ifdef HAVE_STAT
921 len = read(fd, content, size);
922#else
923 len = fread(content, 1, size, fd);
924#endif
925 if (len < 0) {
926 xmlFree(content);
927 return (NULL);
928 }
929#ifdef HAVE_STAT
930 close(fd);
931#else
932 fclose(fd);
933#endif
934 content[len] = 0;
935
936 return(content);
937}
938
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000939/************************************************************************
940 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000941 * The XML Catalog parser *
942 * *
943 ************************************************************************/
944
945static xmlCatalogEntryPtr
946xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000947static void
948xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
949 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000950static xmlChar *
951xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
952 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000953static xmlChar *
954xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
955
Daniel Veillard344cee72001-08-20 00:08:40 +0000956
Daniel Veillard75b96822001-10-11 18:59:45 +0000957/**
958 * xmlGetXMLCatalogEntryType:
959 * @name: the name
960 *
961 * lookup the internal type associated to an XML catalog entry name
962 *
963 * Returns the type associate with that name
964 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000965static xmlCatalogEntryType
966xmlGetXMLCatalogEntryType(const xmlChar *name) {
967 xmlCatalogEntryType type = XML_CATA_NONE;
968 if (xmlStrEqual(name, (const xmlChar *) "system"))
969 type = XML_CATA_SYSTEM;
970 else if (xmlStrEqual(name, (const xmlChar *) "public"))
971 type = XML_CATA_PUBLIC;
972 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
973 type = XML_CATA_REWRITE_SYSTEM;
974 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
975 type = XML_CATA_DELEGATE_PUBLIC;
976 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
977 type = XML_CATA_DELEGATE_SYSTEM;
978 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
979 type = XML_CATA_URI;
980 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
981 type = XML_CATA_REWRITE_URI;
982 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
983 type = XML_CATA_DELEGATE_URI;
984 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
985 type = XML_CATA_NEXT_CATALOG;
986 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
987 type = XML_CATA_CATALOG;
988 return(type);
989}
990
Daniel Veillard75b96822001-10-11 18:59:45 +0000991/**
992 * xmlParseXMLCatalogOneNode:
993 * @cur: the XML node
994 * @type: the type of Catalog entry
995 * @name: the name of the node
996 * @attrName: the attribute holding the value
997 * @uriAttrName: the attribute holding the URI-Reference
998 * @prefer: the PUBLIC vs. SYSTEM current preference value
999 *
1000 * Finishes the examination of an XML tree node of a catalog and build
1001 * a Catalog entry from it.
1002 *
1003 * Returns the new Catalog entry node or NULL in case of error.
1004 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001005static xmlCatalogEntryPtr
1006xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1007 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001008 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001009 int ok = 1;
1010 xmlChar *uriValue;
1011 xmlChar *nameValue = NULL;
1012 xmlChar *base = NULL;
1013 xmlChar *URL = NULL;
1014 xmlCatalogEntryPtr ret = NULL;
1015
1016 if (attrName != NULL) {
1017 nameValue = xmlGetProp(cur, attrName);
1018 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001019 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1020 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001021 ok = 0;
1022 }
1023 }
1024 uriValue = xmlGetProp(cur, uriAttrName);
1025 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001026 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1027 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001028 ok = 0;
1029 }
1030 if (!ok) {
1031 if (nameValue != NULL)
1032 xmlFree(nameValue);
1033 if (uriValue != NULL)
1034 xmlFree(uriValue);
1035 return(NULL);
1036 }
1037
1038 base = xmlNodeGetBase(cur->doc, cur);
1039 URL = xmlBuildURI(uriValue, base);
1040 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001041 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001042 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001043 xmlGenericError(xmlGenericErrorContext,
1044 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001045 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001046 xmlGenericError(xmlGenericErrorContext,
1047 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001048 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001049 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001050 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001051 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001052 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1053 }
1054 if (nameValue != NULL)
1055 xmlFree(nameValue);
1056 if (uriValue != NULL)
1057 xmlFree(uriValue);
1058 if (base != NULL)
1059 xmlFree(base);
1060 if (URL != NULL)
1061 xmlFree(URL);
1062 return(ret);
1063}
1064
Daniel Veillard75b96822001-10-11 18:59:45 +00001065/**
1066 * xmlParseXMLCatalogNode:
1067 * @cur: the XML node
1068 * @prefer: the PUBLIC vs. SYSTEM current preference value
1069 * @parent: the parent Catalog entry
1070 *
1071 * Examines an XML tree node of a catalog and build
1072 * a Catalog entry from it adding it to its parent. The examination can
1073 * be recursive.
1074 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001075static void
1076xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1077 xmlCatalogEntryPtr parent)
1078{
1079 xmlChar *uri = NULL;
1080 xmlChar *URL = NULL;
1081 xmlChar *base = NULL;
1082 xmlCatalogEntryPtr entry = NULL;
1083
1084 if (cur == NULL)
1085 return;
1086 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1087 xmlChar *prop;
1088
1089 prop = xmlGetProp(cur, BAD_CAST "prefer");
1090 if (prop != NULL) {
1091 if (xmlStrEqual(prop, BAD_CAST "system")) {
1092 prefer = XML_CATA_PREFER_SYSTEM;
1093 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1094 prefer = XML_CATA_PREFER_PUBLIC;
1095 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001096 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1097 "Invalid value for prefer: '%s'\n",
1098 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001099 }
1100 xmlFree(prop);
1101 }
1102 /*
1103 * Recurse to propagate prefer to the subtree
1104 * (xml:base handling is automated)
1105 */
1106 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1107 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1108 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001109 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001110 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1111 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001112 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001113 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1114 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1115 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001116 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001117 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1118 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1119 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001120 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001121 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1122 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1123 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001124 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001125 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1126 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1127 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001128 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001129 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1130 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1131 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001132 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001133 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1134 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1135 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001136 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001137 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1138 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1139 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001140 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001141 }
1142 if ((entry != NULL) && (parent != NULL)) {
1143 entry->parent = parent;
1144 if (parent->children == NULL)
1145 parent->children = entry;
1146 else {
1147 xmlCatalogEntryPtr prev;
1148
1149 prev = parent->children;
1150 while (prev->next != NULL)
1151 prev = prev->next;
1152 prev->next = entry;
1153 }
1154 }
1155 if (base != NULL)
1156 xmlFree(base);
1157 if (uri != NULL)
1158 xmlFree(uri);
1159 if (URL != NULL)
1160 xmlFree(URL);
1161}
1162
Daniel Veillard75b96822001-10-11 18:59:45 +00001163/**
1164 * xmlParseXMLCatalogNodeList:
1165 * @cur: the XML node list of siblings
1166 * @prefer: the PUBLIC vs. SYSTEM current preference value
1167 * @parent: the parent Catalog entry
1168 *
1169 * Examines a list of XML sibling nodes of a catalog and build
1170 * a list of Catalog entry from it adding it to the parent.
1171 * The examination will recurse to examine node subtrees.
1172 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001173static void
1174xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1175 xmlCatalogEntryPtr parent) {
1176 while (cur != NULL) {
1177 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1178 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1179 xmlParseXMLCatalogNode(cur, prefer, parent);
1180 }
1181 cur = cur->next;
1182 }
1183 /* TODO: sort the list according to REWRITE lengths and prefer value */
1184}
1185
Daniel Veillard75b96822001-10-11 18:59:45 +00001186/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001187 * xmlParseXMLCatalogFile:
1188 * @prefer: the PUBLIC vs. SYSTEM current preference value
1189 * @filename: the filename for the catalog
1190 *
1191 * Parses the catalog file to extract the XML tree and then analyze the
1192 * tree to build a list of Catalog entries corresponding to this catalog
1193 *
1194 * Returns the resulting Catalog entries list
1195 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001196static xmlCatalogEntryPtr
1197xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1198 xmlDocPtr doc;
1199 xmlNodePtr cur;
1200 xmlChar *prop;
1201 xmlCatalogEntryPtr parent = NULL;
1202
1203 if (filename == NULL)
1204 return(NULL);
1205
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001206 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001207 if (doc == NULL) {
1208 if (xmlDebugCatalogs)
1209 xmlGenericError(xmlGenericErrorContext,
1210 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001211 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001212 }
1213
1214 if (xmlDebugCatalogs)
1215 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001216 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001217
1218 cur = xmlDocGetRootElement(doc);
1219 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1220 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1221 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1222
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001223 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00001224 (const xmlChar *)filename, NULL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001225 if (parent == NULL) {
1226 xmlFreeDoc(doc);
1227 return(NULL);
1228 }
1229
1230 prop = xmlGetProp(cur, BAD_CAST "prefer");
1231 if (prop != NULL) {
1232 if (xmlStrEqual(prop, BAD_CAST "system")) {
1233 prefer = XML_CATA_PREFER_SYSTEM;
1234 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1235 prefer = XML_CATA_PREFER_PUBLIC;
1236 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001237 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1238 "Invalid value for prefer: '%s'\n",
1239 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001240 }
1241 xmlFree(prop);
1242 }
1243 cur = cur->children;
1244 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1245 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001246 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1247 "File %s is not an XML Catalog\n",
1248 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001249 xmlFreeDoc(doc);
1250 return(NULL);
1251 }
1252 xmlFreeDoc(doc);
1253 return(parent);
1254}
1255
Daniel Veillardcda96922001-08-21 10:56:31 +00001256/**
1257 * xmlFetchXMLCatalogFile:
1258 * @catal: an existing but incomplete catalog entry
1259 *
1260 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001261 *
1262 * Returns 0 in case of success, -1 otherwise
1263 */
1264static int
1265xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001266 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001267
1268 if (catal == NULL)
1269 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001270 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001271 return(-1);
1272 if (catal->children != NULL)
1273 return(-1);
1274
Daniel Veillard81463942001-10-16 12:34:39 +00001275 /*
1276 * lock the whole catalog for modification
1277 */
1278 xmlRMutexLock(xmlCatalogMutex);
1279 if (catal->children != NULL) {
1280 /* Okay someone else did it in the meantime */
1281 xmlRMutexUnlock(xmlCatalogMutex);
1282 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001283 }
1284
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001285 if (xmlCatalogXMLFiles != NULL) {
1286 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001287 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001288 if (doc != NULL) {
1289 if (xmlDebugCatalogs)
1290 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001291 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001292
1293 if (catal->type == XML_CATA_CATALOG)
1294 catal->children = doc->children;
1295 else
1296 catal->children = doc;
1297 catal->dealloc = 0;
1298 xmlRMutexUnlock(xmlCatalogMutex);
1299 return(0);
1300 }
1301 if (xmlDebugCatalogs)
1302 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001303 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001304 }
1305
Daniel Veillardcda96922001-08-21 10:56:31 +00001306 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001307 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001308 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001309 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001310 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001311 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001312 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001313 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001314 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001315 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001316 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001317
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001318 if (catal->type == XML_CATA_CATALOG)
1319 catal->children = doc->children;
1320 else
1321 catal->children = doc;
1322
1323 doc->dealloc = 1;
1324
Daniel Veillard81463942001-10-16 12:34:39 +00001325 if (xmlCatalogXMLFiles == NULL)
1326 xmlCatalogXMLFiles = xmlHashCreate(10);
1327 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001328 if (xmlDebugCatalogs)
1329 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001330 "%s added to file hash\n", catal->URL);
1331 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001332 }
Daniel Veillard81463942001-10-16 12:34:39 +00001333 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001334 return(0);
1335}
1336
Daniel Veillard75b96822001-10-11 18:59:45 +00001337/************************************************************************
1338 * *
1339 * XML Catalog handling *
1340 * *
1341 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001342
1343/**
1344 * xmlAddXMLCatalog:
1345 * @catal: top of an XML catalog
1346 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001347 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001348 * @replace: the replacement value for the match
1349 *
1350 * Add an entry in the XML catalog, it may overwrite existing but
1351 * different entries.
1352 *
1353 * Returns 0 if successful, -1 otherwise
1354 */
1355static int
1356xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1357 const xmlChar *orig, const xmlChar *replace) {
1358 xmlCatalogEntryPtr cur;
1359 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001360 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001361
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001362 if ((catal == NULL) ||
1363 ((catal->type != XML_CATA_CATALOG) &&
1364 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001365 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001366 if (catal->children == NULL) {
1367 xmlFetchXMLCatalogFile(catal);
1368 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001369 if (catal->children == NULL)
1370 doregister = 1;
1371
Daniel Veillard344cee72001-08-20 00:08:40 +00001372 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001373 if (typ == XML_CATA_NONE) {
1374 if (xmlDebugCatalogs)
1375 xmlGenericError(xmlGenericErrorContext,
1376 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001377 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001378 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001379
1380 cur = catal->children;
1381 /*
1382 * Might be a simple "update in place"
1383 */
1384 if (cur != NULL) {
1385 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001386 if ((orig != NULL) && (cur->type == typ) &&
1387 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001388 if (xmlDebugCatalogs)
1389 xmlGenericError(xmlGenericErrorContext,
1390 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001391 if (cur->value != NULL)
1392 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001393 if (cur->URL != NULL)
1394 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001395 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001396 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001397 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001398 }
1399 if (cur->next == NULL)
1400 break;
1401 cur = cur->next;
1402 }
1403 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001404 if (xmlDebugCatalogs)
1405 xmlGenericError(xmlGenericErrorContext,
1406 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001407 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001408 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1409 NULL, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001410 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001411 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1412 NULL, catal->prefer);
1413 if (doregister) {
1414 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1415 if (cur != NULL)
1416 cur->children = catal->children;
1417 }
1418
Daniel Veillardcda96922001-08-21 10:56:31 +00001419 return(0);
1420}
1421
1422/**
1423 * xmlDelXMLCatalog:
1424 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001425 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001426 *
1427 * Remove entries in the XML catalog where the value or the URI
1428 * is equal to @value
1429 *
1430 * Returns the number of entries removed if successful, -1 otherwise
1431 */
1432static int
1433xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001434 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001435 int ret = 0;
1436
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001437 if ((catal == NULL) ||
1438 ((catal->type != XML_CATA_CATALOG) &&
1439 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001440 return(-1);
1441 if (value == NULL)
1442 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001443 if (catal->children == NULL) {
1444 xmlFetchXMLCatalogFile(catal);
1445 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001446
1447 /*
1448 * Scan the children
1449 */
1450 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001451 while (cur != NULL) {
1452 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1453 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001454 if (xmlDebugCatalogs) {
1455 if (cur->name != NULL)
1456 xmlGenericError(xmlGenericErrorContext,
1457 "Removing element %s from catalog\n", cur->name);
1458 else
1459 xmlGenericError(xmlGenericErrorContext,
1460 "Removing element %s from catalog\n", cur->value);
1461 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001462 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001463 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001464 cur = cur->next;
1465 }
1466 return(ret);
1467}
1468
1469/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001470 * xmlCatalogXMLResolve:
1471 * @catal: a catalog list
1472 * @pubId: the public ID string
1473 * @sysId: the system ID string
1474 *
1475 * Do a complete resolution lookup of an External Identifier for a
1476 * list of catalog entries.
1477 *
1478 * Implements (or tries to) 7.1. External Identifier Resolution
1479 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1480 *
1481 * Returns the URI of the resource or NULL if not found
1482 */
1483static xmlChar *
1484xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1485 const xmlChar *sysID) {
1486 xmlChar *ret = NULL;
1487 xmlCatalogEntryPtr cur;
1488 int haveDelegate = 0;
1489 int haveNext = 0;
1490
1491 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001492 * protection against loops
1493 */
1494 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001495 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1496 "Detected recursion in catalog %s\n",
1497 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001498 return(NULL);
1499 }
1500 catal->depth++;
1501
1502 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001503 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1504 */
1505 if (sysID != NULL) {
1506 xmlCatalogEntryPtr rewrite = NULL;
1507 int lenrewrite = 0, len;
1508 cur = catal;
1509 haveDelegate = 0;
1510 while (cur != NULL) {
1511 switch (cur->type) {
1512 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001513 if (xmlStrEqual(sysID, cur->name)) {
1514 if (xmlDebugCatalogs)
1515 xmlGenericError(xmlGenericErrorContext,
1516 "Found system match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001517 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001518 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001519 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001520 break;
1521 case XML_CATA_REWRITE_SYSTEM:
1522 len = xmlStrlen(cur->name);
1523 if ((len > lenrewrite) &&
1524 (!xmlStrncmp(sysID, cur->name, len))) {
1525 lenrewrite = len;
1526 rewrite = cur;
1527 }
1528 break;
1529 case XML_CATA_DELEGATE_SYSTEM:
1530 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1531 haveDelegate++;
1532 break;
1533 case XML_CATA_NEXT_CATALOG:
1534 haveNext++;
1535 break;
1536 default:
1537 break;
1538 }
1539 cur = cur->next;
1540 }
1541 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001542 if (xmlDebugCatalogs)
1543 xmlGenericError(xmlGenericErrorContext,
1544 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001545 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001546 if (ret != NULL)
1547 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001548 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001549 return(ret);
1550 }
1551 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001552 const xmlChar *delegates[MAX_DELEGATE];
1553 int nbList = 0, i;
1554
Daniel Veillardcda96922001-08-21 10:56:31 +00001555 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001556 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001557 * matches when the list was produced.
1558 */
1559 cur = catal;
1560 while (cur != NULL) {
1561 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1562 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001563 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001564 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001565 break;
1566 if (i < nbList) {
1567 cur = cur->next;
1568 continue;
1569 }
1570 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001571 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001572
Daniel Veillardcda96922001-08-21 10:56:31 +00001573 if (cur->children == NULL) {
1574 xmlFetchXMLCatalogFile(cur);
1575 }
1576 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001577 if (xmlDebugCatalogs)
1578 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001579 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001580 ret = xmlCatalogListXMLResolve(
1581 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001582 if (ret != NULL) {
1583 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001584 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001585 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001586 }
1587 }
1588 cur = cur->next;
1589 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001590 /*
1591 * Apply the cut algorithm explained in 4/
1592 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001593 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001594 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001595 }
1596 }
1597 /*
1598 * Then tries 5/ 6/ if a public ID is provided
1599 */
1600 if (pubID != NULL) {
1601 cur = catal;
1602 haveDelegate = 0;
1603 while (cur != NULL) {
1604 switch (cur->type) {
1605 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001606 if (xmlStrEqual(pubID, cur->name)) {
1607 if (xmlDebugCatalogs)
1608 xmlGenericError(xmlGenericErrorContext,
1609 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001610 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001611 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001612 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001613 break;
1614 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001615 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1616 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001617 haveDelegate++;
1618 break;
1619 case XML_CATA_NEXT_CATALOG:
1620 if (sysID == NULL)
1621 haveNext++;
1622 break;
1623 default:
1624 break;
1625 }
1626 cur = cur->next;
1627 }
1628 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001629 const xmlChar *delegates[MAX_DELEGATE];
1630 int nbList = 0, i;
1631
Daniel Veillardcda96922001-08-21 10:56:31 +00001632 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001633 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001634 * matches when the list was produced.
1635 */
1636 cur = catal;
1637 while (cur != NULL) {
1638 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001639 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1640 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001641
1642 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001643 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001644 break;
1645 if (i < nbList) {
1646 cur = cur->next;
1647 continue;
1648 }
1649 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001650 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001651
Daniel Veillardcda96922001-08-21 10:56:31 +00001652 if (cur->children == NULL) {
1653 xmlFetchXMLCatalogFile(cur);
1654 }
1655 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001656 if (xmlDebugCatalogs)
1657 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001658 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001659 ret = xmlCatalogListXMLResolve(
1660 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001661 if (ret != NULL) {
1662 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001663 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001664 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001665 }
1666 }
1667 cur = cur->next;
1668 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001669 /*
1670 * Apply the cut algorithm explained in 4/
1671 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001672 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001673 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001674 }
1675 }
1676 if (haveNext) {
1677 cur = catal;
1678 while (cur != NULL) {
1679 if (cur->type == XML_CATA_NEXT_CATALOG) {
1680 if (cur->children == NULL) {
1681 xmlFetchXMLCatalogFile(cur);
1682 }
1683 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001684 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001685 if (ret != NULL) {
1686 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001687 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001688 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001689 }
1690 }
1691 cur = cur->next;
1692 }
1693 }
1694
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001695 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001696 return(NULL);
1697}
1698
1699/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001700 * xmlCatalogXMLResolveURI:
1701 * @catal: a catalog list
1702 * @URI: the URI
1703 * @sysId: the system ID string
1704 *
1705 * Do a complete resolution lookup of an External Identifier for a
1706 * list of catalog entries.
1707 *
1708 * Implements (or tries to) 7.2.2. URI Resolution
1709 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1710 *
1711 * Returns the URI of the resource or NULL if not found
1712 */
1713static xmlChar *
1714xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1715 xmlChar *ret = NULL;
1716 xmlCatalogEntryPtr cur;
1717 int haveDelegate = 0;
1718 int haveNext = 0;
1719 xmlCatalogEntryPtr rewrite = NULL;
1720 int lenrewrite = 0, len;
1721
1722 if (catal == NULL)
1723 return(NULL);
1724
1725 if (URI == NULL)
1726 return(NULL);
1727
1728 /*
1729 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1730 */
1731 cur = catal;
1732 haveDelegate = 0;
1733 while (cur != NULL) {
1734 switch (cur->type) {
1735 case XML_CATA_URI:
1736 if (xmlStrEqual(URI, cur->name)) {
1737 if (xmlDebugCatalogs)
1738 xmlGenericError(xmlGenericErrorContext,
1739 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001740 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001741 }
1742 break;
1743 case XML_CATA_REWRITE_URI:
1744 len = xmlStrlen(cur->name);
1745 if ((len > lenrewrite) &&
1746 (!xmlStrncmp(URI, cur->name, len))) {
1747 lenrewrite = len;
1748 rewrite = cur;
1749 }
1750 break;
1751 case XML_CATA_DELEGATE_URI:
1752 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1753 haveDelegate++;
1754 break;
1755 case XML_CATA_NEXT_CATALOG:
1756 haveNext++;
1757 break;
1758 default:
1759 break;
1760 }
1761 cur = cur->next;
1762 }
1763 if (rewrite != NULL) {
1764 if (xmlDebugCatalogs)
1765 xmlGenericError(xmlGenericErrorContext,
1766 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001767 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001768 if (ret != NULL)
1769 ret = xmlStrcat(ret, &URI[lenrewrite]);
1770 return(ret);
1771 }
1772 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001773 const xmlChar *delegates[MAX_DELEGATE];
1774 int nbList = 0, i;
1775
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001776 /*
1777 * Assume the entries have been sorted by decreasing substring
1778 * matches when the list was produced.
1779 */
1780 cur = catal;
1781 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001782 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1783 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001784 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001785 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001786 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001787 break;
1788 if (i < nbList) {
1789 cur = cur->next;
1790 continue;
1791 }
1792 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001793 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001794
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001795 if (cur->children == NULL) {
1796 xmlFetchXMLCatalogFile(cur);
1797 }
1798 if (cur->children != NULL) {
1799 if (xmlDebugCatalogs)
1800 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001801 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001802 ret = xmlCatalogListXMLResolveURI(
1803 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001804 if (ret != NULL)
1805 return(ret);
1806 }
1807 }
1808 cur = cur->next;
1809 }
1810 /*
1811 * Apply the cut algorithm explained in 4/
1812 */
1813 return(XML_CATAL_BREAK);
1814 }
1815 if (haveNext) {
1816 cur = catal;
1817 while (cur != NULL) {
1818 if (cur->type == XML_CATA_NEXT_CATALOG) {
1819 if (cur->children == NULL) {
1820 xmlFetchXMLCatalogFile(cur);
1821 }
1822 if (cur->children != NULL) {
1823 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1824 if (ret != NULL)
1825 return(ret);
1826 }
1827 }
1828 cur = cur->next;
1829 }
1830 }
1831
1832 return(NULL);
1833}
1834
1835/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001836 * xmlCatalogListXMLResolve:
1837 * @catal: a catalog list
1838 * @pubId: the public ID string
1839 * @sysId: the system ID string
1840 *
1841 * Do a complete resolution lookup of an External Identifier for a
1842 * list of catalogs
1843 *
1844 * Implements (or tries to) 7.1. External Identifier Resolution
1845 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1846 *
1847 * Returns the URI of the resource or NULL if not found
1848 */
1849static xmlChar *
1850xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1851 const xmlChar *sysID) {
1852 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001853 xmlChar *urnID = NULL;
1854
1855 if (catal == NULL)
1856 return(NULL);
1857 if ((pubID == NULL) && (sysID == NULL))
1858 return(NULL);
1859
1860 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1861 urnID = xmlCatalogUnWrapURN(pubID);
1862 if (xmlDebugCatalogs) {
1863 if (urnID == NULL)
1864 xmlGenericError(xmlGenericErrorContext,
1865 "Public URN ID %s expanded to NULL\n", pubID);
1866 else
1867 xmlGenericError(xmlGenericErrorContext,
1868 "Public URN ID expanded to %s\n", urnID);
1869 }
1870 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1871 if (urnID != NULL)
1872 xmlFree(urnID);
1873 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001874 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001875 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1876 urnID = xmlCatalogUnWrapURN(sysID);
1877 if (xmlDebugCatalogs) {
1878 if (urnID == NULL)
1879 xmlGenericError(xmlGenericErrorContext,
1880 "System URN ID %s expanded to NULL\n", sysID);
1881 else
1882 xmlGenericError(xmlGenericErrorContext,
1883 "System URN ID expanded to %s\n", urnID);
1884 }
1885 if (pubID == NULL)
1886 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1887 else if (xmlStrEqual(pubID, urnID))
1888 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1889 else {
1890 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1891 }
1892 if (urnID != NULL)
1893 xmlFree(urnID);
1894 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001895 }
1896 while (catal != NULL) {
1897 if (catal->type == XML_CATA_CATALOG) {
1898 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001899 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001900 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001901 if (catal->children != NULL) {
1902 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1903 if (ret != NULL)
1904 return(ret);
1905 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001906 }
1907 catal = catal->next;
1908 }
1909 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001910}
1911
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001912/**
1913 * xmlCatalogListXMLResolveURI:
1914 * @catal: a catalog list
1915 * @URI: the URI
1916 *
1917 * Do a complete resolution lookup of an URI for a list of catalogs
1918 *
1919 * Implements (or tries to) 7.2. URI Resolution
1920 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1921 *
1922 * Returns the URI of the resource or NULL if not found
1923 */
1924static xmlChar *
1925xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1926 xmlChar *ret = NULL;
1927 xmlChar *urnID = NULL;
1928
1929 if (catal == NULL)
1930 return(NULL);
1931 if (URI == NULL)
1932 return(NULL);
1933
1934 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1935 urnID = xmlCatalogUnWrapURN(URI);
1936 if (xmlDebugCatalogs) {
1937 if (urnID == NULL)
1938 xmlGenericError(xmlGenericErrorContext,
1939 "URN ID %s expanded to NULL\n", URI);
1940 else
1941 xmlGenericError(xmlGenericErrorContext,
1942 "URN ID expanded to %s\n", urnID);
1943 }
1944 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1945 if (urnID != NULL)
1946 xmlFree(urnID);
1947 return(ret);
1948 }
1949 while (catal != NULL) {
1950 if (catal->type == XML_CATA_CATALOG) {
1951 if (catal->children == NULL) {
1952 xmlFetchXMLCatalogFile(catal);
1953 }
1954 if (catal->children != NULL) {
1955 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1956 if (ret != NULL)
1957 return(ret);
1958 }
1959 }
1960 catal = catal->next;
1961 }
1962 return(ret);
1963}
1964
Daniel Veillard344cee72001-08-20 00:08:40 +00001965/************************************************************************
1966 * *
1967 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001968 * *
1969 ************************************************************************/
1970
1971
1972#define RAW *cur
1973#define NEXT cur++;
1974#define SKIP(x) cur += x;
1975
1976#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1977
Daniel Veillard75b96822001-10-11 18:59:45 +00001978/**
1979 * xmlParseSGMLCatalogComment:
1980 * @cur: the current character
1981 *
1982 * Skip a comment in an SGML catalog
1983 *
1984 * Returns new current character
1985 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001986static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001987xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001988 if ((cur[0] != '-') || (cur[1] != '-'))
1989 return(cur);
1990 SKIP(2);
1991 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1992 NEXT;
1993 if (cur[0] == 0) {
1994 return(NULL);
1995 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001996 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001997}
1998
Daniel Veillard75b96822001-10-11 18:59:45 +00001999/**
2000 * xmlParseSGMLCatalogPubid:
2001 * @cur: the current character
2002 * @id: the return location
2003 *
2004 * Parse an SGML catalog ID
2005 *
2006 * Returns new current character and store the value in @id
2007 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002008static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002009xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002010 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002011 int len = 0;
2012 int size = 50;
2013 xmlChar stop;
2014 int count = 0;
2015
2016 *id = NULL;
2017
2018 if (RAW == '"') {
2019 NEXT;
2020 stop = '"';
2021 } else if (RAW == '\'') {
2022 NEXT;
2023 stop = '\'';
2024 } else {
2025 stop = ' ';
2026 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002027 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002028 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002029 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002030 return(NULL);
2031 }
Daniel Veillard935494a2002-10-22 14:22:46 +00002032 while (xmlIsPubidChar(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002033 if ((*cur == stop) && (stop != ' '))
2034 break;
2035 if ((stop == ' ') && (IS_BLANK(*cur)))
2036 break;
2037 if (len + 1 >= size) {
2038 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002039 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2040 if (tmp == NULL) {
2041 xmlCatalogErrMemory("allocating public ID");
2042 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002043 return(NULL);
2044 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002045 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002046 }
2047 buf[len++] = *cur;
2048 count++;
2049 NEXT;
2050 }
2051 buf[len] = 0;
2052 if (stop == ' ') {
2053 if (!IS_BLANK(*cur)) {
2054 xmlFree(buf);
2055 return(NULL);
2056 }
2057 } else {
2058 if (*cur != stop) {
2059 xmlFree(buf);
2060 return(NULL);
2061 }
2062 NEXT;
2063 }
2064 *id = buf;
2065 return(cur);
2066}
2067
Daniel Veillard75b96822001-10-11 18:59:45 +00002068/**
2069 * xmlParseSGMLCatalogName:
2070 * @cur: the current character
2071 * @name: the return location
2072 *
2073 * Parse an SGML catalog name
2074 *
2075 * Returns new current character and store the value in @name
2076 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002077static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002078xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002079 xmlChar buf[XML_MAX_NAMELEN + 5];
2080 int len = 0;
2081 int c;
2082
2083 *name = NULL;
2084
2085 /*
2086 * Handler for more complex cases
2087 */
2088 c = *cur;
2089 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2090 return(NULL);
2091 }
2092
2093 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2094 (c == '.') || (c == '-') ||
2095 (c == '_') || (c == ':'))) {
2096 buf[len++] = c;
2097 cur++;
2098 c = *cur;
2099 if (len >= XML_MAX_NAMELEN)
2100 return(NULL);
2101 }
2102 *name = xmlStrndup(buf, len);
2103 return(cur);
2104}
2105
Daniel Veillard75b96822001-10-11 18:59:45 +00002106/**
2107 * xmlGetSGMLCatalogEntryType:
2108 * @name: the entry name
2109 *
2110 * Get the Catalog entry type for a given SGML Catalog name
2111 *
2112 * Returns Catalog entry type
2113 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002114static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002115xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002116 xmlCatalogEntryType type = XML_CATA_NONE;
2117 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2118 type = SGML_CATA_SYSTEM;
2119 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2120 type = SGML_CATA_PUBLIC;
2121 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2122 type = SGML_CATA_DELEGATE;
2123 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2124 type = SGML_CATA_ENTITY;
2125 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2126 type = SGML_CATA_DOCTYPE;
2127 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2128 type = SGML_CATA_LINKTYPE;
2129 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2130 type = SGML_CATA_NOTATION;
2131 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2132 type = SGML_CATA_SGMLDECL;
2133 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2134 type = SGML_CATA_DOCUMENT;
2135 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2136 type = SGML_CATA_CATALOG;
2137 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2138 type = SGML_CATA_BASE;
2139 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2140 type = SGML_CATA_DELEGATE;
2141 return(type);
2142}
2143
Daniel Veillard75b96822001-10-11 18:59:45 +00002144/**
2145 * xmlParseSGMLCatalog:
2146 * @catal: the SGML Catalog
2147 * @value: the content of the SGML Catalog serialization
2148 * @file: the filepath for the catalog
2149 * @super: should this be handled as a Super Catalog in which case
2150 * parsing is not recursive
2151 *
2152 * Parse an SGML catalog content and fill up the @catal hash table with
2153 * the new entries found.
2154 *
2155 * Returns 0 in case of success, -1 in case of error.
2156 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002157static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002158xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2159 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002160 const xmlChar *cur = value;
2161 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002162 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002163
2164 if ((cur == NULL) || (file == NULL))
2165 return(-1);
2166 base = xmlStrdup((const xmlChar *) file);
2167
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002168 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002169 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002170 if (cur[0] == 0)
2171 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002172 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002173 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002174 if (cur == NULL) {
2175 /* error */
2176 break;
2177 }
2178 } else {
2179 xmlChar *sysid = NULL;
2180 xmlChar *name = NULL;
2181 xmlCatalogEntryType type = XML_CATA_NONE;
2182
Daniel Veillardcda96922001-08-21 10:56:31 +00002183 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002184 if (name == NULL) {
2185 /* error */
2186 break;
2187 }
2188 if (!IS_BLANK(*cur)) {
2189 /* error */
2190 break;
2191 }
2192 SKIP_BLANKS;
2193 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002194 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002195 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002196 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002197 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002198 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002199 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002200 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002201 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002202 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002203 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002204 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002205 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002206 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002207 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002208 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002209 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002210 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002211 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002212 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002213 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002214 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002215 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002216 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002217 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2218 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002219 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002220 if (name == NULL) {
2221 /* error */
2222 break;
2223 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002224 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002225 continue;
2226 }
2227 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002228 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002229
2230 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002231 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002232 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002233 type = SGML_CATA_PENTITY;
2234 case SGML_CATA_PENTITY:
2235 case SGML_CATA_DOCTYPE:
2236 case SGML_CATA_LINKTYPE:
2237 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002238 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002239 if (cur == NULL) {
2240 /* error */
2241 break;
2242 }
2243 if (!IS_BLANK(*cur)) {
2244 /* error */
2245 break;
2246 }
2247 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002248 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002249 if (cur == NULL) {
2250 /* error */
2251 break;
2252 }
2253 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002254 case SGML_CATA_PUBLIC:
2255 case SGML_CATA_SYSTEM:
2256 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002257 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002258 if (cur == NULL) {
2259 /* error */
2260 break;
2261 }
2262 if (!IS_BLANK(*cur)) {
2263 /* error */
2264 break;
2265 }
2266 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002267 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002268 if (cur == NULL) {
2269 /* error */
2270 break;
2271 }
2272 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002273 case SGML_CATA_BASE:
2274 case SGML_CATA_CATALOG:
2275 case SGML_CATA_DOCUMENT:
2276 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002277 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002278 if (cur == NULL) {
2279 /* error */
2280 break;
2281 }
2282 break;
2283 default:
2284 break;
2285 }
2286 if (cur == NULL) {
2287 if (name != NULL)
2288 xmlFree(name);
2289 if (sysid != NULL)
2290 xmlFree(sysid);
2291 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002292 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002293 if (base != NULL)
2294 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002295 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002296 } else if ((type == SGML_CATA_PUBLIC) ||
2297 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002298 xmlChar *filename;
2299
2300 filename = xmlBuildURI(sysid, base);
2301 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002302 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002303
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002304 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002305 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002306 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002307 if (res < 0) {
2308 xmlFreeCatalogEntry(entry);
2309 }
2310 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002311 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002312
Daniel Veillard344cee72001-08-20 00:08:40 +00002313 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002314 if (super) {
2315 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002316
Daniel Veillardc853b322001-11-06 15:24:37 +00002317 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002318 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002319 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002320 if (res < 0) {
2321 xmlFreeCatalogEntry(entry);
2322 }
2323 } else {
2324 xmlChar *filename;
2325
2326 filename = xmlBuildURI(sysid, base);
2327 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002328 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002329 xmlFree(filename);
2330 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002331 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002332 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002333 /*
2334 * drop anything else we won't handle it
2335 */
2336 if (name != NULL)
2337 xmlFree(name);
2338 if (sysid != NULL)
2339 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002340 }
2341 }
2342 if (base != NULL)
2343 xmlFree(base);
2344 if (cur == NULL)
2345 return(-1);
2346 return(0);
2347}
2348
Daniel Veillard75b96822001-10-11 18:59:45 +00002349/************************************************************************
2350 * *
2351 * SGML Catalog handling *
2352 * *
2353 ************************************************************************/
2354
Daniel Veillardcda96922001-08-21 10:56:31 +00002355/**
2356 * xmlCatalogGetSGMLPublic:
2357 * @catal: an SGML catalog hash
2358 * @pubId: the public ID string
2359 *
2360 * Try to lookup the system ID associated to a public ID
2361 *
2362 * Returns the system ID if found or NULL otherwise.
2363 */
2364static const xmlChar *
2365xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2366 xmlCatalogEntryPtr entry;
2367
2368 if (catal == NULL)
2369 return(NULL);
2370
2371 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2372 if (entry == NULL)
2373 return(NULL);
2374 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillardc853b322001-11-06 15:24:37 +00002375 return(entry->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002376 return(NULL);
2377}
2378
2379/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002380 * xmlCatalogGetSGMLSystem:
2381 * @catal: an SGML catalog hash
2382 * @sysId: the public ID string
2383 *
2384 * Try to lookup the catalog local reference for a system ID
2385 *
2386 * Returns the system ID if found or NULL otherwise.
2387 */
2388static const xmlChar *
2389xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2390 xmlCatalogEntryPtr entry;
2391
2392 if (catal == NULL)
2393 return(NULL);
2394
2395 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2396 if (entry == NULL)
2397 return(NULL);
2398 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002399 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002400 return(NULL);
2401}
2402
2403/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002404 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002405 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002406 * @pubId: the public ID string
2407 * @sysId: the system ID string
2408 *
2409 * Do a complete resolution lookup of an External Identifier
2410 *
2411 * Returns the URI of the resource or NULL if not found
2412 */
2413static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002414xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2415 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002416 const xmlChar *ret = NULL;
2417
Daniel Veillard75b96822001-10-11 18:59:45 +00002418 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002419 return(NULL);
2420
2421 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002422 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002423 if (ret != NULL)
2424 return(ret);
2425 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002426 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002427 return(NULL);
2428}
2429
Daniel Veillarda7374592001-05-10 14:17:55 +00002430/************************************************************************
2431 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002432 * Specific Public interfaces *
2433 * *
2434 ************************************************************************/
2435
2436/**
2437 * xmlLoadSGMLSuperCatalog:
2438 * @filename: a file path
2439 *
2440 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2441 * references. This is only needed for manipulating SGML Super Catalogs
2442 * like adding and removing CATALOG or DELEGATE entries.
2443 *
2444 * Returns the catalog parsed or NULL in case of error
2445 */
2446xmlCatalogPtr
2447xmlLoadSGMLSuperCatalog(const char *filename)
2448{
2449 xmlChar *content;
2450 xmlCatalogPtr catal;
2451 int ret;
2452
2453 content = xmlLoadFileContent(filename);
2454 if (content == NULL)
2455 return(NULL);
2456
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002457 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002458 if (catal == NULL) {
2459 xmlFree(content);
2460 return(NULL);
2461 }
2462
2463 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2464 xmlFree(content);
2465 if (ret < 0) {
2466 xmlFreeCatalog(catal);
2467 return(NULL);
2468 }
2469 return (catal);
2470}
2471
2472/**
2473 * xmlLoadACatalog:
2474 * @filename: a file path
2475 *
2476 * Load the catalog and build the associated data structures.
2477 * This can be either an XML Catalog or an SGML Catalog
2478 * It will recurse in SGML CATALOG entries. On the other hand XML
2479 * Catalogs are not handled recursively.
2480 *
2481 * Returns the catalog parsed or NULL in case of error
2482 */
2483xmlCatalogPtr
2484xmlLoadACatalog(const char *filename)
2485{
2486 xmlChar *content;
2487 xmlChar *first;
2488 xmlCatalogPtr catal;
2489 int ret;
2490
2491 content = xmlLoadFileContent(filename);
2492 if (content == NULL)
2493 return(NULL);
2494
2495
2496 first = content;
2497
2498 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2499 (!(((*first >= 'A') && (*first <= 'Z')) ||
2500 ((*first >= 'a') && (*first <= 'z')))))
2501 first++;
2502
2503 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002504 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002505 if (catal == NULL) {
2506 xmlFree(content);
2507 return(NULL);
2508 }
2509 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2510 if (ret < 0) {
2511 xmlFreeCatalog(catal);
2512 xmlFree(content);
2513 return(NULL);
2514 }
2515 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002516 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002517 if (catal == NULL) {
2518 xmlFree(content);
2519 return(NULL);
2520 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002521 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002522 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002523 }
2524 xmlFree(content);
2525 return (catal);
2526}
2527
2528/**
2529 * xmlExpandCatalog:
2530 * @catal: a catalog
2531 * @filename: a file path
2532 *
2533 * Load the catalog and expand the existing catal structure.
2534 * This can be either an XML Catalog or an SGML Catalog
2535 *
2536 * Returns 0 in case of success, -1 in case of error
2537 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002538static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002539xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2540{
Daniel Veillard75b96822001-10-11 18:59:45 +00002541 int ret;
2542
2543 if ((catal == NULL) || (filename == NULL))
2544 return(-1);
2545
Daniel Veillard75b96822001-10-11 18:59:45 +00002546
2547 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002548 xmlChar *content;
2549
2550 content = xmlLoadFileContent(filename);
2551 if (content == NULL)
2552 return(-1);
2553
Daniel Veillard75b96822001-10-11 18:59:45 +00002554 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2555 if (ret < 0) {
2556 xmlFree(content);
2557 return(-1);
2558 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002559 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002560 } else {
2561 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002562 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002563 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002564
Daniel Veillard75b96822001-10-11 18:59:45 +00002565 cur = catal->xml;
2566 if (cur == NULL) {
2567 catal->xml = tmp;
2568 } else {
2569 while (cur->next != NULL) cur = cur->next;
2570 cur->next = tmp;
2571 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002572 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002573 return (0);
2574}
2575
2576/**
2577 * xmlACatalogResolveSystem:
2578 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002579 * @sysID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002580 *
2581 * Try to lookup the catalog resource for a system ID
2582 *
2583 * Returns the system ID if found or NULL otherwise, the value returned
2584 * must be freed by the caller.
2585 */
2586xmlChar *
2587xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2588 xmlChar *ret = NULL;
2589
2590 if ((sysID == NULL) || (catal == NULL))
2591 return(NULL);
2592
2593 if (xmlDebugCatalogs)
2594 xmlGenericError(xmlGenericErrorContext,
2595 "Resolve sysID %s\n", sysID);
2596
2597 if (catal->type == XML_XML_CATALOG_TYPE) {
2598 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2599 if (ret == XML_CATAL_BREAK)
2600 ret = NULL;
2601 } else {
2602 const xmlChar *sgml;
2603
2604 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2605 if (sgml != NULL)
2606 ret = xmlStrdup(sgml);
2607 }
2608 return(ret);
2609}
2610
2611/**
2612 * xmlACatalogResolvePublic:
2613 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002614 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002615 *
2616 * Try to lookup the system ID associated to a public ID in that catalog
2617 *
2618 * Returns the system ID if found or NULL otherwise, the value returned
2619 * must be freed by the caller.
2620 */
2621xmlChar *
2622xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2623 xmlChar *ret = NULL;
2624
2625 if ((pubID == NULL) || (catal == NULL))
2626 return(NULL);
2627
2628 if (xmlDebugCatalogs)
2629 xmlGenericError(xmlGenericErrorContext,
2630 "Resolve pubID %s\n", pubID);
2631
2632 if (catal->type == XML_XML_CATALOG_TYPE) {
2633 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2634 if (ret == XML_CATAL_BREAK)
2635 ret = NULL;
2636 } else {
2637 const xmlChar *sgml;
2638
2639 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2640 if (sgml != NULL)
2641 ret = xmlStrdup(sgml);
2642 }
2643 return(ret);
2644}
2645
2646/**
2647 * xmlACatalogResolve:
2648 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002649 * @pubID: the public ID string
2650 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002651 *
2652 * Do a complete resolution lookup of an External Identifier
2653 *
2654 * Returns the URI of the resource or NULL if not found, it must be freed
2655 * by the caller.
2656 */
2657xmlChar *
2658xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2659 const xmlChar * sysID)
2660{
2661 xmlChar *ret = NULL;
2662
2663 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2664 return (NULL);
2665
2666 if (xmlDebugCatalogs) {
2667 if (pubID != NULL) {
2668 xmlGenericError(xmlGenericErrorContext,
2669 "Resolve: pubID %s\n", pubID);
2670 } else {
2671 xmlGenericError(xmlGenericErrorContext,
2672 "Resolve: sysID %s\n", sysID);
2673 }
2674 }
2675
2676 if (catal->type == XML_XML_CATALOG_TYPE) {
2677 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2678 if (ret == XML_CATAL_BREAK)
2679 ret = NULL;
2680 } else {
2681 const xmlChar *sgml;
2682
2683 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2684 if (sgml != NULL)
2685 ret = xmlStrdup(sgml);
2686 }
2687 return (ret);
2688}
2689
2690/**
2691 * xmlACatalogResolveURI:
2692 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002693 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002694 *
2695 * Do a complete resolution lookup of an URI
2696 *
2697 * Returns the URI of the resource or NULL if not found, it must be freed
2698 * by the caller.
2699 */
2700xmlChar *
2701xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2702 xmlChar *ret = NULL;
2703
2704 if ((URI == NULL) || (catal == NULL))
2705 return(NULL);
2706
Daniel Veillardb44025c2001-10-11 22:55:55 +00002707 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002708 xmlGenericError(xmlGenericErrorContext,
2709 "Resolve URI %s\n", URI);
2710
2711 if (catal->type == XML_XML_CATALOG_TYPE) {
2712 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2713 if (ret == XML_CATAL_BREAK)
2714 ret = NULL;
2715 } else {
2716 const xmlChar *sgml;
2717
2718 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2719 if (sgml != NULL)
2720 sgml = xmlStrdup(sgml);
2721 }
2722 return(ret);
2723}
2724
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002725#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002726/**
2727 * xmlACatalogDump:
2728 * @catal: a Catalog
2729 * @out: the file.
2730 *
2731 * Free up all the memory associated with catalogs
2732 */
2733void
2734xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002735 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002736 return;
2737
2738 if (catal->type == XML_XML_CATALOG_TYPE) {
2739 xmlDumpXMLCatalog(out, catal->xml);
2740 } else {
2741 xmlHashScan(catal->sgml,
2742 (xmlHashScanner) xmlCatalogDumpEntry, out);
2743 }
2744}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002745#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002746
2747/**
2748 * xmlACatalogAdd:
2749 * @catal: a Catalog
2750 * @type: the type of record to add to the catalog
2751 * @orig: the system, public or prefix to match
2752 * @replace: the replacement value for the match
2753 *
2754 * Add an entry in the catalog, it may overwrite existing but
2755 * different entries.
2756 *
2757 * Returns 0 if successful, -1 otherwise
2758 */
2759int
2760xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2761 const xmlChar * orig, const xmlChar * replace)
2762{
2763 int res = -1;
2764
2765 if (catal == NULL)
2766 return(-1);
2767
2768 if (catal->type == XML_XML_CATALOG_TYPE) {
2769 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2770 } else {
2771 xmlCatalogEntryType cattype;
2772
2773 cattype = xmlGetSGMLCatalogEntryType(type);
2774 if (cattype != XML_CATA_NONE) {
2775 xmlCatalogEntryPtr entry;
2776
Daniel Veillardc853b322001-11-06 15:24:37 +00002777 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002778 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002779 if (catal->sgml == NULL)
2780 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002781 res = xmlHashAddEntry(catal->sgml, orig, entry);
2782 }
2783 }
2784 return (res);
2785}
2786
2787/**
2788 * xmlACatalogRemove:
2789 * @catal: a Catalog
2790 * @value: the value to remove
2791 *
2792 * Remove an entry from the catalog
2793 *
2794 * Returns the number of entries removed if successful, -1 otherwise
2795 */
2796int
2797xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2798 int res = -1;
2799
2800 if ((catal == NULL) || (value == NULL))
2801 return(-1);
2802
2803 if (catal->type == XML_XML_CATALOG_TYPE) {
2804 res = xmlDelXMLCatalog(catal->xml, value);
2805 } else {
2806 res = xmlHashRemoveEntry(catal->sgml, value,
2807 (xmlHashDeallocator) xmlFreeCatalogEntry);
2808 if (res == 0)
2809 res = 1;
2810 }
2811 return(res);
2812}
2813
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002814/**
2815 * xmlNewCatalog:
2816 * @sgml: should this create an SGML catalog
2817 *
2818 * create a new Catalog.
2819 *
2820 * Returns the xmlCatalogPtr or NULL in case of error
2821 */
2822xmlCatalogPtr
2823xmlNewCatalog(int sgml) {
2824 xmlCatalogPtr catal = NULL;
2825
2826 if (sgml) {
2827 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2828 xmlCatalogDefaultPrefer);
2829 if ((catal != NULL) && (catal->sgml == NULL))
2830 catal->sgml = xmlHashCreate(10);
2831 } else
2832 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2833 xmlCatalogDefaultPrefer);
2834 return(catal);
2835}
2836
2837/**
2838 * xmlCatalogIsEmpty:
2839 * @catal: should this create an SGML catalog
2840 *
2841 * Check is a catalog is empty
2842 *
2843 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2844 */
2845int
2846xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2847 if (catal == NULL)
2848 return(-1);
2849
2850 if (catal->type == XML_XML_CATALOG_TYPE) {
2851 if (catal->xml == NULL)
2852 return(1);
2853 if ((catal->xml->type != XML_CATA_CATALOG) &&
2854 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2855 return(-1);
2856 if (catal->xml->children == NULL)
2857 return(1);
2858 return(0);
2859 } else {
2860 int res;
2861
2862 if (catal->sgml == NULL)
2863 return(1);
2864 res = xmlHashSize(catal->sgml);
2865 if (res == 0)
2866 return(1);
2867 if (res < 0)
2868 return(-1);
2869 }
2870 return(0);
2871}
2872
Daniel Veillard75b96822001-10-11 18:59:45 +00002873/************************************************************************
2874 * *
2875 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002876 * *
2877 ************************************************************************/
2878
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002879/**
Daniel Veillard81463942001-10-16 12:34:39 +00002880 * xmlInitializeCatalogData:
2881 *
2882 * Do the catalog initialization only of global data, doesn't try to load
2883 * any catalog actually.
2884 * this function is not thread safe, catalog initialization should
2885 * preferably be done once at startup
2886 */
2887static void
2888xmlInitializeCatalogData(void) {
2889 if (xmlCatalogInitialized != 0)
2890 return;
2891
2892 if (getenv("XML_DEBUG_CATALOG"))
2893 xmlDebugCatalogs = 1;
2894 xmlCatalogMutex = xmlNewRMutex();
2895
2896 xmlCatalogInitialized = 1;
2897}
2898/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002899 * xmlInitializeCatalog:
2900 *
2901 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002902 * this function is not thread safe, catalog initialization should
2903 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002904 */
2905void
2906xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002907 if (xmlCatalogInitialized != 0)
2908 return;
2909
Daniel Veillard81463942001-10-16 12:34:39 +00002910 xmlInitializeCatalogData();
2911 xmlRMutexLock(xmlCatalogMutex);
2912
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002913 if (getenv("XML_DEBUG_CATALOG"))
2914 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002915
Daniel Veillard75b96822001-10-11 18:59:45 +00002916 if (xmlDefaultCatalog == NULL) {
2917 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002918 char *path;
2919 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00002920 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002921 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00002922
Daniel Veillardb44025c2001-10-11 22:55:55 +00002923 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002924 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002925 catalogs = XML_XML_DEFAULT_CATALOG;
2926
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002927 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2928 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002929 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002930 /* the XML_CATALOG_FILES envvar is allowed to contain a
2931 space-separated list of entries. */
2932 cur = catalogs;
2933 nextent = &catal->xml;
2934 while (*cur != '\0') {
2935 while (IS_BLANK(*cur))
2936 cur++;
2937 if (*cur != 0) {
2938 paths = cur;
2939 while ((*cur != 0) && (!IS_BLANK(*cur)))
2940 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002941 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002942 if (path != NULL) {
2943 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2944 NULL, BAD_CAST path, xmlCatalogDefaultPrefer);
2945 if (*nextent != NULL)
2946 nextent = &((*nextent)->next);
2947 xmlFree(path);
2948 }
2949 }
2950 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002951 xmlDefaultCatalog = catal;
2952 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002953 }
2954
Daniel Veillard81463942001-10-16 12:34:39 +00002955 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002956}
2957
Daniel Veillard82d75332001-10-08 15:01:59 +00002958
2959/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002960 * xmlLoadCatalog:
2961 * @filename: a file path
2962 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002963 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002964 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002965 * this function is not thread safe, catalog initialization should
2966 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002967 *
2968 * Returns 0 in case of success -1 in case of error
2969 */
2970int
Daniel Veillard16756b62001-10-01 07:36:25 +00002971xmlLoadCatalog(const char *filename)
2972{
Daniel Veillard75b96822001-10-11 18:59:45 +00002973 int ret;
2974 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002975
Daniel Veillard81463942001-10-16 12:34:39 +00002976 if (!xmlCatalogInitialized)
2977 xmlInitializeCatalogData();
2978
2979 xmlRMutexLock(xmlCatalogMutex);
2980
Daniel Veillard75b96822001-10-11 18:59:45 +00002981 if (xmlDefaultCatalog == NULL) {
2982 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00002983 if (catal == NULL) {
2984 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002985 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00002986 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002987
Daniel Veillard75b96822001-10-11 18:59:45 +00002988 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002989 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002990 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002991 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002992
Daniel Veillard75b96822001-10-11 18:59:45 +00002993 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002994 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002995 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002996}
2997
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002998/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002999 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003000 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003001 *
3002 * Load the catalogs and makes their definitions effective for the default
3003 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003004 * this function is not thread safe, catalog initialization should
3005 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003006 */
3007void
3008xmlLoadCatalogs(const char *pathss) {
3009 const char *cur;
3010 const char *paths;
3011 xmlChar *path;
3012
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003013 if (pathss == NULL)
3014 return;
3015
Daniel Veillard81418e32001-05-22 15:08:55 +00003016 cur = pathss;
3017 while ((cur != NULL) && (*cur != 0)) {
3018 while (IS_BLANK(*cur)) cur++;
3019 if (*cur != 0) {
3020 paths = cur;
Igor Zlatkovicee1494a2002-10-31 16:15:29 +00003021 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003022 cur++;
3023 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3024 if (path != NULL) {
3025 xmlLoadCatalog((const char *) path);
3026 xmlFree(path);
3027 }
3028 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003029 while (*cur == ':')
3030 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003031 }
3032}
3033
Daniel Veillarda7374592001-05-10 14:17:55 +00003034/**
3035 * xmlCatalogCleanup:
3036 *
3037 * Free up all the memory associated with catalogs
3038 */
3039void
3040xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003041 if (xmlCatalogInitialized == 0)
3042 return;
3043
Daniel Veillard81463942001-10-16 12:34:39 +00003044 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003045 if (xmlDebugCatalogs)
3046 xmlGenericError(xmlGenericErrorContext,
3047 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003048 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003049 xmlHashFree(xmlCatalogXMLFiles,
3050 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003051 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003052 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003053 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003054 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003055 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003056 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003057 xmlRMutexUnlock(xmlCatalogMutex);
3058 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003059}
3060
3061/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003062 * xmlCatalogResolveSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003063 * @sysID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003064 *
3065 * Try to lookup the catalog resource for a system ID
3066 *
3067 * Returns the system ID if found or NULL otherwise, the value returned
3068 * must be freed by the caller.
3069 */
3070xmlChar *
3071xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003072 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003073
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003074 if (!xmlCatalogInitialized)
3075 xmlInitializeCatalog();
3076
Daniel Veillard75b96822001-10-11 18:59:45 +00003077 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3078 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003079}
3080
3081/**
3082 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003083 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003084 *
3085 * Try to lookup the system ID associated to a public ID
3086 *
3087 * Returns the system ID if found or NULL otherwise, the value returned
3088 * must be freed by the caller.
3089 */
3090xmlChar *
3091xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003092 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003093
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003094 if (!xmlCatalogInitialized)
3095 xmlInitializeCatalog();
3096
Daniel Veillard75b96822001-10-11 18:59:45 +00003097 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3098 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003099}
Daniel Veillard344cee72001-08-20 00:08:40 +00003100
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003101/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003102 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003103 * @pubID: the public ID string
3104 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003105 *
3106 * Do a complete resolution lookup of an External Identifier
3107 *
3108 * Returns the URI of the resource or NULL if not found, it must be freed
3109 * by the caller.
3110 */
3111xmlChar *
3112xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003113 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003114
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003115 if (!xmlCatalogInitialized)
3116 xmlInitializeCatalog();
3117
Daniel Veillard75b96822001-10-11 18:59:45 +00003118 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3119 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003120}
3121
3122/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003123 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003124 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003125 *
3126 * Do a complete resolution lookup of an URI
3127 *
3128 * Returns the URI of the resource or NULL if not found, it must be freed
3129 * by the caller.
3130 */
3131xmlChar *
3132xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003133 xmlChar *ret;
3134
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003135 if (!xmlCatalogInitialized)
3136 xmlInitializeCatalog();
3137
Daniel Veillard75b96822001-10-11 18:59:45 +00003138 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3139 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003140}
3141
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003142#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003143/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003144 * xmlCatalogDump:
3145 * @out: the file.
3146 *
3147 * Free up all the memory associated with catalogs
3148 */
3149void
3150xmlCatalogDump(FILE *out) {
3151 if (out == NULL)
3152 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003153
Daniel Veillard75b96822001-10-11 18:59:45 +00003154 if (!xmlCatalogInitialized)
3155 xmlInitializeCatalog();
3156
3157 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003158}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003159#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003160
3161/**
3162 * xmlCatalogAdd:
3163 * @type: the type of record to add to the catalog
3164 * @orig: the system, public or prefix to match
3165 * @replace: the replacement value for the match
3166 *
3167 * Add an entry in the catalog, it may overwrite existing but
3168 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003169 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003170 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003171 *
3172 * Returns 0 if successful, -1 otherwise
3173 */
3174int
3175xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3176 int res = -1;
3177
Daniel Veillard81463942001-10-16 12:34:39 +00003178 if (!xmlCatalogInitialized)
3179 xmlInitializeCatalogData();
3180
3181 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003182 /*
3183 * Specific case where one want to override the default catalog
3184 * put in place by xmlInitializeCatalog();
3185 */
3186 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003187 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003188 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003189 xmlCatalogDefaultPrefer);
3190 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003191 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003192
Daniel Veillard81463942001-10-16 12:34:39 +00003193 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003194 return(0);
3195 }
3196
Daniel Veillard75b96822001-10-11 18:59:45 +00003197 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003198 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003199 return(res);
3200}
3201
3202/**
3203 * xmlCatalogRemove:
3204 * @value: the value to remove
3205 *
3206 * Remove an entry from the catalog
3207 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003208 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003209 */
3210int
3211xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003212 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003213
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003214 if (!xmlCatalogInitialized)
3215 xmlInitializeCatalog();
3216
Daniel Veillard81463942001-10-16 12:34:39 +00003217 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003218 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003219 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003220 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003221}
3222
3223/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003224 * xmlCatalogConvert:
3225 *
3226 * Convert all the SGML catalog entries as XML ones
3227 *
3228 * Returns the number of entries converted if successful, -1 otherwise
3229 */
3230int
3231xmlCatalogConvert(void) {
3232 int res = -1;
3233
3234 if (!xmlCatalogInitialized)
3235 xmlInitializeCatalog();
3236
Daniel Veillard81463942001-10-16 12:34:39 +00003237 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003238 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003239 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003240 return(res);
3241}
3242
Daniel Veillard75b96822001-10-11 18:59:45 +00003243/************************************************************************
3244 * *
3245 * Public interface manipulating the common preferences *
3246 * *
3247 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003248
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003249/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003250 * xmlCatalogGetDefaults:
3251 *
3252 * Used to get the user preference w.r.t. to what catalogs should
3253 * be accepted
3254 *
3255 * Returns the current xmlCatalogAllow value
3256 */
3257xmlCatalogAllow
3258xmlCatalogGetDefaults(void) {
3259 return(xmlCatalogDefaultAllow);
3260}
3261
3262/**
3263 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003264 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003265 *
3266 * Used to set the user preference w.r.t. to what catalogs should
3267 * be accepted
3268 */
3269void
3270xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003271 if (xmlDebugCatalogs) {
3272 switch (allow) {
3273 case XML_CATA_ALLOW_NONE:
3274 xmlGenericError(xmlGenericErrorContext,
3275 "Disabling catalog usage\n");
3276 break;
3277 case XML_CATA_ALLOW_GLOBAL:
3278 xmlGenericError(xmlGenericErrorContext,
3279 "Allowing only global catalogs\n");
3280 break;
3281 case XML_CATA_ALLOW_DOCUMENT:
3282 xmlGenericError(xmlGenericErrorContext,
3283 "Allowing only catalogs from the document\n");
3284 break;
3285 case XML_CATA_ALLOW_ALL:
3286 xmlGenericError(xmlGenericErrorContext,
3287 "Allowing all catalogs\n");
3288 break;
3289 }
3290 }
3291 xmlCatalogDefaultAllow = allow;
3292}
3293
3294/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003295 * xmlCatalogSetDefaultPrefer:
3296 * @prefer: the default preference for delegation
3297 *
3298 * Allows to set the preference between public and system for deletion
3299 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003300 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003301 *
3302 * Returns the previous value of the default preference for delegation
3303 */
3304xmlCatalogPrefer
3305xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3306 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3307
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003308 if (prefer == XML_CATA_PREFER_NONE)
3309 return(ret);
3310
3311 if (xmlDebugCatalogs) {
3312 switch (prefer) {
3313 case XML_CATA_PREFER_PUBLIC:
3314 xmlGenericError(xmlGenericErrorContext,
3315 "Setting catalog preference to PUBLIC\n");
3316 break;
3317 case XML_CATA_PREFER_SYSTEM:
3318 xmlGenericError(xmlGenericErrorContext,
3319 "Setting catalog preference to SYSTEM\n");
3320 break;
3321 case XML_CATA_PREFER_NONE:
3322 break;
3323 }
3324 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003325 xmlCatalogDefaultPrefer = prefer;
3326 return(ret);
3327}
3328
3329/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003330 * xmlCatalogSetDebug:
3331 * @level: the debug level of catalogs required
3332 *
3333 * Used to set the debug level for catalog operation, 0 disable
3334 * debugging, 1 enable it
3335 *
3336 * Returns the previous value of the catalog debugging level
3337 */
3338int
3339xmlCatalogSetDebug(int level) {
3340 int ret = xmlDebugCatalogs;
3341
3342 if (level <= 0)
3343 xmlDebugCatalogs = 0;
3344 else
3345 xmlDebugCatalogs = level;
3346 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003347}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003348
Daniel Veillard75b96822001-10-11 18:59:45 +00003349/************************************************************************
3350 * *
3351 * Minimal interfaces used for per-document catalogs by the parser *
3352 * *
3353 ************************************************************************/
3354
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003355/**
3356 * xmlCatalogFreeLocal:
3357 * @catalogs: a document's list of catalogs
3358 *
3359 * Free up the memory associated to the catalog list
3360 */
3361void
3362xmlCatalogFreeLocal(void *catalogs) {
3363 xmlCatalogEntryPtr catal;
3364
Daniel Veillard81463942001-10-16 12:34:39 +00003365 if (!xmlCatalogInitialized)
3366 xmlInitializeCatalog();
3367
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003368 catal = (xmlCatalogEntryPtr) catalogs;
3369 if (catal != NULL)
3370 xmlFreeCatalogEntryList(catal);
3371}
3372
3373
3374/**
3375 * xmlCatalogAddLocal:
3376 * @catalogs: a document's list of catalogs
3377 * @URL: the URL to a new local catalog
3378 *
3379 * Add the new entry to the catalog list
3380 *
3381 * Returns the updated list
3382 */
3383void *
3384xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3385 xmlCatalogEntryPtr catal, add;
3386
3387 if (!xmlCatalogInitialized)
3388 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003389
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003390 if (URL == NULL)
3391 return(catalogs);
3392
3393 if (xmlDebugCatalogs)
3394 xmlGenericError(xmlGenericErrorContext,
3395 "Adding document catalog %s\n", URL);
3396
Daniel Veillardc853b322001-11-06 15:24:37 +00003397 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003398 xmlCatalogDefaultPrefer);
3399 if (add == NULL)
3400 return(catalogs);
3401
3402 catal = (xmlCatalogEntryPtr) catalogs;
3403 if (catal == NULL)
3404 return((void *) add);
3405
3406 while (catal->next != NULL)
3407 catal = catal->next;
3408 catal->next = add;
3409 return(catalogs);
3410}
3411
3412/**
3413 * xmlCatalogLocalResolve:
3414 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003415 * @pubID: the public ID string
3416 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003417 *
3418 * Do a complete resolution lookup of an External Identifier using a
3419 * document's private catalog list
3420 *
3421 * Returns the URI of the resource or NULL if not found, it must be freed
3422 * by the caller.
3423 */
3424xmlChar *
3425xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3426 const xmlChar *sysID) {
3427 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003428 xmlChar *ret;
3429
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003430 if (!xmlCatalogInitialized)
3431 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003432
Daniel Veillard81463942001-10-16 12:34:39 +00003433 if ((pubID == NULL) && (sysID == NULL))
3434 return(NULL);
3435
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003436 if (xmlDebugCatalogs) {
3437 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003438 xmlGenericError(xmlGenericErrorContext,
3439 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003440 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003441 xmlGenericError(xmlGenericErrorContext,
3442 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003443 }
3444 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003445
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003446 catal = (xmlCatalogEntryPtr) catalogs;
3447 if (catal == NULL)
3448 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003449 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3450 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3451 return(ret);
3452 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003453}
3454
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003455/**
3456 * xmlCatalogLocalResolveURI:
3457 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003458 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003459 *
3460 * Do a complete resolution lookup of an URI using a
3461 * document's private catalog list
3462 *
3463 * Returns the URI of the resource or NULL if not found, it must be freed
3464 * by the caller.
3465 */
3466xmlChar *
3467xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3468 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003469 xmlChar *ret;
3470
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003471 if (!xmlCatalogInitialized)
3472 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003473
Daniel Veillard81463942001-10-16 12:34:39 +00003474 if (URI == NULL)
3475 return(NULL);
3476
Daniel Veillard6990bf32001-08-23 21:17:48 +00003477 if (xmlDebugCatalogs)
3478 xmlGenericError(xmlGenericErrorContext,
3479 "Resolve URI %s\n", URI);
3480
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003481 catal = (xmlCatalogEntryPtr) catalogs;
3482 if (catal == NULL)
3483 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003484 ret = xmlCatalogListXMLResolveURI(catal, URI);
3485 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3486 return(ret);
3487 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003488}
3489
Daniel Veillard75b96822001-10-11 18:59:45 +00003490/************************************************************************
3491 * *
3492 * Deprecated interfaces *
3493 * *
3494 ************************************************************************/
3495/**
3496 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003497 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003498 *
3499 * Try to lookup the system ID associated to a public ID
3500 * DEPRECATED, use xmlCatalogResolveSystem()
3501 *
3502 * Returns the system ID if found or NULL otherwise.
3503 */
3504const xmlChar *
3505xmlCatalogGetSystem(const xmlChar *sysID) {
3506 xmlChar *ret;
3507 static xmlChar result[1000];
3508 static int msg = 0;
3509
Daniel Veillard81463942001-10-16 12:34:39 +00003510 if (!xmlCatalogInitialized)
3511 xmlInitializeCatalog();
3512
Daniel Veillard75b96822001-10-11 18:59:45 +00003513 if (msg == 0) {
3514 xmlGenericError(xmlGenericErrorContext,
3515 "Use of deprecated xmlCatalogGetSystem() call\n");
3516 msg++;
3517 }
3518
3519 if (sysID == NULL)
3520 return(NULL);
3521
Daniel Veillard75b96822001-10-11 18:59:45 +00003522 /*
3523 * Check first the XML catalogs
3524 */
3525 if (xmlDefaultCatalog != NULL) {
3526 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3527 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3528 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3529 result[sizeof(result) - 1] = 0;
3530 return(result);
3531 }
3532 }
3533
3534 if (xmlDefaultCatalog != NULL)
3535 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3536 return(NULL);
3537}
3538
3539/**
3540 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003541 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003542 *
3543 * Try to lookup the system ID associated to a public ID
3544 * DEPRECATED, use xmlCatalogResolvePublic()
3545 *
3546 * Returns the system ID if found or NULL otherwise.
3547 */
3548const xmlChar *
3549xmlCatalogGetPublic(const xmlChar *pubID) {
3550 xmlChar *ret;
3551 static xmlChar result[1000];
3552 static int msg = 0;
3553
Daniel Veillard81463942001-10-16 12:34:39 +00003554 if (!xmlCatalogInitialized)
3555 xmlInitializeCatalog();
3556
Daniel Veillard75b96822001-10-11 18:59:45 +00003557 if (msg == 0) {
3558 xmlGenericError(xmlGenericErrorContext,
3559 "Use of deprecated xmlCatalogGetPublic() call\n");
3560 msg++;
3561 }
3562
3563 if (pubID == NULL)
3564 return(NULL);
3565
Daniel Veillard75b96822001-10-11 18:59:45 +00003566 /*
3567 * Check first the XML catalogs
3568 */
3569 if (xmlDefaultCatalog != NULL) {
3570 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3571 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3572 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3573 result[sizeof(result) - 1] = 0;
3574 return(result);
3575 }
3576 }
3577
3578 if (xmlDefaultCatalog != NULL)
3579 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3580 return(NULL);
3581}
3582
Daniel Veillarda7374592001-05-10 14:17:55 +00003583#endif /* LIBXML_CATALOG_ENABLED */