blob: 95ebee8f684442c3122d50d80fc4370ecb211952 [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 Veillarded121382007-04-17 12:33:19 +000047#ifdef _WIN32
48# define PATH_SEAPARATOR ';'
49#else
50# define PATH_SEAPARATOR ':'
51#endif
52
Daniel Veillard344cee72001-08-20 00:08:40 +000053/**
54 * TODO:
55 *
56 * macro to flag unimplemented blocks
Daniel Veillard3e59fc52003-04-18 12:34:58 +000057 * XML_CATALOG_PREFER user env to select between system/public prefered
58 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
59 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
60 *> values "system" and "public". I have made the default be "system" to
61 *> match yours.
Daniel Veillard344cee72001-08-20 00:08:40 +000062 */
63#define TODO \
64 xmlGenericError(xmlGenericErrorContext, \
65 "Unimplemented block at %s:%d\n", \
66 __FILE__, __LINE__);
67
Daniel Veillardcda96922001-08-21 10:56:31 +000068#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000069#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000070#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000071#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000072#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000073#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000074#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000075#endif
76
Daniel Veillardfb382b82004-06-14 12:13:12 +000077#if defined(_WIN32) && defined(_MSC_VER)
78#undef XML_XML_DEFAULT_CATALOG
79static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
Daniel Veillard59d3ed82007-04-17 12:44:58 +000080#if defined(_WIN32_WCE)
81/* Windows CE don't have a A variant */
82#define GetModuleHandleA GetModuleHandle
83#define GetModuleFileNameA GetModuleFileName
84#else
Daniel Veillardfb382b82004-06-14 12:13:12 +000085void* __stdcall GetModuleHandleA(const char*);
86unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
87#endif
Daniel Veillard59d3ed82007-04-17 12:44:58 +000088#endif
Daniel Veillardfb382b82004-06-14 12:13:12 +000089
Daniel Veillardc8155052004-07-16 09:03:08 +000090static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
Daniel Veillard85c11fa2001-10-16 21:03:08 +000091static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000092
Daniel Veillarda7374592001-05-10 14:17:55 +000093/************************************************************************
94 * *
95 * Types, all private *
96 * *
97 ************************************************************************/
98
99typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +0000100 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +0000101 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +0000102 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000103 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +0000104 XML_CATA_NEXT_CATALOG,
William M. Brackb7b54de2004-10-06 16:38:01 +0000105 XML_CATA_GROUP,
Daniel Veillard344cee72001-08-20 00:08:40 +0000106 XML_CATA_PUBLIC,
107 XML_CATA_SYSTEM,
108 XML_CATA_REWRITE_SYSTEM,
109 XML_CATA_DELEGATE_PUBLIC,
110 XML_CATA_DELEGATE_SYSTEM,
111 XML_CATA_URI,
112 XML_CATA_REWRITE_URI,
113 XML_CATA_DELEGATE_URI,
114 SGML_CATA_SYSTEM,
115 SGML_CATA_PUBLIC,
116 SGML_CATA_ENTITY,
117 SGML_CATA_PENTITY,
118 SGML_CATA_DOCTYPE,
119 SGML_CATA_LINKTYPE,
120 SGML_CATA_NOTATION,
121 SGML_CATA_DELEGATE,
122 SGML_CATA_BASE,
123 SGML_CATA_CATALOG,
124 SGML_CATA_DOCUMENT,
125 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000126} xmlCatalogEntryType;
127
128typedef struct _xmlCatalogEntry xmlCatalogEntry;
129typedef xmlCatalogEntry *xmlCatalogEntryPtr;
130struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000131 struct _xmlCatalogEntry *next;
132 struct _xmlCatalogEntry *parent;
133 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000134 xmlCatalogEntryType type;
135 xmlChar *name;
136 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000137 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000138 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000139 int dealloc;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000140 int depth;
William M. Brackb7b54de2004-10-06 16:38:01 +0000141 struct _xmlCatalogEntry *group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000142};
143
Daniel Veillard75b96822001-10-11 18:59:45 +0000144typedef enum {
145 XML_XML_CATALOG_TYPE = 1,
146 XML_SGML_CATALOG_TYPE
147} xmlCatalogType;
148
149#define XML_MAX_SGML_CATA_DEPTH 10
150struct _xmlCatalog {
151 xmlCatalogType type; /* either XML or SGML */
152
153 /*
154 * SGML Catalogs are stored as a simple hash table of catalog entries
155 * Catalog stack to check against overflows when building the
156 * SGML catalog
157 */
158 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
159 int catalNr; /* Number of current catal streams */
160 int catalMax; /* Max number of catal streams */
161 xmlHashTablePtr sgml;
162
163 /*
164 * XML Catalogs are stored as a tree of Catalog entries
165 */
166 xmlCatalogPrefer prefer;
167 xmlCatalogEntryPtr xml;
168};
169
170/************************************************************************
171 * *
172 * Global variables *
173 * *
174 ************************************************************************/
175
Daniel Veillard81463942001-10-16 12:34:39 +0000176/*
177 * Those are preferences
178 */
179static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000180static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000181static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000182
183/*
184 * Hash table containing all the trees of XML catalogs parsed by
185 * the application.
186 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000187static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000188
189/*
190 * The default catalog in use by the application
191 */
192static xmlCatalogPtr xmlDefaultCatalog = NULL;
193
194/*
Daniel Veillard81463942001-10-16 12:34:39 +0000195 * A mutex for modifying the shared global catalog(s)
196 * xmlDefaultCatalog tree.
197 * It also protects xmlCatalogXMLFiles
198 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
199 */
200static xmlRMutexPtr xmlCatalogMutex = NULL;
201
202/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000203 * Whether the catalog support was initialized.
204 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000205static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000206
Daniel Veillard69d2c172003-10-09 11:46:07 +0000207/************************************************************************
208 * *
209 * Catalog error handlers *
210 * *
211 ************************************************************************/
212
213/**
214 * xmlCatalogErrMemory:
215 * @extra: extra informations
216 *
217 * Handle an out of memory condition
218 */
219static void
220xmlCatalogErrMemory(const char *extra)
221{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000222 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000223 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
224 extra, NULL, NULL, 0, 0,
225 "Memory allocation failed : %s\n", extra);
226}
227
228/**
229 * xmlCatalogErr:
230 * @catal: the Catalog entry
231 * @node: the context node
232 * @msg: the error message
233 * @extra: extra informations
234 *
235 * Handle a catalog error
236 */
237static void
238xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
239 const char *msg, const xmlChar *str1, const xmlChar *str2,
240 const xmlChar *str3)
241{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000242 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000243 error, XML_ERR_ERROR, NULL, 0,
244 (const char *) str1, (const char *) str2,
245 (const char *) str3, 0, 0,
246 msg, str1, str2, str3);
247}
248
Daniel Veillarda7374592001-05-10 14:17:55 +0000249
250/************************************************************************
251 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000252 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000253 * *
254 ************************************************************************/
255
Daniel Veillard75b96822001-10-11 18:59:45 +0000256/**
257 * xmlNewCatalogEntry:
258 * @type: type of entry
259 * @name: name of the entry
260 * @value: value of the entry
261 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +0000262 * @group: for members of a group, the group entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000263 *
264 * create a new Catalog entry, this type is shared both by XML and
265 * SGML catalogs, but the acceptable types values differs.
266 *
267 * Returns the xmlCatalogEntryPtr or NULL in case of error
268 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000269static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000270xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
William M. Brackb7b54de2004-10-06 16:38:01 +0000271 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
272 xmlCatalogEntryPtr group) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000273 xmlCatalogEntryPtr ret;
Daniel Veillardc8155052004-07-16 09:03:08 +0000274 xmlChar *normid = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000275
276 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
277 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000278 xmlCatalogErrMemory("allocating catalog entry");
Daniel Veillarda7374592001-05-10 14:17:55 +0000279 return(NULL);
280 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000281 ret->next = NULL;
282 ret->parent = NULL;
283 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000284 ret->type = type;
Daniel Veillardc8155052004-07-16 09:03:08 +0000285 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
286 normid = xmlCatalogNormalizePublic(name);
287 if (normid != NULL)
288 name = (*normid != 0 ? normid : NULL);
289 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000290 if (name != NULL)
291 ret->name = xmlStrdup(name);
292 else
293 ret->name = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +0000294 if (normid != NULL)
295 xmlFree(normid);
Daniel Veillard344cee72001-08-20 00:08:40 +0000296 if (value != NULL)
297 ret->value = xmlStrdup(value);
298 else
299 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000300 if (URL == NULL)
301 URL = value;
302 if (URL != NULL)
303 ret->URL = xmlStrdup(URL);
304 else
305 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000306 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000307 ret->dealloc = 0;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000308 ret->depth = 0;
William M. Brackb7b54de2004-10-06 16:38:01 +0000309 ret->group = group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000310 return(ret);
311}
312
313static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000314xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
315
Daniel Veillard75b96822001-10-11 18:59:45 +0000316/**
317 * xmlFreeCatalogEntry:
318 * @ret: a Catalog entry
319 *
320 * Free the memory allocated to a Catalog entry
321 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000322static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000323xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
324 if (ret == NULL)
325 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000326 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000327 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000328 * only by the file hash cleaner !
329 */
330 if (ret->dealloc == 1)
331 return;
332
333 if (xmlDebugCatalogs) {
334 if (ret->name != NULL)
335 xmlGenericError(xmlGenericErrorContext,
336 "Free catalog entry %s\n", ret->name);
337 else if (ret->value != NULL)
338 xmlGenericError(xmlGenericErrorContext,
339 "Free catalog entry %s\n", ret->value);
340 else
341 xmlGenericError(xmlGenericErrorContext,
342 "Free catalog entry\n");
343 }
344
Daniel Veillarda7374592001-05-10 14:17:55 +0000345 if (ret->name != NULL)
346 xmlFree(ret->name);
347 if (ret->value != NULL)
348 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000349 if (ret->URL != NULL)
350 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000351 xmlFree(ret);
352}
353
Daniel Veillard75b96822001-10-11 18:59:45 +0000354/**
355 * xmlFreeCatalogEntryList:
356 * @ret: a Catalog entry list
357 *
358 * Free the memory allocated to a full chained list of Catalog entries
359 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000360static void
361xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
362 xmlCatalogEntryPtr next;
363
364 while (ret != NULL) {
365 next = ret->next;
366 xmlFreeCatalogEntry(ret);
367 ret = next;
368 }
369}
370
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000371/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000372 * xmlFreeCatalogHashEntryList:
373 * @ret: a Catalog entry list
374 *
375 * Free the memory allocated to list of Catalog entries from the
376 * catalog file hash.
377 */
378static void
379xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
380 xmlCatalogEntryPtr children, next;
381
382 if (catal == NULL)
383 return;
384
385 children = catal->children;
386 while (children != NULL) {
387 next = children->next;
388 children->dealloc = 0;
389 children->children = NULL;
390 xmlFreeCatalogEntry(children);
391 children = next;
392 }
393 catal->dealloc = 0;
394 xmlFreeCatalogEntry(catal);
395}
396
397/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000398 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000399 * @type: type of catalog
400 * @prefer: the PUBLIC vs. SYSTEM current preference value
401 *
402 * create a new Catalog, this type is shared both by XML and
403 * SGML catalogs, but the acceptable types values differs.
404 *
405 * Returns the xmlCatalogPtr or NULL in case of error
406 */
407static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000408xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000409 xmlCatalogPtr ret;
410
411 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
412 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000413 xmlCatalogErrMemory("allocating catalog");
Daniel Veillard75b96822001-10-11 18:59:45 +0000414 return(NULL);
415 }
416 memset(ret, 0, sizeof(xmlCatalog));
417 ret->type = type;
418 ret->catalNr = 0;
419 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
420 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000421 if (ret->type == XML_SGML_CATALOG_TYPE)
422 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000423 return(ret);
424}
425
426/**
427 * xmlFreeCatalog:
Daniel Veillard06d25242004-02-25 13:01:42 +0000428 * @catal: a Catalog
Daniel Veillard75b96822001-10-11 18:59:45 +0000429 *
430 * Free the memory allocated to a Catalog
431 */
432void
433xmlFreeCatalog(xmlCatalogPtr catal) {
434 if (catal == NULL)
435 return;
436 if (catal->xml != NULL)
437 xmlFreeCatalogEntryList(catal->xml);
438 if (catal->sgml != NULL)
439 xmlHashFree(catal->sgml,
440 (xmlHashDeallocator) xmlFreeCatalogEntry);
441 xmlFree(catal);
442}
443
444/************************************************************************
445 * *
446 * Serializing Catalogs *
447 * *
448 ************************************************************************/
449
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000450#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000451/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000452 * xmlCatalogDumpEntry:
Daniel Veillard06d25242004-02-25 13:01:42 +0000453 * @entry: the catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000454 * @out: the file.
455 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000456 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000457 */
458static void
459xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
460 if ((entry == NULL) || (out == NULL))
461 return;
462 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000463 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000464 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000465 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000466 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000467 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000468 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000469 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000470 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000471 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000472 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000473 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000474 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000475 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000476 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000477 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000478 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000479 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000480 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000481 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000482 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000483 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000484 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000485 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000486 fprintf(out, "SGMLDECL "); break;
487 default:
488 return;
489 }
490 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000491 case SGML_CATA_ENTITY:
492 case SGML_CATA_PENTITY:
493 case SGML_CATA_DOCTYPE:
494 case SGML_CATA_LINKTYPE:
495 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000496 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000497 case SGML_CATA_PUBLIC:
498 case SGML_CATA_SYSTEM:
499 case SGML_CATA_SGMLDECL:
500 case SGML_CATA_DOCUMENT:
501 case SGML_CATA_CATALOG:
502 case SGML_CATA_BASE:
503 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000504 fprintf(out, "\"%s\"", entry->name); break;
505 default:
506 break;
507 }
508 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000509 case SGML_CATA_ENTITY:
510 case SGML_CATA_PENTITY:
511 case SGML_CATA_DOCTYPE:
512 case SGML_CATA_LINKTYPE:
513 case SGML_CATA_NOTATION:
514 case SGML_CATA_PUBLIC:
515 case SGML_CATA_SYSTEM:
516 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000517 fprintf(out, " \"%s\"", entry->value); break;
518 default:
519 break;
520 }
521 fprintf(out, "\n");
522}
523
William M. Brackb7b54de2004-10-06 16:38:01 +0000524/**
525 * xmlDumpXMLCatalogNode:
526 * @catal: top catalog entry
527 * @catalog: pointer to the xml tree
528 * @doc: the containing document
529 * @ns: the current namespace
530 * @cgroup: group node for group members
531 *
532 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
533 * for group entries
534 */
535static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
536 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
537 xmlNodePtr node;
538 xmlCatalogEntryPtr cur;
539 /*
540 * add all the catalog entries
541 */
542 cur = catal;
543 while (cur != NULL) {
544 if (cur->group == cgroup) {
545 switch (cur->type) {
546 case XML_CATA_REMOVED:
547 break;
548 case XML_CATA_BROKEN_CATALOG:
549 case XML_CATA_CATALOG:
550 if (cur == catal) {
551 cur = cur->children;
552 continue;
553 }
554 break;
555 case XML_CATA_NEXT_CATALOG:
556 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
557 xmlSetProp(node, BAD_CAST "catalog", cur->value);
558 xmlAddChild(catalog, node);
559 break;
560 case XML_CATA_NONE:
561 break;
562 case XML_CATA_GROUP:
563 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
564 xmlSetProp(node, BAD_CAST "id", cur->name);
William M. Brack6218b312004-10-06 17:52:32 +0000565 if (cur->value != NULL) {
566 xmlNsPtr xns;
567 xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
568 if (xns != NULL)
569 xmlSetNsProp(node, xns, BAD_CAST "base",
570 cur->value);
571 }
William M. Brackb7b54de2004-10-06 16:38:01 +0000572 switch (cur->prefer) {
573 case XML_CATA_PREFER_NONE:
574 break;
575 case XML_CATA_PREFER_PUBLIC:
576 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
577 break;
578 case XML_CATA_PREFER_SYSTEM:
579 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
580 break;
581 }
582 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
583 xmlAddChild(catalog, node);
584 break;
585 case XML_CATA_PUBLIC:
586 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
587 xmlSetProp(node, BAD_CAST "publicId", cur->name);
588 xmlSetProp(node, BAD_CAST "uri", cur->value);
589 xmlAddChild(catalog, node);
590 break;
591 case XML_CATA_SYSTEM:
592 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
593 xmlSetProp(node, BAD_CAST "systemId", cur->name);
594 xmlSetProp(node, BAD_CAST "uri", cur->value);
595 xmlAddChild(catalog, node);
596 break;
597 case XML_CATA_REWRITE_SYSTEM:
598 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
599 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
600 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
601 xmlAddChild(catalog, node);
602 break;
603 case XML_CATA_DELEGATE_PUBLIC:
604 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
605 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
606 xmlSetProp(node, BAD_CAST "catalog", cur->value);
607 xmlAddChild(catalog, node);
608 break;
609 case XML_CATA_DELEGATE_SYSTEM:
610 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
611 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
612 xmlSetProp(node, BAD_CAST "catalog", cur->value);
613 xmlAddChild(catalog, node);
614 break;
615 case XML_CATA_URI:
616 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
617 xmlSetProp(node, BAD_CAST "name", cur->name);
618 xmlSetProp(node, BAD_CAST "uri", cur->value);
619 xmlAddChild(catalog, node);
620 break;
621 case XML_CATA_REWRITE_URI:
622 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
623 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
624 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
625 xmlAddChild(catalog, node);
626 break;
627 case XML_CATA_DELEGATE_URI:
628 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
629 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
630 xmlSetProp(node, BAD_CAST "catalog", cur->value);
631 xmlAddChild(catalog, node);
632 break;
633 case SGML_CATA_SYSTEM:
634 case SGML_CATA_PUBLIC:
635 case SGML_CATA_ENTITY:
636 case SGML_CATA_PENTITY:
637 case SGML_CATA_DOCTYPE:
638 case SGML_CATA_LINKTYPE:
639 case SGML_CATA_NOTATION:
640 case SGML_CATA_DELEGATE:
641 case SGML_CATA_BASE:
642 case SGML_CATA_CATALOG:
643 case SGML_CATA_DOCUMENT:
644 case SGML_CATA_SGMLDECL:
645 break;
646 }
647 }
648 cur = cur->next;
649 }
650}
651
Daniel Veillard75b96822001-10-11 18:59:45 +0000652static int
653xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
654 int ret;
655 xmlDocPtr doc;
656 xmlNsPtr ns;
657 xmlDtdPtr dtd;
William M. Brackb7b54de2004-10-06 16:38:01 +0000658 xmlNodePtr catalog;
Daniel Veillard75b96822001-10-11 18:59:45 +0000659 xmlOutputBufferPtr buf;
Daniel Veillard75b96822001-10-11 18:59:45 +0000660
661 /*
662 * Rebuild a catalog
663 */
664 doc = xmlNewDoc(NULL);
665 if (doc == NULL)
666 return(-1);
667 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
668 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
669BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
670
671 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
672
673 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
674 if (ns == NULL) {
675 xmlFreeDoc(doc);
676 return(-1);
677 }
678 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
679 if (catalog == NULL) {
680 xmlFreeNs(ns);
681 xmlFreeDoc(doc);
682 return(-1);
683 }
684 catalog->nsDef = ns;
685 xmlAddChild((xmlNodePtr) doc, catalog);
686
William M. Brackb7b54de2004-10-06 16:38:01 +0000687 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
688
Daniel Veillard75b96822001-10-11 18:59:45 +0000689 /*
690 * reserialize it
691 */
692 buf = xmlOutputBufferCreateFile(out, NULL);
693 if (buf == NULL) {
694 xmlFreeDoc(doc);
695 return(-1);
696 }
697 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
698
699 /*
700 * Free it
701 */
702 xmlFreeDoc(doc);
703
704 return(ret);
705}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000706#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000707
708/************************************************************************
709 * *
710 * Converting SGML Catalogs to XML *
711 * *
712 ************************************************************************/
713
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000714/**
715 * xmlCatalogConvertEntry:
716 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000717 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000718 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000719 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000720 */
721static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000722xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
723 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
724 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000725 return;
726 switch (entry->type) {
727 case SGML_CATA_ENTITY:
728 entry->type = XML_CATA_PUBLIC;
729 break;
730 case SGML_CATA_PENTITY:
731 entry->type = XML_CATA_PUBLIC;
732 break;
733 case SGML_CATA_DOCTYPE:
734 entry->type = XML_CATA_PUBLIC;
735 break;
736 case SGML_CATA_LINKTYPE:
737 entry->type = XML_CATA_PUBLIC;
738 break;
739 case SGML_CATA_NOTATION:
740 entry->type = XML_CATA_PUBLIC;
741 break;
742 case SGML_CATA_PUBLIC:
743 entry->type = XML_CATA_PUBLIC;
744 break;
745 case SGML_CATA_SYSTEM:
746 entry->type = XML_CATA_SYSTEM;
747 break;
748 case SGML_CATA_DELEGATE:
749 entry->type = XML_CATA_DELEGATE_PUBLIC;
750 break;
751 case SGML_CATA_CATALOG:
752 entry->type = XML_CATA_CATALOG;
753 break;
754 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000755 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000756 (xmlHashDeallocator) xmlFreeCatalogEntry);
757 return;
758 }
759 /*
760 * Conversion successful, remove from the SGML catalog
761 * and add it to the default XML one
762 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000763 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
764 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000765 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000766 if (catal->xml->children == NULL)
767 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000768 else {
769 xmlCatalogEntryPtr prev;
770
Daniel Veillard75b96822001-10-11 18:59:45 +0000771 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000772 while (prev->next != NULL)
773 prev = prev->next;
774 prev->next = entry;
775 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000776}
777
778/**
779 * xmlConvertSGMLCatalog:
780 * @catal: the catalog
781 *
782 * Convert all the SGML catalog entries as XML ones
783 *
784 * Returns the number of entries converted if successful, -1 otherwise
785 */
786int
787xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
788
789 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
790 return(-1);
791
792 if (xmlDebugCatalogs) {
793 xmlGenericError(xmlGenericErrorContext,
794 "Converting SGML catalog to XML\n");
795 }
796 xmlHashScan(catal->sgml,
797 (xmlHashScanner) xmlCatalogConvertEntry,
798 &catal);
799 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000800}
801
Daniel Veillarda7374592001-05-10 14:17:55 +0000802/************************************************************************
803 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000804 * Helper function *
805 * *
806 ************************************************************************/
807
808/**
809 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000810 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000811 *
812 * Expand the URN into the equivalent Public Identifier
813 *
814 * Returns the new identifier or NULL, the string must be deallocated
815 * by the caller.
816 */
817static xmlChar *
818xmlCatalogUnWrapURN(const xmlChar *urn) {
819 xmlChar result[2000];
820 unsigned int i = 0;
821
822 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
823 return(NULL);
824 urn += sizeof(XML_URN_PUBID) - 1;
825
826 while (*urn != 0) {
Daniel Veillard770075b2004-02-25 10:44:30 +0000827 if (i > sizeof(result) - 4)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000828 break;
829 if (*urn == '+') {
830 result[i++] = ' ';
831 urn++;
832 } else if (*urn == ':') {
833 result[i++] = '/';
834 result[i++] = '/';
835 urn++;
836 } else if (*urn == ';') {
837 result[i++] = ':';
838 result[i++] = ':';
839 urn++;
840 } else if (*urn == '%') {
Daniel Veillard770075b2004-02-25 10:44:30 +0000841 if ((urn[1] == '2') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000842 result[i++] = '+';
Daniel Veillard770075b2004-02-25 10:44:30 +0000843 else if ((urn[1] == '3') && (urn[2] == 'A'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000844 result[i++] = ':';
Daniel Veillard770075b2004-02-25 10:44:30 +0000845 else if ((urn[1] == '2') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000846 result[i++] = '/';
Daniel Veillard770075b2004-02-25 10:44:30 +0000847 else if ((urn[1] == '3') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000848 result[i++] = ';';
Daniel Veillard770075b2004-02-25 10:44:30 +0000849 else if ((urn[1] == '2') && (urn[2] == '7'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000850 result[i++] = '\'';
Daniel Veillard770075b2004-02-25 10:44:30 +0000851 else if ((urn[1] == '3') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000852 result[i++] = '?';
Daniel Veillard770075b2004-02-25 10:44:30 +0000853 else if ((urn[1] == '2') && (urn[2] == '3'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000854 result[i++] = '#';
Daniel Veillard770075b2004-02-25 10:44:30 +0000855 else if ((urn[1] == '2') && (urn[2] == '5'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000856 result[i++] = '%';
857 else {
858 result[i++] = *urn;
859 urn++;
860 continue;
861 }
862 urn += 3;
863 } else {
864 result[i++] = *urn;
865 urn++;
866 }
867 }
868 result[i] = 0;
869
870 return(xmlStrdup(result));
871}
872
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000873/**
874 * xmlParseCatalogFile:
875 * @filename: the filename
876 *
877 * parse an XML file and build a tree. It's like xmlParseFile()
878 * except it bypass all catalog lookups.
879 *
880 * Returns the resulting document tree or NULL in case of error
881 */
882
883xmlDocPtr
884xmlParseCatalogFile(const char *filename) {
885 xmlDocPtr ret;
886 xmlParserCtxtPtr ctxt;
887 char *directory = NULL;
888 xmlParserInputPtr inputStream;
889 xmlParserInputBufferPtr buf;
890
891 ctxt = xmlNewParserCtxt();
892 if (ctxt == NULL) {
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000893#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000894 if (xmlDefaultSAXHandler.error != NULL) {
895 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
896 }
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000897#endif
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000898 return(NULL);
899 }
900
901 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
902 if (buf == NULL) {
903 xmlFreeParserCtxt(ctxt);
904 return(NULL);
905 }
906
907 inputStream = xmlNewInputStream(ctxt);
908 if (inputStream == NULL) {
909 xmlFreeParserCtxt(ctxt);
910 return(NULL);
911 }
912
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000913 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000914 inputStream->buf = buf;
915 inputStream->base = inputStream->buf->buffer->content;
916 inputStream->cur = inputStream->buf->buffer->content;
917 inputStream->end =
918 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
919
920 inputPush(ctxt, inputStream);
921 if ((ctxt->directory == NULL) && (directory == NULL))
922 directory = xmlParserGetDirectory(filename);
923 if ((ctxt->directory == NULL) && (directory != NULL))
924 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000925 ctxt->valid = 0;
926 ctxt->validate = 0;
927 ctxt->loadsubset = 0;
928 ctxt->pedantic = 0;
Daniel Veillard03a53c32004-10-26 16:06:51 +0000929 ctxt->dictNames = 1;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000930
931 xmlParseDocument(ctxt);
932
933 if (ctxt->wellFormed)
934 ret = ctxt->myDoc;
935 else {
936 ret = NULL;
937 xmlFreeDoc(ctxt->myDoc);
938 ctxt->myDoc = NULL;
939 }
940 xmlFreeParserCtxt(ctxt);
941
942 return(ret);
943}
944
Daniel Veillard75b96822001-10-11 18:59:45 +0000945/**
946 * xmlLoadFileContent:
947 * @filename: a file path
948 *
949 * Load a file content into memory.
950 *
951 * Returns a pointer to the 0 terminated string or NULL in case of error
952 */
953static xmlChar *
954xmlLoadFileContent(const char *filename)
955{
956#ifdef HAVE_STAT
957 int fd;
958#else
959 FILE *fd;
960#endif
961 int len;
962 long size;
963
964#ifdef HAVE_STAT
965 struct stat info;
966#endif
967 xmlChar *content;
968
969 if (filename == NULL)
970 return (NULL);
971
972#ifdef HAVE_STAT
973 if (stat(filename, &info) < 0)
974 return (NULL);
975#endif
976
977#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000978 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000979#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000980 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000981#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000982 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000983 return (NULL);
984 }
985#ifdef HAVE_STAT
986 size = info.st_size;
987#else
988 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
989 fclose(fd);
990 return (NULL);
991 }
992#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000993 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000994 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000995 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard75b96822001-10-11 18:59:45 +0000996 return (NULL);
997 }
998#ifdef HAVE_STAT
999 len = read(fd, content, size);
1000#else
1001 len = fread(content, 1, size, fd);
1002#endif
1003 if (len < 0) {
1004 xmlFree(content);
1005 return (NULL);
1006 }
1007#ifdef HAVE_STAT
1008 close(fd);
1009#else
1010 fclose(fd);
1011#endif
1012 content[len] = 0;
1013
1014 return(content);
1015}
1016
Daniel Veillardc8155052004-07-16 09:03:08 +00001017/**
1018 * xmlCatalogNormalizePublic:
1019 * @pubID: the public ID string
1020 *
1021 * Normalizes the Public Identifier
1022 *
1023 * Implements 6.2. Public Identifier Normalization
1024 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1025 *
1026 * Returns the new string or NULL, the string must be deallocated
1027 * by the caller.
1028 */
1029static xmlChar *
1030xmlCatalogNormalizePublic(const xmlChar *pubID)
1031{
1032 int ok = 1;
1033 int white;
1034 const xmlChar *p;
1035 xmlChar *ret;
1036 xmlChar *q;
1037
1038 if (pubID == NULL)
1039 return(NULL);
1040
1041 white = 1;
1042 for (p = pubID;*p != 0 && ok;p++) {
1043 if (!xmlIsBlank_ch(*p))
1044 white = 0;
1045 else if (*p == 0x20 && !white)
1046 white = 1;
1047 else
1048 ok = 0;
1049 }
1050 if (ok && !white) /* is normalized */
1051 return(NULL);
1052
1053 ret = xmlStrdup(pubID);
1054 q = ret;
1055 white = 0;
1056 for (p = pubID;*p != 0;p++) {
1057 if (xmlIsBlank_ch(*p)) {
1058 if (q != ret)
1059 white = 1;
1060 } else {
1061 if (white) {
1062 *(q++) = 0x20;
1063 white = 0;
1064 }
1065 *(q++) = *p;
1066 }
1067 }
1068 *q = 0;
1069 return(ret);
1070}
1071
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001072/************************************************************************
1073 * *
Daniel Veillard344cee72001-08-20 00:08:40 +00001074 * The XML Catalog parser *
1075 * *
1076 ************************************************************************/
1077
1078static xmlCatalogEntryPtr
1079xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001080static void
1081xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001082 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
Daniel Veillardcda96922001-08-21 10:56:31 +00001083static xmlChar *
1084xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1085 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001086static xmlChar *
1087xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1088
Daniel Veillard344cee72001-08-20 00:08:40 +00001089
Daniel Veillard75b96822001-10-11 18:59:45 +00001090/**
1091 * xmlGetXMLCatalogEntryType:
1092 * @name: the name
1093 *
1094 * lookup the internal type associated to an XML catalog entry name
1095 *
Daniel Veillard06d25242004-02-25 13:01:42 +00001096 * Returns the type associated with that name
Daniel Veillard75b96822001-10-11 18:59:45 +00001097 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001098static xmlCatalogEntryType
1099xmlGetXMLCatalogEntryType(const xmlChar *name) {
1100 xmlCatalogEntryType type = XML_CATA_NONE;
1101 if (xmlStrEqual(name, (const xmlChar *) "system"))
1102 type = XML_CATA_SYSTEM;
1103 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1104 type = XML_CATA_PUBLIC;
1105 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1106 type = XML_CATA_REWRITE_SYSTEM;
1107 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1108 type = XML_CATA_DELEGATE_PUBLIC;
1109 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1110 type = XML_CATA_DELEGATE_SYSTEM;
1111 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1112 type = XML_CATA_URI;
1113 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1114 type = XML_CATA_REWRITE_URI;
1115 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1116 type = XML_CATA_DELEGATE_URI;
1117 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1118 type = XML_CATA_NEXT_CATALOG;
1119 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1120 type = XML_CATA_CATALOG;
1121 return(type);
1122}
1123
Daniel Veillard75b96822001-10-11 18:59:45 +00001124/**
1125 * xmlParseXMLCatalogOneNode:
1126 * @cur: the XML node
1127 * @type: the type of Catalog entry
1128 * @name: the name of the node
1129 * @attrName: the attribute holding the value
1130 * @uriAttrName: the attribute holding the URI-Reference
1131 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +00001132 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001133 *
1134 * Finishes the examination of an XML tree node of a catalog and build
1135 * a Catalog entry from it.
1136 *
1137 * Returns the new Catalog entry node or NULL in case of error.
1138 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001139static xmlCatalogEntryPtr
1140xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1141 const xmlChar *name, const xmlChar *attrName,
William M. Brackb7b54de2004-10-06 16:38:01 +00001142 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1143 xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001144 int ok = 1;
1145 xmlChar *uriValue;
1146 xmlChar *nameValue = NULL;
1147 xmlChar *base = NULL;
1148 xmlChar *URL = NULL;
1149 xmlCatalogEntryPtr ret = NULL;
1150
1151 if (attrName != NULL) {
1152 nameValue = xmlGetProp(cur, attrName);
1153 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001154 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1155 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001156 ok = 0;
1157 }
1158 }
1159 uriValue = xmlGetProp(cur, uriAttrName);
1160 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001161 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1162 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001163 ok = 0;
1164 }
1165 if (!ok) {
1166 if (nameValue != NULL)
1167 xmlFree(nameValue);
1168 if (uriValue != NULL)
1169 xmlFree(uriValue);
1170 return(NULL);
1171 }
1172
1173 base = xmlNodeGetBase(cur->doc, cur);
1174 URL = xmlBuildURI(uriValue, base);
1175 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001176 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001177 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001178 xmlGenericError(xmlGenericErrorContext,
1179 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001180 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001181 xmlGenericError(xmlGenericErrorContext,
1182 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001183 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001184 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001185 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001186 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001187 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1188 }
1189 if (nameValue != NULL)
1190 xmlFree(nameValue);
1191 if (uriValue != NULL)
1192 xmlFree(uriValue);
1193 if (base != NULL)
1194 xmlFree(base);
1195 if (URL != NULL)
1196 xmlFree(URL);
1197 return(ret);
1198}
1199
Daniel Veillard75b96822001-10-11 18:59:45 +00001200/**
1201 * xmlParseXMLCatalogNode:
1202 * @cur: the XML node
1203 * @prefer: the PUBLIC vs. SYSTEM current preference value
1204 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001205 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001206 *
1207 * Examines an XML tree node of a catalog and build
1208 * a Catalog entry from it adding it to its parent. The examination can
1209 * be recursive.
1210 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001211static void
1212xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001213 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
Daniel Veillard344cee72001-08-20 00:08:40 +00001214{
Daniel Veillard344cee72001-08-20 00:08:40 +00001215 xmlChar *base = NULL;
1216 xmlCatalogEntryPtr entry = NULL;
1217
1218 if (cur == NULL)
1219 return;
1220 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1221 xmlChar *prop;
William M. Brackb7b54de2004-10-06 16:38:01 +00001222 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
Daniel Veillard344cee72001-08-20 00:08:40 +00001223
1224 prop = xmlGetProp(cur, BAD_CAST "prefer");
1225 if (prop != NULL) {
1226 if (xmlStrEqual(prop, BAD_CAST "system")) {
1227 prefer = XML_CATA_PREFER_SYSTEM;
1228 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1229 prefer = XML_CATA_PREFER_PUBLIC;
1230 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001231 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1232 "Invalid value for prefer: '%s'\n",
1233 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001234 }
1235 xmlFree(prop);
William M. Brackb7b54de2004-10-06 16:38:01 +00001236 pref = prefer;
Daniel Veillard344cee72001-08-20 00:08:40 +00001237 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001238 prop = xmlGetProp(cur, BAD_CAST "id");
1239 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1240 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
William M. Brack181a1ca2004-10-06 18:00:29 +00001241 xmlFree(prop);
Daniel Veillard344cee72001-08-20 00:08:40 +00001242 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1243 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
William M. Brackb7b54de2004-10-06 16:38:01 +00001244 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001245 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1246 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
William M. Brackb7b54de2004-10-06 16:38:01 +00001247 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001248 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1249 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1250 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001251 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001252 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1253 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1254 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001255 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001256 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1257 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1258 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
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 "uri")) {
1261 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1262 BAD_CAST "uri", BAD_CAST "name",
William M. Brackb7b54de2004-10-06 16:38:01 +00001263 BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001264 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1265 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1266 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001267 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001268 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1269 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1270 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001271 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001272 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1273 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1274 BAD_CAST "nextCatalog", NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001275 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001276 }
William M. Brackb031cef2004-11-05 16:34:22 +00001277 if (entry != NULL) {
1278 if (parent != NULL) {
1279 entry->parent = parent;
1280 if (parent->children == NULL)
1281 parent->children = entry;
1282 else {
1283 xmlCatalogEntryPtr prev;
Daniel Veillard344cee72001-08-20 00:08:40 +00001284
William M. Brackb031cef2004-11-05 16:34:22 +00001285 prev = parent->children;
1286 while (prev->next != NULL)
1287 prev = prev->next;
1288 prev->next = entry;
1289 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001290 }
William M. Brackb031cef2004-11-05 16:34:22 +00001291 if (entry->type == XML_CATA_GROUP) {
1292 /*
1293 * Recurse to propagate prefer to the subtree
1294 * (xml:base handling is automated)
1295 */
1296 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1297 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001298 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001299 if (base != NULL)
1300 xmlFree(base);
Daniel Veillard344cee72001-08-20 00:08:40 +00001301}
1302
Daniel Veillard75b96822001-10-11 18:59:45 +00001303/**
1304 * xmlParseXMLCatalogNodeList:
1305 * @cur: the XML node list of siblings
1306 * @prefer: the PUBLIC vs. SYSTEM current preference value
1307 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001308 * @cgroup: the group which includes this list
Daniel Veillard75b96822001-10-11 18:59:45 +00001309 *
1310 * Examines a list of XML sibling nodes of a catalog and build
1311 * a list of Catalog entry from it adding it to the parent.
1312 * The examination will recurse to examine node subtrees.
1313 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001314static void
1315xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001316 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001317 while (cur != NULL) {
1318 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1319 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
William M. Brackb7b54de2004-10-06 16:38:01 +00001320 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001321 }
1322 cur = cur->next;
1323 }
1324 /* TODO: sort the list according to REWRITE lengths and prefer value */
1325}
1326
Daniel Veillard75b96822001-10-11 18:59:45 +00001327/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001328 * xmlParseXMLCatalogFile:
1329 * @prefer: the PUBLIC vs. SYSTEM current preference value
1330 * @filename: the filename for the catalog
1331 *
1332 * Parses the catalog file to extract the XML tree and then analyze the
1333 * tree to build a list of Catalog entries corresponding to this catalog
1334 *
1335 * Returns the resulting Catalog entries list
1336 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001337static xmlCatalogEntryPtr
1338xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1339 xmlDocPtr doc;
1340 xmlNodePtr cur;
1341 xmlChar *prop;
1342 xmlCatalogEntryPtr parent = NULL;
1343
1344 if (filename == NULL)
1345 return(NULL);
1346
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001347 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001348 if (doc == NULL) {
1349 if (xmlDebugCatalogs)
1350 xmlGenericError(xmlGenericErrorContext,
1351 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001352 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001353 }
1354
1355 if (xmlDebugCatalogs)
1356 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001357 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001358
1359 cur = xmlDocGetRootElement(doc);
1360 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1361 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1362 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1363
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001364 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001365 (const xmlChar *)filename, NULL, prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001366 if (parent == NULL) {
1367 xmlFreeDoc(doc);
1368 return(NULL);
1369 }
1370
1371 prop = xmlGetProp(cur, BAD_CAST "prefer");
1372 if (prop != NULL) {
1373 if (xmlStrEqual(prop, BAD_CAST "system")) {
1374 prefer = XML_CATA_PREFER_SYSTEM;
1375 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1376 prefer = XML_CATA_PREFER_PUBLIC;
1377 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001378 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1379 "Invalid value for prefer: '%s'\n",
1380 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001381 }
1382 xmlFree(prop);
1383 }
1384 cur = cur->children;
William M. Brackb7b54de2004-10-06 16:38:01 +00001385 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001386 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001387 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1388 "File %s is not an XML Catalog\n",
1389 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001390 xmlFreeDoc(doc);
1391 return(NULL);
1392 }
1393 xmlFreeDoc(doc);
1394 return(parent);
1395}
1396
Daniel Veillardcda96922001-08-21 10:56:31 +00001397/**
1398 * xmlFetchXMLCatalogFile:
1399 * @catal: an existing but incomplete catalog entry
1400 *
1401 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001402 *
1403 * Returns 0 in case of success, -1 otherwise
1404 */
1405static int
1406xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001407 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001408
1409 if (catal == NULL)
1410 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001411 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001412 return(-1);
1413 if (catal->children != NULL)
1414 return(-1);
1415
Daniel Veillard81463942001-10-16 12:34:39 +00001416 /*
1417 * lock the whole catalog for modification
1418 */
1419 xmlRMutexLock(xmlCatalogMutex);
1420 if (catal->children != NULL) {
1421 /* Okay someone else did it in the meantime */
1422 xmlRMutexUnlock(xmlCatalogMutex);
1423 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001424 }
1425
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001426 if (xmlCatalogXMLFiles != NULL) {
1427 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001428 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001429 if (doc != NULL) {
1430 if (xmlDebugCatalogs)
1431 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001432 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001433
1434 if (catal->type == XML_CATA_CATALOG)
1435 catal->children = doc->children;
1436 else
1437 catal->children = doc;
1438 catal->dealloc = 0;
1439 xmlRMutexUnlock(xmlCatalogMutex);
1440 return(0);
1441 }
1442 if (xmlDebugCatalogs)
1443 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001444 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001445 }
1446
Daniel Veillardcda96922001-08-21 10:56:31 +00001447 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001448 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001449 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001450 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001451 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001452 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001453 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001454 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001455 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001456 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001457 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001458
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001459 if (catal->type == XML_CATA_CATALOG)
1460 catal->children = doc->children;
1461 else
1462 catal->children = doc;
1463
1464 doc->dealloc = 1;
1465
Daniel Veillard81463942001-10-16 12:34:39 +00001466 if (xmlCatalogXMLFiles == NULL)
1467 xmlCatalogXMLFiles = xmlHashCreate(10);
1468 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001469 if (xmlDebugCatalogs)
1470 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001471 "%s added to file hash\n", catal->URL);
1472 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001473 }
Daniel Veillard81463942001-10-16 12:34:39 +00001474 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001475 return(0);
1476}
1477
Daniel Veillard75b96822001-10-11 18:59:45 +00001478/************************************************************************
1479 * *
1480 * XML Catalog handling *
1481 * *
1482 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001483
1484/**
1485 * xmlAddXMLCatalog:
1486 * @catal: top of an XML catalog
1487 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001488 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001489 * @replace: the replacement value for the match
1490 *
1491 * Add an entry in the XML catalog, it may overwrite existing but
1492 * different entries.
1493 *
1494 * Returns 0 if successful, -1 otherwise
1495 */
1496static int
1497xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1498 const xmlChar *orig, const xmlChar *replace) {
1499 xmlCatalogEntryPtr cur;
1500 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001501 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001502
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001503 if ((catal == NULL) ||
1504 ((catal->type != XML_CATA_CATALOG) &&
1505 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001506 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001507 if (catal->children == NULL) {
1508 xmlFetchXMLCatalogFile(catal);
1509 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001510 if (catal->children == NULL)
1511 doregister = 1;
1512
Daniel Veillard344cee72001-08-20 00:08:40 +00001513 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001514 if (typ == XML_CATA_NONE) {
1515 if (xmlDebugCatalogs)
1516 xmlGenericError(xmlGenericErrorContext,
1517 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001518 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001519 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001520
1521 cur = catal->children;
1522 /*
1523 * Might be a simple "update in place"
1524 */
1525 if (cur != NULL) {
1526 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001527 if ((orig != NULL) && (cur->type == typ) &&
1528 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001529 if (xmlDebugCatalogs)
1530 xmlGenericError(xmlGenericErrorContext,
1531 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001532 if (cur->value != NULL)
1533 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001534 if (cur->URL != NULL)
1535 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001536 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001537 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001538 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001539 }
1540 if (cur->next == NULL)
1541 break;
1542 cur = cur->next;
1543 }
1544 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001545 if (xmlDebugCatalogs)
1546 xmlGenericError(xmlGenericErrorContext,
1547 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001548 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001549 catal->children = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001550 NULL, catal->prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001551 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001552 cur->next = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001553 NULL, catal->prefer, NULL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001554 if (doregister) {
Daniel Veillard27bec142006-02-24 20:22:27 +00001555 catal->type = XML_CATA_CATALOG;
Daniel Veillardc853b322001-11-06 15:24:37 +00001556 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1557 if (cur != NULL)
1558 cur->children = catal->children;
1559 }
1560
Daniel Veillardcda96922001-08-21 10:56:31 +00001561 return(0);
1562}
1563
1564/**
1565 * xmlDelXMLCatalog:
1566 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001567 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001568 *
1569 * Remove entries in the XML catalog where the value or the URI
1570 * is equal to @value
1571 *
1572 * Returns the number of entries removed if successful, -1 otherwise
1573 */
1574static int
1575xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001576 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001577 int ret = 0;
1578
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001579 if ((catal == NULL) ||
1580 ((catal->type != XML_CATA_CATALOG) &&
1581 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001582 return(-1);
1583 if (value == NULL)
1584 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001585 if (catal->children == NULL) {
1586 xmlFetchXMLCatalogFile(catal);
1587 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001588
1589 /*
1590 * Scan the children
1591 */
1592 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001593 while (cur != NULL) {
1594 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1595 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001596 if (xmlDebugCatalogs) {
1597 if (cur->name != NULL)
1598 xmlGenericError(xmlGenericErrorContext,
1599 "Removing element %s from catalog\n", cur->name);
1600 else
1601 xmlGenericError(xmlGenericErrorContext,
1602 "Removing element %s from catalog\n", cur->value);
1603 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001604 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001605 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001606 cur = cur->next;
1607 }
1608 return(ret);
1609}
1610
1611/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001612 * xmlCatalogXMLResolve:
1613 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001614 * @pubID: the public ID string
1615 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001616 *
1617 * Do a complete resolution lookup of an External Identifier for a
1618 * list of catalog entries.
1619 *
1620 * Implements (or tries to) 7.1. External Identifier Resolution
1621 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1622 *
1623 * Returns the URI of the resource or NULL if not found
1624 */
1625static xmlChar *
1626xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1627 const xmlChar *sysID) {
1628 xmlChar *ret = NULL;
1629 xmlCatalogEntryPtr cur;
1630 int haveDelegate = 0;
1631 int haveNext = 0;
1632
1633 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001634 * protection against loops
1635 */
1636 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001637 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1638 "Detected recursion in catalog %s\n",
1639 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001640 return(NULL);
1641 }
1642 catal->depth++;
1643
1644 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001645 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1646 */
1647 if (sysID != NULL) {
1648 xmlCatalogEntryPtr rewrite = NULL;
1649 int lenrewrite = 0, len;
1650 cur = catal;
1651 haveDelegate = 0;
1652 while (cur != NULL) {
1653 switch (cur->type) {
1654 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001655 if (xmlStrEqual(sysID, cur->name)) {
1656 if (xmlDebugCatalogs)
1657 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard890b5492006-02-23 08:14:00 +00001658 "Found system match %s, using %s\n",
1659 cur->name, cur->URL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001660 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001661 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001662 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001663 break;
1664 case XML_CATA_REWRITE_SYSTEM:
1665 len = xmlStrlen(cur->name);
1666 if ((len > lenrewrite) &&
1667 (!xmlStrncmp(sysID, cur->name, len))) {
1668 lenrewrite = len;
1669 rewrite = cur;
1670 }
1671 break;
1672 case XML_CATA_DELEGATE_SYSTEM:
1673 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1674 haveDelegate++;
1675 break;
1676 case XML_CATA_NEXT_CATALOG:
1677 haveNext++;
1678 break;
1679 default:
1680 break;
1681 }
1682 cur = cur->next;
1683 }
1684 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001685 if (xmlDebugCatalogs)
1686 xmlGenericError(xmlGenericErrorContext,
1687 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001688 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001689 if (ret != NULL)
1690 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001691 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001692 return(ret);
1693 }
1694 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001695 const xmlChar *delegates[MAX_DELEGATE];
1696 int nbList = 0, i;
1697
Daniel Veillardcda96922001-08-21 10:56:31 +00001698 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001699 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001700 * matches when the list was produced.
1701 */
1702 cur = catal;
1703 while (cur != NULL) {
1704 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1705 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001706 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001707 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001708 break;
1709 if (i < nbList) {
1710 cur = cur->next;
1711 continue;
1712 }
1713 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001714 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001715
Daniel Veillardcda96922001-08-21 10:56:31 +00001716 if (cur->children == NULL) {
1717 xmlFetchXMLCatalogFile(cur);
1718 }
1719 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001720 if (xmlDebugCatalogs)
1721 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001722 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001723 ret = xmlCatalogListXMLResolve(
1724 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001725 if (ret != NULL) {
1726 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001727 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001728 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001729 }
1730 }
1731 cur = cur->next;
1732 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001733 /*
1734 * Apply the cut algorithm explained in 4/
1735 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001736 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001737 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001738 }
1739 }
1740 /*
1741 * Then tries 5/ 6/ if a public ID is provided
1742 */
1743 if (pubID != NULL) {
1744 cur = catal;
1745 haveDelegate = 0;
1746 while (cur != NULL) {
1747 switch (cur->type) {
1748 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001749 if (xmlStrEqual(pubID, cur->name)) {
1750 if (xmlDebugCatalogs)
1751 xmlGenericError(xmlGenericErrorContext,
1752 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001753 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001754 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001755 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001756 break;
1757 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001758 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1759 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001760 haveDelegate++;
1761 break;
1762 case XML_CATA_NEXT_CATALOG:
1763 if (sysID == NULL)
1764 haveNext++;
1765 break;
1766 default:
1767 break;
1768 }
1769 cur = cur->next;
1770 }
1771 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001772 const xmlChar *delegates[MAX_DELEGATE];
1773 int nbList = 0, i;
1774
Daniel Veillardcda96922001-08-21 10:56:31 +00001775 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001776 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001777 * matches when the list was produced.
1778 */
1779 cur = catal;
1780 while (cur != NULL) {
1781 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001782 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1783 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001784
1785 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001786 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001787 break;
1788 if (i < nbList) {
1789 cur = cur->next;
1790 continue;
1791 }
1792 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001793 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001794
Daniel Veillardcda96922001-08-21 10:56:31 +00001795 if (cur->children == NULL) {
1796 xmlFetchXMLCatalogFile(cur);
1797 }
1798 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001799 if (xmlDebugCatalogs)
1800 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001801 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001802 ret = xmlCatalogListXMLResolve(
1803 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001804 if (ret != NULL) {
1805 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001806 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001807 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001808 }
1809 }
1810 cur = cur->next;
1811 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001812 /*
1813 * Apply the cut algorithm explained in 4/
1814 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001815 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001816 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001817 }
1818 }
1819 if (haveNext) {
1820 cur = catal;
1821 while (cur != NULL) {
1822 if (cur->type == XML_CATA_NEXT_CATALOG) {
1823 if (cur->children == NULL) {
1824 xmlFetchXMLCatalogFile(cur);
1825 }
1826 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001827 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001828 if (ret != NULL) {
1829 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001830 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001831 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001832 }
1833 }
1834 cur = cur->next;
1835 }
1836 }
1837
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001838 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001839 return(NULL);
1840}
1841
1842/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001843 * xmlCatalogXMLResolveURI:
1844 * @catal: a catalog list
1845 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001846 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001847 *
1848 * Do a complete resolution lookup of an External Identifier for a
1849 * list of catalog entries.
1850 *
1851 * Implements (or tries to) 7.2.2. URI Resolution
1852 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1853 *
1854 * Returns the URI of the resource or NULL if not found
1855 */
1856static xmlChar *
1857xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1858 xmlChar *ret = NULL;
1859 xmlCatalogEntryPtr cur;
1860 int haveDelegate = 0;
1861 int haveNext = 0;
1862 xmlCatalogEntryPtr rewrite = NULL;
1863 int lenrewrite = 0, len;
1864
1865 if (catal == NULL)
1866 return(NULL);
1867
1868 if (URI == NULL)
1869 return(NULL);
1870
1871 /*
1872 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1873 */
1874 cur = catal;
1875 haveDelegate = 0;
1876 while (cur != NULL) {
1877 switch (cur->type) {
1878 case XML_CATA_URI:
1879 if (xmlStrEqual(URI, cur->name)) {
1880 if (xmlDebugCatalogs)
1881 xmlGenericError(xmlGenericErrorContext,
1882 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001883 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001884 }
1885 break;
1886 case XML_CATA_REWRITE_URI:
1887 len = xmlStrlen(cur->name);
1888 if ((len > lenrewrite) &&
1889 (!xmlStrncmp(URI, cur->name, len))) {
1890 lenrewrite = len;
1891 rewrite = cur;
1892 }
1893 break;
1894 case XML_CATA_DELEGATE_URI:
1895 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1896 haveDelegate++;
1897 break;
1898 case XML_CATA_NEXT_CATALOG:
1899 haveNext++;
1900 break;
1901 default:
1902 break;
1903 }
1904 cur = cur->next;
1905 }
1906 if (rewrite != NULL) {
1907 if (xmlDebugCatalogs)
1908 xmlGenericError(xmlGenericErrorContext,
1909 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001910 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001911 if (ret != NULL)
1912 ret = xmlStrcat(ret, &URI[lenrewrite]);
1913 return(ret);
1914 }
1915 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001916 const xmlChar *delegates[MAX_DELEGATE];
1917 int nbList = 0, i;
1918
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001919 /*
1920 * Assume the entries have been sorted by decreasing substring
1921 * matches when the list was produced.
1922 */
1923 cur = catal;
1924 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001925 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1926 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001927 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001928 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001929 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001930 break;
1931 if (i < nbList) {
1932 cur = cur->next;
1933 continue;
1934 }
1935 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001936 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001937
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001938 if (cur->children == NULL) {
1939 xmlFetchXMLCatalogFile(cur);
1940 }
1941 if (cur->children != NULL) {
1942 if (xmlDebugCatalogs)
1943 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001944 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001945 ret = xmlCatalogListXMLResolveURI(
1946 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001947 if (ret != NULL)
1948 return(ret);
1949 }
1950 }
1951 cur = cur->next;
1952 }
1953 /*
1954 * Apply the cut algorithm explained in 4/
1955 */
1956 return(XML_CATAL_BREAK);
1957 }
1958 if (haveNext) {
1959 cur = catal;
1960 while (cur != NULL) {
1961 if (cur->type == XML_CATA_NEXT_CATALOG) {
1962 if (cur->children == NULL) {
1963 xmlFetchXMLCatalogFile(cur);
1964 }
1965 if (cur->children != NULL) {
1966 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1967 if (ret != NULL)
1968 return(ret);
1969 }
1970 }
1971 cur = cur->next;
1972 }
1973 }
1974
1975 return(NULL);
1976}
1977
1978/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001979 * xmlCatalogListXMLResolve:
1980 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001981 * @pubID: the public ID string
1982 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001983 *
1984 * Do a complete resolution lookup of an External Identifier for a
1985 * list of catalogs
1986 *
1987 * Implements (or tries to) 7.1. External Identifier Resolution
1988 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1989 *
1990 * Returns the URI of the resource or NULL if not found
1991 */
1992static xmlChar *
1993xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1994 const xmlChar *sysID) {
1995 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001996 xmlChar *urnID = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +00001997 xmlChar *normid;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001998
1999 if (catal == NULL)
2000 return(NULL);
2001 if ((pubID == NULL) && (sysID == NULL))
2002 return(NULL);
2003
Daniel Veillardc8155052004-07-16 09:03:08 +00002004 normid = xmlCatalogNormalizePublic(pubID);
2005 if (normid != NULL)
2006 pubID = (*normid != 0 ? normid : NULL);
2007
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002008 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2009 urnID = xmlCatalogUnWrapURN(pubID);
2010 if (xmlDebugCatalogs) {
2011 if (urnID == NULL)
2012 xmlGenericError(xmlGenericErrorContext,
2013 "Public URN ID %s expanded to NULL\n", pubID);
2014 else
2015 xmlGenericError(xmlGenericErrorContext,
2016 "Public URN ID expanded to %s\n", urnID);
2017 }
2018 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2019 if (urnID != NULL)
2020 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002021 if (normid != NULL)
2022 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002023 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002024 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002025 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2026 urnID = xmlCatalogUnWrapURN(sysID);
2027 if (xmlDebugCatalogs) {
2028 if (urnID == NULL)
2029 xmlGenericError(xmlGenericErrorContext,
2030 "System URN ID %s expanded to NULL\n", sysID);
2031 else
2032 xmlGenericError(xmlGenericErrorContext,
2033 "System URN ID expanded to %s\n", urnID);
2034 }
2035 if (pubID == NULL)
2036 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2037 else if (xmlStrEqual(pubID, urnID))
2038 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2039 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00002040 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002041 }
2042 if (urnID != NULL)
2043 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002044 if (normid != NULL)
2045 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002046 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002047 }
2048 while (catal != NULL) {
2049 if (catal->type == XML_CATA_CATALOG) {
2050 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002051 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00002052 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002053 if (catal->children != NULL) {
2054 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002055 if (ret != NULL) {
2056 if (normid != NULL)
2057 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002058 return(ret);
Daniel Veillardc8155052004-07-16 09:03:08 +00002059 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002060 }
Daniel Veillardcda96922001-08-21 10:56:31 +00002061 }
2062 catal = catal->next;
2063 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002064 if (normid != NULL)
2065 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002066 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00002067}
2068
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002069/**
2070 * xmlCatalogListXMLResolveURI:
2071 * @catal: a catalog list
2072 * @URI: the URI
2073 *
2074 * Do a complete resolution lookup of an URI for a list of catalogs
2075 *
2076 * Implements (or tries to) 7.2. URI Resolution
2077 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2078 *
2079 * Returns the URI of the resource or NULL if not found
2080 */
2081static xmlChar *
2082xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2083 xmlChar *ret = NULL;
2084 xmlChar *urnID = NULL;
2085
2086 if (catal == NULL)
2087 return(NULL);
2088 if (URI == NULL)
2089 return(NULL);
2090
2091 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2092 urnID = xmlCatalogUnWrapURN(URI);
2093 if (xmlDebugCatalogs) {
2094 if (urnID == NULL)
2095 xmlGenericError(xmlGenericErrorContext,
2096 "URN ID %s expanded to NULL\n", URI);
2097 else
2098 xmlGenericError(xmlGenericErrorContext,
2099 "URN ID expanded to %s\n", urnID);
2100 }
2101 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2102 if (urnID != NULL)
2103 xmlFree(urnID);
2104 return(ret);
2105 }
2106 while (catal != NULL) {
2107 if (catal->type == XML_CATA_CATALOG) {
2108 if (catal->children == NULL) {
2109 xmlFetchXMLCatalogFile(catal);
2110 }
2111 if (catal->children != NULL) {
2112 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2113 if (ret != NULL)
2114 return(ret);
2115 }
2116 }
2117 catal = catal->next;
2118 }
2119 return(ret);
2120}
2121
Daniel Veillard344cee72001-08-20 00:08:40 +00002122/************************************************************************
2123 * *
2124 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00002125 * *
2126 ************************************************************************/
2127
2128
2129#define RAW *cur
2130#define NEXT cur++;
2131#define SKIP(x) cur += x;
2132
William M. Brack272693c2003-11-14 16:20:34 +00002133#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002134
Daniel Veillard75b96822001-10-11 18:59:45 +00002135/**
2136 * xmlParseSGMLCatalogComment:
2137 * @cur: the current character
2138 *
2139 * Skip a comment in an SGML catalog
2140 *
2141 * Returns new current character
2142 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002143static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002144xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002145 if ((cur[0] != '-') || (cur[1] != '-'))
2146 return(cur);
2147 SKIP(2);
2148 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2149 NEXT;
2150 if (cur[0] == 0) {
2151 return(NULL);
2152 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002153 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002154}
2155
Daniel Veillard75b96822001-10-11 18:59:45 +00002156/**
2157 * xmlParseSGMLCatalogPubid:
2158 * @cur: the current character
2159 * @id: the return location
2160 *
2161 * Parse an SGML catalog ID
2162 *
2163 * Returns new current character and store the value in @id
2164 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002165static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002166xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002167 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002168 int len = 0;
2169 int size = 50;
2170 xmlChar stop;
2171 int count = 0;
2172
2173 *id = NULL;
2174
2175 if (RAW == '"') {
2176 NEXT;
2177 stop = '"';
2178 } else if (RAW == '\'') {
2179 NEXT;
2180 stop = '\'';
2181 } else {
2182 stop = ' ';
2183 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002184 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002185 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002186 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002187 return(NULL);
2188 }
William M. Brack76e95df2003-10-18 16:20:14 +00002189 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002190 if ((*cur == stop) && (stop != ' '))
2191 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002192 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002193 break;
2194 if (len + 1 >= size) {
2195 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002196 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2197 if (tmp == NULL) {
2198 xmlCatalogErrMemory("allocating public ID");
2199 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002200 return(NULL);
2201 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002202 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002203 }
2204 buf[len++] = *cur;
2205 count++;
2206 NEXT;
2207 }
2208 buf[len] = 0;
2209 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002210 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002211 xmlFree(buf);
2212 return(NULL);
2213 }
2214 } else {
2215 if (*cur != stop) {
2216 xmlFree(buf);
2217 return(NULL);
2218 }
2219 NEXT;
2220 }
2221 *id = buf;
2222 return(cur);
2223}
2224
Daniel Veillard75b96822001-10-11 18:59:45 +00002225/**
2226 * xmlParseSGMLCatalogName:
2227 * @cur: the current character
2228 * @name: the return location
2229 *
2230 * Parse an SGML catalog name
2231 *
2232 * Returns new current character and store the value in @name
2233 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002234static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002235xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002236 xmlChar buf[XML_MAX_NAMELEN + 5];
2237 int len = 0;
2238 int c;
2239
2240 *name = NULL;
2241
2242 /*
2243 * Handler for more complex cases
2244 */
2245 c = *cur;
2246 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2247 return(NULL);
2248 }
2249
2250 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2251 (c == '.') || (c == '-') ||
2252 (c == '_') || (c == ':'))) {
2253 buf[len++] = c;
2254 cur++;
2255 c = *cur;
2256 if (len >= XML_MAX_NAMELEN)
2257 return(NULL);
2258 }
2259 *name = xmlStrndup(buf, len);
2260 return(cur);
2261}
2262
Daniel Veillard75b96822001-10-11 18:59:45 +00002263/**
2264 * xmlGetSGMLCatalogEntryType:
2265 * @name: the entry name
2266 *
2267 * Get the Catalog entry type for a given SGML Catalog name
2268 *
2269 * Returns Catalog entry type
2270 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002271static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002272xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002273 xmlCatalogEntryType type = XML_CATA_NONE;
2274 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2275 type = SGML_CATA_SYSTEM;
2276 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2277 type = SGML_CATA_PUBLIC;
2278 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2279 type = SGML_CATA_DELEGATE;
2280 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2281 type = SGML_CATA_ENTITY;
2282 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2283 type = SGML_CATA_DOCTYPE;
2284 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2285 type = SGML_CATA_LINKTYPE;
2286 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2287 type = SGML_CATA_NOTATION;
2288 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2289 type = SGML_CATA_SGMLDECL;
2290 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2291 type = SGML_CATA_DOCUMENT;
2292 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2293 type = SGML_CATA_CATALOG;
2294 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2295 type = SGML_CATA_BASE;
Daniel Veillard344cee72001-08-20 00:08:40 +00002296 return(type);
2297}
2298
Daniel Veillard75b96822001-10-11 18:59:45 +00002299/**
2300 * xmlParseSGMLCatalog:
2301 * @catal: the SGML Catalog
2302 * @value: the content of the SGML Catalog serialization
2303 * @file: the filepath for the catalog
2304 * @super: should this be handled as a Super Catalog in which case
2305 * parsing is not recursive
2306 *
2307 * Parse an SGML catalog content and fill up the @catal hash table with
2308 * the new entries found.
2309 *
2310 * Returns 0 in case of success, -1 in case of error.
2311 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002312static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002313xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2314 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002315 const xmlChar *cur = value;
2316 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002317 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002318
2319 if ((cur == NULL) || (file == NULL))
2320 return(-1);
2321 base = xmlStrdup((const xmlChar *) file);
2322
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002323 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002324 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002325 if (cur[0] == 0)
2326 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002327 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002328 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002329 if (cur == NULL) {
2330 /* error */
2331 break;
2332 }
2333 } else {
2334 xmlChar *sysid = NULL;
2335 xmlChar *name = NULL;
2336 xmlCatalogEntryType type = XML_CATA_NONE;
2337
Daniel Veillardcda96922001-08-21 10:56:31 +00002338 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002339 if (name == NULL) {
2340 /* error */
2341 break;
2342 }
William M. Brack76e95df2003-10-18 16:20:14 +00002343 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002344 /* error */
2345 break;
2346 }
2347 SKIP_BLANKS;
2348 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002349 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002350 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002351 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002352 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002353 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002354 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002355 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002356 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002357 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002358 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002359 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002360 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002361 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002362 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002363 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002364 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002365 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002366 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002367 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002368 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002369 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002370 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2371 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002372 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002373 if (name == NULL) {
2374 /* error */
2375 break;
2376 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002377 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002378 continue;
2379 }
2380 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002381 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002382
2383 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002384 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002385 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002386 type = SGML_CATA_PENTITY;
2387 case SGML_CATA_PENTITY:
2388 case SGML_CATA_DOCTYPE:
2389 case SGML_CATA_LINKTYPE:
2390 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002391 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002392 if (cur == NULL) {
2393 /* error */
2394 break;
2395 }
William M. Brack76e95df2003-10-18 16:20:14 +00002396 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002397 /* error */
2398 break;
2399 }
2400 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002401 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002402 if (cur == NULL) {
2403 /* error */
2404 break;
2405 }
2406 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002407 case SGML_CATA_PUBLIC:
2408 case SGML_CATA_SYSTEM:
2409 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002410 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002411 if (cur == NULL) {
2412 /* error */
2413 break;
2414 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002415 if (type != SGML_CATA_SYSTEM) {
2416 xmlChar *normid;
2417
2418 normid = xmlCatalogNormalizePublic(name);
2419 if (normid != NULL) {
2420 if (name != NULL)
2421 xmlFree(name);
2422 if (*normid != 0)
2423 name = normid;
2424 else {
2425 xmlFree(normid);
2426 name = NULL;
2427 }
2428 }
2429 }
William M. Brack76e95df2003-10-18 16:20:14 +00002430 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002431 /* error */
2432 break;
2433 }
2434 SKIP_BLANKS;
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;
Daniel Veillard344cee72001-08-20 00:08:40 +00002441 case SGML_CATA_BASE:
2442 case SGML_CATA_CATALOG:
2443 case SGML_CATA_DOCUMENT:
2444 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002445 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002446 if (cur == NULL) {
2447 /* error */
2448 break;
2449 }
2450 break;
2451 default:
2452 break;
2453 }
2454 if (cur == NULL) {
2455 if (name != NULL)
2456 xmlFree(name);
2457 if (sysid != NULL)
2458 xmlFree(sysid);
2459 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002460 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002461 if (base != NULL)
2462 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002463 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002464 } else if ((type == SGML_CATA_PUBLIC) ||
2465 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002466 xmlChar *filename;
2467
2468 filename = xmlBuildURI(sysid, base);
2469 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002470 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002471
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002472 entry = xmlNewCatalogEntry(type, name, filename,
William M. Brackb7b54de2004-10-06 16:38:01 +00002473 NULL, XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002474 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002475 if (res < 0) {
2476 xmlFreeCatalogEntry(entry);
2477 }
2478 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002479 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002480
Daniel Veillard344cee72001-08-20 00:08:40 +00002481 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002482 if (super) {
2483 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002484
Daniel Veillardc853b322001-11-06 15:24:37 +00002485 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002486 XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002487 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002488 if (res < 0) {
2489 xmlFreeCatalogEntry(entry);
2490 }
2491 } else {
2492 xmlChar *filename;
2493
2494 filename = xmlBuildURI(sysid, base);
2495 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002496 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002497 xmlFree(filename);
2498 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002499 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002500 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002501 /*
2502 * drop anything else we won't handle it
2503 */
2504 if (name != NULL)
2505 xmlFree(name);
2506 if (sysid != NULL)
2507 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002508 }
2509 }
2510 if (base != NULL)
2511 xmlFree(base);
2512 if (cur == NULL)
2513 return(-1);
2514 return(0);
2515}
2516
Daniel Veillard75b96822001-10-11 18:59:45 +00002517/************************************************************************
2518 * *
2519 * SGML Catalog handling *
2520 * *
2521 ************************************************************************/
2522
Daniel Veillardcda96922001-08-21 10:56:31 +00002523/**
2524 * xmlCatalogGetSGMLPublic:
2525 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002526 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002527 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002528 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002529 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002530 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002531 */
2532static const xmlChar *
2533xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2534 xmlCatalogEntryPtr entry;
Daniel Veillardc8155052004-07-16 09:03:08 +00002535 xmlChar *normid;
Daniel Veillardcda96922001-08-21 10:56:31 +00002536
2537 if (catal == NULL)
2538 return(NULL);
2539
Daniel Veillardc8155052004-07-16 09:03:08 +00002540 normid = xmlCatalogNormalizePublic(pubID);
2541 if (normid != NULL)
2542 pubID = (*normid != 0 ? normid : NULL);
2543
Daniel Veillardcda96922001-08-21 10:56:31 +00002544 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002545 if (entry == NULL) {
2546 if (normid != NULL)
2547 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002548 return(NULL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002549 }
2550 if (entry->type == SGML_CATA_PUBLIC) {
2551 if (normid != NULL)
2552 xmlFree(normid);
Daniel Veillardc853b322001-11-06 15:24:37 +00002553 return(entry->URL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002554 }
2555 if (normid != NULL)
2556 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002557 return(NULL);
2558}
2559
2560/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002561 * xmlCatalogGetSGMLSystem:
2562 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002563 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002564 *
2565 * Try to lookup the catalog local reference for a system ID
2566 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002567 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002568 */
2569static const xmlChar *
2570xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2571 xmlCatalogEntryPtr entry;
2572
2573 if (catal == NULL)
2574 return(NULL);
2575
2576 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2577 if (entry == NULL)
2578 return(NULL);
2579 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002580 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002581 return(NULL);
2582}
2583
2584/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002585 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002586 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002587 * @pubID: the public ID string
2588 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002589 *
2590 * Do a complete resolution lookup of an External Identifier
2591 *
2592 * Returns the URI of the resource or NULL if not found
2593 */
2594static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002595xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2596 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002597 const xmlChar *ret = NULL;
2598
Daniel Veillard75b96822001-10-11 18:59:45 +00002599 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002600 return(NULL);
2601
2602 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002603 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002604 if (ret != NULL)
2605 return(ret);
2606 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002607 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002608 return(NULL);
2609}
2610
Daniel Veillarda7374592001-05-10 14:17:55 +00002611/************************************************************************
2612 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002613 * Specific Public interfaces *
2614 * *
2615 ************************************************************************/
2616
2617/**
2618 * xmlLoadSGMLSuperCatalog:
2619 * @filename: a file path
2620 *
2621 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2622 * references. This is only needed for manipulating SGML Super Catalogs
2623 * like adding and removing CATALOG or DELEGATE entries.
2624 *
2625 * Returns the catalog parsed or NULL in case of error
2626 */
2627xmlCatalogPtr
2628xmlLoadSGMLSuperCatalog(const char *filename)
2629{
2630 xmlChar *content;
2631 xmlCatalogPtr catal;
2632 int ret;
2633
2634 content = xmlLoadFileContent(filename);
2635 if (content == NULL)
2636 return(NULL);
2637
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002638 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002639 if (catal == NULL) {
2640 xmlFree(content);
2641 return(NULL);
2642 }
2643
2644 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2645 xmlFree(content);
2646 if (ret < 0) {
2647 xmlFreeCatalog(catal);
2648 return(NULL);
2649 }
2650 return (catal);
2651}
2652
2653/**
2654 * xmlLoadACatalog:
2655 * @filename: a file path
2656 *
2657 * Load the catalog and build the associated data structures.
2658 * This can be either an XML Catalog or an SGML Catalog
2659 * It will recurse in SGML CATALOG entries. On the other hand XML
2660 * Catalogs are not handled recursively.
2661 *
2662 * Returns the catalog parsed or NULL in case of error
2663 */
2664xmlCatalogPtr
2665xmlLoadACatalog(const char *filename)
2666{
2667 xmlChar *content;
2668 xmlChar *first;
2669 xmlCatalogPtr catal;
2670 int ret;
2671
2672 content = xmlLoadFileContent(filename);
2673 if (content == NULL)
2674 return(NULL);
2675
2676
2677 first = content;
2678
2679 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2680 (!(((*first >= 'A') && (*first <= 'Z')) ||
2681 ((*first >= 'a') && (*first <= 'z')))))
2682 first++;
2683
2684 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002685 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002686 if (catal == NULL) {
2687 xmlFree(content);
2688 return(NULL);
2689 }
2690 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2691 if (ret < 0) {
2692 xmlFreeCatalog(catal);
2693 xmlFree(content);
2694 return(NULL);
2695 }
2696 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002697 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002698 if (catal == NULL) {
2699 xmlFree(content);
2700 return(NULL);
2701 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002702 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002703 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002704 }
2705 xmlFree(content);
2706 return (catal);
2707}
2708
2709/**
2710 * xmlExpandCatalog:
2711 * @catal: a catalog
2712 * @filename: a file path
2713 *
2714 * Load the catalog and expand the existing catal structure.
2715 * This can be either an XML Catalog or an SGML Catalog
2716 *
2717 * Returns 0 in case of success, -1 in case of error
2718 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002719static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002720xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2721{
Daniel Veillard75b96822001-10-11 18:59:45 +00002722 int ret;
2723
2724 if ((catal == NULL) || (filename == NULL))
2725 return(-1);
2726
Daniel Veillard75b96822001-10-11 18:59:45 +00002727
2728 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002729 xmlChar *content;
2730
2731 content = xmlLoadFileContent(filename);
2732 if (content == NULL)
2733 return(-1);
2734
Daniel Veillard75b96822001-10-11 18:59:45 +00002735 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2736 if (ret < 0) {
2737 xmlFree(content);
2738 return(-1);
2739 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002740 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002741 } else {
2742 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002743 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002744 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002745
Daniel Veillard75b96822001-10-11 18:59:45 +00002746 cur = catal->xml;
2747 if (cur == NULL) {
2748 catal->xml = tmp;
2749 } else {
2750 while (cur->next != NULL) cur = cur->next;
2751 cur->next = tmp;
2752 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002753 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002754 return (0);
2755}
2756
2757/**
2758 * xmlACatalogResolveSystem:
2759 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002760 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002761 *
2762 * Try to lookup the catalog resource for a system ID
2763 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002764 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002765 * must be freed by the caller.
2766 */
2767xmlChar *
2768xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2769 xmlChar *ret = NULL;
2770
2771 if ((sysID == NULL) || (catal == NULL))
2772 return(NULL);
2773
2774 if (xmlDebugCatalogs)
2775 xmlGenericError(xmlGenericErrorContext,
2776 "Resolve sysID %s\n", sysID);
2777
2778 if (catal->type == XML_XML_CATALOG_TYPE) {
2779 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2780 if (ret == XML_CATAL_BREAK)
2781 ret = NULL;
2782 } else {
2783 const xmlChar *sgml;
2784
2785 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2786 if (sgml != NULL)
2787 ret = xmlStrdup(sgml);
2788 }
2789 return(ret);
2790}
2791
2792/**
2793 * xmlACatalogResolvePublic:
2794 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002795 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002796 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002797 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002798 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002799 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002800 * must be freed by the caller.
2801 */
2802xmlChar *
2803xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2804 xmlChar *ret = NULL;
2805
2806 if ((pubID == NULL) || (catal == NULL))
2807 return(NULL);
2808
2809 if (xmlDebugCatalogs)
2810 xmlGenericError(xmlGenericErrorContext,
2811 "Resolve pubID %s\n", pubID);
2812
2813 if (catal->type == XML_XML_CATALOG_TYPE) {
2814 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2815 if (ret == XML_CATAL_BREAK)
2816 ret = NULL;
2817 } else {
2818 const xmlChar *sgml;
2819
2820 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2821 if (sgml != NULL)
2822 ret = xmlStrdup(sgml);
2823 }
2824 return(ret);
2825}
2826
2827/**
2828 * xmlACatalogResolve:
2829 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002830 * @pubID: the public ID string
2831 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002832 *
2833 * Do a complete resolution lookup of an External Identifier
2834 *
2835 * Returns the URI of the resource or NULL if not found, it must be freed
2836 * by the caller.
2837 */
2838xmlChar *
2839xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2840 const xmlChar * sysID)
2841{
2842 xmlChar *ret = NULL;
2843
2844 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2845 return (NULL);
2846
2847 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002848 if ((pubID != NULL) && (sysID != NULL)) {
2849 xmlGenericError(xmlGenericErrorContext,
2850 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2851 } else if (pubID != NULL) {
2852 xmlGenericError(xmlGenericErrorContext,
2853 "Resolve: pubID %s\n", pubID);
2854 } else {
2855 xmlGenericError(xmlGenericErrorContext,
2856 "Resolve: sysID %s\n", sysID);
2857 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002858 }
2859
2860 if (catal->type == XML_XML_CATALOG_TYPE) {
2861 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2862 if (ret == XML_CATAL_BREAK)
2863 ret = NULL;
2864 } else {
2865 const xmlChar *sgml;
2866
2867 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2868 if (sgml != NULL)
2869 ret = xmlStrdup(sgml);
2870 }
2871 return (ret);
2872}
2873
2874/**
2875 * xmlACatalogResolveURI:
2876 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002877 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002878 *
2879 * Do a complete resolution lookup of an URI
2880 *
2881 * Returns the URI of the resource or NULL if not found, it must be freed
2882 * by the caller.
2883 */
2884xmlChar *
2885xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2886 xmlChar *ret = NULL;
2887
2888 if ((URI == NULL) || (catal == NULL))
2889 return(NULL);
2890
Daniel Veillardb44025c2001-10-11 22:55:55 +00002891 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002892 xmlGenericError(xmlGenericErrorContext,
2893 "Resolve URI %s\n", URI);
2894
2895 if (catal->type == XML_XML_CATALOG_TYPE) {
2896 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2897 if (ret == XML_CATAL_BREAK)
2898 ret = NULL;
2899 } else {
2900 const xmlChar *sgml;
2901
2902 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2903 if (sgml != NULL)
2904 sgml = xmlStrdup(sgml);
2905 }
2906 return(ret);
2907}
2908
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002909#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002910/**
2911 * xmlACatalogDump:
2912 * @catal: a Catalog
2913 * @out: the file.
2914 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002915 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002916 */
2917void
2918xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002919 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002920 return;
2921
2922 if (catal->type == XML_XML_CATALOG_TYPE) {
2923 xmlDumpXMLCatalog(out, catal->xml);
2924 } else {
2925 xmlHashScan(catal->sgml,
2926 (xmlHashScanner) xmlCatalogDumpEntry, out);
2927 }
2928}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002929#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002930
2931/**
2932 * xmlACatalogAdd:
2933 * @catal: a Catalog
2934 * @type: the type of record to add to the catalog
2935 * @orig: the system, public or prefix to match
2936 * @replace: the replacement value for the match
2937 *
2938 * Add an entry in the catalog, it may overwrite existing but
2939 * different entries.
2940 *
2941 * Returns 0 if successful, -1 otherwise
2942 */
2943int
2944xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2945 const xmlChar * orig, const xmlChar * replace)
2946{
2947 int res = -1;
2948
2949 if (catal == NULL)
2950 return(-1);
2951
2952 if (catal->type == XML_XML_CATALOG_TYPE) {
2953 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2954 } else {
2955 xmlCatalogEntryType cattype;
2956
2957 cattype = xmlGetSGMLCatalogEntryType(type);
2958 if (cattype != XML_CATA_NONE) {
2959 xmlCatalogEntryPtr entry;
2960
Daniel Veillardc853b322001-11-06 15:24:37 +00002961 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002962 XML_CATA_PREFER_NONE, NULL);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002963 if (catal->sgml == NULL)
2964 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002965 res = xmlHashAddEntry(catal->sgml, orig, entry);
2966 }
2967 }
2968 return (res);
2969}
2970
2971/**
2972 * xmlACatalogRemove:
2973 * @catal: a Catalog
2974 * @value: the value to remove
2975 *
2976 * Remove an entry from the catalog
2977 *
2978 * Returns the number of entries removed if successful, -1 otherwise
2979 */
2980int
2981xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2982 int res = -1;
2983
2984 if ((catal == NULL) || (value == NULL))
2985 return(-1);
2986
2987 if (catal->type == XML_XML_CATALOG_TYPE) {
2988 res = xmlDelXMLCatalog(catal->xml, value);
2989 } else {
2990 res = xmlHashRemoveEntry(catal->sgml, value,
2991 (xmlHashDeallocator) xmlFreeCatalogEntry);
2992 if (res == 0)
2993 res = 1;
2994 }
2995 return(res);
2996}
2997
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002998/**
2999 * xmlNewCatalog:
3000 * @sgml: should this create an SGML catalog
3001 *
3002 * create a new Catalog.
3003 *
3004 * Returns the xmlCatalogPtr or NULL in case of error
3005 */
3006xmlCatalogPtr
3007xmlNewCatalog(int sgml) {
3008 xmlCatalogPtr catal = NULL;
3009
3010 if (sgml) {
3011 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3012 xmlCatalogDefaultPrefer);
3013 if ((catal != NULL) && (catal->sgml == NULL))
3014 catal->sgml = xmlHashCreate(10);
3015 } else
3016 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3017 xmlCatalogDefaultPrefer);
3018 return(catal);
3019}
3020
3021/**
3022 * xmlCatalogIsEmpty:
3023 * @catal: should this create an SGML catalog
3024 *
3025 * Check is a catalog is empty
3026 *
3027 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3028 */
3029int
3030xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3031 if (catal == NULL)
3032 return(-1);
3033
3034 if (catal->type == XML_XML_CATALOG_TYPE) {
3035 if (catal->xml == NULL)
3036 return(1);
3037 if ((catal->xml->type != XML_CATA_CATALOG) &&
3038 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3039 return(-1);
3040 if (catal->xml->children == NULL)
3041 return(1);
3042 return(0);
3043 } else {
3044 int res;
3045
3046 if (catal->sgml == NULL)
3047 return(1);
3048 res = xmlHashSize(catal->sgml);
3049 if (res == 0)
3050 return(1);
3051 if (res < 0)
3052 return(-1);
3053 }
3054 return(0);
3055}
3056
Daniel Veillard75b96822001-10-11 18:59:45 +00003057/************************************************************************
3058 * *
3059 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00003060 * *
3061 ************************************************************************/
3062
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003063/**
Daniel Veillard81463942001-10-16 12:34:39 +00003064 * xmlInitializeCatalogData:
3065 *
3066 * Do the catalog initialization only of global data, doesn't try to load
3067 * any catalog actually.
3068 * this function is not thread safe, catalog initialization should
3069 * preferably be done once at startup
3070 */
3071static void
3072xmlInitializeCatalogData(void) {
3073 if (xmlCatalogInitialized != 0)
3074 return;
3075
3076 if (getenv("XML_DEBUG_CATALOG"))
3077 xmlDebugCatalogs = 1;
3078 xmlCatalogMutex = xmlNewRMutex();
3079
3080 xmlCatalogInitialized = 1;
3081}
3082/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003083 * xmlInitializeCatalog:
3084 *
3085 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00003086 * this function is not thread safe, catalog initialization should
3087 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003088 */
3089void
3090xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003091 if (xmlCatalogInitialized != 0)
3092 return;
3093
Daniel Veillard81463942001-10-16 12:34:39 +00003094 xmlInitializeCatalogData();
3095 xmlRMutexLock(xmlCatalogMutex);
3096
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003097 if (getenv("XML_DEBUG_CATALOG"))
3098 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00003099
Daniel Veillard75b96822001-10-11 18:59:45 +00003100 if (xmlDefaultCatalog == NULL) {
3101 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003102 char *path;
3103 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00003104 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003105 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00003106
Daniel Veillardb44025c2001-10-11 22:55:55 +00003107 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003108 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003109#if defined(_WIN32) && defined(_MSC_VER)
3110 {
3111 void* hmodule;
3112 hmodule = GetModuleHandleA("libxml2.dll");
3113 if (hmodule == NULL)
3114 hmodule = GetModuleHandleA(NULL);
3115 if (hmodule != NULL) {
3116 char buf[256];
3117 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3118 if (len != 0) {
3119 char* p = &(buf[len]);
3120 while (*p != '\\' && p > buf)
3121 p--;
3122 if (p != buf) {
3123 xmlChar* uri;
3124 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3125 uri = xmlCanonicPath(buf);
3126 if (uri != NULL) {
3127 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3128 xmlFree(uri);
3129 }
3130 }
3131 }
3132 }
3133 catalogs = XML_XML_DEFAULT_CATALOG;
3134 }
3135#else
Daniel Veillard75b96822001-10-11 18:59:45 +00003136 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00003137#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00003138
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003139 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3140 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003141 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003142 /* the XML_CATALOG_FILES envvar is allowed to contain a
3143 space-separated list of entries. */
3144 cur = catalogs;
3145 nextent = &catal->xml;
3146 while (*cur != '\0') {
William M. Brack68aca052003-10-11 15:22:13 +00003147 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003148 cur++;
3149 if (*cur != 0) {
3150 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003151 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003152 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00003153 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003154 if (path != NULL) {
3155 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003156 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003157 if (*nextent != NULL)
3158 nextent = &((*nextent)->next);
3159 xmlFree(path);
3160 }
3161 }
3162 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003163 xmlDefaultCatalog = catal;
3164 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003165 }
3166
Daniel Veillard81463942001-10-16 12:34:39 +00003167 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003168}
3169
Daniel Veillard82d75332001-10-08 15:01:59 +00003170
3171/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003172 * xmlLoadCatalog:
3173 * @filename: a file path
3174 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003175 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003176 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003177 * this function is not thread safe, catalog initialization should
3178 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003179 *
3180 * Returns 0 in case of success -1 in case of error
3181 */
3182int
Daniel Veillard16756b62001-10-01 07:36:25 +00003183xmlLoadCatalog(const char *filename)
3184{
Daniel Veillard75b96822001-10-11 18:59:45 +00003185 int ret;
3186 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003187
Daniel Veillard81463942001-10-16 12:34:39 +00003188 if (!xmlCatalogInitialized)
3189 xmlInitializeCatalogData();
3190
3191 xmlRMutexLock(xmlCatalogMutex);
3192
Daniel Veillard75b96822001-10-11 18:59:45 +00003193 if (xmlDefaultCatalog == NULL) {
3194 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003195 if (catal == NULL) {
3196 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003197 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003198 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003199
Daniel Veillard75b96822001-10-11 18:59:45 +00003200 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003201 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003202 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003203 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003204
Daniel Veillard75b96822001-10-11 18:59:45 +00003205 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003206 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003207 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003208}
3209
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003210/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003211 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003212 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003213 *
3214 * Load the catalogs and makes their definitions effective for the default
3215 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003216 * this function is not thread safe, catalog initialization should
3217 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003218 */
3219void
3220xmlLoadCatalogs(const char *pathss) {
3221 const char *cur;
3222 const char *paths;
3223 xmlChar *path;
Daniel Veillarded121382007-04-17 12:33:19 +00003224#ifdef _WIN32
3225 int i, iLen;
3226#endif
Daniel Veillard81418e32001-05-22 15:08:55 +00003227
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003228 if (pathss == NULL)
3229 return;
3230
Daniel Veillard81418e32001-05-22 15:08:55 +00003231 cur = pathss;
Daniel Veillard2728f842006-03-09 16:49:24 +00003232 while (*cur != 0) {
William M. Brack68aca052003-10-11 15:22:13 +00003233 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003234 if (*cur != 0) {
3235 paths = cur;
Daniel Veillarded121382007-04-17 12:33:19 +00003236 while ((*cur != 0) && (*cur != PATH_SEAPARATOR) && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003237 cur++;
3238 path = xmlStrndup((const xmlChar *)paths, cur - paths);
Daniel Veillarded121382007-04-17 12:33:19 +00003239#ifdef _WIN32
3240 iLen = strlen(path);
3241 for(i = 0; i < iLen; i++) {
3242 if(path[i] == '\\') {
3243 path[i] = '/';
3244 }
3245 }
3246#endif
Daniel Veillard81418e32001-05-22 15:08:55 +00003247 if (path != NULL) {
3248 xmlLoadCatalog((const char *) path);
3249 xmlFree(path);
3250 }
3251 }
Daniel Veillarded121382007-04-17 12:33:19 +00003252 while (*cur == PATH_SEAPARATOR)
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003253 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003254 }
3255}
3256
Daniel Veillarda7374592001-05-10 14:17:55 +00003257/**
3258 * xmlCatalogCleanup:
3259 *
3260 * Free up all the memory associated with catalogs
3261 */
3262void
3263xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003264 if (xmlCatalogInitialized == 0)
3265 return;
3266
Daniel Veillard81463942001-10-16 12:34:39 +00003267 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003268 if (xmlDebugCatalogs)
3269 xmlGenericError(xmlGenericErrorContext,
3270 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003271 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003272 xmlHashFree(xmlCatalogXMLFiles,
3273 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003274 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003275 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003276 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003277 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003278 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003279 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003280 xmlRMutexUnlock(xmlCatalogMutex);
3281 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003282}
3283
3284/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003285 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003286 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003287 *
3288 * Try to lookup the catalog resource for a system ID
3289 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003290 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003291 * must be freed by the caller.
3292 */
3293xmlChar *
3294xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003295 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003296
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003297 if (!xmlCatalogInitialized)
3298 xmlInitializeCatalog();
3299
Daniel Veillard75b96822001-10-11 18:59:45 +00003300 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3301 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003302}
3303
3304/**
3305 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003306 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003307 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003308 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003309 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003310 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003311 * must be freed by the caller.
3312 */
3313xmlChar *
3314xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003315 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003316
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003317 if (!xmlCatalogInitialized)
3318 xmlInitializeCatalog();
3319
Daniel Veillard75b96822001-10-11 18:59:45 +00003320 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3321 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003322}
Daniel Veillard344cee72001-08-20 00:08:40 +00003323
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003324/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003325 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003326 * @pubID: the public ID string
3327 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003328 *
3329 * Do a complete resolution lookup of an External Identifier
3330 *
3331 * Returns the URI of the resource or NULL if not found, it must be freed
3332 * by the caller.
3333 */
3334xmlChar *
3335xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003336 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003337
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003338 if (!xmlCatalogInitialized)
3339 xmlInitializeCatalog();
3340
Daniel Veillard75b96822001-10-11 18:59:45 +00003341 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3342 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003343}
3344
3345/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003346 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003347 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003348 *
3349 * Do a complete resolution lookup of an URI
3350 *
3351 * Returns the URI of the resource or NULL if not found, it must be freed
3352 * by the caller.
3353 */
3354xmlChar *
3355xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003356 xmlChar *ret;
3357
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003358 if (!xmlCatalogInitialized)
3359 xmlInitializeCatalog();
3360
Daniel Veillard75b96822001-10-11 18:59:45 +00003361 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3362 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003363}
3364
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003365#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003366/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003367 * xmlCatalogDump:
3368 * @out: the file.
3369 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003370 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003371 */
3372void
3373xmlCatalogDump(FILE *out) {
3374 if (out == NULL)
3375 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003376
Daniel Veillard75b96822001-10-11 18:59:45 +00003377 if (!xmlCatalogInitialized)
3378 xmlInitializeCatalog();
3379
3380 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003381}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003382#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003383
3384/**
3385 * xmlCatalogAdd:
3386 * @type: the type of record to add to the catalog
3387 * @orig: the system, public or prefix to match
3388 * @replace: the replacement value for the match
3389 *
3390 * Add an entry in the catalog, it may overwrite existing but
3391 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003392 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003393 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003394 *
3395 * Returns 0 if successful, -1 otherwise
3396 */
3397int
3398xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3399 int res = -1;
3400
Daniel Veillard81463942001-10-16 12:34:39 +00003401 if (!xmlCatalogInitialized)
3402 xmlInitializeCatalogData();
3403
3404 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003405 /*
3406 * Specific case where one want to override the default catalog
3407 * put in place by xmlInitializeCatalog();
3408 */
3409 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003410 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003411 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003412 xmlCatalogDefaultPrefer);
3413 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003414 orig, NULL, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003415
Daniel Veillard81463942001-10-16 12:34:39 +00003416 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003417 return(0);
3418 }
3419
Daniel Veillard75b96822001-10-11 18:59:45 +00003420 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003421 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003422 return(res);
3423}
3424
3425/**
3426 * xmlCatalogRemove:
3427 * @value: the value to remove
3428 *
3429 * Remove an entry from the catalog
3430 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003431 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003432 */
3433int
3434xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003435 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003436
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003437 if (!xmlCatalogInitialized)
3438 xmlInitializeCatalog();
3439
Daniel Veillard81463942001-10-16 12:34:39 +00003440 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003441 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003442 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003443 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003444}
3445
3446/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003447 * xmlCatalogConvert:
3448 *
3449 * Convert all the SGML catalog entries as XML ones
3450 *
3451 * Returns the number of entries converted if successful, -1 otherwise
3452 */
3453int
3454xmlCatalogConvert(void) {
3455 int res = -1;
3456
3457 if (!xmlCatalogInitialized)
3458 xmlInitializeCatalog();
3459
Daniel Veillard81463942001-10-16 12:34:39 +00003460 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003461 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003462 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003463 return(res);
3464}
3465
Daniel Veillard75b96822001-10-11 18:59:45 +00003466/************************************************************************
3467 * *
3468 * Public interface manipulating the common preferences *
3469 * *
3470 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003471
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003472/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003473 * xmlCatalogGetDefaults:
3474 *
3475 * Used to get the user preference w.r.t. to what catalogs should
3476 * be accepted
3477 *
3478 * Returns the current xmlCatalogAllow value
3479 */
3480xmlCatalogAllow
3481xmlCatalogGetDefaults(void) {
3482 return(xmlCatalogDefaultAllow);
3483}
3484
3485/**
3486 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003487 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003488 *
3489 * Used to set the user preference w.r.t. to what catalogs should
3490 * be accepted
3491 */
3492void
3493xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003494 if (xmlDebugCatalogs) {
3495 switch (allow) {
3496 case XML_CATA_ALLOW_NONE:
3497 xmlGenericError(xmlGenericErrorContext,
3498 "Disabling catalog usage\n");
3499 break;
3500 case XML_CATA_ALLOW_GLOBAL:
3501 xmlGenericError(xmlGenericErrorContext,
3502 "Allowing only global catalogs\n");
3503 break;
3504 case XML_CATA_ALLOW_DOCUMENT:
3505 xmlGenericError(xmlGenericErrorContext,
3506 "Allowing only catalogs from the document\n");
3507 break;
3508 case XML_CATA_ALLOW_ALL:
3509 xmlGenericError(xmlGenericErrorContext,
3510 "Allowing all catalogs\n");
3511 break;
3512 }
3513 }
3514 xmlCatalogDefaultAllow = allow;
3515}
3516
3517/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003518 * xmlCatalogSetDefaultPrefer:
3519 * @prefer: the default preference for delegation
3520 *
3521 * Allows to set the preference between public and system for deletion
3522 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003523 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003524 *
3525 * Returns the previous value of the default preference for delegation
3526 */
3527xmlCatalogPrefer
3528xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3529 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3530
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003531 if (prefer == XML_CATA_PREFER_NONE)
3532 return(ret);
3533
3534 if (xmlDebugCatalogs) {
3535 switch (prefer) {
3536 case XML_CATA_PREFER_PUBLIC:
3537 xmlGenericError(xmlGenericErrorContext,
3538 "Setting catalog preference to PUBLIC\n");
3539 break;
3540 case XML_CATA_PREFER_SYSTEM:
3541 xmlGenericError(xmlGenericErrorContext,
3542 "Setting catalog preference to SYSTEM\n");
3543 break;
3544 case XML_CATA_PREFER_NONE:
3545 break;
3546 }
3547 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003548 xmlCatalogDefaultPrefer = prefer;
3549 return(ret);
3550}
3551
3552/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003553 * xmlCatalogSetDebug:
3554 * @level: the debug level of catalogs required
3555 *
3556 * Used to set the debug level for catalog operation, 0 disable
3557 * debugging, 1 enable it
3558 *
3559 * Returns the previous value of the catalog debugging level
3560 */
3561int
3562xmlCatalogSetDebug(int level) {
3563 int ret = xmlDebugCatalogs;
3564
3565 if (level <= 0)
3566 xmlDebugCatalogs = 0;
3567 else
3568 xmlDebugCatalogs = level;
3569 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003570}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003571
Daniel Veillard75b96822001-10-11 18:59:45 +00003572/************************************************************************
3573 * *
3574 * Minimal interfaces used for per-document catalogs by the parser *
3575 * *
3576 ************************************************************************/
3577
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003578/**
3579 * xmlCatalogFreeLocal:
3580 * @catalogs: a document's list of catalogs
3581 *
3582 * Free up the memory associated to the catalog list
3583 */
3584void
3585xmlCatalogFreeLocal(void *catalogs) {
3586 xmlCatalogEntryPtr catal;
3587
Daniel Veillard81463942001-10-16 12:34:39 +00003588 if (!xmlCatalogInitialized)
3589 xmlInitializeCatalog();
3590
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003591 catal = (xmlCatalogEntryPtr) catalogs;
3592 if (catal != NULL)
3593 xmlFreeCatalogEntryList(catal);
3594}
3595
3596
3597/**
3598 * xmlCatalogAddLocal:
3599 * @catalogs: a document's list of catalogs
3600 * @URL: the URL to a new local catalog
3601 *
3602 * Add the new entry to the catalog list
3603 *
3604 * Returns the updated list
3605 */
3606void *
3607xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3608 xmlCatalogEntryPtr catal, add;
3609
3610 if (!xmlCatalogInitialized)
3611 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003612
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003613 if (URL == NULL)
3614 return(catalogs);
3615
3616 if (xmlDebugCatalogs)
3617 xmlGenericError(xmlGenericErrorContext,
3618 "Adding document catalog %s\n", URL);
3619
Daniel Veillardc853b322001-11-06 15:24:37 +00003620 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003621 xmlCatalogDefaultPrefer, NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003622 if (add == NULL)
3623 return(catalogs);
3624
3625 catal = (xmlCatalogEntryPtr) catalogs;
3626 if (catal == NULL)
3627 return((void *) add);
3628
3629 while (catal->next != NULL)
3630 catal = catal->next;
3631 catal->next = add;
3632 return(catalogs);
3633}
3634
3635/**
3636 * xmlCatalogLocalResolve:
3637 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003638 * @pubID: the public ID string
3639 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003640 *
3641 * Do a complete resolution lookup of an External Identifier using a
3642 * document's private catalog list
3643 *
3644 * Returns the URI of the resource or NULL if not found, it must be freed
3645 * by the caller.
3646 */
3647xmlChar *
3648xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3649 const xmlChar *sysID) {
3650 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003651 xmlChar *ret;
3652
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003653 if (!xmlCatalogInitialized)
3654 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003655
Daniel Veillard81463942001-10-16 12:34:39 +00003656 if ((pubID == NULL) && (sysID == NULL))
3657 return(NULL);
3658
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003659 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003660 if ((pubID != NULL) && (sysID != NULL)) {
3661 xmlGenericError(xmlGenericErrorContext,
3662 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3663 } else if (pubID != NULL) {
3664 xmlGenericError(xmlGenericErrorContext,
3665 "Local Resolve: pubID %s\n", pubID);
3666 } else {
3667 xmlGenericError(xmlGenericErrorContext,
3668 "Local Resolve: sysID %s\n", sysID);
3669 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003670 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003671
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003672 catal = (xmlCatalogEntryPtr) catalogs;
3673 if (catal == NULL)
3674 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003675 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3676 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3677 return(ret);
3678 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003679}
3680
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003681/**
3682 * xmlCatalogLocalResolveURI:
3683 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003684 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003685 *
3686 * Do a complete resolution lookup of an URI using a
3687 * document's private catalog list
3688 *
3689 * Returns the URI of the resource or NULL if not found, it must be freed
3690 * by the caller.
3691 */
3692xmlChar *
3693xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3694 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003695 xmlChar *ret;
3696
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003697 if (!xmlCatalogInitialized)
3698 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003699
Daniel Veillard81463942001-10-16 12:34:39 +00003700 if (URI == NULL)
3701 return(NULL);
3702
Daniel Veillard6990bf32001-08-23 21:17:48 +00003703 if (xmlDebugCatalogs)
3704 xmlGenericError(xmlGenericErrorContext,
3705 "Resolve URI %s\n", URI);
3706
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003707 catal = (xmlCatalogEntryPtr) catalogs;
3708 if (catal == NULL)
3709 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003710 ret = xmlCatalogListXMLResolveURI(catal, URI);
3711 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3712 return(ret);
3713 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003714}
3715
Daniel Veillard75b96822001-10-11 18:59:45 +00003716/************************************************************************
3717 * *
3718 * Deprecated interfaces *
3719 * *
3720 ************************************************************************/
3721/**
3722 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003723 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003724 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003725 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003726 * DEPRECATED, use xmlCatalogResolveSystem()
3727 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003728 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003729 */
3730const xmlChar *
3731xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003732 xmlChar *ret;
3733 static xmlChar result[1000];
3734 static int msg = 0;
3735
3736 if (!xmlCatalogInitialized)
3737 xmlInitializeCatalog();
3738
3739 if (msg == 0) {
3740 xmlGenericError(xmlGenericErrorContext,
3741 "Use of deprecated xmlCatalogGetSystem() call\n");
3742 msg++;
3743 }
3744
3745 if (sysID == NULL)
3746 return(NULL);
3747
3748 /*
3749 * Check first the XML catalogs
3750 */
3751 if (xmlDefaultCatalog != NULL) {
3752 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3753 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3754 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3755 result[sizeof(result) - 1] = 0;
3756 return(result);
3757 }
3758 }
3759
3760 if (xmlDefaultCatalog != NULL)
3761 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3762 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003763}
3764
3765/**
3766 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003767 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003768 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003769 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003770 * DEPRECATED, use xmlCatalogResolvePublic()
3771 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003772 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003773 */
3774const xmlChar *
3775xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003776 xmlChar *ret;
3777 static xmlChar result[1000];
3778 static int msg = 0;
3779
3780 if (!xmlCatalogInitialized)
3781 xmlInitializeCatalog();
3782
3783 if (msg == 0) {
3784 xmlGenericError(xmlGenericErrorContext,
3785 "Use of deprecated xmlCatalogGetPublic() call\n");
3786 msg++;
3787 }
3788
3789 if (pubID == NULL)
3790 return(NULL);
3791
3792 /*
3793 * Check first the XML catalogs
3794 */
3795 if (xmlDefaultCatalog != NULL) {
3796 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3797 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3798 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3799 result[sizeof(result) - 1] = 0;
3800 return(result);
3801 }
3802 }
3803
3804 if (xmlDefaultCatalog != NULL)
3805 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3806 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003807}
3808
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003809#define bottom_catalog
3810#include "elfgcchack.h"
Daniel Veillarda7374592001-05-10 14:17:55 +00003811#endif /* LIBXML_CATALOG_ENABLED */