blob: 4ca29ac6b672a280f373d27560c83c4b52377168 [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) {
881 if (xmlDefaultSAXHandler.error != NULL) {
882 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
883 }
884 return(NULL);
885 }
886
887 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
888 if (buf == NULL) {
889 xmlFreeParserCtxt(ctxt);
890 return(NULL);
891 }
892
893 inputStream = xmlNewInputStream(ctxt);
894 if (inputStream == NULL) {
895 xmlFreeParserCtxt(ctxt);
896 return(NULL);
897 }
898
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000899 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000900 inputStream->buf = buf;
901 inputStream->base = inputStream->buf->buffer->content;
902 inputStream->cur = inputStream->buf->buffer->content;
903 inputStream->end =
904 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
905
906 inputPush(ctxt, inputStream);
907 if ((ctxt->directory == NULL) && (directory == NULL))
908 directory = xmlParserGetDirectory(filename);
909 if ((ctxt->directory == NULL) && (directory != NULL))
910 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000911 ctxt->valid = 0;
912 ctxt->validate = 0;
913 ctxt->loadsubset = 0;
914 ctxt->pedantic = 0;
Daniel Veillard03a53c32004-10-26 16:06:51 +0000915 ctxt->dictNames = 1;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000916
917 xmlParseDocument(ctxt);
918
919 if (ctxt->wellFormed)
920 ret = ctxt->myDoc;
921 else {
922 ret = NULL;
923 xmlFreeDoc(ctxt->myDoc);
924 ctxt->myDoc = NULL;
925 }
926 xmlFreeParserCtxt(ctxt);
927
928 return(ret);
929}
930
Daniel Veillard75b96822001-10-11 18:59:45 +0000931/**
932 * xmlLoadFileContent:
933 * @filename: a file path
934 *
935 * Load a file content into memory.
936 *
937 * Returns a pointer to the 0 terminated string or NULL in case of error
938 */
939static xmlChar *
940xmlLoadFileContent(const char *filename)
941{
942#ifdef HAVE_STAT
943 int fd;
944#else
945 FILE *fd;
946#endif
947 int len;
948 long size;
949
950#ifdef HAVE_STAT
951 struct stat info;
952#endif
953 xmlChar *content;
954
955 if (filename == NULL)
956 return (NULL);
957
958#ifdef HAVE_STAT
959 if (stat(filename, &info) < 0)
960 return (NULL);
961#endif
962
963#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000964 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000965#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000966 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000967#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000968 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000969 return (NULL);
970 }
971#ifdef HAVE_STAT
972 size = info.st_size;
973#else
974 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
975 fclose(fd);
976 return (NULL);
977 }
978#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000979 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000980 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000981 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard75b96822001-10-11 18:59:45 +0000982 return (NULL);
983 }
984#ifdef HAVE_STAT
985 len = read(fd, content, size);
986#else
987 len = fread(content, 1, size, fd);
988#endif
989 if (len < 0) {
990 xmlFree(content);
991 return (NULL);
992 }
993#ifdef HAVE_STAT
994 close(fd);
995#else
996 fclose(fd);
997#endif
998 content[len] = 0;
999
1000 return(content);
1001}
1002
Daniel Veillardc8155052004-07-16 09:03:08 +00001003/**
1004 * xmlCatalogNormalizePublic:
1005 * @pubID: the public ID string
1006 *
1007 * Normalizes the Public Identifier
1008 *
1009 * Implements 6.2. Public Identifier Normalization
1010 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1011 *
1012 * Returns the new string or NULL, the string must be deallocated
1013 * by the caller.
1014 */
1015static xmlChar *
1016xmlCatalogNormalizePublic(const xmlChar *pubID)
1017{
1018 int ok = 1;
1019 int white;
1020 const xmlChar *p;
1021 xmlChar *ret;
1022 xmlChar *q;
1023
1024 if (pubID == NULL)
1025 return(NULL);
1026
1027 white = 1;
1028 for (p = pubID;*p != 0 && ok;p++) {
1029 if (!xmlIsBlank_ch(*p))
1030 white = 0;
1031 else if (*p == 0x20 && !white)
1032 white = 1;
1033 else
1034 ok = 0;
1035 }
1036 if (ok && !white) /* is normalized */
1037 return(NULL);
1038
1039 ret = xmlStrdup(pubID);
1040 q = ret;
1041 white = 0;
1042 for (p = pubID;*p != 0;p++) {
1043 if (xmlIsBlank_ch(*p)) {
1044 if (q != ret)
1045 white = 1;
1046 } else {
1047 if (white) {
1048 *(q++) = 0x20;
1049 white = 0;
1050 }
1051 *(q++) = *p;
1052 }
1053 }
1054 *q = 0;
1055 return(ret);
1056}
1057
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001058/************************************************************************
1059 * *
Daniel Veillard344cee72001-08-20 00:08:40 +00001060 * The XML Catalog parser *
1061 * *
1062 ************************************************************************/
1063
1064static xmlCatalogEntryPtr
1065xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001066static void
1067xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001068 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
Daniel Veillardcda96922001-08-21 10:56:31 +00001069static xmlChar *
1070xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1071 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001072static xmlChar *
1073xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1074
Daniel Veillard344cee72001-08-20 00:08:40 +00001075
Daniel Veillard75b96822001-10-11 18:59:45 +00001076/**
1077 * xmlGetXMLCatalogEntryType:
1078 * @name: the name
1079 *
1080 * lookup the internal type associated to an XML catalog entry name
1081 *
Daniel Veillard06d25242004-02-25 13:01:42 +00001082 * Returns the type associated with that name
Daniel Veillard75b96822001-10-11 18:59:45 +00001083 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001084static xmlCatalogEntryType
1085xmlGetXMLCatalogEntryType(const xmlChar *name) {
1086 xmlCatalogEntryType type = XML_CATA_NONE;
1087 if (xmlStrEqual(name, (const xmlChar *) "system"))
1088 type = XML_CATA_SYSTEM;
1089 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1090 type = XML_CATA_PUBLIC;
1091 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1092 type = XML_CATA_REWRITE_SYSTEM;
1093 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1094 type = XML_CATA_DELEGATE_PUBLIC;
1095 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1096 type = XML_CATA_DELEGATE_SYSTEM;
1097 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1098 type = XML_CATA_URI;
1099 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1100 type = XML_CATA_REWRITE_URI;
1101 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1102 type = XML_CATA_DELEGATE_URI;
1103 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1104 type = XML_CATA_NEXT_CATALOG;
1105 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1106 type = XML_CATA_CATALOG;
1107 return(type);
1108}
1109
Daniel Veillard75b96822001-10-11 18:59:45 +00001110/**
1111 * xmlParseXMLCatalogOneNode:
1112 * @cur: the XML node
1113 * @type: the type of Catalog entry
1114 * @name: the name of the node
1115 * @attrName: the attribute holding the value
1116 * @uriAttrName: the attribute holding the URI-Reference
1117 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +00001118 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001119 *
1120 * Finishes the examination of an XML tree node of a catalog and build
1121 * a Catalog entry from it.
1122 *
1123 * Returns the new Catalog entry node or NULL in case of error.
1124 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001125static xmlCatalogEntryPtr
1126xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1127 const xmlChar *name, const xmlChar *attrName,
William M. Brackb7b54de2004-10-06 16:38:01 +00001128 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1129 xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001130 int ok = 1;
1131 xmlChar *uriValue;
1132 xmlChar *nameValue = NULL;
1133 xmlChar *base = NULL;
1134 xmlChar *URL = NULL;
1135 xmlCatalogEntryPtr ret = NULL;
1136
1137 if (attrName != NULL) {
1138 nameValue = xmlGetProp(cur, attrName);
1139 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001140 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1141 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001142 ok = 0;
1143 }
1144 }
1145 uriValue = xmlGetProp(cur, uriAttrName);
1146 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001147 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1148 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001149 ok = 0;
1150 }
1151 if (!ok) {
1152 if (nameValue != NULL)
1153 xmlFree(nameValue);
1154 if (uriValue != NULL)
1155 xmlFree(uriValue);
1156 return(NULL);
1157 }
1158
1159 base = xmlNodeGetBase(cur->doc, cur);
1160 URL = xmlBuildURI(uriValue, base);
1161 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001162 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001163 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001164 xmlGenericError(xmlGenericErrorContext,
1165 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001166 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001167 xmlGenericError(xmlGenericErrorContext,
1168 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001169 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001170 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001171 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001172 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001173 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1174 }
1175 if (nameValue != NULL)
1176 xmlFree(nameValue);
1177 if (uriValue != NULL)
1178 xmlFree(uriValue);
1179 if (base != NULL)
1180 xmlFree(base);
1181 if (URL != NULL)
1182 xmlFree(URL);
1183 return(ret);
1184}
1185
Daniel Veillard75b96822001-10-11 18:59:45 +00001186/**
1187 * xmlParseXMLCatalogNode:
1188 * @cur: the XML node
1189 * @prefer: the PUBLIC vs. SYSTEM current preference value
1190 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001191 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001192 *
1193 * Examines an XML tree node of a catalog and build
1194 * a Catalog entry from it adding it to its parent. The examination can
1195 * be recursive.
1196 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001197static void
1198xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001199 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
Daniel Veillard344cee72001-08-20 00:08:40 +00001200{
1201 xmlChar *uri = NULL;
1202 xmlChar *URL = NULL;
1203 xmlChar *base = NULL;
1204 xmlCatalogEntryPtr entry = NULL;
1205
1206 if (cur == NULL)
1207 return;
1208 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1209 xmlChar *prop;
William M. Brackb7b54de2004-10-06 16:38:01 +00001210 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
Daniel Veillard344cee72001-08-20 00:08:40 +00001211
1212 prop = xmlGetProp(cur, BAD_CAST "prefer");
1213 if (prop != NULL) {
1214 if (xmlStrEqual(prop, BAD_CAST "system")) {
1215 prefer = XML_CATA_PREFER_SYSTEM;
1216 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1217 prefer = XML_CATA_PREFER_PUBLIC;
1218 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001219 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1220 "Invalid value for prefer: '%s'\n",
1221 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001222 }
1223 xmlFree(prop);
William M. Brackb7b54de2004-10-06 16:38:01 +00001224 pref = prefer;
Daniel Veillard344cee72001-08-20 00:08:40 +00001225 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001226 prop = xmlGetProp(cur, BAD_CAST "id");
1227 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1228 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
William M. Brack181a1ca2004-10-06 18:00:29 +00001229 xmlFree(prop);
Daniel Veillard344cee72001-08-20 00:08:40 +00001230 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1231 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
William M. Brackb7b54de2004-10-06 16:38:01 +00001232 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001233 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1234 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
William M. Brackb7b54de2004-10-06 16:38:01 +00001235 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001236 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1237 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1238 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001239 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001240 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1241 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1242 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001243 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001244 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1245 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1246 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001247 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001248 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1249 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1250 BAD_CAST "uri", BAD_CAST "name",
William M. Brackb7b54de2004-10-06 16:38:01 +00001251 BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001252 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1253 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1254 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001255 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001256 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1257 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1258 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001259 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001260 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1261 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1262 BAD_CAST "nextCatalog", NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001263 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001264 }
William M. Brackb031cef2004-11-05 16:34:22 +00001265 if (entry != NULL) {
1266 if (parent != NULL) {
1267 entry->parent = parent;
1268 if (parent->children == NULL)
1269 parent->children = entry;
1270 else {
1271 xmlCatalogEntryPtr prev;
Daniel Veillard344cee72001-08-20 00:08:40 +00001272
William M. Brackb031cef2004-11-05 16:34:22 +00001273 prev = parent->children;
1274 while (prev->next != NULL)
1275 prev = prev->next;
1276 prev->next = entry;
1277 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001278 }
William M. Brackb031cef2004-11-05 16:34:22 +00001279 if (entry->type == XML_CATA_GROUP) {
1280 /*
1281 * Recurse to propagate prefer to the subtree
1282 * (xml:base handling is automated)
1283 */
1284 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1285 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001286 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001287 if (base != NULL)
1288 xmlFree(base);
1289 if (uri != NULL)
1290 xmlFree(uri);
1291 if (URL != NULL)
1292 xmlFree(URL);
1293}
1294
Daniel Veillard75b96822001-10-11 18:59:45 +00001295/**
1296 * xmlParseXMLCatalogNodeList:
1297 * @cur: the XML node list of siblings
1298 * @prefer: the PUBLIC vs. SYSTEM current preference value
1299 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001300 * @cgroup: the group which includes this list
Daniel Veillard75b96822001-10-11 18:59:45 +00001301 *
1302 * Examines a list of XML sibling nodes of a catalog and build
1303 * a list of Catalog entry from it adding it to the parent.
1304 * The examination will recurse to examine node subtrees.
1305 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001306static void
1307xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001308 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001309 while (cur != NULL) {
1310 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1311 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
William M. Brackb7b54de2004-10-06 16:38:01 +00001312 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001313 }
1314 cur = cur->next;
1315 }
1316 /* TODO: sort the list according to REWRITE lengths and prefer value */
1317}
1318
Daniel Veillard75b96822001-10-11 18:59:45 +00001319/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001320 * xmlParseXMLCatalogFile:
1321 * @prefer: the PUBLIC vs. SYSTEM current preference value
1322 * @filename: the filename for the catalog
1323 *
1324 * Parses the catalog file to extract the XML tree and then analyze the
1325 * tree to build a list of Catalog entries corresponding to this catalog
1326 *
1327 * Returns the resulting Catalog entries list
1328 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001329static xmlCatalogEntryPtr
1330xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1331 xmlDocPtr doc;
1332 xmlNodePtr cur;
1333 xmlChar *prop;
1334 xmlCatalogEntryPtr parent = NULL;
1335
1336 if (filename == NULL)
1337 return(NULL);
1338
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001339 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001340 if (doc == NULL) {
1341 if (xmlDebugCatalogs)
1342 xmlGenericError(xmlGenericErrorContext,
1343 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001344 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001345 }
1346
1347 if (xmlDebugCatalogs)
1348 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001349 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001350
1351 cur = xmlDocGetRootElement(doc);
1352 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1353 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1354 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1355
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001356 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001357 (const xmlChar *)filename, NULL, prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001358 if (parent == NULL) {
1359 xmlFreeDoc(doc);
1360 return(NULL);
1361 }
1362
1363 prop = xmlGetProp(cur, BAD_CAST "prefer");
1364 if (prop != NULL) {
1365 if (xmlStrEqual(prop, BAD_CAST "system")) {
1366 prefer = XML_CATA_PREFER_SYSTEM;
1367 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1368 prefer = XML_CATA_PREFER_PUBLIC;
1369 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001370 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1371 "Invalid value for prefer: '%s'\n",
1372 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001373 }
1374 xmlFree(prop);
1375 }
1376 cur = cur->children;
William M. Brackb7b54de2004-10-06 16:38:01 +00001377 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001378 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001379 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1380 "File %s is not an XML Catalog\n",
1381 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001382 xmlFreeDoc(doc);
1383 return(NULL);
1384 }
1385 xmlFreeDoc(doc);
1386 return(parent);
1387}
1388
Daniel Veillardcda96922001-08-21 10:56:31 +00001389/**
1390 * xmlFetchXMLCatalogFile:
1391 * @catal: an existing but incomplete catalog entry
1392 *
1393 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001394 *
1395 * Returns 0 in case of success, -1 otherwise
1396 */
1397static int
1398xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001399 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001400
1401 if (catal == NULL)
1402 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001403 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001404 return(-1);
1405 if (catal->children != NULL)
1406 return(-1);
1407
Daniel Veillard81463942001-10-16 12:34:39 +00001408 /*
1409 * lock the whole catalog for modification
1410 */
1411 xmlRMutexLock(xmlCatalogMutex);
1412 if (catal->children != NULL) {
1413 /* Okay someone else did it in the meantime */
1414 xmlRMutexUnlock(xmlCatalogMutex);
1415 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001416 }
1417
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001418 if (xmlCatalogXMLFiles != NULL) {
1419 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001420 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001421 if (doc != NULL) {
1422 if (xmlDebugCatalogs)
1423 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001424 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001425
1426 if (catal->type == XML_CATA_CATALOG)
1427 catal->children = doc->children;
1428 else
1429 catal->children = doc;
1430 catal->dealloc = 0;
1431 xmlRMutexUnlock(xmlCatalogMutex);
1432 return(0);
1433 }
1434 if (xmlDebugCatalogs)
1435 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001436 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001437 }
1438
Daniel Veillardcda96922001-08-21 10:56:31 +00001439 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001440 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001441 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001442 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001443 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001444 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001445 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001446 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001447 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001448 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001449 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001450
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001451 if (catal->type == XML_CATA_CATALOG)
1452 catal->children = doc->children;
1453 else
1454 catal->children = doc;
1455
1456 doc->dealloc = 1;
1457
Daniel Veillard81463942001-10-16 12:34:39 +00001458 if (xmlCatalogXMLFiles == NULL)
1459 xmlCatalogXMLFiles = xmlHashCreate(10);
1460 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001461 if (xmlDebugCatalogs)
1462 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001463 "%s added to file hash\n", catal->URL);
1464 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001465 }
Daniel Veillard81463942001-10-16 12:34:39 +00001466 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001467 return(0);
1468}
1469
Daniel Veillard75b96822001-10-11 18:59:45 +00001470/************************************************************************
1471 * *
1472 * XML Catalog handling *
1473 * *
1474 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001475
1476/**
1477 * xmlAddXMLCatalog:
1478 * @catal: top of an XML catalog
1479 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001480 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001481 * @replace: the replacement value for the match
1482 *
1483 * Add an entry in the XML catalog, it may overwrite existing but
1484 * different entries.
1485 *
1486 * Returns 0 if successful, -1 otherwise
1487 */
1488static int
1489xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1490 const xmlChar *orig, const xmlChar *replace) {
1491 xmlCatalogEntryPtr cur;
1492 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001493 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001494
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001495 if ((catal == NULL) ||
1496 ((catal->type != XML_CATA_CATALOG) &&
1497 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001498 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001499 if (catal->children == NULL) {
1500 xmlFetchXMLCatalogFile(catal);
1501 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001502 if (catal->children == NULL)
1503 doregister = 1;
1504
Daniel Veillard344cee72001-08-20 00:08:40 +00001505 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001506 if (typ == XML_CATA_NONE) {
1507 if (xmlDebugCatalogs)
1508 xmlGenericError(xmlGenericErrorContext,
1509 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001510 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001511 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001512
1513 cur = catal->children;
1514 /*
1515 * Might be a simple "update in place"
1516 */
1517 if (cur != NULL) {
1518 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001519 if ((orig != NULL) && (cur->type == typ) &&
1520 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001521 if (xmlDebugCatalogs)
1522 xmlGenericError(xmlGenericErrorContext,
1523 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001524 if (cur->value != NULL)
1525 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001526 if (cur->URL != NULL)
1527 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001528 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001529 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001530 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001531 }
1532 if (cur->next == NULL)
1533 break;
1534 cur = cur->next;
1535 }
1536 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001537 if (xmlDebugCatalogs)
1538 xmlGenericError(xmlGenericErrorContext,
1539 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001540 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001541 catal->children = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001542 NULL, catal->prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001543 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001544 cur->next = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001545 NULL, catal->prefer, NULL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001546 if (doregister) {
1547 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1548 if (cur != NULL)
1549 cur->children = catal->children;
1550 }
1551
Daniel Veillardcda96922001-08-21 10:56:31 +00001552 return(0);
1553}
1554
1555/**
1556 * xmlDelXMLCatalog:
1557 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001558 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001559 *
1560 * Remove entries in the XML catalog where the value or the URI
1561 * is equal to @value
1562 *
1563 * Returns the number of entries removed if successful, -1 otherwise
1564 */
1565static int
1566xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001567 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001568 int ret = 0;
1569
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001570 if ((catal == NULL) ||
1571 ((catal->type != XML_CATA_CATALOG) &&
1572 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001573 return(-1);
1574 if (value == NULL)
1575 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001576 if (catal->children == NULL) {
1577 xmlFetchXMLCatalogFile(catal);
1578 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001579
1580 /*
1581 * Scan the children
1582 */
1583 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001584 while (cur != NULL) {
1585 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1586 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001587 if (xmlDebugCatalogs) {
1588 if (cur->name != NULL)
1589 xmlGenericError(xmlGenericErrorContext,
1590 "Removing element %s from catalog\n", cur->name);
1591 else
1592 xmlGenericError(xmlGenericErrorContext,
1593 "Removing element %s from catalog\n", cur->value);
1594 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001595 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001596 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001597 cur = cur->next;
1598 }
1599 return(ret);
1600}
1601
1602/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001603 * xmlCatalogXMLResolve:
1604 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001605 * @pubID: the public ID string
1606 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001607 *
1608 * Do a complete resolution lookup of an External Identifier for a
1609 * list of catalog entries.
1610 *
1611 * Implements (or tries to) 7.1. External Identifier Resolution
1612 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1613 *
1614 * Returns the URI of the resource or NULL if not found
1615 */
1616static xmlChar *
1617xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1618 const xmlChar *sysID) {
1619 xmlChar *ret = NULL;
1620 xmlCatalogEntryPtr cur;
1621 int haveDelegate = 0;
1622 int haveNext = 0;
1623
1624 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001625 * protection against loops
1626 */
1627 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001628 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1629 "Detected recursion in catalog %s\n",
1630 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001631 return(NULL);
1632 }
1633 catal->depth++;
1634
1635 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001636 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1637 */
1638 if (sysID != NULL) {
1639 xmlCatalogEntryPtr rewrite = NULL;
1640 int lenrewrite = 0, len;
1641 cur = catal;
1642 haveDelegate = 0;
1643 while (cur != NULL) {
1644 switch (cur->type) {
1645 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001646 if (xmlStrEqual(sysID, cur->name)) {
1647 if (xmlDebugCatalogs)
1648 xmlGenericError(xmlGenericErrorContext,
1649 "Found system match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001650 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001651 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001652 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001653 break;
1654 case XML_CATA_REWRITE_SYSTEM:
1655 len = xmlStrlen(cur->name);
1656 if ((len > lenrewrite) &&
1657 (!xmlStrncmp(sysID, cur->name, len))) {
1658 lenrewrite = len;
1659 rewrite = cur;
1660 }
1661 break;
1662 case XML_CATA_DELEGATE_SYSTEM:
1663 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1664 haveDelegate++;
1665 break;
1666 case XML_CATA_NEXT_CATALOG:
1667 haveNext++;
1668 break;
1669 default:
1670 break;
1671 }
1672 cur = cur->next;
1673 }
1674 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001675 if (xmlDebugCatalogs)
1676 xmlGenericError(xmlGenericErrorContext,
1677 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001678 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001679 if (ret != NULL)
1680 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001681 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001682 return(ret);
1683 }
1684 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001685 const xmlChar *delegates[MAX_DELEGATE];
1686 int nbList = 0, i;
1687
Daniel Veillardcda96922001-08-21 10:56:31 +00001688 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001689 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001690 * matches when the list was produced.
1691 */
1692 cur = catal;
1693 while (cur != NULL) {
1694 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1695 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001696 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001697 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001698 break;
1699 if (i < nbList) {
1700 cur = cur->next;
1701 continue;
1702 }
1703 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001704 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001705
Daniel Veillardcda96922001-08-21 10:56:31 +00001706 if (cur->children == NULL) {
1707 xmlFetchXMLCatalogFile(cur);
1708 }
1709 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001710 if (xmlDebugCatalogs)
1711 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001712 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001713 ret = xmlCatalogListXMLResolve(
1714 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001715 if (ret != NULL) {
1716 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001717 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001718 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001719 }
1720 }
1721 cur = cur->next;
1722 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001723 /*
1724 * Apply the cut algorithm explained in 4/
1725 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001726 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001727 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001728 }
1729 }
1730 /*
1731 * Then tries 5/ 6/ if a public ID is provided
1732 */
1733 if (pubID != NULL) {
1734 cur = catal;
1735 haveDelegate = 0;
1736 while (cur != NULL) {
1737 switch (cur->type) {
1738 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001739 if (xmlStrEqual(pubID, cur->name)) {
1740 if (xmlDebugCatalogs)
1741 xmlGenericError(xmlGenericErrorContext,
1742 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001743 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001744 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001745 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001746 break;
1747 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001748 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1749 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001750 haveDelegate++;
1751 break;
1752 case XML_CATA_NEXT_CATALOG:
1753 if (sysID == NULL)
1754 haveNext++;
1755 break;
1756 default:
1757 break;
1758 }
1759 cur = cur->next;
1760 }
1761 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001762 const xmlChar *delegates[MAX_DELEGATE];
1763 int nbList = 0, i;
1764
Daniel Veillardcda96922001-08-21 10:56:31 +00001765 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001766 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001767 * matches when the list was produced.
1768 */
1769 cur = catal;
1770 while (cur != NULL) {
1771 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001772 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1773 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001774
1775 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001776 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001777 break;
1778 if (i < nbList) {
1779 cur = cur->next;
1780 continue;
1781 }
1782 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001783 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001784
Daniel Veillardcda96922001-08-21 10:56:31 +00001785 if (cur->children == NULL) {
1786 xmlFetchXMLCatalogFile(cur);
1787 }
1788 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001789 if (xmlDebugCatalogs)
1790 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001791 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001792 ret = xmlCatalogListXMLResolve(
1793 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001794 if (ret != NULL) {
1795 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001796 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001797 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001798 }
1799 }
1800 cur = cur->next;
1801 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001802 /*
1803 * Apply the cut algorithm explained in 4/
1804 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001805 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001806 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001807 }
1808 }
1809 if (haveNext) {
1810 cur = catal;
1811 while (cur != NULL) {
1812 if (cur->type == XML_CATA_NEXT_CATALOG) {
1813 if (cur->children == NULL) {
1814 xmlFetchXMLCatalogFile(cur);
1815 }
1816 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001817 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001818 if (ret != NULL) {
1819 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001820 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001821 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001822 }
1823 }
1824 cur = cur->next;
1825 }
1826 }
1827
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001828 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001829 return(NULL);
1830}
1831
1832/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001833 * xmlCatalogXMLResolveURI:
1834 * @catal: a catalog list
1835 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001836 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001837 *
1838 * Do a complete resolution lookup of an External Identifier for a
1839 * list of catalog entries.
1840 *
1841 * Implements (or tries to) 7.2.2. URI Resolution
1842 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1843 *
1844 * Returns the URI of the resource or NULL if not found
1845 */
1846static xmlChar *
1847xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1848 xmlChar *ret = NULL;
1849 xmlCatalogEntryPtr cur;
1850 int haveDelegate = 0;
1851 int haveNext = 0;
1852 xmlCatalogEntryPtr rewrite = NULL;
1853 int lenrewrite = 0, len;
1854
1855 if (catal == NULL)
1856 return(NULL);
1857
1858 if (URI == NULL)
1859 return(NULL);
1860
1861 /*
1862 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1863 */
1864 cur = catal;
1865 haveDelegate = 0;
1866 while (cur != NULL) {
1867 switch (cur->type) {
1868 case XML_CATA_URI:
1869 if (xmlStrEqual(URI, cur->name)) {
1870 if (xmlDebugCatalogs)
1871 xmlGenericError(xmlGenericErrorContext,
1872 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001873 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001874 }
1875 break;
1876 case XML_CATA_REWRITE_URI:
1877 len = xmlStrlen(cur->name);
1878 if ((len > lenrewrite) &&
1879 (!xmlStrncmp(URI, cur->name, len))) {
1880 lenrewrite = len;
1881 rewrite = cur;
1882 }
1883 break;
1884 case XML_CATA_DELEGATE_URI:
1885 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1886 haveDelegate++;
1887 break;
1888 case XML_CATA_NEXT_CATALOG:
1889 haveNext++;
1890 break;
1891 default:
1892 break;
1893 }
1894 cur = cur->next;
1895 }
1896 if (rewrite != NULL) {
1897 if (xmlDebugCatalogs)
1898 xmlGenericError(xmlGenericErrorContext,
1899 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001900 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001901 if (ret != NULL)
1902 ret = xmlStrcat(ret, &URI[lenrewrite]);
1903 return(ret);
1904 }
1905 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001906 const xmlChar *delegates[MAX_DELEGATE];
1907 int nbList = 0, i;
1908
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001909 /*
1910 * Assume the entries have been sorted by decreasing substring
1911 * matches when the list was produced.
1912 */
1913 cur = catal;
1914 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001915 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1916 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001917 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001918 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001919 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001920 break;
1921 if (i < nbList) {
1922 cur = cur->next;
1923 continue;
1924 }
1925 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001926 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001927
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001928 if (cur->children == NULL) {
1929 xmlFetchXMLCatalogFile(cur);
1930 }
1931 if (cur->children != NULL) {
1932 if (xmlDebugCatalogs)
1933 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001934 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001935 ret = xmlCatalogListXMLResolveURI(
1936 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001937 if (ret != NULL)
1938 return(ret);
1939 }
1940 }
1941 cur = cur->next;
1942 }
1943 /*
1944 * Apply the cut algorithm explained in 4/
1945 */
1946 return(XML_CATAL_BREAK);
1947 }
1948 if (haveNext) {
1949 cur = catal;
1950 while (cur != NULL) {
1951 if (cur->type == XML_CATA_NEXT_CATALOG) {
1952 if (cur->children == NULL) {
1953 xmlFetchXMLCatalogFile(cur);
1954 }
1955 if (cur->children != NULL) {
1956 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1957 if (ret != NULL)
1958 return(ret);
1959 }
1960 }
1961 cur = cur->next;
1962 }
1963 }
1964
1965 return(NULL);
1966}
1967
1968/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001969 * xmlCatalogListXMLResolve:
1970 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001971 * @pubID: the public ID string
1972 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001973 *
1974 * Do a complete resolution lookup of an External Identifier for a
1975 * list of catalogs
1976 *
1977 * Implements (or tries to) 7.1. External Identifier Resolution
1978 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1979 *
1980 * Returns the URI of the resource or NULL if not found
1981 */
1982static xmlChar *
1983xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1984 const xmlChar *sysID) {
1985 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001986 xmlChar *urnID = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +00001987 xmlChar *normid;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001988
1989 if (catal == NULL)
1990 return(NULL);
1991 if ((pubID == NULL) && (sysID == NULL))
1992 return(NULL);
1993
Daniel Veillardc8155052004-07-16 09:03:08 +00001994 normid = xmlCatalogNormalizePublic(pubID);
1995 if (normid != NULL)
1996 pubID = (*normid != 0 ? normid : NULL);
1997
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001998 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1999 urnID = xmlCatalogUnWrapURN(pubID);
2000 if (xmlDebugCatalogs) {
2001 if (urnID == NULL)
2002 xmlGenericError(xmlGenericErrorContext,
2003 "Public URN ID %s expanded to NULL\n", pubID);
2004 else
2005 xmlGenericError(xmlGenericErrorContext,
2006 "Public URN ID expanded to %s\n", urnID);
2007 }
2008 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2009 if (urnID != NULL)
2010 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002011 if (normid != NULL)
2012 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002013 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002014 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002015 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2016 urnID = xmlCatalogUnWrapURN(sysID);
2017 if (xmlDebugCatalogs) {
2018 if (urnID == NULL)
2019 xmlGenericError(xmlGenericErrorContext,
2020 "System URN ID %s expanded to NULL\n", sysID);
2021 else
2022 xmlGenericError(xmlGenericErrorContext,
2023 "System URN ID expanded to %s\n", urnID);
2024 }
2025 if (pubID == NULL)
2026 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2027 else if (xmlStrEqual(pubID, urnID))
2028 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2029 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00002030 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002031 }
2032 if (urnID != NULL)
2033 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002034 if (normid != NULL)
2035 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002036 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002037 }
2038 while (catal != NULL) {
2039 if (catal->type == XML_CATA_CATALOG) {
2040 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002041 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00002042 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002043 if (catal->children != NULL) {
2044 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002045 if (ret != NULL) {
2046 if (normid != NULL)
2047 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002048 return(ret);
Daniel Veillardc8155052004-07-16 09:03:08 +00002049 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002050 }
Daniel Veillardcda96922001-08-21 10:56:31 +00002051 }
2052 catal = catal->next;
2053 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002054 if (normid != NULL)
2055 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002056 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00002057}
2058
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002059/**
2060 * xmlCatalogListXMLResolveURI:
2061 * @catal: a catalog list
2062 * @URI: the URI
2063 *
2064 * Do a complete resolution lookup of an URI for a list of catalogs
2065 *
2066 * Implements (or tries to) 7.2. URI Resolution
2067 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2068 *
2069 * Returns the URI of the resource or NULL if not found
2070 */
2071static xmlChar *
2072xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2073 xmlChar *ret = NULL;
2074 xmlChar *urnID = NULL;
2075
2076 if (catal == NULL)
2077 return(NULL);
2078 if (URI == NULL)
2079 return(NULL);
2080
2081 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2082 urnID = xmlCatalogUnWrapURN(URI);
2083 if (xmlDebugCatalogs) {
2084 if (urnID == NULL)
2085 xmlGenericError(xmlGenericErrorContext,
2086 "URN ID %s expanded to NULL\n", URI);
2087 else
2088 xmlGenericError(xmlGenericErrorContext,
2089 "URN ID expanded to %s\n", urnID);
2090 }
2091 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2092 if (urnID != NULL)
2093 xmlFree(urnID);
2094 return(ret);
2095 }
2096 while (catal != NULL) {
2097 if (catal->type == XML_CATA_CATALOG) {
2098 if (catal->children == NULL) {
2099 xmlFetchXMLCatalogFile(catal);
2100 }
2101 if (catal->children != NULL) {
2102 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2103 if (ret != NULL)
2104 return(ret);
2105 }
2106 }
2107 catal = catal->next;
2108 }
2109 return(ret);
2110}
2111
Daniel Veillard344cee72001-08-20 00:08:40 +00002112/************************************************************************
2113 * *
2114 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00002115 * *
2116 ************************************************************************/
2117
2118
2119#define RAW *cur
2120#define NEXT cur++;
2121#define SKIP(x) cur += x;
2122
William M. Brack272693c2003-11-14 16:20:34 +00002123#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002124
Daniel Veillard75b96822001-10-11 18:59:45 +00002125/**
2126 * xmlParseSGMLCatalogComment:
2127 * @cur: the current character
2128 *
2129 * Skip a comment in an SGML catalog
2130 *
2131 * Returns new current character
2132 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002133static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002134xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002135 if ((cur[0] != '-') || (cur[1] != '-'))
2136 return(cur);
2137 SKIP(2);
2138 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2139 NEXT;
2140 if (cur[0] == 0) {
2141 return(NULL);
2142 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002143 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002144}
2145
Daniel Veillard75b96822001-10-11 18:59:45 +00002146/**
2147 * xmlParseSGMLCatalogPubid:
2148 * @cur: the current character
2149 * @id: the return location
2150 *
2151 * Parse an SGML catalog ID
2152 *
2153 * Returns new current character and store the value in @id
2154 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002155static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002156xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002157 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002158 int len = 0;
2159 int size = 50;
2160 xmlChar stop;
2161 int count = 0;
2162
2163 *id = NULL;
2164
2165 if (RAW == '"') {
2166 NEXT;
2167 stop = '"';
2168 } else if (RAW == '\'') {
2169 NEXT;
2170 stop = '\'';
2171 } else {
2172 stop = ' ';
2173 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002174 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002175 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002176 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002177 return(NULL);
2178 }
William M. Brack76e95df2003-10-18 16:20:14 +00002179 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002180 if ((*cur == stop) && (stop != ' '))
2181 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002182 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002183 break;
2184 if (len + 1 >= size) {
2185 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002186 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2187 if (tmp == NULL) {
2188 xmlCatalogErrMemory("allocating public ID");
2189 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002190 return(NULL);
2191 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002192 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002193 }
2194 buf[len++] = *cur;
2195 count++;
2196 NEXT;
2197 }
2198 buf[len] = 0;
2199 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002200 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002201 xmlFree(buf);
2202 return(NULL);
2203 }
2204 } else {
2205 if (*cur != stop) {
2206 xmlFree(buf);
2207 return(NULL);
2208 }
2209 NEXT;
2210 }
2211 *id = buf;
2212 return(cur);
2213}
2214
Daniel Veillard75b96822001-10-11 18:59:45 +00002215/**
2216 * xmlParseSGMLCatalogName:
2217 * @cur: the current character
2218 * @name: the return location
2219 *
2220 * Parse an SGML catalog name
2221 *
2222 * Returns new current character and store the value in @name
2223 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002224static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002225xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002226 xmlChar buf[XML_MAX_NAMELEN + 5];
2227 int len = 0;
2228 int c;
2229
2230 *name = NULL;
2231
2232 /*
2233 * Handler for more complex cases
2234 */
2235 c = *cur;
2236 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2237 return(NULL);
2238 }
2239
2240 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2241 (c == '.') || (c == '-') ||
2242 (c == '_') || (c == ':'))) {
2243 buf[len++] = c;
2244 cur++;
2245 c = *cur;
2246 if (len >= XML_MAX_NAMELEN)
2247 return(NULL);
2248 }
2249 *name = xmlStrndup(buf, len);
2250 return(cur);
2251}
2252
Daniel Veillard75b96822001-10-11 18:59:45 +00002253/**
2254 * xmlGetSGMLCatalogEntryType:
2255 * @name: the entry name
2256 *
2257 * Get the Catalog entry type for a given SGML Catalog name
2258 *
2259 * Returns Catalog entry type
2260 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002261static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002262xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002263 xmlCatalogEntryType type = XML_CATA_NONE;
2264 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2265 type = SGML_CATA_SYSTEM;
2266 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2267 type = SGML_CATA_PUBLIC;
2268 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2269 type = SGML_CATA_DELEGATE;
2270 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2271 type = SGML_CATA_ENTITY;
2272 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2273 type = SGML_CATA_DOCTYPE;
2274 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2275 type = SGML_CATA_LINKTYPE;
2276 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2277 type = SGML_CATA_NOTATION;
2278 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2279 type = SGML_CATA_SGMLDECL;
2280 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2281 type = SGML_CATA_DOCUMENT;
2282 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2283 type = SGML_CATA_CATALOG;
2284 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2285 type = SGML_CATA_BASE;
Daniel Veillard344cee72001-08-20 00:08:40 +00002286 return(type);
2287}
2288
Daniel Veillard75b96822001-10-11 18:59:45 +00002289/**
2290 * xmlParseSGMLCatalog:
2291 * @catal: the SGML Catalog
2292 * @value: the content of the SGML Catalog serialization
2293 * @file: the filepath for the catalog
2294 * @super: should this be handled as a Super Catalog in which case
2295 * parsing is not recursive
2296 *
2297 * Parse an SGML catalog content and fill up the @catal hash table with
2298 * the new entries found.
2299 *
2300 * Returns 0 in case of success, -1 in case of error.
2301 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002302static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002303xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2304 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002305 const xmlChar *cur = value;
2306 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002307 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002308
2309 if ((cur == NULL) || (file == NULL))
2310 return(-1);
2311 base = xmlStrdup((const xmlChar *) file);
2312
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002313 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002314 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002315 if (cur[0] == 0)
2316 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002317 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002318 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002319 if (cur == NULL) {
2320 /* error */
2321 break;
2322 }
2323 } else {
2324 xmlChar *sysid = NULL;
2325 xmlChar *name = NULL;
2326 xmlCatalogEntryType type = XML_CATA_NONE;
2327
Daniel Veillardcda96922001-08-21 10:56:31 +00002328 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002329 if (name == NULL) {
2330 /* error */
2331 break;
2332 }
William M. Brack76e95df2003-10-18 16:20:14 +00002333 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002334 /* error */
2335 break;
2336 }
2337 SKIP_BLANKS;
2338 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002339 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002340 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002341 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002342 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002343 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002344 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002345 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002346 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002347 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002348 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002349 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002350 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002351 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002352 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002353 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002354 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002355 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002356 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002357 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002358 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002359 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002360 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2361 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002362 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002363 if (name == NULL) {
2364 /* error */
2365 break;
2366 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002367 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002368 continue;
2369 }
2370 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002371 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002372
2373 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002374 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002375 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002376 type = SGML_CATA_PENTITY;
2377 case SGML_CATA_PENTITY:
2378 case SGML_CATA_DOCTYPE:
2379 case SGML_CATA_LINKTYPE:
2380 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002381 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002382 if (cur == NULL) {
2383 /* error */
2384 break;
2385 }
William M. Brack76e95df2003-10-18 16:20:14 +00002386 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002387 /* error */
2388 break;
2389 }
2390 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002391 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002392 if (cur == NULL) {
2393 /* error */
2394 break;
2395 }
2396 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002397 case SGML_CATA_PUBLIC:
2398 case SGML_CATA_SYSTEM:
2399 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002400 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002401 if (cur == NULL) {
2402 /* error */
2403 break;
2404 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002405 if (type != SGML_CATA_SYSTEM) {
2406 xmlChar *normid;
2407
2408 normid = xmlCatalogNormalizePublic(name);
2409 if (normid != NULL) {
2410 if (name != NULL)
2411 xmlFree(name);
2412 if (*normid != 0)
2413 name = normid;
2414 else {
2415 xmlFree(normid);
2416 name = NULL;
2417 }
2418 }
2419 }
William M. Brack76e95df2003-10-18 16:20:14 +00002420 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002421 /* error */
2422 break;
2423 }
2424 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002425 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002426 if (cur == NULL) {
2427 /* error */
2428 break;
2429 }
2430 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002431 case SGML_CATA_BASE:
2432 case SGML_CATA_CATALOG:
2433 case SGML_CATA_DOCUMENT:
2434 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002435 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002436 if (cur == NULL) {
2437 /* error */
2438 break;
2439 }
2440 break;
2441 default:
2442 break;
2443 }
2444 if (cur == NULL) {
2445 if (name != NULL)
2446 xmlFree(name);
2447 if (sysid != NULL)
2448 xmlFree(sysid);
2449 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002450 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002451 if (base != NULL)
2452 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002453 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002454 } else if ((type == SGML_CATA_PUBLIC) ||
2455 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002456 xmlChar *filename;
2457
2458 filename = xmlBuildURI(sysid, base);
2459 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002460 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002461
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002462 entry = xmlNewCatalogEntry(type, name, filename,
William M. Brackb7b54de2004-10-06 16:38:01 +00002463 NULL, XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002464 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002465 if (res < 0) {
2466 xmlFreeCatalogEntry(entry);
2467 }
2468 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002469 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002470
Daniel Veillard344cee72001-08-20 00:08:40 +00002471 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002472 if (super) {
2473 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002474
Daniel Veillardc853b322001-11-06 15:24:37 +00002475 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002476 XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002477 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002478 if (res < 0) {
2479 xmlFreeCatalogEntry(entry);
2480 }
2481 } else {
2482 xmlChar *filename;
2483
2484 filename = xmlBuildURI(sysid, base);
2485 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002486 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002487 xmlFree(filename);
2488 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002489 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002490 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002491 /*
2492 * drop anything else we won't handle it
2493 */
2494 if (name != NULL)
2495 xmlFree(name);
2496 if (sysid != NULL)
2497 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002498 }
2499 }
2500 if (base != NULL)
2501 xmlFree(base);
2502 if (cur == NULL)
2503 return(-1);
2504 return(0);
2505}
2506
Daniel Veillard75b96822001-10-11 18:59:45 +00002507/************************************************************************
2508 * *
2509 * SGML Catalog handling *
2510 * *
2511 ************************************************************************/
2512
Daniel Veillardcda96922001-08-21 10:56:31 +00002513/**
2514 * xmlCatalogGetSGMLPublic:
2515 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002516 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002517 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002518 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002519 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002520 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002521 */
2522static const xmlChar *
2523xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2524 xmlCatalogEntryPtr entry;
Daniel Veillardc8155052004-07-16 09:03:08 +00002525 xmlChar *normid;
Daniel Veillardcda96922001-08-21 10:56:31 +00002526
2527 if (catal == NULL)
2528 return(NULL);
2529
Daniel Veillardc8155052004-07-16 09:03:08 +00002530 normid = xmlCatalogNormalizePublic(pubID);
2531 if (normid != NULL)
2532 pubID = (*normid != 0 ? normid : NULL);
2533
Daniel Veillardcda96922001-08-21 10:56:31 +00002534 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002535 if (entry == NULL) {
2536 if (normid != NULL)
2537 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002538 return(NULL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002539 }
2540 if (entry->type == SGML_CATA_PUBLIC) {
2541 if (normid != NULL)
2542 xmlFree(normid);
Daniel Veillardc853b322001-11-06 15:24:37 +00002543 return(entry->URL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002544 }
2545 if (normid != NULL)
2546 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002547 return(NULL);
2548}
2549
2550/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002551 * xmlCatalogGetSGMLSystem:
2552 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002553 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002554 *
2555 * Try to lookup the catalog local reference for a system ID
2556 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002557 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002558 */
2559static const xmlChar *
2560xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2561 xmlCatalogEntryPtr entry;
2562
2563 if (catal == NULL)
2564 return(NULL);
2565
2566 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2567 if (entry == NULL)
2568 return(NULL);
2569 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002570 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002571 return(NULL);
2572}
2573
2574/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002575 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002576 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002577 * @pubID: the public ID string
2578 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002579 *
2580 * Do a complete resolution lookup of an External Identifier
2581 *
2582 * Returns the URI of the resource or NULL if not found
2583 */
2584static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002585xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2586 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002587 const xmlChar *ret = NULL;
2588
Daniel Veillard75b96822001-10-11 18:59:45 +00002589 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002590 return(NULL);
2591
2592 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002593 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002594 if (ret != NULL)
2595 return(ret);
2596 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002597 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002598 return(NULL);
2599}
2600
Daniel Veillarda7374592001-05-10 14:17:55 +00002601/************************************************************************
2602 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002603 * Specific Public interfaces *
2604 * *
2605 ************************************************************************/
2606
2607/**
2608 * xmlLoadSGMLSuperCatalog:
2609 * @filename: a file path
2610 *
2611 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2612 * references. This is only needed for manipulating SGML Super Catalogs
2613 * like adding and removing CATALOG or DELEGATE entries.
2614 *
2615 * Returns the catalog parsed or NULL in case of error
2616 */
2617xmlCatalogPtr
2618xmlLoadSGMLSuperCatalog(const char *filename)
2619{
2620 xmlChar *content;
2621 xmlCatalogPtr catal;
2622 int ret;
2623
2624 content = xmlLoadFileContent(filename);
2625 if (content == NULL)
2626 return(NULL);
2627
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002628 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002629 if (catal == NULL) {
2630 xmlFree(content);
2631 return(NULL);
2632 }
2633
2634 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2635 xmlFree(content);
2636 if (ret < 0) {
2637 xmlFreeCatalog(catal);
2638 return(NULL);
2639 }
2640 return (catal);
2641}
2642
2643/**
2644 * xmlLoadACatalog:
2645 * @filename: a file path
2646 *
2647 * Load the catalog and build the associated data structures.
2648 * This can be either an XML Catalog or an SGML Catalog
2649 * It will recurse in SGML CATALOG entries. On the other hand XML
2650 * Catalogs are not handled recursively.
2651 *
2652 * Returns the catalog parsed or NULL in case of error
2653 */
2654xmlCatalogPtr
2655xmlLoadACatalog(const char *filename)
2656{
2657 xmlChar *content;
2658 xmlChar *first;
2659 xmlCatalogPtr catal;
2660 int ret;
2661
2662 content = xmlLoadFileContent(filename);
2663 if (content == NULL)
2664 return(NULL);
2665
2666
2667 first = content;
2668
2669 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2670 (!(((*first >= 'A') && (*first <= 'Z')) ||
2671 ((*first >= 'a') && (*first <= 'z')))))
2672 first++;
2673
2674 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002675 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002676 if (catal == NULL) {
2677 xmlFree(content);
2678 return(NULL);
2679 }
2680 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2681 if (ret < 0) {
2682 xmlFreeCatalog(catal);
2683 xmlFree(content);
2684 return(NULL);
2685 }
2686 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002687 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002688 if (catal == NULL) {
2689 xmlFree(content);
2690 return(NULL);
2691 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002692 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002693 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002694 }
2695 xmlFree(content);
2696 return (catal);
2697}
2698
2699/**
2700 * xmlExpandCatalog:
2701 * @catal: a catalog
2702 * @filename: a file path
2703 *
2704 * Load the catalog and expand the existing catal structure.
2705 * This can be either an XML Catalog or an SGML Catalog
2706 *
2707 * Returns 0 in case of success, -1 in case of error
2708 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002709static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002710xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2711{
Daniel Veillard75b96822001-10-11 18:59:45 +00002712 int ret;
2713
2714 if ((catal == NULL) || (filename == NULL))
2715 return(-1);
2716
Daniel Veillard75b96822001-10-11 18:59:45 +00002717
2718 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002719 xmlChar *content;
2720
2721 content = xmlLoadFileContent(filename);
2722 if (content == NULL)
2723 return(-1);
2724
Daniel Veillard75b96822001-10-11 18:59:45 +00002725 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2726 if (ret < 0) {
2727 xmlFree(content);
2728 return(-1);
2729 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002730 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002731 } else {
2732 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002733 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002734 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002735
Daniel Veillard75b96822001-10-11 18:59:45 +00002736 cur = catal->xml;
2737 if (cur == NULL) {
2738 catal->xml = tmp;
2739 } else {
2740 while (cur->next != NULL) cur = cur->next;
2741 cur->next = tmp;
2742 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002743 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002744 return (0);
2745}
2746
2747/**
2748 * xmlACatalogResolveSystem:
2749 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002750 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002751 *
2752 * Try to lookup the catalog resource for a system ID
2753 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002754 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002755 * must be freed by the caller.
2756 */
2757xmlChar *
2758xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2759 xmlChar *ret = NULL;
2760
2761 if ((sysID == NULL) || (catal == NULL))
2762 return(NULL);
2763
2764 if (xmlDebugCatalogs)
2765 xmlGenericError(xmlGenericErrorContext,
2766 "Resolve sysID %s\n", sysID);
2767
2768 if (catal->type == XML_XML_CATALOG_TYPE) {
2769 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2770 if (ret == XML_CATAL_BREAK)
2771 ret = NULL;
2772 } else {
2773 const xmlChar *sgml;
2774
2775 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2776 if (sgml != NULL)
2777 ret = xmlStrdup(sgml);
2778 }
2779 return(ret);
2780}
2781
2782/**
2783 * xmlACatalogResolvePublic:
2784 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002785 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002786 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002787 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002788 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002789 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002790 * must be freed by the caller.
2791 */
2792xmlChar *
2793xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2794 xmlChar *ret = NULL;
2795
2796 if ((pubID == NULL) || (catal == NULL))
2797 return(NULL);
2798
2799 if (xmlDebugCatalogs)
2800 xmlGenericError(xmlGenericErrorContext,
2801 "Resolve pubID %s\n", pubID);
2802
2803 if (catal->type == XML_XML_CATALOG_TYPE) {
2804 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2805 if (ret == XML_CATAL_BREAK)
2806 ret = NULL;
2807 } else {
2808 const xmlChar *sgml;
2809
2810 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2811 if (sgml != NULL)
2812 ret = xmlStrdup(sgml);
2813 }
2814 return(ret);
2815}
2816
2817/**
2818 * xmlACatalogResolve:
2819 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002820 * @pubID: the public ID string
2821 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002822 *
2823 * Do a complete resolution lookup of an External Identifier
2824 *
2825 * Returns the URI of the resource or NULL if not found, it must be freed
2826 * by the caller.
2827 */
2828xmlChar *
2829xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2830 const xmlChar * sysID)
2831{
2832 xmlChar *ret = NULL;
2833
2834 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2835 return (NULL);
2836
2837 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002838 if ((pubID != NULL) && (sysID != NULL)) {
2839 xmlGenericError(xmlGenericErrorContext,
2840 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2841 } else if (pubID != NULL) {
2842 xmlGenericError(xmlGenericErrorContext,
2843 "Resolve: pubID %s\n", pubID);
2844 } else {
2845 xmlGenericError(xmlGenericErrorContext,
2846 "Resolve: sysID %s\n", sysID);
2847 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002848 }
2849
2850 if (catal->type == XML_XML_CATALOG_TYPE) {
2851 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2852 if (ret == XML_CATAL_BREAK)
2853 ret = NULL;
2854 } else {
2855 const xmlChar *sgml;
2856
2857 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2858 if (sgml != NULL)
2859 ret = xmlStrdup(sgml);
2860 }
2861 return (ret);
2862}
2863
2864/**
2865 * xmlACatalogResolveURI:
2866 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002867 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002868 *
2869 * Do a complete resolution lookup of an URI
2870 *
2871 * Returns the URI of the resource or NULL if not found, it must be freed
2872 * by the caller.
2873 */
2874xmlChar *
2875xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2876 xmlChar *ret = NULL;
2877
2878 if ((URI == NULL) || (catal == NULL))
2879 return(NULL);
2880
Daniel Veillardb44025c2001-10-11 22:55:55 +00002881 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002882 xmlGenericError(xmlGenericErrorContext,
2883 "Resolve URI %s\n", URI);
2884
2885 if (catal->type == XML_XML_CATALOG_TYPE) {
2886 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2887 if (ret == XML_CATAL_BREAK)
2888 ret = NULL;
2889 } else {
2890 const xmlChar *sgml;
2891
2892 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2893 if (sgml != NULL)
2894 sgml = xmlStrdup(sgml);
2895 }
2896 return(ret);
2897}
2898
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002899#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002900/**
2901 * xmlACatalogDump:
2902 * @catal: a Catalog
2903 * @out: the file.
2904 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002905 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002906 */
2907void
2908xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002909 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002910 return;
2911
2912 if (catal->type == XML_XML_CATALOG_TYPE) {
2913 xmlDumpXMLCatalog(out, catal->xml);
2914 } else {
2915 xmlHashScan(catal->sgml,
2916 (xmlHashScanner) xmlCatalogDumpEntry, out);
2917 }
2918}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002919#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002920
2921/**
2922 * xmlACatalogAdd:
2923 * @catal: a Catalog
2924 * @type: the type of record to add to the catalog
2925 * @orig: the system, public or prefix to match
2926 * @replace: the replacement value for the match
2927 *
2928 * Add an entry in the catalog, it may overwrite existing but
2929 * different entries.
2930 *
2931 * Returns 0 if successful, -1 otherwise
2932 */
2933int
2934xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2935 const xmlChar * orig, const xmlChar * replace)
2936{
2937 int res = -1;
2938
2939 if (catal == NULL)
2940 return(-1);
2941
2942 if (catal->type == XML_XML_CATALOG_TYPE) {
2943 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2944 } else {
2945 xmlCatalogEntryType cattype;
2946
2947 cattype = xmlGetSGMLCatalogEntryType(type);
2948 if (cattype != XML_CATA_NONE) {
2949 xmlCatalogEntryPtr entry;
2950
Daniel Veillardc853b322001-11-06 15:24:37 +00002951 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002952 XML_CATA_PREFER_NONE, NULL);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002953 if (catal->sgml == NULL)
2954 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002955 res = xmlHashAddEntry(catal->sgml, orig, entry);
2956 }
2957 }
2958 return (res);
2959}
2960
2961/**
2962 * xmlACatalogRemove:
2963 * @catal: a Catalog
2964 * @value: the value to remove
2965 *
2966 * Remove an entry from the catalog
2967 *
2968 * Returns the number of entries removed if successful, -1 otherwise
2969 */
2970int
2971xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2972 int res = -1;
2973
2974 if ((catal == NULL) || (value == NULL))
2975 return(-1);
2976
2977 if (catal->type == XML_XML_CATALOG_TYPE) {
2978 res = xmlDelXMLCatalog(catal->xml, value);
2979 } else {
2980 res = xmlHashRemoveEntry(catal->sgml, value,
2981 (xmlHashDeallocator) xmlFreeCatalogEntry);
2982 if (res == 0)
2983 res = 1;
2984 }
2985 return(res);
2986}
2987
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002988/**
2989 * xmlNewCatalog:
2990 * @sgml: should this create an SGML catalog
2991 *
2992 * create a new Catalog.
2993 *
2994 * Returns the xmlCatalogPtr or NULL in case of error
2995 */
2996xmlCatalogPtr
2997xmlNewCatalog(int sgml) {
2998 xmlCatalogPtr catal = NULL;
2999
3000 if (sgml) {
3001 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3002 xmlCatalogDefaultPrefer);
3003 if ((catal != NULL) && (catal->sgml == NULL))
3004 catal->sgml = xmlHashCreate(10);
3005 } else
3006 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3007 xmlCatalogDefaultPrefer);
3008 return(catal);
3009}
3010
3011/**
3012 * xmlCatalogIsEmpty:
3013 * @catal: should this create an SGML catalog
3014 *
3015 * Check is a catalog is empty
3016 *
3017 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3018 */
3019int
3020xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3021 if (catal == NULL)
3022 return(-1);
3023
3024 if (catal->type == XML_XML_CATALOG_TYPE) {
3025 if (catal->xml == NULL)
3026 return(1);
3027 if ((catal->xml->type != XML_CATA_CATALOG) &&
3028 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3029 return(-1);
3030 if (catal->xml->children == NULL)
3031 return(1);
3032 return(0);
3033 } else {
3034 int res;
3035
3036 if (catal->sgml == NULL)
3037 return(1);
3038 res = xmlHashSize(catal->sgml);
3039 if (res == 0)
3040 return(1);
3041 if (res < 0)
3042 return(-1);
3043 }
3044 return(0);
3045}
3046
Daniel Veillard75b96822001-10-11 18:59:45 +00003047/************************************************************************
3048 * *
3049 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00003050 * *
3051 ************************************************************************/
3052
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003053/**
Daniel Veillard81463942001-10-16 12:34:39 +00003054 * xmlInitializeCatalogData:
3055 *
3056 * Do the catalog initialization only of global data, doesn't try to load
3057 * any catalog actually.
3058 * this function is not thread safe, catalog initialization should
3059 * preferably be done once at startup
3060 */
3061static void
3062xmlInitializeCatalogData(void) {
3063 if (xmlCatalogInitialized != 0)
3064 return;
3065
3066 if (getenv("XML_DEBUG_CATALOG"))
3067 xmlDebugCatalogs = 1;
3068 xmlCatalogMutex = xmlNewRMutex();
3069
3070 xmlCatalogInitialized = 1;
3071}
3072/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003073 * xmlInitializeCatalog:
3074 *
3075 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00003076 * this function is not thread safe, catalog initialization should
3077 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003078 */
3079void
3080xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003081 if (xmlCatalogInitialized != 0)
3082 return;
3083
Daniel Veillard81463942001-10-16 12:34:39 +00003084 xmlInitializeCatalogData();
3085 xmlRMutexLock(xmlCatalogMutex);
3086
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003087 if (getenv("XML_DEBUG_CATALOG"))
3088 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00003089
Daniel Veillard75b96822001-10-11 18:59:45 +00003090 if (xmlDefaultCatalog == NULL) {
3091 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003092 char *path;
3093 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00003094 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003095 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00003096
Daniel Veillardb44025c2001-10-11 22:55:55 +00003097 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003098 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003099#if defined(_WIN32) && defined(_MSC_VER)
3100 {
3101 void* hmodule;
3102 hmodule = GetModuleHandleA("libxml2.dll");
3103 if (hmodule == NULL)
3104 hmodule = GetModuleHandleA(NULL);
3105 if (hmodule != NULL) {
3106 char buf[256];
3107 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3108 if (len != 0) {
3109 char* p = &(buf[len]);
3110 while (*p != '\\' && p > buf)
3111 p--;
3112 if (p != buf) {
3113 xmlChar* uri;
3114 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3115 uri = xmlCanonicPath(buf);
3116 if (uri != NULL) {
3117 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3118 xmlFree(uri);
3119 }
3120 }
3121 }
3122 }
3123 catalogs = XML_XML_DEFAULT_CATALOG;
3124 }
3125#else
Daniel Veillard75b96822001-10-11 18:59:45 +00003126 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00003127#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00003128
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003129 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3130 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003131 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003132 /* the XML_CATALOG_FILES envvar is allowed to contain a
3133 space-separated list of entries. */
3134 cur = catalogs;
3135 nextent = &catal->xml;
3136 while (*cur != '\0') {
William M. Brack68aca052003-10-11 15:22:13 +00003137 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003138 cur++;
3139 if (*cur != 0) {
3140 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003141 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003142 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00003143 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003144 if (path != NULL) {
3145 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003146 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003147 if (*nextent != NULL)
3148 nextent = &((*nextent)->next);
3149 xmlFree(path);
3150 }
3151 }
3152 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003153 xmlDefaultCatalog = catal;
3154 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003155 }
3156
Daniel Veillard81463942001-10-16 12:34:39 +00003157 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003158}
3159
Daniel Veillard82d75332001-10-08 15:01:59 +00003160
3161/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003162 * xmlLoadCatalog:
3163 * @filename: a file path
3164 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003165 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003166 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003167 * this function is not thread safe, catalog initialization should
3168 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003169 *
3170 * Returns 0 in case of success -1 in case of error
3171 */
3172int
Daniel Veillard16756b62001-10-01 07:36:25 +00003173xmlLoadCatalog(const char *filename)
3174{
Daniel Veillard75b96822001-10-11 18:59:45 +00003175 int ret;
3176 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003177
Daniel Veillard81463942001-10-16 12:34:39 +00003178 if (!xmlCatalogInitialized)
3179 xmlInitializeCatalogData();
3180
3181 xmlRMutexLock(xmlCatalogMutex);
3182
Daniel Veillard75b96822001-10-11 18:59:45 +00003183 if (xmlDefaultCatalog == NULL) {
3184 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003185 if (catal == NULL) {
3186 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003187 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003188 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003189
Daniel Veillard75b96822001-10-11 18:59:45 +00003190 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003191 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003192 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003193 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003194
Daniel Veillard75b96822001-10-11 18:59:45 +00003195 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003196 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003197 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003198}
3199
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003200/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003201 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003202 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003203 *
3204 * Load the catalogs and makes their definitions effective for the default
3205 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003206 * this function is not thread safe, catalog initialization should
3207 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003208 */
3209void
3210xmlLoadCatalogs(const char *pathss) {
3211 const char *cur;
3212 const char *paths;
3213 xmlChar *path;
3214
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003215 if (pathss == NULL)
3216 return;
3217
Daniel Veillard81418e32001-05-22 15:08:55 +00003218 cur = pathss;
3219 while ((cur != NULL) && (*cur != 0)) {
William M. Brack68aca052003-10-11 15:22:13 +00003220 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003221 if (*cur != 0) {
3222 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003223 while ((*cur != 0) && (*cur != ':') && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003224 cur++;
3225 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3226 if (path != NULL) {
3227 xmlLoadCatalog((const char *) path);
3228 xmlFree(path);
3229 }
3230 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003231 while (*cur == ':')
3232 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003233 }
3234}
3235
Daniel Veillarda7374592001-05-10 14:17:55 +00003236/**
3237 * xmlCatalogCleanup:
3238 *
3239 * Free up all the memory associated with catalogs
3240 */
3241void
3242xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003243 if (xmlCatalogInitialized == 0)
3244 return;
3245
Daniel Veillard81463942001-10-16 12:34:39 +00003246 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003247 if (xmlDebugCatalogs)
3248 xmlGenericError(xmlGenericErrorContext,
3249 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003250 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003251 xmlHashFree(xmlCatalogXMLFiles,
3252 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003253 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003254 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003255 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003256 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003257 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003258 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003259 xmlRMutexUnlock(xmlCatalogMutex);
3260 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003261}
3262
3263/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003264 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003265 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003266 *
3267 * Try to lookup the catalog resource for a system ID
3268 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003269 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003270 * must be freed by the caller.
3271 */
3272xmlChar *
3273xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003274 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003275
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003276 if (!xmlCatalogInitialized)
3277 xmlInitializeCatalog();
3278
Daniel Veillard75b96822001-10-11 18:59:45 +00003279 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3280 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003281}
3282
3283/**
3284 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003285 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003286 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003287 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003288 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003289 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003290 * must be freed by the caller.
3291 */
3292xmlChar *
3293xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003294 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003295
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003296 if (!xmlCatalogInitialized)
3297 xmlInitializeCatalog();
3298
Daniel Veillard75b96822001-10-11 18:59:45 +00003299 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3300 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003301}
Daniel Veillard344cee72001-08-20 00:08:40 +00003302
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003303/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003304 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003305 * @pubID: the public ID string
3306 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003307 *
3308 * Do a complete resolution lookup of an External Identifier
3309 *
3310 * Returns the URI of the resource or NULL if not found, it must be freed
3311 * by the caller.
3312 */
3313xmlChar *
3314xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003315 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003316
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003317 if (!xmlCatalogInitialized)
3318 xmlInitializeCatalog();
3319
Daniel Veillard75b96822001-10-11 18:59:45 +00003320 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3321 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003322}
3323
3324/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003325 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003326 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003327 *
3328 * Do a complete resolution lookup of an URI
3329 *
3330 * Returns the URI of the resource or NULL if not found, it must be freed
3331 * by the caller.
3332 */
3333xmlChar *
3334xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003335 xmlChar *ret;
3336
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003337 if (!xmlCatalogInitialized)
3338 xmlInitializeCatalog();
3339
Daniel Veillard75b96822001-10-11 18:59:45 +00003340 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3341 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003342}
3343
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003344#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003345/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003346 * xmlCatalogDump:
3347 * @out: the file.
3348 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003349 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003350 */
3351void
3352xmlCatalogDump(FILE *out) {
3353 if (out == NULL)
3354 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003355
Daniel Veillard75b96822001-10-11 18:59:45 +00003356 if (!xmlCatalogInitialized)
3357 xmlInitializeCatalog();
3358
3359 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003360}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003361#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003362
3363/**
3364 * xmlCatalogAdd:
3365 * @type: the type of record to add to the catalog
3366 * @orig: the system, public or prefix to match
3367 * @replace: the replacement value for the match
3368 *
3369 * Add an entry in the catalog, it may overwrite existing but
3370 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003371 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003372 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003373 *
3374 * Returns 0 if successful, -1 otherwise
3375 */
3376int
3377xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3378 int res = -1;
3379
Daniel Veillard81463942001-10-16 12:34:39 +00003380 if (!xmlCatalogInitialized)
3381 xmlInitializeCatalogData();
3382
3383 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003384 /*
3385 * Specific case where one want to override the default catalog
3386 * put in place by xmlInitializeCatalog();
3387 */
3388 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003389 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003390 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003391 xmlCatalogDefaultPrefer);
3392 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003393 orig, NULL, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003394
Daniel Veillard81463942001-10-16 12:34:39 +00003395 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003396 return(0);
3397 }
3398
Daniel Veillard75b96822001-10-11 18:59:45 +00003399 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003400 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003401 return(res);
3402}
3403
3404/**
3405 * xmlCatalogRemove:
3406 * @value: the value to remove
3407 *
3408 * Remove an entry from the catalog
3409 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003410 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003411 */
3412int
3413xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003414 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003415
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003416 if (!xmlCatalogInitialized)
3417 xmlInitializeCatalog();
3418
Daniel Veillard81463942001-10-16 12:34:39 +00003419 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003420 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003421 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003422 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003423}
3424
3425/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003426 * xmlCatalogConvert:
3427 *
3428 * Convert all the SGML catalog entries as XML ones
3429 *
3430 * Returns the number of entries converted if successful, -1 otherwise
3431 */
3432int
3433xmlCatalogConvert(void) {
3434 int res = -1;
3435
3436 if (!xmlCatalogInitialized)
3437 xmlInitializeCatalog();
3438
Daniel Veillard81463942001-10-16 12:34:39 +00003439 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003440 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003441 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003442 return(res);
3443}
3444
Daniel Veillard75b96822001-10-11 18:59:45 +00003445/************************************************************************
3446 * *
3447 * Public interface manipulating the common preferences *
3448 * *
3449 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003450
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003451/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003452 * xmlCatalogGetDefaults:
3453 *
3454 * Used to get the user preference w.r.t. to what catalogs should
3455 * be accepted
3456 *
3457 * Returns the current xmlCatalogAllow value
3458 */
3459xmlCatalogAllow
3460xmlCatalogGetDefaults(void) {
3461 return(xmlCatalogDefaultAllow);
3462}
3463
3464/**
3465 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003466 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003467 *
3468 * Used to set the user preference w.r.t. to what catalogs should
3469 * be accepted
3470 */
3471void
3472xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003473 if (xmlDebugCatalogs) {
3474 switch (allow) {
3475 case XML_CATA_ALLOW_NONE:
3476 xmlGenericError(xmlGenericErrorContext,
3477 "Disabling catalog usage\n");
3478 break;
3479 case XML_CATA_ALLOW_GLOBAL:
3480 xmlGenericError(xmlGenericErrorContext,
3481 "Allowing only global catalogs\n");
3482 break;
3483 case XML_CATA_ALLOW_DOCUMENT:
3484 xmlGenericError(xmlGenericErrorContext,
3485 "Allowing only catalogs from the document\n");
3486 break;
3487 case XML_CATA_ALLOW_ALL:
3488 xmlGenericError(xmlGenericErrorContext,
3489 "Allowing all catalogs\n");
3490 break;
3491 }
3492 }
3493 xmlCatalogDefaultAllow = allow;
3494}
3495
3496/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003497 * xmlCatalogSetDefaultPrefer:
3498 * @prefer: the default preference for delegation
3499 *
3500 * Allows to set the preference between public and system for deletion
3501 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003502 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003503 *
3504 * Returns the previous value of the default preference for delegation
3505 */
3506xmlCatalogPrefer
3507xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3508 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3509
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003510 if (prefer == XML_CATA_PREFER_NONE)
3511 return(ret);
3512
3513 if (xmlDebugCatalogs) {
3514 switch (prefer) {
3515 case XML_CATA_PREFER_PUBLIC:
3516 xmlGenericError(xmlGenericErrorContext,
3517 "Setting catalog preference to PUBLIC\n");
3518 break;
3519 case XML_CATA_PREFER_SYSTEM:
3520 xmlGenericError(xmlGenericErrorContext,
3521 "Setting catalog preference to SYSTEM\n");
3522 break;
3523 case XML_CATA_PREFER_NONE:
3524 break;
3525 }
3526 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003527 xmlCatalogDefaultPrefer = prefer;
3528 return(ret);
3529}
3530
3531/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003532 * xmlCatalogSetDebug:
3533 * @level: the debug level of catalogs required
3534 *
3535 * Used to set the debug level for catalog operation, 0 disable
3536 * debugging, 1 enable it
3537 *
3538 * Returns the previous value of the catalog debugging level
3539 */
3540int
3541xmlCatalogSetDebug(int level) {
3542 int ret = xmlDebugCatalogs;
3543
3544 if (level <= 0)
3545 xmlDebugCatalogs = 0;
3546 else
3547 xmlDebugCatalogs = level;
3548 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003549}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003550
Daniel Veillard75b96822001-10-11 18:59:45 +00003551/************************************************************************
3552 * *
3553 * Minimal interfaces used for per-document catalogs by the parser *
3554 * *
3555 ************************************************************************/
3556
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003557/**
3558 * xmlCatalogFreeLocal:
3559 * @catalogs: a document's list of catalogs
3560 *
3561 * Free up the memory associated to the catalog list
3562 */
3563void
3564xmlCatalogFreeLocal(void *catalogs) {
3565 xmlCatalogEntryPtr catal;
3566
Daniel Veillard81463942001-10-16 12:34:39 +00003567 if (!xmlCatalogInitialized)
3568 xmlInitializeCatalog();
3569
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003570 catal = (xmlCatalogEntryPtr) catalogs;
3571 if (catal != NULL)
3572 xmlFreeCatalogEntryList(catal);
3573}
3574
3575
3576/**
3577 * xmlCatalogAddLocal:
3578 * @catalogs: a document's list of catalogs
3579 * @URL: the URL to a new local catalog
3580 *
3581 * Add the new entry to the catalog list
3582 *
3583 * Returns the updated list
3584 */
3585void *
3586xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3587 xmlCatalogEntryPtr catal, add;
3588
3589 if (!xmlCatalogInitialized)
3590 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003591
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003592 if (URL == NULL)
3593 return(catalogs);
3594
3595 if (xmlDebugCatalogs)
3596 xmlGenericError(xmlGenericErrorContext,
3597 "Adding document catalog %s\n", URL);
3598
Daniel Veillardc853b322001-11-06 15:24:37 +00003599 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003600 xmlCatalogDefaultPrefer, NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003601 if (add == NULL)
3602 return(catalogs);
3603
3604 catal = (xmlCatalogEntryPtr) catalogs;
3605 if (catal == NULL)
3606 return((void *) add);
3607
3608 while (catal->next != NULL)
3609 catal = catal->next;
3610 catal->next = add;
3611 return(catalogs);
3612}
3613
3614/**
3615 * xmlCatalogLocalResolve:
3616 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003617 * @pubID: the public ID string
3618 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003619 *
3620 * Do a complete resolution lookup of an External Identifier using a
3621 * document's private catalog list
3622 *
3623 * Returns the URI of the resource or NULL if not found, it must be freed
3624 * by the caller.
3625 */
3626xmlChar *
3627xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3628 const xmlChar *sysID) {
3629 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003630 xmlChar *ret;
3631
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003632 if (!xmlCatalogInitialized)
3633 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003634
Daniel Veillard81463942001-10-16 12:34:39 +00003635 if ((pubID == NULL) && (sysID == NULL))
3636 return(NULL);
3637
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003638 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003639 if ((pubID != NULL) && (sysID != NULL)) {
3640 xmlGenericError(xmlGenericErrorContext,
3641 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3642 } else if (pubID != NULL) {
3643 xmlGenericError(xmlGenericErrorContext,
3644 "Local Resolve: pubID %s\n", pubID);
3645 } else {
3646 xmlGenericError(xmlGenericErrorContext,
3647 "Local Resolve: sysID %s\n", sysID);
3648 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003649 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003650
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003651 catal = (xmlCatalogEntryPtr) catalogs;
3652 if (catal == NULL)
3653 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003654 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3655 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3656 return(ret);
3657 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003658}
3659
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003660/**
3661 * xmlCatalogLocalResolveURI:
3662 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003663 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003664 *
3665 * Do a complete resolution lookup of an URI using a
3666 * document's private catalog list
3667 *
3668 * Returns the URI of the resource or NULL if not found, it must be freed
3669 * by the caller.
3670 */
3671xmlChar *
3672xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3673 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003674 xmlChar *ret;
3675
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003676 if (!xmlCatalogInitialized)
3677 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003678
Daniel Veillard81463942001-10-16 12:34:39 +00003679 if (URI == NULL)
3680 return(NULL);
3681
Daniel Veillard6990bf32001-08-23 21:17:48 +00003682 if (xmlDebugCatalogs)
3683 xmlGenericError(xmlGenericErrorContext,
3684 "Resolve URI %s\n", URI);
3685
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003686 catal = (xmlCatalogEntryPtr) catalogs;
3687 if (catal == NULL)
3688 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003689 ret = xmlCatalogListXMLResolveURI(catal, URI);
3690 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3691 return(ret);
3692 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003693}
3694
Daniel Veillard75b96822001-10-11 18:59:45 +00003695/************************************************************************
3696 * *
3697 * Deprecated interfaces *
3698 * *
3699 ************************************************************************/
3700/**
3701 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003702 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003703 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003704 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003705 * DEPRECATED, use xmlCatalogResolveSystem()
3706 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003707 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003708 */
3709const xmlChar *
3710xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003711 xmlChar *ret;
3712 static xmlChar result[1000];
3713 static int msg = 0;
3714
3715 if (!xmlCatalogInitialized)
3716 xmlInitializeCatalog();
3717
3718 if (msg == 0) {
3719 xmlGenericError(xmlGenericErrorContext,
3720 "Use of deprecated xmlCatalogGetSystem() call\n");
3721 msg++;
3722 }
3723
3724 if (sysID == NULL)
3725 return(NULL);
3726
3727 /*
3728 * Check first the XML catalogs
3729 */
3730 if (xmlDefaultCatalog != NULL) {
3731 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3732 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3733 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3734 result[sizeof(result) - 1] = 0;
3735 return(result);
3736 }
3737 }
3738
3739 if (xmlDefaultCatalog != NULL)
3740 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3741 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003742}
3743
3744/**
3745 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003746 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003747 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003748 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003749 * DEPRECATED, use xmlCatalogResolvePublic()
3750 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003751 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003752 */
3753const xmlChar *
3754xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003755 xmlChar *ret;
3756 static xmlChar result[1000];
3757 static int msg = 0;
3758
3759 if (!xmlCatalogInitialized)
3760 xmlInitializeCatalog();
3761
3762 if (msg == 0) {
3763 xmlGenericError(xmlGenericErrorContext,
3764 "Use of deprecated xmlCatalogGetPublic() call\n");
3765 msg++;
3766 }
3767
3768 if (pubID == NULL)
3769 return(NULL);
3770
3771 /*
3772 * Check first the XML catalogs
3773 */
3774 if (xmlDefaultCatalog != NULL) {
3775 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3776 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3777 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3778 result[sizeof(result) - 1] = 0;
3779 return(result);
3780 }
3781 }
3782
3783 if (xmlDefaultCatalog != NULL)
3784 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3785 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003786}
3787
Daniel Veillarda7374592001-05-10 14:17:55 +00003788#endif /* LIBXML_CATALOG_ENABLED */