blob: 5dcc928b3374f94fd897c10bfdb213e347f31035 [file] [log] [blame]
Daniel Veillarda7374592001-05-10 14:17:55 +00001/**
2 * catalog.c: set of generic Catalog related routines
3 *
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
6 *
Daniel Veillard344cee72001-08-20 00:08:40 +00007 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9 *
Daniel Veillarda7374592001-05-10 14:17:55 +000010 * See Copyright for the status of this software.
11 *
12 * Daniel.Veillard@imag.fr
13 */
14
Daniel Veillard34ce8be2002-03-18 19:37:11 +000015#define IN_LIBXML
Daniel Veillarda7374592001-05-10 14:17:55 +000016#include "libxml.h"
17
18#ifdef LIBXML_CATALOG_ENABLED
19#ifdef HAVE_SYS_TYPES_H
20#include <sys/types.h>
21#endif
22#ifdef HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#ifdef HAVE_FCNTL_H
29#include <fcntl.h>
30#endif
Daniel Veillardc0631a62001-09-20 13:56:06 +000031#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000034#include <string.h>
35#include <libxml/xmlmemory.h>
36#include <libxml/hash.h>
37#include <libxml/uri.h>
38#include <libxml/parserInternals.h>
39#include <libxml/catalog.h>
40#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000041#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000042#include <libxml/globals.h>
Daniel Veillarda7374592001-05-10 14:17:55 +000043
Daniel Veillard6990bf32001-08-23 21:17:48 +000044#define MAX_DELEGATE 50
Daniel Veillard5ee43b02003-08-04 00:58:46 +000045#define MAX_CATAL_DEPTH 50
Daniel Veillard6990bf32001-08-23 21:17:48 +000046
Daniel Veillard344cee72001-08-20 00:08:40 +000047/**
48 * TODO:
49 *
50 * macro to flag unimplemented blocks
Daniel Veillard3e59fc52003-04-18 12:34:58 +000051 * XML_CATALOG_PREFER user env to select between system/public prefered
52 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
53 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
54 *> values "system" and "public". I have made the default be "system" to
55 *> match yours.
Daniel Veillard344cee72001-08-20 00:08:40 +000056 */
57#define TODO \
58 xmlGenericError(xmlGenericErrorContext, \
59 "Unimplemented block at %s:%d\n", \
60 __FILE__, __LINE__);
61
Daniel Veillardcda96922001-08-21 10:56:31 +000062#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000063#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000064#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000065#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000066#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000067#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000068#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000069#endif
70
Daniel Veillardfb382b82004-06-14 12:13:12 +000071#if defined(_WIN32) && defined(_MSC_VER)
72#undef XML_XML_DEFAULT_CATALOG
73static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
74void* __stdcall GetModuleHandleA(const char*);
75unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
76#endif
77
Daniel Veillardc8155052004-07-16 09:03:08 +000078static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
Daniel Veillard85c11fa2001-10-16 21:03:08 +000079static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000080
Daniel Veillarda7374592001-05-10 14:17:55 +000081/************************************************************************
82 * *
83 * Types, all private *
84 * *
85 ************************************************************************/
86
87typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000088 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000089 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000090 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000091 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000092 XML_CATA_NEXT_CATALOG,
93 XML_CATA_PUBLIC,
94 XML_CATA_SYSTEM,
95 XML_CATA_REWRITE_SYSTEM,
96 XML_CATA_DELEGATE_PUBLIC,
97 XML_CATA_DELEGATE_SYSTEM,
98 XML_CATA_URI,
99 XML_CATA_REWRITE_URI,
100 XML_CATA_DELEGATE_URI,
101 SGML_CATA_SYSTEM,
102 SGML_CATA_PUBLIC,
103 SGML_CATA_ENTITY,
104 SGML_CATA_PENTITY,
105 SGML_CATA_DOCTYPE,
106 SGML_CATA_LINKTYPE,
107 SGML_CATA_NOTATION,
108 SGML_CATA_DELEGATE,
109 SGML_CATA_BASE,
110 SGML_CATA_CATALOG,
111 SGML_CATA_DOCUMENT,
112 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000113} xmlCatalogEntryType;
114
115typedef struct _xmlCatalogEntry xmlCatalogEntry;
116typedef xmlCatalogEntry *xmlCatalogEntryPtr;
117struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000118 struct _xmlCatalogEntry *next;
119 struct _xmlCatalogEntry *parent;
120 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000121 xmlCatalogEntryType type;
122 xmlChar *name;
123 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000124 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000125 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000126 int dealloc;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000127 int depth;
Daniel Veillarda7374592001-05-10 14:17:55 +0000128};
129
Daniel Veillard75b96822001-10-11 18:59:45 +0000130typedef enum {
131 XML_XML_CATALOG_TYPE = 1,
132 XML_SGML_CATALOG_TYPE
133} xmlCatalogType;
134
135#define XML_MAX_SGML_CATA_DEPTH 10
136struct _xmlCatalog {
137 xmlCatalogType type; /* either XML or SGML */
138
139 /*
140 * SGML Catalogs are stored as a simple hash table of catalog entries
141 * Catalog stack to check against overflows when building the
142 * SGML catalog
143 */
144 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
145 int catalNr; /* Number of current catal streams */
146 int catalMax; /* Max number of catal streams */
147 xmlHashTablePtr sgml;
148
149 /*
150 * XML Catalogs are stored as a tree of Catalog entries
151 */
152 xmlCatalogPrefer prefer;
153 xmlCatalogEntryPtr xml;
154};
155
156/************************************************************************
157 * *
158 * Global variables *
159 * *
160 ************************************************************************/
161
Daniel Veillard81463942001-10-16 12:34:39 +0000162/*
163 * Those are preferences
164 */
165static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000166static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000167static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000168
169/*
170 * Hash table containing all the trees of XML catalogs parsed by
171 * the application.
172 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000173static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000174
175/*
176 * The default catalog in use by the application
177 */
178static xmlCatalogPtr xmlDefaultCatalog = NULL;
179
180/*
Daniel Veillard81463942001-10-16 12:34:39 +0000181 * A mutex for modifying the shared global catalog(s)
182 * xmlDefaultCatalog tree.
183 * It also protects xmlCatalogXMLFiles
184 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
185 */
186static xmlRMutexPtr xmlCatalogMutex = NULL;
187
188/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000189 * Whether the catalog support was initialized.
190 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000191static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000192
Daniel Veillard69d2c172003-10-09 11:46:07 +0000193/************************************************************************
194 * *
195 * Catalog error handlers *
196 * *
197 ************************************************************************/
198
199/**
200 * xmlCatalogErrMemory:
201 * @extra: extra informations
202 *
203 * Handle an out of memory condition
204 */
205static void
206xmlCatalogErrMemory(const char *extra)
207{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000208 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000209 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
210 extra, NULL, NULL, 0, 0,
211 "Memory allocation failed : %s\n", extra);
212}
213
214/**
215 * xmlCatalogErr:
216 * @catal: the Catalog entry
217 * @node: the context node
218 * @msg: the error message
219 * @extra: extra informations
220 *
221 * Handle a catalog error
222 */
223static void
224xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
225 const char *msg, const xmlChar *str1, const xmlChar *str2,
226 const xmlChar *str3)
227{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000228 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000229 error, XML_ERR_ERROR, NULL, 0,
230 (const char *) str1, (const char *) str2,
231 (const char *) str3, 0, 0,
232 msg, str1, str2, str3);
233}
234
Daniel Veillarda7374592001-05-10 14:17:55 +0000235
236/************************************************************************
237 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000238 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000239 * *
240 ************************************************************************/
241
Daniel Veillard75b96822001-10-11 18:59:45 +0000242/**
243 * xmlNewCatalogEntry:
244 * @type: type of entry
245 * @name: name of the entry
246 * @value: value of the entry
247 * @prefer: the PUBLIC vs. SYSTEM current preference value
248 *
249 * create a new Catalog entry, this type is shared both by XML and
250 * SGML catalogs, but the acceptable types values differs.
251 *
252 * Returns the xmlCatalogEntryPtr or NULL in case of error
253 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000254static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000255xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillardc853b322001-11-06 15:24:37 +0000256 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000257 xmlCatalogEntryPtr ret;
Daniel Veillardc8155052004-07-16 09:03:08 +0000258 xmlChar *normid = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000259
260 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
261 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000262 xmlCatalogErrMemory("allocating catalog entry");
Daniel Veillarda7374592001-05-10 14:17:55 +0000263 return(NULL);
264 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000265 ret->next = NULL;
266 ret->parent = NULL;
267 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000268 ret->type = type;
Daniel Veillardc8155052004-07-16 09:03:08 +0000269 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
270 normid = xmlCatalogNormalizePublic(name);
271 if (normid != NULL)
272 name = (*normid != 0 ? normid : NULL);
273 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000274 if (name != NULL)
275 ret->name = xmlStrdup(name);
276 else
277 ret->name = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +0000278 if (normid != NULL)
279 xmlFree(normid);
Daniel Veillard344cee72001-08-20 00:08:40 +0000280 if (value != NULL)
281 ret->value = xmlStrdup(value);
282 else
283 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000284 if (URL == NULL)
285 URL = value;
286 if (URL != NULL)
287 ret->URL = xmlStrdup(URL);
288 else
289 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000290 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000291 ret->dealloc = 0;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000292 ret->depth = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +0000293 return(ret);
294}
295
296static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000297xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
298
Daniel Veillard75b96822001-10-11 18:59:45 +0000299/**
300 * xmlFreeCatalogEntry:
301 * @ret: a Catalog entry
302 *
303 * Free the memory allocated to a Catalog entry
304 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000305static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000306xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
307 if (ret == NULL)
308 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000309 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000310 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000311 * only by the file hash cleaner !
312 */
313 if (ret->dealloc == 1)
314 return;
315
316 if (xmlDebugCatalogs) {
317 if (ret->name != NULL)
318 xmlGenericError(xmlGenericErrorContext,
319 "Free catalog entry %s\n", ret->name);
320 else if (ret->value != NULL)
321 xmlGenericError(xmlGenericErrorContext,
322 "Free catalog entry %s\n", ret->value);
323 else
324 xmlGenericError(xmlGenericErrorContext,
325 "Free catalog entry\n");
326 }
327
Daniel Veillarda7374592001-05-10 14:17:55 +0000328 if (ret->name != NULL)
329 xmlFree(ret->name);
330 if (ret->value != NULL)
331 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000332 if (ret->URL != NULL)
333 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000334 xmlFree(ret);
335}
336
Daniel Veillard75b96822001-10-11 18:59:45 +0000337/**
338 * xmlFreeCatalogEntryList:
339 * @ret: a Catalog entry list
340 *
341 * Free the memory allocated to a full chained list of Catalog entries
342 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000343static void
344xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
345 xmlCatalogEntryPtr next;
346
347 while (ret != NULL) {
348 next = ret->next;
349 xmlFreeCatalogEntry(ret);
350 ret = next;
351 }
352}
353
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000354/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000355 * xmlFreeCatalogHashEntryList:
356 * @ret: a Catalog entry list
357 *
358 * Free the memory allocated to list of Catalog entries from the
359 * catalog file hash.
360 */
361static void
362xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
363 xmlCatalogEntryPtr children, next;
364
365 if (catal == NULL)
366 return;
367
368 children = catal->children;
369 while (children != NULL) {
370 next = children->next;
371 children->dealloc = 0;
372 children->children = NULL;
373 xmlFreeCatalogEntry(children);
374 children = next;
375 }
376 catal->dealloc = 0;
377 xmlFreeCatalogEntry(catal);
378}
379
380/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000381 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000382 * @type: type of catalog
383 * @prefer: the PUBLIC vs. SYSTEM current preference value
384 *
385 * create a new Catalog, this type is shared both by XML and
386 * SGML catalogs, but the acceptable types values differs.
387 *
388 * Returns the xmlCatalogPtr or NULL in case of error
389 */
390static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000391xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000392 xmlCatalogPtr ret;
393
394 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
395 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000396 xmlCatalogErrMemory("allocating catalog");
Daniel Veillard75b96822001-10-11 18:59:45 +0000397 return(NULL);
398 }
399 memset(ret, 0, sizeof(xmlCatalog));
400 ret->type = type;
401 ret->catalNr = 0;
402 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
403 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000404 if (ret->type == XML_SGML_CATALOG_TYPE)
405 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000406 return(ret);
407}
408
409/**
410 * xmlFreeCatalog:
Daniel Veillard06d25242004-02-25 13:01:42 +0000411 * @catal: a Catalog
Daniel Veillard75b96822001-10-11 18:59:45 +0000412 *
413 * Free the memory allocated to a Catalog
414 */
415void
416xmlFreeCatalog(xmlCatalogPtr catal) {
417 if (catal == NULL)
418 return;
419 if (catal->xml != NULL)
420 xmlFreeCatalogEntryList(catal->xml);
421 if (catal->sgml != NULL)
422 xmlHashFree(catal->sgml,
423 (xmlHashDeallocator) xmlFreeCatalogEntry);
424 xmlFree(catal);
425}
426
427/************************************************************************
428 * *
429 * Serializing Catalogs *
430 * *
431 ************************************************************************/
432
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000433#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000434/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000435 * xmlCatalogDumpEntry:
Daniel Veillard06d25242004-02-25 13:01:42 +0000436 * @entry: the catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000437 * @out: the file.
438 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000439 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000440 */
441static void
442xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
443 if ((entry == NULL) || (out == NULL))
444 return;
445 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000446 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000447 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000448 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000449 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000450 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000451 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000452 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000453 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000454 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000455 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000456 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000457 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000458 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000459 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000460 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000461 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000462 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000463 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000464 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000465 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000466 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000467 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000468 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000469 fprintf(out, "SGMLDECL "); break;
470 default:
471 return;
472 }
473 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000474 case SGML_CATA_ENTITY:
475 case SGML_CATA_PENTITY:
476 case SGML_CATA_DOCTYPE:
477 case SGML_CATA_LINKTYPE:
478 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000479 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000480 case SGML_CATA_PUBLIC:
481 case SGML_CATA_SYSTEM:
482 case SGML_CATA_SGMLDECL:
483 case SGML_CATA_DOCUMENT:
484 case SGML_CATA_CATALOG:
485 case SGML_CATA_BASE:
486 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000487 fprintf(out, "\"%s\"", entry->name); break;
488 default:
489 break;
490 }
491 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000492 case SGML_CATA_ENTITY:
493 case SGML_CATA_PENTITY:
494 case SGML_CATA_DOCTYPE:
495 case SGML_CATA_LINKTYPE:
496 case SGML_CATA_NOTATION:
497 case SGML_CATA_PUBLIC:
498 case SGML_CATA_SYSTEM:
499 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000500 fprintf(out, " \"%s\"", entry->value); break;
501 default:
502 break;
503 }
504 fprintf(out, "\n");
505}
506
Daniel Veillard75b96822001-10-11 18:59:45 +0000507static int
508xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
509 int ret;
510 xmlDocPtr doc;
511 xmlNsPtr ns;
512 xmlDtdPtr dtd;
513 xmlNodePtr node, catalog;
514 xmlOutputBufferPtr buf;
515 xmlCatalogEntryPtr cur;
516
517 /*
518 * Rebuild a catalog
519 */
520 doc = xmlNewDoc(NULL);
521 if (doc == NULL)
522 return(-1);
523 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
524 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
525BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
526
527 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
528
529 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
530 if (ns == NULL) {
531 xmlFreeDoc(doc);
532 return(-1);
533 }
534 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
535 if (catalog == NULL) {
536 xmlFreeNs(ns);
537 xmlFreeDoc(doc);
538 return(-1);
539 }
540 catalog->nsDef = ns;
541 xmlAddChild((xmlNodePtr) doc, catalog);
542
543 /*
544 * add all the catalog entries
545 */
546 cur = catal;
547 while (cur != NULL) {
548 switch (cur->type) {
Daniel Veillardc853b322001-11-06 15:24:37 +0000549 case XML_CATA_REMOVED:
550 break;
Daniel Veillard75b96822001-10-11 18:59:45 +0000551 case XML_CATA_BROKEN_CATALOG:
552 case XML_CATA_CATALOG:
553 if (cur == catal) {
554 cur = cur->children;
555 continue;
556 }
557 break;
558 case XML_CATA_NEXT_CATALOG:
559 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
560 xmlSetProp(node, BAD_CAST "catalog", cur->value);
561 xmlAddChild(catalog, node);
562 break;
563 case XML_CATA_NONE:
564 break;
565 case XML_CATA_PUBLIC:
566 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
567 xmlSetProp(node, BAD_CAST "publicId", cur->name);
568 xmlSetProp(node, BAD_CAST "uri", cur->value);
569 xmlAddChild(catalog, node);
570 break;
571 case XML_CATA_SYSTEM:
572 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
573 xmlSetProp(node, BAD_CAST "systemId", cur->name);
574 xmlSetProp(node, BAD_CAST "uri", cur->value);
575 xmlAddChild(catalog, node);
576 break;
577 case XML_CATA_REWRITE_SYSTEM:
578 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
579 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
580 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
581 xmlAddChild(catalog, node);
582 break;
583 case XML_CATA_DELEGATE_PUBLIC:
584 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
585 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
586 xmlSetProp(node, BAD_CAST "catalog", cur->value);
587 xmlAddChild(catalog, node);
588 break;
589 case XML_CATA_DELEGATE_SYSTEM:
590 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
591 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
592 xmlSetProp(node, BAD_CAST "catalog", cur->value);
593 xmlAddChild(catalog, node);
594 break;
595 case XML_CATA_URI:
596 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
597 xmlSetProp(node, BAD_CAST "name", cur->name);
598 xmlSetProp(node, BAD_CAST "uri", cur->value);
599 xmlAddChild(catalog, node);
600 break;
601 case XML_CATA_REWRITE_URI:
602 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
603 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
604 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
605 xmlAddChild(catalog, node);
606 break;
607 case XML_CATA_DELEGATE_URI:
608 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
609 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
610 xmlSetProp(node, BAD_CAST "catalog", cur->value);
611 xmlAddChild(catalog, node);
612 break;
613 case SGML_CATA_SYSTEM:
614 case SGML_CATA_PUBLIC:
615 case SGML_CATA_ENTITY:
616 case SGML_CATA_PENTITY:
617 case SGML_CATA_DOCTYPE:
618 case SGML_CATA_LINKTYPE:
619 case SGML_CATA_NOTATION:
620 case SGML_CATA_DELEGATE:
621 case SGML_CATA_BASE:
622 case SGML_CATA_CATALOG:
623 case SGML_CATA_DOCUMENT:
624 case SGML_CATA_SGMLDECL:
625 break;
626 }
627 cur = cur->next;
628 }
629
630 /*
631 * reserialize it
632 */
633 buf = xmlOutputBufferCreateFile(out, NULL);
634 if (buf == NULL) {
635 xmlFreeDoc(doc);
636 return(-1);
637 }
638 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
639
640 /*
641 * Free it
642 */
643 xmlFreeDoc(doc);
644
645 return(ret);
646}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000647#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000648
649/************************************************************************
650 * *
651 * Converting SGML Catalogs to XML *
652 * *
653 ************************************************************************/
654
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000655/**
656 * xmlCatalogConvertEntry:
657 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000658 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000659 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000660 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000661 */
662static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000663xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
664 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
665 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000666 return;
667 switch (entry->type) {
668 case SGML_CATA_ENTITY:
669 entry->type = XML_CATA_PUBLIC;
670 break;
671 case SGML_CATA_PENTITY:
672 entry->type = XML_CATA_PUBLIC;
673 break;
674 case SGML_CATA_DOCTYPE:
675 entry->type = XML_CATA_PUBLIC;
676 break;
677 case SGML_CATA_LINKTYPE:
678 entry->type = XML_CATA_PUBLIC;
679 break;
680 case SGML_CATA_NOTATION:
681 entry->type = XML_CATA_PUBLIC;
682 break;
683 case SGML_CATA_PUBLIC:
684 entry->type = XML_CATA_PUBLIC;
685 break;
686 case SGML_CATA_SYSTEM:
687 entry->type = XML_CATA_SYSTEM;
688 break;
689 case SGML_CATA_DELEGATE:
690 entry->type = XML_CATA_DELEGATE_PUBLIC;
691 break;
692 case SGML_CATA_CATALOG:
693 entry->type = XML_CATA_CATALOG;
694 break;
695 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000696 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000697 (xmlHashDeallocator) xmlFreeCatalogEntry);
698 return;
699 }
700 /*
701 * Conversion successful, remove from the SGML catalog
702 * and add it to the default XML one
703 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000704 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
705 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000706 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000707 if (catal->xml->children == NULL)
708 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000709 else {
710 xmlCatalogEntryPtr prev;
711
Daniel Veillard75b96822001-10-11 18:59:45 +0000712 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000713 while (prev->next != NULL)
714 prev = prev->next;
715 prev->next = entry;
716 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000717}
718
719/**
720 * xmlConvertSGMLCatalog:
721 * @catal: the catalog
722 *
723 * Convert all the SGML catalog entries as XML ones
724 *
725 * Returns the number of entries converted if successful, -1 otherwise
726 */
727int
728xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
729
730 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
731 return(-1);
732
733 if (xmlDebugCatalogs) {
734 xmlGenericError(xmlGenericErrorContext,
735 "Converting SGML catalog to XML\n");
736 }
737 xmlHashScan(catal->sgml,
738 (xmlHashScanner) xmlCatalogConvertEntry,
739 &catal);
740 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000741}
742
Daniel Veillarda7374592001-05-10 14:17:55 +0000743/************************************************************************
744 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000745 * Helper function *
746 * *
747 ************************************************************************/
748
749/**
750 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000751 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000752 *
753 * Expand the URN into the equivalent Public Identifier
754 *
755 * Returns the new identifier or NULL, the string must be deallocated
756 * by the caller.
757 */
758static xmlChar *
759xmlCatalogUnWrapURN(const xmlChar *urn) {
760 xmlChar result[2000];
761 unsigned int i = 0;
762
763 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
764 return(NULL);
765 urn += sizeof(XML_URN_PUBID) - 1;
766
767 while (*urn != 0) {
Daniel Veillard770075b2004-02-25 10:44:30 +0000768 if (i > sizeof(result) - 4)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000769 break;
770 if (*urn == '+') {
771 result[i++] = ' ';
772 urn++;
773 } else if (*urn == ':') {
774 result[i++] = '/';
775 result[i++] = '/';
776 urn++;
777 } else if (*urn == ';') {
778 result[i++] = ':';
779 result[i++] = ':';
780 urn++;
781 } else if (*urn == '%') {
Daniel Veillard770075b2004-02-25 10:44:30 +0000782 if ((urn[1] == '2') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000783 result[i++] = '+';
Daniel Veillard770075b2004-02-25 10:44:30 +0000784 else if ((urn[1] == '3') && (urn[2] == 'A'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000785 result[i++] = ':';
Daniel Veillard770075b2004-02-25 10:44:30 +0000786 else if ((urn[1] == '2') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000787 result[i++] = '/';
Daniel Veillard770075b2004-02-25 10:44:30 +0000788 else if ((urn[1] == '3') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000789 result[i++] = ';';
Daniel Veillard770075b2004-02-25 10:44:30 +0000790 else if ((urn[1] == '2') && (urn[2] == '7'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000791 result[i++] = '\'';
Daniel Veillard770075b2004-02-25 10:44:30 +0000792 else if ((urn[1] == '3') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000793 result[i++] = '?';
Daniel Veillard770075b2004-02-25 10:44:30 +0000794 else if ((urn[1] == '2') && (urn[2] == '3'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000795 result[i++] = '#';
Daniel Veillard770075b2004-02-25 10:44:30 +0000796 else if ((urn[1] == '2') && (urn[2] == '5'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000797 result[i++] = '%';
798 else {
799 result[i++] = *urn;
800 urn++;
801 continue;
802 }
803 urn += 3;
804 } else {
805 result[i++] = *urn;
806 urn++;
807 }
808 }
809 result[i] = 0;
810
811 return(xmlStrdup(result));
812}
813
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000814/**
815 * xmlParseCatalogFile:
816 * @filename: the filename
817 *
818 * parse an XML file and build a tree. It's like xmlParseFile()
819 * except it bypass all catalog lookups.
820 *
821 * Returns the resulting document tree or NULL in case of error
822 */
823
824xmlDocPtr
825xmlParseCatalogFile(const char *filename) {
826 xmlDocPtr ret;
827 xmlParserCtxtPtr ctxt;
828 char *directory = NULL;
829 xmlParserInputPtr inputStream;
830 xmlParserInputBufferPtr buf;
831
832 ctxt = xmlNewParserCtxt();
833 if (ctxt == NULL) {
834 if (xmlDefaultSAXHandler.error != NULL) {
835 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
836 }
837 return(NULL);
838 }
839
840 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
841 if (buf == NULL) {
842 xmlFreeParserCtxt(ctxt);
843 return(NULL);
844 }
845
846 inputStream = xmlNewInputStream(ctxt);
847 if (inputStream == NULL) {
848 xmlFreeParserCtxt(ctxt);
849 return(NULL);
850 }
851
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000852 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000853 inputStream->buf = buf;
854 inputStream->base = inputStream->buf->buffer->content;
855 inputStream->cur = inputStream->buf->buffer->content;
856 inputStream->end =
857 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
858
859 inputPush(ctxt, inputStream);
860 if ((ctxt->directory == NULL) && (directory == NULL))
861 directory = xmlParserGetDirectory(filename);
862 if ((ctxt->directory == NULL) && (directory != NULL))
863 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000864 ctxt->valid = 0;
865 ctxt->validate = 0;
866 ctxt->loadsubset = 0;
867 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000868
869 xmlParseDocument(ctxt);
870
871 if (ctxt->wellFormed)
872 ret = ctxt->myDoc;
873 else {
874 ret = NULL;
875 xmlFreeDoc(ctxt->myDoc);
876 ctxt->myDoc = NULL;
877 }
878 xmlFreeParserCtxt(ctxt);
879
880 return(ret);
881}
882
Daniel Veillard75b96822001-10-11 18:59:45 +0000883/**
884 * xmlLoadFileContent:
885 * @filename: a file path
886 *
887 * Load a file content into memory.
888 *
889 * Returns a pointer to the 0 terminated string or NULL in case of error
890 */
891static xmlChar *
892xmlLoadFileContent(const char *filename)
893{
894#ifdef HAVE_STAT
895 int fd;
896#else
897 FILE *fd;
898#endif
899 int len;
900 long size;
901
902#ifdef HAVE_STAT
903 struct stat info;
904#endif
905 xmlChar *content;
906
907 if (filename == NULL)
908 return (NULL);
909
910#ifdef HAVE_STAT
911 if (stat(filename, &info) < 0)
912 return (NULL);
913#endif
914
915#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000916 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000917#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000918 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000919#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000920 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000921 return (NULL);
922 }
923#ifdef HAVE_STAT
924 size = info.st_size;
925#else
926 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
927 fclose(fd);
928 return (NULL);
929 }
930#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000931 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000932 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000933 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard75b96822001-10-11 18:59:45 +0000934 return (NULL);
935 }
936#ifdef HAVE_STAT
937 len = read(fd, content, size);
938#else
939 len = fread(content, 1, size, fd);
940#endif
941 if (len < 0) {
942 xmlFree(content);
943 return (NULL);
944 }
945#ifdef HAVE_STAT
946 close(fd);
947#else
948 fclose(fd);
949#endif
950 content[len] = 0;
951
952 return(content);
953}
954
Daniel Veillardc8155052004-07-16 09:03:08 +0000955/**
956 * xmlCatalogNormalizePublic:
957 * @pubID: the public ID string
958 *
959 * Normalizes the Public Identifier
960 *
961 * Implements 6.2. Public Identifier Normalization
962 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
963 *
964 * Returns the new string or NULL, the string must be deallocated
965 * by the caller.
966 */
967static xmlChar *
968xmlCatalogNormalizePublic(const xmlChar *pubID)
969{
970 int ok = 1;
971 int white;
972 const xmlChar *p;
973 xmlChar *ret;
974 xmlChar *q;
975
976 if (pubID == NULL)
977 return(NULL);
978
979 white = 1;
980 for (p = pubID;*p != 0 && ok;p++) {
981 if (!xmlIsBlank_ch(*p))
982 white = 0;
983 else if (*p == 0x20 && !white)
984 white = 1;
985 else
986 ok = 0;
987 }
988 if (ok && !white) /* is normalized */
989 return(NULL);
990
991 ret = xmlStrdup(pubID);
992 q = ret;
993 white = 0;
994 for (p = pubID;*p != 0;p++) {
995 if (xmlIsBlank_ch(*p)) {
996 if (q != ret)
997 white = 1;
998 } else {
999 if (white) {
1000 *(q++) = 0x20;
1001 white = 0;
1002 }
1003 *(q++) = *p;
1004 }
1005 }
1006 *q = 0;
1007 return(ret);
1008}
1009
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001010/************************************************************************
1011 * *
Daniel Veillard344cee72001-08-20 00:08:40 +00001012 * The XML Catalog parser *
1013 * *
1014 ************************************************************************/
1015
1016static xmlCatalogEntryPtr
1017xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001018static void
1019xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1020 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +00001021static xmlChar *
1022xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1023 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001024static xmlChar *
1025xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1026
Daniel Veillard344cee72001-08-20 00:08:40 +00001027
Daniel Veillard75b96822001-10-11 18:59:45 +00001028/**
1029 * xmlGetXMLCatalogEntryType:
1030 * @name: the name
1031 *
1032 * lookup the internal type associated to an XML catalog entry name
1033 *
Daniel Veillard06d25242004-02-25 13:01:42 +00001034 * Returns the type associated with that name
Daniel Veillard75b96822001-10-11 18:59:45 +00001035 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001036static xmlCatalogEntryType
1037xmlGetXMLCatalogEntryType(const xmlChar *name) {
1038 xmlCatalogEntryType type = XML_CATA_NONE;
1039 if (xmlStrEqual(name, (const xmlChar *) "system"))
1040 type = XML_CATA_SYSTEM;
1041 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1042 type = XML_CATA_PUBLIC;
1043 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1044 type = XML_CATA_REWRITE_SYSTEM;
1045 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1046 type = XML_CATA_DELEGATE_PUBLIC;
1047 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1048 type = XML_CATA_DELEGATE_SYSTEM;
1049 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1050 type = XML_CATA_URI;
1051 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1052 type = XML_CATA_REWRITE_URI;
1053 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1054 type = XML_CATA_DELEGATE_URI;
1055 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1056 type = XML_CATA_NEXT_CATALOG;
1057 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1058 type = XML_CATA_CATALOG;
1059 return(type);
1060}
1061
Daniel Veillard75b96822001-10-11 18:59:45 +00001062/**
1063 * xmlParseXMLCatalogOneNode:
1064 * @cur: the XML node
1065 * @type: the type of Catalog entry
1066 * @name: the name of the node
1067 * @attrName: the attribute holding the value
1068 * @uriAttrName: the attribute holding the URI-Reference
1069 * @prefer: the PUBLIC vs. SYSTEM current preference value
1070 *
1071 * Finishes the examination of an XML tree node of a catalog and build
1072 * a Catalog entry from it.
1073 *
1074 * Returns the new Catalog entry node or NULL in case of error.
1075 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001076static xmlCatalogEntryPtr
1077xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1078 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001079 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001080 int ok = 1;
1081 xmlChar *uriValue;
1082 xmlChar *nameValue = NULL;
1083 xmlChar *base = NULL;
1084 xmlChar *URL = NULL;
1085 xmlCatalogEntryPtr ret = NULL;
1086
1087 if (attrName != NULL) {
1088 nameValue = xmlGetProp(cur, attrName);
1089 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001090 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1091 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001092 ok = 0;
1093 }
1094 }
1095 uriValue = xmlGetProp(cur, uriAttrName);
1096 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001097 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1098 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001099 ok = 0;
1100 }
1101 if (!ok) {
1102 if (nameValue != NULL)
1103 xmlFree(nameValue);
1104 if (uriValue != NULL)
1105 xmlFree(uriValue);
1106 return(NULL);
1107 }
1108
1109 base = xmlNodeGetBase(cur->doc, cur);
1110 URL = xmlBuildURI(uriValue, base);
1111 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001112 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001113 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001114 xmlGenericError(xmlGenericErrorContext,
1115 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001116 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001117 xmlGenericError(xmlGenericErrorContext,
1118 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001119 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001120 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001121 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001122 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001123 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1124 }
1125 if (nameValue != NULL)
1126 xmlFree(nameValue);
1127 if (uriValue != NULL)
1128 xmlFree(uriValue);
1129 if (base != NULL)
1130 xmlFree(base);
1131 if (URL != NULL)
1132 xmlFree(URL);
1133 return(ret);
1134}
1135
Daniel Veillard75b96822001-10-11 18:59:45 +00001136/**
1137 * xmlParseXMLCatalogNode:
1138 * @cur: the XML node
1139 * @prefer: the PUBLIC vs. SYSTEM current preference value
1140 * @parent: the parent Catalog entry
1141 *
1142 * Examines an XML tree node of a catalog and build
1143 * a Catalog entry from it adding it to its parent. The examination can
1144 * be recursive.
1145 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001146static void
1147xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1148 xmlCatalogEntryPtr parent)
1149{
1150 xmlChar *uri = NULL;
1151 xmlChar *URL = NULL;
1152 xmlChar *base = NULL;
1153 xmlCatalogEntryPtr entry = NULL;
1154
1155 if (cur == NULL)
1156 return;
1157 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1158 xmlChar *prop;
1159
1160 prop = xmlGetProp(cur, BAD_CAST "prefer");
1161 if (prop != NULL) {
1162 if (xmlStrEqual(prop, BAD_CAST "system")) {
1163 prefer = XML_CATA_PREFER_SYSTEM;
1164 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1165 prefer = XML_CATA_PREFER_PUBLIC;
1166 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001167 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1168 "Invalid value for prefer: '%s'\n",
1169 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001170 }
1171 xmlFree(prop);
1172 }
1173 /*
1174 * Recurse to propagate prefer to the subtree
1175 * (xml:base handling is automated)
1176 */
1177 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1178 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1179 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001180 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001181 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1182 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001183 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001184 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1185 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1186 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001187 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001188 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1189 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1190 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001191 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001192 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1193 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1194 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001195 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001196 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1197 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1198 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001199 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001200 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1201 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1202 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001203 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001204 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1205 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1206 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001207 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001208 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1209 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1210 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001211 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001212 }
1213 if ((entry != NULL) && (parent != NULL)) {
1214 entry->parent = parent;
1215 if (parent->children == NULL)
1216 parent->children = entry;
1217 else {
1218 xmlCatalogEntryPtr prev;
1219
1220 prev = parent->children;
1221 while (prev->next != NULL)
1222 prev = prev->next;
1223 prev->next = entry;
1224 }
1225 }
1226 if (base != NULL)
1227 xmlFree(base);
1228 if (uri != NULL)
1229 xmlFree(uri);
1230 if (URL != NULL)
1231 xmlFree(URL);
1232}
1233
Daniel Veillard75b96822001-10-11 18:59:45 +00001234/**
1235 * xmlParseXMLCatalogNodeList:
1236 * @cur: the XML node list of siblings
1237 * @prefer: the PUBLIC vs. SYSTEM current preference value
1238 * @parent: the parent Catalog entry
1239 *
1240 * Examines a list of XML sibling nodes of a catalog and build
1241 * a list of Catalog entry from it adding it to the parent.
1242 * The examination will recurse to examine node subtrees.
1243 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001244static void
1245xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1246 xmlCatalogEntryPtr parent) {
1247 while (cur != NULL) {
1248 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1249 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1250 xmlParseXMLCatalogNode(cur, prefer, parent);
1251 }
1252 cur = cur->next;
1253 }
1254 /* TODO: sort the list according to REWRITE lengths and prefer value */
1255}
1256
Daniel Veillard75b96822001-10-11 18:59:45 +00001257/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001258 * xmlParseXMLCatalogFile:
1259 * @prefer: the PUBLIC vs. SYSTEM current preference value
1260 * @filename: the filename for the catalog
1261 *
1262 * Parses the catalog file to extract the XML tree and then analyze the
1263 * tree to build a list of Catalog entries corresponding to this catalog
1264 *
1265 * Returns the resulting Catalog entries list
1266 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001267static xmlCatalogEntryPtr
1268xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1269 xmlDocPtr doc;
1270 xmlNodePtr cur;
1271 xmlChar *prop;
1272 xmlCatalogEntryPtr parent = NULL;
1273
1274 if (filename == NULL)
1275 return(NULL);
1276
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001277 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001278 if (doc == NULL) {
1279 if (xmlDebugCatalogs)
1280 xmlGenericError(xmlGenericErrorContext,
1281 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001282 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001283 }
1284
1285 if (xmlDebugCatalogs)
1286 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001287 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001288
1289 cur = xmlDocGetRootElement(doc);
1290 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1291 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1292 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1293
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001294 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00001295 (const xmlChar *)filename, NULL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001296 if (parent == NULL) {
1297 xmlFreeDoc(doc);
1298 return(NULL);
1299 }
1300
1301 prop = xmlGetProp(cur, BAD_CAST "prefer");
1302 if (prop != NULL) {
1303 if (xmlStrEqual(prop, BAD_CAST "system")) {
1304 prefer = XML_CATA_PREFER_SYSTEM;
1305 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1306 prefer = XML_CATA_PREFER_PUBLIC;
1307 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001308 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1309 "Invalid value for prefer: '%s'\n",
1310 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001311 }
1312 xmlFree(prop);
1313 }
1314 cur = cur->children;
1315 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1316 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001317 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1318 "File %s is not an XML Catalog\n",
1319 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001320 xmlFreeDoc(doc);
1321 return(NULL);
1322 }
1323 xmlFreeDoc(doc);
1324 return(parent);
1325}
1326
Daniel Veillardcda96922001-08-21 10:56:31 +00001327/**
1328 * xmlFetchXMLCatalogFile:
1329 * @catal: an existing but incomplete catalog entry
1330 *
1331 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001332 *
1333 * Returns 0 in case of success, -1 otherwise
1334 */
1335static int
1336xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001337 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001338
1339 if (catal == NULL)
1340 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001341 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001342 return(-1);
1343 if (catal->children != NULL)
1344 return(-1);
1345
Daniel Veillard81463942001-10-16 12:34:39 +00001346 /*
1347 * lock the whole catalog for modification
1348 */
1349 xmlRMutexLock(xmlCatalogMutex);
1350 if (catal->children != NULL) {
1351 /* Okay someone else did it in the meantime */
1352 xmlRMutexUnlock(xmlCatalogMutex);
1353 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001354 }
1355
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001356 if (xmlCatalogXMLFiles != NULL) {
1357 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001358 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001359 if (doc != NULL) {
1360 if (xmlDebugCatalogs)
1361 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001362 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001363
1364 if (catal->type == XML_CATA_CATALOG)
1365 catal->children = doc->children;
1366 else
1367 catal->children = doc;
1368 catal->dealloc = 0;
1369 xmlRMutexUnlock(xmlCatalogMutex);
1370 return(0);
1371 }
1372 if (xmlDebugCatalogs)
1373 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001374 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001375 }
1376
Daniel Veillardcda96922001-08-21 10:56:31 +00001377 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001378 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001379 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001380 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001381 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001382 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001383 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001384 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001385 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001386 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001387 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001388
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001389 if (catal->type == XML_CATA_CATALOG)
1390 catal->children = doc->children;
1391 else
1392 catal->children = doc;
1393
1394 doc->dealloc = 1;
1395
Daniel Veillard81463942001-10-16 12:34:39 +00001396 if (xmlCatalogXMLFiles == NULL)
1397 xmlCatalogXMLFiles = xmlHashCreate(10);
1398 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001399 if (xmlDebugCatalogs)
1400 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001401 "%s added to file hash\n", catal->URL);
1402 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001403 }
Daniel Veillard81463942001-10-16 12:34:39 +00001404 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001405 return(0);
1406}
1407
Daniel Veillard75b96822001-10-11 18:59:45 +00001408/************************************************************************
1409 * *
1410 * XML Catalog handling *
1411 * *
1412 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001413
1414/**
1415 * xmlAddXMLCatalog:
1416 * @catal: top of an XML catalog
1417 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001418 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001419 * @replace: the replacement value for the match
1420 *
1421 * Add an entry in the XML catalog, it may overwrite existing but
1422 * different entries.
1423 *
1424 * Returns 0 if successful, -1 otherwise
1425 */
1426static int
1427xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1428 const xmlChar *orig, const xmlChar *replace) {
1429 xmlCatalogEntryPtr cur;
1430 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001431 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001432
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001433 if ((catal == NULL) ||
1434 ((catal->type != XML_CATA_CATALOG) &&
1435 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001436 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001437 if (catal->children == NULL) {
1438 xmlFetchXMLCatalogFile(catal);
1439 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001440 if (catal->children == NULL)
1441 doregister = 1;
1442
Daniel Veillard344cee72001-08-20 00:08:40 +00001443 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001444 if (typ == XML_CATA_NONE) {
1445 if (xmlDebugCatalogs)
1446 xmlGenericError(xmlGenericErrorContext,
1447 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001448 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001449 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001450
1451 cur = catal->children;
1452 /*
1453 * Might be a simple "update in place"
1454 */
1455 if (cur != NULL) {
1456 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001457 if ((orig != NULL) && (cur->type == typ) &&
1458 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001459 if (xmlDebugCatalogs)
1460 xmlGenericError(xmlGenericErrorContext,
1461 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001462 if (cur->value != NULL)
1463 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001464 if (cur->URL != NULL)
1465 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001466 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001467 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001468 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001469 }
1470 if (cur->next == NULL)
1471 break;
1472 cur = cur->next;
1473 }
1474 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001475 if (xmlDebugCatalogs)
1476 xmlGenericError(xmlGenericErrorContext,
1477 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001478 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001479 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1480 NULL, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001481 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001482 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1483 NULL, catal->prefer);
1484 if (doregister) {
1485 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1486 if (cur != NULL)
1487 cur->children = catal->children;
1488 }
1489
Daniel Veillardcda96922001-08-21 10:56:31 +00001490 return(0);
1491}
1492
1493/**
1494 * xmlDelXMLCatalog:
1495 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001496 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001497 *
1498 * Remove entries in the XML catalog where the value or the URI
1499 * is equal to @value
1500 *
1501 * Returns the number of entries removed if successful, -1 otherwise
1502 */
1503static int
1504xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001505 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001506 int ret = 0;
1507
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001508 if ((catal == NULL) ||
1509 ((catal->type != XML_CATA_CATALOG) &&
1510 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001511 return(-1);
1512 if (value == NULL)
1513 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001514 if (catal->children == NULL) {
1515 xmlFetchXMLCatalogFile(catal);
1516 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001517
1518 /*
1519 * Scan the children
1520 */
1521 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001522 while (cur != NULL) {
1523 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1524 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001525 if (xmlDebugCatalogs) {
1526 if (cur->name != NULL)
1527 xmlGenericError(xmlGenericErrorContext,
1528 "Removing element %s from catalog\n", cur->name);
1529 else
1530 xmlGenericError(xmlGenericErrorContext,
1531 "Removing element %s from catalog\n", cur->value);
1532 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001533 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001534 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001535 cur = cur->next;
1536 }
1537 return(ret);
1538}
1539
1540/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001541 * xmlCatalogXMLResolve:
1542 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001543 * @pubID: the public ID string
1544 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001545 *
1546 * Do a complete resolution lookup of an External Identifier for a
1547 * list of catalog entries.
1548 *
1549 * Implements (or tries to) 7.1. External Identifier Resolution
1550 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1551 *
1552 * Returns the URI of the resource or NULL if not found
1553 */
1554static xmlChar *
1555xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1556 const xmlChar *sysID) {
1557 xmlChar *ret = NULL;
1558 xmlCatalogEntryPtr cur;
1559 int haveDelegate = 0;
1560 int haveNext = 0;
1561
1562 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001563 * protection against loops
1564 */
1565 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001566 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1567 "Detected recursion in catalog %s\n",
1568 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001569 return(NULL);
1570 }
1571 catal->depth++;
1572
1573 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001574 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1575 */
1576 if (sysID != NULL) {
1577 xmlCatalogEntryPtr rewrite = NULL;
1578 int lenrewrite = 0, len;
1579 cur = catal;
1580 haveDelegate = 0;
1581 while (cur != NULL) {
1582 switch (cur->type) {
1583 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001584 if (xmlStrEqual(sysID, cur->name)) {
1585 if (xmlDebugCatalogs)
1586 xmlGenericError(xmlGenericErrorContext,
1587 "Found system match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001588 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001589 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001590 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001591 break;
1592 case XML_CATA_REWRITE_SYSTEM:
1593 len = xmlStrlen(cur->name);
1594 if ((len > lenrewrite) &&
1595 (!xmlStrncmp(sysID, cur->name, len))) {
1596 lenrewrite = len;
1597 rewrite = cur;
1598 }
1599 break;
1600 case XML_CATA_DELEGATE_SYSTEM:
1601 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1602 haveDelegate++;
1603 break;
1604 case XML_CATA_NEXT_CATALOG:
1605 haveNext++;
1606 break;
1607 default:
1608 break;
1609 }
1610 cur = cur->next;
1611 }
1612 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001613 if (xmlDebugCatalogs)
1614 xmlGenericError(xmlGenericErrorContext,
1615 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001616 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001617 if (ret != NULL)
1618 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001619 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001620 return(ret);
1621 }
1622 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001623 const xmlChar *delegates[MAX_DELEGATE];
1624 int nbList = 0, i;
1625
Daniel Veillardcda96922001-08-21 10:56:31 +00001626 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001627 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001628 * matches when the list was produced.
1629 */
1630 cur = catal;
1631 while (cur != NULL) {
1632 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1633 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001634 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001635 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001636 break;
1637 if (i < nbList) {
1638 cur = cur->next;
1639 continue;
1640 }
1641 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001642 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001643
Daniel Veillardcda96922001-08-21 10:56:31 +00001644 if (cur->children == NULL) {
1645 xmlFetchXMLCatalogFile(cur);
1646 }
1647 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001648 if (xmlDebugCatalogs)
1649 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001650 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001651 ret = xmlCatalogListXMLResolve(
1652 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001653 if (ret != NULL) {
1654 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001655 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001656 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001657 }
1658 }
1659 cur = cur->next;
1660 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001661 /*
1662 * Apply the cut algorithm explained in 4/
1663 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001664 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001665 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001666 }
1667 }
1668 /*
1669 * Then tries 5/ 6/ if a public ID is provided
1670 */
1671 if (pubID != NULL) {
1672 cur = catal;
1673 haveDelegate = 0;
1674 while (cur != NULL) {
1675 switch (cur->type) {
1676 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001677 if (xmlStrEqual(pubID, cur->name)) {
1678 if (xmlDebugCatalogs)
1679 xmlGenericError(xmlGenericErrorContext,
1680 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001681 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001682 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001683 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001684 break;
1685 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001686 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1687 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001688 haveDelegate++;
1689 break;
1690 case XML_CATA_NEXT_CATALOG:
1691 if (sysID == NULL)
1692 haveNext++;
1693 break;
1694 default:
1695 break;
1696 }
1697 cur = cur->next;
1698 }
1699 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001700 const xmlChar *delegates[MAX_DELEGATE];
1701 int nbList = 0, i;
1702
Daniel Veillardcda96922001-08-21 10:56:31 +00001703 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001704 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001705 * matches when the list was produced.
1706 */
1707 cur = catal;
1708 while (cur != NULL) {
1709 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001710 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1711 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001712
1713 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001714 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001715 break;
1716 if (i < nbList) {
1717 cur = cur->next;
1718 continue;
1719 }
1720 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001721 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001722
Daniel Veillardcda96922001-08-21 10:56:31 +00001723 if (cur->children == NULL) {
1724 xmlFetchXMLCatalogFile(cur);
1725 }
1726 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001727 if (xmlDebugCatalogs)
1728 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001729 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001730 ret = xmlCatalogListXMLResolve(
1731 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001732 if (ret != NULL) {
1733 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001734 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001735 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001736 }
1737 }
1738 cur = cur->next;
1739 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001740 /*
1741 * Apply the cut algorithm explained in 4/
1742 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001743 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001744 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001745 }
1746 }
1747 if (haveNext) {
1748 cur = catal;
1749 while (cur != NULL) {
1750 if (cur->type == XML_CATA_NEXT_CATALOG) {
1751 if (cur->children == NULL) {
1752 xmlFetchXMLCatalogFile(cur);
1753 }
1754 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001755 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001756 if (ret != NULL) {
1757 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001758 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001759 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001760 }
1761 }
1762 cur = cur->next;
1763 }
1764 }
1765
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001766 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001767 return(NULL);
1768}
1769
1770/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001771 * xmlCatalogXMLResolveURI:
1772 * @catal: a catalog list
1773 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001774 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001775 *
1776 * Do a complete resolution lookup of an External Identifier for a
1777 * list of catalog entries.
1778 *
1779 * Implements (or tries to) 7.2.2. URI Resolution
1780 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1781 *
1782 * Returns the URI of the resource or NULL if not found
1783 */
1784static xmlChar *
1785xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1786 xmlChar *ret = NULL;
1787 xmlCatalogEntryPtr cur;
1788 int haveDelegate = 0;
1789 int haveNext = 0;
1790 xmlCatalogEntryPtr rewrite = NULL;
1791 int lenrewrite = 0, len;
1792
1793 if (catal == NULL)
1794 return(NULL);
1795
1796 if (URI == NULL)
1797 return(NULL);
1798
1799 /*
1800 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1801 */
1802 cur = catal;
1803 haveDelegate = 0;
1804 while (cur != NULL) {
1805 switch (cur->type) {
1806 case XML_CATA_URI:
1807 if (xmlStrEqual(URI, cur->name)) {
1808 if (xmlDebugCatalogs)
1809 xmlGenericError(xmlGenericErrorContext,
1810 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001811 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001812 }
1813 break;
1814 case XML_CATA_REWRITE_URI:
1815 len = xmlStrlen(cur->name);
1816 if ((len > lenrewrite) &&
1817 (!xmlStrncmp(URI, cur->name, len))) {
1818 lenrewrite = len;
1819 rewrite = cur;
1820 }
1821 break;
1822 case XML_CATA_DELEGATE_URI:
1823 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1824 haveDelegate++;
1825 break;
1826 case XML_CATA_NEXT_CATALOG:
1827 haveNext++;
1828 break;
1829 default:
1830 break;
1831 }
1832 cur = cur->next;
1833 }
1834 if (rewrite != NULL) {
1835 if (xmlDebugCatalogs)
1836 xmlGenericError(xmlGenericErrorContext,
1837 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001838 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001839 if (ret != NULL)
1840 ret = xmlStrcat(ret, &URI[lenrewrite]);
1841 return(ret);
1842 }
1843 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001844 const xmlChar *delegates[MAX_DELEGATE];
1845 int nbList = 0, i;
1846
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001847 /*
1848 * Assume the entries have been sorted by decreasing substring
1849 * matches when the list was produced.
1850 */
1851 cur = catal;
1852 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001853 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1854 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001855 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001856 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001857 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001858 break;
1859 if (i < nbList) {
1860 cur = cur->next;
1861 continue;
1862 }
1863 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001864 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001865
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001866 if (cur->children == NULL) {
1867 xmlFetchXMLCatalogFile(cur);
1868 }
1869 if (cur->children != NULL) {
1870 if (xmlDebugCatalogs)
1871 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001872 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001873 ret = xmlCatalogListXMLResolveURI(
1874 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001875 if (ret != NULL)
1876 return(ret);
1877 }
1878 }
1879 cur = cur->next;
1880 }
1881 /*
1882 * Apply the cut algorithm explained in 4/
1883 */
1884 return(XML_CATAL_BREAK);
1885 }
1886 if (haveNext) {
1887 cur = catal;
1888 while (cur != NULL) {
1889 if (cur->type == XML_CATA_NEXT_CATALOG) {
1890 if (cur->children == NULL) {
1891 xmlFetchXMLCatalogFile(cur);
1892 }
1893 if (cur->children != NULL) {
1894 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1895 if (ret != NULL)
1896 return(ret);
1897 }
1898 }
1899 cur = cur->next;
1900 }
1901 }
1902
1903 return(NULL);
1904}
1905
1906/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001907 * xmlCatalogListXMLResolve:
1908 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001909 * @pubID: the public ID string
1910 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001911 *
1912 * Do a complete resolution lookup of an External Identifier for a
1913 * list of catalogs
1914 *
1915 * Implements (or tries to) 7.1. External Identifier Resolution
1916 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1917 *
1918 * Returns the URI of the resource or NULL if not found
1919 */
1920static xmlChar *
1921xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1922 const xmlChar *sysID) {
1923 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001924 xmlChar *urnID = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +00001925 xmlChar *normid;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001926
1927 if (catal == NULL)
1928 return(NULL);
1929 if ((pubID == NULL) && (sysID == NULL))
1930 return(NULL);
1931
Daniel Veillardc8155052004-07-16 09:03:08 +00001932 normid = xmlCatalogNormalizePublic(pubID);
1933 if (normid != NULL)
1934 pubID = (*normid != 0 ? normid : NULL);
1935
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001936 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1937 urnID = xmlCatalogUnWrapURN(pubID);
1938 if (xmlDebugCatalogs) {
1939 if (urnID == NULL)
1940 xmlGenericError(xmlGenericErrorContext,
1941 "Public URN ID %s expanded to NULL\n", pubID);
1942 else
1943 xmlGenericError(xmlGenericErrorContext,
1944 "Public URN ID expanded to %s\n", urnID);
1945 }
1946 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1947 if (urnID != NULL)
1948 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00001949 if (normid != NULL)
1950 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001951 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001952 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001953 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1954 urnID = xmlCatalogUnWrapURN(sysID);
1955 if (xmlDebugCatalogs) {
1956 if (urnID == NULL)
1957 xmlGenericError(xmlGenericErrorContext,
1958 "System URN ID %s expanded to NULL\n", sysID);
1959 else
1960 xmlGenericError(xmlGenericErrorContext,
1961 "System URN ID expanded to %s\n", urnID);
1962 }
1963 if (pubID == NULL)
1964 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1965 else if (xmlStrEqual(pubID, urnID))
1966 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1967 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00001968 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001969 }
1970 if (urnID != NULL)
1971 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00001972 if (normid != NULL)
1973 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001974 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001975 }
1976 while (catal != NULL) {
1977 if (catal->type == XML_CATA_CATALOG) {
1978 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001979 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001980 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001981 if (catal->children != NULL) {
1982 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
Daniel Veillardc8155052004-07-16 09:03:08 +00001983 if (ret != NULL) {
1984 if (normid != NULL)
1985 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001986 return(ret);
Daniel Veillardc8155052004-07-16 09:03:08 +00001987 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001988 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001989 }
1990 catal = catal->next;
1991 }
Daniel Veillardc8155052004-07-16 09:03:08 +00001992 if (normid != NULL)
1993 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00001994 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001995}
1996
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001997/**
1998 * xmlCatalogListXMLResolveURI:
1999 * @catal: a catalog list
2000 * @URI: the URI
2001 *
2002 * Do a complete resolution lookup of an URI for a list of catalogs
2003 *
2004 * Implements (or tries to) 7.2. URI Resolution
2005 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2006 *
2007 * Returns the URI of the resource or NULL if not found
2008 */
2009static xmlChar *
2010xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2011 xmlChar *ret = NULL;
2012 xmlChar *urnID = NULL;
2013
2014 if (catal == NULL)
2015 return(NULL);
2016 if (URI == NULL)
2017 return(NULL);
2018
2019 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2020 urnID = xmlCatalogUnWrapURN(URI);
2021 if (xmlDebugCatalogs) {
2022 if (urnID == NULL)
2023 xmlGenericError(xmlGenericErrorContext,
2024 "URN ID %s expanded to NULL\n", URI);
2025 else
2026 xmlGenericError(xmlGenericErrorContext,
2027 "URN ID expanded to %s\n", urnID);
2028 }
2029 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2030 if (urnID != NULL)
2031 xmlFree(urnID);
2032 return(ret);
2033 }
2034 while (catal != NULL) {
2035 if (catal->type == XML_CATA_CATALOG) {
2036 if (catal->children == NULL) {
2037 xmlFetchXMLCatalogFile(catal);
2038 }
2039 if (catal->children != NULL) {
2040 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2041 if (ret != NULL)
2042 return(ret);
2043 }
2044 }
2045 catal = catal->next;
2046 }
2047 return(ret);
2048}
2049
Daniel Veillard344cee72001-08-20 00:08:40 +00002050/************************************************************************
2051 * *
2052 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00002053 * *
2054 ************************************************************************/
2055
2056
2057#define RAW *cur
2058#define NEXT cur++;
2059#define SKIP(x) cur += x;
2060
William M. Brack272693c2003-11-14 16:20:34 +00002061#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002062
Daniel Veillard75b96822001-10-11 18:59:45 +00002063/**
2064 * xmlParseSGMLCatalogComment:
2065 * @cur: the current character
2066 *
2067 * Skip a comment in an SGML catalog
2068 *
2069 * Returns new current character
2070 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002071static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002072xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002073 if ((cur[0] != '-') || (cur[1] != '-'))
2074 return(cur);
2075 SKIP(2);
2076 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2077 NEXT;
2078 if (cur[0] == 0) {
2079 return(NULL);
2080 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002081 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002082}
2083
Daniel Veillard75b96822001-10-11 18:59:45 +00002084/**
2085 * xmlParseSGMLCatalogPubid:
2086 * @cur: the current character
2087 * @id: the return location
2088 *
2089 * Parse an SGML catalog ID
2090 *
2091 * Returns new current character and store the value in @id
2092 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002093static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002094xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002095 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002096 int len = 0;
2097 int size = 50;
2098 xmlChar stop;
2099 int count = 0;
2100
2101 *id = NULL;
2102
2103 if (RAW == '"') {
2104 NEXT;
2105 stop = '"';
2106 } else if (RAW == '\'') {
2107 NEXT;
2108 stop = '\'';
2109 } else {
2110 stop = ' ';
2111 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002112 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002113 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002114 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002115 return(NULL);
2116 }
William M. Brack76e95df2003-10-18 16:20:14 +00002117 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002118 if ((*cur == stop) && (stop != ' '))
2119 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002120 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002121 break;
2122 if (len + 1 >= size) {
2123 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002124 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2125 if (tmp == NULL) {
2126 xmlCatalogErrMemory("allocating public ID");
2127 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002128 return(NULL);
2129 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002130 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002131 }
2132 buf[len++] = *cur;
2133 count++;
2134 NEXT;
2135 }
2136 buf[len] = 0;
2137 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002138 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002139 xmlFree(buf);
2140 return(NULL);
2141 }
2142 } else {
2143 if (*cur != stop) {
2144 xmlFree(buf);
2145 return(NULL);
2146 }
2147 NEXT;
2148 }
2149 *id = buf;
2150 return(cur);
2151}
2152
Daniel Veillard75b96822001-10-11 18:59:45 +00002153/**
2154 * xmlParseSGMLCatalogName:
2155 * @cur: the current character
2156 * @name: the return location
2157 *
2158 * Parse an SGML catalog name
2159 *
2160 * Returns new current character and store the value in @name
2161 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002162static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002163xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002164 xmlChar buf[XML_MAX_NAMELEN + 5];
2165 int len = 0;
2166 int c;
2167
2168 *name = NULL;
2169
2170 /*
2171 * Handler for more complex cases
2172 */
2173 c = *cur;
2174 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2175 return(NULL);
2176 }
2177
2178 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2179 (c == '.') || (c == '-') ||
2180 (c == '_') || (c == ':'))) {
2181 buf[len++] = c;
2182 cur++;
2183 c = *cur;
2184 if (len >= XML_MAX_NAMELEN)
2185 return(NULL);
2186 }
2187 *name = xmlStrndup(buf, len);
2188 return(cur);
2189}
2190
Daniel Veillard75b96822001-10-11 18:59:45 +00002191/**
2192 * xmlGetSGMLCatalogEntryType:
2193 * @name: the entry name
2194 *
2195 * Get the Catalog entry type for a given SGML Catalog name
2196 *
2197 * Returns Catalog entry type
2198 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002199static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002200xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002201 xmlCatalogEntryType type = XML_CATA_NONE;
2202 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2203 type = SGML_CATA_SYSTEM;
2204 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2205 type = SGML_CATA_PUBLIC;
2206 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2207 type = SGML_CATA_DELEGATE;
2208 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2209 type = SGML_CATA_ENTITY;
2210 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2211 type = SGML_CATA_DOCTYPE;
2212 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2213 type = SGML_CATA_LINKTYPE;
2214 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2215 type = SGML_CATA_NOTATION;
2216 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2217 type = SGML_CATA_SGMLDECL;
2218 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2219 type = SGML_CATA_DOCUMENT;
2220 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2221 type = SGML_CATA_CATALOG;
2222 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2223 type = SGML_CATA_BASE;
Daniel Veillard344cee72001-08-20 00:08:40 +00002224 return(type);
2225}
2226
Daniel Veillard75b96822001-10-11 18:59:45 +00002227/**
2228 * xmlParseSGMLCatalog:
2229 * @catal: the SGML Catalog
2230 * @value: the content of the SGML Catalog serialization
2231 * @file: the filepath for the catalog
2232 * @super: should this be handled as a Super Catalog in which case
2233 * parsing is not recursive
2234 *
2235 * Parse an SGML catalog content and fill up the @catal hash table with
2236 * the new entries found.
2237 *
2238 * Returns 0 in case of success, -1 in case of error.
2239 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002240static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002241xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2242 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002243 const xmlChar *cur = value;
2244 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002245 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002246
2247 if ((cur == NULL) || (file == NULL))
2248 return(-1);
2249 base = xmlStrdup((const xmlChar *) file);
2250
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002251 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002252 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002253 if (cur[0] == 0)
2254 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002255 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002256 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002257 if (cur == NULL) {
2258 /* error */
2259 break;
2260 }
2261 } else {
2262 xmlChar *sysid = NULL;
2263 xmlChar *name = NULL;
2264 xmlCatalogEntryType type = XML_CATA_NONE;
2265
Daniel Veillardcda96922001-08-21 10:56:31 +00002266 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002267 if (name == NULL) {
2268 /* error */
2269 break;
2270 }
William M. Brack76e95df2003-10-18 16:20:14 +00002271 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002272 /* error */
2273 break;
2274 }
2275 SKIP_BLANKS;
2276 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002277 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002278 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002279 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002280 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002281 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002282 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002283 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002284 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002285 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002286 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002287 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002288 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002289 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002290 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002291 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002292 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002293 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002294 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002295 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002296 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002297 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002298 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2299 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002300 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002301 if (name == NULL) {
2302 /* error */
2303 break;
2304 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002305 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002306 continue;
2307 }
2308 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002309 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002310
2311 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002312 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002313 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002314 type = SGML_CATA_PENTITY;
2315 case SGML_CATA_PENTITY:
2316 case SGML_CATA_DOCTYPE:
2317 case SGML_CATA_LINKTYPE:
2318 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002319 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002320 if (cur == NULL) {
2321 /* error */
2322 break;
2323 }
William M. Brack76e95df2003-10-18 16:20:14 +00002324 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002325 /* error */
2326 break;
2327 }
2328 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002329 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002330 if (cur == NULL) {
2331 /* error */
2332 break;
2333 }
2334 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002335 case SGML_CATA_PUBLIC:
2336 case SGML_CATA_SYSTEM:
2337 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002338 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002339 if (cur == NULL) {
2340 /* error */
2341 break;
2342 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002343 if (type != SGML_CATA_SYSTEM) {
2344 xmlChar *normid;
2345
2346 normid = xmlCatalogNormalizePublic(name);
2347 if (normid != NULL) {
2348 if (name != NULL)
2349 xmlFree(name);
2350 if (*normid != 0)
2351 name = normid;
2352 else {
2353 xmlFree(normid);
2354 name = NULL;
2355 }
2356 }
2357 }
William M. Brack76e95df2003-10-18 16:20:14 +00002358 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002359 /* error */
2360 break;
2361 }
2362 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002363 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002364 if (cur == NULL) {
2365 /* error */
2366 break;
2367 }
2368 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002369 case SGML_CATA_BASE:
2370 case SGML_CATA_CATALOG:
2371 case SGML_CATA_DOCUMENT:
2372 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002373 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002374 if (cur == NULL) {
2375 /* error */
2376 break;
2377 }
2378 break;
2379 default:
2380 break;
2381 }
2382 if (cur == NULL) {
2383 if (name != NULL)
2384 xmlFree(name);
2385 if (sysid != NULL)
2386 xmlFree(sysid);
2387 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002388 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002389 if (base != NULL)
2390 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002391 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002392 } else if ((type == SGML_CATA_PUBLIC) ||
2393 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002394 xmlChar *filename;
2395
2396 filename = xmlBuildURI(sysid, base);
2397 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002398 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002399
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002400 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002401 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002402 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002403 if (res < 0) {
2404 xmlFreeCatalogEntry(entry);
2405 }
2406 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002407 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002408
Daniel Veillard344cee72001-08-20 00:08:40 +00002409 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002410 if (super) {
2411 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002412
Daniel Veillardc853b322001-11-06 15:24:37 +00002413 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002414 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002415 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002416 if (res < 0) {
2417 xmlFreeCatalogEntry(entry);
2418 }
2419 } else {
2420 xmlChar *filename;
2421
2422 filename = xmlBuildURI(sysid, base);
2423 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002424 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002425 xmlFree(filename);
2426 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002427 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002428 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002429 /*
2430 * drop anything else we won't handle it
2431 */
2432 if (name != NULL)
2433 xmlFree(name);
2434 if (sysid != NULL)
2435 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002436 }
2437 }
2438 if (base != NULL)
2439 xmlFree(base);
2440 if (cur == NULL)
2441 return(-1);
2442 return(0);
2443}
2444
Daniel Veillard75b96822001-10-11 18:59:45 +00002445/************************************************************************
2446 * *
2447 * SGML Catalog handling *
2448 * *
2449 ************************************************************************/
2450
Daniel Veillardcda96922001-08-21 10:56:31 +00002451/**
2452 * xmlCatalogGetSGMLPublic:
2453 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002454 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002455 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002456 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002457 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002458 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002459 */
2460static const xmlChar *
2461xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2462 xmlCatalogEntryPtr entry;
Daniel Veillardc8155052004-07-16 09:03:08 +00002463 xmlChar *normid;
Daniel Veillardcda96922001-08-21 10:56:31 +00002464
2465 if (catal == NULL)
2466 return(NULL);
2467
Daniel Veillardc8155052004-07-16 09:03:08 +00002468 normid = xmlCatalogNormalizePublic(pubID);
2469 if (normid != NULL)
2470 pubID = (*normid != 0 ? normid : NULL);
2471
Daniel Veillardcda96922001-08-21 10:56:31 +00002472 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002473 if (entry == NULL) {
2474 if (normid != NULL)
2475 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002476 return(NULL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002477 }
2478 if (entry->type == SGML_CATA_PUBLIC) {
2479 if (normid != NULL)
2480 xmlFree(normid);
Daniel Veillardc853b322001-11-06 15:24:37 +00002481 return(entry->URL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002482 }
2483 if (normid != NULL)
2484 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002485 return(NULL);
2486}
2487
2488/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002489 * xmlCatalogGetSGMLSystem:
2490 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002491 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002492 *
2493 * Try to lookup the catalog local reference for a system ID
2494 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002495 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002496 */
2497static const xmlChar *
2498xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2499 xmlCatalogEntryPtr entry;
2500
2501 if (catal == NULL)
2502 return(NULL);
2503
2504 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2505 if (entry == NULL)
2506 return(NULL);
2507 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002508 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002509 return(NULL);
2510}
2511
2512/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002513 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002514 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002515 * @pubID: the public ID string
2516 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002517 *
2518 * Do a complete resolution lookup of an External Identifier
2519 *
2520 * Returns the URI of the resource or NULL if not found
2521 */
2522static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002523xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2524 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002525 const xmlChar *ret = NULL;
2526
Daniel Veillard75b96822001-10-11 18:59:45 +00002527 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002528 return(NULL);
2529
2530 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002531 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002532 if (ret != NULL)
2533 return(ret);
2534 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002535 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002536 return(NULL);
2537}
2538
Daniel Veillarda7374592001-05-10 14:17:55 +00002539/************************************************************************
2540 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002541 * Specific Public interfaces *
2542 * *
2543 ************************************************************************/
2544
2545/**
2546 * xmlLoadSGMLSuperCatalog:
2547 * @filename: a file path
2548 *
2549 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2550 * references. This is only needed for manipulating SGML Super Catalogs
2551 * like adding and removing CATALOG or DELEGATE entries.
2552 *
2553 * Returns the catalog parsed or NULL in case of error
2554 */
2555xmlCatalogPtr
2556xmlLoadSGMLSuperCatalog(const char *filename)
2557{
2558 xmlChar *content;
2559 xmlCatalogPtr catal;
2560 int ret;
2561
2562 content = xmlLoadFileContent(filename);
2563 if (content == NULL)
2564 return(NULL);
2565
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002566 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002567 if (catal == NULL) {
2568 xmlFree(content);
2569 return(NULL);
2570 }
2571
2572 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2573 xmlFree(content);
2574 if (ret < 0) {
2575 xmlFreeCatalog(catal);
2576 return(NULL);
2577 }
2578 return (catal);
2579}
2580
2581/**
2582 * xmlLoadACatalog:
2583 * @filename: a file path
2584 *
2585 * Load the catalog and build the associated data structures.
2586 * This can be either an XML Catalog or an SGML Catalog
2587 * It will recurse in SGML CATALOG entries. On the other hand XML
2588 * Catalogs are not handled recursively.
2589 *
2590 * Returns the catalog parsed or NULL in case of error
2591 */
2592xmlCatalogPtr
2593xmlLoadACatalog(const char *filename)
2594{
2595 xmlChar *content;
2596 xmlChar *first;
2597 xmlCatalogPtr catal;
2598 int ret;
2599
2600 content = xmlLoadFileContent(filename);
2601 if (content == NULL)
2602 return(NULL);
2603
2604
2605 first = content;
2606
2607 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2608 (!(((*first >= 'A') && (*first <= 'Z')) ||
2609 ((*first >= 'a') && (*first <= 'z')))))
2610 first++;
2611
2612 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002613 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002614 if (catal == NULL) {
2615 xmlFree(content);
2616 return(NULL);
2617 }
2618 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2619 if (ret < 0) {
2620 xmlFreeCatalog(catal);
2621 xmlFree(content);
2622 return(NULL);
2623 }
2624 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002625 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002626 if (catal == NULL) {
2627 xmlFree(content);
2628 return(NULL);
2629 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002630 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002631 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002632 }
2633 xmlFree(content);
2634 return (catal);
2635}
2636
2637/**
2638 * xmlExpandCatalog:
2639 * @catal: a catalog
2640 * @filename: a file path
2641 *
2642 * Load the catalog and expand the existing catal structure.
2643 * This can be either an XML Catalog or an SGML Catalog
2644 *
2645 * Returns 0 in case of success, -1 in case of error
2646 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002647static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002648xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2649{
Daniel Veillard75b96822001-10-11 18:59:45 +00002650 int ret;
2651
2652 if ((catal == NULL) || (filename == NULL))
2653 return(-1);
2654
Daniel Veillard75b96822001-10-11 18:59:45 +00002655
2656 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002657 xmlChar *content;
2658
2659 content = xmlLoadFileContent(filename);
2660 if (content == NULL)
2661 return(-1);
2662
Daniel Veillard75b96822001-10-11 18:59:45 +00002663 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2664 if (ret < 0) {
2665 xmlFree(content);
2666 return(-1);
2667 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002668 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002669 } else {
2670 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002671 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002672 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002673
Daniel Veillard75b96822001-10-11 18:59:45 +00002674 cur = catal->xml;
2675 if (cur == NULL) {
2676 catal->xml = tmp;
2677 } else {
2678 while (cur->next != NULL) cur = cur->next;
2679 cur->next = tmp;
2680 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002681 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002682 return (0);
2683}
2684
2685/**
2686 * xmlACatalogResolveSystem:
2687 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002688 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002689 *
2690 * Try to lookup the catalog resource for a system ID
2691 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002692 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002693 * must be freed by the caller.
2694 */
2695xmlChar *
2696xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2697 xmlChar *ret = NULL;
2698
2699 if ((sysID == NULL) || (catal == NULL))
2700 return(NULL);
2701
2702 if (xmlDebugCatalogs)
2703 xmlGenericError(xmlGenericErrorContext,
2704 "Resolve sysID %s\n", sysID);
2705
2706 if (catal->type == XML_XML_CATALOG_TYPE) {
2707 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2708 if (ret == XML_CATAL_BREAK)
2709 ret = NULL;
2710 } else {
2711 const xmlChar *sgml;
2712
2713 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2714 if (sgml != NULL)
2715 ret = xmlStrdup(sgml);
2716 }
2717 return(ret);
2718}
2719
2720/**
2721 * xmlACatalogResolvePublic:
2722 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002723 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002724 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002725 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002726 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002727 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002728 * must be freed by the caller.
2729 */
2730xmlChar *
2731xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2732 xmlChar *ret = NULL;
2733
2734 if ((pubID == NULL) || (catal == NULL))
2735 return(NULL);
2736
2737 if (xmlDebugCatalogs)
2738 xmlGenericError(xmlGenericErrorContext,
2739 "Resolve pubID %s\n", pubID);
2740
2741 if (catal->type == XML_XML_CATALOG_TYPE) {
2742 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2743 if (ret == XML_CATAL_BREAK)
2744 ret = NULL;
2745 } else {
2746 const xmlChar *sgml;
2747
2748 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2749 if (sgml != NULL)
2750 ret = xmlStrdup(sgml);
2751 }
2752 return(ret);
2753}
2754
2755/**
2756 * xmlACatalogResolve:
2757 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002758 * @pubID: the public ID string
2759 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002760 *
2761 * Do a complete resolution lookup of an External Identifier
2762 *
2763 * Returns the URI of the resource or NULL if not found, it must be freed
2764 * by the caller.
2765 */
2766xmlChar *
2767xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2768 const xmlChar * sysID)
2769{
2770 xmlChar *ret = NULL;
2771
2772 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2773 return (NULL);
2774
2775 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002776 if ((pubID != NULL) && (sysID != NULL)) {
2777 xmlGenericError(xmlGenericErrorContext,
2778 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2779 } else if (pubID != NULL) {
2780 xmlGenericError(xmlGenericErrorContext,
2781 "Resolve: pubID %s\n", pubID);
2782 } else {
2783 xmlGenericError(xmlGenericErrorContext,
2784 "Resolve: sysID %s\n", sysID);
2785 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002786 }
2787
2788 if (catal->type == XML_XML_CATALOG_TYPE) {
2789 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2790 if (ret == XML_CATAL_BREAK)
2791 ret = NULL;
2792 } else {
2793 const xmlChar *sgml;
2794
2795 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2796 if (sgml != NULL)
2797 ret = xmlStrdup(sgml);
2798 }
2799 return (ret);
2800}
2801
2802/**
2803 * xmlACatalogResolveURI:
2804 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002805 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002806 *
2807 * Do a complete resolution lookup of an URI
2808 *
2809 * Returns the URI of the resource or NULL if not found, it must be freed
2810 * by the caller.
2811 */
2812xmlChar *
2813xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2814 xmlChar *ret = NULL;
2815
2816 if ((URI == NULL) || (catal == NULL))
2817 return(NULL);
2818
Daniel Veillardb44025c2001-10-11 22:55:55 +00002819 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002820 xmlGenericError(xmlGenericErrorContext,
2821 "Resolve URI %s\n", URI);
2822
2823 if (catal->type == XML_XML_CATALOG_TYPE) {
2824 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2825 if (ret == XML_CATAL_BREAK)
2826 ret = NULL;
2827 } else {
2828 const xmlChar *sgml;
2829
2830 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2831 if (sgml != NULL)
2832 sgml = xmlStrdup(sgml);
2833 }
2834 return(ret);
2835}
2836
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002837#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002838/**
2839 * xmlACatalogDump:
2840 * @catal: a Catalog
2841 * @out: the file.
2842 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002843 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002844 */
2845void
2846xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002847 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002848 return;
2849
2850 if (catal->type == XML_XML_CATALOG_TYPE) {
2851 xmlDumpXMLCatalog(out, catal->xml);
2852 } else {
2853 xmlHashScan(catal->sgml,
2854 (xmlHashScanner) xmlCatalogDumpEntry, out);
2855 }
2856}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002857#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002858
2859/**
2860 * xmlACatalogAdd:
2861 * @catal: a Catalog
2862 * @type: the type of record to add to the catalog
2863 * @orig: the system, public or prefix to match
2864 * @replace: the replacement value for the match
2865 *
2866 * Add an entry in the catalog, it may overwrite existing but
2867 * different entries.
2868 *
2869 * Returns 0 if successful, -1 otherwise
2870 */
2871int
2872xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2873 const xmlChar * orig, const xmlChar * replace)
2874{
2875 int res = -1;
2876
2877 if (catal == NULL)
2878 return(-1);
2879
2880 if (catal->type == XML_XML_CATALOG_TYPE) {
2881 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2882 } else {
2883 xmlCatalogEntryType cattype;
2884
2885 cattype = xmlGetSGMLCatalogEntryType(type);
2886 if (cattype != XML_CATA_NONE) {
2887 xmlCatalogEntryPtr entry;
2888
Daniel Veillardc853b322001-11-06 15:24:37 +00002889 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002890 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002891 if (catal->sgml == NULL)
2892 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002893 res = xmlHashAddEntry(catal->sgml, orig, entry);
2894 }
2895 }
2896 return (res);
2897}
2898
2899/**
2900 * xmlACatalogRemove:
2901 * @catal: a Catalog
2902 * @value: the value to remove
2903 *
2904 * Remove an entry from the catalog
2905 *
2906 * Returns the number of entries removed if successful, -1 otherwise
2907 */
2908int
2909xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2910 int res = -1;
2911
2912 if ((catal == NULL) || (value == NULL))
2913 return(-1);
2914
2915 if (catal->type == XML_XML_CATALOG_TYPE) {
2916 res = xmlDelXMLCatalog(catal->xml, value);
2917 } else {
2918 res = xmlHashRemoveEntry(catal->sgml, value,
2919 (xmlHashDeallocator) xmlFreeCatalogEntry);
2920 if (res == 0)
2921 res = 1;
2922 }
2923 return(res);
2924}
2925
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002926/**
2927 * xmlNewCatalog:
2928 * @sgml: should this create an SGML catalog
2929 *
2930 * create a new Catalog.
2931 *
2932 * Returns the xmlCatalogPtr or NULL in case of error
2933 */
2934xmlCatalogPtr
2935xmlNewCatalog(int sgml) {
2936 xmlCatalogPtr catal = NULL;
2937
2938 if (sgml) {
2939 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2940 xmlCatalogDefaultPrefer);
2941 if ((catal != NULL) && (catal->sgml == NULL))
2942 catal->sgml = xmlHashCreate(10);
2943 } else
2944 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2945 xmlCatalogDefaultPrefer);
2946 return(catal);
2947}
2948
2949/**
2950 * xmlCatalogIsEmpty:
2951 * @catal: should this create an SGML catalog
2952 *
2953 * Check is a catalog is empty
2954 *
2955 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2956 */
2957int
2958xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2959 if (catal == NULL)
2960 return(-1);
2961
2962 if (catal->type == XML_XML_CATALOG_TYPE) {
2963 if (catal->xml == NULL)
2964 return(1);
2965 if ((catal->xml->type != XML_CATA_CATALOG) &&
2966 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2967 return(-1);
2968 if (catal->xml->children == NULL)
2969 return(1);
2970 return(0);
2971 } else {
2972 int res;
2973
2974 if (catal->sgml == NULL)
2975 return(1);
2976 res = xmlHashSize(catal->sgml);
2977 if (res == 0)
2978 return(1);
2979 if (res < 0)
2980 return(-1);
2981 }
2982 return(0);
2983}
2984
Daniel Veillard75b96822001-10-11 18:59:45 +00002985/************************************************************************
2986 * *
2987 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002988 * *
2989 ************************************************************************/
2990
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002991/**
Daniel Veillard81463942001-10-16 12:34:39 +00002992 * xmlInitializeCatalogData:
2993 *
2994 * Do the catalog initialization only of global data, doesn't try to load
2995 * any catalog actually.
2996 * this function is not thread safe, catalog initialization should
2997 * preferably be done once at startup
2998 */
2999static void
3000xmlInitializeCatalogData(void) {
3001 if (xmlCatalogInitialized != 0)
3002 return;
3003
3004 if (getenv("XML_DEBUG_CATALOG"))
3005 xmlDebugCatalogs = 1;
3006 xmlCatalogMutex = xmlNewRMutex();
3007
3008 xmlCatalogInitialized = 1;
3009}
3010/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003011 * xmlInitializeCatalog:
3012 *
3013 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00003014 * this function is not thread safe, catalog initialization should
3015 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003016 */
3017void
3018xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003019 if (xmlCatalogInitialized != 0)
3020 return;
3021
Daniel Veillard81463942001-10-16 12:34:39 +00003022 xmlInitializeCatalogData();
3023 xmlRMutexLock(xmlCatalogMutex);
3024
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003025 if (getenv("XML_DEBUG_CATALOG"))
3026 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00003027
Daniel Veillard75b96822001-10-11 18:59:45 +00003028 if (xmlDefaultCatalog == NULL) {
3029 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003030 char *path;
3031 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00003032 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003033 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00003034
Daniel Veillardb44025c2001-10-11 22:55:55 +00003035 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003036 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003037#if defined(_WIN32) && defined(_MSC_VER)
3038 {
3039 void* hmodule;
3040 hmodule = GetModuleHandleA("libxml2.dll");
3041 if (hmodule == NULL)
3042 hmodule = GetModuleHandleA(NULL);
3043 if (hmodule != NULL) {
3044 char buf[256];
3045 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3046 if (len != 0) {
3047 char* p = &(buf[len]);
3048 while (*p != '\\' && p > buf)
3049 p--;
3050 if (p != buf) {
3051 xmlChar* uri;
3052 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3053 uri = xmlCanonicPath(buf);
3054 if (uri != NULL) {
3055 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3056 xmlFree(uri);
3057 }
3058 }
3059 }
3060 }
3061 catalogs = XML_XML_DEFAULT_CATALOG;
3062 }
3063#else
Daniel Veillard75b96822001-10-11 18:59:45 +00003064 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00003065#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00003066
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003067 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3068 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003069 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003070 /* the XML_CATALOG_FILES envvar is allowed to contain a
3071 space-separated list of entries. */
3072 cur = catalogs;
3073 nextent = &catal->xml;
3074 while (*cur != '\0') {
William M. Brack68aca052003-10-11 15:22:13 +00003075 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003076 cur++;
3077 if (*cur != 0) {
3078 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003079 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003080 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00003081 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003082 if (path != NULL) {
3083 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3084 NULL, BAD_CAST path, xmlCatalogDefaultPrefer);
3085 if (*nextent != NULL)
3086 nextent = &((*nextent)->next);
3087 xmlFree(path);
3088 }
3089 }
3090 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003091 xmlDefaultCatalog = catal;
3092 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003093 }
3094
Daniel Veillard81463942001-10-16 12:34:39 +00003095 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003096}
3097
Daniel Veillard82d75332001-10-08 15:01:59 +00003098
3099/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003100 * xmlLoadCatalog:
3101 * @filename: a file path
3102 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003103 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003104 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003105 * this function is not thread safe, catalog initialization should
3106 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003107 *
3108 * Returns 0 in case of success -1 in case of error
3109 */
3110int
Daniel Veillard16756b62001-10-01 07:36:25 +00003111xmlLoadCatalog(const char *filename)
3112{
Daniel Veillard75b96822001-10-11 18:59:45 +00003113 int ret;
3114 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003115
Daniel Veillard81463942001-10-16 12:34:39 +00003116 if (!xmlCatalogInitialized)
3117 xmlInitializeCatalogData();
3118
3119 xmlRMutexLock(xmlCatalogMutex);
3120
Daniel Veillard75b96822001-10-11 18:59:45 +00003121 if (xmlDefaultCatalog == NULL) {
3122 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003123 if (catal == NULL) {
3124 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003125 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003126 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003127
Daniel Veillard75b96822001-10-11 18:59:45 +00003128 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003129 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003130 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003131 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003132
Daniel Veillard75b96822001-10-11 18:59:45 +00003133 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003134 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003135 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003136}
3137
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003138/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003139 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003140 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003141 *
3142 * Load the catalogs and makes their definitions effective for the default
3143 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003144 * this function is not thread safe, catalog initialization should
3145 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003146 */
3147void
3148xmlLoadCatalogs(const char *pathss) {
3149 const char *cur;
3150 const char *paths;
3151 xmlChar *path;
3152
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003153 if (pathss == NULL)
3154 return;
3155
Daniel Veillard81418e32001-05-22 15:08:55 +00003156 cur = pathss;
3157 while ((cur != NULL) && (*cur != 0)) {
William M. Brack68aca052003-10-11 15:22:13 +00003158 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003159 if (*cur != 0) {
3160 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003161 while ((*cur != 0) && (*cur != ':') && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003162 cur++;
3163 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3164 if (path != NULL) {
3165 xmlLoadCatalog((const char *) path);
3166 xmlFree(path);
3167 }
3168 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003169 while (*cur == ':')
3170 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003171 }
3172}
3173
Daniel Veillarda7374592001-05-10 14:17:55 +00003174/**
3175 * xmlCatalogCleanup:
3176 *
3177 * Free up all the memory associated with catalogs
3178 */
3179void
3180xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003181 if (xmlCatalogInitialized == 0)
3182 return;
3183
Daniel Veillard81463942001-10-16 12:34:39 +00003184 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003185 if (xmlDebugCatalogs)
3186 xmlGenericError(xmlGenericErrorContext,
3187 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003188 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003189 xmlHashFree(xmlCatalogXMLFiles,
3190 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003191 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003192 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003193 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003194 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003195 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003196 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003197 xmlRMutexUnlock(xmlCatalogMutex);
3198 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003199}
3200
3201/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003202 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003203 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003204 *
3205 * Try to lookup the catalog resource for a system ID
3206 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003207 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003208 * must be freed by the caller.
3209 */
3210xmlChar *
3211xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003212 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003213
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003214 if (!xmlCatalogInitialized)
3215 xmlInitializeCatalog();
3216
Daniel Veillard75b96822001-10-11 18:59:45 +00003217 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3218 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003219}
3220
3221/**
3222 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003223 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003224 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003225 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003226 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003227 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003228 * must be freed by the caller.
3229 */
3230xmlChar *
3231xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003232 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003233
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003234 if (!xmlCatalogInitialized)
3235 xmlInitializeCatalog();
3236
Daniel Veillard75b96822001-10-11 18:59:45 +00003237 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3238 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003239}
Daniel Veillard344cee72001-08-20 00:08:40 +00003240
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003241/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003242 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003243 * @pubID: the public ID string
3244 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003245 *
3246 * Do a complete resolution lookup of an External Identifier
3247 *
3248 * Returns the URI of the resource or NULL if not found, it must be freed
3249 * by the caller.
3250 */
3251xmlChar *
3252xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003253 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003254
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003255 if (!xmlCatalogInitialized)
3256 xmlInitializeCatalog();
3257
Daniel Veillard75b96822001-10-11 18:59:45 +00003258 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3259 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003260}
3261
3262/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003263 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003264 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003265 *
3266 * Do a complete resolution lookup of an URI
3267 *
3268 * Returns the URI of the resource or NULL if not found, it must be freed
3269 * by the caller.
3270 */
3271xmlChar *
3272xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003273 xmlChar *ret;
3274
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003275 if (!xmlCatalogInitialized)
3276 xmlInitializeCatalog();
3277
Daniel Veillard75b96822001-10-11 18:59:45 +00003278 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3279 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003280}
3281
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003282#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003283/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003284 * xmlCatalogDump:
3285 * @out: the file.
3286 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003287 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003288 */
3289void
3290xmlCatalogDump(FILE *out) {
3291 if (out == NULL)
3292 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003293
Daniel Veillard75b96822001-10-11 18:59:45 +00003294 if (!xmlCatalogInitialized)
3295 xmlInitializeCatalog();
3296
3297 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003298}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003299#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003300
3301/**
3302 * xmlCatalogAdd:
3303 * @type: the type of record to add to the catalog
3304 * @orig: the system, public or prefix to match
3305 * @replace: the replacement value for the match
3306 *
3307 * Add an entry in the catalog, it may overwrite existing but
3308 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003309 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003310 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003311 *
3312 * Returns 0 if successful, -1 otherwise
3313 */
3314int
3315xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3316 int res = -1;
3317
Daniel Veillard81463942001-10-16 12:34:39 +00003318 if (!xmlCatalogInitialized)
3319 xmlInitializeCatalogData();
3320
3321 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003322 /*
3323 * Specific case where one want to override the default catalog
3324 * put in place by xmlInitializeCatalog();
3325 */
3326 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003327 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003328 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003329 xmlCatalogDefaultPrefer);
3330 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003331 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003332
Daniel Veillard81463942001-10-16 12:34:39 +00003333 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003334 return(0);
3335 }
3336
Daniel Veillard75b96822001-10-11 18:59:45 +00003337 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003338 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003339 return(res);
3340}
3341
3342/**
3343 * xmlCatalogRemove:
3344 * @value: the value to remove
3345 *
3346 * Remove an entry from the catalog
3347 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003348 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003349 */
3350int
3351xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003352 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003353
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003354 if (!xmlCatalogInitialized)
3355 xmlInitializeCatalog();
3356
Daniel Veillard81463942001-10-16 12:34:39 +00003357 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003358 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003359 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003360 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003361}
3362
3363/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003364 * xmlCatalogConvert:
3365 *
3366 * Convert all the SGML catalog entries as XML ones
3367 *
3368 * Returns the number of entries converted if successful, -1 otherwise
3369 */
3370int
3371xmlCatalogConvert(void) {
3372 int res = -1;
3373
3374 if (!xmlCatalogInitialized)
3375 xmlInitializeCatalog();
3376
Daniel Veillard81463942001-10-16 12:34:39 +00003377 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003378 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003379 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003380 return(res);
3381}
3382
Daniel Veillard75b96822001-10-11 18:59:45 +00003383/************************************************************************
3384 * *
3385 * Public interface manipulating the common preferences *
3386 * *
3387 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003388
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003389/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003390 * xmlCatalogGetDefaults:
3391 *
3392 * Used to get the user preference w.r.t. to what catalogs should
3393 * be accepted
3394 *
3395 * Returns the current xmlCatalogAllow value
3396 */
3397xmlCatalogAllow
3398xmlCatalogGetDefaults(void) {
3399 return(xmlCatalogDefaultAllow);
3400}
3401
3402/**
3403 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003404 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003405 *
3406 * Used to set the user preference w.r.t. to what catalogs should
3407 * be accepted
3408 */
3409void
3410xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003411 if (xmlDebugCatalogs) {
3412 switch (allow) {
3413 case XML_CATA_ALLOW_NONE:
3414 xmlGenericError(xmlGenericErrorContext,
3415 "Disabling catalog usage\n");
3416 break;
3417 case XML_CATA_ALLOW_GLOBAL:
3418 xmlGenericError(xmlGenericErrorContext,
3419 "Allowing only global catalogs\n");
3420 break;
3421 case XML_CATA_ALLOW_DOCUMENT:
3422 xmlGenericError(xmlGenericErrorContext,
3423 "Allowing only catalogs from the document\n");
3424 break;
3425 case XML_CATA_ALLOW_ALL:
3426 xmlGenericError(xmlGenericErrorContext,
3427 "Allowing all catalogs\n");
3428 break;
3429 }
3430 }
3431 xmlCatalogDefaultAllow = allow;
3432}
3433
3434/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003435 * xmlCatalogSetDefaultPrefer:
3436 * @prefer: the default preference for delegation
3437 *
3438 * Allows to set the preference between public and system for deletion
3439 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003440 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003441 *
3442 * Returns the previous value of the default preference for delegation
3443 */
3444xmlCatalogPrefer
3445xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3446 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3447
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003448 if (prefer == XML_CATA_PREFER_NONE)
3449 return(ret);
3450
3451 if (xmlDebugCatalogs) {
3452 switch (prefer) {
3453 case XML_CATA_PREFER_PUBLIC:
3454 xmlGenericError(xmlGenericErrorContext,
3455 "Setting catalog preference to PUBLIC\n");
3456 break;
3457 case XML_CATA_PREFER_SYSTEM:
3458 xmlGenericError(xmlGenericErrorContext,
3459 "Setting catalog preference to SYSTEM\n");
3460 break;
3461 case XML_CATA_PREFER_NONE:
3462 break;
3463 }
3464 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003465 xmlCatalogDefaultPrefer = prefer;
3466 return(ret);
3467}
3468
3469/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003470 * xmlCatalogSetDebug:
3471 * @level: the debug level of catalogs required
3472 *
3473 * Used to set the debug level for catalog operation, 0 disable
3474 * debugging, 1 enable it
3475 *
3476 * Returns the previous value of the catalog debugging level
3477 */
3478int
3479xmlCatalogSetDebug(int level) {
3480 int ret = xmlDebugCatalogs;
3481
3482 if (level <= 0)
3483 xmlDebugCatalogs = 0;
3484 else
3485 xmlDebugCatalogs = level;
3486 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003487}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003488
Daniel Veillard75b96822001-10-11 18:59:45 +00003489/************************************************************************
3490 * *
3491 * Minimal interfaces used for per-document catalogs by the parser *
3492 * *
3493 ************************************************************************/
3494
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003495/**
3496 * xmlCatalogFreeLocal:
3497 * @catalogs: a document's list of catalogs
3498 *
3499 * Free up the memory associated to the catalog list
3500 */
3501void
3502xmlCatalogFreeLocal(void *catalogs) {
3503 xmlCatalogEntryPtr catal;
3504
Daniel Veillard81463942001-10-16 12:34:39 +00003505 if (!xmlCatalogInitialized)
3506 xmlInitializeCatalog();
3507
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003508 catal = (xmlCatalogEntryPtr) catalogs;
3509 if (catal != NULL)
3510 xmlFreeCatalogEntryList(catal);
3511}
3512
3513
3514/**
3515 * xmlCatalogAddLocal:
3516 * @catalogs: a document's list of catalogs
3517 * @URL: the URL to a new local catalog
3518 *
3519 * Add the new entry to the catalog list
3520 *
3521 * Returns the updated list
3522 */
3523void *
3524xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3525 xmlCatalogEntryPtr catal, add;
3526
3527 if (!xmlCatalogInitialized)
3528 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003529
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003530 if (URL == NULL)
3531 return(catalogs);
3532
3533 if (xmlDebugCatalogs)
3534 xmlGenericError(xmlGenericErrorContext,
3535 "Adding document catalog %s\n", URL);
3536
Daniel Veillardc853b322001-11-06 15:24:37 +00003537 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003538 xmlCatalogDefaultPrefer);
3539 if (add == NULL)
3540 return(catalogs);
3541
3542 catal = (xmlCatalogEntryPtr) catalogs;
3543 if (catal == NULL)
3544 return((void *) add);
3545
3546 while (catal->next != NULL)
3547 catal = catal->next;
3548 catal->next = add;
3549 return(catalogs);
3550}
3551
3552/**
3553 * xmlCatalogLocalResolve:
3554 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003555 * @pubID: the public ID string
3556 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003557 *
3558 * Do a complete resolution lookup of an External Identifier using a
3559 * document's private catalog list
3560 *
3561 * Returns the URI of the resource or NULL if not found, it must be freed
3562 * by the caller.
3563 */
3564xmlChar *
3565xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3566 const xmlChar *sysID) {
3567 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003568 xmlChar *ret;
3569
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003570 if (!xmlCatalogInitialized)
3571 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003572
Daniel Veillard81463942001-10-16 12:34:39 +00003573 if ((pubID == NULL) && (sysID == NULL))
3574 return(NULL);
3575
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003576 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003577 if ((pubID != NULL) && (sysID != NULL)) {
3578 xmlGenericError(xmlGenericErrorContext,
3579 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3580 } else if (pubID != NULL) {
3581 xmlGenericError(xmlGenericErrorContext,
3582 "Local Resolve: pubID %s\n", pubID);
3583 } else {
3584 xmlGenericError(xmlGenericErrorContext,
3585 "Local Resolve: sysID %s\n", sysID);
3586 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003587 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003588
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003589 catal = (xmlCatalogEntryPtr) catalogs;
3590 if (catal == NULL)
3591 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003592 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3593 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3594 return(ret);
3595 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003596}
3597
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003598/**
3599 * xmlCatalogLocalResolveURI:
3600 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003601 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003602 *
3603 * Do a complete resolution lookup of an URI using a
3604 * document's private catalog list
3605 *
3606 * Returns the URI of the resource or NULL if not found, it must be freed
3607 * by the caller.
3608 */
3609xmlChar *
3610xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3611 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003612 xmlChar *ret;
3613
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003614 if (!xmlCatalogInitialized)
3615 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003616
Daniel Veillard81463942001-10-16 12:34:39 +00003617 if (URI == NULL)
3618 return(NULL);
3619
Daniel Veillard6990bf32001-08-23 21:17:48 +00003620 if (xmlDebugCatalogs)
3621 xmlGenericError(xmlGenericErrorContext,
3622 "Resolve URI %s\n", URI);
3623
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003624 catal = (xmlCatalogEntryPtr) catalogs;
3625 if (catal == NULL)
3626 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003627 ret = xmlCatalogListXMLResolveURI(catal, URI);
3628 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3629 return(ret);
3630 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003631}
3632
Daniel Veillard75b96822001-10-11 18:59:45 +00003633/************************************************************************
3634 * *
3635 * Deprecated interfaces *
3636 * *
3637 ************************************************************************/
3638/**
3639 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003640 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003641 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003642 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003643 * DEPRECATED, use xmlCatalogResolveSystem()
3644 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003645 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003646 */
3647const xmlChar *
3648xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003649 xmlChar *ret;
3650 static xmlChar result[1000];
3651 static int msg = 0;
3652
3653 if (!xmlCatalogInitialized)
3654 xmlInitializeCatalog();
3655
3656 if (msg == 0) {
3657 xmlGenericError(xmlGenericErrorContext,
3658 "Use of deprecated xmlCatalogGetSystem() call\n");
3659 msg++;
3660 }
3661
3662 if (sysID == NULL)
3663 return(NULL);
3664
3665 /*
3666 * Check first the XML catalogs
3667 */
3668 if (xmlDefaultCatalog != NULL) {
3669 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3670 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3671 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3672 result[sizeof(result) - 1] = 0;
3673 return(result);
3674 }
3675 }
3676
3677 if (xmlDefaultCatalog != NULL)
3678 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3679 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003680}
3681
3682/**
3683 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003684 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003685 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003686 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003687 * DEPRECATED, use xmlCatalogResolvePublic()
3688 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003689 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003690 */
3691const xmlChar *
3692xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003693 xmlChar *ret;
3694 static xmlChar result[1000];
3695 static int msg = 0;
3696
3697 if (!xmlCatalogInitialized)
3698 xmlInitializeCatalog();
3699
3700 if (msg == 0) {
3701 xmlGenericError(xmlGenericErrorContext,
3702 "Use of deprecated xmlCatalogGetPublic() call\n");
3703 msg++;
3704 }
3705
3706 if (pubID == NULL)
3707 return(NULL);
3708
3709 /*
3710 * Check first the XML catalogs
3711 */
3712 if (xmlDefaultCatalog != NULL) {
3713 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3714 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3715 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3716 result[sizeof(result) - 1] = 0;
3717 return(result);
3718 }
3719 }
3720
3721 if (xmlDefaultCatalog != NULL)
3722 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3723 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003724}
3725
Daniel Veillarda7374592001-05-10 14:17:55 +00003726#endif /* LIBXML_CATALOG_ENABLED */