blob: 908dda5da5653b0ed22a40e8e705e61d413cba78 [file] [log] [blame]
Daniel Veillarda7374592001-05-10 14:17:55 +00001/**
2 * catalog.c: set of generic Catalog related routines
3 *
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
6 *
Daniel Veillard344cee72001-08-20 00:08:40 +00007 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9 *
Daniel Veillarda7374592001-05-10 14:17:55 +000010 * See Copyright for the status of this software.
11 *
12 * Daniel.Veillard@imag.fr
13 */
14
Daniel Veillard34ce8be2002-03-18 19:37:11 +000015#define IN_LIBXML
Daniel Veillarda7374592001-05-10 14:17:55 +000016#include "libxml.h"
17
18#ifdef LIBXML_CATALOG_ENABLED
19#ifdef HAVE_SYS_TYPES_H
20#include <sys/types.h>
21#endif
22#ifdef HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#ifdef HAVE_FCNTL_H
29#include <fcntl.h>
30#endif
Daniel Veillardc0631a62001-09-20 13:56:06 +000031#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000034#include <string.h>
35#include <libxml/xmlmemory.h>
36#include <libxml/hash.h>
37#include <libxml/uri.h>
38#include <libxml/parserInternals.h>
39#include <libxml/catalog.h>
40#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000041#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000042#include <libxml/globals.h>
Daniel Veillarda7374592001-05-10 14:17:55 +000043
Daniel Veillard6990bf32001-08-23 21:17:48 +000044#define MAX_DELEGATE 50
Daniel Veillard5ee43b02003-08-04 00:58:46 +000045#define MAX_CATAL_DEPTH 50
Daniel Veillard6990bf32001-08-23 21:17:48 +000046
Daniel Veillard344cee72001-08-20 00:08:40 +000047/**
48 * TODO:
49 *
50 * macro to flag unimplemented blocks
Daniel Veillard3e59fc52003-04-18 12:34:58 +000051 * XML_CATALOG_PREFER user env to select between system/public prefered
52 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
53 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
54 *> values "system" and "public". I have made the default be "system" to
55 *> match yours.
Daniel Veillard344cee72001-08-20 00:08:40 +000056 */
57#define TODO \
58 xmlGenericError(xmlGenericErrorContext, \
59 "Unimplemented block at %s:%d\n", \
60 __FILE__, __LINE__);
61
Daniel Veillardcda96922001-08-21 10:56:31 +000062#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000063#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000064#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000065#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000066#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000067#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000068#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000069#endif
70
Daniel Veillardfb382b82004-06-14 12:13:12 +000071#if defined(_WIN32) && defined(_MSC_VER)
72#undef XML_XML_DEFAULT_CATALOG
73static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
74void* __stdcall GetModuleHandleA(const char*);
75unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
76#endif
77
Daniel Veillardc8155052004-07-16 09:03:08 +000078static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
Daniel Veillard85c11fa2001-10-16 21:03:08 +000079static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000080
Daniel Veillarda7374592001-05-10 14:17:55 +000081/************************************************************************
82 * *
83 * Types, all private *
84 * *
85 ************************************************************************/
86
87typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000088 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000089 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000090 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000091 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000092 XML_CATA_NEXT_CATALOG,
William M. Brackb7b54de2004-10-06 16:38:01 +000093 XML_CATA_GROUP,
Daniel Veillard344cee72001-08-20 00:08:40 +000094 XML_CATA_PUBLIC,
95 XML_CATA_SYSTEM,
96 XML_CATA_REWRITE_SYSTEM,
97 XML_CATA_DELEGATE_PUBLIC,
98 XML_CATA_DELEGATE_SYSTEM,
99 XML_CATA_URI,
100 XML_CATA_REWRITE_URI,
101 XML_CATA_DELEGATE_URI,
102 SGML_CATA_SYSTEM,
103 SGML_CATA_PUBLIC,
104 SGML_CATA_ENTITY,
105 SGML_CATA_PENTITY,
106 SGML_CATA_DOCTYPE,
107 SGML_CATA_LINKTYPE,
108 SGML_CATA_NOTATION,
109 SGML_CATA_DELEGATE,
110 SGML_CATA_BASE,
111 SGML_CATA_CATALOG,
112 SGML_CATA_DOCUMENT,
113 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000114} xmlCatalogEntryType;
115
116typedef struct _xmlCatalogEntry xmlCatalogEntry;
117typedef xmlCatalogEntry *xmlCatalogEntryPtr;
118struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000119 struct _xmlCatalogEntry *next;
120 struct _xmlCatalogEntry *parent;
121 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000122 xmlCatalogEntryType type;
123 xmlChar *name;
124 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000125 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000126 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000127 int dealloc;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000128 int depth;
William M. Brackb7b54de2004-10-06 16:38:01 +0000129 struct _xmlCatalogEntry *group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000130};
131
Daniel Veillard75b96822001-10-11 18:59:45 +0000132typedef enum {
133 XML_XML_CATALOG_TYPE = 1,
134 XML_SGML_CATALOG_TYPE
135} xmlCatalogType;
136
137#define XML_MAX_SGML_CATA_DEPTH 10
138struct _xmlCatalog {
139 xmlCatalogType type; /* either XML or SGML */
140
141 /*
142 * SGML Catalogs are stored as a simple hash table of catalog entries
143 * Catalog stack to check against overflows when building the
144 * SGML catalog
145 */
146 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
147 int catalNr; /* Number of current catal streams */
148 int catalMax; /* Max number of catal streams */
149 xmlHashTablePtr sgml;
150
151 /*
152 * XML Catalogs are stored as a tree of Catalog entries
153 */
154 xmlCatalogPrefer prefer;
155 xmlCatalogEntryPtr xml;
156};
157
158/************************************************************************
159 * *
160 * Global variables *
161 * *
162 ************************************************************************/
163
Daniel Veillard81463942001-10-16 12:34:39 +0000164/*
165 * Those are preferences
166 */
167static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000168static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000169static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000170
171/*
172 * Hash table containing all the trees of XML catalogs parsed by
173 * the application.
174 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000175static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000176
177/*
178 * The default catalog in use by the application
179 */
180static xmlCatalogPtr xmlDefaultCatalog = NULL;
181
182/*
Daniel Veillard81463942001-10-16 12:34:39 +0000183 * A mutex for modifying the shared global catalog(s)
184 * xmlDefaultCatalog tree.
185 * It also protects xmlCatalogXMLFiles
186 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
187 */
188static xmlRMutexPtr xmlCatalogMutex = NULL;
189
190/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000191 * Whether the catalog support was initialized.
192 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000193static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000194
Daniel Veillard69d2c172003-10-09 11:46:07 +0000195/************************************************************************
196 * *
197 * Catalog error handlers *
198 * *
199 ************************************************************************/
200
201/**
202 * xmlCatalogErrMemory:
203 * @extra: extra informations
204 *
205 * Handle an out of memory condition
206 */
207static void
208xmlCatalogErrMemory(const char *extra)
209{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000210 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000211 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
212 extra, NULL, NULL, 0, 0,
213 "Memory allocation failed : %s\n", extra);
214}
215
216/**
217 * xmlCatalogErr:
218 * @catal: the Catalog entry
219 * @node: the context node
220 * @msg: the error message
221 * @extra: extra informations
222 *
223 * Handle a catalog error
224 */
225static void
226xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
227 const char *msg, const xmlChar *str1, const xmlChar *str2,
228 const xmlChar *str3)
229{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000230 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000231 error, XML_ERR_ERROR, NULL, 0,
232 (const char *) str1, (const char *) str2,
233 (const char *) str3, 0, 0,
234 msg, str1, str2, str3);
235}
236
Daniel Veillarda7374592001-05-10 14:17:55 +0000237
238/************************************************************************
239 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000240 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000241 * *
242 ************************************************************************/
243
Daniel Veillard75b96822001-10-11 18:59:45 +0000244/**
245 * xmlNewCatalogEntry:
246 * @type: type of entry
247 * @name: name of the entry
248 * @value: value of the entry
249 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +0000250 * @group: for members of a group, the group entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000251 *
252 * create a new Catalog entry, this type is shared both by XML and
253 * SGML catalogs, but the acceptable types values differs.
254 *
255 * Returns the xmlCatalogEntryPtr or NULL in case of error
256 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000257static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000258xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
William M. Brackb7b54de2004-10-06 16:38:01 +0000259 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
260 xmlCatalogEntryPtr group) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000261 xmlCatalogEntryPtr ret;
Daniel Veillardc8155052004-07-16 09:03:08 +0000262 xmlChar *normid = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000263
264 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
265 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000266 xmlCatalogErrMemory("allocating catalog entry");
Daniel Veillarda7374592001-05-10 14:17:55 +0000267 return(NULL);
268 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000269 ret->next = NULL;
270 ret->parent = NULL;
271 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000272 ret->type = type;
Daniel Veillardc8155052004-07-16 09:03:08 +0000273 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
274 normid = xmlCatalogNormalizePublic(name);
275 if (normid != NULL)
276 name = (*normid != 0 ? normid : NULL);
277 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000278 if (name != NULL)
279 ret->name = xmlStrdup(name);
280 else
281 ret->name = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +0000282 if (normid != NULL)
283 xmlFree(normid);
Daniel Veillard344cee72001-08-20 00:08:40 +0000284 if (value != NULL)
285 ret->value = xmlStrdup(value);
286 else
287 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000288 if (URL == NULL)
289 URL = value;
290 if (URL != NULL)
291 ret->URL = xmlStrdup(URL);
292 else
293 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000294 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000295 ret->dealloc = 0;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000296 ret->depth = 0;
William M. Brackb7b54de2004-10-06 16:38:01 +0000297 ret->group = group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000298 return(ret);
299}
300
301static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000302xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
303
Daniel Veillard75b96822001-10-11 18:59:45 +0000304/**
305 * xmlFreeCatalogEntry:
306 * @ret: a Catalog entry
307 *
308 * Free the memory allocated to a Catalog entry
309 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000310static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000311xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
312 if (ret == NULL)
313 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000314 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000315 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000316 * only by the file hash cleaner !
317 */
318 if (ret->dealloc == 1)
319 return;
320
321 if (xmlDebugCatalogs) {
322 if (ret->name != NULL)
323 xmlGenericError(xmlGenericErrorContext,
324 "Free catalog entry %s\n", ret->name);
325 else if (ret->value != NULL)
326 xmlGenericError(xmlGenericErrorContext,
327 "Free catalog entry %s\n", ret->value);
328 else
329 xmlGenericError(xmlGenericErrorContext,
330 "Free catalog entry\n");
331 }
332
Daniel Veillarda7374592001-05-10 14:17:55 +0000333 if (ret->name != NULL)
334 xmlFree(ret->name);
335 if (ret->value != NULL)
336 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000337 if (ret->URL != NULL)
338 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000339 xmlFree(ret);
340}
341
Daniel Veillard75b96822001-10-11 18:59:45 +0000342/**
343 * xmlFreeCatalogEntryList:
344 * @ret: a Catalog entry list
345 *
346 * Free the memory allocated to a full chained list of Catalog entries
347 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000348static void
349xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
350 xmlCatalogEntryPtr next;
351
352 while (ret != NULL) {
353 next = ret->next;
354 xmlFreeCatalogEntry(ret);
355 ret = next;
356 }
357}
358
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000359/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000360 * xmlFreeCatalogHashEntryList:
361 * @ret: a Catalog entry list
362 *
363 * Free the memory allocated to list of Catalog entries from the
364 * catalog file hash.
365 */
366static void
367xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
368 xmlCatalogEntryPtr children, next;
369
370 if (catal == NULL)
371 return;
372
373 children = catal->children;
374 while (children != NULL) {
375 next = children->next;
376 children->dealloc = 0;
377 children->children = NULL;
378 xmlFreeCatalogEntry(children);
379 children = next;
380 }
381 catal->dealloc = 0;
382 xmlFreeCatalogEntry(catal);
383}
384
385/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000386 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000387 * @type: type of catalog
388 * @prefer: the PUBLIC vs. SYSTEM current preference value
389 *
390 * create a new Catalog, this type is shared both by XML and
391 * SGML catalogs, but the acceptable types values differs.
392 *
393 * Returns the xmlCatalogPtr or NULL in case of error
394 */
395static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000396xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000397 xmlCatalogPtr ret;
398
399 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
400 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000401 xmlCatalogErrMemory("allocating catalog");
Daniel Veillard75b96822001-10-11 18:59:45 +0000402 return(NULL);
403 }
404 memset(ret, 0, sizeof(xmlCatalog));
405 ret->type = type;
406 ret->catalNr = 0;
407 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
408 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000409 if (ret->type == XML_SGML_CATALOG_TYPE)
410 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000411 return(ret);
412}
413
414/**
415 * xmlFreeCatalog:
Daniel Veillard06d25242004-02-25 13:01:42 +0000416 * @catal: a Catalog
Daniel Veillard75b96822001-10-11 18:59:45 +0000417 *
418 * Free the memory allocated to a Catalog
419 */
420void
421xmlFreeCatalog(xmlCatalogPtr catal) {
422 if (catal == NULL)
423 return;
424 if (catal->xml != NULL)
425 xmlFreeCatalogEntryList(catal->xml);
426 if (catal->sgml != NULL)
427 xmlHashFree(catal->sgml,
428 (xmlHashDeallocator) xmlFreeCatalogEntry);
429 xmlFree(catal);
430}
431
432/************************************************************************
433 * *
434 * Serializing Catalogs *
435 * *
436 ************************************************************************/
437
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000438#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000439/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000440 * xmlCatalogDumpEntry:
Daniel Veillard06d25242004-02-25 13:01:42 +0000441 * @entry: the catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000442 * @out: the file.
443 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000444 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000445 */
446static void
447xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
448 if ((entry == NULL) || (out == NULL))
449 return;
450 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000451 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000452 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000453 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000454 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000455 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000456 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000457 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000458 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000459 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000460 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000461 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000462 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000463 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000464 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000465 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000466 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000467 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000468 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000469 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000470 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000471 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000472 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000473 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000474 fprintf(out, "SGMLDECL "); break;
475 default:
476 return;
477 }
478 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000479 case SGML_CATA_ENTITY:
480 case SGML_CATA_PENTITY:
481 case SGML_CATA_DOCTYPE:
482 case SGML_CATA_LINKTYPE:
483 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000484 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000485 case SGML_CATA_PUBLIC:
486 case SGML_CATA_SYSTEM:
487 case SGML_CATA_SGMLDECL:
488 case SGML_CATA_DOCUMENT:
489 case SGML_CATA_CATALOG:
490 case SGML_CATA_BASE:
491 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000492 fprintf(out, "\"%s\"", entry->name); break;
493 default:
494 break;
495 }
496 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000497 case SGML_CATA_ENTITY:
498 case SGML_CATA_PENTITY:
499 case SGML_CATA_DOCTYPE:
500 case SGML_CATA_LINKTYPE:
501 case SGML_CATA_NOTATION:
502 case SGML_CATA_PUBLIC:
503 case SGML_CATA_SYSTEM:
504 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000505 fprintf(out, " \"%s\"", entry->value); break;
506 default:
507 break;
508 }
509 fprintf(out, "\n");
510}
511
William M. Brackb7b54de2004-10-06 16:38:01 +0000512/**
513 * xmlDumpXMLCatalogNode:
514 * @catal: top catalog entry
515 * @catalog: pointer to the xml tree
516 * @doc: the containing document
517 * @ns: the current namespace
518 * @cgroup: group node for group members
519 *
520 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
521 * for group entries
522 */
523static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
524 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
525 xmlNodePtr node;
526 xmlCatalogEntryPtr cur;
527 /*
528 * add all the catalog entries
529 */
530 cur = catal;
531 while (cur != NULL) {
532 if (cur->group == cgroup) {
533 switch (cur->type) {
534 case XML_CATA_REMOVED:
535 break;
536 case XML_CATA_BROKEN_CATALOG:
537 case XML_CATA_CATALOG:
538 if (cur == catal) {
539 cur = cur->children;
540 continue;
541 }
542 break;
543 case XML_CATA_NEXT_CATALOG:
544 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
545 xmlSetProp(node, BAD_CAST "catalog", cur->value);
546 xmlAddChild(catalog, node);
547 break;
548 case XML_CATA_NONE:
549 break;
550 case XML_CATA_GROUP:
551 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
552 xmlSetProp(node, BAD_CAST "id", cur->name);
553 if (cur->value != NULL)
554 xmlSetProp(node, BAD_CAST "uri", cur->value);
555 switch (cur->prefer) {
556 case XML_CATA_PREFER_NONE:
557 break;
558 case XML_CATA_PREFER_PUBLIC:
559 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
560 break;
561 case XML_CATA_PREFER_SYSTEM:
562 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
563 break;
564 }
565 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
566 xmlAddChild(catalog, node);
567 break;
568 case XML_CATA_PUBLIC:
569 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
570 xmlSetProp(node, BAD_CAST "publicId", cur->name);
571 xmlSetProp(node, BAD_CAST "uri", cur->value);
572 xmlAddChild(catalog, node);
573 break;
574 case XML_CATA_SYSTEM:
575 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
576 xmlSetProp(node, BAD_CAST "systemId", cur->name);
577 xmlSetProp(node, BAD_CAST "uri", cur->value);
578 xmlAddChild(catalog, node);
579 break;
580 case XML_CATA_REWRITE_SYSTEM:
581 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
582 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
583 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
584 xmlAddChild(catalog, node);
585 break;
586 case XML_CATA_DELEGATE_PUBLIC:
587 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
588 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
589 xmlSetProp(node, BAD_CAST "catalog", cur->value);
590 xmlAddChild(catalog, node);
591 break;
592 case XML_CATA_DELEGATE_SYSTEM:
593 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
594 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
595 xmlSetProp(node, BAD_CAST "catalog", cur->value);
596 xmlAddChild(catalog, node);
597 break;
598 case XML_CATA_URI:
599 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
600 xmlSetProp(node, BAD_CAST "name", cur->name);
601 xmlSetProp(node, BAD_CAST "uri", cur->value);
602 xmlAddChild(catalog, node);
603 break;
604 case XML_CATA_REWRITE_URI:
605 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
606 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
607 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
608 xmlAddChild(catalog, node);
609 break;
610 case XML_CATA_DELEGATE_URI:
611 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
612 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
613 xmlSetProp(node, BAD_CAST "catalog", cur->value);
614 xmlAddChild(catalog, node);
615 break;
616 case SGML_CATA_SYSTEM:
617 case SGML_CATA_PUBLIC:
618 case SGML_CATA_ENTITY:
619 case SGML_CATA_PENTITY:
620 case SGML_CATA_DOCTYPE:
621 case SGML_CATA_LINKTYPE:
622 case SGML_CATA_NOTATION:
623 case SGML_CATA_DELEGATE:
624 case SGML_CATA_BASE:
625 case SGML_CATA_CATALOG:
626 case SGML_CATA_DOCUMENT:
627 case SGML_CATA_SGMLDECL:
628 break;
629 }
630 }
631 cur = cur->next;
632 }
633}
634
Daniel Veillard75b96822001-10-11 18:59:45 +0000635static int
636xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
637 int ret;
638 xmlDocPtr doc;
639 xmlNsPtr ns;
640 xmlDtdPtr dtd;
William M. Brackb7b54de2004-10-06 16:38:01 +0000641 xmlNodePtr catalog;
Daniel Veillard75b96822001-10-11 18:59:45 +0000642 xmlOutputBufferPtr buf;
Daniel Veillard75b96822001-10-11 18:59:45 +0000643
644 /*
645 * Rebuild a catalog
646 */
647 doc = xmlNewDoc(NULL);
648 if (doc == NULL)
649 return(-1);
650 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
651 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
652BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
653
654 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
655
656 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
657 if (ns == NULL) {
658 xmlFreeDoc(doc);
659 return(-1);
660 }
661 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
662 if (catalog == NULL) {
663 xmlFreeNs(ns);
664 xmlFreeDoc(doc);
665 return(-1);
666 }
667 catalog->nsDef = ns;
668 xmlAddChild((xmlNodePtr) doc, catalog);
669
William M. Brackb7b54de2004-10-06 16:38:01 +0000670 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
671
Daniel Veillard75b96822001-10-11 18:59:45 +0000672 /*
673 * reserialize it
674 */
675 buf = xmlOutputBufferCreateFile(out, NULL);
676 if (buf == NULL) {
677 xmlFreeDoc(doc);
678 return(-1);
679 }
680 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
681
682 /*
683 * Free it
684 */
685 xmlFreeDoc(doc);
686
687 return(ret);
688}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000689#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000690
691/************************************************************************
692 * *
693 * Converting SGML Catalogs to XML *
694 * *
695 ************************************************************************/
696
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000697/**
698 * xmlCatalogConvertEntry:
699 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000700 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000701 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000702 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000703 */
704static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000705xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
706 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
707 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000708 return;
709 switch (entry->type) {
710 case SGML_CATA_ENTITY:
711 entry->type = XML_CATA_PUBLIC;
712 break;
713 case SGML_CATA_PENTITY:
714 entry->type = XML_CATA_PUBLIC;
715 break;
716 case SGML_CATA_DOCTYPE:
717 entry->type = XML_CATA_PUBLIC;
718 break;
719 case SGML_CATA_LINKTYPE:
720 entry->type = XML_CATA_PUBLIC;
721 break;
722 case SGML_CATA_NOTATION:
723 entry->type = XML_CATA_PUBLIC;
724 break;
725 case SGML_CATA_PUBLIC:
726 entry->type = XML_CATA_PUBLIC;
727 break;
728 case SGML_CATA_SYSTEM:
729 entry->type = XML_CATA_SYSTEM;
730 break;
731 case SGML_CATA_DELEGATE:
732 entry->type = XML_CATA_DELEGATE_PUBLIC;
733 break;
734 case SGML_CATA_CATALOG:
735 entry->type = XML_CATA_CATALOG;
736 break;
737 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000738 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000739 (xmlHashDeallocator) xmlFreeCatalogEntry);
740 return;
741 }
742 /*
743 * Conversion successful, remove from the SGML catalog
744 * and add it to the default XML one
745 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000746 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
747 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000748 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000749 if (catal->xml->children == NULL)
750 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000751 else {
752 xmlCatalogEntryPtr prev;
753
Daniel Veillard75b96822001-10-11 18:59:45 +0000754 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000755 while (prev->next != NULL)
756 prev = prev->next;
757 prev->next = entry;
758 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000759}
760
761/**
762 * xmlConvertSGMLCatalog:
763 * @catal: the catalog
764 *
765 * Convert all the SGML catalog entries as XML ones
766 *
767 * Returns the number of entries converted if successful, -1 otherwise
768 */
769int
770xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
771
772 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
773 return(-1);
774
775 if (xmlDebugCatalogs) {
776 xmlGenericError(xmlGenericErrorContext,
777 "Converting SGML catalog to XML\n");
778 }
779 xmlHashScan(catal->sgml,
780 (xmlHashScanner) xmlCatalogConvertEntry,
781 &catal);
782 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000783}
784
Daniel Veillarda7374592001-05-10 14:17:55 +0000785/************************************************************************
786 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000787 * Helper function *
788 * *
789 ************************************************************************/
790
791/**
792 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000793 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000794 *
795 * Expand the URN into the equivalent Public Identifier
796 *
797 * Returns the new identifier or NULL, the string must be deallocated
798 * by the caller.
799 */
800static xmlChar *
801xmlCatalogUnWrapURN(const xmlChar *urn) {
802 xmlChar result[2000];
803 unsigned int i = 0;
804
805 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
806 return(NULL);
807 urn += sizeof(XML_URN_PUBID) - 1;
808
809 while (*urn != 0) {
Daniel Veillard770075b2004-02-25 10:44:30 +0000810 if (i > sizeof(result) - 4)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000811 break;
812 if (*urn == '+') {
813 result[i++] = ' ';
814 urn++;
815 } else if (*urn == ':') {
816 result[i++] = '/';
817 result[i++] = '/';
818 urn++;
819 } else if (*urn == ';') {
820 result[i++] = ':';
821 result[i++] = ':';
822 urn++;
823 } else if (*urn == '%') {
Daniel Veillard770075b2004-02-25 10:44:30 +0000824 if ((urn[1] == '2') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000825 result[i++] = '+';
Daniel Veillard770075b2004-02-25 10:44:30 +0000826 else if ((urn[1] == '3') && (urn[2] == 'A'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000827 result[i++] = ':';
Daniel Veillard770075b2004-02-25 10:44:30 +0000828 else if ((urn[1] == '2') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000829 result[i++] = '/';
Daniel Veillard770075b2004-02-25 10:44:30 +0000830 else if ((urn[1] == '3') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000831 result[i++] = ';';
Daniel Veillard770075b2004-02-25 10:44:30 +0000832 else if ((urn[1] == '2') && (urn[2] == '7'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000833 result[i++] = '\'';
Daniel Veillard770075b2004-02-25 10:44:30 +0000834 else if ((urn[1] == '3') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000835 result[i++] = '?';
Daniel Veillard770075b2004-02-25 10:44:30 +0000836 else if ((urn[1] == '2') && (urn[2] == '3'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000837 result[i++] = '#';
Daniel Veillard770075b2004-02-25 10:44:30 +0000838 else if ((urn[1] == '2') && (urn[2] == '5'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000839 result[i++] = '%';
840 else {
841 result[i++] = *urn;
842 urn++;
843 continue;
844 }
845 urn += 3;
846 } else {
847 result[i++] = *urn;
848 urn++;
849 }
850 }
851 result[i] = 0;
852
853 return(xmlStrdup(result));
854}
855
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000856/**
857 * xmlParseCatalogFile:
858 * @filename: the filename
859 *
860 * parse an XML file and build a tree. It's like xmlParseFile()
861 * except it bypass all catalog lookups.
862 *
863 * Returns the resulting document tree or NULL in case of error
864 */
865
866xmlDocPtr
867xmlParseCatalogFile(const char *filename) {
868 xmlDocPtr ret;
869 xmlParserCtxtPtr ctxt;
870 char *directory = NULL;
871 xmlParserInputPtr inputStream;
872 xmlParserInputBufferPtr buf;
873
874 ctxt = xmlNewParserCtxt();
875 if (ctxt == NULL) {
876 if (xmlDefaultSAXHandler.error != NULL) {
877 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
878 }
879 return(NULL);
880 }
881
882 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
883 if (buf == NULL) {
884 xmlFreeParserCtxt(ctxt);
885 return(NULL);
886 }
887
888 inputStream = xmlNewInputStream(ctxt);
889 if (inputStream == NULL) {
890 xmlFreeParserCtxt(ctxt);
891 return(NULL);
892 }
893
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000894 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000895 inputStream->buf = buf;
896 inputStream->base = inputStream->buf->buffer->content;
897 inputStream->cur = inputStream->buf->buffer->content;
898 inputStream->end =
899 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
900
901 inputPush(ctxt, inputStream);
902 if ((ctxt->directory == NULL) && (directory == NULL))
903 directory = xmlParserGetDirectory(filename);
904 if ((ctxt->directory == NULL) && (directory != NULL))
905 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000906 ctxt->valid = 0;
907 ctxt->validate = 0;
908 ctxt->loadsubset = 0;
909 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000910
911 xmlParseDocument(ctxt);
912
913 if (ctxt->wellFormed)
914 ret = ctxt->myDoc;
915 else {
916 ret = NULL;
917 xmlFreeDoc(ctxt->myDoc);
918 ctxt->myDoc = NULL;
919 }
920 xmlFreeParserCtxt(ctxt);
921
922 return(ret);
923}
924
Daniel Veillard75b96822001-10-11 18:59:45 +0000925/**
926 * xmlLoadFileContent:
927 * @filename: a file path
928 *
929 * Load a file content into memory.
930 *
931 * Returns a pointer to the 0 terminated string or NULL in case of error
932 */
933static xmlChar *
934xmlLoadFileContent(const char *filename)
935{
936#ifdef HAVE_STAT
937 int fd;
938#else
939 FILE *fd;
940#endif
941 int len;
942 long size;
943
944#ifdef HAVE_STAT
945 struct stat info;
946#endif
947 xmlChar *content;
948
949 if (filename == NULL)
950 return (NULL);
951
952#ifdef HAVE_STAT
953 if (stat(filename, &info) < 0)
954 return (NULL);
955#endif
956
957#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000958 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000959#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000960 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000961#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000962 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000963 return (NULL);
964 }
965#ifdef HAVE_STAT
966 size = info.st_size;
967#else
968 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
969 fclose(fd);
970 return (NULL);
971 }
972#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000973 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000974 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000975 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard75b96822001-10-11 18:59:45 +0000976 return (NULL);
977 }
978#ifdef HAVE_STAT
979 len = read(fd, content, size);
980#else
981 len = fread(content, 1, size, fd);
982#endif
983 if (len < 0) {
984 xmlFree(content);
985 return (NULL);
986 }
987#ifdef HAVE_STAT
988 close(fd);
989#else
990 fclose(fd);
991#endif
992 content[len] = 0;
993
994 return(content);
995}
996
Daniel Veillardc8155052004-07-16 09:03:08 +0000997/**
998 * xmlCatalogNormalizePublic:
999 * @pubID: the public ID string
1000 *
1001 * Normalizes the Public Identifier
1002 *
1003 * Implements 6.2. Public Identifier Normalization
1004 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1005 *
1006 * Returns the new string or NULL, the string must be deallocated
1007 * by the caller.
1008 */
1009static xmlChar *
1010xmlCatalogNormalizePublic(const xmlChar *pubID)
1011{
1012 int ok = 1;
1013 int white;
1014 const xmlChar *p;
1015 xmlChar *ret;
1016 xmlChar *q;
1017
1018 if (pubID == NULL)
1019 return(NULL);
1020
1021 white = 1;
1022 for (p = pubID;*p != 0 && ok;p++) {
1023 if (!xmlIsBlank_ch(*p))
1024 white = 0;
1025 else if (*p == 0x20 && !white)
1026 white = 1;
1027 else
1028 ok = 0;
1029 }
1030 if (ok && !white) /* is normalized */
1031 return(NULL);
1032
1033 ret = xmlStrdup(pubID);
1034 q = ret;
1035 white = 0;
1036 for (p = pubID;*p != 0;p++) {
1037 if (xmlIsBlank_ch(*p)) {
1038 if (q != ret)
1039 white = 1;
1040 } else {
1041 if (white) {
1042 *(q++) = 0x20;
1043 white = 0;
1044 }
1045 *(q++) = *p;
1046 }
1047 }
1048 *q = 0;
1049 return(ret);
1050}
1051
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001052/************************************************************************
1053 * *
Daniel Veillard344cee72001-08-20 00:08:40 +00001054 * The XML Catalog parser *
1055 * *
1056 ************************************************************************/
1057
1058static xmlCatalogEntryPtr
1059xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001060static void
1061xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001062 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
Daniel Veillardcda96922001-08-21 10:56:31 +00001063static xmlChar *
1064xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1065 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001066static xmlChar *
1067xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1068
Daniel Veillard344cee72001-08-20 00:08:40 +00001069
Daniel Veillard75b96822001-10-11 18:59:45 +00001070/**
1071 * xmlGetXMLCatalogEntryType:
1072 * @name: the name
1073 *
1074 * lookup the internal type associated to an XML catalog entry name
1075 *
Daniel Veillard06d25242004-02-25 13:01:42 +00001076 * Returns the type associated with that name
Daniel Veillard75b96822001-10-11 18:59:45 +00001077 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001078static xmlCatalogEntryType
1079xmlGetXMLCatalogEntryType(const xmlChar *name) {
1080 xmlCatalogEntryType type = XML_CATA_NONE;
1081 if (xmlStrEqual(name, (const xmlChar *) "system"))
1082 type = XML_CATA_SYSTEM;
1083 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1084 type = XML_CATA_PUBLIC;
1085 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1086 type = XML_CATA_REWRITE_SYSTEM;
1087 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1088 type = XML_CATA_DELEGATE_PUBLIC;
1089 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1090 type = XML_CATA_DELEGATE_SYSTEM;
1091 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1092 type = XML_CATA_URI;
1093 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1094 type = XML_CATA_REWRITE_URI;
1095 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1096 type = XML_CATA_DELEGATE_URI;
1097 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1098 type = XML_CATA_NEXT_CATALOG;
1099 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1100 type = XML_CATA_CATALOG;
1101 return(type);
1102}
1103
Daniel Veillard75b96822001-10-11 18:59:45 +00001104/**
1105 * xmlParseXMLCatalogOneNode:
1106 * @cur: the XML node
1107 * @type: the type of Catalog entry
1108 * @name: the name of the node
1109 * @attrName: the attribute holding the value
1110 * @uriAttrName: the attribute holding the URI-Reference
1111 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +00001112 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001113 *
1114 * Finishes the examination of an XML tree node of a catalog and build
1115 * a Catalog entry from it.
1116 *
1117 * Returns the new Catalog entry node or NULL in case of error.
1118 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001119static xmlCatalogEntryPtr
1120xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1121 const xmlChar *name, const xmlChar *attrName,
William M. Brackb7b54de2004-10-06 16:38:01 +00001122 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1123 xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001124 int ok = 1;
1125 xmlChar *uriValue;
1126 xmlChar *nameValue = NULL;
1127 xmlChar *base = NULL;
1128 xmlChar *URL = NULL;
1129 xmlCatalogEntryPtr ret = NULL;
1130
1131 if (attrName != NULL) {
1132 nameValue = xmlGetProp(cur, attrName);
1133 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001134 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1135 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001136 ok = 0;
1137 }
1138 }
1139 uriValue = xmlGetProp(cur, uriAttrName);
1140 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001141 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1142 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001143 ok = 0;
1144 }
1145 if (!ok) {
1146 if (nameValue != NULL)
1147 xmlFree(nameValue);
1148 if (uriValue != NULL)
1149 xmlFree(uriValue);
1150 return(NULL);
1151 }
1152
1153 base = xmlNodeGetBase(cur->doc, cur);
1154 URL = xmlBuildURI(uriValue, base);
1155 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001156 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001157 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001158 xmlGenericError(xmlGenericErrorContext,
1159 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001160 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001161 xmlGenericError(xmlGenericErrorContext,
1162 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001163 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001164 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001165 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001166 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001167 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1168 }
1169 if (nameValue != NULL)
1170 xmlFree(nameValue);
1171 if (uriValue != NULL)
1172 xmlFree(uriValue);
1173 if (base != NULL)
1174 xmlFree(base);
1175 if (URL != NULL)
1176 xmlFree(URL);
1177 return(ret);
1178}
1179
Daniel Veillard75b96822001-10-11 18:59:45 +00001180/**
1181 * xmlParseXMLCatalogNode:
1182 * @cur: the XML node
1183 * @prefer: the PUBLIC vs. SYSTEM current preference value
1184 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001185 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001186 *
1187 * Examines an XML tree node of a catalog and build
1188 * a Catalog entry from it adding it to its parent. The examination can
1189 * be recursive.
1190 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001191static void
1192xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001193 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
Daniel Veillard344cee72001-08-20 00:08:40 +00001194{
1195 xmlChar *uri = NULL;
1196 xmlChar *URL = NULL;
1197 xmlChar *base = NULL;
1198 xmlCatalogEntryPtr entry = NULL;
1199
1200 if (cur == NULL)
1201 return;
1202 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1203 xmlChar *prop;
William M. Brackb7b54de2004-10-06 16:38:01 +00001204 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
Daniel Veillard344cee72001-08-20 00:08:40 +00001205
1206 prop = xmlGetProp(cur, BAD_CAST "prefer");
1207 if (prop != NULL) {
1208 if (xmlStrEqual(prop, BAD_CAST "system")) {
1209 prefer = XML_CATA_PREFER_SYSTEM;
1210 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1211 prefer = XML_CATA_PREFER_PUBLIC;
1212 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001213 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1214 "Invalid value for prefer: '%s'\n",
1215 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001216 }
1217 xmlFree(prop);
William M. Brackb7b54de2004-10-06 16:38:01 +00001218 pref = prefer;
Daniel Veillard344cee72001-08-20 00:08:40 +00001219 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001220 prop = xmlGetProp(cur, BAD_CAST "id");
1221 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1222 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001223 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1224 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
William M. Brackb7b54de2004-10-06 16:38:01 +00001225 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001226 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1227 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
William M. Brackb7b54de2004-10-06 16:38:01 +00001228 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001229 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1230 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1231 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001232 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001233 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1234 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1235 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001236 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001237 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1238 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1239 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001240 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001241 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1242 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1243 BAD_CAST "uri", BAD_CAST "name",
William M. Brackb7b54de2004-10-06 16:38:01 +00001244 BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001245 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1246 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1247 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001248 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001249 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1250 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1251 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001252 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001253 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1254 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1255 BAD_CAST "nextCatalog", NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001256 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001257 }
1258 if ((entry != NULL) && (parent != NULL)) {
1259 entry->parent = parent;
1260 if (parent->children == NULL)
1261 parent->children = entry;
1262 else {
1263 xmlCatalogEntryPtr prev;
1264
1265 prev = parent->children;
1266 while (prev->next != NULL)
1267 prev = prev->next;
1268 prev->next = entry;
1269 }
1270 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001271 if (entry->type == XML_CATA_GROUP) {
1272 /*
1273 * Recurse to propagate prefer to the subtree
1274 * (xml:base handling is automated)
1275 */
1276 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1277 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001278 if (base != NULL)
1279 xmlFree(base);
1280 if (uri != NULL)
1281 xmlFree(uri);
1282 if (URL != NULL)
1283 xmlFree(URL);
1284}
1285
Daniel Veillard75b96822001-10-11 18:59:45 +00001286/**
1287 * xmlParseXMLCatalogNodeList:
1288 * @cur: the XML node list of siblings
1289 * @prefer: the PUBLIC vs. SYSTEM current preference value
1290 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001291 * @cgroup: the group which includes this list
Daniel Veillard75b96822001-10-11 18:59:45 +00001292 *
1293 * Examines a list of XML sibling nodes of a catalog and build
1294 * a list of Catalog entry from it adding it to the parent.
1295 * The examination will recurse to examine node subtrees.
1296 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001297static void
1298xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001299 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001300 while (cur != NULL) {
1301 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1302 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
William M. Brackb7b54de2004-10-06 16:38:01 +00001303 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001304 }
1305 cur = cur->next;
1306 }
1307 /* TODO: sort the list according to REWRITE lengths and prefer value */
1308}
1309
Daniel Veillard75b96822001-10-11 18:59:45 +00001310/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001311 * xmlParseXMLCatalogFile:
1312 * @prefer: the PUBLIC vs. SYSTEM current preference value
1313 * @filename: the filename for the catalog
1314 *
1315 * Parses the catalog file to extract the XML tree and then analyze the
1316 * tree to build a list of Catalog entries corresponding to this catalog
1317 *
1318 * Returns the resulting Catalog entries list
1319 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001320static xmlCatalogEntryPtr
1321xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1322 xmlDocPtr doc;
1323 xmlNodePtr cur;
1324 xmlChar *prop;
1325 xmlCatalogEntryPtr parent = NULL;
1326
1327 if (filename == NULL)
1328 return(NULL);
1329
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001330 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001331 if (doc == NULL) {
1332 if (xmlDebugCatalogs)
1333 xmlGenericError(xmlGenericErrorContext,
1334 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001335 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001336 }
1337
1338 if (xmlDebugCatalogs)
1339 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001340 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001341
1342 cur = xmlDocGetRootElement(doc);
1343 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1344 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1345 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1346
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001347 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001348 (const xmlChar *)filename, NULL, prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001349 if (parent == NULL) {
1350 xmlFreeDoc(doc);
1351 return(NULL);
1352 }
1353
1354 prop = xmlGetProp(cur, BAD_CAST "prefer");
1355 if (prop != NULL) {
1356 if (xmlStrEqual(prop, BAD_CAST "system")) {
1357 prefer = XML_CATA_PREFER_SYSTEM;
1358 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1359 prefer = XML_CATA_PREFER_PUBLIC;
1360 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001361 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1362 "Invalid value for prefer: '%s'\n",
1363 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001364 }
1365 xmlFree(prop);
1366 }
1367 cur = cur->children;
William M. Brackb7b54de2004-10-06 16:38:01 +00001368 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001369 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001370 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1371 "File %s is not an XML Catalog\n",
1372 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001373 xmlFreeDoc(doc);
1374 return(NULL);
1375 }
1376 xmlFreeDoc(doc);
1377 return(parent);
1378}
1379
Daniel Veillardcda96922001-08-21 10:56:31 +00001380/**
1381 * xmlFetchXMLCatalogFile:
1382 * @catal: an existing but incomplete catalog entry
1383 *
1384 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001385 *
1386 * Returns 0 in case of success, -1 otherwise
1387 */
1388static int
1389xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001390 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001391
1392 if (catal == NULL)
1393 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001394 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001395 return(-1);
1396 if (catal->children != NULL)
1397 return(-1);
1398
Daniel Veillard81463942001-10-16 12:34:39 +00001399 /*
1400 * lock the whole catalog for modification
1401 */
1402 xmlRMutexLock(xmlCatalogMutex);
1403 if (catal->children != NULL) {
1404 /* Okay someone else did it in the meantime */
1405 xmlRMutexUnlock(xmlCatalogMutex);
1406 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001407 }
1408
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001409 if (xmlCatalogXMLFiles != NULL) {
1410 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001411 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001412 if (doc != NULL) {
1413 if (xmlDebugCatalogs)
1414 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001415 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001416
1417 if (catal->type == XML_CATA_CATALOG)
1418 catal->children = doc->children;
1419 else
1420 catal->children = doc;
1421 catal->dealloc = 0;
1422 xmlRMutexUnlock(xmlCatalogMutex);
1423 return(0);
1424 }
1425 if (xmlDebugCatalogs)
1426 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001427 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001428 }
1429
Daniel Veillardcda96922001-08-21 10:56:31 +00001430 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001431 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001432 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001433 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001434 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001435 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001436 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001437 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001438 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001439 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001440 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001441
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001442 if (catal->type == XML_CATA_CATALOG)
1443 catal->children = doc->children;
1444 else
1445 catal->children = doc;
1446
1447 doc->dealloc = 1;
1448
Daniel Veillard81463942001-10-16 12:34:39 +00001449 if (xmlCatalogXMLFiles == NULL)
1450 xmlCatalogXMLFiles = xmlHashCreate(10);
1451 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001452 if (xmlDebugCatalogs)
1453 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001454 "%s added to file hash\n", catal->URL);
1455 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001456 }
Daniel Veillard81463942001-10-16 12:34:39 +00001457 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001458 return(0);
1459}
1460
Daniel Veillard75b96822001-10-11 18:59:45 +00001461/************************************************************************
1462 * *
1463 * XML Catalog handling *
1464 * *
1465 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001466
1467/**
1468 * xmlAddXMLCatalog:
1469 * @catal: top of an XML catalog
1470 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001471 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001472 * @replace: the replacement value for the match
1473 *
1474 * Add an entry in the XML catalog, it may overwrite existing but
1475 * different entries.
1476 *
1477 * Returns 0 if successful, -1 otherwise
1478 */
1479static int
1480xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1481 const xmlChar *orig, const xmlChar *replace) {
1482 xmlCatalogEntryPtr cur;
1483 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001484 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001485
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001486 if ((catal == NULL) ||
1487 ((catal->type != XML_CATA_CATALOG) &&
1488 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001489 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001490 if (catal->children == NULL) {
1491 xmlFetchXMLCatalogFile(catal);
1492 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001493 if (catal->children == NULL)
1494 doregister = 1;
1495
Daniel Veillard344cee72001-08-20 00:08:40 +00001496 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001497 if (typ == XML_CATA_NONE) {
1498 if (xmlDebugCatalogs)
1499 xmlGenericError(xmlGenericErrorContext,
1500 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001501 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001502 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001503
1504 cur = catal->children;
1505 /*
1506 * Might be a simple "update in place"
1507 */
1508 if (cur != NULL) {
1509 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001510 if ((orig != NULL) && (cur->type == typ) &&
1511 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001512 if (xmlDebugCatalogs)
1513 xmlGenericError(xmlGenericErrorContext,
1514 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001515 if (cur->value != NULL)
1516 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001517 if (cur->URL != NULL)
1518 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001519 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001520 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001521 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001522 }
1523 if (cur->next == NULL)
1524 break;
1525 cur = cur->next;
1526 }
1527 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001528 if (xmlDebugCatalogs)
1529 xmlGenericError(xmlGenericErrorContext,
1530 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001531 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001532 catal->children = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001533 NULL, catal->prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001534 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001535 cur->next = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001536 NULL, catal->prefer, NULL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001537 if (doregister) {
1538 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1539 if (cur != NULL)
1540 cur->children = catal->children;
1541 }
1542
Daniel Veillardcda96922001-08-21 10:56:31 +00001543 return(0);
1544}
1545
1546/**
1547 * xmlDelXMLCatalog:
1548 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001549 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001550 *
1551 * Remove entries in the XML catalog where the value or the URI
1552 * is equal to @value
1553 *
1554 * Returns the number of entries removed if successful, -1 otherwise
1555 */
1556static int
1557xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001558 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001559 int ret = 0;
1560
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001561 if ((catal == NULL) ||
1562 ((catal->type != XML_CATA_CATALOG) &&
1563 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001564 return(-1);
1565 if (value == NULL)
1566 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001567 if (catal->children == NULL) {
1568 xmlFetchXMLCatalogFile(catal);
1569 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001570
1571 /*
1572 * Scan the children
1573 */
1574 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001575 while (cur != NULL) {
1576 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1577 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001578 if (xmlDebugCatalogs) {
1579 if (cur->name != NULL)
1580 xmlGenericError(xmlGenericErrorContext,
1581 "Removing element %s from catalog\n", cur->name);
1582 else
1583 xmlGenericError(xmlGenericErrorContext,
1584 "Removing element %s from catalog\n", cur->value);
1585 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001586 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001587 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001588 cur = cur->next;
1589 }
1590 return(ret);
1591}
1592
1593/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001594 * xmlCatalogXMLResolve:
1595 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001596 * @pubID: the public ID string
1597 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001598 *
1599 * Do a complete resolution lookup of an External Identifier for a
1600 * list of catalog entries.
1601 *
1602 * Implements (or tries to) 7.1. External Identifier Resolution
1603 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1604 *
1605 * Returns the URI of the resource or NULL if not found
1606 */
1607static xmlChar *
1608xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1609 const xmlChar *sysID) {
1610 xmlChar *ret = NULL;
1611 xmlCatalogEntryPtr cur;
1612 int haveDelegate = 0;
1613 int haveNext = 0;
1614
1615 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001616 * protection against loops
1617 */
1618 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001619 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1620 "Detected recursion in catalog %s\n",
1621 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001622 return(NULL);
1623 }
1624 catal->depth++;
1625
1626 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001627 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1628 */
1629 if (sysID != NULL) {
1630 xmlCatalogEntryPtr rewrite = NULL;
1631 int lenrewrite = 0, len;
1632 cur = catal;
1633 haveDelegate = 0;
1634 while (cur != NULL) {
1635 switch (cur->type) {
1636 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001637 if (xmlStrEqual(sysID, cur->name)) {
1638 if (xmlDebugCatalogs)
1639 xmlGenericError(xmlGenericErrorContext,
1640 "Found system match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001641 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001642 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001643 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001644 break;
1645 case XML_CATA_REWRITE_SYSTEM:
1646 len = xmlStrlen(cur->name);
1647 if ((len > lenrewrite) &&
1648 (!xmlStrncmp(sysID, cur->name, len))) {
1649 lenrewrite = len;
1650 rewrite = cur;
1651 }
1652 break;
1653 case XML_CATA_DELEGATE_SYSTEM:
1654 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1655 haveDelegate++;
1656 break;
1657 case XML_CATA_NEXT_CATALOG:
1658 haveNext++;
1659 break;
1660 default:
1661 break;
1662 }
1663 cur = cur->next;
1664 }
1665 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001666 if (xmlDebugCatalogs)
1667 xmlGenericError(xmlGenericErrorContext,
1668 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001669 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001670 if (ret != NULL)
1671 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001672 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001673 return(ret);
1674 }
1675 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001676 const xmlChar *delegates[MAX_DELEGATE];
1677 int nbList = 0, i;
1678
Daniel Veillardcda96922001-08-21 10:56:31 +00001679 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001680 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001681 * matches when the list was produced.
1682 */
1683 cur = catal;
1684 while (cur != NULL) {
1685 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1686 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001687 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001688 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001689 break;
1690 if (i < nbList) {
1691 cur = cur->next;
1692 continue;
1693 }
1694 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001695 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001696
Daniel Veillardcda96922001-08-21 10:56:31 +00001697 if (cur->children == NULL) {
1698 xmlFetchXMLCatalogFile(cur);
1699 }
1700 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001701 if (xmlDebugCatalogs)
1702 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001703 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001704 ret = xmlCatalogListXMLResolve(
1705 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001706 if (ret != NULL) {
1707 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001708 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001709 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001710 }
1711 }
1712 cur = cur->next;
1713 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001714 /*
1715 * Apply the cut algorithm explained in 4/
1716 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001717 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001718 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001719 }
1720 }
1721 /*
1722 * Then tries 5/ 6/ if a public ID is provided
1723 */
1724 if (pubID != NULL) {
1725 cur = catal;
1726 haveDelegate = 0;
1727 while (cur != NULL) {
1728 switch (cur->type) {
1729 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001730 if (xmlStrEqual(pubID, cur->name)) {
1731 if (xmlDebugCatalogs)
1732 xmlGenericError(xmlGenericErrorContext,
1733 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001734 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001735 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001736 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001737 break;
1738 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001739 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1740 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001741 haveDelegate++;
1742 break;
1743 case XML_CATA_NEXT_CATALOG:
1744 if (sysID == NULL)
1745 haveNext++;
1746 break;
1747 default:
1748 break;
1749 }
1750 cur = cur->next;
1751 }
1752 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001753 const xmlChar *delegates[MAX_DELEGATE];
1754 int nbList = 0, i;
1755
Daniel Veillardcda96922001-08-21 10:56:31 +00001756 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001757 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001758 * matches when the list was produced.
1759 */
1760 cur = catal;
1761 while (cur != NULL) {
1762 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001763 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1764 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001765
1766 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001767 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001768 break;
1769 if (i < nbList) {
1770 cur = cur->next;
1771 continue;
1772 }
1773 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001774 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001775
Daniel Veillardcda96922001-08-21 10:56:31 +00001776 if (cur->children == NULL) {
1777 xmlFetchXMLCatalogFile(cur);
1778 }
1779 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001780 if (xmlDebugCatalogs)
1781 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001782 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001783 ret = xmlCatalogListXMLResolve(
1784 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001785 if (ret != NULL) {
1786 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001787 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001788 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001789 }
1790 }
1791 cur = cur->next;
1792 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001793 /*
1794 * Apply the cut algorithm explained in 4/
1795 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001796 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001797 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001798 }
1799 }
1800 if (haveNext) {
1801 cur = catal;
1802 while (cur != NULL) {
1803 if (cur->type == XML_CATA_NEXT_CATALOG) {
1804 if (cur->children == NULL) {
1805 xmlFetchXMLCatalogFile(cur);
1806 }
1807 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001808 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001809 if (ret != NULL) {
1810 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001811 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001812 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001813 }
1814 }
1815 cur = cur->next;
1816 }
1817 }
1818
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001819 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001820 return(NULL);
1821}
1822
1823/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001824 * xmlCatalogXMLResolveURI:
1825 * @catal: a catalog list
1826 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001827 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001828 *
1829 * Do a complete resolution lookup of an External Identifier for a
1830 * list of catalog entries.
1831 *
1832 * Implements (or tries to) 7.2.2. URI Resolution
1833 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1834 *
1835 * Returns the URI of the resource or NULL if not found
1836 */
1837static xmlChar *
1838xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1839 xmlChar *ret = NULL;
1840 xmlCatalogEntryPtr cur;
1841 int haveDelegate = 0;
1842 int haveNext = 0;
1843 xmlCatalogEntryPtr rewrite = NULL;
1844 int lenrewrite = 0, len;
1845
1846 if (catal == NULL)
1847 return(NULL);
1848
1849 if (URI == NULL)
1850 return(NULL);
1851
1852 /*
1853 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1854 */
1855 cur = catal;
1856 haveDelegate = 0;
1857 while (cur != NULL) {
1858 switch (cur->type) {
1859 case XML_CATA_URI:
1860 if (xmlStrEqual(URI, cur->name)) {
1861 if (xmlDebugCatalogs)
1862 xmlGenericError(xmlGenericErrorContext,
1863 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001864 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001865 }
1866 break;
1867 case XML_CATA_REWRITE_URI:
1868 len = xmlStrlen(cur->name);
1869 if ((len > lenrewrite) &&
1870 (!xmlStrncmp(URI, cur->name, len))) {
1871 lenrewrite = len;
1872 rewrite = cur;
1873 }
1874 break;
1875 case XML_CATA_DELEGATE_URI:
1876 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1877 haveDelegate++;
1878 break;
1879 case XML_CATA_NEXT_CATALOG:
1880 haveNext++;
1881 break;
1882 default:
1883 break;
1884 }
1885 cur = cur->next;
1886 }
1887 if (rewrite != NULL) {
1888 if (xmlDebugCatalogs)
1889 xmlGenericError(xmlGenericErrorContext,
1890 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001891 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001892 if (ret != NULL)
1893 ret = xmlStrcat(ret, &URI[lenrewrite]);
1894 return(ret);
1895 }
1896 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001897 const xmlChar *delegates[MAX_DELEGATE];
1898 int nbList = 0, i;
1899
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001900 /*
1901 * Assume the entries have been sorted by decreasing substring
1902 * matches when the list was produced.
1903 */
1904 cur = catal;
1905 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001906 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1907 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001908 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001909 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001910 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001911 break;
1912 if (i < nbList) {
1913 cur = cur->next;
1914 continue;
1915 }
1916 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001917 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001918
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001919 if (cur->children == NULL) {
1920 xmlFetchXMLCatalogFile(cur);
1921 }
1922 if (cur->children != NULL) {
1923 if (xmlDebugCatalogs)
1924 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001925 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001926 ret = xmlCatalogListXMLResolveURI(
1927 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001928 if (ret != NULL)
1929 return(ret);
1930 }
1931 }
1932 cur = cur->next;
1933 }
1934 /*
1935 * Apply the cut algorithm explained in 4/
1936 */
1937 return(XML_CATAL_BREAK);
1938 }
1939 if (haveNext) {
1940 cur = catal;
1941 while (cur != NULL) {
1942 if (cur->type == XML_CATA_NEXT_CATALOG) {
1943 if (cur->children == NULL) {
1944 xmlFetchXMLCatalogFile(cur);
1945 }
1946 if (cur->children != NULL) {
1947 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1948 if (ret != NULL)
1949 return(ret);
1950 }
1951 }
1952 cur = cur->next;
1953 }
1954 }
1955
1956 return(NULL);
1957}
1958
1959/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001960 * xmlCatalogListXMLResolve:
1961 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001962 * @pubID: the public ID string
1963 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001964 *
1965 * Do a complete resolution lookup of an External Identifier for a
1966 * list of catalogs
1967 *
1968 * Implements (or tries to) 7.1. External Identifier Resolution
1969 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1970 *
1971 * Returns the URI of the resource or NULL if not found
1972 */
1973static xmlChar *
1974xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1975 const xmlChar *sysID) {
1976 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001977 xmlChar *urnID = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +00001978 xmlChar *normid;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001979
1980 if (catal == NULL)
1981 return(NULL);
1982 if ((pubID == NULL) && (sysID == NULL))
1983 return(NULL);
1984
Daniel Veillardc8155052004-07-16 09:03:08 +00001985 normid = xmlCatalogNormalizePublic(pubID);
1986 if (normid != NULL)
1987 pubID = (*normid != 0 ? normid : NULL);
1988
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001989 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1990 urnID = xmlCatalogUnWrapURN(pubID);
1991 if (xmlDebugCatalogs) {
1992 if (urnID == NULL)
1993 xmlGenericError(xmlGenericErrorContext,
1994 "Public URN ID %s expanded to NULL\n", pubID);
1995 else
1996 xmlGenericError(xmlGenericErrorContext,
1997 "Public URN ID expanded to %s\n", urnID);
1998 }
1999 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2000 if (urnID != NULL)
2001 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002002 if (normid != NULL)
2003 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002004 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002005 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002006 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2007 urnID = xmlCatalogUnWrapURN(sysID);
2008 if (xmlDebugCatalogs) {
2009 if (urnID == NULL)
2010 xmlGenericError(xmlGenericErrorContext,
2011 "System URN ID %s expanded to NULL\n", sysID);
2012 else
2013 xmlGenericError(xmlGenericErrorContext,
2014 "System URN ID expanded to %s\n", urnID);
2015 }
2016 if (pubID == NULL)
2017 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2018 else if (xmlStrEqual(pubID, urnID))
2019 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2020 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00002021 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002022 }
2023 if (urnID != NULL)
2024 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002025 if (normid != NULL)
2026 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002027 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002028 }
2029 while (catal != NULL) {
2030 if (catal->type == XML_CATA_CATALOG) {
2031 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002032 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00002033 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002034 if (catal->children != NULL) {
2035 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002036 if (ret != NULL) {
2037 if (normid != NULL)
2038 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002039 return(ret);
Daniel Veillardc8155052004-07-16 09:03:08 +00002040 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002041 }
Daniel Veillardcda96922001-08-21 10:56:31 +00002042 }
2043 catal = catal->next;
2044 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002045 if (normid != NULL)
2046 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002047 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00002048}
2049
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002050/**
2051 * xmlCatalogListXMLResolveURI:
2052 * @catal: a catalog list
2053 * @URI: the URI
2054 *
2055 * Do a complete resolution lookup of an URI for a list of catalogs
2056 *
2057 * Implements (or tries to) 7.2. URI Resolution
2058 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2059 *
2060 * Returns the URI of the resource or NULL if not found
2061 */
2062static xmlChar *
2063xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2064 xmlChar *ret = NULL;
2065 xmlChar *urnID = NULL;
2066
2067 if (catal == NULL)
2068 return(NULL);
2069 if (URI == NULL)
2070 return(NULL);
2071
2072 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2073 urnID = xmlCatalogUnWrapURN(URI);
2074 if (xmlDebugCatalogs) {
2075 if (urnID == NULL)
2076 xmlGenericError(xmlGenericErrorContext,
2077 "URN ID %s expanded to NULL\n", URI);
2078 else
2079 xmlGenericError(xmlGenericErrorContext,
2080 "URN ID expanded to %s\n", urnID);
2081 }
2082 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2083 if (urnID != NULL)
2084 xmlFree(urnID);
2085 return(ret);
2086 }
2087 while (catal != NULL) {
2088 if (catal->type == XML_CATA_CATALOG) {
2089 if (catal->children == NULL) {
2090 xmlFetchXMLCatalogFile(catal);
2091 }
2092 if (catal->children != NULL) {
2093 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2094 if (ret != NULL)
2095 return(ret);
2096 }
2097 }
2098 catal = catal->next;
2099 }
2100 return(ret);
2101}
2102
Daniel Veillard344cee72001-08-20 00:08:40 +00002103/************************************************************************
2104 * *
2105 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00002106 * *
2107 ************************************************************************/
2108
2109
2110#define RAW *cur
2111#define NEXT cur++;
2112#define SKIP(x) cur += x;
2113
William M. Brack272693c2003-11-14 16:20:34 +00002114#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002115
Daniel Veillard75b96822001-10-11 18:59:45 +00002116/**
2117 * xmlParseSGMLCatalogComment:
2118 * @cur: the current character
2119 *
2120 * Skip a comment in an SGML catalog
2121 *
2122 * Returns new current character
2123 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002124static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002125xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002126 if ((cur[0] != '-') || (cur[1] != '-'))
2127 return(cur);
2128 SKIP(2);
2129 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2130 NEXT;
2131 if (cur[0] == 0) {
2132 return(NULL);
2133 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002134 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002135}
2136
Daniel Veillard75b96822001-10-11 18:59:45 +00002137/**
2138 * xmlParseSGMLCatalogPubid:
2139 * @cur: the current character
2140 * @id: the return location
2141 *
2142 * Parse an SGML catalog ID
2143 *
2144 * Returns new current character and store the value in @id
2145 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002146static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002147xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002148 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002149 int len = 0;
2150 int size = 50;
2151 xmlChar stop;
2152 int count = 0;
2153
2154 *id = NULL;
2155
2156 if (RAW == '"') {
2157 NEXT;
2158 stop = '"';
2159 } else if (RAW == '\'') {
2160 NEXT;
2161 stop = '\'';
2162 } else {
2163 stop = ' ';
2164 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002165 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002166 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002167 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002168 return(NULL);
2169 }
William M. Brack76e95df2003-10-18 16:20:14 +00002170 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002171 if ((*cur == stop) && (stop != ' '))
2172 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002173 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002174 break;
2175 if (len + 1 >= size) {
2176 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002177 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2178 if (tmp == NULL) {
2179 xmlCatalogErrMemory("allocating public ID");
2180 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002181 return(NULL);
2182 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002183 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002184 }
2185 buf[len++] = *cur;
2186 count++;
2187 NEXT;
2188 }
2189 buf[len] = 0;
2190 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002191 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002192 xmlFree(buf);
2193 return(NULL);
2194 }
2195 } else {
2196 if (*cur != stop) {
2197 xmlFree(buf);
2198 return(NULL);
2199 }
2200 NEXT;
2201 }
2202 *id = buf;
2203 return(cur);
2204}
2205
Daniel Veillard75b96822001-10-11 18:59:45 +00002206/**
2207 * xmlParseSGMLCatalogName:
2208 * @cur: the current character
2209 * @name: the return location
2210 *
2211 * Parse an SGML catalog name
2212 *
2213 * Returns new current character and store the value in @name
2214 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002215static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002216xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002217 xmlChar buf[XML_MAX_NAMELEN + 5];
2218 int len = 0;
2219 int c;
2220
2221 *name = NULL;
2222
2223 /*
2224 * Handler for more complex cases
2225 */
2226 c = *cur;
2227 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2228 return(NULL);
2229 }
2230
2231 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2232 (c == '.') || (c == '-') ||
2233 (c == '_') || (c == ':'))) {
2234 buf[len++] = c;
2235 cur++;
2236 c = *cur;
2237 if (len >= XML_MAX_NAMELEN)
2238 return(NULL);
2239 }
2240 *name = xmlStrndup(buf, len);
2241 return(cur);
2242}
2243
Daniel Veillard75b96822001-10-11 18:59:45 +00002244/**
2245 * xmlGetSGMLCatalogEntryType:
2246 * @name: the entry name
2247 *
2248 * Get the Catalog entry type for a given SGML Catalog name
2249 *
2250 * Returns Catalog entry type
2251 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002252static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002253xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002254 xmlCatalogEntryType type = XML_CATA_NONE;
2255 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2256 type = SGML_CATA_SYSTEM;
2257 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2258 type = SGML_CATA_PUBLIC;
2259 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2260 type = SGML_CATA_DELEGATE;
2261 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2262 type = SGML_CATA_ENTITY;
2263 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2264 type = SGML_CATA_DOCTYPE;
2265 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2266 type = SGML_CATA_LINKTYPE;
2267 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2268 type = SGML_CATA_NOTATION;
2269 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2270 type = SGML_CATA_SGMLDECL;
2271 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2272 type = SGML_CATA_DOCUMENT;
2273 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2274 type = SGML_CATA_CATALOG;
2275 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2276 type = SGML_CATA_BASE;
Daniel Veillard344cee72001-08-20 00:08:40 +00002277 return(type);
2278}
2279
Daniel Veillard75b96822001-10-11 18:59:45 +00002280/**
2281 * xmlParseSGMLCatalog:
2282 * @catal: the SGML Catalog
2283 * @value: the content of the SGML Catalog serialization
2284 * @file: the filepath for the catalog
2285 * @super: should this be handled as a Super Catalog in which case
2286 * parsing is not recursive
2287 *
2288 * Parse an SGML catalog content and fill up the @catal hash table with
2289 * the new entries found.
2290 *
2291 * Returns 0 in case of success, -1 in case of error.
2292 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002293static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002294xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2295 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002296 const xmlChar *cur = value;
2297 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002298 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002299
2300 if ((cur == NULL) || (file == NULL))
2301 return(-1);
2302 base = xmlStrdup((const xmlChar *) file);
2303
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002304 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002305 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002306 if (cur[0] == 0)
2307 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002308 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002309 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002310 if (cur == NULL) {
2311 /* error */
2312 break;
2313 }
2314 } else {
2315 xmlChar *sysid = NULL;
2316 xmlChar *name = NULL;
2317 xmlCatalogEntryType type = XML_CATA_NONE;
2318
Daniel Veillardcda96922001-08-21 10:56:31 +00002319 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002320 if (name == NULL) {
2321 /* error */
2322 break;
2323 }
William M. Brack76e95df2003-10-18 16:20:14 +00002324 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002325 /* error */
2326 break;
2327 }
2328 SKIP_BLANKS;
2329 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002330 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002331 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002332 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002333 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002334 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002335 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002336 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002337 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002338 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002339 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002340 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002341 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002342 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002343 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002344 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002345 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002346 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002347 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002348 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002349 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002350 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002351 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2352 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002353 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002354 if (name == NULL) {
2355 /* error */
2356 break;
2357 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002358 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002359 continue;
2360 }
2361 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002362 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002363
2364 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002365 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002366 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002367 type = SGML_CATA_PENTITY;
2368 case SGML_CATA_PENTITY:
2369 case SGML_CATA_DOCTYPE:
2370 case SGML_CATA_LINKTYPE:
2371 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002372 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002373 if (cur == NULL) {
2374 /* error */
2375 break;
2376 }
William M. Brack76e95df2003-10-18 16:20:14 +00002377 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002378 /* error */
2379 break;
2380 }
2381 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002382 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002383 if (cur == NULL) {
2384 /* error */
2385 break;
2386 }
2387 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002388 case SGML_CATA_PUBLIC:
2389 case SGML_CATA_SYSTEM:
2390 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002391 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002392 if (cur == NULL) {
2393 /* error */
2394 break;
2395 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002396 if (type != SGML_CATA_SYSTEM) {
2397 xmlChar *normid;
2398
2399 normid = xmlCatalogNormalizePublic(name);
2400 if (normid != NULL) {
2401 if (name != NULL)
2402 xmlFree(name);
2403 if (*normid != 0)
2404 name = normid;
2405 else {
2406 xmlFree(normid);
2407 name = NULL;
2408 }
2409 }
2410 }
William M. Brack76e95df2003-10-18 16:20:14 +00002411 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002412 /* error */
2413 break;
2414 }
2415 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002416 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002417 if (cur == NULL) {
2418 /* error */
2419 break;
2420 }
2421 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002422 case SGML_CATA_BASE:
2423 case SGML_CATA_CATALOG:
2424 case SGML_CATA_DOCUMENT:
2425 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002426 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002427 if (cur == NULL) {
2428 /* error */
2429 break;
2430 }
2431 break;
2432 default:
2433 break;
2434 }
2435 if (cur == NULL) {
2436 if (name != NULL)
2437 xmlFree(name);
2438 if (sysid != NULL)
2439 xmlFree(sysid);
2440 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002441 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002442 if (base != NULL)
2443 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002444 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002445 } else if ((type == SGML_CATA_PUBLIC) ||
2446 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002447 xmlChar *filename;
2448
2449 filename = xmlBuildURI(sysid, base);
2450 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002451 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002452
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002453 entry = xmlNewCatalogEntry(type, name, filename,
William M. Brackb7b54de2004-10-06 16:38:01 +00002454 NULL, XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002455 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002456 if (res < 0) {
2457 xmlFreeCatalogEntry(entry);
2458 }
2459 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002460 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002461
Daniel Veillard344cee72001-08-20 00:08:40 +00002462 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002463 if (super) {
2464 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002465
Daniel Veillardc853b322001-11-06 15:24:37 +00002466 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002467 XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002468 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002469 if (res < 0) {
2470 xmlFreeCatalogEntry(entry);
2471 }
2472 } else {
2473 xmlChar *filename;
2474
2475 filename = xmlBuildURI(sysid, base);
2476 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002477 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002478 xmlFree(filename);
2479 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002480 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002481 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002482 /*
2483 * drop anything else we won't handle it
2484 */
2485 if (name != NULL)
2486 xmlFree(name);
2487 if (sysid != NULL)
2488 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002489 }
2490 }
2491 if (base != NULL)
2492 xmlFree(base);
2493 if (cur == NULL)
2494 return(-1);
2495 return(0);
2496}
2497
Daniel Veillard75b96822001-10-11 18:59:45 +00002498/************************************************************************
2499 * *
2500 * SGML Catalog handling *
2501 * *
2502 ************************************************************************/
2503
Daniel Veillardcda96922001-08-21 10:56:31 +00002504/**
2505 * xmlCatalogGetSGMLPublic:
2506 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002507 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002508 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002509 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002510 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002511 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002512 */
2513static const xmlChar *
2514xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2515 xmlCatalogEntryPtr entry;
Daniel Veillardc8155052004-07-16 09:03:08 +00002516 xmlChar *normid;
Daniel Veillardcda96922001-08-21 10:56:31 +00002517
2518 if (catal == NULL)
2519 return(NULL);
2520
Daniel Veillardc8155052004-07-16 09:03:08 +00002521 normid = xmlCatalogNormalizePublic(pubID);
2522 if (normid != NULL)
2523 pubID = (*normid != 0 ? normid : NULL);
2524
Daniel Veillardcda96922001-08-21 10:56:31 +00002525 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002526 if (entry == NULL) {
2527 if (normid != NULL)
2528 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002529 return(NULL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002530 }
2531 if (entry->type == SGML_CATA_PUBLIC) {
2532 if (normid != NULL)
2533 xmlFree(normid);
Daniel Veillardc853b322001-11-06 15:24:37 +00002534 return(entry->URL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002535 }
2536 if (normid != NULL)
2537 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002538 return(NULL);
2539}
2540
2541/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002542 * xmlCatalogGetSGMLSystem:
2543 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002544 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002545 *
2546 * Try to lookup the catalog local reference for a system ID
2547 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002548 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002549 */
2550static const xmlChar *
2551xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2552 xmlCatalogEntryPtr entry;
2553
2554 if (catal == NULL)
2555 return(NULL);
2556
2557 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2558 if (entry == NULL)
2559 return(NULL);
2560 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002561 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002562 return(NULL);
2563}
2564
2565/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002566 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002567 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002568 * @pubID: the public ID string
2569 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002570 *
2571 * Do a complete resolution lookup of an External Identifier
2572 *
2573 * Returns the URI of the resource or NULL if not found
2574 */
2575static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002576xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2577 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002578 const xmlChar *ret = NULL;
2579
Daniel Veillard75b96822001-10-11 18:59:45 +00002580 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002581 return(NULL);
2582
2583 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002584 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002585 if (ret != NULL)
2586 return(ret);
2587 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002588 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002589 return(NULL);
2590}
2591
Daniel Veillarda7374592001-05-10 14:17:55 +00002592/************************************************************************
2593 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002594 * Specific Public interfaces *
2595 * *
2596 ************************************************************************/
2597
2598/**
2599 * xmlLoadSGMLSuperCatalog:
2600 * @filename: a file path
2601 *
2602 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2603 * references. This is only needed for manipulating SGML Super Catalogs
2604 * like adding and removing CATALOG or DELEGATE entries.
2605 *
2606 * Returns the catalog parsed or NULL in case of error
2607 */
2608xmlCatalogPtr
2609xmlLoadSGMLSuperCatalog(const char *filename)
2610{
2611 xmlChar *content;
2612 xmlCatalogPtr catal;
2613 int ret;
2614
2615 content = xmlLoadFileContent(filename);
2616 if (content == NULL)
2617 return(NULL);
2618
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002619 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002620 if (catal == NULL) {
2621 xmlFree(content);
2622 return(NULL);
2623 }
2624
2625 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2626 xmlFree(content);
2627 if (ret < 0) {
2628 xmlFreeCatalog(catal);
2629 return(NULL);
2630 }
2631 return (catal);
2632}
2633
2634/**
2635 * xmlLoadACatalog:
2636 * @filename: a file path
2637 *
2638 * Load the catalog and build the associated data structures.
2639 * This can be either an XML Catalog or an SGML Catalog
2640 * It will recurse in SGML CATALOG entries. On the other hand XML
2641 * Catalogs are not handled recursively.
2642 *
2643 * Returns the catalog parsed or NULL in case of error
2644 */
2645xmlCatalogPtr
2646xmlLoadACatalog(const char *filename)
2647{
2648 xmlChar *content;
2649 xmlChar *first;
2650 xmlCatalogPtr catal;
2651 int ret;
2652
2653 content = xmlLoadFileContent(filename);
2654 if (content == NULL)
2655 return(NULL);
2656
2657
2658 first = content;
2659
2660 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2661 (!(((*first >= 'A') && (*first <= 'Z')) ||
2662 ((*first >= 'a') && (*first <= 'z')))))
2663 first++;
2664
2665 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002666 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002667 if (catal == NULL) {
2668 xmlFree(content);
2669 return(NULL);
2670 }
2671 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2672 if (ret < 0) {
2673 xmlFreeCatalog(catal);
2674 xmlFree(content);
2675 return(NULL);
2676 }
2677 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002678 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002679 if (catal == NULL) {
2680 xmlFree(content);
2681 return(NULL);
2682 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002683 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002684 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002685 }
2686 xmlFree(content);
2687 return (catal);
2688}
2689
2690/**
2691 * xmlExpandCatalog:
2692 * @catal: a catalog
2693 * @filename: a file path
2694 *
2695 * Load the catalog and expand the existing catal structure.
2696 * This can be either an XML Catalog or an SGML Catalog
2697 *
2698 * Returns 0 in case of success, -1 in case of error
2699 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002700static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002701xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2702{
Daniel Veillard75b96822001-10-11 18:59:45 +00002703 int ret;
2704
2705 if ((catal == NULL) || (filename == NULL))
2706 return(-1);
2707
Daniel Veillard75b96822001-10-11 18:59:45 +00002708
2709 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002710 xmlChar *content;
2711
2712 content = xmlLoadFileContent(filename);
2713 if (content == NULL)
2714 return(-1);
2715
Daniel Veillard75b96822001-10-11 18:59:45 +00002716 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2717 if (ret < 0) {
2718 xmlFree(content);
2719 return(-1);
2720 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002721 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002722 } else {
2723 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002724 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002725 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002726
Daniel Veillard75b96822001-10-11 18:59:45 +00002727 cur = catal->xml;
2728 if (cur == NULL) {
2729 catal->xml = tmp;
2730 } else {
2731 while (cur->next != NULL) cur = cur->next;
2732 cur->next = tmp;
2733 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002734 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002735 return (0);
2736}
2737
2738/**
2739 * xmlACatalogResolveSystem:
2740 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002741 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002742 *
2743 * Try to lookup the catalog resource for a system ID
2744 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002745 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002746 * must be freed by the caller.
2747 */
2748xmlChar *
2749xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2750 xmlChar *ret = NULL;
2751
2752 if ((sysID == NULL) || (catal == NULL))
2753 return(NULL);
2754
2755 if (xmlDebugCatalogs)
2756 xmlGenericError(xmlGenericErrorContext,
2757 "Resolve sysID %s\n", sysID);
2758
2759 if (catal->type == XML_XML_CATALOG_TYPE) {
2760 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2761 if (ret == XML_CATAL_BREAK)
2762 ret = NULL;
2763 } else {
2764 const xmlChar *sgml;
2765
2766 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2767 if (sgml != NULL)
2768 ret = xmlStrdup(sgml);
2769 }
2770 return(ret);
2771}
2772
2773/**
2774 * xmlACatalogResolvePublic:
2775 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002776 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002777 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002778 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002779 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002780 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002781 * must be freed by the caller.
2782 */
2783xmlChar *
2784xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2785 xmlChar *ret = NULL;
2786
2787 if ((pubID == NULL) || (catal == NULL))
2788 return(NULL);
2789
2790 if (xmlDebugCatalogs)
2791 xmlGenericError(xmlGenericErrorContext,
2792 "Resolve pubID %s\n", pubID);
2793
2794 if (catal->type == XML_XML_CATALOG_TYPE) {
2795 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2796 if (ret == XML_CATAL_BREAK)
2797 ret = NULL;
2798 } else {
2799 const xmlChar *sgml;
2800
2801 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2802 if (sgml != NULL)
2803 ret = xmlStrdup(sgml);
2804 }
2805 return(ret);
2806}
2807
2808/**
2809 * xmlACatalogResolve:
2810 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002811 * @pubID: the public ID string
2812 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002813 *
2814 * Do a complete resolution lookup of an External Identifier
2815 *
2816 * Returns the URI of the resource or NULL if not found, it must be freed
2817 * by the caller.
2818 */
2819xmlChar *
2820xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2821 const xmlChar * sysID)
2822{
2823 xmlChar *ret = NULL;
2824
2825 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2826 return (NULL);
2827
2828 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002829 if ((pubID != NULL) && (sysID != NULL)) {
2830 xmlGenericError(xmlGenericErrorContext,
2831 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2832 } else if (pubID != NULL) {
2833 xmlGenericError(xmlGenericErrorContext,
2834 "Resolve: pubID %s\n", pubID);
2835 } else {
2836 xmlGenericError(xmlGenericErrorContext,
2837 "Resolve: sysID %s\n", sysID);
2838 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002839 }
2840
2841 if (catal->type == XML_XML_CATALOG_TYPE) {
2842 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2843 if (ret == XML_CATAL_BREAK)
2844 ret = NULL;
2845 } else {
2846 const xmlChar *sgml;
2847
2848 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2849 if (sgml != NULL)
2850 ret = xmlStrdup(sgml);
2851 }
2852 return (ret);
2853}
2854
2855/**
2856 * xmlACatalogResolveURI:
2857 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002858 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002859 *
2860 * Do a complete resolution lookup of an URI
2861 *
2862 * Returns the URI of the resource or NULL if not found, it must be freed
2863 * by the caller.
2864 */
2865xmlChar *
2866xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2867 xmlChar *ret = NULL;
2868
2869 if ((URI == NULL) || (catal == NULL))
2870 return(NULL);
2871
Daniel Veillardb44025c2001-10-11 22:55:55 +00002872 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002873 xmlGenericError(xmlGenericErrorContext,
2874 "Resolve URI %s\n", URI);
2875
2876 if (catal->type == XML_XML_CATALOG_TYPE) {
2877 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2878 if (ret == XML_CATAL_BREAK)
2879 ret = NULL;
2880 } else {
2881 const xmlChar *sgml;
2882
2883 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2884 if (sgml != NULL)
2885 sgml = xmlStrdup(sgml);
2886 }
2887 return(ret);
2888}
2889
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002890#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002891/**
2892 * xmlACatalogDump:
2893 * @catal: a Catalog
2894 * @out: the file.
2895 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002896 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002897 */
2898void
2899xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002900 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002901 return;
2902
2903 if (catal->type == XML_XML_CATALOG_TYPE) {
2904 xmlDumpXMLCatalog(out, catal->xml);
2905 } else {
2906 xmlHashScan(catal->sgml,
2907 (xmlHashScanner) xmlCatalogDumpEntry, out);
2908 }
2909}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002910#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002911
2912/**
2913 * xmlACatalogAdd:
2914 * @catal: a Catalog
2915 * @type: the type of record to add to the catalog
2916 * @orig: the system, public or prefix to match
2917 * @replace: the replacement value for the match
2918 *
2919 * Add an entry in the catalog, it may overwrite existing but
2920 * different entries.
2921 *
2922 * Returns 0 if successful, -1 otherwise
2923 */
2924int
2925xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2926 const xmlChar * orig, const xmlChar * replace)
2927{
2928 int res = -1;
2929
2930 if (catal == NULL)
2931 return(-1);
2932
2933 if (catal->type == XML_XML_CATALOG_TYPE) {
2934 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2935 } else {
2936 xmlCatalogEntryType cattype;
2937
2938 cattype = xmlGetSGMLCatalogEntryType(type);
2939 if (cattype != XML_CATA_NONE) {
2940 xmlCatalogEntryPtr entry;
2941
Daniel Veillardc853b322001-11-06 15:24:37 +00002942 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002943 XML_CATA_PREFER_NONE, NULL);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002944 if (catal->sgml == NULL)
2945 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002946 res = xmlHashAddEntry(catal->sgml, orig, entry);
2947 }
2948 }
2949 return (res);
2950}
2951
2952/**
2953 * xmlACatalogRemove:
2954 * @catal: a Catalog
2955 * @value: the value to remove
2956 *
2957 * Remove an entry from the catalog
2958 *
2959 * Returns the number of entries removed if successful, -1 otherwise
2960 */
2961int
2962xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2963 int res = -1;
2964
2965 if ((catal == NULL) || (value == NULL))
2966 return(-1);
2967
2968 if (catal->type == XML_XML_CATALOG_TYPE) {
2969 res = xmlDelXMLCatalog(catal->xml, value);
2970 } else {
2971 res = xmlHashRemoveEntry(catal->sgml, value,
2972 (xmlHashDeallocator) xmlFreeCatalogEntry);
2973 if (res == 0)
2974 res = 1;
2975 }
2976 return(res);
2977}
2978
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002979/**
2980 * xmlNewCatalog:
2981 * @sgml: should this create an SGML catalog
2982 *
2983 * create a new Catalog.
2984 *
2985 * Returns the xmlCatalogPtr or NULL in case of error
2986 */
2987xmlCatalogPtr
2988xmlNewCatalog(int sgml) {
2989 xmlCatalogPtr catal = NULL;
2990
2991 if (sgml) {
2992 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2993 xmlCatalogDefaultPrefer);
2994 if ((catal != NULL) && (catal->sgml == NULL))
2995 catal->sgml = xmlHashCreate(10);
2996 } else
2997 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2998 xmlCatalogDefaultPrefer);
2999 return(catal);
3000}
3001
3002/**
3003 * xmlCatalogIsEmpty:
3004 * @catal: should this create an SGML catalog
3005 *
3006 * Check is a catalog is empty
3007 *
3008 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3009 */
3010int
3011xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3012 if (catal == NULL)
3013 return(-1);
3014
3015 if (catal->type == XML_XML_CATALOG_TYPE) {
3016 if (catal->xml == NULL)
3017 return(1);
3018 if ((catal->xml->type != XML_CATA_CATALOG) &&
3019 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3020 return(-1);
3021 if (catal->xml->children == NULL)
3022 return(1);
3023 return(0);
3024 } else {
3025 int res;
3026
3027 if (catal->sgml == NULL)
3028 return(1);
3029 res = xmlHashSize(catal->sgml);
3030 if (res == 0)
3031 return(1);
3032 if (res < 0)
3033 return(-1);
3034 }
3035 return(0);
3036}
3037
Daniel Veillard75b96822001-10-11 18:59:45 +00003038/************************************************************************
3039 * *
3040 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00003041 * *
3042 ************************************************************************/
3043
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003044/**
Daniel Veillard81463942001-10-16 12:34:39 +00003045 * xmlInitializeCatalogData:
3046 *
3047 * Do the catalog initialization only of global data, doesn't try to load
3048 * any catalog actually.
3049 * this function is not thread safe, catalog initialization should
3050 * preferably be done once at startup
3051 */
3052static void
3053xmlInitializeCatalogData(void) {
3054 if (xmlCatalogInitialized != 0)
3055 return;
3056
3057 if (getenv("XML_DEBUG_CATALOG"))
3058 xmlDebugCatalogs = 1;
3059 xmlCatalogMutex = xmlNewRMutex();
3060
3061 xmlCatalogInitialized = 1;
3062}
3063/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003064 * xmlInitializeCatalog:
3065 *
3066 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00003067 * this function is not thread safe, catalog initialization should
3068 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003069 */
3070void
3071xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003072 if (xmlCatalogInitialized != 0)
3073 return;
3074
Daniel Veillard81463942001-10-16 12:34:39 +00003075 xmlInitializeCatalogData();
3076 xmlRMutexLock(xmlCatalogMutex);
3077
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003078 if (getenv("XML_DEBUG_CATALOG"))
3079 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00003080
Daniel Veillard75b96822001-10-11 18:59:45 +00003081 if (xmlDefaultCatalog == NULL) {
3082 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003083 char *path;
3084 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00003085 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003086 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00003087
Daniel Veillardb44025c2001-10-11 22:55:55 +00003088 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003089 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003090#if defined(_WIN32) && defined(_MSC_VER)
3091 {
3092 void* hmodule;
3093 hmodule = GetModuleHandleA("libxml2.dll");
3094 if (hmodule == NULL)
3095 hmodule = GetModuleHandleA(NULL);
3096 if (hmodule != NULL) {
3097 char buf[256];
3098 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3099 if (len != 0) {
3100 char* p = &(buf[len]);
3101 while (*p != '\\' && p > buf)
3102 p--;
3103 if (p != buf) {
3104 xmlChar* uri;
3105 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3106 uri = xmlCanonicPath(buf);
3107 if (uri != NULL) {
3108 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3109 xmlFree(uri);
3110 }
3111 }
3112 }
3113 }
3114 catalogs = XML_XML_DEFAULT_CATALOG;
3115 }
3116#else
Daniel Veillard75b96822001-10-11 18:59:45 +00003117 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00003118#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00003119
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003120 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3121 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003122 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003123 /* the XML_CATALOG_FILES envvar is allowed to contain a
3124 space-separated list of entries. */
3125 cur = catalogs;
3126 nextent = &catal->xml;
3127 while (*cur != '\0') {
William M. Brack68aca052003-10-11 15:22:13 +00003128 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003129 cur++;
3130 if (*cur != 0) {
3131 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003132 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003133 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00003134 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003135 if (path != NULL) {
3136 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003137 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003138 if (*nextent != NULL)
3139 nextent = &((*nextent)->next);
3140 xmlFree(path);
3141 }
3142 }
3143 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003144 xmlDefaultCatalog = catal;
3145 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003146 }
3147
Daniel Veillard81463942001-10-16 12:34:39 +00003148 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003149}
3150
Daniel Veillard82d75332001-10-08 15:01:59 +00003151
3152/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003153 * xmlLoadCatalog:
3154 * @filename: a file path
3155 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003156 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003157 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003158 * this function is not thread safe, catalog initialization should
3159 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003160 *
3161 * Returns 0 in case of success -1 in case of error
3162 */
3163int
Daniel Veillard16756b62001-10-01 07:36:25 +00003164xmlLoadCatalog(const char *filename)
3165{
Daniel Veillard75b96822001-10-11 18:59:45 +00003166 int ret;
3167 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003168
Daniel Veillard81463942001-10-16 12:34:39 +00003169 if (!xmlCatalogInitialized)
3170 xmlInitializeCatalogData();
3171
3172 xmlRMutexLock(xmlCatalogMutex);
3173
Daniel Veillard75b96822001-10-11 18:59:45 +00003174 if (xmlDefaultCatalog == NULL) {
3175 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003176 if (catal == NULL) {
3177 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003178 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003179 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003180
Daniel Veillard75b96822001-10-11 18:59:45 +00003181 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003182 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003183 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003184 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003185
Daniel Veillard75b96822001-10-11 18:59:45 +00003186 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003187 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003188 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003189}
3190
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003191/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003192 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003193 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003194 *
3195 * Load the catalogs and makes their definitions effective for the default
3196 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003197 * this function is not thread safe, catalog initialization should
3198 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003199 */
3200void
3201xmlLoadCatalogs(const char *pathss) {
3202 const char *cur;
3203 const char *paths;
3204 xmlChar *path;
3205
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003206 if (pathss == NULL)
3207 return;
3208
Daniel Veillard81418e32001-05-22 15:08:55 +00003209 cur = pathss;
3210 while ((cur != NULL) && (*cur != 0)) {
William M. Brack68aca052003-10-11 15:22:13 +00003211 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003212 if (*cur != 0) {
3213 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003214 while ((*cur != 0) && (*cur != ':') && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003215 cur++;
3216 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3217 if (path != NULL) {
3218 xmlLoadCatalog((const char *) path);
3219 xmlFree(path);
3220 }
3221 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003222 while (*cur == ':')
3223 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003224 }
3225}
3226
Daniel Veillarda7374592001-05-10 14:17:55 +00003227/**
3228 * xmlCatalogCleanup:
3229 *
3230 * Free up all the memory associated with catalogs
3231 */
3232void
3233xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003234 if (xmlCatalogInitialized == 0)
3235 return;
3236
Daniel Veillard81463942001-10-16 12:34:39 +00003237 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003238 if (xmlDebugCatalogs)
3239 xmlGenericError(xmlGenericErrorContext,
3240 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003241 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003242 xmlHashFree(xmlCatalogXMLFiles,
3243 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003244 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003245 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003246 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003247 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003248 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003249 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003250 xmlRMutexUnlock(xmlCatalogMutex);
3251 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003252}
3253
3254/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003255 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003256 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003257 *
3258 * Try to lookup the catalog resource for a system ID
3259 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003260 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003261 * must be freed by the caller.
3262 */
3263xmlChar *
3264xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003265 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003266
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003267 if (!xmlCatalogInitialized)
3268 xmlInitializeCatalog();
3269
Daniel Veillard75b96822001-10-11 18:59:45 +00003270 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3271 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003272}
3273
3274/**
3275 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003276 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003277 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003278 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003279 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003280 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003281 * must be freed by the caller.
3282 */
3283xmlChar *
3284xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003285 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003286
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003287 if (!xmlCatalogInitialized)
3288 xmlInitializeCatalog();
3289
Daniel Veillard75b96822001-10-11 18:59:45 +00003290 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3291 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003292}
Daniel Veillard344cee72001-08-20 00:08:40 +00003293
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003294/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003295 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003296 * @pubID: the public ID string
3297 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003298 *
3299 * Do a complete resolution lookup of an External Identifier
3300 *
3301 * Returns the URI of the resource or NULL if not found, it must be freed
3302 * by the caller.
3303 */
3304xmlChar *
3305xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003306 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003307
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003308 if (!xmlCatalogInitialized)
3309 xmlInitializeCatalog();
3310
Daniel Veillard75b96822001-10-11 18:59:45 +00003311 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3312 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003313}
3314
3315/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003316 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003317 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003318 *
3319 * Do a complete resolution lookup of an URI
3320 *
3321 * Returns the URI of the resource or NULL if not found, it must be freed
3322 * by the caller.
3323 */
3324xmlChar *
3325xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003326 xmlChar *ret;
3327
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003328 if (!xmlCatalogInitialized)
3329 xmlInitializeCatalog();
3330
Daniel Veillard75b96822001-10-11 18:59:45 +00003331 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3332 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003333}
3334
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003335#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003336/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003337 * xmlCatalogDump:
3338 * @out: the file.
3339 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003340 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003341 */
3342void
3343xmlCatalogDump(FILE *out) {
3344 if (out == NULL)
3345 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003346
Daniel Veillard75b96822001-10-11 18:59:45 +00003347 if (!xmlCatalogInitialized)
3348 xmlInitializeCatalog();
3349
3350 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003351}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003352#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003353
3354/**
3355 * xmlCatalogAdd:
3356 * @type: the type of record to add to the catalog
3357 * @orig: the system, public or prefix to match
3358 * @replace: the replacement value for the match
3359 *
3360 * Add an entry in the catalog, it may overwrite existing but
3361 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003362 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003363 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003364 *
3365 * Returns 0 if successful, -1 otherwise
3366 */
3367int
3368xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3369 int res = -1;
3370
Daniel Veillard81463942001-10-16 12:34:39 +00003371 if (!xmlCatalogInitialized)
3372 xmlInitializeCatalogData();
3373
3374 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003375 /*
3376 * Specific case where one want to override the default catalog
3377 * put in place by xmlInitializeCatalog();
3378 */
3379 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003380 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003381 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003382 xmlCatalogDefaultPrefer);
3383 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003384 orig, NULL, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003385
Daniel Veillard81463942001-10-16 12:34:39 +00003386 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003387 return(0);
3388 }
3389
Daniel Veillard75b96822001-10-11 18:59:45 +00003390 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003391 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003392 return(res);
3393}
3394
3395/**
3396 * xmlCatalogRemove:
3397 * @value: the value to remove
3398 *
3399 * Remove an entry from the catalog
3400 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003401 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003402 */
3403int
3404xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003405 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003406
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003407 if (!xmlCatalogInitialized)
3408 xmlInitializeCatalog();
3409
Daniel Veillard81463942001-10-16 12:34:39 +00003410 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003411 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003412 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003413 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003414}
3415
3416/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003417 * xmlCatalogConvert:
3418 *
3419 * Convert all the SGML catalog entries as XML ones
3420 *
3421 * Returns the number of entries converted if successful, -1 otherwise
3422 */
3423int
3424xmlCatalogConvert(void) {
3425 int res = -1;
3426
3427 if (!xmlCatalogInitialized)
3428 xmlInitializeCatalog();
3429
Daniel Veillard81463942001-10-16 12:34:39 +00003430 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003431 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003432 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003433 return(res);
3434}
3435
Daniel Veillard75b96822001-10-11 18:59:45 +00003436/************************************************************************
3437 * *
3438 * Public interface manipulating the common preferences *
3439 * *
3440 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003441
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003442/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003443 * xmlCatalogGetDefaults:
3444 *
3445 * Used to get the user preference w.r.t. to what catalogs should
3446 * be accepted
3447 *
3448 * Returns the current xmlCatalogAllow value
3449 */
3450xmlCatalogAllow
3451xmlCatalogGetDefaults(void) {
3452 return(xmlCatalogDefaultAllow);
3453}
3454
3455/**
3456 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003457 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003458 *
3459 * Used to set the user preference w.r.t. to what catalogs should
3460 * be accepted
3461 */
3462void
3463xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003464 if (xmlDebugCatalogs) {
3465 switch (allow) {
3466 case XML_CATA_ALLOW_NONE:
3467 xmlGenericError(xmlGenericErrorContext,
3468 "Disabling catalog usage\n");
3469 break;
3470 case XML_CATA_ALLOW_GLOBAL:
3471 xmlGenericError(xmlGenericErrorContext,
3472 "Allowing only global catalogs\n");
3473 break;
3474 case XML_CATA_ALLOW_DOCUMENT:
3475 xmlGenericError(xmlGenericErrorContext,
3476 "Allowing only catalogs from the document\n");
3477 break;
3478 case XML_CATA_ALLOW_ALL:
3479 xmlGenericError(xmlGenericErrorContext,
3480 "Allowing all catalogs\n");
3481 break;
3482 }
3483 }
3484 xmlCatalogDefaultAllow = allow;
3485}
3486
3487/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003488 * xmlCatalogSetDefaultPrefer:
3489 * @prefer: the default preference for delegation
3490 *
3491 * Allows to set the preference between public and system for deletion
3492 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003493 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003494 *
3495 * Returns the previous value of the default preference for delegation
3496 */
3497xmlCatalogPrefer
3498xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3499 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3500
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003501 if (prefer == XML_CATA_PREFER_NONE)
3502 return(ret);
3503
3504 if (xmlDebugCatalogs) {
3505 switch (prefer) {
3506 case XML_CATA_PREFER_PUBLIC:
3507 xmlGenericError(xmlGenericErrorContext,
3508 "Setting catalog preference to PUBLIC\n");
3509 break;
3510 case XML_CATA_PREFER_SYSTEM:
3511 xmlGenericError(xmlGenericErrorContext,
3512 "Setting catalog preference to SYSTEM\n");
3513 break;
3514 case XML_CATA_PREFER_NONE:
3515 break;
3516 }
3517 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003518 xmlCatalogDefaultPrefer = prefer;
3519 return(ret);
3520}
3521
3522/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003523 * xmlCatalogSetDebug:
3524 * @level: the debug level of catalogs required
3525 *
3526 * Used to set the debug level for catalog operation, 0 disable
3527 * debugging, 1 enable it
3528 *
3529 * Returns the previous value of the catalog debugging level
3530 */
3531int
3532xmlCatalogSetDebug(int level) {
3533 int ret = xmlDebugCatalogs;
3534
3535 if (level <= 0)
3536 xmlDebugCatalogs = 0;
3537 else
3538 xmlDebugCatalogs = level;
3539 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003540}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003541
Daniel Veillard75b96822001-10-11 18:59:45 +00003542/************************************************************************
3543 * *
3544 * Minimal interfaces used for per-document catalogs by the parser *
3545 * *
3546 ************************************************************************/
3547
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003548/**
3549 * xmlCatalogFreeLocal:
3550 * @catalogs: a document's list of catalogs
3551 *
3552 * Free up the memory associated to the catalog list
3553 */
3554void
3555xmlCatalogFreeLocal(void *catalogs) {
3556 xmlCatalogEntryPtr catal;
3557
Daniel Veillard81463942001-10-16 12:34:39 +00003558 if (!xmlCatalogInitialized)
3559 xmlInitializeCatalog();
3560
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003561 catal = (xmlCatalogEntryPtr) catalogs;
3562 if (catal != NULL)
3563 xmlFreeCatalogEntryList(catal);
3564}
3565
3566
3567/**
3568 * xmlCatalogAddLocal:
3569 * @catalogs: a document's list of catalogs
3570 * @URL: the URL to a new local catalog
3571 *
3572 * Add the new entry to the catalog list
3573 *
3574 * Returns the updated list
3575 */
3576void *
3577xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3578 xmlCatalogEntryPtr catal, add;
3579
3580 if (!xmlCatalogInitialized)
3581 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003582
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003583 if (URL == NULL)
3584 return(catalogs);
3585
3586 if (xmlDebugCatalogs)
3587 xmlGenericError(xmlGenericErrorContext,
3588 "Adding document catalog %s\n", URL);
3589
Daniel Veillardc853b322001-11-06 15:24:37 +00003590 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003591 xmlCatalogDefaultPrefer, NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003592 if (add == NULL)
3593 return(catalogs);
3594
3595 catal = (xmlCatalogEntryPtr) catalogs;
3596 if (catal == NULL)
3597 return((void *) add);
3598
3599 while (catal->next != NULL)
3600 catal = catal->next;
3601 catal->next = add;
3602 return(catalogs);
3603}
3604
3605/**
3606 * xmlCatalogLocalResolve:
3607 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003608 * @pubID: the public ID string
3609 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003610 *
3611 * Do a complete resolution lookup of an External Identifier using a
3612 * document's private catalog list
3613 *
3614 * Returns the URI of the resource or NULL if not found, it must be freed
3615 * by the caller.
3616 */
3617xmlChar *
3618xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3619 const xmlChar *sysID) {
3620 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003621 xmlChar *ret;
3622
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003623 if (!xmlCatalogInitialized)
3624 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003625
Daniel Veillard81463942001-10-16 12:34:39 +00003626 if ((pubID == NULL) && (sysID == NULL))
3627 return(NULL);
3628
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003629 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003630 if ((pubID != NULL) && (sysID != NULL)) {
3631 xmlGenericError(xmlGenericErrorContext,
3632 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3633 } else if (pubID != NULL) {
3634 xmlGenericError(xmlGenericErrorContext,
3635 "Local Resolve: pubID %s\n", pubID);
3636 } else {
3637 xmlGenericError(xmlGenericErrorContext,
3638 "Local Resolve: sysID %s\n", sysID);
3639 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003640 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003641
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003642 catal = (xmlCatalogEntryPtr) catalogs;
3643 if (catal == NULL)
3644 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003645 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3646 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3647 return(ret);
3648 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003649}
3650
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003651/**
3652 * xmlCatalogLocalResolveURI:
3653 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003654 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003655 *
3656 * Do a complete resolution lookup of an URI using a
3657 * document's private catalog list
3658 *
3659 * Returns the URI of the resource or NULL if not found, it must be freed
3660 * by the caller.
3661 */
3662xmlChar *
3663xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3664 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003665 xmlChar *ret;
3666
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003667 if (!xmlCatalogInitialized)
3668 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003669
Daniel Veillard81463942001-10-16 12:34:39 +00003670 if (URI == NULL)
3671 return(NULL);
3672
Daniel Veillard6990bf32001-08-23 21:17:48 +00003673 if (xmlDebugCatalogs)
3674 xmlGenericError(xmlGenericErrorContext,
3675 "Resolve URI %s\n", URI);
3676
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003677 catal = (xmlCatalogEntryPtr) catalogs;
3678 if (catal == NULL)
3679 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003680 ret = xmlCatalogListXMLResolveURI(catal, URI);
3681 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3682 return(ret);
3683 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003684}
3685
Daniel Veillard75b96822001-10-11 18:59:45 +00003686/************************************************************************
3687 * *
3688 * Deprecated interfaces *
3689 * *
3690 ************************************************************************/
3691/**
3692 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003693 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003694 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003695 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003696 * DEPRECATED, use xmlCatalogResolveSystem()
3697 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003698 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003699 */
3700const xmlChar *
3701xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003702 xmlChar *ret;
3703 static xmlChar result[1000];
3704 static int msg = 0;
3705
3706 if (!xmlCatalogInitialized)
3707 xmlInitializeCatalog();
3708
3709 if (msg == 0) {
3710 xmlGenericError(xmlGenericErrorContext,
3711 "Use of deprecated xmlCatalogGetSystem() call\n");
3712 msg++;
3713 }
3714
3715 if (sysID == NULL)
3716 return(NULL);
3717
3718 /*
3719 * Check first the XML catalogs
3720 */
3721 if (xmlDefaultCatalog != NULL) {
3722 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3723 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3724 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3725 result[sizeof(result) - 1] = 0;
3726 return(result);
3727 }
3728 }
3729
3730 if (xmlDefaultCatalog != NULL)
3731 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3732 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003733}
3734
3735/**
3736 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003737 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003738 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003739 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003740 * DEPRECATED, use xmlCatalogResolvePublic()
3741 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003742 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003743 */
3744const xmlChar *
3745xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003746 xmlChar *ret;
3747 static xmlChar result[1000];
3748 static int msg = 0;
3749
3750 if (!xmlCatalogInitialized)
3751 xmlInitializeCatalog();
3752
3753 if (msg == 0) {
3754 xmlGenericError(xmlGenericErrorContext,
3755 "Use of deprecated xmlCatalogGetPublic() call\n");
3756 msg++;
3757 }
3758
3759 if (pubID == NULL)
3760 return(NULL);
3761
3762 /*
3763 * Check first the XML catalogs
3764 */
3765 if (xmlDefaultCatalog != NULL) {
3766 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3767 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3768 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3769 result[sizeof(result) - 1] = 0;
3770 return(result);
3771 }
3772 }
3773
3774 if (xmlDefaultCatalog != NULL)
3775 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3776 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003777}
3778
Daniel Veillarda7374592001-05-10 14:17:55 +00003779#endif /* LIBXML_CATALOG_ENABLED */