blob: b9f2840ec094260f9857f29164930c64a7b32a35 [file] [log] [blame]
Daniel Veillarda7374592001-05-10 14:17:55 +00001/**
2 * catalog.c: set of generic Catalog related routines
3 *
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
6 *
Daniel Veillard344cee72001-08-20 00:08:40 +00007 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9 *
Daniel Veillarda7374592001-05-10 14:17:55 +000010 * See Copyright for the status of this software.
11 *
12 * Daniel.Veillard@imag.fr
13 */
14
Daniel Veillard34ce8be2002-03-18 19:37:11 +000015#define IN_LIBXML
Daniel Veillarda7374592001-05-10 14:17:55 +000016#include "libxml.h"
17
18#ifdef LIBXML_CATALOG_ENABLED
19#ifdef HAVE_SYS_TYPES_H
20#include <sys/types.h>
21#endif
22#ifdef HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#ifdef HAVE_FCNTL_H
29#include <fcntl.h>
30#endif
Daniel Veillardc0631a62001-09-20 13:56:06 +000031#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000034#include <string.h>
35#include <libxml/xmlmemory.h>
36#include <libxml/hash.h>
37#include <libxml/uri.h>
38#include <libxml/parserInternals.h>
39#include <libxml/catalog.h>
40#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000041#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000042#include <libxml/globals.h>
Daniel Veillarda7374592001-05-10 14:17:55 +000043
Daniel Veillard6990bf32001-08-23 21:17:48 +000044#define MAX_DELEGATE 50
Daniel Veillard5ee43b02003-08-04 00:58:46 +000045#define MAX_CATAL_DEPTH 50
Daniel Veillard6990bf32001-08-23 21:17:48 +000046
Daniel Veillard344cee72001-08-20 00:08:40 +000047/**
48 * TODO:
49 *
50 * macro to flag unimplemented blocks
Daniel Veillard3e59fc52003-04-18 12:34:58 +000051 * XML_CATALOG_PREFER user env to select between system/public prefered
52 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
53 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
54 *> values "system" and "public". I have made the default be "system" to
55 *> match yours.
Daniel Veillard344cee72001-08-20 00:08:40 +000056 */
57#define TODO \
58 xmlGenericError(xmlGenericErrorContext, \
59 "Unimplemented block at %s:%d\n", \
60 __FILE__, __LINE__);
61
Daniel Veillardcda96922001-08-21 10:56:31 +000062#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000063#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000064#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000065#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000066#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000067#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000068#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000069#endif
70
Daniel Veillardfb382b82004-06-14 12:13:12 +000071#if defined(_WIN32) && defined(_MSC_VER)
72#undef XML_XML_DEFAULT_CATALOG
73static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
74void* __stdcall GetModuleHandleA(const char*);
75unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
76#endif
77
Daniel Veillard85c11fa2001-10-16 21:03:08 +000078static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000079
Daniel Veillarda7374592001-05-10 14:17:55 +000080/************************************************************************
81 * *
82 * Types, all private *
83 * *
84 ************************************************************************/
85
86typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000087 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000088 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000089 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000090 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000091 XML_CATA_NEXT_CATALOG,
92 XML_CATA_PUBLIC,
93 XML_CATA_SYSTEM,
94 XML_CATA_REWRITE_SYSTEM,
95 XML_CATA_DELEGATE_PUBLIC,
96 XML_CATA_DELEGATE_SYSTEM,
97 XML_CATA_URI,
98 XML_CATA_REWRITE_URI,
99 XML_CATA_DELEGATE_URI,
100 SGML_CATA_SYSTEM,
101 SGML_CATA_PUBLIC,
102 SGML_CATA_ENTITY,
103 SGML_CATA_PENTITY,
104 SGML_CATA_DOCTYPE,
105 SGML_CATA_LINKTYPE,
106 SGML_CATA_NOTATION,
107 SGML_CATA_DELEGATE,
108 SGML_CATA_BASE,
109 SGML_CATA_CATALOG,
110 SGML_CATA_DOCUMENT,
111 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000112} xmlCatalogEntryType;
113
114typedef struct _xmlCatalogEntry xmlCatalogEntry;
115typedef xmlCatalogEntry *xmlCatalogEntryPtr;
116struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000117 struct _xmlCatalogEntry *next;
118 struct _xmlCatalogEntry *parent;
119 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000120 xmlCatalogEntryType type;
121 xmlChar *name;
122 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000123 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000124 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000125 int dealloc;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000126 int depth;
Daniel Veillarda7374592001-05-10 14:17:55 +0000127};
128
Daniel Veillard75b96822001-10-11 18:59:45 +0000129typedef enum {
130 XML_XML_CATALOG_TYPE = 1,
131 XML_SGML_CATALOG_TYPE
132} xmlCatalogType;
133
134#define XML_MAX_SGML_CATA_DEPTH 10
135struct _xmlCatalog {
136 xmlCatalogType type; /* either XML or SGML */
137
138 /*
139 * SGML Catalogs are stored as a simple hash table of catalog entries
140 * Catalog stack to check against overflows when building the
141 * SGML catalog
142 */
143 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
144 int catalNr; /* Number of current catal streams */
145 int catalMax; /* Max number of catal streams */
146 xmlHashTablePtr sgml;
147
148 /*
149 * XML Catalogs are stored as a tree of Catalog entries
150 */
151 xmlCatalogPrefer prefer;
152 xmlCatalogEntryPtr xml;
153};
154
155/************************************************************************
156 * *
157 * Global variables *
158 * *
159 ************************************************************************/
160
Daniel Veillard81463942001-10-16 12:34:39 +0000161/*
162 * Those are preferences
163 */
164static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000165static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000166static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000167
168/*
169 * Hash table containing all the trees of XML catalogs parsed by
170 * the application.
171 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000172static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000173
174/*
175 * The default catalog in use by the application
176 */
177static xmlCatalogPtr xmlDefaultCatalog = NULL;
178
179/*
Daniel Veillard81463942001-10-16 12:34:39 +0000180 * A mutex for modifying the shared global catalog(s)
181 * xmlDefaultCatalog tree.
182 * It also protects xmlCatalogXMLFiles
183 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
184 */
185static xmlRMutexPtr xmlCatalogMutex = NULL;
186
187/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000188 * Whether the catalog support was initialized.
189 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000190static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000191
Daniel Veillard69d2c172003-10-09 11:46:07 +0000192/************************************************************************
193 * *
194 * Catalog error handlers *
195 * *
196 ************************************************************************/
197
198/**
199 * xmlCatalogErrMemory:
200 * @extra: extra informations
201 *
202 * Handle an out of memory condition
203 */
204static void
205xmlCatalogErrMemory(const char *extra)
206{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000207 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000208 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
209 extra, NULL, NULL, 0, 0,
210 "Memory allocation failed : %s\n", extra);
211}
212
213/**
214 * xmlCatalogErr:
215 * @catal: the Catalog entry
216 * @node: the context node
217 * @msg: the error message
218 * @extra: extra informations
219 *
220 * Handle a catalog error
221 */
222static void
223xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
224 const char *msg, const xmlChar *str1, const xmlChar *str2,
225 const xmlChar *str3)
226{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000227 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000228 error, XML_ERR_ERROR, NULL, 0,
229 (const char *) str1, (const char *) str2,
230 (const char *) str3, 0, 0,
231 msg, str1, str2, str3);
232}
233
Daniel Veillarda7374592001-05-10 14:17:55 +0000234
235/************************************************************************
236 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000237 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000238 * *
239 ************************************************************************/
240
Daniel Veillard75b96822001-10-11 18:59:45 +0000241/**
242 * xmlNewCatalogEntry:
243 * @type: type of entry
244 * @name: name of the entry
245 * @value: value of the entry
246 * @prefer: the PUBLIC vs. SYSTEM current preference value
247 *
248 * create a new Catalog entry, this type is shared both by XML and
249 * SGML catalogs, but the acceptable types values differs.
250 *
251 * Returns the xmlCatalogEntryPtr or NULL in case of error
252 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000253static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000254xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillardc853b322001-11-06 15:24:37 +0000255 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000256 xmlCatalogEntryPtr ret;
257
258 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
259 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000260 xmlCatalogErrMemory("allocating catalog entry");
Daniel Veillarda7374592001-05-10 14:17:55 +0000261 return(NULL);
262 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000263 ret->next = NULL;
264 ret->parent = NULL;
265 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000266 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000267 if (name != NULL)
268 ret->name = xmlStrdup(name);
269 else
270 ret->name = NULL;
271 if (value != NULL)
272 ret->value = xmlStrdup(value);
273 else
274 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000275 if (URL == NULL)
276 URL = value;
277 if (URL != NULL)
278 ret->URL = xmlStrdup(URL);
279 else
280 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000281 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000282 ret->dealloc = 0;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000283 ret->depth = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +0000284 return(ret);
285}
286
287static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000288xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
289
Daniel Veillard75b96822001-10-11 18:59:45 +0000290/**
291 * xmlFreeCatalogEntry:
292 * @ret: a Catalog entry
293 *
294 * Free the memory allocated to a Catalog entry
295 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000296static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000297xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
298 if (ret == NULL)
299 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000300 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000301 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000302 * only by the file hash cleaner !
303 */
304 if (ret->dealloc == 1)
305 return;
306
307 if (xmlDebugCatalogs) {
308 if (ret->name != NULL)
309 xmlGenericError(xmlGenericErrorContext,
310 "Free catalog entry %s\n", ret->name);
311 else if (ret->value != NULL)
312 xmlGenericError(xmlGenericErrorContext,
313 "Free catalog entry %s\n", ret->value);
314 else
315 xmlGenericError(xmlGenericErrorContext,
316 "Free catalog entry\n");
317 }
318
Daniel Veillarda7374592001-05-10 14:17:55 +0000319 if (ret->name != NULL)
320 xmlFree(ret->name);
321 if (ret->value != NULL)
322 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000323 if (ret->URL != NULL)
324 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000325 xmlFree(ret);
326}
327
Daniel Veillard75b96822001-10-11 18:59:45 +0000328/**
329 * xmlFreeCatalogEntryList:
330 * @ret: a Catalog entry list
331 *
332 * Free the memory allocated to a full chained list of Catalog entries
333 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000334static void
335xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
336 xmlCatalogEntryPtr next;
337
338 while (ret != NULL) {
339 next = ret->next;
340 xmlFreeCatalogEntry(ret);
341 ret = next;
342 }
343}
344
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000345/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000346 * xmlFreeCatalogHashEntryList:
347 * @ret: a Catalog entry list
348 *
349 * Free the memory allocated to list of Catalog entries from the
350 * catalog file hash.
351 */
352static void
353xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
354 xmlCatalogEntryPtr children, next;
355
356 if (catal == NULL)
357 return;
358
359 children = catal->children;
360 while (children != NULL) {
361 next = children->next;
362 children->dealloc = 0;
363 children->children = NULL;
364 xmlFreeCatalogEntry(children);
365 children = next;
366 }
367 catal->dealloc = 0;
368 xmlFreeCatalogEntry(catal);
369}
370
371/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000372 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000373 * @type: type of catalog
374 * @prefer: the PUBLIC vs. SYSTEM current preference value
375 *
376 * create a new Catalog, this type is shared both by XML and
377 * SGML catalogs, but the acceptable types values differs.
378 *
379 * Returns the xmlCatalogPtr or NULL in case of error
380 */
381static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000382xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000383 xmlCatalogPtr ret;
384
385 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
386 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000387 xmlCatalogErrMemory("allocating catalog");
Daniel Veillard75b96822001-10-11 18:59:45 +0000388 return(NULL);
389 }
390 memset(ret, 0, sizeof(xmlCatalog));
391 ret->type = type;
392 ret->catalNr = 0;
393 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
394 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000395 if (ret->type == XML_SGML_CATALOG_TYPE)
396 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000397 return(ret);
398}
399
400/**
401 * xmlFreeCatalog:
Daniel Veillard06d25242004-02-25 13:01:42 +0000402 * @catal: a Catalog
Daniel Veillard75b96822001-10-11 18:59:45 +0000403 *
404 * Free the memory allocated to a Catalog
405 */
406void
407xmlFreeCatalog(xmlCatalogPtr catal) {
408 if (catal == NULL)
409 return;
410 if (catal->xml != NULL)
411 xmlFreeCatalogEntryList(catal->xml);
412 if (catal->sgml != NULL)
413 xmlHashFree(catal->sgml,
414 (xmlHashDeallocator) xmlFreeCatalogEntry);
415 xmlFree(catal);
416}
417
418/************************************************************************
419 * *
420 * Serializing Catalogs *
421 * *
422 ************************************************************************/
423
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000424#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000425/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000426 * xmlCatalogDumpEntry:
Daniel Veillard06d25242004-02-25 13:01:42 +0000427 * @entry: the catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000428 * @out: the file.
429 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000430 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000431 */
432static void
433xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
434 if ((entry == NULL) || (out == NULL))
435 return;
436 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000437 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000438 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000439 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000440 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000441 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000442 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000443 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000444 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000445 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000446 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000447 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000448 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000449 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000450 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000451 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000452 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000453 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000454 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000455 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000456 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000457 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000458 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000459 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000460 fprintf(out, "SGMLDECL "); break;
461 default:
462 return;
463 }
464 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000465 case SGML_CATA_ENTITY:
466 case SGML_CATA_PENTITY:
467 case SGML_CATA_DOCTYPE:
468 case SGML_CATA_LINKTYPE:
469 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000470 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000471 case SGML_CATA_PUBLIC:
472 case SGML_CATA_SYSTEM:
473 case SGML_CATA_SGMLDECL:
474 case SGML_CATA_DOCUMENT:
475 case SGML_CATA_CATALOG:
476 case SGML_CATA_BASE:
477 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000478 fprintf(out, "\"%s\"", entry->name); break;
479 default:
480 break;
481 }
482 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000483 case SGML_CATA_ENTITY:
484 case SGML_CATA_PENTITY:
485 case SGML_CATA_DOCTYPE:
486 case SGML_CATA_LINKTYPE:
487 case SGML_CATA_NOTATION:
488 case SGML_CATA_PUBLIC:
489 case SGML_CATA_SYSTEM:
490 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000491 fprintf(out, " \"%s\"", entry->value); break;
492 default:
493 break;
494 }
495 fprintf(out, "\n");
496}
497
Daniel Veillard75b96822001-10-11 18:59:45 +0000498static int
499xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
500 int ret;
501 xmlDocPtr doc;
502 xmlNsPtr ns;
503 xmlDtdPtr dtd;
504 xmlNodePtr node, catalog;
505 xmlOutputBufferPtr buf;
506 xmlCatalogEntryPtr cur;
507
508 /*
509 * Rebuild a catalog
510 */
511 doc = xmlNewDoc(NULL);
512 if (doc == NULL)
513 return(-1);
514 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
515 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
516BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
517
518 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
519
520 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
521 if (ns == NULL) {
522 xmlFreeDoc(doc);
523 return(-1);
524 }
525 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
526 if (catalog == NULL) {
527 xmlFreeNs(ns);
528 xmlFreeDoc(doc);
529 return(-1);
530 }
531 catalog->nsDef = ns;
532 xmlAddChild((xmlNodePtr) doc, catalog);
533
534 /*
535 * add all the catalog entries
536 */
537 cur = catal;
538 while (cur != NULL) {
539 switch (cur->type) {
Daniel Veillardc853b322001-11-06 15:24:37 +0000540 case XML_CATA_REMOVED:
541 break;
Daniel Veillard75b96822001-10-11 18:59:45 +0000542 case XML_CATA_BROKEN_CATALOG:
543 case XML_CATA_CATALOG:
544 if (cur == catal) {
545 cur = cur->children;
546 continue;
547 }
548 break;
549 case XML_CATA_NEXT_CATALOG:
550 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
551 xmlSetProp(node, BAD_CAST "catalog", cur->value);
552 xmlAddChild(catalog, node);
553 break;
554 case XML_CATA_NONE:
555 break;
556 case XML_CATA_PUBLIC:
557 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
558 xmlSetProp(node, BAD_CAST "publicId", cur->name);
559 xmlSetProp(node, BAD_CAST "uri", cur->value);
560 xmlAddChild(catalog, node);
561 break;
562 case XML_CATA_SYSTEM:
563 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
564 xmlSetProp(node, BAD_CAST "systemId", cur->name);
565 xmlSetProp(node, BAD_CAST "uri", cur->value);
566 xmlAddChild(catalog, node);
567 break;
568 case XML_CATA_REWRITE_SYSTEM:
569 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
570 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
571 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
572 xmlAddChild(catalog, node);
573 break;
574 case XML_CATA_DELEGATE_PUBLIC:
575 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
576 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
577 xmlSetProp(node, BAD_CAST "catalog", cur->value);
578 xmlAddChild(catalog, node);
579 break;
580 case XML_CATA_DELEGATE_SYSTEM:
581 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
582 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
583 xmlSetProp(node, BAD_CAST "catalog", cur->value);
584 xmlAddChild(catalog, node);
585 break;
586 case XML_CATA_URI:
587 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
588 xmlSetProp(node, BAD_CAST "name", cur->name);
589 xmlSetProp(node, BAD_CAST "uri", cur->value);
590 xmlAddChild(catalog, node);
591 break;
592 case XML_CATA_REWRITE_URI:
593 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
594 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
595 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
596 xmlAddChild(catalog, node);
597 break;
598 case XML_CATA_DELEGATE_URI:
599 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
600 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
601 xmlSetProp(node, BAD_CAST "catalog", cur->value);
602 xmlAddChild(catalog, node);
603 break;
604 case SGML_CATA_SYSTEM:
605 case SGML_CATA_PUBLIC:
606 case SGML_CATA_ENTITY:
607 case SGML_CATA_PENTITY:
608 case SGML_CATA_DOCTYPE:
609 case SGML_CATA_LINKTYPE:
610 case SGML_CATA_NOTATION:
611 case SGML_CATA_DELEGATE:
612 case SGML_CATA_BASE:
613 case SGML_CATA_CATALOG:
614 case SGML_CATA_DOCUMENT:
615 case SGML_CATA_SGMLDECL:
616 break;
617 }
618 cur = cur->next;
619 }
620
621 /*
622 * reserialize it
623 */
624 buf = xmlOutputBufferCreateFile(out, NULL);
625 if (buf == NULL) {
626 xmlFreeDoc(doc);
627 return(-1);
628 }
629 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
630
631 /*
632 * Free it
633 */
634 xmlFreeDoc(doc);
635
636 return(ret);
637}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000638#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000639
640/************************************************************************
641 * *
642 * Converting SGML Catalogs to XML *
643 * *
644 ************************************************************************/
645
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000646/**
647 * xmlCatalogConvertEntry:
648 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000649 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000650 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000651 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000652 */
653static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000654xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
655 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
656 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000657 return;
658 switch (entry->type) {
659 case SGML_CATA_ENTITY:
660 entry->type = XML_CATA_PUBLIC;
661 break;
662 case SGML_CATA_PENTITY:
663 entry->type = XML_CATA_PUBLIC;
664 break;
665 case SGML_CATA_DOCTYPE:
666 entry->type = XML_CATA_PUBLIC;
667 break;
668 case SGML_CATA_LINKTYPE:
669 entry->type = XML_CATA_PUBLIC;
670 break;
671 case SGML_CATA_NOTATION:
672 entry->type = XML_CATA_PUBLIC;
673 break;
674 case SGML_CATA_PUBLIC:
675 entry->type = XML_CATA_PUBLIC;
676 break;
677 case SGML_CATA_SYSTEM:
678 entry->type = XML_CATA_SYSTEM;
679 break;
680 case SGML_CATA_DELEGATE:
681 entry->type = XML_CATA_DELEGATE_PUBLIC;
682 break;
683 case SGML_CATA_CATALOG:
684 entry->type = XML_CATA_CATALOG;
685 break;
686 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000687 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000688 (xmlHashDeallocator) xmlFreeCatalogEntry);
689 return;
690 }
691 /*
692 * Conversion successful, remove from the SGML catalog
693 * and add it to the default XML one
694 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000695 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
696 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000697 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000698 if (catal->xml->children == NULL)
699 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000700 else {
701 xmlCatalogEntryPtr prev;
702
Daniel Veillard75b96822001-10-11 18:59:45 +0000703 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000704 while (prev->next != NULL)
705 prev = prev->next;
706 prev->next = entry;
707 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000708}
709
710/**
711 * xmlConvertSGMLCatalog:
712 * @catal: the catalog
713 *
714 * Convert all the SGML catalog entries as XML ones
715 *
716 * Returns the number of entries converted if successful, -1 otherwise
717 */
718int
719xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
720
721 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
722 return(-1);
723
724 if (xmlDebugCatalogs) {
725 xmlGenericError(xmlGenericErrorContext,
726 "Converting SGML catalog to XML\n");
727 }
728 xmlHashScan(catal->sgml,
729 (xmlHashScanner) xmlCatalogConvertEntry,
730 &catal);
731 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000732}
733
Daniel Veillarda7374592001-05-10 14:17:55 +0000734/************************************************************************
735 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000736 * Helper function *
737 * *
738 ************************************************************************/
739
740/**
741 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000742 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000743 *
744 * Expand the URN into the equivalent Public Identifier
745 *
746 * Returns the new identifier or NULL, the string must be deallocated
747 * by the caller.
748 */
749static xmlChar *
750xmlCatalogUnWrapURN(const xmlChar *urn) {
751 xmlChar result[2000];
752 unsigned int i = 0;
753
754 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
755 return(NULL);
756 urn += sizeof(XML_URN_PUBID) - 1;
757
758 while (*urn != 0) {
Daniel Veillard770075b2004-02-25 10:44:30 +0000759 if (i > sizeof(result) - 4)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000760 break;
761 if (*urn == '+') {
762 result[i++] = ' ';
763 urn++;
764 } else if (*urn == ':') {
765 result[i++] = '/';
766 result[i++] = '/';
767 urn++;
768 } else if (*urn == ';') {
769 result[i++] = ':';
770 result[i++] = ':';
771 urn++;
772 } else if (*urn == '%') {
Daniel Veillard770075b2004-02-25 10:44:30 +0000773 if ((urn[1] == '2') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000774 result[i++] = '+';
Daniel Veillard770075b2004-02-25 10:44:30 +0000775 else if ((urn[1] == '3') && (urn[2] == 'A'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000776 result[i++] = ':';
Daniel Veillard770075b2004-02-25 10:44:30 +0000777 else if ((urn[1] == '2') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000778 result[i++] = '/';
Daniel Veillard770075b2004-02-25 10:44:30 +0000779 else if ((urn[1] == '3') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000780 result[i++] = ';';
Daniel Veillard770075b2004-02-25 10:44:30 +0000781 else if ((urn[1] == '2') && (urn[2] == '7'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000782 result[i++] = '\'';
Daniel Veillard770075b2004-02-25 10:44:30 +0000783 else if ((urn[1] == '3') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000784 result[i++] = '?';
Daniel Veillard770075b2004-02-25 10:44:30 +0000785 else if ((urn[1] == '2') && (urn[2] == '3'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000786 result[i++] = '#';
Daniel Veillard770075b2004-02-25 10:44:30 +0000787 else if ((urn[1] == '2') && (urn[2] == '5'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000788 result[i++] = '%';
789 else {
790 result[i++] = *urn;
791 urn++;
792 continue;
793 }
794 urn += 3;
795 } else {
796 result[i++] = *urn;
797 urn++;
798 }
799 }
800 result[i] = 0;
801
802 return(xmlStrdup(result));
803}
804
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000805/**
806 * xmlParseCatalogFile:
807 * @filename: the filename
808 *
809 * parse an XML file and build a tree. It's like xmlParseFile()
810 * except it bypass all catalog lookups.
811 *
812 * Returns the resulting document tree or NULL in case of error
813 */
814
815xmlDocPtr
816xmlParseCatalogFile(const char *filename) {
817 xmlDocPtr ret;
818 xmlParserCtxtPtr ctxt;
819 char *directory = NULL;
820 xmlParserInputPtr inputStream;
821 xmlParserInputBufferPtr buf;
822
823 ctxt = xmlNewParserCtxt();
824 if (ctxt == NULL) {
825 if (xmlDefaultSAXHandler.error != NULL) {
826 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
827 }
828 return(NULL);
829 }
830
831 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
832 if (buf == NULL) {
833 xmlFreeParserCtxt(ctxt);
834 return(NULL);
835 }
836
837 inputStream = xmlNewInputStream(ctxt);
838 if (inputStream == NULL) {
839 xmlFreeParserCtxt(ctxt);
840 return(NULL);
841 }
842
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000843 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000844 inputStream->buf = buf;
845 inputStream->base = inputStream->buf->buffer->content;
846 inputStream->cur = inputStream->buf->buffer->content;
847 inputStream->end =
848 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
849
850 inputPush(ctxt, inputStream);
851 if ((ctxt->directory == NULL) && (directory == NULL))
852 directory = xmlParserGetDirectory(filename);
853 if ((ctxt->directory == NULL) && (directory != NULL))
854 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000855 ctxt->valid = 0;
856 ctxt->validate = 0;
857 ctxt->loadsubset = 0;
858 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000859
860 xmlParseDocument(ctxt);
861
862 if (ctxt->wellFormed)
863 ret = ctxt->myDoc;
864 else {
865 ret = NULL;
866 xmlFreeDoc(ctxt->myDoc);
867 ctxt->myDoc = NULL;
868 }
869 xmlFreeParserCtxt(ctxt);
870
871 return(ret);
872}
873
Daniel Veillard75b96822001-10-11 18:59:45 +0000874/**
875 * xmlLoadFileContent:
876 * @filename: a file path
877 *
878 * Load a file content into memory.
879 *
880 * Returns a pointer to the 0 terminated string or NULL in case of error
881 */
882static xmlChar *
883xmlLoadFileContent(const char *filename)
884{
885#ifdef HAVE_STAT
886 int fd;
887#else
888 FILE *fd;
889#endif
890 int len;
891 long size;
892
893#ifdef HAVE_STAT
894 struct stat info;
895#endif
896 xmlChar *content;
897
898 if (filename == NULL)
899 return (NULL);
900
901#ifdef HAVE_STAT
902 if (stat(filename, &info) < 0)
903 return (NULL);
904#endif
905
906#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000907 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000908#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000909 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000910#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000911 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000912 return (NULL);
913 }
914#ifdef HAVE_STAT
915 size = info.st_size;
916#else
917 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
918 fclose(fd);
919 return (NULL);
920 }
921#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000922 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000923 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000924 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard75b96822001-10-11 18:59:45 +0000925 return (NULL);
926 }
927#ifdef HAVE_STAT
928 len = read(fd, content, size);
929#else
930 len = fread(content, 1, size, fd);
931#endif
932 if (len < 0) {
933 xmlFree(content);
934 return (NULL);
935 }
936#ifdef HAVE_STAT
937 close(fd);
938#else
939 fclose(fd);
940#endif
941 content[len] = 0;
942
943 return(content);
944}
945
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000946/************************************************************************
947 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000948 * The XML Catalog parser *
949 * *
950 ************************************************************************/
951
952static xmlCatalogEntryPtr
953xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000954static void
955xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
956 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000957static xmlChar *
958xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
959 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000960static xmlChar *
961xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
962
Daniel Veillard344cee72001-08-20 00:08:40 +0000963
Daniel Veillard75b96822001-10-11 18:59:45 +0000964/**
965 * xmlGetXMLCatalogEntryType:
966 * @name: the name
967 *
968 * lookup the internal type associated to an XML catalog entry name
969 *
Daniel Veillard06d25242004-02-25 13:01:42 +0000970 * Returns the type associated with that name
Daniel Veillard75b96822001-10-11 18:59:45 +0000971 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000972static xmlCatalogEntryType
973xmlGetXMLCatalogEntryType(const xmlChar *name) {
974 xmlCatalogEntryType type = XML_CATA_NONE;
975 if (xmlStrEqual(name, (const xmlChar *) "system"))
976 type = XML_CATA_SYSTEM;
977 else if (xmlStrEqual(name, (const xmlChar *) "public"))
978 type = XML_CATA_PUBLIC;
979 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
980 type = XML_CATA_REWRITE_SYSTEM;
981 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
982 type = XML_CATA_DELEGATE_PUBLIC;
983 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
984 type = XML_CATA_DELEGATE_SYSTEM;
985 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
986 type = XML_CATA_URI;
987 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
988 type = XML_CATA_REWRITE_URI;
989 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
990 type = XML_CATA_DELEGATE_URI;
991 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
992 type = XML_CATA_NEXT_CATALOG;
993 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
994 type = XML_CATA_CATALOG;
995 return(type);
996}
997
Daniel Veillard75b96822001-10-11 18:59:45 +0000998/**
999 * xmlParseXMLCatalogOneNode:
1000 * @cur: the XML node
1001 * @type: the type of Catalog entry
1002 * @name: the name of the node
1003 * @attrName: the attribute holding the value
1004 * @uriAttrName: the attribute holding the URI-Reference
1005 * @prefer: the PUBLIC vs. SYSTEM current preference value
1006 *
1007 * Finishes the examination of an XML tree node of a catalog and build
1008 * a Catalog entry from it.
1009 *
1010 * Returns the new Catalog entry node or NULL in case of error.
1011 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001012static xmlCatalogEntryPtr
1013xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1014 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001015 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001016 int ok = 1;
1017 xmlChar *uriValue;
1018 xmlChar *nameValue = NULL;
1019 xmlChar *base = NULL;
1020 xmlChar *URL = NULL;
1021 xmlCatalogEntryPtr ret = NULL;
1022
1023 if (attrName != NULL) {
1024 nameValue = xmlGetProp(cur, attrName);
1025 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001026 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1027 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001028 ok = 0;
1029 }
1030 }
1031 uriValue = xmlGetProp(cur, uriAttrName);
1032 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001033 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1034 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001035 ok = 0;
1036 }
1037 if (!ok) {
1038 if (nameValue != NULL)
1039 xmlFree(nameValue);
1040 if (uriValue != NULL)
1041 xmlFree(uriValue);
1042 return(NULL);
1043 }
1044
1045 base = xmlNodeGetBase(cur->doc, cur);
1046 URL = xmlBuildURI(uriValue, base);
1047 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001048 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001049 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001050 xmlGenericError(xmlGenericErrorContext,
1051 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001052 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001053 xmlGenericError(xmlGenericErrorContext,
1054 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001055 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001056 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001057 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001058 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001059 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1060 }
1061 if (nameValue != NULL)
1062 xmlFree(nameValue);
1063 if (uriValue != NULL)
1064 xmlFree(uriValue);
1065 if (base != NULL)
1066 xmlFree(base);
1067 if (URL != NULL)
1068 xmlFree(URL);
1069 return(ret);
1070}
1071
Daniel Veillard75b96822001-10-11 18:59:45 +00001072/**
1073 * xmlParseXMLCatalogNode:
1074 * @cur: the XML node
1075 * @prefer: the PUBLIC vs. SYSTEM current preference value
1076 * @parent: the parent Catalog entry
1077 *
1078 * Examines an XML tree node of a catalog and build
1079 * a Catalog entry from it adding it to its parent. The examination can
1080 * be recursive.
1081 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001082static void
1083xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1084 xmlCatalogEntryPtr parent)
1085{
1086 xmlChar *uri = NULL;
1087 xmlChar *URL = NULL;
1088 xmlChar *base = NULL;
1089 xmlCatalogEntryPtr entry = NULL;
1090
1091 if (cur == NULL)
1092 return;
1093 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1094 xmlChar *prop;
1095
1096 prop = xmlGetProp(cur, BAD_CAST "prefer");
1097 if (prop != NULL) {
1098 if (xmlStrEqual(prop, BAD_CAST "system")) {
1099 prefer = XML_CATA_PREFER_SYSTEM;
1100 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1101 prefer = XML_CATA_PREFER_PUBLIC;
1102 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001103 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1104 "Invalid value for prefer: '%s'\n",
1105 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001106 }
1107 xmlFree(prop);
1108 }
1109 /*
1110 * Recurse to propagate prefer to the subtree
1111 * (xml:base handling is automated)
1112 */
1113 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1114 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1115 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001116 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001117 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1118 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001119 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001120 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1121 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1122 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001123 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001124 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1125 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1126 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001127 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001128 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1129 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1130 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001131 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001132 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1133 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1134 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001135 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001136 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1137 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1138 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001139 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001140 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1141 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1142 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001143 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001144 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1145 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1146 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001147 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001148 }
1149 if ((entry != NULL) && (parent != NULL)) {
1150 entry->parent = parent;
1151 if (parent->children == NULL)
1152 parent->children = entry;
1153 else {
1154 xmlCatalogEntryPtr prev;
1155
1156 prev = parent->children;
1157 while (prev->next != NULL)
1158 prev = prev->next;
1159 prev->next = entry;
1160 }
1161 }
1162 if (base != NULL)
1163 xmlFree(base);
1164 if (uri != NULL)
1165 xmlFree(uri);
1166 if (URL != NULL)
1167 xmlFree(URL);
1168}
1169
Daniel Veillard75b96822001-10-11 18:59:45 +00001170/**
1171 * xmlParseXMLCatalogNodeList:
1172 * @cur: the XML node list of siblings
1173 * @prefer: the PUBLIC vs. SYSTEM current preference value
1174 * @parent: the parent Catalog entry
1175 *
1176 * Examines a list of XML sibling nodes of a catalog and build
1177 * a list of Catalog entry from it adding it to the parent.
1178 * The examination will recurse to examine node subtrees.
1179 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001180static void
1181xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1182 xmlCatalogEntryPtr parent) {
1183 while (cur != NULL) {
1184 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1185 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1186 xmlParseXMLCatalogNode(cur, prefer, parent);
1187 }
1188 cur = cur->next;
1189 }
1190 /* TODO: sort the list according to REWRITE lengths and prefer value */
1191}
1192
Daniel Veillard75b96822001-10-11 18:59:45 +00001193/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001194 * xmlParseXMLCatalogFile:
1195 * @prefer: the PUBLIC vs. SYSTEM current preference value
1196 * @filename: the filename for the catalog
1197 *
1198 * Parses the catalog file to extract the XML tree and then analyze the
1199 * tree to build a list of Catalog entries corresponding to this catalog
1200 *
1201 * Returns the resulting Catalog entries list
1202 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001203static xmlCatalogEntryPtr
1204xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1205 xmlDocPtr doc;
1206 xmlNodePtr cur;
1207 xmlChar *prop;
1208 xmlCatalogEntryPtr parent = NULL;
1209
1210 if (filename == NULL)
1211 return(NULL);
1212
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001213 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001214 if (doc == NULL) {
1215 if (xmlDebugCatalogs)
1216 xmlGenericError(xmlGenericErrorContext,
1217 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001218 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001219 }
1220
1221 if (xmlDebugCatalogs)
1222 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001223 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001224
1225 cur = xmlDocGetRootElement(doc);
1226 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1227 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1228 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1229
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001230 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00001231 (const xmlChar *)filename, NULL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001232 if (parent == NULL) {
1233 xmlFreeDoc(doc);
1234 return(NULL);
1235 }
1236
1237 prop = xmlGetProp(cur, BAD_CAST "prefer");
1238 if (prop != NULL) {
1239 if (xmlStrEqual(prop, BAD_CAST "system")) {
1240 prefer = XML_CATA_PREFER_SYSTEM;
1241 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1242 prefer = XML_CATA_PREFER_PUBLIC;
1243 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001244 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1245 "Invalid value for prefer: '%s'\n",
1246 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001247 }
1248 xmlFree(prop);
1249 }
1250 cur = cur->children;
1251 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1252 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001253 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1254 "File %s is not an XML Catalog\n",
1255 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001256 xmlFreeDoc(doc);
1257 return(NULL);
1258 }
1259 xmlFreeDoc(doc);
1260 return(parent);
1261}
1262
Daniel Veillardcda96922001-08-21 10:56:31 +00001263/**
1264 * xmlFetchXMLCatalogFile:
1265 * @catal: an existing but incomplete catalog entry
1266 *
1267 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001268 *
1269 * Returns 0 in case of success, -1 otherwise
1270 */
1271static int
1272xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001273 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001274
1275 if (catal == NULL)
1276 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001277 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001278 return(-1);
1279 if (catal->children != NULL)
1280 return(-1);
1281
Daniel Veillard81463942001-10-16 12:34:39 +00001282 /*
1283 * lock the whole catalog for modification
1284 */
1285 xmlRMutexLock(xmlCatalogMutex);
1286 if (catal->children != NULL) {
1287 /* Okay someone else did it in the meantime */
1288 xmlRMutexUnlock(xmlCatalogMutex);
1289 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001290 }
1291
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001292 if (xmlCatalogXMLFiles != NULL) {
1293 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001294 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001295 if (doc != NULL) {
1296 if (xmlDebugCatalogs)
1297 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001298 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001299
1300 if (catal->type == XML_CATA_CATALOG)
1301 catal->children = doc->children;
1302 else
1303 catal->children = doc;
1304 catal->dealloc = 0;
1305 xmlRMutexUnlock(xmlCatalogMutex);
1306 return(0);
1307 }
1308 if (xmlDebugCatalogs)
1309 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001310 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001311 }
1312
Daniel Veillardcda96922001-08-21 10:56:31 +00001313 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001314 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001315 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001316 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001317 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001318 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001319 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001320 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001321 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001322 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001323 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001324
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001325 if (catal->type == XML_CATA_CATALOG)
1326 catal->children = doc->children;
1327 else
1328 catal->children = doc;
1329
1330 doc->dealloc = 1;
1331
Daniel Veillard81463942001-10-16 12:34:39 +00001332 if (xmlCatalogXMLFiles == NULL)
1333 xmlCatalogXMLFiles = xmlHashCreate(10);
1334 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001335 if (xmlDebugCatalogs)
1336 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001337 "%s added to file hash\n", catal->URL);
1338 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001339 }
Daniel Veillard81463942001-10-16 12:34:39 +00001340 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001341 return(0);
1342}
1343
Daniel Veillard75b96822001-10-11 18:59:45 +00001344/************************************************************************
1345 * *
1346 * XML Catalog handling *
1347 * *
1348 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001349
1350/**
1351 * xmlAddXMLCatalog:
1352 * @catal: top of an XML catalog
1353 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001354 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001355 * @replace: the replacement value for the match
1356 *
1357 * Add an entry in the XML catalog, it may overwrite existing but
1358 * different entries.
1359 *
1360 * Returns 0 if successful, -1 otherwise
1361 */
1362static int
1363xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1364 const xmlChar *orig, const xmlChar *replace) {
1365 xmlCatalogEntryPtr cur;
1366 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001367 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001368
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001369 if ((catal == NULL) ||
1370 ((catal->type != XML_CATA_CATALOG) &&
1371 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001372 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001373 if (catal->children == NULL) {
1374 xmlFetchXMLCatalogFile(catal);
1375 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001376 if (catal->children == NULL)
1377 doregister = 1;
1378
Daniel Veillard344cee72001-08-20 00:08:40 +00001379 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001380 if (typ == XML_CATA_NONE) {
1381 if (xmlDebugCatalogs)
1382 xmlGenericError(xmlGenericErrorContext,
1383 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001384 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001385 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001386
1387 cur = catal->children;
1388 /*
1389 * Might be a simple "update in place"
1390 */
1391 if (cur != NULL) {
1392 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001393 if ((orig != NULL) && (cur->type == typ) &&
1394 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001395 if (xmlDebugCatalogs)
1396 xmlGenericError(xmlGenericErrorContext,
1397 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001398 if (cur->value != NULL)
1399 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001400 if (cur->URL != NULL)
1401 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001402 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001403 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001404 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001405 }
1406 if (cur->next == NULL)
1407 break;
1408 cur = cur->next;
1409 }
1410 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001411 if (xmlDebugCatalogs)
1412 xmlGenericError(xmlGenericErrorContext,
1413 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001414 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001415 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1416 NULL, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001417 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001418 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1419 NULL, catal->prefer);
1420 if (doregister) {
1421 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1422 if (cur != NULL)
1423 cur->children = catal->children;
1424 }
1425
Daniel Veillardcda96922001-08-21 10:56:31 +00001426 return(0);
1427}
1428
1429/**
1430 * xmlDelXMLCatalog:
1431 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001432 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001433 *
1434 * Remove entries in the XML catalog where the value or the URI
1435 * is equal to @value
1436 *
1437 * Returns the number of entries removed if successful, -1 otherwise
1438 */
1439static int
1440xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001441 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001442 int ret = 0;
1443
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001444 if ((catal == NULL) ||
1445 ((catal->type != XML_CATA_CATALOG) &&
1446 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001447 return(-1);
1448 if (value == NULL)
1449 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001450 if (catal->children == NULL) {
1451 xmlFetchXMLCatalogFile(catal);
1452 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001453
1454 /*
1455 * Scan the children
1456 */
1457 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001458 while (cur != NULL) {
1459 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1460 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001461 if (xmlDebugCatalogs) {
1462 if (cur->name != NULL)
1463 xmlGenericError(xmlGenericErrorContext,
1464 "Removing element %s from catalog\n", cur->name);
1465 else
1466 xmlGenericError(xmlGenericErrorContext,
1467 "Removing element %s from catalog\n", cur->value);
1468 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001469 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001470 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001471 cur = cur->next;
1472 }
1473 return(ret);
1474}
1475
1476/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001477 * xmlCatalogXMLResolve:
1478 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001479 * @pubID: the public ID string
1480 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001481 *
1482 * Do a complete resolution lookup of an External Identifier for a
1483 * list of catalog entries.
1484 *
1485 * Implements (or tries to) 7.1. External Identifier Resolution
1486 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1487 *
1488 * Returns the URI of the resource or NULL if not found
1489 */
1490static xmlChar *
1491xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1492 const xmlChar *sysID) {
1493 xmlChar *ret = NULL;
1494 xmlCatalogEntryPtr cur;
1495 int haveDelegate = 0;
1496 int haveNext = 0;
1497
1498 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001499 * protection against loops
1500 */
1501 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001502 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1503 "Detected recursion in catalog %s\n",
1504 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001505 return(NULL);
1506 }
1507 catal->depth++;
1508
1509 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001510 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1511 */
1512 if (sysID != NULL) {
1513 xmlCatalogEntryPtr rewrite = NULL;
1514 int lenrewrite = 0, len;
1515 cur = catal;
1516 haveDelegate = 0;
1517 while (cur != NULL) {
1518 switch (cur->type) {
1519 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001520 if (xmlStrEqual(sysID, cur->name)) {
1521 if (xmlDebugCatalogs)
1522 xmlGenericError(xmlGenericErrorContext,
1523 "Found system match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001524 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001525 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001526 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001527 break;
1528 case XML_CATA_REWRITE_SYSTEM:
1529 len = xmlStrlen(cur->name);
1530 if ((len > lenrewrite) &&
1531 (!xmlStrncmp(sysID, cur->name, len))) {
1532 lenrewrite = len;
1533 rewrite = cur;
1534 }
1535 break;
1536 case XML_CATA_DELEGATE_SYSTEM:
1537 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1538 haveDelegate++;
1539 break;
1540 case XML_CATA_NEXT_CATALOG:
1541 haveNext++;
1542 break;
1543 default:
1544 break;
1545 }
1546 cur = cur->next;
1547 }
1548 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001549 if (xmlDebugCatalogs)
1550 xmlGenericError(xmlGenericErrorContext,
1551 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001552 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001553 if (ret != NULL)
1554 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001555 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001556 return(ret);
1557 }
1558 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001559 const xmlChar *delegates[MAX_DELEGATE];
1560 int nbList = 0, i;
1561
Daniel Veillardcda96922001-08-21 10:56:31 +00001562 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001563 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001564 * matches when the list was produced.
1565 */
1566 cur = catal;
1567 while (cur != NULL) {
1568 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1569 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001570 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001571 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001572 break;
1573 if (i < nbList) {
1574 cur = cur->next;
1575 continue;
1576 }
1577 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001578 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001579
Daniel Veillardcda96922001-08-21 10:56:31 +00001580 if (cur->children == NULL) {
1581 xmlFetchXMLCatalogFile(cur);
1582 }
1583 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001584 if (xmlDebugCatalogs)
1585 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001586 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001587 ret = xmlCatalogListXMLResolve(
1588 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001589 if (ret != NULL) {
1590 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001591 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001592 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001593 }
1594 }
1595 cur = cur->next;
1596 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001597 /*
1598 * Apply the cut algorithm explained in 4/
1599 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001600 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001601 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001602 }
1603 }
1604 /*
1605 * Then tries 5/ 6/ if a public ID is provided
1606 */
1607 if (pubID != NULL) {
1608 cur = catal;
1609 haveDelegate = 0;
1610 while (cur != NULL) {
1611 switch (cur->type) {
1612 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001613 if (xmlStrEqual(pubID, cur->name)) {
1614 if (xmlDebugCatalogs)
1615 xmlGenericError(xmlGenericErrorContext,
1616 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001617 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001618 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001619 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001620 break;
1621 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001622 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1623 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001624 haveDelegate++;
1625 break;
1626 case XML_CATA_NEXT_CATALOG:
1627 if (sysID == NULL)
1628 haveNext++;
1629 break;
1630 default:
1631 break;
1632 }
1633 cur = cur->next;
1634 }
1635 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001636 const xmlChar *delegates[MAX_DELEGATE];
1637 int nbList = 0, i;
1638
Daniel Veillardcda96922001-08-21 10:56:31 +00001639 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001640 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001641 * matches when the list was produced.
1642 */
1643 cur = catal;
1644 while (cur != NULL) {
1645 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001646 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1647 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001648
1649 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001650 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001651 break;
1652 if (i < nbList) {
1653 cur = cur->next;
1654 continue;
1655 }
1656 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001657 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001658
Daniel Veillardcda96922001-08-21 10:56:31 +00001659 if (cur->children == NULL) {
1660 xmlFetchXMLCatalogFile(cur);
1661 }
1662 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001663 if (xmlDebugCatalogs)
1664 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001665 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001666 ret = xmlCatalogListXMLResolve(
1667 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001668 if (ret != NULL) {
1669 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001670 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001671 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001672 }
1673 }
1674 cur = cur->next;
1675 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001676 /*
1677 * Apply the cut algorithm explained in 4/
1678 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001679 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001680 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001681 }
1682 }
1683 if (haveNext) {
1684 cur = catal;
1685 while (cur != NULL) {
1686 if (cur->type == XML_CATA_NEXT_CATALOG) {
1687 if (cur->children == NULL) {
1688 xmlFetchXMLCatalogFile(cur);
1689 }
1690 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001691 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001692 if (ret != NULL) {
1693 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001694 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001695 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001696 }
1697 }
1698 cur = cur->next;
1699 }
1700 }
1701
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001702 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001703 return(NULL);
1704}
1705
1706/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001707 * xmlCatalogXMLResolveURI:
1708 * @catal: a catalog list
1709 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001710 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001711 *
1712 * Do a complete resolution lookup of an External Identifier for a
1713 * list of catalog entries.
1714 *
1715 * Implements (or tries to) 7.2.2. URI Resolution
1716 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1717 *
1718 * Returns the URI of the resource or NULL if not found
1719 */
1720static xmlChar *
1721xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1722 xmlChar *ret = NULL;
1723 xmlCatalogEntryPtr cur;
1724 int haveDelegate = 0;
1725 int haveNext = 0;
1726 xmlCatalogEntryPtr rewrite = NULL;
1727 int lenrewrite = 0, len;
1728
1729 if (catal == NULL)
1730 return(NULL);
1731
1732 if (URI == NULL)
1733 return(NULL);
1734
1735 /*
1736 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1737 */
1738 cur = catal;
1739 haveDelegate = 0;
1740 while (cur != NULL) {
1741 switch (cur->type) {
1742 case XML_CATA_URI:
1743 if (xmlStrEqual(URI, cur->name)) {
1744 if (xmlDebugCatalogs)
1745 xmlGenericError(xmlGenericErrorContext,
1746 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001747 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001748 }
1749 break;
1750 case XML_CATA_REWRITE_URI:
1751 len = xmlStrlen(cur->name);
1752 if ((len > lenrewrite) &&
1753 (!xmlStrncmp(URI, cur->name, len))) {
1754 lenrewrite = len;
1755 rewrite = cur;
1756 }
1757 break;
1758 case XML_CATA_DELEGATE_URI:
1759 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1760 haveDelegate++;
1761 break;
1762 case XML_CATA_NEXT_CATALOG:
1763 haveNext++;
1764 break;
1765 default:
1766 break;
1767 }
1768 cur = cur->next;
1769 }
1770 if (rewrite != NULL) {
1771 if (xmlDebugCatalogs)
1772 xmlGenericError(xmlGenericErrorContext,
1773 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001774 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001775 if (ret != NULL)
1776 ret = xmlStrcat(ret, &URI[lenrewrite]);
1777 return(ret);
1778 }
1779 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001780 const xmlChar *delegates[MAX_DELEGATE];
1781 int nbList = 0, i;
1782
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001783 /*
1784 * Assume the entries have been sorted by decreasing substring
1785 * matches when the list was produced.
1786 */
1787 cur = catal;
1788 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001789 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1790 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001791 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001792 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001793 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001794 break;
1795 if (i < nbList) {
1796 cur = cur->next;
1797 continue;
1798 }
1799 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001800 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001801
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001802 if (cur->children == NULL) {
1803 xmlFetchXMLCatalogFile(cur);
1804 }
1805 if (cur->children != NULL) {
1806 if (xmlDebugCatalogs)
1807 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001808 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001809 ret = xmlCatalogListXMLResolveURI(
1810 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001811 if (ret != NULL)
1812 return(ret);
1813 }
1814 }
1815 cur = cur->next;
1816 }
1817 /*
1818 * Apply the cut algorithm explained in 4/
1819 */
1820 return(XML_CATAL_BREAK);
1821 }
1822 if (haveNext) {
1823 cur = catal;
1824 while (cur != NULL) {
1825 if (cur->type == XML_CATA_NEXT_CATALOG) {
1826 if (cur->children == NULL) {
1827 xmlFetchXMLCatalogFile(cur);
1828 }
1829 if (cur->children != NULL) {
1830 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1831 if (ret != NULL)
1832 return(ret);
1833 }
1834 }
1835 cur = cur->next;
1836 }
1837 }
1838
1839 return(NULL);
1840}
1841
1842/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001843 * xmlCatalogListXMLResolve:
1844 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001845 * @pubID: the public ID string
1846 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001847 *
1848 * Do a complete resolution lookup of an External Identifier for a
1849 * list of catalogs
1850 *
1851 * Implements (or tries to) 7.1. External Identifier Resolution
1852 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1853 *
1854 * Returns the URI of the resource or NULL if not found
1855 */
1856static xmlChar *
1857xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1858 const xmlChar *sysID) {
1859 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001860 xmlChar *urnID = NULL;
1861
1862 if (catal == NULL)
1863 return(NULL);
1864 if ((pubID == NULL) && (sysID == NULL))
1865 return(NULL);
1866
1867 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1868 urnID = xmlCatalogUnWrapURN(pubID);
1869 if (xmlDebugCatalogs) {
1870 if (urnID == NULL)
1871 xmlGenericError(xmlGenericErrorContext,
1872 "Public URN ID %s expanded to NULL\n", pubID);
1873 else
1874 xmlGenericError(xmlGenericErrorContext,
1875 "Public URN ID expanded to %s\n", urnID);
1876 }
1877 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1878 if (urnID != NULL)
1879 xmlFree(urnID);
1880 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001881 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001882 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1883 urnID = xmlCatalogUnWrapURN(sysID);
1884 if (xmlDebugCatalogs) {
1885 if (urnID == NULL)
1886 xmlGenericError(xmlGenericErrorContext,
1887 "System URN ID %s expanded to NULL\n", sysID);
1888 else
1889 xmlGenericError(xmlGenericErrorContext,
1890 "System URN ID expanded to %s\n", urnID);
1891 }
1892 if (pubID == NULL)
1893 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1894 else if (xmlStrEqual(pubID, urnID))
1895 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1896 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00001897 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001898 }
1899 if (urnID != NULL)
1900 xmlFree(urnID);
1901 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001902 }
1903 while (catal != NULL) {
1904 if (catal->type == XML_CATA_CATALOG) {
1905 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001906 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001907 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001908 if (catal->children != NULL) {
1909 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1910 if (ret != NULL)
1911 return(ret);
1912 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001913 }
1914 catal = catal->next;
1915 }
1916 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001917}
1918
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001919/**
1920 * xmlCatalogListXMLResolveURI:
1921 * @catal: a catalog list
1922 * @URI: the URI
1923 *
1924 * Do a complete resolution lookup of an URI for a list of catalogs
1925 *
1926 * Implements (or tries to) 7.2. URI Resolution
1927 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1928 *
1929 * Returns the URI of the resource or NULL if not found
1930 */
1931static xmlChar *
1932xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1933 xmlChar *ret = NULL;
1934 xmlChar *urnID = NULL;
1935
1936 if (catal == NULL)
1937 return(NULL);
1938 if (URI == NULL)
1939 return(NULL);
1940
1941 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1942 urnID = xmlCatalogUnWrapURN(URI);
1943 if (xmlDebugCatalogs) {
1944 if (urnID == NULL)
1945 xmlGenericError(xmlGenericErrorContext,
1946 "URN ID %s expanded to NULL\n", URI);
1947 else
1948 xmlGenericError(xmlGenericErrorContext,
1949 "URN ID expanded to %s\n", urnID);
1950 }
1951 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1952 if (urnID != NULL)
1953 xmlFree(urnID);
1954 return(ret);
1955 }
1956 while (catal != NULL) {
1957 if (catal->type == XML_CATA_CATALOG) {
1958 if (catal->children == NULL) {
1959 xmlFetchXMLCatalogFile(catal);
1960 }
1961 if (catal->children != NULL) {
1962 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1963 if (ret != NULL)
1964 return(ret);
1965 }
1966 }
1967 catal = catal->next;
1968 }
1969 return(ret);
1970}
1971
Daniel Veillard344cee72001-08-20 00:08:40 +00001972/************************************************************************
1973 * *
1974 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001975 * *
1976 ************************************************************************/
1977
1978
1979#define RAW *cur
1980#define NEXT cur++;
1981#define SKIP(x) cur += x;
1982
William M. Brack272693c2003-11-14 16:20:34 +00001983#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00001984
Daniel Veillard75b96822001-10-11 18:59:45 +00001985/**
1986 * xmlParseSGMLCatalogComment:
1987 * @cur: the current character
1988 *
1989 * Skip a comment in an SGML catalog
1990 *
1991 * Returns new current character
1992 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001993static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001994xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001995 if ((cur[0] != '-') || (cur[1] != '-'))
1996 return(cur);
1997 SKIP(2);
1998 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1999 NEXT;
2000 if (cur[0] == 0) {
2001 return(NULL);
2002 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002003 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002004}
2005
Daniel Veillard75b96822001-10-11 18:59:45 +00002006/**
2007 * xmlParseSGMLCatalogPubid:
2008 * @cur: the current character
2009 * @id: the return location
2010 *
2011 * Parse an SGML catalog ID
2012 *
2013 * Returns new current character and store the value in @id
2014 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002015static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002016xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002017 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002018 int len = 0;
2019 int size = 50;
2020 xmlChar stop;
2021 int count = 0;
2022
2023 *id = NULL;
2024
2025 if (RAW == '"') {
2026 NEXT;
2027 stop = '"';
2028 } else if (RAW == '\'') {
2029 NEXT;
2030 stop = '\'';
2031 } else {
2032 stop = ' ';
2033 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002034 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002035 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002036 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002037 return(NULL);
2038 }
William M. Brack76e95df2003-10-18 16:20:14 +00002039 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002040 if ((*cur == stop) && (stop != ' '))
2041 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002042 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002043 break;
2044 if (len + 1 >= size) {
2045 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002046 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2047 if (tmp == NULL) {
2048 xmlCatalogErrMemory("allocating public ID");
2049 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002050 return(NULL);
2051 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002052 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002053 }
2054 buf[len++] = *cur;
2055 count++;
2056 NEXT;
2057 }
2058 buf[len] = 0;
2059 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002060 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002061 xmlFree(buf);
2062 return(NULL);
2063 }
2064 } else {
2065 if (*cur != stop) {
2066 xmlFree(buf);
2067 return(NULL);
2068 }
2069 NEXT;
2070 }
2071 *id = buf;
2072 return(cur);
2073}
2074
Daniel Veillard75b96822001-10-11 18:59:45 +00002075/**
2076 * xmlParseSGMLCatalogName:
2077 * @cur: the current character
2078 * @name: the return location
2079 *
2080 * Parse an SGML catalog name
2081 *
2082 * Returns new current character and store the value in @name
2083 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002084static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002085xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002086 xmlChar buf[XML_MAX_NAMELEN + 5];
2087 int len = 0;
2088 int c;
2089
2090 *name = NULL;
2091
2092 /*
2093 * Handler for more complex cases
2094 */
2095 c = *cur;
2096 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2097 return(NULL);
2098 }
2099
2100 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2101 (c == '.') || (c == '-') ||
2102 (c == '_') || (c == ':'))) {
2103 buf[len++] = c;
2104 cur++;
2105 c = *cur;
2106 if (len >= XML_MAX_NAMELEN)
2107 return(NULL);
2108 }
2109 *name = xmlStrndup(buf, len);
2110 return(cur);
2111}
2112
Daniel Veillard75b96822001-10-11 18:59:45 +00002113/**
2114 * xmlGetSGMLCatalogEntryType:
2115 * @name: the entry name
2116 *
2117 * Get the Catalog entry type for a given SGML Catalog name
2118 *
2119 * Returns Catalog entry type
2120 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002121static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002122xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002123 xmlCatalogEntryType type = XML_CATA_NONE;
2124 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2125 type = SGML_CATA_SYSTEM;
2126 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2127 type = SGML_CATA_PUBLIC;
2128 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2129 type = SGML_CATA_DELEGATE;
2130 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2131 type = SGML_CATA_ENTITY;
2132 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2133 type = SGML_CATA_DOCTYPE;
2134 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2135 type = SGML_CATA_LINKTYPE;
2136 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2137 type = SGML_CATA_NOTATION;
2138 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2139 type = SGML_CATA_SGMLDECL;
2140 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2141 type = SGML_CATA_DOCUMENT;
2142 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2143 type = SGML_CATA_CATALOG;
2144 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2145 type = SGML_CATA_BASE;
2146 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2147 type = SGML_CATA_DELEGATE;
2148 return(type);
2149}
2150
Daniel Veillard75b96822001-10-11 18:59:45 +00002151/**
2152 * xmlParseSGMLCatalog:
2153 * @catal: the SGML Catalog
2154 * @value: the content of the SGML Catalog serialization
2155 * @file: the filepath for the catalog
2156 * @super: should this be handled as a Super Catalog in which case
2157 * parsing is not recursive
2158 *
2159 * Parse an SGML catalog content and fill up the @catal hash table with
2160 * the new entries found.
2161 *
2162 * Returns 0 in case of success, -1 in case of error.
2163 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002164static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002165xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2166 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002167 const xmlChar *cur = value;
2168 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002169 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002170
2171 if ((cur == NULL) || (file == NULL))
2172 return(-1);
2173 base = xmlStrdup((const xmlChar *) file);
2174
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002175 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002176 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002177 if (cur[0] == 0)
2178 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002179 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002180 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002181 if (cur == NULL) {
2182 /* error */
2183 break;
2184 }
2185 } else {
2186 xmlChar *sysid = NULL;
2187 xmlChar *name = NULL;
2188 xmlCatalogEntryType type = XML_CATA_NONE;
2189
Daniel Veillardcda96922001-08-21 10:56:31 +00002190 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002191 if (name == NULL) {
2192 /* error */
2193 break;
2194 }
William M. Brack76e95df2003-10-18 16:20:14 +00002195 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002196 /* error */
2197 break;
2198 }
2199 SKIP_BLANKS;
2200 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002201 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002202 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002203 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002204 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002205 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002206 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002207 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002208 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002209 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002210 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002211 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002212 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002213 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002214 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002215 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002216 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002217 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002218 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002219 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002220 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002221 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002222 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002223 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002224 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2225 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002226 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002227 if (name == NULL) {
2228 /* error */
2229 break;
2230 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002231 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002232 continue;
2233 }
2234 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002235 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002236
2237 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002238 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002239 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002240 type = SGML_CATA_PENTITY;
2241 case SGML_CATA_PENTITY:
2242 case SGML_CATA_DOCTYPE:
2243 case SGML_CATA_LINKTYPE:
2244 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002245 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002246 if (cur == NULL) {
2247 /* error */
2248 break;
2249 }
William M. Brack76e95df2003-10-18 16:20:14 +00002250 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002251 /* error */
2252 break;
2253 }
2254 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002255 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002256 if (cur == NULL) {
2257 /* error */
2258 break;
2259 }
2260 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002261 case SGML_CATA_PUBLIC:
2262 case SGML_CATA_SYSTEM:
2263 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002264 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002265 if (cur == NULL) {
2266 /* error */
2267 break;
2268 }
William M. Brack76e95df2003-10-18 16:20:14 +00002269 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002270 /* error */
2271 break;
2272 }
2273 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002274 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002275 if (cur == NULL) {
2276 /* error */
2277 break;
2278 }
2279 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002280 case SGML_CATA_BASE:
2281 case SGML_CATA_CATALOG:
2282 case SGML_CATA_DOCUMENT:
2283 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002284 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002285 if (cur == NULL) {
2286 /* error */
2287 break;
2288 }
2289 break;
2290 default:
2291 break;
2292 }
2293 if (cur == NULL) {
2294 if (name != NULL)
2295 xmlFree(name);
2296 if (sysid != NULL)
2297 xmlFree(sysid);
2298 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002299 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002300 if (base != NULL)
2301 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002302 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002303 } else if ((type == SGML_CATA_PUBLIC) ||
2304 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002305 xmlChar *filename;
2306
2307 filename = xmlBuildURI(sysid, base);
2308 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002309 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002310
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002311 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002312 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002313 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002314 if (res < 0) {
2315 xmlFreeCatalogEntry(entry);
2316 }
2317 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002318 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002319
Daniel Veillard344cee72001-08-20 00:08:40 +00002320 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002321 if (super) {
2322 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002323
Daniel Veillardc853b322001-11-06 15:24:37 +00002324 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002325 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002326 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002327 if (res < 0) {
2328 xmlFreeCatalogEntry(entry);
2329 }
2330 } else {
2331 xmlChar *filename;
2332
2333 filename = xmlBuildURI(sysid, base);
2334 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002335 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002336 xmlFree(filename);
2337 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002338 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002339 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002340 /*
2341 * drop anything else we won't handle it
2342 */
2343 if (name != NULL)
2344 xmlFree(name);
2345 if (sysid != NULL)
2346 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002347 }
2348 }
2349 if (base != NULL)
2350 xmlFree(base);
2351 if (cur == NULL)
2352 return(-1);
2353 return(0);
2354}
2355
Daniel Veillard75b96822001-10-11 18:59:45 +00002356/************************************************************************
2357 * *
2358 * SGML Catalog handling *
2359 * *
2360 ************************************************************************/
2361
Daniel Veillardcda96922001-08-21 10:56:31 +00002362/**
2363 * xmlCatalogGetSGMLPublic:
2364 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002365 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002366 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002367 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002368 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002369 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002370 */
2371static const xmlChar *
2372xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2373 xmlCatalogEntryPtr entry;
2374
2375 if (catal == NULL)
2376 return(NULL);
2377
2378 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2379 if (entry == NULL)
2380 return(NULL);
2381 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillardc853b322001-11-06 15:24:37 +00002382 return(entry->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002383 return(NULL);
2384}
2385
2386/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002387 * xmlCatalogGetSGMLSystem:
2388 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002389 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002390 *
2391 * Try to lookup the catalog local reference for a system ID
2392 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002393 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002394 */
2395static const xmlChar *
2396xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2397 xmlCatalogEntryPtr entry;
2398
2399 if (catal == NULL)
2400 return(NULL);
2401
2402 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2403 if (entry == NULL)
2404 return(NULL);
2405 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002406 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002407 return(NULL);
2408}
2409
2410/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002411 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002412 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002413 * @pubID: the public ID string
2414 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002415 *
2416 * Do a complete resolution lookup of an External Identifier
2417 *
2418 * Returns the URI of the resource or NULL if not found
2419 */
2420static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002421xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2422 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002423 const xmlChar *ret = NULL;
2424
Daniel Veillard75b96822001-10-11 18:59:45 +00002425 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002426 return(NULL);
2427
2428 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002429 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002430 if (ret != NULL)
2431 return(ret);
2432 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002433 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002434 return(NULL);
2435}
2436
Daniel Veillarda7374592001-05-10 14:17:55 +00002437/************************************************************************
2438 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002439 * Specific Public interfaces *
2440 * *
2441 ************************************************************************/
2442
2443/**
2444 * xmlLoadSGMLSuperCatalog:
2445 * @filename: a file path
2446 *
2447 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2448 * references. This is only needed for manipulating SGML Super Catalogs
2449 * like adding and removing CATALOG or DELEGATE entries.
2450 *
2451 * Returns the catalog parsed or NULL in case of error
2452 */
2453xmlCatalogPtr
2454xmlLoadSGMLSuperCatalog(const char *filename)
2455{
2456 xmlChar *content;
2457 xmlCatalogPtr catal;
2458 int ret;
2459
2460 content = xmlLoadFileContent(filename);
2461 if (content == NULL)
2462 return(NULL);
2463
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002464 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002465 if (catal == NULL) {
2466 xmlFree(content);
2467 return(NULL);
2468 }
2469
2470 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2471 xmlFree(content);
2472 if (ret < 0) {
2473 xmlFreeCatalog(catal);
2474 return(NULL);
2475 }
2476 return (catal);
2477}
2478
2479/**
2480 * xmlLoadACatalog:
2481 * @filename: a file path
2482 *
2483 * Load the catalog and build the associated data structures.
2484 * This can be either an XML Catalog or an SGML Catalog
2485 * It will recurse in SGML CATALOG entries. On the other hand XML
2486 * Catalogs are not handled recursively.
2487 *
2488 * Returns the catalog parsed or NULL in case of error
2489 */
2490xmlCatalogPtr
2491xmlLoadACatalog(const char *filename)
2492{
2493 xmlChar *content;
2494 xmlChar *first;
2495 xmlCatalogPtr catal;
2496 int ret;
2497
2498 content = xmlLoadFileContent(filename);
2499 if (content == NULL)
2500 return(NULL);
2501
2502
2503 first = content;
2504
2505 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2506 (!(((*first >= 'A') && (*first <= 'Z')) ||
2507 ((*first >= 'a') && (*first <= 'z')))))
2508 first++;
2509
2510 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002511 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002512 if (catal == NULL) {
2513 xmlFree(content);
2514 return(NULL);
2515 }
2516 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2517 if (ret < 0) {
2518 xmlFreeCatalog(catal);
2519 xmlFree(content);
2520 return(NULL);
2521 }
2522 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002523 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002524 if (catal == NULL) {
2525 xmlFree(content);
2526 return(NULL);
2527 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002528 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002529 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002530 }
2531 xmlFree(content);
2532 return (catal);
2533}
2534
2535/**
2536 * xmlExpandCatalog:
2537 * @catal: a catalog
2538 * @filename: a file path
2539 *
2540 * Load the catalog and expand the existing catal structure.
2541 * This can be either an XML Catalog or an SGML Catalog
2542 *
2543 * Returns 0 in case of success, -1 in case of error
2544 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002545static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002546xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2547{
Daniel Veillard75b96822001-10-11 18:59:45 +00002548 int ret;
2549
2550 if ((catal == NULL) || (filename == NULL))
2551 return(-1);
2552
Daniel Veillard75b96822001-10-11 18:59:45 +00002553
2554 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002555 xmlChar *content;
2556
2557 content = xmlLoadFileContent(filename);
2558 if (content == NULL)
2559 return(-1);
2560
Daniel Veillard75b96822001-10-11 18:59:45 +00002561 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2562 if (ret < 0) {
2563 xmlFree(content);
2564 return(-1);
2565 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002566 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002567 } else {
2568 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002569 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002570 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002571
Daniel Veillard75b96822001-10-11 18:59:45 +00002572 cur = catal->xml;
2573 if (cur == NULL) {
2574 catal->xml = tmp;
2575 } else {
2576 while (cur->next != NULL) cur = cur->next;
2577 cur->next = tmp;
2578 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002579 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002580 return (0);
2581}
2582
2583/**
2584 * xmlACatalogResolveSystem:
2585 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002586 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002587 *
2588 * Try to lookup the catalog resource for a system ID
2589 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002590 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002591 * must be freed by the caller.
2592 */
2593xmlChar *
2594xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2595 xmlChar *ret = NULL;
2596
2597 if ((sysID == NULL) || (catal == NULL))
2598 return(NULL);
2599
2600 if (xmlDebugCatalogs)
2601 xmlGenericError(xmlGenericErrorContext,
2602 "Resolve sysID %s\n", sysID);
2603
2604 if (catal->type == XML_XML_CATALOG_TYPE) {
2605 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2606 if (ret == XML_CATAL_BREAK)
2607 ret = NULL;
2608 } else {
2609 const xmlChar *sgml;
2610
2611 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2612 if (sgml != NULL)
2613 ret = xmlStrdup(sgml);
2614 }
2615 return(ret);
2616}
2617
2618/**
2619 * xmlACatalogResolvePublic:
2620 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002621 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002622 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002623 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002624 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002625 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002626 * must be freed by the caller.
2627 */
2628xmlChar *
2629xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2630 xmlChar *ret = NULL;
2631
2632 if ((pubID == NULL) || (catal == NULL))
2633 return(NULL);
2634
2635 if (xmlDebugCatalogs)
2636 xmlGenericError(xmlGenericErrorContext,
2637 "Resolve pubID %s\n", pubID);
2638
2639 if (catal->type == XML_XML_CATALOG_TYPE) {
2640 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2641 if (ret == XML_CATAL_BREAK)
2642 ret = NULL;
2643 } else {
2644 const xmlChar *sgml;
2645
2646 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2647 if (sgml != NULL)
2648 ret = xmlStrdup(sgml);
2649 }
2650 return(ret);
2651}
2652
2653/**
2654 * xmlACatalogResolve:
2655 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002656 * @pubID: the public ID string
2657 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002658 *
2659 * Do a complete resolution lookup of an External Identifier
2660 *
2661 * Returns the URI of the resource or NULL if not found, it must be freed
2662 * by the caller.
2663 */
2664xmlChar *
2665xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2666 const xmlChar * sysID)
2667{
2668 xmlChar *ret = NULL;
2669
2670 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2671 return (NULL);
2672
2673 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002674 if ((pubID != NULL) && (sysID != NULL)) {
2675 xmlGenericError(xmlGenericErrorContext,
2676 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2677 } else if (pubID != NULL) {
2678 xmlGenericError(xmlGenericErrorContext,
2679 "Resolve: pubID %s\n", pubID);
2680 } else {
2681 xmlGenericError(xmlGenericErrorContext,
2682 "Resolve: sysID %s\n", sysID);
2683 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002684 }
2685
2686 if (catal->type == XML_XML_CATALOG_TYPE) {
2687 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2688 if (ret == XML_CATAL_BREAK)
2689 ret = NULL;
2690 } else {
2691 const xmlChar *sgml;
2692
2693 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2694 if (sgml != NULL)
2695 ret = xmlStrdup(sgml);
2696 }
2697 return (ret);
2698}
2699
2700/**
2701 * xmlACatalogResolveURI:
2702 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002703 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002704 *
2705 * Do a complete resolution lookup of an URI
2706 *
2707 * Returns the URI of the resource or NULL if not found, it must be freed
2708 * by the caller.
2709 */
2710xmlChar *
2711xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2712 xmlChar *ret = NULL;
2713
2714 if ((URI == NULL) || (catal == NULL))
2715 return(NULL);
2716
Daniel Veillardb44025c2001-10-11 22:55:55 +00002717 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002718 xmlGenericError(xmlGenericErrorContext,
2719 "Resolve URI %s\n", URI);
2720
2721 if (catal->type == XML_XML_CATALOG_TYPE) {
2722 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2723 if (ret == XML_CATAL_BREAK)
2724 ret = NULL;
2725 } else {
2726 const xmlChar *sgml;
2727
2728 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2729 if (sgml != NULL)
2730 sgml = xmlStrdup(sgml);
2731 }
2732 return(ret);
2733}
2734
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002735#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002736/**
2737 * xmlACatalogDump:
2738 * @catal: a Catalog
2739 * @out: the file.
2740 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002741 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002742 */
2743void
2744xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002745 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002746 return;
2747
2748 if (catal->type == XML_XML_CATALOG_TYPE) {
2749 xmlDumpXMLCatalog(out, catal->xml);
2750 } else {
2751 xmlHashScan(catal->sgml,
2752 (xmlHashScanner) xmlCatalogDumpEntry, out);
2753 }
2754}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002755#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002756
2757/**
2758 * xmlACatalogAdd:
2759 * @catal: a Catalog
2760 * @type: the type of record to add to the catalog
2761 * @orig: the system, public or prefix to match
2762 * @replace: the replacement value for the match
2763 *
2764 * Add an entry in the catalog, it may overwrite existing but
2765 * different entries.
2766 *
2767 * Returns 0 if successful, -1 otherwise
2768 */
2769int
2770xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2771 const xmlChar * orig, const xmlChar * replace)
2772{
2773 int res = -1;
2774
2775 if (catal == NULL)
2776 return(-1);
2777
2778 if (catal->type == XML_XML_CATALOG_TYPE) {
2779 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2780 } else {
2781 xmlCatalogEntryType cattype;
2782
2783 cattype = xmlGetSGMLCatalogEntryType(type);
2784 if (cattype != XML_CATA_NONE) {
2785 xmlCatalogEntryPtr entry;
2786
Daniel Veillardc853b322001-11-06 15:24:37 +00002787 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002788 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002789 if (catal->sgml == NULL)
2790 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002791 res = xmlHashAddEntry(catal->sgml, orig, entry);
2792 }
2793 }
2794 return (res);
2795}
2796
2797/**
2798 * xmlACatalogRemove:
2799 * @catal: a Catalog
2800 * @value: the value to remove
2801 *
2802 * Remove an entry from the catalog
2803 *
2804 * Returns the number of entries removed if successful, -1 otherwise
2805 */
2806int
2807xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2808 int res = -1;
2809
2810 if ((catal == NULL) || (value == NULL))
2811 return(-1);
2812
2813 if (catal->type == XML_XML_CATALOG_TYPE) {
2814 res = xmlDelXMLCatalog(catal->xml, value);
2815 } else {
2816 res = xmlHashRemoveEntry(catal->sgml, value,
2817 (xmlHashDeallocator) xmlFreeCatalogEntry);
2818 if (res == 0)
2819 res = 1;
2820 }
2821 return(res);
2822}
2823
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002824/**
2825 * xmlNewCatalog:
2826 * @sgml: should this create an SGML catalog
2827 *
2828 * create a new Catalog.
2829 *
2830 * Returns the xmlCatalogPtr or NULL in case of error
2831 */
2832xmlCatalogPtr
2833xmlNewCatalog(int sgml) {
2834 xmlCatalogPtr catal = NULL;
2835
2836 if (sgml) {
2837 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2838 xmlCatalogDefaultPrefer);
2839 if ((catal != NULL) && (catal->sgml == NULL))
2840 catal->sgml = xmlHashCreate(10);
2841 } else
2842 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2843 xmlCatalogDefaultPrefer);
2844 return(catal);
2845}
2846
2847/**
2848 * xmlCatalogIsEmpty:
2849 * @catal: should this create an SGML catalog
2850 *
2851 * Check is a catalog is empty
2852 *
2853 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2854 */
2855int
2856xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2857 if (catal == NULL)
2858 return(-1);
2859
2860 if (catal->type == XML_XML_CATALOG_TYPE) {
2861 if (catal->xml == NULL)
2862 return(1);
2863 if ((catal->xml->type != XML_CATA_CATALOG) &&
2864 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2865 return(-1);
2866 if (catal->xml->children == NULL)
2867 return(1);
2868 return(0);
2869 } else {
2870 int res;
2871
2872 if (catal->sgml == NULL)
2873 return(1);
2874 res = xmlHashSize(catal->sgml);
2875 if (res == 0)
2876 return(1);
2877 if (res < 0)
2878 return(-1);
2879 }
2880 return(0);
2881}
2882
Daniel Veillard75b96822001-10-11 18:59:45 +00002883/************************************************************************
2884 * *
2885 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002886 * *
2887 ************************************************************************/
2888
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002889/**
Daniel Veillard81463942001-10-16 12:34:39 +00002890 * xmlInitializeCatalogData:
2891 *
2892 * Do the catalog initialization only of global data, doesn't try to load
2893 * any catalog actually.
2894 * this function is not thread safe, catalog initialization should
2895 * preferably be done once at startup
2896 */
2897static void
2898xmlInitializeCatalogData(void) {
2899 if (xmlCatalogInitialized != 0)
2900 return;
2901
2902 if (getenv("XML_DEBUG_CATALOG"))
2903 xmlDebugCatalogs = 1;
2904 xmlCatalogMutex = xmlNewRMutex();
2905
2906 xmlCatalogInitialized = 1;
2907}
2908/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002909 * xmlInitializeCatalog:
2910 *
2911 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002912 * this function is not thread safe, catalog initialization should
2913 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002914 */
2915void
2916xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002917 if (xmlCatalogInitialized != 0)
2918 return;
2919
Daniel Veillard81463942001-10-16 12:34:39 +00002920 xmlInitializeCatalogData();
2921 xmlRMutexLock(xmlCatalogMutex);
2922
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002923 if (getenv("XML_DEBUG_CATALOG"))
2924 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002925
Daniel Veillard75b96822001-10-11 18:59:45 +00002926 if (xmlDefaultCatalog == NULL) {
2927 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002928 char *path;
2929 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00002930 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002931 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00002932
Daniel Veillardb44025c2001-10-11 22:55:55 +00002933 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002934 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00002935#if defined(_WIN32) && defined(_MSC_VER)
2936 {
2937 void* hmodule;
2938 hmodule = GetModuleHandleA("libxml2.dll");
2939 if (hmodule == NULL)
2940 hmodule = GetModuleHandleA(NULL);
2941 if (hmodule != NULL) {
2942 char buf[256];
2943 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
2944 if (len != 0) {
2945 char* p = &(buf[len]);
2946 while (*p != '\\' && p > buf)
2947 p--;
2948 if (p != buf) {
2949 xmlChar* uri;
2950 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
2951 uri = xmlCanonicPath(buf);
2952 if (uri != NULL) {
2953 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
2954 xmlFree(uri);
2955 }
2956 }
2957 }
2958 }
2959 catalogs = XML_XML_DEFAULT_CATALOG;
2960 }
2961#else
Daniel Veillard75b96822001-10-11 18:59:45 +00002962 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00002963#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00002964
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002965 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2966 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002967 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002968 /* the XML_CATALOG_FILES envvar is allowed to contain a
2969 space-separated list of entries. */
2970 cur = catalogs;
2971 nextent = &catal->xml;
2972 while (*cur != '\0') {
William M. Brack68aca052003-10-11 15:22:13 +00002973 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002974 cur++;
2975 if (*cur != 0) {
2976 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00002977 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002978 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002979 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002980 if (path != NULL) {
2981 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2982 NULL, BAD_CAST path, xmlCatalogDefaultPrefer);
2983 if (*nextent != NULL)
2984 nextent = &((*nextent)->next);
2985 xmlFree(path);
2986 }
2987 }
2988 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002989 xmlDefaultCatalog = catal;
2990 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002991 }
2992
Daniel Veillard81463942001-10-16 12:34:39 +00002993 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002994}
2995
Daniel Veillard82d75332001-10-08 15:01:59 +00002996
2997/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002998 * xmlLoadCatalog:
2999 * @filename: a file path
3000 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003001 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003002 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003003 * this function is not thread safe, catalog initialization should
3004 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003005 *
3006 * Returns 0 in case of success -1 in case of error
3007 */
3008int
Daniel Veillard16756b62001-10-01 07:36:25 +00003009xmlLoadCatalog(const char *filename)
3010{
Daniel Veillard75b96822001-10-11 18:59:45 +00003011 int ret;
3012 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003013
Daniel Veillard81463942001-10-16 12:34:39 +00003014 if (!xmlCatalogInitialized)
3015 xmlInitializeCatalogData();
3016
3017 xmlRMutexLock(xmlCatalogMutex);
3018
Daniel Veillard75b96822001-10-11 18:59:45 +00003019 if (xmlDefaultCatalog == NULL) {
3020 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003021 if (catal == NULL) {
3022 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003023 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003024 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003025
Daniel Veillard75b96822001-10-11 18:59:45 +00003026 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003027 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003028 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003029 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003030
Daniel Veillard75b96822001-10-11 18:59:45 +00003031 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003032 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003033 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003034}
3035
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003036/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003037 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003038 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003039 *
3040 * Load the catalogs and makes their definitions effective for the default
3041 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003042 * this function is not thread safe, catalog initialization should
3043 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003044 */
3045void
3046xmlLoadCatalogs(const char *pathss) {
3047 const char *cur;
3048 const char *paths;
3049 xmlChar *path;
3050
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003051 if (pathss == NULL)
3052 return;
3053
Daniel Veillard81418e32001-05-22 15:08:55 +00003054 cur = pathss;
3055 while ((cur != NULL) && (*cur != 0)) {
William M. Brack68aca052003-10-11 15:22:13 +00003056 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003057 if (*cur != 0) {
3058 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003059 while ((*cur != 0) && (*cur != ':') && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003060 cur++;
3061 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3062 if (path != NULL) {
3063 xmlLoadCatalog((const char *) path);
3064 xmlFree(path);
3065 }
3066 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003067 while (*cur == ':')
3068 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003069 }
3070}
3071
Daniel Veillarda7374592001-05-10 14:17:55 +00003072/**
3073 * xmlCatalogCleanup:
3074 *
3075 * Free up all the memory associated with catalogs
3076 */
3077void
3078xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003079 if (xmlCatalogInitialized == 0)
3080 return;
3081
Daniel Veillard81463942001-10-16 12:34:39 +00003082 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003083 if (xmlDebugCatalogs)
3084 xmlGenericError(xmlGenericErrorContext,
3085 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003086 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003087 xmlHashFree(xmlCatalogXMLFiles,
3088 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003089 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003090 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003091 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003092 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003093 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003094 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003095 xmlRMutexUnlock(xmlCatalogMutex);
3096 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003097}
3098
3099/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003100 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003101 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003102 *
3103 * Try to lookup the catalog resource for a system ID
3104 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003105 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003106 * must be freed by the caller.
3107 */
3108xmlChar *
3109xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003110 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003111
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003112 if (!xmlCatalogInitialized)
3113 xmlInitializeCatalog();
3114
Daniel Veillard75b96822001-10-11 18:59:45 +00003115 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3116 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003117}
3118
3119/**
3120 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003121 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003122 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003123 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003124 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003125 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003126 * must be freed by the caller.
3127 */
3128xmlChar *
3129xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003130 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003131
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003132 if (!xmlCatalogInitialized)
3133 xmlInitializeCatalog();
3134
Daniel Veillard75b96822001-10-11 18:59:45 +00003135 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3136 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003137}
Daniel Veillard344cee72001-08-20 00:08:40 +00003138
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003139/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003140 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003141 * @pubID: the public ID string
3142 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003143 *
3144 * Do a complete resolution lookup of an External Identifier
3145 *
3146 * Returns the URI of the resource or NULL if not found, it must be freed
3147 * by the caller.
3148 */
3149xmlChar *
3150xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003151 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003152
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003153 if (!xmlCatalogInitialized)
3154 xmlInitializeCatalog();
3155
Daniel Veillard75b96822001-10-11 18:59:45 +00003156 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3157 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003158}
3159
3160/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003161 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003162 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003163 *
3164 * Do a complete resolution lookup of an URI
3165 *
3166 * Returns the URI of the resource or NULL if not found, it must be freed
3167 * by the caller.
3168 */
3169xmlChar *
3170xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003171 xmlChar *ret;
3172
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003173 if (!xmlCatalogInitialized)
3174 xmlInitializeCatalog();
3175
Daniel Veillard75b96822001-10-11 18:59:45 +00003176 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3177 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003178}
3179
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003180#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003181/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003182 * xmlCatalogDump:
3183 * @out: the file.
3184 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003185 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003186 */
3187void
3188xmlCatalogDump(FILE *out) {
3189 if (out == NULL)
3190 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003191
Daniel Veillard75b96822001-10-11 18:59:45 +00003192 if (!xmlCatalogInitialized)
3193 xmlInitializeCatalog();
3194
3195 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003196}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003197#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003198
3199/**
3200 * xmlCatalogAdd:
3201 * @type: the type of record to add to the catalog
3202 * @orig: the system, public or prefix to match
3203 * @replace: the replacement value for the match
3204 *
3205 * Add an entry in the catalog, it may overwrite existing but
3206 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003207 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003208 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003209 *
3210 * Returns 0 if successful, -1 otherwise
3211 */
3212int
3213xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3214 int res = -1;
3215
Daniel Veillard81463942001-10-16 12:34:39 +00003216 if (!xmlCatalogInitialized)
3217 xmlInitializeCatalogData();
3218
3219 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003220 /*
3221 * Specific case where one want to override the default catalog
3222 * put in place by xmlInitializeCatalog();
3223 */
3224 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003225 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003226 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003227 xmlCatalogDefaultPrefer);
3228 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003229 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003230
Daniel Veillard81463942001-10-16 12:34:39 +00003231 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003232 return(0);
3233 }
3234
Daniel Veillard75b96822001-10-11 18:59:45 +00003235 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003236 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003237 return(res);
3238}
3239
3240/**
3241 * xmlCatalogRemove:
3242 * @value: the value to remove
3243 *
3244 * Remove an entry from the catalog
3245 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003246 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003247 */
3248int
3249xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003250 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003251
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003252 if (!xmlCatalogInitialized)
3253 xmlInitializeCatalog();
3254
Daniel Veillard81463942001-10-16 12:34:39 +00003255 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003256 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003257 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003258 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003259}
3260
3261/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003262 * xmlCatalogConvert:
3263 *
3264 * Convert all the SGML catalog entries as XML ones
3265 *
3266 * Returns the number of entries converted if successful, -1 otherwise
3267 */
3268int
3269xmlCatalogConvert(void) {
3270 int res = -1;
3271
3272 if (!xmlCatalogInitialized)
3273 xmlInitializeCatalog();
3274
Daniel Veillard81463942001-10-16 12:34:39 +00003275 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003276 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003277 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003278 return(res);
3279}
3280
Daniel Veillard75b96822001-10-11 18:59:45 +00003281/************************************************************************
3282 * *
3283 * Public interface manipulating the common preferences *
3284 * *
3285 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003286
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003287/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003288 * xmlCatalogGetDefaults:
3289 *
3290 * Used to get the user preference w.r.t. to what catalogs should
3291 * be accepted
3292 *
3293 * Returns the current xmlCatalogAllow value
3294 */
3295xmlCatalogAllow
3296xmlCatalogGetDefaults(void) {
3297 return(xmlCatalogDefaultAllow);
3298}
3299
3300/**
3301 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003302 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003303 *
3304 * Used to set the user preference w.r.t. to what catalogs should
3305 * be accepted
3306 */
3307void
3308xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003309 if (xmlDebugCatalogs) {
3310 switch (allow) {
3311 case XML_CATA_ALLOW_NONE:
3312 xmlGenericError(xmlGenericErrorContext,
3313 "Disabling catalog usage\n");
3314 break;
3315 case XML_CATA_ALLOW_GLOBAL:
3316 xmlGenericError(xmlGenericErrorContext,
3317 "Allowing only global catalogs\n");
3318 break;
3319 case XML_CATA_ALLOW_DOCUMENT:
3320 xmlGenericError(xmlGenericErrorContext,
3321 "Allowing only catalogs from the document\n");
3322 break;
3323 case XML_CATA_ALLOW_ALL:
3324 xmlGenericError(xmlGenericErrorContext,
3325 "Allowing all catalogs\n");
3326 break;
3327 }
3328 }
3329 xmlCatalogDefaultAllow = allow;
3330}
3331
3332/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003333 * xmlCatalogSetDefaultPrefer:
3334 * @prefer: the default preference for delegation
3335 *
3336 * Allows to set the preference between public and system for deletion
3337 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003338 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003339 *
3340 * Returns the previous value of the default preference for delegation
3341 */
3342xmlCatalogPrefer
3343xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3344 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3345
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003346 if (prefer == XML_CATA_PREFER_NONE)
3347 return(ret);
3348
3349 if (xmlDebugCatalogs) {
3350 switch (prefer) {
3351 case XML_CATA_PREFER_PUBLIC:
3352 xmlGenericError(xmlGenericErrorContext,
3353 "Setting catalog preference to PUBLIC\n");
3354 break;
3355 case XML_CATA_PREFER_SYSTEM:
3356 xmlGenericError(xmlGenericErrorContext,
3357 "Setting catalog preference to SYSTEM\n");
3358 break;
3359 case XML_CATA_PREFER_NONE:
3360 break;
3361 }
3362 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003363 xmlCatalogDefaultPrefer = prefer;
3364 return(ret);
3365}
3366
3367/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003368 * xmlCatalogSetDebug:
3369 * @level: the debug level of catalogs required
3370 *
3371 * Used to set the debug level for catalog operation, 0 disable
3372 * debugging, 1 enable it
3373 *
3374 * Returns the previous value of the catalog debugging level
3375 */
3376int
3377xmlCatalogSetDebug(int level) {
3378 int ret = xmlDebugCatalogs;
3379
3380 if (level <= 0)
3381 xmlDebugCatalogs = 0;
3382 else
3383 xmlDebugCatalogs = level;
3384 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003385}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003386
Daniel Veillard75b96822001-10-11 18:59:45 +00003387/************************************************************************
3388 * *
3389 * Minimal interfaces used for per-document catalogs by the parser *
3390 * *
3391 ************************************************************************/
3392
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003393/**
3394 * xmlCatalogFreeLocal:
3395 * @catalogs: a document's list of catalogs
3396 *
3397 * Free up the memory associated to the catalog list
3398 */
3399void
3400xmlCatalogFreeLocal(void *catalogs) {
3401 xmlCatalogEntryPtr catal;
3402
Daniel Veillard81463942001-10-16 12:34:39 +00003403 if (!xmlCatalogInitialized)
3404 xmlInitializeCatalog();
3405
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003406 catal = (xmlCatalogEntryPtr) catalogs;
3407 if (catal != NULL)
3408 xmlFreeCatalogEntryList(catal);
3409}
3410
3411
3412/**
3413 * xmlCatalogAddLocal:
3414 * @catalogs: a document's list of catalogs
3415 * @URL: the URL to a new local catalog
3416 *
3417 * Add the new entry to the catalog list
3418 *
3419 * Returns the updated list
3420 */
3421void *
3422xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3423 xmlCatalogEntryPtr catal, add;
3424
3425 if (!xmlCatalogInitialized)
3426 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003427
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003428 if (URL == NULL)
3429 return(catalogs);
3430
3431 if (xmlDebugCatalogs)
3432 xmlGenericError(xmlGenericErrorContext,
3433 "Adding document catalog %s\n", URL);
3434
Daniel Veillardc853b322001-11-06 15:24:37 +00003435 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003436 xmlCatalogDefaultPrefer);
3437 if (add == NULL)
3438 return(catalogs);
3439
3440 catal = (xmlCatalogEntryPtr) catalogs;
3441 if (catal == NULL)
3442 return((void *) add);
3443
3444 while (catal->next != NULL)
3445 catal = catal->next;
3446 catal->next = add;
3447 return(catalogs);
3448}
3449
3450/**
3451 * xmlCatalogLocalResolve:
3452 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003453 * @pubID: the public ID string
3454 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003455 *
3456 * Do a complete resolution lookup of an External Identifier using a
3457 * document's private catalog list
3458 *
3459 * Returns the URI of the resource or NULL if not found, it must be freed
3460 * by the caller.
3461 */
3462xmlChar *
3463xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3464 const xmlChar *sysID) {
3465 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003466 xmlChar *ret;
3467
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003468 if (!xmlCatalogInitialized)
3469 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003470
Daniel Veillard81463942001-10-16 12:34:39 +00003471 if ((pubID == NULL) && (sysID == NULL))
3472 return(NULL);
3473
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003474 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003475 if ((pubID != NULL) && (sysID != NULL)) {
3476 xmlGenericError(xmlGenericErrorContext,
3477 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3478 } else if (pubID != NULL) {
3479 xmlGenericError(xmlGenericErrorContext,
3480 "Local Resolve: pubID %s\n", pubID);
3481 } else {
3482 xmlGenericError(xmlGenericErrorContext,
3483 "Local Resolve: sysID %s\n", sysID);
3484 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003485 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003486
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003487 catal = (xmlCatalogEntryPtr) catalogs;
3488 if (catal == NULL)
3489 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003490 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3491 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3492 return(ret);
3493 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003494}
3495
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003496/**
3497 * xmlCatalogLocalResolveURI:
3498 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003499 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003500 *
3501 * Do a complete resolution lookup of an URI using a
3502 * document's private catalog list
3503 *
3504 * Returns the URI of the resource or NULL if not found, it must be freed
3505 * by the caller.
3506 */
3507xmlChar *
3508xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3509 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003510 xmlChar *ret;
3511
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003512 if (!xmlCatalogInitialized)
3513 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003514
Daniel Veillard81463942001-10-16 12:34:39 +00003515 if (URI == NULL)
3516 return(NULL);
3517
Daniel Veillard6990bf32001-08-23 21:17:48 +00003518 if (xmlDebugCatalogs)
3519 xmlGenericError(xmlGenericErrorContext,
3520 "Resolve URI %s\n", URI);
3521
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003522 catal = (xmlCatalogEntryPtr) catalogs;
3523 if (catal == NULL)
3524 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003525 ret = xmlCatalogListXMLResolveURI(catal, URI);
3526 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3527 return(ret);
3528 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003529}
3530
Daniel Veillard75b96822001-10-11 18:59:45 +00003531/************************************************************************
3532 * *
3533 * Deprecated interfaces *
3534 * *
3535 ************************************************************************/
3536/**
3537 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003538 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003539 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003540 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003541 * DEPRECATED, use xmlCatalogResolveSystem()
3542 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003543 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003544 */
3545const xmlChar *
3546xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardfb382b82004-06-14 12:13:12 +00003547 return xmlCatalogResolveSystem(sysID);
Daniel Veillard75b96822001-10-11 18:59:45 +00003548}
3549
3550/**
3551 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003552 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003553 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003554 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003555 * DEPRECATED, use xmlCatalogResolvePublic()
3556 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003557 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003558 */
3559const xmlChar *
3560xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardfb382b82004-06-14 12:13:12 +00003561 return xmlCatalogResolvePublic(pubID);
Daniel Veillard75b96822001-10-11 18:59:45 +00003562}
3563
Daniel Veillarda7374592001-05-10 14:17:55 +00003564#endif /* LIBXML_CATALOG_ENABLED */