blob: 5456094da8948e54d5447503312092325bbd7323 [file] [log] [blame]
Daniel Veillarda7374592001-05-10 14:17:55 +00001/**
2 * catalog.c: set of generic Catalog related routines
3 *
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
6 *
Daniel Veillard344cee72001-08-20 00:08:40 +00007 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9 *
Daniel Veillarda7374592001-05-10 14:17:55 +000010 * See Copyright for the status of this software.
11 *
12 * Daniel.Veillard@imag.fr
13 */
14
Daniel Veillard34ce8be2002-03-18 19:37:11 +000015#define IN_LIBXML
Daniel Veillarda7374592001-05-10 14:17:55 +000016#include "libxml.h"
17
18#ifdef LIBXML_CATALOG_ENABLED
19#ifdef HAVE_SYS_TYPES_H
20#include <sys/types.h>
21#endif
22#ifdef HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#ifdef HAVE_FCNTL_H
29#include <fcntl.h>
30#endif
Daniel Veillardc0631a62001-09-20 13:56:06 +000031#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000034#include <string.h>
35#include <libxml/xmlmemory.h>
36#include <libxml/hash.h>
37#include <libxml/uri.h>
38#include <libxml/parserInternals.h>
39#include <libxml/catalog.h>
40#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000041#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000042#include <libxml/globals.h>
Daniel Veillarda7374592001-05-10 14:17:55 +000043
Daniel Veillard6990bf32001-08-23 21:17:48 +000044#define MAX_DELEGATE 50
Daniel Veillard5ee43b02003-08-04 00:58:46 +000045#define MAX_CATAL_DEPTH 50
Daniel Veillard6990bf32001-08-23 21:17:48 +000046
Daniel Veillard344cee72001-08-20 00:08:40 +000047/**
48 * TODO:
49 *
50 * macro to flag unimplemented blocks
Daniel Veillard3e59fc52003-04-18 12:34:58 +000051 * XML_CATALOG_PREFER user env to select between system/public prefered
52 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
53 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
54 *> values "system" and "public". I have made the default be "system" to
55 *> match yours.
Daniel Veillard344cee72001-08-20 00:08:40 +000056 */
57#define TODO \
58 xmlGenericError(xmlGenericErrorContext, \
59 "Unimplemented block at %s:%d\n", \
60 __FILE__, __LINE__);
61
Daniel Veillardcda96922001-08-21 10:56:31 +000062#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000063#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000064#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000065#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000066#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000067#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000068#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000069#endif
70
Daniel Veillardfb382b82004-06-14 12:13:12 +000071#if defined(_WIN32) && defined(_MSC_VER)
72#undef XML_XML_DEFAULT_CATALOG
73static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
74void* __stdcall GetModuleHandleA(const char*);
75unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
76#endif
77
Daniel Veillardc8155052004-07-16 09:03:08 +000078static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
Daniel Veillard85c11fa2001-10-16 21:03:08 +000079static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000080
Daniel Veillarda7374592001-05-10 14:17:55 +000081/************************************************************************
82 * *
83 * Types, all private *
84 * *
85 ************************************************************************/
86
87typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000088 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000089 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000090 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000091 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000092 XML_CATA_NEXT_CATALOG,
William M. Brackb7b54de2004-10-06 16:38:01 +000093 XML_CATA_GROUP,
Daniel Veillard344cee72001-08-20 00:08:40 +000094 XML_CATA_PUBLIC,
95 XML_CATA_SYSTEM,
96 XML_CATA_REWRITE_SYSTEM,
97 XML_CATA_DELEGATE_PUBLIC,
98 XML_CATA_DELEGATE_SYSTEM,
99 XML_CATA_URI,
100 XML_CATA_REWRITE_URI,
101 XML_CATA_DELEGATE_URI,
102 SGML_CATA_SYSTEM,
103 SGML_CATA_PUBLIC,
104 SGML_CATA_ENTITY,
105 SGML_CATA_PENTITY,
106 SGML_CATA_DOCTYPE,
107 SGML_CATA_LINKTYPE,
108 SGML_CATA_NOTATION,
109 SGML_CATA_DELEGATE,
110 SGML_CATA_BASE,
111 SGML_CATA_CATALOG,
112 SGML_CATA_DOCUMENT,
113 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000114} xmlCatalogEntryType;
115
116typedef struct _xmlCatalogEntry xmlCatalogEntry;
117typedef xmlCatalogEntry *xmlCatalogEntryPtr;
118struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000119 struct _xmlCatalogEntry *next;
120 struct _xmlCatalogEntry *parent;
121 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000122 xmlCatalogEntryType type;
123 xmlChar *name;
124 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000125 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000126 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000127 int dealloc;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000128 int depth;
William M. Brackb7b54de2004-10-06 16:38:01 +0000129 struct _xmlCatalogEntry *group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000130};
131
Daniel Veillard75b96822001-10-11 18:59:45 +0000132typedef enum {
133 XML_XML_CATALOG_TYPE = 1,
134 XML_SGML_CATALOG_TYPE
135} xmlCatalogType;
136
137#define XML_MAX_SGML_CATA_DEPTH 10
138struct _xmlCatalog {
139 xmlCatalogType type; /* either XML or SGML */
140
141 /*
142 * SGML Catalogs are stored as a simple hash table of catalog entries
143 * Catalog stack to check against overflows when building the
144 * SGML catalog
145 */
146 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
147 int catalNr; /* Number of current catal streams */
148 int catalMax; /* Max number of catal streams */
149 xmlHashTablePtr sgml;
150
151 /*
152 * XML Catalogs are stored as a tree of Catalog entries
153 */
154 xmlCatalogPrefer prefer;
155 xmlCatalogEntryPtr xml;
156};
157
158/************************************************************************
159 * *
160 * Global variables *
161 * *
162 ************************************************************************/
163
Daniel Veillard81463942001-10-16 12:34:39 +0000164/*
165 * Those are preferences
166 */
167static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000168static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000169static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000170
171/*
172 * Hash table containing all the trees of XML catalogs parsed by
173 * the application.
174 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000175static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000176
177/*
178 * The default catalog in use by the application
179 */
180static xmlCatalogPtr xmlDefaultCatalog = NULL;
181
182/*
Daniel Veillard81463942001-10-16 12:34:39 +0000183 * A mutex for modifying the shared global catalog(s)
184 * xmlDefaultCatalog tree.
185 * It also protects xmlCatalogXMLFiles
186 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
187 */
188static xmlRMutexPtr xmlCatalogMutex = NULL;
189
190/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000191 * Whether the catalog support was initialized.
192 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000193static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000194
Daniel Veillard69d2c172003-10-09 11:46:07 +0000195/************************************************************************
196 * *
197 * Catalog error handlers *
198 * *
199 ************************************************************************/
200
201/**
202 * xmlCatalogErrMemory:
203 * @extra: extra informations
204 *
205 * Handle an out of memory condition
206 */
207static void
208xmlCatalogErrMemory(const char *extra)
209{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000210 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000211 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
212 extra, NULL, NULL, 0, 0,
213 "Memory allocation failed : %s\n", extra);
214}
215
216/**
217 * xmlCatalogErr:
218 * @catal: the Catalog entry
219 * @node: the context node
220 * @msg: the error message
221 * @extra: extra informations
222 *
223 * Handle a catalog error
224 */
225static void
226xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
227 const char *msg, const xmlChar *str1, const xmlChar *str2,
228 const xmlChar *str3)
229{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000230 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000231 error, XML_ERR_ERROR, NULL, 0,
232 (const char *) str1, (const char *) str2,
233 (const char *) str3, 0, 0,
234 msg, str1, str2, str3);
235}
236
Daniel Veillarda7374592001-05-10 14:17:55 +0000237
238/************************************************************************
239 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000240 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000241 * *
242 ************************************************************************/
243
Daniel Veillard75b96822001-10-11 18:59:45 +0000244/**
245 * xmlNewCatalogEntry:
246 * @type: type of entry
247 * @name: name of the entry
248 * @value: value of the entry
249 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +0000250 * @group: for members of a group, the group entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000251 *
252 * create a new Catalog entry, this type is shared both by XML and
253 * SGML catalogs, but the acceptable types values differs.
254 *
255 * Returns the xmlCatalogEntryPtr or NULL in case of error
256 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000257static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000258xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
William M. Brackb7b54de2004-10-06 16:38:01 +0000259 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
260 xmlCatalogEntryPtr group) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000261 xmlCatalogEntryPtr ret;
Daniel Veillardc8155052004-07-16 09:03:08 +0000262 xmlChar *normid = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000263
264 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
265 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000266 xmlCatalogErrMemory("allocating catalog entry");
Daniel Veillarda7374592001-05-10 14:17:55 +0000267 return(NULL);
268 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000269 ret->next = NULL;
270 ret->parent = NULL;
271 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000272 ret->type = type;
Daniel Veillardc8155052004-07-16 09:03:08 +0000273 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
274 normid = xmlCatalogNormalizePublic(name);
275 if (normid != NULL)
276 name = (*normid != 0 ? normid : NULL);
277 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000278 if (name != NULL)
279 ret->name = xmlStrdup(name);
280 else
281 ret->name = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +0000282 if (normid != NULL)
283 xmlFree(normid);
Daniel Veillard344cee72001-08-20 00:08:40 +0000284 if (value != NULL)
285 ret->value = xmlStrdup(value);
286 else
287 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000288 if (URL == NULL)
289 URL = value;
290 if (URL != NULL)
291 ret->URL = xmlStrdup(URL);
292 else
293 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000294 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000295 ret->dealloc = 0;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000296 ret->depth = 0;
William M. Brackb7b54de2004-10-06 16:38:01 +0000297 ret->group = group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000298 return(ret);
299}
300
301static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000302xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
303
Daniel Veillard75b96822001-10-11 18:59:45 +0000304/**
305 * xmlFreeCatalogEntry:
306 * @ret: a Catalog entry
307 *
308 * Free the memory allocated to a Catalog entry
309 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000310static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000311xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
312 if (ret == NULL)
313 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000314 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000315 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000316 * only by the file hash cleaner !
317 */
318 if (ret->dealloc == 1)
319 return;
320
321 if (xmlDebugCatalogs) {
322 if (ret->name != NULL)
323 xmlGenericError(xmlGenericErrorContext,
324 "Free catalog entry %s\n", ret->name);
325 else if (ret->value != NULL)
326 xmlGenericError(xmlGenericErrorContext,
327 "Free catalog entry %s\n", ret->value);
328 else
329 xmlGenericError(xmlGenericErrorContext,
330 "Free catalog entry\n");
331 }
332
Daniel Veillarda7374592001-05-10 14:17:55 +0000333 if (ret->name != NULL)
334 xmlFree(ret->name);
335 if (ret->value != NULL)
336 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000337 if (ret->URL != NULL)
338 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000339 xmlFree(ret);
340}
341
Daniel Veillard75b96822001-10-11 18:59:45 +0000342/**
343 * xmlFreeCatalogEntryList:
344 * @ret: a Catalog entry list
345 *
346 * Free the memory allocated to a full chained list of Catalog entries
347 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000348static void
349xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
350 xmlCatalogEntryPtr next;
351
352 while (ret != NULL) {
353 next = ret->next;
354 xmlFreeCatalogEntry(ret);
355 ret = next;
356 }
357}
358
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000359/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000360 * xmlFreeCatalogHashEntryList:
361 * @ret: a Catalog entry list
362 *
363 * Free the memory allocated to list of Catalog entries from the
364 * catalog file hash.
365 */
366static void
367xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
368 xmlCatalogEntryPtr children, next;
369
370 if (catal == NULL)
371 return;
372
373 children = catal->children;
374 while (children != NULL) {
375 next = children->next;
376 children->dealloc = 0;
377 children->children = NULL;
378 xmlFreeCatalogEntry(children);
379 children = next;
380 }
381 catal->dealloc = 0;
382 xmlFreeCatalogEntry(catal);
383}
384
385/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000386 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000387 * @type: type of catalog
388 * @prefer: the PUBLIC vs. SYSTEM current preference value
389 *
390 * create a new Catalog, this type is shared both by XML and
391 * SGML catalogs, but the acceptable types values differs.
392 *
393 * Returns the xmlCatalogPtr or NULL in case of error
394 */
395static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000396xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000397 xmlCatalogPtr ret;
398
399 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
400 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000401 xmlCatalogErrMemory("allocating catalog");
Daniel Veillard75b96822001-10-11 18:59:45 +0000402 return(NULL);
403 }
404 memset(ret, 0, sizeof(xmlCatalog));
405 ret->type = type;
406 ret->catalNr = 0;
407 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
408 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000409 if (ret->type == XML_SGML_CATALOG_TYPE)
410 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000411 return(ret);
412}
413
414/**
415 * xmlFreeCatalog:
Daniel Veillard06d25242004-02-25 13:01:42 +0000416 * @catal: a Catalog
Daniel Veillard75b96822001-10-11 18:59:45 +0000417 *
418 * Free the memory allocated to a Catalog
419 */
420void
421xmlFreeCatalog(xmlCatalogPtr catal) {
422 if (catal == NULL)
423 return;
424 if (catal->xml != NULL)
425 xmlFreeCatalogEntryList(catal->xml);
426 if (catal->sgml != NULL)
427 xmlHashFree(catal->sgml,
428 (xmlHashDeallocator) xmlFreeCatalogEntry);
429 xmlFree(catal);
430}
431
432/************************************************************************
433 * *
434 * Serializing Catalogs *
435 * *
436 ************************************************************************/
437
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000438#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000439/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000440 * xmlCatalogDumpEntry:
Daniel Veillard06d25242004-02-25 13:01:42 +0000441 * @entry: the catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000442 * @out: the file.
443 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000444 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000445 */
446static void
447xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
448 if ((entry == NULL) || (out == NULL))
449 return;
450 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000451 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000452 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000453 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000454 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000455 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000456 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000457 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000458 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000459 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000460 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000461 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000462 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000463 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000464 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000465 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000466 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000467 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000468 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000469 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000470 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000471 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000472 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000473 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000474 fprintf(out, "SGMLDECL "); break;
475 default:
476 return;
477 }
478 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000479 case SGML_CATA_ENTITY:
480 case SGML_CATA_PENTITY:
481 case SGML_CATA_DOCTYPE:
482 case SGML_CATA_LINKTYPE:
483 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000484 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000485 case SGML_CATA_PUBLIC:
486 case SGML_CATA_SYSTEM:
487 case SGML_CATA_SGMLDECL:
488 case SGML_CATA_DOCUMENT:
489 case SGML_CATA_CATALOG:
490 case SGML_CATA_BASE:
491 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000492 fprintf(out, "\"%s\"", entry->name); break;
493 default:
494 break;
495 }
496 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000497 case SGML_CATA_ENTITY:
498 case SGML_CATA_PENTITY:
499 case SGML_CATA_DOCTYPE:
500 case SGML_CATA_LINKTYPE:
501 case SGML_CATA_NOTATION:
502 case SGML_CATA_PUBLIC:
503 case SGML_CATA_SYSTEM:
504 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000505 fprintf(out, " \"%s\"", entry->value); break;
506 default:
507 break;
508 }
509 fprintf(out, "\n");
510}
511
William M. Brackb7b54de2004-10-06 16:38:01 +0000512/**
513 * xmlDumpXMLCatalogNode:
514 * @catal: top catalog entry
515 * @catalog: pointer to the xml tree
516 * @doc: the containing document
517 * @ns: the current namespace
518 * @cgroup: group node for group members
519 *
520 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
521 * for group entries
522 */
523static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
524 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
525 xmlNodePtr node;
526 xmlCatalogEntryPtr cur;
527 /*
528 * add all the catalog entries
529 */
530 cur = catal;
531 while (cur != NULL) {
532 if (cur->group == cgroup) {
533 switch (cur->type) {
534 case XML_CATA_REMOVED:
535 break;
536 case XML_CATA_BROKEN_CATALOG:
537 case XML_CATA_CATALOG:
538 if (cur == catal) {
539 cur = cur->children;
540 continue;
541 }
542 break;
543 case XML_CATA_NEXT_CATALOG:
544 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
545 xmlSetProp(node, BAD_CAST "catalog", cur->value);
546 xmlAddChild(catalog, node);
547 break;
548 case XML_CATA_NONE:
549 break;
550 case XML_CATA_GROUP:
551 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
552 xmlSetProp(node, BAD_CAST "id", cur->name);
William M. Brack6218b312004-10-06 17:52:32 +0000553 if (cur->value != NULL) {
554 xmlNsPtr xns;
555 xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
556 if (xns != NULL)
557 xmlSetNsProp(node, xns, BAD_CAST "base",
558 cur->value);
559 }
William M. Brackb7b54de2004-10-06 16:38:01 +0000560 switch (cur->prefer) {
561 case XML_CATA_PREFER_NONE:
562 break;
563 case XML_CATA_PREFER_PUBLIC:
564 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
565 break;
566 case XML_CATA_PREFER_SYSTEM:
567 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
568 break;
569 }
570 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
571 xmlAddChild(catalog, node);
572 break;
573 case XML_CATA_PUBLIC:
574 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
575 xmlSetProp(node, BAD_CAST "publicId", cur->name);
576 xmlSetProp(node, BAD_CAST "uri", cur->value);
577 xmlAddChild(catalog, node);
578 break;
579 case XML_CATA_SYSTEM:
580 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
581 xmlSetProp(node, BAD_CAST "systemId", cur->name);
582 xmlSetProp(node, BAD_CAST "uri", cur->value);
583 xmlAddChild(catalog, node);
584 break;
585 case XML_CATA_REWRITE_SYSTEM:
586 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
587 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
588 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
589 xmlAddChild(catalog, node);
590 break;
591 case XML_CATA_DELEGATE_PUBLIC:
592 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
593 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
594 xmlSetProp(node, BAD_CAST "catalog", cur->value);
595 xmlAddChild(catalog, node);
596 break;
597 case XML_CATA_DELEGATE_SYSTEM:
598 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
599 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
600 xmlSetProp(node, BAD_CAST "catalog", cur->value);
601 xmlAddChild(catalog, node);
602 break;
603 case XML_CATA_URI:
604 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
605 xmlSetProp(node, BAD_CAST "name", cur->name);
606 xmlSetProp(node, BAD_CAST "uri", cur->value);
607 xmlAddChild(catalog, node);
608 break;
609 case XML_CATA_REWRITE_URI:
610 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
611 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
612 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
613 xmlAddChild(catalog, node);
614 break;
615 case XML_CATA_DELEGATE_URI:
616 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
617 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
618 xmlSetProp(node, BAD_CAST "catalog", cur->value);
619 xmlAddChild(catalog, node);
620 break;
621 case SGML_CATA_SYSTEM:
622 case SGML_CATA_PUBLIC:
623 case SGML_CATA_ENTITY:
624 case SGML_CATA_PENTITY:
625 case SGML_CATA_DOCTYPE:
626 case SGML_CATA_LINKTYPE:
627 case SGML_CATA_NOTATION:
628 case SGML_CATA_DELEGATE:
629 case SGML_CATA_BASE:
630 case SGML_CATA_CATALOG:
631 case SGML_CATA_DOCUMENT:
632 case SGML_CATA_SGMLDECL:
633 break;
634 }
635 }
636 cur = cur->next;
637 }
638}
639
Daniel Veillard75b96822001-10-11 18:59:45 +0000640static int
641xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
642 int ret;
643 xmlDocPtr doc;
644 xmlNsPtr ns;
645 xmlDtdPtr dtd;
William M. Brackb7b54de2004-10-06 16:38:01 +0000646 xmlNodePtr catalog;
Daniel Veillard75b96822001-10-11 18:59:45 +0000647 xmlOutputBufferPtr buf;
Daniel Veillard75b96822001-10-11 18:59:45 +0000648
649 /*
650 * Rebuild a catalog
651 */
652 doc = xmlNewDoc(NULL);
653 if (doc == NULL)
654 return(-1);
655 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
656 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
657BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
658
659 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
660
661 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
662 if (ns == NULL) {
663 xmlFreeDoc(doc);
664 return(-1);
665 }
666 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
667 if (catalog == NULL) {
668 xmlFreeNs(ns);
669 xmlFreeDoc(doc);
670 return(-1);
671 }
672 catalog->nsDef = ns;
673 xmlAddChild((xmlNodePtr) doc, catalog);
674
William M. Brackb7b54de2004-10-06 16:38:01 +0000675 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
676
Daniel Veillard75b96822001-10-11 18:59:45 +0000677 /*
678 * reserialize it
679 */
680 buf = xmlOutputBufferCreateFile(out, NULL);
681 if (buf == NULL) {
682 xmlFreeDoc(doc);
683 return(-1);
684 }
685 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
686
687 /*
688 * Free it
689 */
690 xmlFreeDoc(doc);
691
692 return(ret);
693}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000694#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000695
696/************************************************************************
697 * *
698 * Converting SGML Catalogs to XML *
699 * *
700 ************************************************************************/
701
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000702/**
703 * xmlCatalogConvertEntry:
704 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000705 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000706 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000707 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000708 */
709static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000710xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
711 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
712 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000713 return;
714 switch (entry->type) {
715 case SGML_CATA_ENTITY:
716 entry->type = XML_CATA_PUBLIC;
717 break;
718 case SGML_CATA_PENTITY:
719 entry->type = XML_CATA_PUBLIC;
720 break;
721 case SGML_CATA_DOCTYPE:
722 entry->type = XML_CATA_PUBLIC;
723 break;
724 case SGML_CATA_LINKTYPE:
725 entry->type = XML_CATA_PUBLIC;
726 break;
727 case SGML_CATA_NOTATION:
728 entry->type = XML_CATA_PUBLIC;
729 break;
730 case SGML_CATA_PUBLIC:
731 entry->type = XML_CATA_PUBLIC;
732 break;
733 case SGML_CATA_SYSTEM:
734 entry->type = XML_CATA_SYSTEM;
735 break;
736 case SGML_CATA_DELEGATE:
737 entry->type = XML_CATA_DELEGATE_PUBLIC;
738 break;
739 case SGML_CATA_CATALOG:
740 entry->type = XML_CATA_CATALOG;
741 break;
742 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000743 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000744 (xmlHashDeallocator) xmlFreeCatalogEntry);
745 return;
746 }
747 /*
748 * Conversion successful, remove from the SGML catalog
749 * and add it to the default XML one
750 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000751 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
752 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000753 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000754 if (catal->xml->children == NULL)
755 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000756 else {
757 xmlCatalogEntryPtr prev;
758
Daniel Veillard75b96822001-10-11 18:59:45 +0000759 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000760 while (prev->next != NULL)
761 prev = prev->next;
762 prev->next = entry;
763 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000764}
765
766/**
767 * xmlConvertSGMLCatalog:
768 * @catal: the catalog
769 *
770 * Convert all the SGML catalog entries as XML ones
771 *
772 * Returns the number of entries converted if successful, -1 otherwise
773 */
774int
775xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
776
777 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
778 return(-1);
779
780 if (xmlDebugCatalogs) {
781 xmlGenericError(xmlGenericErrorContext,
782 "Converting SGML catalog to XML\n");
783 }
784 xmlHashScan(catal->sgml,
785 (xmlHashScanner) xmlCatalogConvertEntry,
786 &catal);
787 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000788}
789
Daniel Veillarda7374592001-05-10 14:17:55 +0000790/************************************************************************
791 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000792 * Helper function *
793 * *
794 ************************************************************************/
795
796/**
797 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000798 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000799 *
800 * Expand the URN into the equivalent Public Identifier
801 *
802 * Returns the new identifier or NULL, the string must be deallocated
803 * by the caller.
804 */
805static xmlChar *
806xmlCatalogUnWrapURN(const xmlChar *urn) {
807 xmlChar result[2000];
808 unsigned int i = 0;
809
810 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
811 return(NULL);
812 urn += sizeof(XML_URN_PUBID) - 1;
813
814 while (*urn != 0) {
Daniel Veillard770075b2004-02-25 10:44:30 +0000815 if (i > sizeof(result) - 4)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000816 break;
817 if (*urn == '+') {
818 result[i++] = ' ';
819 urn++;
820 } else if (*urn == ':') {
821 result[i++] = '/';
822 result[i++] = '/';
823 urn++;
824 } else if (*urn == ';') {
825 result[i++] = ':';
826 result[i++] = ':';
827 urn++;
828 } else if (*urn == '%') {
Daniel Veillard770075b2004-02-25 10:44:30 +0000829 if ((urn[1] == '2') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000830 result[i++] = '+';
Daniel Veillard770075b2004-02-25 10:44:30 +0000831 else if ((urn[1] == '3') && (urn[2] == 'A'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000832 result[i++] = ':';
Daniel Veillard770075b2004-02-25 10:44:30 +0000833 else if ((urn[1] == '2') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000834 result[i++] = '/';
Daniel Veillard770075b2004-02-25 10:44:30 +0000835 else if ((urn[1] == '3') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000836 result[i++] = ';';
Daniel Veillard770075b2004-02-25 10:44:30 +0000837 else if ((urn[1] == '2') && (urn[2] == '7'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000838 result[i++] = '\'';
Daniel Veillard770075b2004-02-25 10:44:30 +0000839 else if ((urn[1] == '3') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000840 result[i++] = '?';
Daniel Veillard770075b2004-02-25 10:44:30 +0000841 else if ((urn[1] == '2') && (urn[2] == '3'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000842 result[i++] = '#';
Daniel Veillard770075b2004-02-25 10:44:30 +0000843 else if ((urn[1] == '2') && (urn[2] == '5'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000844 result[i++] = '%';
845 else {
846 result[i++] = *urn;
847 urn++;
848 continue;
849 }
850 urn += 3;
851 } else {
852 result[i++] = *urn;
853 urn++;
854 }
855 }
856 result[i] = 0;
857
858 return(xmlStrdup(result));
859}
860
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000861/**
862 * xmlParseCatalogFile:
863 * @filename: the filename
864 *
865 * parse an XML file and build a tree. It's like xmlParseFile()
866 * except it bypass all catalog lookups.
867 *
868 * Returns the resulting document tree or NULL in case of error
869 */
870
871xmlDocPtr
872xmlParseCatalogFile(const char *filename) {
873 xmlDocPtr ret;
874 xmlParserCtxtPtr ctxt;
875 char *directory = NULL;
876 xmlParserInputPtr inputStream;
877 xmlParserInputBufferPtr buf;
878
879 ctxt = xmlNewParserCtxt();
880 if (ctxt == NULL) {
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000881#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000882 if (xmlDefaultSAXHandler.error != NULL) {
883 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
884 }
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000885#endif
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000886 return(NULL);
887 }
888
889 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
890 if (buf == NULL) {
891 xmlFreeParserCtxt(ctxt);
892 return(NULL);
893 }
894
895 inputStream = xmlNewInputStream(ctxt);
896 if (inputStream == NULL) {
897 xmlFreeParserCtxt(ctxt);
898 return(NULL);
899 }
900
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000901 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000902 inputStream->buf = buf;
903 inputStream->base = inputStream->buf->buffer->content;
904 inputStream->cur = inputStream->buf->buffer->content;
905 inputStream->end =
906 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
907
908 inputPush(ctxt, inputStream);
909 if ((ctxt->directory == NULL) && (directory == NULL))
910 directory = xmlParserGetDirectory(filename);
911 if ((ctxt->directory == NULL) && (directory != NULL))
912 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000913 ctxt->valid = 0;
914 ctxt->validate = 0;
915 ctxt->loadsubset = 0;
916 ctxt->pedantic = 0;
Daniel Veillard03a53c32004-10-26 16:06:51 +0000917 ctxt->dictNames = 1;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000918
919 xmlParseDocument(ctxt);
920
921 if (ctxt->wellFormed)
922 ret = ctxt->myDoc;
923 else {
924 ret = NULL;
925 xmlFreeDoc(ctxt->myDoc);
926 ctxt->myDoc = NULL;
927 }
928 xmlFreeParserCtxt(ctxt);
929
930 return(ret);
931}
932
Daniel Veillard75b96822001-10-11 18:59:45 +0000933/**
934 * xmlLoadFileContent:
935 * @filename: a file path
936 *
937 * Load a file content into memory.
938 *
939 * Returns a pointer to the 0 terminated string or NULL in case of error
940 */
941static xmlChar *
942xmlLoadFileContent(const char *filename)
943{
944#ifdef HAVE_STAT
945 int fd;
946#else
947 FILE *fd;
948#endif
949 int len;
950 long size;
951
952#ifdef HAVE_STAT
953 struct stat info;
954#endif
955 xmlChar *content;
956
957 if (filename == NULL)
958 return (NULL);
959
960#ifdef HAVE_STAT
961 if (stat(filename, &info) < 0)
962 return (NULL);
963#endif
964
965#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000966 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000967#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000968 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000969#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000970 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000971 return (NULL);
972 }
973#ifdef HAVE_STAT
974 size = info.st_size;
975#else
976 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
977 fclose(fd);
978 return (NULL);
979 }
980#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000981 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000982 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000983 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard75b96822001-10-11 18:59:45 +0000984 return (NULL);
985 }
986#ifdef HAVE_STAT
987 len = read(fd, content, size);
988#else
989 len = fread(content, 1, size, fd);
990#endif
991 if (len < 0) {
992 xmlFree(content);
993 return (NULL);
994 }
995#ifdef HAVE_STAT
996 close(fd);
997#else
998 fclose(fd);
999#endif
1000 content[len] = 0;
1001
1002 return(content);
1003}
1004
Daniel Veillardc8155052004-07-16 09:03:08 +00001005/**
1006 * xmlCatalogNormalizePublic:
1007 * @pubID: the public ID string
1008 *
1009 * Normalizes the Public Identifier
1010 *
1011 * Implements 6.2. Public Identifier Normalization
1012 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1013 *
1014 * Returns the new string or NULL, the string must be deallocated
1015 * by the caller.
1016 */
1017static xmlChar *
1018xmlCatalogNormalizePublic(const xmlChar *pubID)
1019{
1020 int ok = 1;
1021 int white;
1022 const xmlChar *p;
1023 xmlChar *ret;
1024 xmlChar *q;
1025
1026 if (pubID == NULL)
1027 return(NULL);
1028
1029 white = 1;
1030 for (p = pubID;*p != 0 && ok;p++) {
1031 if (!xmlIsBlank_ch(*p))
1032 white = 0;
1033 else if (*p == 0x20 && !white)
1034 white = 1;
1035 else
1036 ok = 0;
1037 }
1038 if (ok && !white) /* is normalized */
1039 return(NULL);
1040
1041 ret = xmlStrdup(pubID);
1042 q = ret;
1043 white = 0;
1044 for (p = pubID;*p != 0;p++) {
1045 if (xmlIsBlank_ch(*p)) {
1046 if (q != ret)
1047 white = 1;
1048 } else {
1049 if (white) {
1050 *(q++) = 0x20;
1051 white = 0;
1052 }
1053 *(q++) = *p;
1054 }
1055 }
1056 *q = 0;
1057 return(ret);
1058}
1059
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001060/************************************************************************
1061 * *
Daniel Veillard344cee72001-08-20 00:08:40 +00001062 * The XML Catalog parser *
1063 * *
1064 ************************************************************************/
1065
1066static xmlCatalogEntryPtr
1067xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001068static void
1069xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001070 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
Daniel Veillardcda96922001-08-21 10:56:31 +00001071static xmlChar *
1072xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1073 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001074static xmlChar *
1075xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1076
Daniel Veillard344cee72001-08-20 00:08:40 +00001077
Daniel Veillard75b96822001-10-11 18:59:45 +00001078/**
1079 * xmlGetXMLCatalogEntryType:
1080 * @name: the name
1081 *
1082 * lookup the internal type associated to an XML catalog entry name
1083 *
Daniel Veillard06d25242004-02-25 13:01:42 +00001084 * Returns the type associated with that name
Daniel Veillard75b96822001-10-11 18:59:45 +00001085 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001086static xmlCatalogEntryType
1087xmlGetXMLCatalogEntryType(const xmlChar *name) {
1088 xmlCatalogEntryType type = XML_CATA_NONE;
1089 if (xmlStrEqual(name, (const xmlChar *) "system"))
1090 type = XML_CATA_SYSTEM;
1091 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1092 type = XML_CATA_PUBLIC;
1093 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1094 type = XML_CATA_REWRITE_SYSTEM;
1095 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1096 type = XML_CATA_DELEGATE_PUBLIC;
1097 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1098 type = XML_CATA_DELEGATE_SYSTEM;
1099 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1100 type = XML_CATA_URI;
1101 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1102 type = XML_CATA_REWRITE_URI;
1103 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1104 type = XML_CATA_DELEGATE_URI;
1105 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1106 type = XML_CATA_NEXT_CATALOG;
1107 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1108 type = XML_CATA_CATALOG;
1109 return(type);
1110}
1111
Daniel Veillard75b96822001-10-11 18:59:45 +00001112/**
1113 * xmlParseXMLCatalogOneNode:
1114 * @cur: the XML node
1115 * @type: the type of Catalog entry
1116 * @name: the name of the node
1117 * @attrName: the attribute holding the value
1118 * @uriAttrName: the attribute holding the URI-Reference
1119 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +00001120 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001121 *
1122 * Finishes the examination of an XML tree node of a catalog and build
1123 * a Catalog entry from it.
1124 *
1125 * Returns the new Catalog entry node or NULL in case of error.
1126 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001127static xmlCatalogEntryPtr
1128xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1129 const xmlChar *name, const xmlChar *attrName,
William M. Brackb7b54de2004-10-06 16:38:01 +00001130 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1131 xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001132 int ok = 1;
1133 xmlChar *uriValue;
1134 xmlChar *nameValue = NULL;
1135 xmlChar *base = NULL;
1136 xmlChar *URL = NULL;
1137 xmlCatalogEntryPtr ret = NULL;
1138
1139 if (attrName != NULL) {
1140 nameValue = xmlGetProp(cur, attrName);
1141 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001142 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1143 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001144 ok = 0;
1145 }
1146 }
1147 uriValue = xmlGetProp(cur, uriAttrName);
1148 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001149 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1150 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001151 ok = 0;
1152 }
1153 if (!ok) {
1154 if (nameValue != NULL)
1155 xmlFree(nameValue);
1156 if (uriValue != NULL)
1157 xmlFree(uriValue);
1158 return(NULL);
1159 }
1160
1161 base = xmlNodeGetBase(cur->doc, cur);
1162 URL = xmlBuildURI(uriValue, base);
1163 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001164 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001165 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001166 xmlGenericError(xmlGenericErrorContext,
1167 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001168 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001169 xmlGenericError(xmlGenericErrorContext,
1170 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001171 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001172 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001173 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001174 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001175 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1176 }
1177 if (nameValue != NULL)
1178 xmlFree(nameValue);
1179 if (uriValue != NULL)
1180 xmlFree(uriValue);
1181 if (base != NULL)
1182 xmlFree(base);
1183 if (URL != NULL)
1184 xmlFree(URL);
1185 return(ret);
1186}
1187
Daniel Veillard75b96822001-10-11 18:59:45 +00001188/**
1189 * xmlParseXMLCatalogNode:
1190 * @cur: the XML node
1191 * @prefer: the PUBLIC vs. SYSTEM current preference value
1192 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001193 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001194 *
1195 * Examines an XML tree node of a catalog and build
1196 * a Catalog entry from it adding it to its parent. The examination can
1197 * be recursive.
1198 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001199static void
1200xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001201 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
Daniel Veillard344cee72001-08-20 00:08:40 +00001202{
Daniel Veillard344cee72001-08-20 00:08:40 +00001203 xmlChar *base = NULL;
1204 xmlCatalogEntryPtr entry = NULL;
1205
1206 if (cur == NULL)
1207 return;
1208 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1209 xmlChar *prop;
William M. Brackb7b54de2004-10-06 16:38:01 +00001210 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
Daniel Veillard344cee72001-08-20 00:08:40 +00001211
1212 prop = xmlGetProp(cur, BAD_CAST "prefer");
1213 if (prop != NULL) {
1214 if (xmlStrEqual(prop, BAD_CAST "system")) {
1215 prefer = XML_CATA_PREFER_SYSTEM;
1216 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1217 prefer = XML_CATA_PREFER_PUBLIC;
1218 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001219 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1220 "Invalid value for prefer: '%s'\n",
1221 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001222 }
1223 xmlFree(prop);
William M. Brackb7b54de2004-10-06 16:38:01 +00001224 pref = prefer;
Daniel Veillard344cee72001-08-20 00:08:40 +00001225 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001226 prop = xmlGetProp(cur, BAD_CAST "id");
1227 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1228 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
William M. Brack181a1ca2004-10-06 18:00:29 +00001229 xmlFree(prop);
Daniel Veillard344cee72001-08-20 00:08:40 +00001230 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1231 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
William M. Brackb7b54de2004-10-06 16:38:01 +00001232 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001233 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1234 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
William M. Brackb7b54de2004-10-06 16:38:01 +00001235 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001236 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1237 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1238 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001239 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001240 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1241 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1242 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001243 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001244 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1245 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1246 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001247 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001248 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1249 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1250 BAD_CAST "uri", BAD_CAST "name",
William M. Brackb7b54de2004-10-06 16:38:01 +00001251 BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001252 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1253 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1254 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001255 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001256 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1257 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1258 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001259 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001260 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1261 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1262 BAD_CAST "nextCatalog", NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001263 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001264 }
William M. Brackb031cef2004-11-05 16:34:22 +00001265 if (entry != NULL) {
1266 if (parent != NULL) {
1267 entry->parent = parent;
1268 if (parent->children == NULL)
1269 parent->children = entry;
1270 else {
1271 xmlCatalogEntryPtr prev;
Daniel Veillard344cee72001-08-20 00:08:40 +00001272
William M. Brackb031cef2004-11-05 16:34:22 +00001273 prev = parent->children;
1274 while (prev->next != NULL)
1275 prev = prev->next;
1276 prev->next = entry;
1277 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001278 }
William M. Brackb031cef2004-11-05 16:34:22 +00001279 if (entry->type == XML_CATA_GROUP) {
1280 /*
1281 * Recurse to propagate prefer to the subtree
1282 * (xml:base handling is automated)
1283 */
1284 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1285 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001286 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001287 if (base != NULL)
1288 xmlFree(base);
Daniel Veillard344cee72001-08-20 00:08:40 +00001289}
1290
Daniel Veillard75b96822001-10-11 18:59:45 +00001291/**
1292 * xmlParseXMLCatalogNodeList:
1293 * @cur: the XML node list of siblings
1294 * @prefer: the PUBLIC vs. SYSTEM current preference value
1295 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001296 * @cgroup: the group which includes this list
Daniel Veillard75b96822001-10-11 18:59:45 +00001297 *
1298 * Examines a list of XML sibling nodes of a catalog and build
1299 * a list of Catalog entry from it adding it to the parent.
1300 * The examination will recurse to examine node subtrees.
1301 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001302static void
1303xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001304 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001305 while (cur != NULL) {
1306 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1307 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
William M. Brackb7b54de2004-10-06 16:38:01 +00001308 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001309 }
1310 cur = cur->next;
1311 }
1312 /* TODO: sort the list according to REWRITE lengths and prefer value */
1313}
1314
Daniel Veillard75b96822001-10-11 18:59:45 +00001315/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001316 * xmlParseXMLCatalogFile:
1317 * @prefer: the PUBLIC vs. SYSTEM current preference value
1318 * @filename: the filename for the catalog
1319 *
1320 * Parses the catalog file to extract the XML tree and then analyze the
1321 * tree to build a list of Catalog entries corresponding to this catalog
1322 *
1323 * Returns the resulting Catalog entries list
1324 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001325static xmlCatalogEntryPtr
1326xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1327 xmlDocPtr doc;
1328 xmlNodePtr cur;
1329 xmlChar *prop;
1330 xmlCatalogEntryPtr parent = NULL;
1331
1332 if (filename == NULL)
1333 return(NULL);
1334
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001335 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001336 if (doc == NULL) {
1337 if (xmlDebugCatalogs)
1338 xmlGenericError(xmlGenericErrorContext,
1339 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001340 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001341 }
1342
1343 if (xmlDebugCatalogs)
1344 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001345 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001346
1347 cur = xmlDocGetRootElement(doc);
1348 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1349 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1350 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1351
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001352 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001353 (const xmlChar *)filename, NULL, prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001354 if (parent == NULL) {
1355 xmlFreeDoc(doc);
1356 return(NULL);
1357 }
1358
1359 prop = xmlGetProp(cur, BAD_CAST "prefer");
1360 if (prop != NULL) {
1361 if (xmlStrEqual(prop, BAD_CAST "system")) {
1362 prefer = XML_CATA_PREFER_SYSTEM;
1363 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1364 prefer = XML_CATA_PREFER_PUBLIC;
1365 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001366 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1367 "Invalid value for prefer: '%s'\n",
1368 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001369 }
1370 xmlFree(prop);
1371 }
1372 cur = cur->children;
William M. Brackb7b54de2004-10-06 16:38:01 +00001373 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001374 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001375 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1376 "File %s is not an XML Catalog\n",
1377 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001378 xmlFreeDoc(doc);
1379 return(NULL);
1380 }
1381 xmlFreeDoc(doc);
1382 return(parent);
1383}
1384
Daniel Veillardcda96922001-08-21 10:56:31 +00001385/**
1386 * xmlFetchXMLCatalogFile:
1387 * @catal: an existing but incomplete catalog entry
1388 *
1389 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001390 *
1391 * Returns 0 in case of success, -1 otherwise
1392 */
1393static int
1394xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001395 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001396
1397 if (catal == NULL)
1398 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001399 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001400 return(-1);
1401 if (catal->children != NULL)
1402 return(-1);
1403
Daniel Veillard81463942001-10-16 12:34:39 +00001404 /*
1405 * lock the whole catalog for modification
1406 */
1407 xmlRMutexLock(xmlCatalogMutex);
1408 if (catal->children != NULL) {
1409 /* Okay someone else did it in the meantime */
1410 xmlRMutexUnlock(xmlCatalogMutex);
1411 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001412 }
1413
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001414 if (xmlCatalogXMLFiles != NULL) {
1415 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001416 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001417 if (doc != NULL) {
1418 if (xmlDebugCatalogs)
1419 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001420 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001421
1422 if (catal->type == XML_CATA_CATALOG)
1423 catal->children = doc->children;
1424 else
1425 catal->children = doc;
1426 catal->dealloc = 0;
1427 xmlRMutexUnlock(xmlCatalogMutex);
1428 return(0);
1429 }
1430 if (xmlDebugCatalogs)
1431 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001432 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001433 }
1434
Daniel Veillardcda96922001-08-21 10:56:31 +00001435 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001436 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001437 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001438 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001439 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001440 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001441 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001442 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001443 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001444 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001445 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001446
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001447 if (catal->type == XML_CATA_CATALOG)
1448 catal->children = doc->children;
1449 else
1450 catal->children = doc;
1451
1452 doc->dealloc = 1;
1453
Daniel Veillard81463942001-10-16 12:34:39 +00001454 if (xmlCatalogXMLFiles == NULL)
1455 xmlCatalogXMLFiles = xmlHashCreate(10);
1456 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001457 if (xmlDebugCatalogs)
1458 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001459 "%s added to file hash\n", catal->URL);
1460 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001461 }
Daniel Veillard81463942001-10-16 12:34:39 +00001462 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001463 return(0);
1464}
1465
Daniel Veillard75b96822001-10-11 18:59:45 +00001466/************************************************************************
1467 * *
1468 * XML Catalog handling *
1469 * *
1470 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001471
1472/**
1473 * xmlAddXMLCatalog:
1474 * @catal: top of an XML catalog
1475 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001476 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001477 * @replace: the replacement value for the match
1478 *
1479 * Add an entry in the XML catalog, it may overwrite existing but
1480 * different entries.
1481 *
1482 * Returns 0 if successful, -1 otherwise
1483 */
1484static int
1485xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1486 const xmlChar *orig, const xmlChar *replace) {
1487 xmlCatalogEntryPtr cur;
1488 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001489 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001490
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001491 if ((catal == NULL) ||
1492 ((catal->type != XML_CATA_CATALOG) &&
1493 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001494 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001495 if (catal->children == NULL) {
1496 xmlFetchXMLCatalogFile(catal);
1497 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001498 if (catal->children == NULL)
1499 doregister = 1;
1500
Daniel Veillard344cee72001-08-20 00:08:40 +00001501 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001502 if (typ == XML_CATA_NONE) {
1503 if (xmlDebugCatalogs)
1504 xmlGenericError(xmlGenericErrorContext,
1505 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001506 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001507 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001508
1509 cur = catal->children;
1510 /*
1511 * Might be a simple "update in place"
1512 */
1513 if (cur != NULL) {
1514 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001515 if ((orig != NULL) && (cur->type == typ) &&
1516 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001517 if (xmlDebugCatalogs)
1518 xmlGenericError(xmlGenericErrorContext,
1519 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001520 if (cur->value != NULL)
1521 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001522 if (cur->URL != NULL)
1523 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001524 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001525 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001526 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001527 }
1528 if (cur->next == NULL)
1529 break;
1530 cur = cur->next;
1531 }
1532 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001533 if (xmlDebugCatalogs)
1534 xmlGenericError(xmlGenericErrorContext,
1535 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001536 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001537 catal->children = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001538 NULL, catal->prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001539 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001540 cur->next = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001541 NULL, catal->prefer, NULL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001542 if (doregister) {
Daniel Veillard27bec142006-02-24 20:22:27 +00001543 catal->type = XML_CATA_CATALOG;
Daniel Veillardc853b322001-11-06 15:24:37 +00001544 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1545 if (cur != NULL)
1546 cur->children = catal->children;
1547 }
1548
Daniel Veillardcda96922001-08-21 10:56:31 +00001549 return(0);
1550}
1551
1552/**
1553 * xmlDelXMLCatalog:
1554 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001555 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001556 *
1557 * Remove entries in the XML catalog where the value or the URI
1558 * is equal to @value
1559 *
1560 * Returns the number of entries removed if successful, -1 otherwise
1561 */
1562static int
1563xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001564 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001565 int ret = 0;
1566
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001567 if ((catal == NULL) ||
1568 ((catal->type != XML_CATA_CATALOG) &&
1569 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001570 return(-1);
1571 if (value == NULL)
1572 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001573 if (catal->children == NULL) {
1574 xmlFetchXMLCatalogFile(catal);
1575 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001576
1577 /*
1578 * Scan the children
1579 */
1580 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001581 while (cur != NULL) {
1582 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1583 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001584 if (xmlDebugCatalogs) {
1585 if (cur->name != NULL)
1586 xmlGenericError(xmlGenericErrorContext,
1587 "Removing element %s from catalog\n", cur->name);
1588 else
1589 xmlGenericError(xmlGenericErrorContext,
1590 "Removing element %s from catalog\n", cur->value);
1591 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001592 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001593 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001594 cur = cur->next;
1595 }
1596 return(ret);
1597}
1598
1599/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001600 * xmlCatalogXMLResolve:
1601 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001602 * @pubID: the public ID string
1603 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001604 *
1605 * Do a complete resolution lookup of an External Identifier for a
1606 * list of catalog entries.
1607 *
1608 * Implements (or tries to) 7.1. External Identifier Resolution
1609 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1610 *
1611 * Returns the URI of the resource or NULL if not found
1612 */
1613static xmlChar *
1614xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1615 const xmlChar *sysID) {
1616 xmlChar *ret = NULL;
1617 xmlCatalogEntryPtr cur;
1618 int haveDelegate = 0;
1619 int haveNext = 0;
1620
1621 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001622 * protection against loops
1623 */
1624 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001625 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1626 "Detected recursion in catalog %s\n",
1627 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001628 return(NULL);
1629 }
1630 catal->depth++;
1631
1632 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001633 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1634 */
1635 if (sysID != NULL) {
1636 xmlCatalogEntryPtr rewrite = NULL;
1637 int lenrewrite = 0, len;
1638 cur = catal;
1639 haveDelegate = 0;
1640 while (cur != NULL) {
1641 switch (cur->type) {
1642 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001643 if (xmlStrEqual(sysID, cur->name)) {
1644 if (xmlDebugCatalogs)
1645 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard890b5492006-02-23 08:14:00 +00001646 "Found system match %s, using %s\n",
1647 cur->name, cur->URL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001648 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001649 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001650 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001651 break;
1652 case XML_CATA_REWRITE_SYSTEM:
1653 len = xmlStrlen(cur->name);
1654 if ((len > lenrewrite) &&
1655 (!xmlStrncmp(sysID, cur->name, len))) {
1656 lenrewrite = len;
1657 rewrite = cur;
1658 }
1659 break;
1660 case XML_CATA_DELEGATE_SYSTEM:
1661 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1662 haveDelegate++;
1663 break;
1664 case XML_CATA_NEXT_CATALOG:
1665 haveNext++;
1666 break;
1667 default:
1668 break;
1669 }
1670 cur = cur->next;
1671 }
1672 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001673 if (xmlDebugCatalogs)
1674 xmlGenericError(xmlGenericErrorContext,
1675 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001676 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001677 if (ret != NULL)
1678 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001679 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001680 return(ret);
1681 }
1682 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001683 const xmlChar *delegates[MAX_DELEGATE];
1684 int nbList = 0, i;
1685
Daniel Veillardcda96922001-08-21 10:56:31 +00001686 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001687 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001688 * matches when the list was produced.
1689 */
1690 cur = catal;
1691 while (cur != NULL) {
1692 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1693 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001694 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001695 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001696 break;
1697 if (i < nbList) {
1698 cur = cur->next;
1699 continue;
1700 }
1701 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001702 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001703
Daniel Veillardcda96922001-08-21 10:56:31 +00001704 if (cur->children == NULL) {
1705 xmlFetchXMLCatalogFile(cur);
1706 }
1707 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001708 if (xmlDebugCatalogs)
1709 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001710 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001711 ret = xmlCatalogListXMLResolve(
1712 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001713 if (ret != NULL) {
1714 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001715 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001716 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001717 }
1718 }
1719 cur = cur->next;
1720 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001721 /*
1722 * Apply the cut algorithm explained in 4/
1723 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001724 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001725 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001726 }
1727 }
1728 /*
1729 * Then tries 5/ 6/ if a public ID is provided
1730 */
1731 if (pubID != NULL) {
1732 cur = catal;
1733 haveDelegate = 0;
1734 while (cur != NULL) {
1735 switch (cur->type) {
1736 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001737 if (xmlStrEqual(pubID, cur->name)) {
1738 if (xmlDebugCatalogs)
1739 xmlGenericError(xmlGenericErrorContext,
1740 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001741 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001742 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001743 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001744 break;
1745 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001746 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1747 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001748 haveDelegate++;
1749 break;
1750 case XML_CATA_NEXT_CATALOG:
1751 if (sysID == NULL)
1752 haveNext++;
1753 break;
1754 default:
1755 break;
1756 }
1757 cur = cur->next;
1758 }
1759 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001760 const xmlChar *delegates[MAX_DELEGATE];
1761 int nbList = 0, i;
1762
Daniel Veillardcda96922001-08-21 10:56:31 +00001763 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001764 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001765 * matches when the list was produced.
1766 */
1767 cur = catal;
1768 while (cur != NULL) {
1769 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001770 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1771 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001772
1773 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001774 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001775 break;
1776 if (i < nbList) {
1777 cur = cur->next;
1778 continue;
1779 }
1780 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001781 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001782
Daniel Veillardcda96922001-08-21 10:56:31 +00001783 if (cur->children == NULL) {
1784 xmlFetchXMLCatalogFile(cur);
1785 }
1786 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001787 if (xmlDebugCatalogs)
1788 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001789 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001790 ret = xmlCatalogListXMLResolve(
1791 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001792 if (ret != NULL) {
1793 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001794 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001795 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001796 }
1797 }
1798 cur = cur->next;
1799 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001800 /*
1801 * Apply the cut algorithm explained in 4/
1802 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001803 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001804 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001805 }
1806 }
1807 if (haveNext) {
1808 cur = catal;
1809 while (cur != NULL) {
1810 if (cur->type == XML_CATA_NEXT_CATALOG) {
1811 if (cur->children == NULL) {
1812 xmlFetchXMLCatalogFile(cur);
1813 }
1814 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001815 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001816 if (ret != NULL) {
1817 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001818 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001819 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001820 }
1821 }
1822 cur = cur->next;
1823 }
1824 }
1825
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001826 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001827 return(NULL);
1828}
1829
1830/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001831 * xmlCatalogXMLResolveURI:
1832 * @catal: a catalog list
1833 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001834 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001835 *
1836 * Do a complete resolution lookup of an External Identifier for a
1837 * list of catalog entries.
1838 *
1839 * Implements (or tries to) 7.2.2. URI Resolution
1840 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1841 *
1842 * Returns the URI of the resource or NULL if not found
1843 */
1844static xmlChar *
1845xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1846 xmlChar *ret = NULL;
1847 xmlCatalogEntryPtr cur;
1848 int haveDelegate = 0;
1849 int haveNext = 0;
1850 xmlCatalogEntryPtr rewrite = NULL;
1851 int lenrewrite = 0, len;
1852
1853 if (catal == NULL)
1854 return(NULL);
1855
1856 if (URI == NULL)
1857 return(NULL);
1858
1859 /*
1860 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1861 */
1862 cur = catal;
1863 haveDelegate = 0;
1864 while (cur != NULL) {
1865 switch (cur->type) {
1866 case XML_CATA_URI:
1867 if (xmlStrEqual(URI, cur->name)) {
1868 if (xmlDebugCatalogs)
1869 xmlGenericError(xmlGenericErrorContext,
1870 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001871 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001872 }
1873 break;
1874 case XML_CATA_REWRITE_URI:
1875 len = xmlStrlen(cur->name);
1876 if ((len > lenrewrite) &&
1877 (!xmlStrncmp(URI, cur->name, len))) {
1878 lenrewrite = len;
1879 rewrite = cur;
1880 }
1881 break;
1882 case XML_CATA_DELEGATE_URI:
1883 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1884 haveDelegate++;
1885 break;
1886 case XML_CATA_NEXT_CATALOG:
1887 haveNext++;
1888 break;
1889 default:
1890 break;
1891 }
1892 cur = cur->next;
1893 }
1894 if (rewrite != NULL) {
1895 if (xmlDebugCatalogs)
1896 xmlGenericError(xmlGenericErrorContext,
1897 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001898 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001899 if (ret != NULL)
1900 ret = xmlStrcat(ret, &URI[lenrewrite]);
1901 return(ret);
1902 }
1903 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001904 const xmlChar *delegates[MAX_DELEGATE];
1905 int nbList = 0, i;
1906
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001907 /*
1908 * Assume the entries have been sorted by decreasing substring
1909 * matches when the list was produced.
1910 */
1911 cur = catal;
1912 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001913 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1914 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001915 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001916 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001917 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001918 break;
1919 if (i < nbList) {
1920 cur = cur->next;
1921 continue;
1922 }
1923 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001924 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001925
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001926 if (cur->children == NULL) {
1927 xmlFetchXMLCatalogFile(cur);
1928 }
1929 if (cur->children != NULL) {
1930 if (xmlDebugCatalogs)
1931 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001932 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001933 ret = xmlCatalogListXMLResolveURI(
1934 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001935 if (ret != NULL)
1936 return(ret);
1937 }
1938 }
1939 cur = cur->next;
1940 }
1941 /*
1942 * Apply the cut algorithm explained in 4/
1943 */
1944 return(XML_CATAL_BREAK);
1945 }
1946 if (haveNext) {
1947 cur = catal;
1948 while (cur != NULL) {
1949 if (cur->type == XML_CATA_NEXT_CATALOG) {
1950 if (cur->children == NULL) {
1951 xmlFetchXMLCatalogFile(cur);
1952 }
1953 if (cur->children != NULL) {
1954 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1955 if (ret != NULL)
1956 return(ret);
1957 }
1958 }
1959 cur = cur->next;
1960 }
1961 }
1962
1963 return(NULL);
1964}
1965
1966/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001967 * xmlCatalogListXMLResolve:
1968 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001969 * @pubID: the public ID string
1970 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001971 *
1972 * Do a complete resolution lookup of an External Identifier for a
1973 * list of catalogs
1974 *
1975 * Implements (or tries to) 7.1. External Identifier Resolution
1976 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1977 *
1978 * Returns the URI of the resource or NULL if not found
1979 */
1980static xmlChar *
1981xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1982 const xmlChar *sysID) {
1983 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001984 xmlChar *urnID = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +00001985 xmlChar *normid;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001986
1987 if (catal == NULL)
1988 return(NULL);
1989 if ((pubID == NULL) && (sysID == NULL))
1990 return(NULL);
1991
Daniel Veillardc8155052004-07-16 09:03:08 +00001992 normid = xmlCatalogNormalizePublic(pubID);
1993 if (normid != NULL)
1994 pubID = (*normid != 0 ? normid : NULL);
1995
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001996 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1997 urnID = xmlCatalogUnWrapURN(pubID);
1998 if (xmlDebugCatalogs) {
1999 if (urnID == NULL)
2000 xmlGenericError(xmlGenericErrorContext,
2001 "Public URN ID %s expanded to NULL\n", pubID);
2002 else
2003 xmlGenericError(xmlGenericErrorContext,
2004 "Public URN ID expanded to %s\n", urnID);
2005 }
2006 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2007 if (urnID != NULL)
2008 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002009 if (normid != NULL)
2010 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002011 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002012 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002013 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2014 urnID = xmlCatalogUnWrapURN(sysID);
2015 if (xmlDebugCatalogs) {
2016 if (urnID == NULL)
2017 xmlGenericError(xmlGenericErrorContext,
2018 "System URN ID %s expanded to NULL\n", sysID);
2019 else
2020 xmlGenericError(xmlGenericErrorContext,
2021 "System URN ID expanded to %s\n", urnID);
2022 }
2023 if (pubID == NULL)
2024 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2025 else if (xmlStrEqual(pubID, urnID))
2026 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2027 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00002028 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002029 }
2030 if (urnID != NULL)
2031 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002032 if (normid != NULL)
2033 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002034 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002035 }
2036 while (catal != NULL) {
2037 if (catal->type == XML_CATA_CATALOG) {
2038 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002039 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00002040 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002041 if (catal->children != NULL) {
2042 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002043 if (ret != NULL) {
2044 if (normid != NULL)
2045 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002046 return(ret);
Daniel Veillardc8155052004-07-16 09:03:08 +00002047 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002048 }
Daniel Veillardcda96922001-08-21 10:56:31 +00002049 }
2050 catal = catal->next;
2051 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002052 if (normid != NULL)
2053 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002054 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00002055}
2056
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002057/**
2058 * xmlCatalogListXMLResolveURI:
2059 * @catal: a catalog list
2060 * @URI: the URI
2061 *
2062 * Do a complete resolution lookup of an URI for a list of catalogs
2063 *
2064 * Implements (or tries to) 7.2. URI Resolution
2065 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2066 *
2067 * Returns the URI of the resource or NULL if not found
2068 */
2069static xmlChar *
2070xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2071 xmlChar *ret = NULL;
2072 xmlChar *urnID = NULL;
2073
2074 if (catal == NULL)
2075 return(NULL);
2076 if (URI == NULL)
2077 return(NULL);
2078
2079 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2080 urnID = xmlCatalogUnWrapURN(URI);
2081 if (xmlDebugCatalogs) {
2082 if (urnID == NULL)
2083 xmlGenericError(xmlGenericErrorContext,
2084 "URN ID %s expanded to NULL\n", URI);
2085 else
2086 xmlGenericError(xmlGenericErrorContext,
2087 "URN ID expanded to %s\n", urnID);
2088 }
2089 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2090 if (urnID != NULL)
2091 xmlFree(urnID);
2092 return(ret);
2093 }
2094 while (catal != NULL) {
2095 if (catal->type == XML_CATA_CATALOG) {
2096 if (catal->children == NULL) {
2097 xmlFetchXMLCatalogFile(catal);
2098 }
2099 if (catal->children != NULL) {
2100 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2101 if (ret != NULL)
2102 return(ret);
2103 }
2104 }
2105 catal = catal->next;
2106 }
2107 return(ret);
2108}
2109
Daniel Veillard344cee72001-08-20 00:08:40 +00002110/************************************************************************
2111 * *
2112 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00002113 * *
2114 ************************************************************************/
2115
2116
2117#define RAW *cur
2118#define NEXT cur++;
2119#define SKIP(x) cur += x;
2120
William M. Brack272693c2003-11-14 16:20:34 +00002121#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002122
Daniel Veillard75b96822001-10-11 18:59:45 +00002123/**
2124 * xmlParseSGMLCatalogComment:
2125 * @cur: the current character
2126 *
2127 * Skip a comment in an SGML catalog
2128 *
2129 * Returns new current character
2130 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002131static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002132xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002133 if ((cur[0] != '-') || (cur[1] != '-'))
2134 return(cur);
2135 SKIP(2);
2136 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2137 NEXT;
2138 if (cur[0] == 0) {
2139 return(NULL);
2140 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002141 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002142}
2143
Daniel Veillard75b96822001-10-11 18:59:45 +00002144/**
2145 * xmlParseSGMLCatalogPubid:
2146 * @cur: the current character
2147 * @id: the return location
2148 *
2149 * Parse an SGML catalog ID
2150 *
2151 * Returns new current character and store the value in @id
2152 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002153static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002154xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002155 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002156 int len = 0;
2157 int size = 50;
2158 xmlChar stop;
2159 int count = 0;
2160
2161 *id = NULL;
2162
2163 if (RAW == '"') {
2164 NEXT;
2165 stop = '"';
2166 } else if (RAW == '\'') {
2167 NEXT;
2168 stop = '\'';
2169 } else {
2170 stop = ' ';
2171 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002172 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002173 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002174 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002175 return(NULL);
2176 }
William M. Brack76e95df2003-10-18 16:20:14 +00002177 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002178 if ((*cur == stop) && (stop != ' '))
2179 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002180 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002181 break;
2182 if (len + 1 >= size) {
2183 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002184 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2185 if (tmp == NULL) {
2186 xmlCatalogErrMemory("allocating public ID");
2187 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002188 return(NULL);
2189 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002190 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002191 }
2192 buf[len++] = *cur;
2193 count++;
2194 NEXT;
2195 }
2196 buf[len] = 0;
2197 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002198 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002199 xmlFree(buf);
2200 return(NULL);
2201 }
2202 } else {
2203 if (*cur != stop) {
2204 xmlFree(buf);
2205 return(NULL);
2206 }
2207 NEXT;
2208 }
2209 *id = buf;
2210 return(cur);
2211}
2212
Daniel Veillard75b96822001-10-11 18:59:45 +00002213/**
2214 * xmlParseSGMLCatalogName:
2215 * @cur: the current character
2216 * @name: the return location
2217 *
2218 * Parse an SGML catalog name
2219 *
2220 * Returns new current character and store the value in @name
2221 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002222static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002223xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002224 xmlChar buf[XML_MAX_NAMELEN + 5];
2225 int len = 0;
2226 int c;
2227
2228 *name = NULL;
2229
2230 /*
2231 * Handler for more complex cases
2232 */
2233 c = *cur;
2234 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2235 return(NULL);
2236 }
2237
2238 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2239 (c == '.') || (c == '-') ||
2240 (c == '_') || (c == ':'))) {
2241 buf[len++] = c;
2242 cur++;
2243 c = *cur;
2244 if (len >= XML_MAX_NAMELEN)
2245 return(NULL);
2246 }
2247 *name = xmlStrndup(buf, len);
2248 return(cur);
2249}
2250
Daniel Veillard75b96822001-10-11 18:59:45 +00002251/**
2252 * xmlGetSGMLCatalogEntryType:
2253 * @name: the entry name
2254 *
2255 * Get the Catalog entry type for a given SGML Catalog name
2256 *
2257 * Returns Catalog entry type
2258 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002259static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002260xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002261 xmlCatalogEntryType type = XML_CATA_NONE;
2262 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2263 type = SGML_CATA_SYSTEM;
2264 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2265 type = SGML_CATA_PUBLIC;
2266 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2267 type = SGML_CATA_DELEGATE;
2268 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2269 type = SGML_CATA_ENTITY;
2270 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2271 type = SGML_CATA_DOCTYPE;
2272 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2273 type = SGML_CATA_LINKTYPE;
2274 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2275 type = SGML_CATA_NOTATION;
2276 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2277 type = SGML_CATA_SGMLDECL;
2278 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2279 type = SGML_CATA_DOCUMENT;
2280 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2281 type = SGML_CATA_CATALOG;
2282 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2283 type = SGML_CATA_BASE;
Daniel Veillard344cee72001-08-20 00:08:40 +00002284 return(type);
2285}
2286
Daniel Veillard75b96822001-10-11 18:59:45 +00002287/**
2288 * xmlParseSGMLCatalog:
2289 * @catal: the SGML Catalog
2290 * @value: the content of the SGML Catalog serialization
2291 * @file: the filepath for the catalog
2292 * @super: should this be handled as a Super Catalog in which case
2293 * parsing is not recursive
2294 *
2295 * Parse an SGML catalog content and fill up the @catal hash table with
2296 * the new entries found.
2297 *
2298 * Returns 0 in case of success, -1 in case of error.
2299 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002300static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002301xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2302 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002303 const xmlChar *cur = value;
2304 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002305 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002306
2307 if ((cur == NULL) || (file == NULL))
2308 return(-1);
2309 base = xmlStrdup((const xmlChar *) file);
2310
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002311 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002312 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002313 if (cur[0] == 0)
2314 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002315 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002316 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002317 if (cur == NULL) {
2318 /* error */
2319 break;
2320 }
2321 } else {
2322 xmlChar *sysid = NULL;
2323 xmlChar *name = NULL;
2324 xmlCatalogEntryType type = XML_CATA_NONE;
2325
Daniel Veillardcda96922001-08-21 10:56:31 +00002326 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002327 if (name == NULL) {
2328 /* error */
2329 break;
2330 }
William M. Brack76e95df2003-10-18 16:20:14 +00002331 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002332 /* error */
2333 break;
2334 }
2335 SKIP_BLANKS;
2336 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002337 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002338 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002339 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002340 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002341 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002342 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002343 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002344 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002345 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002346 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002347 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002348 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002349 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002350 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002351 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002352 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002353 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002354 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002355 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002356 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002357 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002358 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2359 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002360 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002361 if (name == NULL) {
2362 /* error */
2363 break;
2364 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002365 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002366 continue;
2367 }
2368 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002369 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002370
2371 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002372 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002373 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002374 type = SGML_CATA_PENTITY;
2375 case SGML_CATA_PENTITY:
2376 case SGML_CATA_DOCTYPE:
2377 case SGML_CATA_LINKTYPE:
2378 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002379 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002380 if (cur == NULL) {
2381 /* error */
2382 break;
2383 }
William M. Brack76e95df2003-10-18 16:20:14 +00002384 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002385 /* error */
2386 break;
2387 }
2388 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002389 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002390 if (cur == NULL) {
2391 /* error */
2392 break;
2393 }
2394 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002395 case SGML_CATA_PUBLIC:
2396 case SGML_CATA_SYSTEM:
2397 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002398 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002399 if (cur == NULL) {
2400 /* error */
2401 break;
2402 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002403 if (type != SGML_CATA_SYSTEM) {
2404 xmlChar *normid;
2405
2406 normid = xmlCatalogNormalizePublic(name);
2407 if (normid != NULL) {
2408 if (name != NULL)
2409 xmlFree(name);
2410 if (*normid != 0)
2411 name = normid;
2412 else {
2413 xmlFree(normid);
2414 name = NULL;
2415 }
2416 }
2417 }
William M. Brack76e95df2003-10-18 16:20:14 +00002418 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002419 /* error */
2420 break;
2421 }
2422 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002423 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002424 if (cur == NULL) {
2425 /* error */
2426 break;
2427 }
2428 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002429 case SGML_CATA_BASE:
2430 case SGML_CATA_CATALOG:
2431 case SGML_CATA_DOCUMENT:
2432 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002433 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002434 if (cur == NULL) {
2435 /* error */
2436 break;
2437 }
2438 break;
2439 default:
2440 break;
2441 }
2442 if (cur == NULL) {
2443 if (name != NULL)
2444 xmlFree(name);
2445 if (sysid != NULL)
2446 xmlFree(sysid);
2447 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002448 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002449 if (base != NULL)
2450 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002451 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002452 } else if ((type == SGML_CATA_PUBLIC) ||
2453 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002454 xmlChar *filename;
2455
2456 filename = xmlBuildURI(sysid, base);
2457 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002458 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002459
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002460 entry = xmlNewCatalogEntry(type, name, filename,
William M. Brackb7b54de2004-10-06 16:38:01 +00002461 NULL, XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002462 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002463 if (res < 0) {
2464 xmlFreeCatalogEntry(entry);
2465 }
2466 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002467 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002468
Daniel Veillard344cee72001-08-20 00:08:40 +00002469 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002470 if (super) {
2471 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002472
Daniel Veillardc853b322001-11-06 15:24:37 +00002473 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002474 XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002475 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002476 if (res < 0) {
2477 xmlFreeCatalogEntry(entry);
2478 }
2479 } else {
2480 xmlChar *filename;
2481
2482 filename = xmlBuildURI(sysid, base);
2483 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002484 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002485 xmlFree(filename);
2486 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002487 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002488 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002489 /*
2490 * drop anything else we won't handle it
2491 */
2492 if (name != NULL)
2493 xmlFree(name);
2494 if (sysid != NULL)
2495 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002496 }
2497 }
2498 if (base != NULL)
2499 xmlFree(base);
2500 if (cur == NULL)
2501 return(-1);
2502 return(0);
2503}
2504
Daniel Veillard75b96822001-10-11 18:59:45 +00002505/************************************************************************
2506 * *
2507 * SGML Catalog handling *
2508 * *
2509 ************************************************************************/
2510
Daniel Veillardcda96922001-08-21 10:56:31 +00002511/**
2512 * xmlCatalogGetSGMLPublic:
2513 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002514 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002515 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002516 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002517 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002518 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002519 */
2520static const xmlChar *
2521xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2522 xmlCatalogEntryPtr entry;
Daniel Veillardc8155052004-07-16 09:03:08 +00002523 xmlChar *normid;
Daniel Veillardcda96922001-08-21 10:56:31 +00002524
2525 if (catal == NULL)
2526 return(NULL);
2527
Daniel Veillardc8155052004-07-16 09:03:08 +00002528 normid = xmlCatalogNormalizePublic(pubID);
2529 if (normid != NULL)
2530 pubID = (*normid != 0 ? normid : NULL);
2531
Daniel Veillardcda96922001-08-21 10:56:31 +00002532 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002533 if (entry == NULL) {
2534 if (normid != NULL)
2535 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002536 return(NULL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002537 }
2538 if (entry->type == SGML_CATA_PUBLIC) {
2539 if (normid != NULL)
2540 xmlFree(normid);
Daniel Veillardc853b322001-11-06 15:24:37 +00002541 return(entry->URL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002542 }
2543 if (normid != NULL)
2544 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002545 return(NULL);
2546}
2547
2548/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002549 * xmlCatalogGetSGMLSystem:
2550 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002551 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002552 *
2553 * Try to lookup the catalog local reference for a system ID
2554 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002555 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002556 */
2557static const xmlChar *
2558xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2559 xmlCatalogEntryPtr entry;
2560
2561 if (catal == NULL)
2562 return(NULL);
2563
2564 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2565 if (entry == NULL)
2566 return(NULL);
2567 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002568 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002569 return(NULL);
2570}
2571
2572/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002573 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002574 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002575 * @pubID: the public ID string
2576 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002577 *
2578 * Do a complete resolution lookup of an External Identifier
2579 *
2580 * Returns the URI of the resource or NULL if not found
2581 */
2582static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002583xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2584 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002585 const xmlChar *ret = NULL;
2586
Daniel Veillard75b96822001-10-11 18:59:45 +00002587 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002588 return(NULL);
2589
2590 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002591 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002592 if (ret != NULL)
2593 return(ret);
2594 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002595 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002596 return(NULL);
2597}
2598
Daniel Veillarda7374592001-05-10 14:17:55 +00002599/************************************************************************
2600 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002601 * Specific Public interfaces *
2602 * *
2603 ************************************************************************/
2604
2605/**
2606 * xmlLoadSGMLSuperCatalog:
2607 * @filename: a file path
2608 *
2609 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2610 * references. This is only needed for manipulating SGML Super Catalogs
2611 * like adding and removing CATALOG or DELEGATE entries.
2612 *
2613 * Returns the catalog parsed or NULL in case of error
2614 */
2615xmlCatalogPtr
2616xmlLoadSGMLSuperCatalog(const char *filename)
2617{
2618 xmlChar *content;
2619 xmlCatalogPtr catal;
2620 int ret;
2621
2622 content = xmlLoadFileContent(filename);
2623 if (content == NULL)
2624 return(NULL);
2625
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002626 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002627 if (catal == NULL) {
2628 xmlFree(content);
2629 return(NULL);
2630 }
2631
2632 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2633 xmlFree(content);
2634 if (ret < 0) {
2635 xmlFreeCatalog(catal);
2636 return(NULL);
2637 }
2638 return (catal);
2639}
2640
2641/**
2642 * xmlLoadACatalog:
2643 * @filename: a file path
2644 *
2645 * Load the catalog and build the associated data structures.
2646 * This can be either an XML Catalog or an SGML Catalog
2647 * It will recurse in SGML CATALOG entries. On the other hand XML
2648 * Catalogs are not handled recursively.
2649 *
2650 * Returns the catalog parsed or NULL in case of error
2651 */
2652xmlCatalogPtr
2653xmlLoadACatalog(const char *filename)
2654{
2655 xmlChar *content;
2656 xmlChar *first;
2657 xmlCatalogPtr catal;
2658 int ret;
2659
2660 content = xmlLoadFileContent(filename);
2661 if (content == NULL)
2662 return(NULL);
2663
2664
2665 first = content;
2666
2667 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2668 (!(((*first >= 'A') && (*first <= 'Z')) ||
2669 ((*first >= 'a') && (*first <= 'z')))))
2670 first++;
2671
2672 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002673 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002674 if (catal == NULL) {
2675 xmlFree(content);
2676 return(NULL);
2677 }
2678 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2679 if (ret < 0) {
2680 xmlFreeCatalog(catal);
2681 xmlFree(content);
2682 return(NULL);
2683 }
2684 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002685 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002686 if (catal == NULL) {
2687 xmlFree(content);
2688 return(NULL);
2689 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002690 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002691 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002692 }
2693 xmlFree(content);
2694 return (catal);
2695}
2696
2697/**
2698 * xmlExpandCatalog:
2699 * @catal: a catalog
2700 * @filename: a file path
2701 *
2702 * Load the catalog and expand the existing catal structure.
2703 * This can be either an XML Catalog or an SGML Catalog
2704 *
2705 * Returns 0 in case of success, -1 in case of error
2706 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002707static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002708xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2709{
Daniel Veillard75b96822001-10-11 18:59:45 +00002710 int ret;
2711
2712 if ((catal == NULL) || (filename == NULL))
2713 return(-1);
2714
Daniel Veillard75b96822001-10-11 18:59:45 +00002715
2716 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002717 xmlChar *content;
2718
2719 content = xmlLoadFileContent(filename);
2720 if (content == NULL)
2721 return(-1);
2722
Daniel Veillard75b96822001-10-11 18:59:45 +00002723 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2724 if (ret < 0) {
2725 xmlFree(content);
2726 return(-1);
2727 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002728 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002729 } else {
2730 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002731 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002732 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002733
Daniel Veillard75b96822001-10-11 18:59:45 +00002734 cur = catal->xml;
2735 if (cur == NULL) {
2736 catal->xml = tmp;
2737 } else {
2738 while (cur->next != NULL) cur = cur->next;
2739 cur->next = tmp;
2740 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002741 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002742 return (0);
2743}
2744
2745/**
2746 * xmlACatalogResolveSystem:
2747 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002748 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002749 *
2750 * Try to lookup the catalog resource for a system ID
2751 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002752 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002753 * must be freed by the caller.
2754 */
2755xmlChar *
2756xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2757 xmlChar *ret = NULL;
2758
2759 if ((sysID == NULL) || (catal == NULL))
2760 return(NULL);
2761
2762 if (xmlDebugCatalogs)
2763 xmlGenericError(xmlGenericErrorContext,
2764 "Resolve sysID %s\n", sysID);
2765
2766 if (catal->type == XML_XML_CATALOG_TYPE) {
2767 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2768 if (ret == XML_CATAL_BREAK)
2769 ret = NULL;
2770 } else {
2771 const xmlChar *sgml;
2772
2773 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2774 if (sgml != NULL)
2775 ret = xmlStrdup(sgml);
2776 }
2777 return(ret);
2778}
2779
2780/**
2781 * xmlACatalogResolvePublic:
2782 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002783 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002784 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002785 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002786 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002787 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002788 * must be freed by the caller.
2789 */
2790xmlChar *
2791xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2792 xmlChar *ret = NULL;
2793
2794 if ((pubID == NULL) || (catal == NULL))
2795 return(NULL);
2796
2797 if (xmlDebugCatalogs)
2798 xmlGenericError(xmlGenericErrorContext,
2799 "Resolve pubID %s\n", pubID);
2800
2801 if (catal->type == XML_XML_CATALOG_TYPE) {
2802 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2803 if (ret == XML_CATAL_BREAK)
2804 ret = NULL;
2805 } else {
2806 const xmlChar *sgml;
2807
2808 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2809 if (sgml != NULL)
2810 ret = xmlStrdup(sgml);
2811 }
2812 return(ret);
2813}
2814
2815/**
2816 * xmlACatalogResolve:
2817 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002818 * @pubID: the public ID string
2819 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002820 *
2821 * Do a complete resolution lookup of an External Identifier
2822 *
2823 * Returns the URI of the resource or NULL if not found, it must be freed
2824 * by the caller.
2825 */
2826xmlChar *
2827xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2828 const xmlChar * sysID)
2829{
2830 xmlChar *ret = NULL;
2831
2832 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2833 return (NULL);
2834
2835 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002836 if ((pubID != NULL) && (sysID != NULL)) {
2837 xmlGenericError(xmlGenericErrorContext,
2838 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2839 } else if (pubID != NULL) {
2840 xmlGenericError(xmlGenericErrorContext,
2841 "Resolve: pubID %s\n", pubID);
2842 } else {
2843 xmlGenericError(xmlGenericErrorContext,
2844 "Resolve: sysID %s\n", sysID);
2845 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002846 }
2847
2848 if (catal->type == XML_XML_CATALOG_TYPE) {
2849 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2850 if (ret == XML_CATAL_BREAK)
2851 ret = NULL;
2852 } else {
2853 const xmlChar *sgml;
2854
2855 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2856 if (sgml != NULL)
2857 ret = xmlStrdup(sgml);
2858 }
2859 return (ret);
2860}
2861
2862/**
2863 * xmlACatalogResolveURI:
2864 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002865 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002866 *
2867 * Do a complete resolution lookup of an URI
2868 *
2869 * Returns the URI of the resource or NULL if not found, it must be freed
2870 * by the caller.
2871 */
2872xmlChar *
2873xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2874 xmlChar *ret = NULL;
2875
2876 if ((URI == NULL) || (catal == NULL))
2877 return(NULL);
2878
Daniel Veillardb44025c2001-10-11 22:55:55 +00002879 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002880 xmlGenericError(xmlGenericErrorContext,
2881 "Resolve URI %s\n", URI);
2882
2883 if (catal->type == XML_XML_CATALOG_TYPE) {
2884 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2885 if (ret == XML_CATAL_BREAK)
2886 ret = NULL;
2887 } else {
2888 const xmlChar *sgml;
2889
2890 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2891 if (sgml != NULL)
2892 sgml = xmlStrdup(sgml);
2893 }
2894 return(ret);
2895}
2896
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002897#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002898/**
2899 * xmlACatalogDump:
2900 * @catal: a Catalog
2901 * @out: the file.
2902 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002903 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002904 */
2905void
2906xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002907 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002908 return;
2909
2910 if (catal->type == XML_XML_CATALOG_TYPE) {
2911 xmlDumpXMLCatalog(out, catal->xml);
2912 } else {
2913 xmlHashScan(catal->sgml,
2914 (xmlHashScanner) xmlCatalogDumpEntry, out);
2915 }
2916}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002917#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002918
2919/**
2920 * xmlACatalogAdd:
2921 * @catal: a Catalog
2922 * @type: the type of record to add to the catalog
2923 * @orig: the system, public or prefix to match
2924 * @replace: the replacement value for the match
2925 *
2926 * Add an entry in the catalog, it may overwrite existing but
2927 * different entries.
2928 *
2929 * Returns 0 if successful, -1 otherwise
2930 */
2931int
2932xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2933 const xmlChar * orig, const xmlChar * replace)
2934{
2935 int res = -1;
2936
2937 if (catal == NULL)
2938 return(-1);
2939
2940 if (catal->type == XML_XML_CATALOG_TYPE) {
2941 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2942 } else {
2943 xmlCatalogEntryType cattype;
2944
2945 cattype = xmlGetSGMLCatalogEntryType(type);
2946 if (cattype != XML_CATA_NONE) {
2947 xmlCatalogEntryPtr entry;
2948
Daniel Veillardc853b322001-11-06 15:24:37 +00002949 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002950 XML_CATA_PREFER_NONE, NULL);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002951 if (catal->sgml == NULL)
2952 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002953 res = xmlHashAddEntry(catal->sgml, orig, entry);
2954 }
2955 }
2956 return (res);
2957}
2958
2959/**
2960 * xmlACatalogRemove:
2961 * @catal: a Catalog
2962 * @value: the value to remove
2963 *
2964 * Remove an entry from the catalog
2965 *
2966 * Returns the number of entries removed if successful, -1 otherwise
2967 */
2968int
2969xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2970 int res = -1;
2971
2972 if ((catal == NULL) || (value == NULL))
2973 return(-1);
2974
2975 if (catal->type == XML_XML_CATALOG_TYPE) {
2976 res = xmlDelXMLCatalog(catal->xml, value);
2977 } else {
2978 res = xmlHashRemoveEntry(catal->sgml, value,
2979 (xmlHashDeallocator) xmlFreeCatalogEntry);
2980 if (res == 0)
2981 res = 1;
2982 }
2983 return(res);
2984}
2985
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002986/**
2987 * xmlNewCatalog:
2988 * @sgml: should this create an SGML catalog
2989 *
2990 * create a new Catalog.
2991 *
2992 * Returns the xmlCatalogPtr or NULL in case of error
2993 */
2994xmlCatalogPtr
2995xmlNewCatalog(int sgml) {
2996 xmlCatalogPtr catal = NULL;
2997
2998 if (sgml) {
2999 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3000 xmlCatalogDefaultPrefer);
3001 if ((catal != NULL) && (catal->sgml == NULL))
3002 catal->sgml = xmlHashCreate(10);
3003 } else
3004 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3005 xmlCatalogDefaultPrefer);
3006 return(catal);
3007}
3008
3009/**
3010 * xmlCatalogIsEmpty:
3011 * @catal: should this create an SGML catalog
3012 *
3013 * Check is a catalog is empty
3014 *
3015 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3016 */
3017int
3018xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3019 if (catal == NULL)
3020 return(-1);
3021
3022 if (catal->type == XML_XML_CATALOG_TYPE) {
3023 if (catal->xml == NULL)
3024 return(1);
3025 if ((catal->xml->type != XML_CATA_CATALOG) &&
3026 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3027 return(-1);
3028 if (catal->xml->children == NULL)
3029 return(1);
3030 return(0);
3031 } else {
3032 int res;
3033
3034 if (catal->sgml == NULL)
3035 return(1);
3036 res = xmlHashSize(catal->sgml);
3037 if (res == 0)
3038 return(1);
3039 if (res < 0)
3040 return(-1);
3041 }
3042 return(0);
3043}
3044
Daniel Veillard75b96822001-10-11 18:59:45 +00003045/************************************************************************
3046 * *
3047 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00003048 * *
3049 ************************************************************************/
3050
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003051/**
Daniel Veillard81463942001-10-16 12:34:39 +00003052 * xmlInitializeCatalogData:
3053 *
3054 * Do the catalog initialization only of global data, doesn't try to load
3055 * any catalog actually.
3056 * this function is not thread safe, catalog initialization should
3057 * preferably be done once at startup
3058 */
3059static void
3060xmlInitializeCatalogData(void) {
3061 if (xmlCatalogInitialized != 0)
3062 return;
3063
3064 if (getenv("XML_DEBUG_CATALOG"))
3065 xmlDebugCatalogs = 1;
3066 xmlCatalogMutex = xmlNewRMutex();
3067
3068 xmlCatalogInitialized = 1;
3069}
3070/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003071 * xmlInitializeCatalog:
3072 *
3073 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00003074 * this function is not thread safe, catalog initialization should
3075 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003076 */
3077void
3078xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003079 if (xmlCatalogInitialized != 0)
3080 return;
3081
Daniel Veillard81463942001-10-16 12:34:39 +00003082 xmlInitializeCatalogData();
3083 xmlRMutexLock(xmlCatalogMutex);
3084
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003085 if (getenv("XML_DEBUG_CATALOG"))
3086 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00003087
Daniel Veillard75b96822001-10-11 18:59:45 +00003088 if (xmlDefaultCatalog == NULL) {
3089 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003090 char *path;
3091 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00003092 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003093 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00003094
Daniel Veillardb44025c2001-10-11 22:55:55 +00003095 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003096 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003097#if defined(_WIN32) && defined(_MSC_VER)
3098 {
3099 void* hmodule;
3100 hmodule = GetModuleHandleA("libxml2.dll");
3101 if (hmodule == NULL)
3102 hmodule = GetModuleHandleA(NULL);
3103 if (hmodule != NULL) {
3104 char buf[256];
3105 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3106 if (len != 0) {
3107 char* p = &(buf[len]);
3108 while (*p != '\\' && p > buf)
3109 p--;
3110 if (p != buf) {
3111 xmlChar* uri;
3112 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3113 uri = xmlCanonicPath(buf);
3114 if (uri != NULL) {
3115 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3116 xmlFree(uri);
3117 }
3118 }
3119 }
3120 }
3121 catalogs = XML_XML_DEFAULT_CATALOG;
3122 }
3123#else
Daniel Veillard75b96822001-10-11 18:59:45 +00003124 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00003125#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00003126
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003127 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3128 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003129 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003130 /* the XML_CATALOG_FILES envvar is allowed to contain a
3131 space-separated list of entries. */
3132 cur = catalogs;
3133 nextent = &catal->xml;
3134 while (*cur != '\0') {
William M. Brack68aca052003-10-11 15:22:13 +00003135 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003136 cur++;
3137 if (*cur != 0) {
3138 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003139 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003140 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00003141 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003142 if (path != NULL) {
3143 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003144 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003145 if (*nextent != NULL)
3146 nextent = &((*nextent)->next);
3147 xmlFree(path);
3148 }
3149 }
3150 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003151 xmlDefaultCatalog = catal;
3152 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003153 }
3154
Daniel Veillard81463942001-10-16 12:34:39 +00003155 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003156}
3157
Daniel Veillard82d75332001-10-08 15:01:59 +00003158
3159/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003160 * xmlLoadCatalog:
3161 * @filename: a file path
3162 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003163 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003164 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003165 * this function is not thread safe, catalog initialization should
3166 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003167 *
3168 * Returns 0 in case of success -1 in case of error
3169 */
3170int
Daniel Veillard16756b62001-10-01 07:36:25 +00003171xmlLoadCatalog(const char *filename)
3172{
Daniel Veillard75b96822001-10-11 18:59:45 +00003173 int ret;
3174 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003175
Daniel Veillard81463942001-10-16 12:34:39 +00003176 if (!xmlCatalogInitialized)
3177 xmlInitializeCatalogData();
3178
3179 xmlRMutexLock(xmlCatalogMutex);
3180
Daniel Veillard75b96822001-10-11 18:59:45 +00003181 if (xmlDefaultCatalog == NULL) {
3182 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003183 if (catal == NULL) {
3184 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003185 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003186 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003187
Daniel Veillard75b96822001-10-11 18:59:45 +00003188 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003189 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003190 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003191 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003192
Daniel Veillard75b96822001-10-11 18:59:45 +00003193 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003194 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003195 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003196}
3197
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003198/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003199 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003200 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003201 *
3202 * Load the catalogs and makes their definitions effective for the default
3203 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003204 * this function is not thread safe, catalog initialization should
3205 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003206 */
3207void
3208xmlLoadCatalogs(const char *pathss) {
3209 const char *cur;
3210 const char *paths;
3211 xmlChar *path;
3212
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003213 if (pathss == NULL)
3214 return;
3215
Daniel Veillard81418e32001-05-22 15:08:55 +00003216 cur = pathss;
Daniel Veillard2728f842006-03-09 16:49:24 +00003217 while (*cur != 0) {
William M. Brack68aca052003-10-11 15:22:13 +00003218 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003219 if (*cur != 0) {
3220 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003221 while ((*cur != 0) && (*cur != ':') && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003222 cur++;
3223 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3224 if (path != NULL) {
3225 xmlLoadCatalog((const char *) path);
3226 xmlFree(path);
3227 }
3228 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003229 while (*cur == ':')
3230 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003231 }
3232}
3233
Daniel Veillarda7374592001-05-10 14:17:55 +00003234/**
3235 * xmlCatalogCleanup:
3236 *
3237 * Free up all the memory associated with catalogs
3238 */
3239void
3240xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003241 if (xmlCatalogInitialized == 0)
3242 return;
3243
Daniel Veillard81463942001-10-16 12:34:39 +00003244 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003245 if (xmlDebugCatalogs)
3246 xmlGenericError(xmlGenericErrorContext,
3247 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003248 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003249 xmlHashFree(xmlCatalogXMLFiles,
3250 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003251 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003252 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003253 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003254 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003255 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003256 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003257 xmlRMutexUnlock(xmlCatalogMutex);
3258 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003259}
3260
3261/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003262 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003263 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003264 *
3265 * Try to lookup the catalog resource for a system ID
3266 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003267 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003268 * must be freed by the caller.
3269 */
3270xmlChar *
3271xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003272 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003273
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003274 if (!xmlCatalogInitialized)
3275 xmlInitializeCatalog();
3276
Daniel Veillard75b96822001-10-11 18:59:45 +00003277 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3278 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003279}
3280
3281/**
3282 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003283 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003284 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003285 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003286 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003287 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003288 * must be freed by the caller.
3289 */
3290xmlChar *
3291xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003292 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003293
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003294 if (!xmlCatalogInitialized)
3295 xmlInitializeCatalog();
3296
Daniel Veillard75b96822001-10-11 18:59:45 +00003297 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3298 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003299}
Daniel Veillard344cee72001-08-20 00:08:40 +00003300
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003301/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003302 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003303 * @pubID: the public ID string
3304 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003305 *
3306 * Do a complete resolution lookup of an External Identifier
3307 *
3308 * Returns the URI of the resource or NULL if not found, it must be freed
3309 * by the caller.
3310 */
3311xmlChar *
3312xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003313 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003314
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003315 if (!xmlCatalogInitialized)
3316 xmlInitializeCatalog();
3317
Daniel Veillard75b96822001-10-11 18:59:45 +00003318 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3319 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003320}
3321
3322/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003323 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003324 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003325 *
3326 * Do a complete resolution lookup of an URI
3327 *
3328 * Returns the URI of the resource or NULL if not found, it must be freed
3329 * by the caller.
3330 */
3331xmlChar *
3332xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003333 xmlChar *ret;
3334
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003335 if (!xmlCatalogInitialized)
3336 xmlInitializeCatalog();
3337
Daniel Veillard75b96822001-10-11 18:59:45 +00003338 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3339 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003340}
3341
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003342#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003343/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003344 * xmlCatalogDump:
3345 * @out: the file.
3346 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003347 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003348 */
3349void
3350xmlCatalogDump(FILE *out) {
3351 if (out == NULL)
3352 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003353
Daniel Veillard75b96822001-10-11 18:59:45 +00003354 if (!xmlCatalogInitialized)
3355 xmlInitializeCatalog();
3356
3357 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003358}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003359#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003360
3361/**
3362 * xmlCatalogAdd:
3363 * @type: the type of record to add to the catalog
3364 * @orig: the system, public or prefix to match
3365 * @replace: the replacement value for the match
3366 *
3367 * Add an entry in the catalog, it may overwrite existing but
3368 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003369 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003370 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003371 *
3372 * Returns 0 if successful, -1 otherwise
3373 */
3374int
3375xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3376 int res = -1;
3377
Daniel Veillard81463942001-10-16 12:34:39 +00003378 if (!xmlCatalogInitialized)
3379 xmlInitializeCatalogData();
3380
3381 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003382 /*
3383 * Specific case where one want to override the default catalog
3384 * put in place by xmlInitializeCatalog();
3385 */
3386 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003387 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003388 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003389 xmlCatalogDefaultPrefer);
3390 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003391 orig, NULL, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003392
Daniel Veillard81463942001-10-16 12:34:39 +00003393 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003394 return(0);
3395 }
3396
Daniel Veillard75b96822001-10-11 18:59:45 +00003397 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003398 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003399 return(res);
3400}
3401
3402/**
3403 * xmlCatalogRemove:
3404 * @value: the value to remove
3405 *
3406 * Remove an entry from the catalog
3407 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003408 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003409 */
3410int
3411xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003412 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003413
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003414 if (!xmlCatalogInitialized)
3415 xmlInitializeCatalog();
3416
Daniel Veillard81463942001-10-16 12:34:39 +00003417 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003418 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003419 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003420 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003421}
3422
3423/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003424 * xmlCatalogConvert:
3425 *
3426 * Convert all the SGML catalog entries as XML ones
3427 *
3428 * Returns the number of entries converted if successful, -1 otherwise
3429 */
3430int
3431xmlCatalogConvert(void) {
3432 int res = -1;
3433
3434 if (!xmlCatalogInitialized)
3435 xmlInitializeCatalog();
3436
Daniel Veillard81463942001-10-16 12:34:39 +00003437 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003438 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003439 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003440 return(res);
3441}
3442
Daniel Veillard75b96822001-10-11 18:59:45 +00003443/************************************************************************
3444 * *
3445 * Public interface manipulating the common preferences *
3446 * *
3447 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003448
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003449/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003450 * xmlCatalogGetDefaults:
3451 *
3452 * Used to get the user preference w.r.t. to what catalogs should
3453 * be accepted
3454 *
3455 * Returns the current xmlCatalogAllow value
3456 */
3457xmlCatalogAllow
3458xmlCatalogGetDefaults(void) {
3459 return(xmlCatalogDefaultAllow);
3460}
3461
3462/**
3463 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003464 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003465 *
3466 * Used to set the user preference w.r.t. to what catalogs should
3467 * be accepted
3468 */
3469void
3470xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003471 if (xmlDebugCatalogs) {
3472 switch (allow) {
3473 case XML_CATA_ALLOW_NONE:
3474 xmlGenericError(xmlGenericErrorContext,
3475 "Disabling catalog usage\n");
3476 break;
3477 case XML_CATA_ALLOW_GLOBAL:
3478 xmlGenericError(xmlGenericErrorContext,
3479 "Allowing only global catalogs\n");
3480 break;
3481 case XML_CATA_ALLOW_DOCUMENT:
3482 xmlGenericError(xmlGenericErrorContext,
3483 "Allowing only catalogs from the document\n");
3484 break;
3485 case XML_CATA_ALLOW_ALL:
3486 xmlGenericError(xmlGenericErrorContext,
3487 "Allowing all catalogs\n");
3488 break;
3489 }
3490 }
3491 xmlCatalogDefaultAllow = allow;
3492}
3493
3494/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003495 * xmlCatalogSetDefaultPrefer:
3496 * @prefer: the default preference for delegation
3497 *
3498 * Allows to set the preference between public and system for deletion
3499 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003500 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003501 *
3502 * Returns the previous value of the default preference for delegation
3503 */
3504xmlCatalogPrefer
3505xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3506 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3507
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003508 if (prefer == XML_CATA_PREFER_NONE)
3509 return(ret);
3510
3511 if (xmlDebugCatalogs) {
3512 switch (prefer) {
3513 case XML_CATA_PREFER_PUBLIC:
3514 xmlGenericError(xmlGenericErrorContext,
3515 "Setting catalog preference to PUBLIC\n");
3516 break;
3517 case XML_CATA_PREFER_SYSTEM:
3518 xmlGenericError(xmlGenericErrorContext,
3519 "Setting catalog preference to SYSTEM\n");
3520 break;
3521 case XML_CATA_PREFER_NONE:
3522 break;
3523 }
3524 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003525 xmlCatalogDefaultPrefer = prefer;
3526 return(ret);
3527}
3528
3529/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003530 * xmlCatalogSetDebug:
3531 * @level: the debug level of catalogs required
3532 *
3533 * Used to set the debug level for catalog operation, 0 disable
3534 * debugging, 1 enable it
3535 *
3536 * Returns the previous value of the catalog debugging level
3537 */
3538int
3539xmlCatalogSetDebug(int level) {
3540 int ret = xmlDebugCatalogs;
3541
3542 if (level <= 0)
3543 xmlDebugCatalogs = 0;
3544 else
3545 xmlDebugCatalogs = level;
3546 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003547}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003548
Daniel Veillard75b96822001-10-11 18:59:45 +00003549/************************************************************************
3550 * *
3551 * Minimal interfaces used for per-document catalogs by the parser *
3552 * *
3553 ************************************************************************/
3554
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003555/**
3556 * xmlCatalogFreeLocal:
3557 * @catalogs: a document's list of catalogs
3558 *
3559 * Free up the memory associated to the catalog list
3560 */
3561void
3562xmlCatalogFreeLocal(void *catalogs) {
3563 xmlCatalogEntryPtr catal;
3564
Daniel Veillard81463942001-10-16 12:34:39 +00003565 if (!xmlCatalogInitialized)
3566 xmlInitializeCatalog();
3567
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003568 catal = (xmlCatalogEntryPtr) catalogs;
3569 if (catal != NULL)
3570 xmlFreeCatalogEntryList(catal);
3571}
3572
3573
3574/**
3575 * xmlCatalogAddLocal:
3576 * @catalogs: a document's list of catalogs
3577 * @URL: the URL to a new local catalog
3578 *
3579 * Add the new entry to the catalog list
3580 *
3581 * Returns the updated list
3582 */
3583void *
3584xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3585 xmlCatalogEntryPtr catal, add;
3586
3587 if (!xmlCatalogInitialized)
3588 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003589
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003590 if (URL == NULL)
3591 return(catalogs);
3592
3593 if (xmlDebugCatalogs)
3594 xmlGenericError(xmlGenericErrorContext,
3595 "Adding document catalog %s\n", URL);
3596
Daniel Veillardc853b322001-11-06 15:24:37 +00003597 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003598 xmlCatalogDefaultPrefer, NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003599 if (add == NULL)
3600 return(catalogs);
3601
3602 catal = (xmlCatalogEntryPtr) catalogs;
3603 if (catal == NULL)
3604 return((void *) add);
3605
3606 while (catal->next != NULL)
3607 catal = catal->next;
3608 catal->next = add;
3609 return(catalogs);
3610}
3611
3612/**
3613 * xmlCatalogLocalResolve:
3614 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003615 * @pubID: the public ID string
3616 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003617 *
3618 * Do a complete resolution lookup of an External Identifier using a
3619 * document's private catalog list
3620 *
3621 * Returns the URI of the resource or NULL if not found, it must be freed
3622 * by the caller.
3623 */
3624xmlChar *
3625xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3626 const xmlChar *sysID) {
3627 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003628 xmlChar *ret;
3629
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003630 if (!xmlCatalogInitialized)
3631 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003632
Daniel Veillard81463942001-10-16 12:34:39 +00003633 if ((pubID == NULL) && (sysID == NULL))
3634 return(NULL);
3635
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003636 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003637 if ((pubID != NULL) && (sysID != NULL)) {
3638 xmlGenericError(xmlGenericErrorContext,
3639 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3640 } else if (pubID != NULL) {
3641 xmlGenericError(xmlGenericErrorContext,
3642 "Local Resolve: pubID %s\n", pubID);
3643 } else {
3644 xmlGenericError(xmlGenericErrorContext,
3645 "Local Resolve: sysID %s\n", sysID);
3646 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003647 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003648
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003649 catal = (xmlCatalogEntryPtr) catalogs;
3650 if (catal == NULL)
3651 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003652 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3653 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3654 return(ret);
3655 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003656}
3657
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003658/**
3659 * xmlCatalogLocalResolveURI:
3660 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003661 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003662 *
3663 * Do a complete resolution lookup of an URI using a
3664 * document's private catalog list
3665 *
3666 * Returns the URI of the resource or NULL if not found, it must be freed
3667 * by the caller.
3668 */
3669xmlChar *
3670xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3671 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003672 xmlChar *ret;
3673
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003674 if (!xmlCatalogInitialized)
3675 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003676
Daniel Veillard81463942001-10-16 12:34:39 +00003677 if (URI == NULL)
3678 return(NULL);
3679
Daniel Veillard6990bf32001-08-23 21:17:48 +00003680 if (xmlDebugCatalogs)
3681 xmlGenericError(xmlGenericErrorContext,
3682 "Resolve URI %s\n", URI);
3683
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003684 catal = (xmlCatalogEntryPtr) catalogs;
3685 if (catal == NULL)
3686 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003687 ret = xmlCatalogListXMLResolveURI(catal, URI);
3688 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3689 return(ret);
3690 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003691}
3692
Daniel Veillard75b96822001-10-11 18:59:45 +00003693/************************************************************************
3694 * *
3695 * Deprecated interfaces *
3696 * *
3697 ************************************************************************/
3698/**
3699 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003700 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003701 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003702 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003703 * DEPRECATED, use xmlCatalogResolveSystem()
3704 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003705 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003706 */
3707const xmlChar *
3708xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003709 xmlChar *ret;
3710 static xmlChar result[1000];
3711 static int msg = 0;
3712
3713 if (!xmlCatalogInitialized)
3714 xmlInitializeCatalog();
3715
3716 if (msg == 0) {
3717 xmlGenericError(xmlGenericErrorContext,
3718 "Use of deprecated xmlCatalogGetSystem() call\n");
3719 msg++;
3720 }
3721
3722 if (sysID == NULL)
3723 return(NULL);
3724
3725 /*
3726 * Check first the XML catalogs
3727 */
3728 if (xmlDefaultCatalog != NULL) {
3729 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3730 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3731 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3732 result[sizeof(result) - 1] = 0;
3733 return(result);
3734 }
3735 }
3736
3737 if (xmlDefaultCatalog != NULL)
3738 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3739 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003740}
3741
3742/**
3743 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003744 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003745 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003746 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003747 * DEPRECATED, use xmlCatalogResolvePublic()
3748 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003749 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003750 */
3751const xmlChar *
3752xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003753 xmlChar *ret;
3754 static xmlChar result[1000];
3755 static int msg = 0;
3756
3757 if (!xmlCatalogInitialized)
3758 xmlInitializeCatalog();
3759
3760 if (msg == 0) {
3761 xmlGenericError(xmlGenericErrorContext,
3762 "Use of deprecated xmlCatalogGetPublic() call\n");
3763 msg++;
3764 }
3765
3766 if (pubID == NULL)
3767 return(NULL);
3768
3769 /*
3770 * Check first the XML catalogs
3771 */
3772 if (xmlDefaultCatalog != NULL) {
3773 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3774 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3775 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3776 result[sizeof(result) - 1] = 0;
3777 return(result);
3778 }
3779 }
3780
3781 if (xmlDefaultCatalog != NULL)
3782 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3783 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003784}
3785
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003786#define bottom_catalog
3787#include "elfgcchack.h"
Daniel Veillarda7374592001-05-10 14:17:55 +00003788#endif /* LIBXML_CATALOG_ENABLED */