blob: 7aea57142eb1a703d476e14539854da32091006c [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{
1203 xmlChar *uri = NULL;
1204 xmlChar *URL = NULL;
1205 xmlChar *base = NULL;
1206 xmlCatalogEntryPtr entry = NULL;
1207
1208 if (cur == NULL)
1209 return;
1210 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1211 xmlChar *prop;
William M. Brackb7b54de2004-10-06 16:38:01 +00001212 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
Daniel Veillard344cee72001-08-20 00:08:40 +00001213
1214 prop = xmlGetProp(cur, BAD_CAST "prefer");
1215 if (prop != NULL) {
1216 if (xmlStrEqual(prop, BAD_CAST "system")) {
1217 prefer = XML_CATA_PREFER_SYSTEM;
1218 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1219 prefer = XML_CATA_PREFER_PUBLIC;
1220 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001221 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1222 "Invalid value for prefer: '%s'\n",
1223 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001224 }
1225 xmlFree(prop);
William M. Brackb7b54de2004-10-06 16:38:01 +00001226 pref = prefer;
Daniel Veillard344cee72001-08-20 00:08:40 +00001227 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001228 prop = xmlGetProp(cur, BAD_CAST "id");
1229 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1230 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
William M. Brack181a1ca2004-10-06 18:00:29 +00001231 xmlFree(prop);
Daniel Veillard344cee72001-08-20 00:08:40 +00001232 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1233 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
William M. Brackb7b54de2004-10-06 16:38:01 +00001234 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001235 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1236 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
William M. Brackb7b54de2004-10-06 16:38:01 +00001237 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001238 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1239 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1240 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001241 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001242 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1243 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1244 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001245 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001246 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1247 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1248 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001249 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001250 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1251 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1252 BAD_CAST "uri", BAD_CAST "name",
William M. Brackb7b54de2004-10-06 16:38:01 +00001253 BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001254 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1255 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1256 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001257 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001258 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1259 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1260 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001261 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001262 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1263 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1264 BAD_CAST "nextCatalog", NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001265 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001266 }
William M. Brackb031cef2004-11-05 16:34:22 +00001267 if (entry != NULL) {
1268 if (parent != NULL) {
1269 entry->parent = parent;
1270 if (parent->children == NULL)
1271 parent->children = entry;
1272 else {
1273 xmlCatalogEntryPtr prev;
Daniel Veillard344cee72001-08-20 00:08:40 +00001274
William M. Brackb031cef2004-11-05 16:34:22 +00001275 prev = parent->children;
1276 while (prev->next != NULL)
1277 prev = prev->next;
1278 prev->next = entry;
1279 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001280 }
William M. Brackb031cef2004-11-05 16:34:22 +00001281 if (entry->type == XML_CATA_GROUP) {
1282 /*
1283 * Recurse to propagate prefer to the subtree
1284 * (xml:base handling is automated)
1285 */
1286 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1287 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001288 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001289 if (base != NULL)
1290 xmlFree(base);
1291 if (uri != NULL)
1292 xmlFree(uri);
1293 if (URL != NULL)
1294 xmlFree(URL);
1295}
1296
Daniel Veillard75b96822001-10-11 18:59:45 +00001297/**
1298 * xmlParseXMLCatalogNodeList:
1299 * @cur: the XML node list of siblings
1300 * @prefer: the PUBLIC vs. SYSTEM current preference value
1301 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001302 * @cgroup: the group which includes this list
Daniel Veillard75b96822001-10-11 18:59:45 +00001303 *
1304 * Examines a list of XML sibling nodes of a catalog and build
1305 * a list of Catalog entry from it adding it to the parent.
1306 * The examination will recurse to examine node subtrees.
1307 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001308static void
1309xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001310 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001311 while (cur != NULL) {
1312 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1313 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
William M. Brackb7b54de2004-10-06 16:38:01 +00001314 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001315 }
1316 cur = cur->next;
1317 }
1318 /* TODO: sort the list according to REWRITE lengths and prefer value */
1319}
1320
Daniel Veillard75b96822001-10-11 18:59:45 +00001321/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001322 * xmlParseXMLCatalogFile:
1323 * @prefer: the PUBLIC vs. SYSTEM current preference value
1324 * @filename: the filename for the catalog
1325 *
1326 * Parses the catalog file to extract the XML tree and then analyze the
1327 * tree to build a list of Catalog entries corresponding to this catalog
1328 *
1329 * Returns the resulting Catalog entries list
1330 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001331static xmlCatalogEntryPtr
1332xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1333 xmlDocPtr doc;
1334 xmlNodePtr cur;
1335 xmlChar *prop;
1336 xmlCatalogEntryPtr parent = NULL;
1337
1338 if (filename == NULL)
1339 return(NULL);
1340
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001341 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001342 if (doc == NULL) {
1343 if (xmlDebugCatalogs)
1344 xmlGenericError(xmlGenericErrorContext,
1345 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001346 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001347 }
1348
1349 if (xmlDebugCatalogs)
1350 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001351 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001352
1353 cur = xmlDocGetRootElement(doc);
1354 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1355 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1356 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1357
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001358 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001359 (const xmlChar *)filename, NULL, prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001360 if (parent == NULL) {
1361 xmlFreeDoc(doc);
1362 return(NULL);
1363 }
1364
1365 prop = xmlGetProp(cur, BAD_CAST "prefer");
1366 if (prop != NULL) {
1367 if (xmlStrEqual(prop, BAD_CAST "system")) {
1368 prefer = XML_CATA_PREFER_SYSTEM;
1369 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1370 prefer = XML_CATA_PREFER_PUBLIC;
1371 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001372 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1373 "Invalid value for prefer: '%s'\n",
1374 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001375 }
1376 xmlFree(prop);
1377 }
1378 cur = cur->children;
William M. Brackb7b54de2004-10-06 16:38:01 +00001379 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001380 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001381 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1382 "File %s is not an XML Catalog\n",
1383 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001384 xmlFreeDoc(doc);
1385 return(NULL);
1386 }
1387 xmlFreeDoc(doc);
1388 return(parent);
1389}
1390
Daniel Veillardcda96922001-08-21 10:56:31 +00001391/**
1392 * xmlFetchXMLCatalogFile:
1393 * @catal: an existing but incomplete catalog entry
1394 *
1395 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001396 *
1397 * Returns 0 in case of success, -1 otherwise
1398 */
1399static int
1400xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001401 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001402
1403 if (catal == NULL)
1404 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001405 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001406 return(-1);
1407 if (catal->children != NULL)
1408 return(-1);
1409
Daniel Veillard81463942001-10-16 12:34:39 +00001410 /*
1411 * lock the whole catalog for modification
1412 */
1413 xmlRMutexLock(xmlCatalogMutex);
1414 if (catal->children != NULL) {
1415 /* Okay someone else did it in the meantime */
1416 xmlRMutexUnlock(xmlCatalogMutex);
1417 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001418 }
1419
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001420 if (xmlCatalogXMLFiles != NULL) {
1421 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001422 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001423 if (doc != NULL) {
1424 if (xmlDebugCatalogs)
1425 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001426 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001427
1428 if (catal->type == XML_CATA_CATALOG)
1429 catal->children = doc->children;
1430 else
1431 catal->children = doc;
1432 catal->dealloc = 0;
1433 xmlRMutexUnlock(xmlCatalogMutex);
1434 return(0);
1435 }
1436 if (xmlDebugCatalogs)
1437 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001438 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001439 }
1440
Daniel Veillardcda96922001-08-21 10:56:31 +00001441 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001442 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001443 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001444 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001445 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001446 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001447 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001448 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001449 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001450 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001451 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001452
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001453 if (catal->type == XML_CATA_CATALOG)
1454 catal->children = doc->children;
1455 else
1456 catal->children = doc;
1457
1458 doc->dealloc = 1;
1459
Daniel Veillard81463942001-10-16 12:34:39 +00001460 if (xmlCatalogXMLFiles == NULL)
1461 xmlCatalogXMLFiles = xmlHashCreate(10);
1462 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001463 if (xmlDebugCatalogs)
1464 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001465 "%s added to file hash\n", catal->URL);
1466 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001467 }
Daniel Veillard81463942001-10-16 12:34:39 +00001468 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001469 return(0);
1470}
1471
Daniel Veillard75b96822001-10-11 18:59:45 +00001472/************************************************************************
1473 * *
1474 * XML Catalog handling *
1475 * *
1476 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001477
1478/**
1479 * xmlAddXMLCatalog:
1480 * @catal: top of an XML catalog
1481 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001482 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001483 * @replace: the replacement value for the match
1484 *
1485 * Add an entry in the XML catalog, it may overwrite existing but
1486 * different entries.
1487 *
1488 * Returns 0 if successful, -1 otherwise
1489 */
1490static int
1491xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1492 const xmlChar *orig, const xmlChar *replace) {
1493 xmlCatalogEntryPtr cur;
1494 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001495 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001496
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001497 if ((catal == NULL) ||
1498 ((catal->type != XML_CATA_CATALOG) &&
1499 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001500 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001501 if (catal->children == NULL) {
1502 xmlFetchXMLCatalogFile(catal);
1503 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001504 if (catal->children == NULL)
1505 doregister = 1;
1506
Daniel Veillard344cee72001-08-20 00:08:40 +00001507 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001508 if (typ == XML_CATA_NONE) {
1509 if (xmlDebugCatalogs)
1510 xmlGenericError(xmlGenericErrorContext,
1511 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001512 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001513 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001514
1515 cur = catal->children;
1516 /*
1517 * Might be a simple "update in place"
1518 */
1519 if (cur != NULL) {
1520 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001521 if ((orig != NULL) && (cur->type == typ) &&
1522 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001523 if (xmlDebugCatalogs)
1524 xmlGenericError(xmlGenericErrorContext,
1525 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001526 if (cur->value != NULL)
1527 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001528 if (cur->URL != NULL)
1529 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001530 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001531 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001532 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001533 }
1534 if (cur->next == NULL)
1535 break;
1536 cur = cur->next;
1537 }
1538 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001539 if (xmlDebugCatalogs)
1540 xmlGenericError(xmlGenericErrorContext,
1541 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001542 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001543 catal->children = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001544 NULL, catal->prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001545 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001546 cur->next = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001547 NULL, catal->prefer, NULL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001548 if (doregister) {
Daniel Veillard27bec142006-02-24 20:22:27 +00001549 catal->type = XML_CATA_CATALOG;
Daniel Veillardc853b322001-11-06 15:24:37 +00001550 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1551 if (cur != NULL)
1552 cur->children = catal->children;
1553 }
1554
Daniel Veillardcda96922001-08-21 10:56:31 +00001555 return(0);
1556}
1557
1558/**
1559 * xmlDelXMLCatalog:
1560 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001561 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001562 *
1563 * Remove entries in the XML catalog where the value or the URI
1564 * is equal to @value
1565 *
1566 * Returns the number of entries removed if successful, -1 otherwise
1567 */
1568static int
1569xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001570 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001571 int ret = 0;
1572
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001573 if ((catal == NULL) ||
1574 ((catal->type != XML_CATA_CATALOG) &&
1575 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001576 return(-1);
1577 if (value == NULL)
1578 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001579 if (catal->children == NULL) {
1580 xmlFetchXMLCatalogFile(catal);
1581 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001582
1583 /*
1584 * Scan the children
1585 */
1586 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001587 while (cur != NULL) {
1588 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1589 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001590 if (xmlDebugCatalogs) {
1591 if (cur->name != NULL)
1592 xmlGenericError(xmlGenericErrorContext,
1593 "Removing element %s from catalog\n", cur->name);
1594 else
1595 xmlGenericError(xmlGenericErrorContext,
1596 "Removing element %s from catalog\n", cur->value);
1597 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001598 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001599 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001600 cur = cur->next;
1601 }
1602 return(ret);
1603}
1604
1605/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001606 * xmlCatalogXMLResolve:
1607 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001608 * @pubID: the public ID string
1609 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001610 *
1611 * Do a complete resolution lookup of an External Identifier for a
1612 * list of catalog entries.
1613 *
1614 * Implements (or tries to) 7.1. External Identifier Resolution
1615 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1616 *
1617 * Returns the URI of the resource or NULL if not found
1618 */
1619static xmlChar *
1620xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1621 const xmlChar *sysID) {
1622 xmlChar *ret = NULL;
1623 xmlCatalogEntryPtr cur;
1624 int haveDelegate = 0;
1625 int haveNext = 0;
1626
1627 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001628 * protection against loops
1629 */
1630 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001631 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1632 "Detected recursion in catalog %s\n",
1633 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001634 return(NULL);
1635 }
1636 catal->depth++;
1637
1638 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001639 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1640 */
1641 if (sysID != NULL) {
1642 xmlCatalogEntryPtr rewrite = NULL;
1643 int lenrewrite = 0, len;
1644 cur = catal;
1645 haveDelegate = 0;
1646 while (cur != NULL) {
1647 switch (cur->type) {
1648 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001649 if (xmlStrEqual(sysID, cur->name)) {
1650 if (xmlDebugCatalogs)
1651 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard890b5492006-02-23 08:14:00 +00001652 "Found system match %s, using %s\n",
1653 cur->name, cur->URL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001654 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001655 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001656 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001657 break;
1658 case XML_CATA_REWRITE_SYSTEM:
1659 len = xmlStrlen(cur->name);
1660 if ((len > lenrewrite) &&
1661 (!xmlStrncmp(sysID, cur->name, len))) {
1662 lenrewrite = len;
1663 rewrite = cur;
1664 }
1665 break;
1666 case XML_CATA_DELEGATE_SYSTEM:
1667 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1668 haveDelegate++;
1669 break;
1670 case XML_CATA_NEXT_CATALOG:
1671 haveNext++;
1672 break;
1673 default:
1674 break;
1675 }
1676 cur = cur->next;
1677 }
1678 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001679 if (xmlDebugCatalogs)
1680 xmlGenericError(xmlGenericErrorContext,
1681 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001682 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001683 if (ret != NULL)
1684 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001685 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001686 return(ret);
1687 }
1688 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001689 const xmlChar *delegates[MAX_DELEGATE];
1690 int nbList = 0, i;
1691
Daniel Veillardcda96922001-08-21 10:56:31 +00001692 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001693 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001694 * matches when the list was produced.
1695 */
1696 cur = catal;
1697 while (cur != NULL) {
1698 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1699 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001700 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001701 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001702 break;
1703 if (i < nbList) {
1704 cur = cur->next;
1705 continue;
1706 }
1707 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001708 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001709
Daniel Veillardcda96922001-08-21 10:56:31 +00001710 if (cur->children == NULL) {
1711 xmlFetchXMLCatalogFile(cur);
1712 }
1713 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001714 if (xmlDebugCatalogs)
1715 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001716 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001717 ret = xmlCatalogListXMLResolve(
1718 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001719 if (ret != NULL) {
1720 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001721 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001722 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001723 }
1724 }
1725 cur = cur->next;
1726 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001727 /*
1728 * Apply the cut algorithm explained in 4/
1729 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001730 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001731 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001732 }
1733 }
1734 /*
1735 * Then tries 5/ 6/ if a public ID is provided
1736 */
1737 if (pubID != NULL) {
1738 cur = catal;
1739 haveDelegate = 0;
1740 while (cur != NULL) {
1741 switch (cur->type) {
1742 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001743 if (xmlStrEqual(pubID, cur->name)) {
1744 if (xmlDebugCatalogs)
1745 xmlGenericError(xmlGenericErrorContext,
1746 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001747 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001748 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001749 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001750 break;
1751 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001752 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1753 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001754 haveDelegate++;
1755 break;
1756 case XML_CATA_NEXT_CATALOG:
1757 if (sysID == NULL)
1758 haveNext++;
1759 break;
1760 default:
1761 break;
1762 }
1763 cur = cur->next;
1764 }
1765 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001766 const xmlChar *delegates[MAX_DELEGATE];
1767 int nbList = 0, i;
1768
Daniel Veillardcda96922001-08-21 10:56:31 +00001769 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001770 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001771 * matches when the list was produced.
1772 */
1773 cur = catal;
1774 while (cur != NULL) {
1775 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001776 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1777 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001778
1779 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001780 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001781 break;
1782 if (i < nbList) {
1783 cur = cur->next;
1784 continue;
1785 }
1786 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001787 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001788
Daniel Veillardcda96922001-08-21 10:56:31 +00001789 if (cur->children == NULL) {
1790 xmlFetchXMLCatalogFile(cur);
1791 }
1792 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001793 if (xmlDebugCatalogs)
1794 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001795 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001796 ret = xmlCatalogListXMLResolve(
1797 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001798 if (ret != NULL) {
1799 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001800 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001801 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001802 }
1803 }
1804 cur = cur->next;
1805 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001806 /*
1807 * Apply the cut algorithm explained in 4/
1808 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001809 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001810 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001811 }
1812 }
1813 if (haveNext) {
1814 cur = catal;
1815 while (cur != NULL) {
1816 if (cur->type == XML_CATA_NEXT_CATALOG) {
1817 if (cur->children == NULL) {
1818 xmlFetchXMLCatalogFile(cur);
1819 }
1820 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001821 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001822 if (ret != NULL) {
1823 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001824 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001825 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001826 }
1827 }
1828 cur = cur->next;
1829 }
1830 }
1831
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001832 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001833 return(NULL);
1834}
1835
1836/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001837 * xmlCatalogXMLResolveURI:
1838 * @catal: a catalog list
1839 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001840 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001841 *
1842 * Do a complete resolution lookup of an External Identifier for a
1843 * list of catalog entries.
1844 *
1845 * Implements (or tries to) 7.2.2. URI Resolution
1846 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1847 *
1848 * Returns the URI of the resource or NULL if not found
1849 */
1850static xmlChar *
1851xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1852 xmlChar *ret = NULL;
1853 xmlCatalogEntryPtr cur;
1854 int haveDelegate = 0;
1855 int haveNext = 0;
1856 xmlCatalogEntryPtr rewrite = NULL;
1857 int lenrewrite = 0, len;
1858
1859 if (catal == NULL)
1860 return(NULL);
1861
1862 if (URI == NULL)
1863 return(NULL);
1864
1865 /*
1866 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1867 */
1868 cur = catal;
1869 haveDelegate = 0;
1870 while (cur != NULL) {
1871 switch (cur->type) {
1872 case XML_CATA_URI:
1873 if (xmlStrEqual(URI, cur->name)) {
1874 if (xmlDebugCatalogs)
1875 xmlGenericError(xmlGenericErrorContext,
1876 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001877 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001878 }
1879 break;
1880 case XML_CATA_REWRITE_URI:
1881 len = xmlStrlen(cur->name);
1882 if ((len > lenrewrite) &&
1883 (!xmlStrncmp(URI, cur->name, len))) {
1884 lenrewrite = len;
1885 rewrite = cur;
1886 }
1887 break;
1888 case XML_CATA_DELEGATE_URI:
1889 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1890 haveDelegate++;
1891 break;
1892 case XML_CATA_NEXT_CATALOG:
1893 haveNext++;
1894 break;
1895 default:
1896 break;
1897 }
1898 cur = cur->next;
1899 }
1900 if (rewrite != NULL) {
1901 if (xmlDebugCatalogs)
1902 xmlGenericError(xmlGenericErrorContext,
1903 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001904 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001905 if (ret != NULL)
1906 ret = xmlStrcat(ret, &URI[lenrewrite]);
1907 return(ret);
1908 }
1909 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001910 const xmlChar *delegates[MAX_DELEGATE];
1911 int nbList = 0, i;
1912
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001913 /*
1914 * Assume the entries have been sorted by decreasing substring
1915 * matches when the list was produced.
1916 */
1917 cur = catal;
1918 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001919 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1920 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001921 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001922 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001923 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001924 break;
1925 if (i < nbList) {
1926 cur = cur->next;
1927 continue;
1928 }
1929 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001930 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001931
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001932 if (cur->children == NULL) {
1933 xmlFetchXMLCatalogFile(cur);
1934 }
1935 if (cur->children != NULL) {
1936 if (xmlDebugCatalogs)
1937 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001938 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001939 ret = xmlCatalogListXMLResolveURI(
1940 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001941 if (ret != NULL)
1942 return(ret);
1943 }
1944 }
1945 cur = cur->next;
1946 }
1947 /*
1948 * Apply the cut algorithm explained in 4/
1949 */
1950 return(XML_CATAL_BREAK);
1951 }
1952 if (haveNext) {
1953 cur = catal;
1954 while (cur != NULL) {
1955 if (cur->type == XML_CATA_NEXT_CATALOG) {
1956 if (cur->children == NULL) {
1957 xmlFetchXMLCatalogFile(cur);
1958 }
1959 if (cur->children != NULL) {
1960 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1961 if (ret != NULL)
1962 return(ret);
1963 }
1964 }
1965 cur = cur->next;
1966 }
1967 }
1968
1969 return(NULL);
1970}
1971
1972/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001973 * xmlCatalogListXMLResolve:
1974 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001975 * @pubID: the public ID string
1976 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001977 *
1978 * Do a complete resolution lookup of an External Identifier for a
1979 * list of catalogs
1980 *
1981 * Implements (or tries to) 7.1. External Identifier Resolution
1982 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1983 *
1984 * Returns the URI of the resource or NULL if not found
1985 */
1986static xmlChar *
1987xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1988 const xmlChar *sysID) {
1989 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001990 xmlChar *urnID = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +00001991 xmlChar *normid;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001992
1993 if (catal == NULL)
1994 return(NULL);
1995 if ((pubID == NULL) && (sysID == NULL))
1996 return(NULL);
1997
Daniel Veillardc8155052004-07-16 09:03:08 +00001998 normid = xmlCatalogNormalizePublic(pubID);
1999 if (normid != NULL)
2000 pubID = (*normid != 0 ? normid : NULL);
2001
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002002 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2003 urnID = xmlCatalogUnWrapURN(pubID);
2004 if (xmlDebugCatalogs) {
2005 if (urnID == NULL)
2006 xmlGenericError(xmlGenericErrorContext,
2007 "Public URN ID %s expanded to NULL\n", pubID);
2008 else
2009 xmlGenericError(xmlGenericErrorContext,
2010 "Public URN ID expanded to %s\n", urnID);
2011 }
2012 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2013 if (urnID != NULL)
2014 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002015 if (normid != NULL)
2016 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002017 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002018 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002019 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2020 urnID = xmlCatalogUnWrapURN(sysID);
2021 if (xmlDebugCatalogs) {
2022 if (urnID == NULL)
2023 xmlGenericError(xmlGenericErrorContext,
2024 "System URN ID %s expanded to NULL\n", sysID);
2025 else
2026 xmlGenericError(xmlGenericErrorContext,
2027 "System URN ID expanded to %s\n", urnID);
2028 }
2029 if (pubID == NULL)
2030 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2031 else if (xmlStrEqual(pubID, urnID))
2032 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2033 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00002034 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002035 }
2036 if (urnID != NULL)
2037 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002038 if (normid != NULL)
2039 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002040 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002041 }
2042 while (catal != NULL) {
2043 if (catal->type == XML_CATA_CATALOG) {
2044 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002045 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00002046 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002047 if (catal->children != NULL) {
2048 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002049 if (ret != NULL) {
2050 if (normid != NULL)
2051 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002052 return(ret);
Daniel Veillardc8155052004-07-16 09:03:08 +00002053 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002054 }
Daniel Veillardcda96922001-08-21 10:56:31 +00002055 }
2056 catal = catal->next;
2057 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002058 if (normid != NULL)
2059 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002060 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00002061}
2062
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002063/**
2064 * xmlCatalogListXMLResolveURI:
2065 * @catal: a catalog list
2066 * @URI: the URI
2067 *
2068 * Do a complete resolution lookup of an URI for a list of catalogs
2069 *
2070 * Implements (or tries to) 7.2. URI Resolution
2071 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2072 *
2073 * Returns the URI of the resource or NULL if not found
2074 */
2075static xmlChar *
2076xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2077 xmlChar *ret = NULL;
2078 xmlChar *urnID = NULL;
2079
2080 if (catal == NULL)
2081 return(NULL);
2082 if (URI == NULL)
2083 return(NULL);
2084
2085 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2086 urnID = xmlCatalogUnWrapURN(URI);
2087 if (xmlDebugCatalogs) {
2088 if (urnID == NULL)
2089 xmlGenericError(xmlGenericErrorContext,
2090 "URN ID %s expanded to NULL\n", URI);
2091 else
2092 xmlGenericError(xmlGenericErrorContext,
2093 "URN ID expanded to %s\n", urnID);
2094 }
2095 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2096 if (urnID != NULL)
2097 xmlFree(urnID);
2098 return(ret);
2099 }
2100 while (catal != NULL) {
2101 if (catal->type == XML_CATA_CATALOG) {
2102 if (catal->children == NULL) {
2103 xmlFetchXMLCatalogFile(catal);
2104 }
2105 if (catal->children != NULL) {
2106 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2107 if (ret != NULL)
2108 return(ret);
2109 }
2110 }
2111 catal = catal->next;
2112 }
2113 return(ret);
2114}
2115
Daniel Veillard344cee72001-08-20 00:08:40 +00002116/************************************************************************
2117 * *
2118 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00002119 * *
2120 ************************************************************************/
2121
2122
2123#define RAW *cur
2124#define NEXT cur++;
2125#define SKIP(x) cur += x;
2126
William M. Brack272693c2003-11-14 16:20:34 +00002127#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002128
Daniel Veillard75b96822001-10-11 18:59:45 +00002129/**
2130 * xmlParseSGMLCatalogComment:
2131 * @cur: the current character
2132 *
2133 * Skip a comment in an SGML catalog
2134 *
2135 * Returns new current character
2136 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002137static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002138xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002139 if ((cur[0] != '-') || (cur[1] != '-'))
2140 return(cur);
2141 SKIP(2);
2142 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2143 NEXT;
2144 if (cur[0] == 0) {
2145 return(NULL);
2146 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002147 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002148}
2149
Daniel Veillard75b96822001-10-11 18:59:45 +00002150/**
2151 * xmlParseSGMLCatalogPubid:
2152 * @cur: the current character
2153 * @id: the return location
2154 *
2155 * Parse an SGML catalog ID
2156 *
2157 * Returns new current character and store the value in @id
2158 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002159static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002160xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002161 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002162 int len = 0;
2163 int size = 50;
2164 xmlChar stop;
2165 int count = 0;
2166
2167 *id = NULL;
2168
2169 if (RAW == '"') {
2170 NEXT;
2171 stop = '"';
2172 } else if (RAW == '\'') {
2173 NEXT;
2174 stop = '\'';
2175 } else {
2176 stop = ' ';
2177 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002178 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002179 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002180 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002181 return(NULL);
2182 }
William M. Brack76e95df2003-10-18 16:20:14 +00002183 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002184 if ((*cur == stop) && (stop != ' '))
2185 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002186 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002187 break;
2188 if (len + 1 >= size) {
2189 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002190 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2191 if (tmp == NULL) {
2192 xmlCatalogErrMemory("allocating public ID");
2193 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002194 return(NULL);
2195 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002196 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002197 }
2198 buf[len++] = *cur;
2199 count++;
2200 NEXT;
2201 }
2202 buf[len] = 0;
2203 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002204 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002205 xmlFree(buf);
2206 return(NULL);
2207 }
2208 } else {
2209 if (*cur != stop) {
2210 xmlFree(buf);
2211 return(NULL);
2212 }
2213 NEXT;
2214 }
2215 *id = buf;
2216 return(cur);
2217}
2218
Daniel Veillard75b96822001-10-11 18:59:45 +00002219/**
2220 * xmlParseSGMLCatalogName:
2221 * @cur: the current character
2222 * @name: the return location
2223 *
2224 * Parse an SGML catalog name
2225 *
2226 * Returns new current character and store the value in @name
2227 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002228static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002229xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002230 xmlChar buf[XML_MAX_NAMELEN + 5];
2231 int len = 0;
2232 int c;
2233
2234 *name = NULL;
2235
2236 /*
2237 * Handler for more complex cases
2238 */
2239 c = *cur;
2240 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2241 return(NULL);
2242 }
2243
2244 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2245 (c == '.') || (c == '-') ||
2246 (c == '_') || (c == ':'))) {
2247 buf[len++] = c;
2248 cur++;
2249 c = *cur;
2250 if (len >= XML_MAX_NAMELEN)
2251 return(NULL);
2252 }
2253 *name = xmlStrndup(buf, len);
2254 return(cur);
2255}
2256
Daniel Veillard75b96822001-10-11 18:59:45 +00002257/**
2258 * xmlGetSGMLCatalogEntryType:
2259 * @name: the entry name
2260 *
2261 * Get the Catalog entry type for a given SGML Catalog name
2262 *
2263 * Returns Catalog entry type
2264 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002265static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002266xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002267 xmlCatalogEntryType type = XML_CATA_NONE;
2268 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2269 type = SGML_CATA_SYSTEM;
2270 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2271 type = SGML_CATA_PUBLIC;
2272 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2273 type = SGML_CATA_DELEGATE;
2274 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2275 type = SGML_CATA_ENTITY;
2276 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2277 type = SGML_CATA_DOCTYPE;
2278 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2279 type = SGML_CATA_LINKTYPE;
2280 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2281 type = SGML_CATA_NOTATION;
2282 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2283 type = SGML_CATA_SGMLDECL;
2284 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2285 type = SGML_CATA_DOCUMENT;
2286 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2287 type = SGML_CATA_CATALOG;
2288 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2289 type = SGML_CATA_BASE;
Daniel Veillard344cee72001-08-20 00:08:40 +00002290 return(type);
2291}
2292
Daniel Veillard75b96822001-10-11 18:59:45 +00002293/**
2294 * xmlParseSGMLCatalog:
2295 * @catal: the SGML Catalog
2296 * @value: the content of the SGML Catalog serialization
2297 * @file: the filepath for the catalog
2298 * @super: should this be handled as a Super Catalog in which case
2299 * parsing is not recursive
2300 *
2301 * Parse an SGML catalog content and fill up the @catal hash table with
2302 * the new entries found.
2303 *
2304 * Returns 0 in case of success, -1 in case of error.
2305 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002306static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002307xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2308 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002309 const xmlChar *cur = value;
2310 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002311 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002312
2313 if ((cur == NULL) || (file == NULL))
2314 return(-1);
2315 base = xmlStrdup((const xmlChar *) file);
2316
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002317 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002318 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002319 if (cur[0] == 0)
2320 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002321 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002322 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002323 if (cur == NULL) {
2324 /* error */
2325 break;
2326 }
2327 } else {
2328 xmlChar *sysid = NULL;
2329 xmlChar *name = NULL;
2330 xmlCatalogEntryType type = XML_CATA_NONE;
2331
Daniel Veillardcda96922001-08-21 10:56:31 +00002332 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002333 if (name == NULL) {
2334 /* error */
2335 break;
2336 }
William M. Brack76e95df2003-10-18 16:20:14 +00002337 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002338 /* error */
2339 break;
2340 }
2341 SKIP_BLANKS;
2342 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002343 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002344 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002345 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002346 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002347 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002348 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002349 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002350 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002351 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002352 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002353 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002354 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002355 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002356 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002357 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002358 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002359 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002360 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002361 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002362 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002363 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002364 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2365 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002366 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002367 if (name == NULL) {
2368 /* error */
2369 break;
2370 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002371 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002372 continue;
2373 }
2374 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002375 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002376
2377 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002378 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002379 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002380 type = SGML_CATA_PENTITY;
2381 case SGML_CATA_PENTITY:
2382 case SGML_CATA_DOCTYPE:
2383 case SGML_CATA_LINKTYPE:
2384 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002385 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002386 if (cur == NULL) {
2387 /* error */
2388 break;
2389 }
William M. Brack76e95df2003-10-18 16:20:14 +00002390 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002391 /* error */
2392 break;
2393 }
2394 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002395 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002396 if (cur == NULL) {
2397 /* error */
2398 break;
2399 }
2400 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002401 case SGML_CATA_PUBLIC:
2402 case SGML_CATA_SYSTEM:
2403 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002404 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002405 if (cur == NULL) {
2406 /* error */
2407 break;
2408 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002409 if (type != SGML_CATA_SYSTEM) {
2410 xmlChar *normid;
2411
2412 normid = xmlCatalogNormalizePublic(name);
2413 if (normid != NULL) {
2414 if (name != NULL)
2415 xmlFree(name);
2416 if (*normid != 0)
2417 name = normid;
2418 else {
2419 xmlFree(normid);
2420 name = NULL;
2421 }
2422 }
2423 }
William M. Brack76e95df2003-10-18 16:20:14 +00002424 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002425 /* error */
2426 break;
2427 }
2428 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002429 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002430 if (cur == NULL) {
2431 /* error */
2432 break;
2433 }
2434 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002435 case SGML_CATA_BASE:
2436 case SGML_CATA_CATALOG:
2437 case SGML_CATA_DOCUMENT:
2438 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002439 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002440 if (cur == NULL) {
2441 /* error */
2442 break;
2443 }
2444 break;
2445 default:
2446 break;
2447 }
2448 if (cur == NULL) {
2449 if (name != NULL)
2450 xmlFree(name);
2451 if (sysid != NULL)
2452 xmlFree(sysid);
2453 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002454 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002455 if (base != NULL)
2456 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002457 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002458 } else if ((type == SGML_CATA_PUBLIC) ||
2459 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002460 xmlChar *filename;
2461
2462 filename = xmlBuildURI(sysid, base);
2463 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002464 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002465
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002466 entry = xmlNewCatalogEntry(type, name, filename,
William M. Brackb7b54de2004-10-06 16:38:01 +00002467 NULL, XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002468 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002469 if (res < 0) {
2470 xmlFreeCatalogEntry(entry);
2471 }
2472 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002473 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002474
Daniel Veillard344cee72001-08-20 00:08:40 +00002475 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002476 if (super) {
2477 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002478
Daniel Veillardc853b322001-11-06 15:24:37 +00002479 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002480 XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002481 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002482 if (res < 0) {
2483 xmlFreeCatalogEntry(entry);
2484 }
2485 } else {
2486 xmlChar *filename;
2487
2488 filename = xmlBuildURI(sysid, base);
2489 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002490 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002491 xmlFree(filename);
2492 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002493 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002494 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002495 /*
2496 * drop anything else we won't handle it
2497 */
2498 if (name != NULL)
2499 xmlFree(name);
2500 if (sysid != NULL)
2501 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002502 }
2503 }
2504 if (base != NULL)
2505 xmlFree(base);
2506 if (cur == NULL)
2507 return(-1);
2508 return(0);
2509}
2510
Daniel Veillard75b96822001-10-11 18:59:45 +00002511/************************************************************************
2512 * *
2513 * SGML Catalog handling *
2514 * *
2515 ************************************************************************/
2516
Daniel Veillardcda96922001-08-21 10:56:31 +00002517/**
2518 * xmlCatalogGetSGMLPublic:
2519 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002520 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002521 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002522 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002523 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002524 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002525 */
2526static const xmlChar *
2527xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2528 xmlCatalogEntryPtr entry;
Daniel Veillardc8155052004-07-16 09:03:08 +00002529 xmlChar *normid;
Daniel Veillardcda96922001-08-21 10:56:31 +00002530
2531 if (catal == NULL)
2532 return(NULL);
2533
Daniel Veillardc8155052004-07-16 09:03:08 +00002534 normid = xmlCatalogNormalizePublic(pubID);
2535 if (normid != NULL)
2536 pubID = (*normid != 0 ? normid : NULL);
2537
Daniel Veillardcda96922001-08-21 10:56:31 +00002538 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002539 if (entry == NULL) {
2540 if (normid != NULL)
2541 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002542 return(NULL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002543 }
2544 if (entry->type == SGML_CATA_PUBLIC) {
2545 if (normid != NULL)
2546 xmlFree(normid);
Daniel Veillardc853b322001-11-06 15:24:37 +00002547 return(entry->URL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002548 }
2549 if (normid != NULL)
2550 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002551 return(NULL);
2552}
2553
2554/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002555 * xmlCatalogGetSGMLSystem:
2556 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002557 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002558 *
2559 * Try to lookup the catalog local reference for a system ID
2560 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002561 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002562 */
2563static const xmlChar *
2564xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2565 xmlCatalogEntryPtr entry;
2566
2567 if (catal == NULL)
2568 return(NULL);
2569
2570 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2571 if (entry == NULL)
2572 return(NULL);
2573 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002574 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002575 return(NULL);
2576}
2577
2578/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002579 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002580 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002581 * @pubID: the public ID string
2582 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002583 *
2584 * Do a complete resolution lookup of an External Identifier
2585 *
2586 * Returns the URI of the resource or NULL if not found
2587 */
2588static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002589xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2590 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002591 const xmlChar *ret = NULL;
2592
Daniel Veillard75b96822001-10-11 18:59:45 +00002593 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002594 return(NULL);
2595
2596 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002597 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002598 if (ret != NULL)
2599 return(ret);
2600 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002601 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002602 return(NULL);
2603}
2604
Daniel Veillarda7374592001-05-10 14:17:55 +00002605/************************************************************************
2606 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002607 * Specific Public interfaces *
2608 * *
2609 ************************************************************************/
2610
2611/**
2612 * xmlLoadSGMLSuperCatalog:
2613 * @filename: a file path
2614 *
2615 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2616 * references. This is only needed for manipulating SGML Super Catalogs
2617 * like adding and removing CATALOG or DELEGATE entries.
2618 *
2619 * Returns the catalog parsed or NULL in case of error
2620 */
2621xmlCatalogPtr
2622xmlLoadSGMLSuperCatalog(const char *filename)
2623{
2624 xmlChar *content;
2625 xmlCatalogPtr catal;
2626 int ret;
2627
2628 content = xmlLoadFileContent(filename);
2629 if (content == NULL)
2630 return(NULL);
2631
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002632 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002633 if (catal == NULL) {
2634 xmlFree(content);
2635 return(NULL);
2636 }
2637
2638 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2639 xmlFree(content);
2640 if (ret < 0) {
2641 xmlFreeCatalog(catal);
2642 return(NULL);
2643 }
2644 return (catal);
2645}
2646
2647/**
2648 * xmlLoadACatalog:
2649 * @filename: a file path
2650 *
2651 * Load the catalog and build the associated data structures.
2652 * This can be either an XML Catalog or an SGML Catalog
2653 * It will recurse in SGML CATALOG entries. On the other hand XML
2654 * Catalogs are not handled recursively.
2655 *
2656 * Returns the catalog parsed or NULL in case of error
2657 */
2658xmlCatalogPtr
2659xmlLoadACatalog(const char *filename)
2660{
2661 xmlChar *content;
2662 xmlChar *first;
2663 xmlCatalogPtr catal;
2664 int ret;
2665
2666 content = xmlLoadFileContent(filename);
2667 if (content == NULL)
2668 return(NULL);
2669
2670
2671 first = content;
2672
2673 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2674 (!(((*first >= 'A') && (*first <= 'Z')) ||
2675 ((*first >= 'a') && (*first <= 'z')))))
2676 first++;
2677
2678 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002679 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002680 if (catal == NULL) {
2681 xmlFree(content);
2682 return(NULL);
2683 }
2684 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2685 if (ret < 0) {
2686 xmlFreeCatalog(catal);
2687 xmlFree(content);
2688 return(NULL);
2689 }
2690 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002691 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002692 if (catal == NULL) {
2693 xmlFree(content);
2694 return(NULL);
2695 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002696 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002697 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002698 }
2699 xmlFree(content);
2700 return (catal);
2701}
2702
2703/**
2704 * xmlExpandCatalog:
2705 * @catal: a catalog
2706 * @filename: a file path
2707 *
2708 * Load the catalog and expand the existing catal structure.
2709 * This can be either an XML Catalog or an SGML Catalog
2710 *
2711 * Returns 0 in case of success, -1 in case of error
2712 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002713static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002714xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2715{
Daniel Veillard75b96822001-10-11 18:59:45 +00002716 int ret;
2717
2718 if ((catal == NULL) || (filename == NULL))
2719 return(-1);
2720
Daniel Veillard75b96822001-10-11 18:59:45 +00002721
2722 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002723 xmlChar *content;
2724
2725 content = xmlLoadFileContent(filename);
2726 if (content == NULL)
2727 return(-1);
2728
Daniel Veillard75b96822001-10-11 18:59:45 +00002729 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2730 if (ret < 0) {
2731 xmlFree(content);
2732 return(-1);
2733 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002734 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002735 } else {
2736 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002737 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002738 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002739
Daniel Veillard75b96822001-10-11 18:59:45 +00002740 cur = catal->xml;
2741 if (cur == NULL) {
2742 catal->xml = tmp;
2743 } else {
2744 while (cur->next != NULL) cur = cur->next;
2745 cur->next = tmp;
2746 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002747 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002748 return (0);
2749}
2750
2751/**
2752 * xmlACatalogResolveSystem:
2753 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002754 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002755 *
2756 * Try to lookup the catalog resource for a system ID
2757 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002758 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002759 * must be freed by the caller.
2760 */
2761xmlChar *
2762xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2763 xmlChar *ret = NULL;
2764
2765 if ((sysID == NULL) || (catal == NULL))
2766 return(NULL);
2767
2768 if (xmlDebugCatalogs)
2769 xmlGenericError(xmlGenericErrorContext,
2770 "Resolve sysID %s\n", sysID);
2771
2772 if (catal->type == XML_XML_CATALOG_TYPE) {
2773 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2774 if (ret == XML_CATAL_BREAK)
2775 ret = NULL;
2776 } else {
2777 const xmlChar *sgml;
2778
2779 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2780 if (sgml != NULL)
2781 ret = xmlStrdup(sgml);
2782 }
2783 return(ret);
2784}
2785
2786/**
2787 * xmlACatalogResolvePublic:
2788 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002789 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002790 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002791 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002792 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002793 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002794 * must be freed by the caller.
2795 */
2796xmlChar *
2797xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2798 xmlChar *ret = NULL;
2799
2800 if ((pubID == NULL) || (catal == NULL))
2801 return(NULL);
2802
2803 if (xmlDebugCatalogs)
2804 xmlGenericError(xmlGenericErrorContext,
2805 "Resolve pubID %s\n", pubID);
2806
2807 if (catal->type == XML_XML_CATALOG_TYPE) {
2808 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2809 if (ret == XML_CATAL_BREAK)
2810 ret = NULL;
2811 } else {
2812 const xmlChar *sgml;
2813
2814 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2815 if (sgml != NULL)
2816 ret = xmlStrdup(sgml);
2817 }
2818 return(ret);
2819}
2820
2821/**
2822 * xmlACatalogResolve:
2823 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002824 * @pubID: the public ID string
2825 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002826 *
2827 * Do a complete resolution lookup of an External Identifier
2828 *
2829 * Returns the URI of the resource or NULL if not found, it must be freed
2830 * by the caller.
2831 */
2832xmlChar *
2833xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2834 const xmlChar * sysID)
2835{
2836 xmlChar *ret = NULL;
2837
2838 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2839 return (NULL);
2840
2841 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002842 if ((pubID != NULL) && (sysID != NULL)) {
2843 xmlGenericError(xmlGenericErrorContext,
2844 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2845 } else if (pubID != NULL) {
2846 xmlGenericError(xmlGenericErrorContext,
2847 "Resolve: pubID %s\n", pubID);
2848 } else {
2849 xmlGenericError(xmlGenericErrorContext,
2850 "Resolve: sysID %s\n", sysID);
2851 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002852 }
2853
2854 if (catal->type == XML_XML_CATALOG_TYPE) {
2855 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2856 if (ret == XML_CATAL_BREAK)
2857 ret = NULL;
2858 } else {
2859 const xmlChar *sgml;
2860
2861 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2862 if (sgml != NULL)
2863 ret = xmlStrdup(sgml);
2864 }
2865 return (ret);
2866}
2867
2868/**
2869 * xmlACatalogResolveURI:
2870 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002871 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002872 *
2873 * Do a complete resolution lookup of an URI
2874 *
2875 * Returns the URI of the resource or NULL if not found, it must be freed
2876 * by the caller.
2877 */
2878xmlChar *
2879xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2880 xmlChar *ret = NULL;
2881
2882 if ((URI == NULL) || (catal == NULL))
2883 return(NULL);
2884
Daniel Veillardb44025c2001-10-11 22:55:55 +00002885 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002886 xmlGenericError(xmlGenericErrorContext,
2887 "Resolve URI %s\n", URI);
2888
2889 if (catal->type == XML_XML_CATALOG_TYPE) {
2890 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2891 if (ret == XML_CATAL_BREAK)
2892 ret = NULL;
2893 } else {
2894 const xmlChar *sgml;
2895
2896 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2897 if (sgml != NULL)
2898 sgml = xmlStrdup(sgml);
2899 }
2900 return(ret);
2901}
2902
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002903#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002904/**
2905 * xmlACatalogDump:
2906 * @catal: a Catalog
2907 * @out: the file.
2908 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002909 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002910 */
2911void
2912xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002913 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002914 return;
2915
2916 if (catal->type == XML_XML_CATALOG_TYPE) {
2917 xmlDumpXMLCatalog(out, catal->xml);
2918 } else {
2919 xmlHashScan(catal->sgml,
2920 (xmlHashScanner) xmlCatalogDumpEntry, out);
2921 }
2922}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002923#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002924
2925/**
2926 * xmlACatalogAdd:
2927 * @catal: a Catalog
2928 * @type: the type of record to add to the catalog
2929 * @orig: the system, public or prefix to match
2930 * @replace: the replacement value for the match
2931 *
2932 * Add an entry in the catalog, it may overwrite existing but
2933 * different entries.
2934 *
2935 * Returns 0 if successful, -1 otherwise
2936 */
2937int
2938xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2939 const xmlChar * orig, const xmlChar * replace)
2940{
2941 int res = -1;
2942
2943 if (catal == NULL)
2944 return(-1);
2945
2946 if (catal->type == XML_XML_CATALOG_TYPE) {
2947 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2948 } else {
2949 xmlCatalogEntryType cattype;
2950
2951 cattype = xmlGetSGMLCatalogEntryType(type);
2952 if (cattype != XML_CATA_NONE) {
2953 xmlCatalogEntryPtr entry;
2954
Daniel Veillardc853b322001-11-06 15:24:37 +00002955 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002956 XML_CATA_PREFER_NONE, NULL);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002957 if (catal->sgml == NULL)
2958 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002959 res = xmlHashAddEntry(catal->sgml, orig, entry);
2960 }
2961 }
2962 return (res);
2963}
2964
2965/**
2966 * xmlACatalogRemove:
2967 * @catal: a Catalog
2968 * @value: the value to remove
2969 *
2970 * Remove an entry from the catalog
2971 *
2972 * Returns the number of entries removed if successful, -1 otherwise
2973 */
2974int
2975xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2976 int res = -1;
2977
2978 if ((catal == NULL) || (value == NULL))
2979 return(-1);
2980
2981 if (catal->type == XML_XML_CATALOG_TYPE) {
2982 res = xmlDelXMLCatalog(catal->xml, value);
2983 } else {
2984 res = xmlHashRemoveEntry(catal->sgml, value,
2985 (xmlHashDeallocator) xmlFreeCatalogEntry);
2986 if (res == 0)
2987 res = 1;
2988 }
2989 return(res);
2990}
2991
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002992/**
2993 * xmlNewCatalog:
2994 * @sgml: should this create an SGML catalog
2995 *
2996 * create a new Catalog.
2997 *
2998 * Returns the xmlCatalogPtr or NULL in case of error
2999 */
3000xmlCatalogPtr
3001xmlNewCatalog(int sgml) {
3002 xmlCatalogPtr catal = NULL;
3003
3004 if (sgml) {
3005 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3006 xmlCatalogDefaultPrefer);
3007 if ((catal != NULL) && (catal->sgml == NULL))
3008 catal->sgml = xmlHashCreate(10);
3009 } else
3010 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3011 xmlCatalogDefaultPrefer);
3012 return(catal);
3013}
3014
3015/**
3016 * xmlCatalogIsEmpty:
3017 * @catal: should this create an SGML catalog
3018 *
3019 * Check is a catalog is empty
3020 *
3021 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3022 */
3023int
3024xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3025 if (catal == NULL)
3026 return(-1);
3027
3028 if (catal->type == XML_XML_CATALOG_TYPE) {
3029 if (catal->xml == NULL)
3030 return(1);
3031 if ((catal->xml->type != XML_CATA_CATALOG) &&
3032 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3033 return(-1);
3034 if (catal->xml->children == NULL)
3035 return(1);
3036 return(0);
3037 } else {
3038 int res;
3039
3040 if (catal->sgml == NULL)
3041 return(1);
3042 res = xmlHashSize(catal->sgml);
3043 if (res == 0)
3044 return(1);
3045 if (res < 0)
3046 return(-1);
3047 }
3048 return(0);
3049}
3050
Daniel Veillard75b96822001-10-11 18:59:45 +00003051/************************************************************************
3052 * *
3053 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00003054 * *
3055 ************************************************************************/
3056
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003057/**
Daniel Veillard81463942001-10-16 12:34:39 +00003058 * xmlInitializeCatalogData:
3059 *
3060 * Do the catalog initialization only of global data, doesn't try to load
3061 * any catalog actually.
3062 * this function is not thread safe, catalog initialization should
3063 * preferably be done once at startup
3064 */
3065static void
3066xmlInitializeCatalogData(void) {
3067 if (xmlCatalogInitialized != 0)
3068 return;
3069
3070 if (getenv("XML_DEBUG_CATALOG"))
3071 xmlDebugCatalogs = 1;
3072 xmlCatalogMutex = xmlNewRMutex();
3073
3074 xmlCatalogInitialized = 1;
3075}
3076/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003077 * xmlInitializeCatalog:
3078 *
3079 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00003080 * this function is not thread safe, catalog initialization should
3081 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003082 */
3083void
3084xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003085 if (xmlCatalogInitialized != 0)
3086 return;
3087
Daniel Veillard81463942001-10-16 12:34:39 +00003088 xmlInitializeCatalogData();
3089 xmlRMutexLock(xmlCatalogMutex);
3090
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003091 if (getenv("XML_DEBUG_CATALOG"))
3092 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00003093
Daniel Veillard75b96822001-10-11 18:59:45 +00003094 if (xmlDefaultCatalog == NULL) {
3095 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003096 char *path;
3097 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00003098 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003099 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00003100
Daniel Veillardb44025c2001-10-11 22:55:55 +00003101 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003102 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003103#if defined(_WIN32) && defined(_MSC_VER)
3104 {
3105 void* hmodule;
3106 hmodule = GetModuleHandleA("libxml2.dll");
3107 if (hmodule == NULL)
3108 hmodule = GetModuleHandleA(NULL);
3109 if (hmodule != NULL) {
3110 char buf[256];
3111 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3112 if (len != 0) {
3113 char* p = &(buf[len]);
3114 while (*p != '\\' && p > buf)
3115 p--;
3116 if (p != buf) {
3117 xmlChar* uri;
3118 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3119 uri = xmlCanonicPath(buf);
3120 if (uri != NULL) {
3121 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3122 xmlFree(uri);
3123 }
3124 }
3125 }
3126 }
3127 catalogs = XML_XML_DEFAULT_CATALOG;
3128 }
3129#else
Daniel Veillard75b96822001-10-11 18:59:45 +00003130 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00003131#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00003132
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003133 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3134 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003135 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003136 /* the XML_CATALOG_FILES envvar is allowed to contain a
3137 space-separated list of entries. */
3138 cur = catalogs;
3139 nextent = &catal->xml;
3140 while (*cur != '\0') {
William M. Brack68aca052003-10-11 15:22:13 +00003141 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003142 cur++;
3143 if (*cur != 0) {
3144 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003145 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003146 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00003147 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003148 if (path != NULL) {
3149 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003150 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003151 if (*nextent != NULL)
3152 nextent = &((*nextent)->next);
3153 xmlFree(path);
3154 }
3155 }
3156 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003157 xmlDefaultCatalog = catal;
3158 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003159 }
3160
Daniel Veillard81463942001-10-16 12:34:39 +00003161 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003162}
3163
Daniel Veillard82d75332001-10-08 15:01:59 +00003164
3165/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003166 * xmlLoadCatalog:
3167 * @filename: a file path
3168 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003169 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003170 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003171 * this function is not thread safe, catalog initialization should
3172 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003173 *
3174 * Returns 0 in case of success -1 in case of error
3175 */
3176int
Daniel Veillard16756b62001-10-01 07:36:25 +00003177xmlLoadCatalog(const char *filename)
3178{
Daniel Veillard75b96822001-10-11 18:59:45 +00003179 int ret;
3180 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003181
Daniel Veillard81463942001-10-16 12:34:39 +00003182 if (!xmlCatalogInitialized)
3183 xmlInitializeCatalogData();
3184
3185 xmlRMutexLock(xmlCatalogMutex);
3186
Daniel Veillard75b96822001-10-11 18:59:45 +00003187 if (xmlDefaultCatalog == NULL) {
3188 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003189 if (catal == NULL) {
3190 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003191 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003192 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003193
Daniel Veillard75b96822001-10-11 18:59:45 +00003194 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003195 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003196 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003197 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003198
Daniel Veillard75b96822001-10-11 18:59:45 +00003199 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003200 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003201 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003202}
3203
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003204/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003205 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003206 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003207 *
3208 * Load the catalogs and makes their definitions effective for the default
3209 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003210 * this function is not thread safe, catalog initialization should
3211 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003212 */
3213void
3214xmlLoadCatalogs(const char *pathss) {
3215 const char *cur;
3216 const char *paths;
3217 xmlChar *path;
3218
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003219 if (pathss == NULL)
3220 return;
3221
Daniel Veillard81418e32001-05-22 15:08:55 +00003222 cur = pathss;
3223 while ((cur != NULL) && (*cur != 0)) {
William M. Brack68aca052003-10-11 15:22:13 +00003224 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003225 if (*cur != 0) {
3226 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003227 while ((*cur != 0) && (*cur != ':') && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003228 cur++;
3229 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3230 if (path != NULL) {
3231 xmlLoadCatalog((const char *) path);
3232 xmlFree(path);
3233 }
3234 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003235 while (*cur == ':')
3236 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003237 }
3238}
3239
Daniel Veillarda7374592001-05-10 14:17:55 +00003240/**
3241 * xmlCatalogCleanup:
3242 *
3243 * Free up all the memory associated with catalogs
3244 */
3245void
3246xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003247 if (xmlCatalogInitialized == 0)
3248 return;
3249
Daniel Veillard81463942001-10-16 12:34:39 +00003250 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003251 if (xmlDebugCatalogs)
3252 xmlGenericError(xmlGenericErrorContext,
3253 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003254 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003255 xmlHashFree(xmlCatalogXMLFiles,
3256 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003257 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003258 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003259 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003260 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003261 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003262 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003263 xmlRMutexUnlock(xmlCatalogMutex);
3264 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003265}
3266
3267/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003268 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003269 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003270 *
3271 * Try to lookup the catalog resource for a system ID
3272 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003273 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003274 * must be freed by the caller.
3275 */
3276xmlChar *
3277xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003278 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003279
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003280 if (!xmlCatalogInitialized)
3281 xmlInitializeCatalog();
3282
Daniel Veillard75b96822001-10-11 18:59:45 +00003283 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3284 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003285}
3286
3287/**
3288 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003289 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003290 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003291 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003292 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003293 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003294 * must be freed by the caller.
3295 */
3296xmlChar *
3297xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003298 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003299
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003300 if (!xmlCatalogInitialized)
3301 xmlInitializeCatalog();
3302
Daniel Veillard75b96822001-10-11 18:59:45 +00003303 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3304 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003305}
Daniel Veillard344cee72001-08-20 00:08:40 +00003306
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003307/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003308 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003309 * @pubID: the public ID string
3310 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003311 *
3312 * Do a complete resolution lookup of an External Identifier
3313 *
3314 * Returns the URI of the resource or NULL if not found, it must be freed
3315 * by the caller.
3316 */
3317xmlChar *
3318xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003319 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003320
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003321 if (!xmlCatalogInitialized)
3322 xmlInitializeCatalog();
3323
Daniel Veillard75b96822001-10-11 18:59:45 +00003324 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3325 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003326}
3327
3328/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003329 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003330 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003331 *
3332 * Do a complete resolution lookup of an URI
3333 *
3334 * Returns the URI of the resource or NULL if not found, it must be freed
3335 * by the caller.
3336 */
3337xmlChar *
3338xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003339 xmlChar *ret;
3340
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003341 if (!xmlCatalogInitialized)
3342 xmlInitializeCatalog();
3343
Daniel Veillard75b96822001-10-11 18:59:45 +00003344 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3345 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003346}
3347
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003348#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003349/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003350 * xmlCatalogDump:
3351 * @out: the file.
3352 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003353 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003354 */
3355void
3356xmlCatalogDump(FILE *out) {
3357 if (out == NULL)
3358 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003359
Daniel Veillard75b96822001-10-11 18:59:45 +00003360 if (!xmlCatalogInitialized)
3361 xmlInitializeCatalog();
3362
3363 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003364}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003365#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003366
3367/**
3368 * xmlCatalogAdd:
3369 * @type: the type of record to add to the catalog
3370 * @orig: the system, public or prefix to match
3371 * @replace: the replacement value for the match
3372 *
3373 * Add an entry in the catalog, it may overwrite existing but
3374 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003375 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003376 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003377 *
3378 * Returns 0 if successful, -1 otherwise
3379 */
3380int
3381xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3382 int res = -1;
3383
Daniel Veillard81463942001-10-16 12:34:39 +00003384 if (!xmlCatalogInitialized)
3385 xmlInitializeCatalogData();
3386
3387 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003388 /*
3389 * Specific case where one want to override the default catalog
3390 * put in place by xmlInitializeCatalog();
3391 */
3392 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003393 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003394 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003395 xmlCatalogDefaultPrefer);
3396 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003397 orig, NULL, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003398
Daniel Veillard81463942001-10-16 12:34:39 +00003399 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003400 return(0);
3401 }
3402
Daniel Veillard75b96822001-10-11 18:59:45 +00003403 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003404 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003405 return(res);
3406}
3407
3408/**
3409 * xmlCatalogRemove:
3410 * @value: the value to remove
3411 *
3412 * Remove an entry from the catalog
3413 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003414 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003415 */
3416int
3417xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003418 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003419
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003420 if (!xmlCatalogInitialized)
3421 xmlInitializeCatalog();
3422
Daniel Veillard81463942001-10-16 12:34:39 +00003423 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003424 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003425 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003426 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003427}
3428
3429/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003430 * xmlCatalogConvert:
3431 *
3432 * Convert all the SGML catalog entries as XML ones
3433 *
3434 * Returns the number of entries converted if successful, -1 otherwise
3435 */
3436int
3437xmlCatalogConvert(void) {
3438 int res = -1;
3439
3440 if (!xmlCatalogInitialized)
3441 xmlInitializeCatalog();
3442
Daniel Veillard81463942001-10-16 12:34:39 +00003443 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003444 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003445 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003446 return(res);
3447}
3448
Daniel Veillard75b96822001-10-11 18:59:45 +00003449/************************************************************************
3450 * *
3451 * Public interface manipulating the common preferences *
3452 * *
3453 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003454
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003455/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003456 * xmlCatalogGetDefaults:
3457 *
3458 * Used to get the user preference w.r.t. to what catalogs should
3459 * be accepted
3460 *
3461 * Returns the current xmlCatalogAllow value
3462 */
3463xmlCatalogAllow
3464xmlCatalogGetDefaults(void) {
3465 return(xmlCatalogDefaultAllow);
3466}
3467
3468/**
3469 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003470 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003471 *
3472 * Used to set the user preference w.r.t. to what catalogs should
3473 * be accepted
3474 */
3475void
3476xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003477 if (xmlDebugCatalogs) {
3478 switch (allow) {
3479 case XML_CATA_ALLOW_NONE:
3480 xmlGenericError(xmlGenericErrorContext,
3481 "Disabling catalog usage\n");
3482 break;
3483 case XML_CATA_ALLOW_GLOBAL:
3484 xmlGenericError(xmlGenericErrorContext,
3485 "Allowing only global catalogs\n");
3486 break;
3487 case XML_CATA_ALLOW_DOCUMENT:
3488 xmlGenericError(xmlGenericErrorContext,
3489 "Allowing only catalogs from the document\n");
3490 break;
3491 case XML_CATA_ALLOW_ALL:
3492 xmlGenericError(xmlGenericErrorContext,
3493 "Allowing all catalogs\n");
3494 break;
3495 }
3496 }
3497 xmlCatalogDefaultAllow = allow;
3498}
3499
3500/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003501 * xmlCatalogSetDefaultPrefer:
3502 * @prefer: the default preference for delegation
3503 *
3504 * Allows to set the preference between public and system for deletion
3505 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003506 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003507 *
3508 * Returns the previous value of the default preference for delegation
3509 */
3510xmlCatalogPrefer
3511xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3512 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3513
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003514 if (prefer == XML_CATA_PREFER_NONE)
3515 return(ret);
3516
3517 if (xmlDebugCatalogs) {
3518 switch (prefer) {
3519 case XML_CATA_PREFER_PUBLIC:
3520 xmlGenericError(xmlGenericErrorContext,
3521 "Setting catalog preference to PUBLIC\n");
3522 break;
3523 case XML_CATA_PREFER_SYSTEM:
3524 xmlGenericError(xmlGenericErrorContext,
3525 "Setting catalog preference to SYSTEM\n");
3526 break;
3527 case XML_CATA_PREFER_NONE:
3528 break;
3529 }
3530 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003531 xmlCatalogDefaultPrefer = prefer;
3532 return(ret);
3533}
3534
3535/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003536 * xmlCatalogSetDebug:
3537 * @level: the debug level of catalogs required
3538 *
3539 * Used to set the debug level for catalog operation, 0 disable
3540 * debugging, 1 enable it
3541 *
3542 * Returns the previous value of the catalog debugging level
3543 */
3544int
3545xmlCatalogSetDebug(int level) {
3546 int ret = xmlDebugCatalogs;
3547
3548 if (level <= 0)
3549 xmlDebugCatalogs = 0;
3550 else
3551 xmlDebugCatalogs = level;
3552 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003553}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003554
Daniel Veillard75b96822001-10-11 18:59:45 +00003555/************************************************************************
3556 * *
3557 * Minimal interfaces used for per-document catalogs by the parser *
3558 * *
3559 ************************************************************************/
3560
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003561/**
3562 * xmlCatalogFreeLocal:
3563 * @catalogs: a document's list of catalogs
3564 *
3565 * Free up the memory associated to the catalog list
3566 */
3567void
3568xmlCatalogFreeLocal(void *catalogs) {
3569 xmlCatalogEntryPtr catal;
3570
Daniel Veillard81463942001-10-16 12:34:39 +00003571 if (!xmlCatalogInitialized)
3572 xmlInitializeCatalog();
3573
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003574 catal = (xmlCatalogEntryPtr) catalogs;
3575 if (catal != NULL)
3576 xmlFreeCatalogEntryList(catal);
3577}
3578
3579
3580/**
3581 * xmlCatalogAddLocal:
3582 * @catalogs: a document's list of catalogs
3583 * @URL: the URL to a new local catalog
3584 *
3585 * Add the new entry to the catalog list
3586 *
3587 * Returns the updated list
3588 */
3589void *
3590xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3591 xmlCatalogEntryPtr catal, add;
3592
3593 if (!xmlCatalogInitialized)
3594 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003595
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003596 if (URL == NULL)
3597 return(catalogs);
3598
3599 if (xmlDebugCatalogs)
3600 xmlGenericError(xmlGenericErrorContext,
3601 "Adding document catalog %s\n", URL);
3602
Daniel Veillardc853b322001-11-06 15:24:37 +00003603 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003604 xmlCatalogDefaultPrefer, NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003605 if (add == NULL)
3606 return(catalogs);
3607
3608 catal = (xmlCatalogEntryPtr) catalogs;
3609 if (catal == NULL)
3610 return((void *) add);
3611
3612 while (catal->next != NULL)
3613 catal = catal->next;
3614 catal->next = add;
3615 return(catalogs);
3616}
3617
3618/**
3619 * xmlCatalogLocalResolve:
3620 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003621 * @pubID: the public ID string
3622 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003623 *
3624 * Do a complete resolution lookup of an External Identifier using a
3625 * document's private catalog list
3626 *
3627 * Returns the URI of the resource or NULL if not found, it must be freed
3628 * by the caller.
3629 */
3630xmlChar *
3631xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3632 const xmlChar *sysID) {
3633 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003634 xmlChar *ret;
3635
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003636 if (!xmlCatalogInitialized)
3637 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003638
Daniel Veillard81463942001-10-16 12:34:39 +00003639 if ((pubID == NULL) && (sysID == NULL))
3640 return(NULL);
3641
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003642 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003643 if ((pubID != NULL) && (sysID != NULL)) {
3644 xmlGenericError(xmlGenericErrorContext,
3645 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3646 } else if (pubID != NULL) {
3647 xmlGenericError(xmlGenericErrorContext,
3648 "Local Resolve: pubID %s\n", pubID);
3649 } else {
3650 xmlGenericError(xmlGenericErrorContext,
3651 "Local Resolve: sysID %s\n", sysID);
3652 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003653 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003654
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003655 catal = (xmlCatalogEntryPtr) catalogs;
3656 if (catal == NULL)
3657 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003658 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3659 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3660 return(ret);
3661 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003662}
3663
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003664/**
3665 * xmlCatalogLocalResolveURI:
3666 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003667 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003668 *
3669 * Do a complete resolution lookup of an URI using a
3670 * document's private catalog list
3671 *
3672 * Returns the URI of the resource or NULL if not found, it must be freed
3673 * by the caller.
3674 */
3675xmlChar *
3676xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3677 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003678 xmlChar *ret;
3679
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003680 if (!xmlCatalogInitialized)
3681 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003682
Daniel Veillard81463942001-10-16 12:34:39 +00003683 if (URI == NULL)
3684 return(NULL);
3685
Daniel Veillard6990bf32001-08-23 21:17:48 +00003686 if (xmlDebugCatalogs)
3687 xmlGenericError(xmlGenericErrorContext,
3688 "Resolve URI %s\n", URI);
3689
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003690 catal = (xmlCatalogEntryPtr) catalogs;
3691 if (catal == NULL)
3692 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003693 ret = xmlCatalogListXMLResolveURI(catal, URI);
3694 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3695 return(ret);
3696 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003697}
3698
Daniel Veillard75b96822001-10-11 18:59:45 +00003699/************************************************************************
3700 * *
3701 * Deprecated interfaces *
3702 * *
3703 ************************************************************************/
3704/**
3705 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003706 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003707 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003708 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003709 * DEPRECATED, use xmlCatalogResolveSystem()
3710 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003711 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003712 */
3713const xmlChar *
3714xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003715 xmlChar *ret;
3716 static xmlChar result[1000];
3717 static int msg = 0;
3718
3719 if (!xmlCatalogInitialized)
3720 xmlInitializeCatalog();
3721
3722 if (msg == 0) {
3723 xmlGenericError(xmlGenericErrorContext,
3724 "Use of deprecated xmlCatalogGetSystem() call\n");
3725 msg++;
3726 }
3727
3728 if (sysID == NULL)
3729 return(NULL);
3730
3731 /*
3732 * Check first the XML catalogs
3733 */
3734 if (xmlDefaultCatalog != NULL) {
3735 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3736 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3737 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3738 result[sizeof(result) - 1] = 0;
3739 return(result);
3740 }
3741 }
3742
3743 if (xmlDefaultCatalog != NULL)
3744 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3745 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003746}
3747
3748/**
3749 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003750 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003751 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003752 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003753 * DEPRECATED, use xmlCatalogResolvePublic()
3754 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003755 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003756 */
3757const xmlChar *
3758xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003759 xmlChar *ret;
3760 static xmlChar result[1000];
3761 static int msg = 0;
3762
3763 if (!xmlCatalogInitialized)
3764 xmlInitializeCatalog();
3765
3766 if (msg == 0) {
3767 xmlGenericError(xmlGenericErrorContext,
3768 "Use of deprecated xmlCatalogGetPublic() call\n");
3769 msg++;
3770 }
3771
3772 if (pubID == NULL)
3773 return(NULL);
3774
3775 /*
3776 * Check first the XML catalogs
3777 */
3778 if (xmlDefaultCatalog != NULL) {
3779 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3780 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3781 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3782 result[sizeof(result) - 1] = 0;
3783 return(result);
3784 }
3785 }
3786
3787 if (xmlDefaultCatalog != NULL)
3788 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3789 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003790}
3791
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003792#define bottom_catalog
3793#include "elfgcchack.h"
Daniel Veillarda7374592001-05-10 14:17:55 +00003794#endif /* LIBXML_CATALOG_ENABLED */