blob: 6ff22a1b1d704572001e9a10cb0cc89542bf74fd [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 Veillard85c11fa2001-10-16 21:03:08 +000071static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000072
Daniel Veillarda7374592001-05-10 14:17:55 +000073/************************************************************************
74 * *
75 * Types, all private *
76 * *
77 ************************************************************************/
78
79typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000080 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000081 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000082 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000083 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000084 XML_CATA_NEXT_CATALOG,
85 XML_CATA_PUBLIC,
86 XML_CATA_SYSTEM,
87 XML_CATA_REWRITE_SYSTEM,
88 XML_CATA_DELEGATE_PUBLIC,
89 XML_CATA_DELEGATE_SYSTEM,
90 XML_CATA_URI,
91 XML_CATA_REWRITE_URI,
92 XML_CATA_DELEGATE_URI,
93 SGML_CATA_SYSTEM,
94 SGML_CATA_PUBLIC,
95 SGML_CATA_ENTITY,
96 SGML_CATA_PENTITY,
97 SGML_CATA_DOCTYPE,
98 SGML_CATA_LINKTYPE,
99 SGML_CATA_NOTATION,
100 SGML_CATA_DELEGATE,
101 SGML_CATA_BASE,
102 SGML_CATA_CATALOG,
103 SGML_CATA_DOCUMENT,
104 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000105} xmlCatalogEntryType;
106
107typedef struct _xmlCatalogEntry xmlCatalogEntry;
108typedef xmlCatalogEntry *xmlCatalogEntryPtr;
109struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000110 struct _xmlCatalogEntry *next;
111 struct _xmlCatalogEntry *parent;
112 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000113 xmlCatalogEntryType type;
114 xmlChar *name;
115 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000116 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000117 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000118 int dealloc;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000119 int depth;
Daniel Veillarda7374592001-05-10 14:17:55 +0000120};
121
Daniel Veillard75b96822001-10-11 18:59:45 +0000122typedef enum {
123 XML_XML_CATALOG_TYPE = 1,
124 XML_SGML_CATALOG_TYPE
125} xmlCatalogType;
126
127#define XML_MAX_SGML_CATA_DEPTH 10
128struct _xmlCatalog {
129 xmlCatalogType type; /* either XML or SGML */
130
131 /*
132 * SGML Catalogs are stored as a simple hash table of catalog entries
133 * Catalog stack to check against overflows when building the
134 * SGML catalog
135 */
136 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
137 int catalNr; /* Number of current catal streams */
138 int catalMax; /* Max number of catal streams */
139 xmlHashTablePtr sgml;
140
141 /*
142 * XML Catalogs are stored as a tree of Catalog entries
143 */
144 xmlCatalogPrefer prefer;
145 xmlCatalogEntryPtr xml;
146};
147
148/************************************************************************
149 * *
150 * Global variables *
151 * *
152 ************************************************************************/
153
Daniel Veillard81463942001-10-16 12:34:39 +0000154/*
155 * Those are preferences
156 */
157static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000158static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000159static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000160
161/*
162 * Hash table containing all the trees of XML catalogs parsed by
163 * the application.
164 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000165static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000166
167/*
168 * The default catalog in use by the application
169 */
170static xmlCatalogPtr xmlDefaultCatalog = NULL;
171
172/*
Daniel Veillard81463942001-10-16 12:34:39 +0000173 * A mutex for modifying the shared global catalog(s)
174 * xmlDefaultCatalog tree.
175 * It also protects xmlCatalogXMLFiles
176 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
177 */
178static xmlRMutexPtr xmlCatalogMutex = NULL;
179
180/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000181 * Whether the catalog support was initialized.
182 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000183static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000184
Daniel Veillarda7374592001-05-10 14:17:55 +0000185
186/************************************************************************
187 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000188 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000189 * *
190 ************************************************************************/
191
Daniel Veillard75b96822001-10-11 18:59:45 +0000192/**
193 * xmlNewCatalogEntry:
194 * @type: type of entry
195 * @name: name of the entry
196 * @value: value of the entry
197 * @prefer: the PUBLIC vs. SYSTEM current preference value
198 *
199 * create a new Catalog entry, this type is shared both by XML and
200 * SGML catalogs, but the acceptable types values differs.
201 *
202 * Returns the xmlCatalogEntryPtr or NULL in case of error
203 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000204static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000205xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillardc853b322001-11-06 15:24:37 +0000206 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000207 xmlCatalogEntryPtr ret;
208
209 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
210 if (ret == NULL) {
211 xmlGenericError(xmlGenericErrorContext,
212 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
213 return(NULL);
214 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000215 ret->next = NULL;
216 ret->parent = NULL;
217 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000218 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000219 if (name != NULL)
220 ret->name = xmlStrdup(name);
221 else
222 ret->name = NULL;
223 if (value != NULL)
224 ret->value = xmlStrdup(value);
225 else
226 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000227 if (URL == NULL)
228 URL = value;
229 if (URL != NULL)
230 ret->URL = xmlStrdup(URL);
231 else
232 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000233 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000234 ret->dealloc = 0;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000235 ret->depth = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +0000236 return(ret);
237}
238
239static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000240xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
241
Daniel Veillard75b96822001-10-11 18:59:45 +0000242/**
243 * xmlFreeCatalogEntry:
244 * @ret: a Catalog entry
245 *
246 * Free the memory allocated to a Catalog entry
247 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000248static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000249xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
250 if (ret == NULL)
251 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000252 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000253 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000254 * only by the file hash cleaner !
255 */
256 if (ret->dealloc == 1)
257 return;
258
259 if (xmlDebugCatalogs) {
260 if (ret->name != NULL)
261 xmlGenericError(xmlGenericErrorContext,
262 "Free catalog entry %s\n", ret->name);
263 else if (ret->value != NULL)
264 xmlGenericError(xmlGenericErrorContext,
265 "Free catalog entry %s\n", ret->value);
266 else
267 xmlGenericError(xmlGenericErrorContext,
268 "Free catalog entry\n");
269 }
270
Daniel Veillarda7374592001-05-10 14:17:55 +0000271 if (ret->name != NULL)
272 xmlFree(ret->name);
273 if (ret->value != NULL)
274 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000275 if (ret->URL != NULL)
276 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000277 xmlFree(ret);
278}
279
Daniel Veillard75b96822001-10-11 18:59:45 +0000280/**
281 * xmlFreeCatalogEntryList:
282 * @ret: a Catalog entry list
283 *
284 * Free the memory allocated to a full chained list of Catalog entries
285 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000286static void
287xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
288 xmlCatalogEntryPtr next;
289
290 while (ret != NULL) {
291 next = ret->next;
292 xmlFreeCatalogEntry(ret);
293 ret = next;
294 }
295}
296
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000297/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000298 * xmlFreeCatalogHashEntryList:
299 * @ret: a Catalog entry list
300 *
301 * Free the memory allocated to list of Catalog entries from the
302 * catalog file hash.
303 */
304static void
305xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
306 xmlCatalogEntryPtr children, next;
307
308 if (catal == NULL)
309 return;
310
311 children = catal->children;
312 while (children != NULL) {
313 next = children->next;
314 children->dealloc = 0;
315 children->children = NULL;
316 xmlFreeCatalogEntry(children);
317 children = next;
318 }
319 catal->dealloc = 0;
320 xmlFreeCatalogEntry(catal);
321}
322
323/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000324 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000325 * @type: type of catalog
326 * @prefer: the PUBLIC vs. SYSTEM current preference value
327 *
328 * create a new Catalog, this type is shared both by XML and
329 * SGML catalogs, but the acceptable types values differs.
330 *
331 * Returns the xmlCatalogPtr or NULL in case of error
332 */
333static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000334xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000335 xmlCatalogPtr ret;
336
337 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
338 if (ret == NULL) {
339 xmlGenericError(xmlGenericErrorContext,
340 "malloc of %d byte failed\n", sizeof(xmlCatalog));
341 return(NULL);
342 }
343 memset(ret, 0, sizeof(xmlCatalog));
344 ret->type = type;
345 ret->catalNr = 0;
346 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
347 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000348 if (ret->type == XML_SGML_CATALOG_TYPE)
349 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000350 return(ret);
351}
352
353/**
354 * xmlFreeCatalog:
355 * @catal: a Catalog entry
356 *
357 * Free the memory allocated to a Catalog
358 */
359void
360xmlFreeCatalog(xmlCatalogPtr catal) {
361 if (catal == NULL)
362 return;
363 if (catal->xml != NULL)
364 xmlFreeCatalogEntryList(catal->xml);
365 if (catal->sgml != NULL)
366 xmlHashFree(catal->sgml,
367 (xmlHashDeallocator) xmlFreeCatalogEntry);
368 xmlFree(catal);
369}
370
371/************************************************************************
372 * *
373 * Serializing Catalogs *
374 * *
375 ************************************************************************/
376
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000377#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000378/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000379 * xmlCatalogDumpEntry:
380 * @entry: the
381 * @out: the file.
382 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000383 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000384 */
385static void
386xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
387 if ((entry == NULL) || (out == NULL))
388 return;
389 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000390 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000391 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000392 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000393 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000394 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000395 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000396 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000397 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000398 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000399 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000400 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000401 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000402 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000403 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000404 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000405 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000406 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000407 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000408 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000409 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000410 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000411 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000412 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000413 fprintf(out, "SGMLDECL "); break;
414 default:
415 return;
416 }
417 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000418 case SGML_CATA_ENTITY:
419 case SGML_CATA_PENTITY:
420 case SGML_CATA_DOCTYPE:
421 case SGML_CATA_LINKTYPE:
422 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000423 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000424 case SGML_CATA_PUBLIC:
425 case SGML_CATA_SYSTEM:
426 case SGML_CATA_SGMLDECL:
427 case SGML_CATA_DOCUMENT:
428 case SGML_CATA_CATALOG:
429 case SGML_CATA_BASE:
430 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000431 fprintf(out, "\"%s\"", entry->name); break;
432 default:
433 break;
434 }
435 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000436 case SGML_CATA_ENTITY:
437 case SGML_CATA_PENTITY:
438 case SGML_CATA_DOCTYPE:
439 case SGML_CATA_LINKTYPE:
440 case SGML_CATA_NOTATION:
441 case SGML_CATA_PUBLIC:
442 case SGML_CATA_SYSTEM:
443 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000444 fprintf(out, " \"%s\"", entry->value); break;
445 default:
446 break;
447 }
448 fprintf(out, "\n");
449}
450
Daniel Veillard75b96822001-10-11 18:59:45 +0000451static int
452xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
453 int ret;
454 xmlDocPtr doc;
455 xmlNsPtr ns;
456 xmlDtdPtr dtd;
457 xmlNodePtr node, catalog;
458 xmlOutputBufferPtr buf;
459 xmlCatalogEntryPtr cur;
460
461 /*
462 * Rebuild a catalog
463 */
464 doc = xmlNewDoc(NULL);
465 if (doc == NULL)
466 return(-1);
467 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
468 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
469BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
470
471 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
472
473 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
474 if (ns == NULL) {
475 xmlFreeDoc(doc);
476 return(-1);
477 }
478 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
479 if (catalog == NULL) {
480 xmlFreeNs(ns);
481 xmlFreeDoc(doc);
482 return(-1);
483 }
484 catalog->nsDef = ns;
485 xmlAddChild((xmlNodePtr) doc, catalog);
486
487 /*
488 * add all the catalog entries
489 */
490 cur = catal;
491 while (cur != NULL) {
492 switch (cur->type) {
Daniel Veillardc853b322001-11-06 15:24:37 +0000493 case XML_CATA_REMOVED:
494 break;
Daniel Veillard75b96822001-10-11 18:59:45 +0000495 case XML_CATA_BROKEN_CATALOG:
496 case XML_CATA_CATALOG:
497 if (cur == catal) {
498 cur = cur->children;
499 continue;
500 }
501 break;
502 case XML_CATA_NEXT_CATALOG:
503 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
504 xmlSetProp(node, BAD_CAST "catalog", cur->value);
505 xmlAddChild(catalog, node);
506 break;
507 case XML_CATA_NONE:
508 break;
509 case XML_CATA_PUBLIC:
510 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
511 xmlSetProp(node, BAD_CAST "publicId", cur->name);
512 xmlSetProp(node, BAD_CAST "uri", cur->value);
513 xmlAddChild(catalog, node);
514 break;
515 case XML_CATA_SYSTEM:
516 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
517 xmlSetProp(node, BAD_CAST "systemId", cur->name);
518 xmlSetProp(node, BAD_CAST "uri", cur->value);
519 xmlAddChild(catalog, node);
520 break;
521 case XML_CATA_REWRITE_SYSTEM:
522 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
523 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
524 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
525 xmlAddChild(catalog, node);
526 break;
527 case XML_CATA_DELEGATE_PUBLIC:
528 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
529 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
530 xmlSetProp(node, BAD_CAST "catalog", cur->value);
531 xmlAddChild(catalog, node);
532 break;
533 case XML_CATA_DELEGATE_SYSTEM:
534 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
535 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
536 xmlSetProp(node, BAD_CAST "catalog", cur->value);
537 xmlAddChild(catalog, node);
538 break;
539 case XML_CATA_URI:
540 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
541 xmlSetProp(node, BAD_CAST "name", cur->name);
542 xmlSetProp(node, BAD_CAST "uri", cur->value);
543 xmlAddChild(catalog, node);
544 break;
545 case XML_CATA_REWRITE_URI:
546 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
547 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
548 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
549 xmlAddChild(catalog, node);
550 break;
551 case XML_CATA_DELEGATE_URI:
552 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
553 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
554 xmlSetProp(node, BAD_CAST "catalog", cur->value);
555 xmlAddChild(catalog, node);
556 break;
557 case SGML_CATA_SYSTEM:
558 case SGML_CATA_PUBLIC:
559 case SGML_CATA_ENTITY:
560 case SGML_CATA_PENTITY:
561 case SGML_CATA_DOCTYPE:
562 case SGML_CATA_LINKTYPE:
563 case SGML_CATA_NOTATION:
564 case SGML_CATA_DELEGATE:
565 case SGML_CATA_BASE:
566 case SGML_CATA_CATALOG:
567 case SGML_CATA_DOCUMENT:
568 case SGML_CATA_SGMLDECL:
569 break;
570 }
571 cur = cur->next;
572 }
573
574 /*
575 * reserialize it
576 */
577 buf = xmlOutputBufferCreateFile(out, NULL);
578 if (buf == NULL) {
579 xmlFreeDoc(doc);
580 return(-1);
581 }
582 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
583
584 /*
585 * Free it
586 */
587 xmlFreeDoc(doc);
588
589 return(ret);
590}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000591#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000592
593/************************************************************************
594 * *
595 * Converting SGML Catalogs to XML *
596 * *
597 ************************************************************************/
598
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000599/**
600 * xmlCatalogConvertEntry:
601 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000602 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000603 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000604 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000605 */
606static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000607xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
608 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
609 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000610 return;
611 switch (entry->type) {
612 case SGML_CATA_ENTITY:
613 entry->type = XML_CATA_PUBLIC;
614 break;
615 case SGML_CATA_PENTITY:
616 entry->type = XML_CATA_PUBLIC;
617 break;
618 case SGML_CATA_DOCTYPE:
619 entry->type = XML_CATA_PUBLIC;
620 break;
621 case SGML_CATA_LINKTYPE:
622 entry->type = XML_CATA_PUBLIC;
623 break;
624 case SGML_CATA_NOTATION:
625 entry->type = XML_CATA_PUBLIC;
626 break;
627 case SGML_CATA_PUBLIC:
628 entry->type = XML_CATA_PUBLIC;
629 break;
630 case SGML_CATA_SYSTEM:
631 entry->type = XML_CATA_SYSTEM;
632 break;
633 case SGML_CATA_DELEGATE:
634 entry->type = XML_CATA_DELEGATE_PUBLIC;
635 break;
636 case SGML_CATA_CATALOG:
637 entry->type = XML_CATA_CATALOG;
638 break;
639 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000640 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000641 (xmlHashDeallocator) xmlFreeCatalogEntry);
642 return;
643 }
644 /*
645 * Conversion successful, remove from the SGML catalog
646 * and add it to the default XML one
647 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000648 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
649 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000650 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000651 if (catal->xml->children == NULL)
652 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000653 else {
654 xmlCatalogEntryPtr prev;
655
Daniel Veillard75b96822001-10-11 18:59:45 +0000656 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000657 while (prev->next != NULL)
658 prev = prev->next;
659 prev->next = entry;
660 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000661}
662
663/**
664 * xmlConvertSGMLCatalog:
665 * @catal: the catalog
666 *
667 * Convert all the SGML catalog entries as XML ones
668 *
669 * Returns the number of entries converted if successful, -1 otherwise
670 */
671int
672xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
673
674 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
675 return(-1);
676
677 if (xmlDebugCatalogs) {
678 xmlGenericError(xmlGenericErrorContext,
679 "Converting SGML catalog to XML\n");
680 }
681 xmlHashScan(catal->sgml,
682 (xmlHashScanner) xmlCatalogConvertEntry,
683 &catal);
684 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000685}
686
Daniel Veillarda7374592001-05-10 14:17:55 +0000687/************************************************************************
688 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000689 * Helper function *
690 * *
691 ************************************************************************/
692
693/**
694 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000695 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000696 *
697 * Expand the URN into the equivalent Public Identifier
698 *
699 * Returns the new identifier or NULL, the string must be deallocated
700 * by the caller.
701 */
702static xmlChar *
703xmlCatalogUnWrapURN(const xmlChar *urn) {
704 xmlChar result[2000];
705 unsigned int i = 0;
706
707 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
708 return(NULL);
709 urn += sizeof(XML_URN_PUBID) - 1;
710
711 while (*urn != 0) {
712 if (i > sizeof(result) - 3)
713 break;
714 if (*urn == '+') {
715 result[i++] = ' ';
716 urn++;
717 } else if (*urn == ':') {
718 result[i++] = '/';
719 result[i++] = '/';
720 urn++;
721 } else if (*urn == ';') {
722 result[i++] = ':';
723 result[i++] = ':';
724 urn++;
725 } else if (*urn == '%') {
726 if ((urn[1] == '2') && (urn[1] == 'B'))
727 result[i++] = '+';
728 else if ((urn[1] == '3') && (urn[1] == 'A'))
729 result[i++] = ':';
730 else if ((urn[1] == '2') && (urn[1] == 'F'))
731 result[i++] = '/';
732 else if ((urn[1] == '3') && (urn[1] == 'B'))
733 result[i++] = ';';
734 else if ((urn[1] == '2') && (urn[1] == '7'))
735 result[i++] = '\'';
736 else if ((urn[1] == '3') && (urn[1] == 'F'))
737 result[i++] = '?';
738 else if ((urn[1] == '2') && (urn[1] == '3'))
739 result[i++] = '#';
740 else if ((urn[1] == '2') && (urn[1] == '5'))
741 result[i++] = '%';
742 else {
743 result[i++] = *urn;
744 urn++;
745 continue;
746 }
747 urn += 3;
748 } else {
749 result[i++] = *urn;
750 urn++;
751 }
752 }
753 result[i] = 0;
754
755 return(xmlStrdup(result));
756}
757
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000758/**
759 * xmlParseCatalogFile:
760 * @filename: the filename
761 *
762 * parse an XML file and build a tree. It's like xmlParseFile()
763 * except it bypass all catalog lookups.
764 *
765 * Returns the resulting document tree or NULL in case of error
766 */
767
768xmlDocPtr
769xmlParseCatalogFile(const char *filename) {
770 xmlDocPtr ret;
771 xmlParserCtxtPtr ctxt;
772 char *directory = NULL;
773 xmlParserInputPtr inputStream;
774 xmlParserInputBufferPtr buf;
775
776 ctxt = xmlNewParserCtxt();
777 if (ctxt == NULL) {
778 if (xmlDefaultSAXHandler.error != NULL) {
779 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
780 }
781 return(NULL);
782 }
783
784 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
785 if (buf == NULL) {
786 xmlFreeParserCtxt(ctxt);
787 return(NULL);
788 }
789
790 inputStream = xmlNewInputStream(ctxt);
791 if (inputStream == NULL) {
792 xmlFreeParserCtxt(ctxt);
793 return(NULL);
794 }
795
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000796 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000797 inputStream->buf = buf;
798 inputStream->base = inputStream->buf->buffer->content;
799 inputStream->cur = inputStream->buf->buffer->content;
800 inputStream->end =
801 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
802
803 inputPush(ctxt, inputStream);
804 if ((ctxt->directory == NULL) && (directory == NULL))
805 directory = xmlParserGetDirectory(filename);
806 if ((ctxt->directory == NULL) && (directory != NULL))
807 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000808 ctxt->valid = 0;
809 ctxt->validate = 0;
810 ctxt->loadsubset = 0;
811 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000812
813 xmlParseDocument(ctxt);
814
815 if (ctxt->wellFormed)
816 ret = ctxt->myDoc;
817 else {
818 ret = NULL;
819 xmlFreeDoc(ctxt->myDoc);
820 ctxt->myDoc = NULL;
821 }
822 xmlFreeParserCtxt(ctxt);
823
824 return(ret);
825}
826
Daniel Veillard75b96822001-10-11 18:59:45 +0000827/**
828 * xmlLoadFileContent:
829 * @filename: a file path
830 *
831 * Load a file content into memory.
832 *
833 * Returns a pointer to the 0 terminated string or NULL in case of error
834 */
835static xmlChar *
836xmlLoadFileContent(const char *filename)
837{
838#ifdef HAVE_STAT
839 int fd;
840#else
841 FILE *fd;
842#endif
843 int len;
844 long size;
845
846#ifdef HAVE_STAT
847 struct stat info;
848#endif
849 xmlChar *content;
850
851 if (filename == NULL)
852 return (NULL);
853
854#ifdef HAVE_STAT
855 if (stat(filename, &info) < 0)
856 return (NULL);
857#endif
858
859#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000860 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000861#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000862 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000863#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000864 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000865 return (NULL);
866 }
867#ifdef HAVE_STAT
868 size = info.st_size;
869#else
870 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
871 fclose(fd);
872 return (NULL);
873 }
874#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000875 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000876 if (content == NULL) {
877 xmlGenericError(xmlGenericErrorContext,
878 "malloc of %d byte failed\n", size + 10);
879 return (NULL);
880 }
881#ifdef HAVE_STAT
882 len = read(fd, content, size);
883#else
884 len = fread(content, 1, size, fd);
885#endif
886 if (len < 0) {
887 xmlFree(content);
888 return (NULL);
889 }
890#ifdef HAVE_STAT
891 close(fd);
892#else
893 fclose(fd);
894#endif
895 content[len] = 0;
896
897 return(content);
898}
899
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000900/************************************************************************
901 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000902 * The XML Catalog parser *
903 * *
904 ************************************************************************/
905
906static xmlCatalogEntryPtr
907xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000908static void
909xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
910 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000911static xmlChar *
912xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
913 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000914static xmlChar *
915xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
916
Daniel Veillard344cee72001-08-20 00:08:40 +0000917
Daniel Veillard75b96822001-10-11 18:59:45 +0000918/**
919 * xmlGetXMLCatalogEntryType:
920 * @name: the name
921 *
922 * lookup the internal type associated to an XML catalog entry name
923 *
924 * Returns the type associate with that name
925 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000926static xmlCatalogEntryType
927xmlGetXMLCatalogEntryType(const xmlChar *name) {
928 xmlCatalogEntryType type = XML_CATA_NONE;
929 if (xmlStrEqual(name, (const xmlChar *) "system"))
930 type = XML_CATA_SYSTEM;
931 else if (xmlStrEqual(name, (const xmlChar *) "public"))
932 type = XML_CATA_PUBLIC;
933 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
934 type = XML_CATA_REWRITE_SYSTEM;
935 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
936 type = XML_CATA_DELEGATE_PUBLIC;
937 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
938 type = XML_CATA_DELEGATE_SYSTEM;
939 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
940 type = XML_CATA_URI;
941 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
942 type = XML_CATA_REWRITE_URI;
943 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
944 type = XML_CATA_DELEGATE_URI;
945 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
946 type = XML_CATA_NEXT_CATALOG;
947 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
948 type = XML_CATA_CATALOG;
949 return(type);
950}
951
Daniel Veillard75b96822001-10-11 18:59:45 +0000952/**
953 * xmlParseXMLCatalogOneNode:
954 * @cur: the XML node
955 * @type: the type of Catalog entry
956 * @name: the name of the node
957 * @attrName: the attribute holding the value
958 * @uriAttrName: the attribute holding the URI-Reference
959 * @prefer: the PUBLIC vs. SYSTEM current preference value
960 *
961 * Finishes the examination of an XML tree node of a catalog and build
962 * a Catalog entry from it.
963 *
964 * Returns the new Catalog entry node or NULL in case of error.
965 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000966static xmlCatalogEntryPtr
967xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
968 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000969 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000970 int ok = 1;
971 xmlChar *uriValue;
972 xmlChar *nameValue = NULL;
973 xmlChar *base = NULL;
974 xmlChar *URL = NULL;
975 xmlCatalogEntryPtr ret = NULL;
976
977 if (attrName != NULL) {
978 nameValue = xmlGetProp(cur, attrName);
979 if (nameValue == NULL) {
980 xmlGenericError(xmlGenericErrorContext,
981 "%s entry lacks '%s'\n", name, attrName);
982 ok = 0;
983 }
984 }
985 uriValue = xmlGetProp(cur, uriAttrName);
986 if (uriValue == NULL) {
987 xmlGenericError(xmlGenericErrorContext,
988 "%s entry lacks '%s'\n", name, uriAttrName);
989 ok = 0;
990 }
991 if (!ok) {
992 if (nameValue != NULL)
993 xmlFree(nameValue);
994 if (uriValue != NULL)
995 xmlFree(uriValue);
996 return(NULL);
997 }
998
999 base = xmlNodeGetBase(cur->doc, cur);
1000 URL = xmlBuildURI(uriValue, base);
1001 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001002 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001003 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001004 xmlGenericError(xmlGenericErrorContext,
1005 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001006 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001007 xmlGenericError(xmlGenericErrorContext,
1008 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001009 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001010 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001011 } else {
1012 xmlGenericError(xmlGenericErrorContext,
1013 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1014 }
1015 if (nameValue != NULL)
1016 xmlFree(nameValue);
1017 if (uriValue != NULL)
1018 xmlFree(uriValue);
1019 if (base != NULL)
1020 xmlFree(base);
1021 if (URL != NULL)
1022 xmlFree(URL);
1023 return(ret);
1024}
1025
Daniel Veillard75b96822001-10-11 18:59:45 +00001026/**
1027 * xmlParseXMLCatalogNode:
1028 * @cur: the XML node
1029 * @prefer: the PUBLIC vs. SYSTEM current preference value
1030 * @parent: the parent Catalog entry
1031 *
1032 * Examines an XML tree node of a catalog and build
1033 * a Catalog entry from it adding it to its parent. The examination can
1034 * be recursive.
1035 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001036static void
1037xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1038 xmlCatalogEntryPtr parent)
1039{
1040 xmlChar *uri = NULL;
1041 xmlChar *URL = NULL;
1042 xmlChar *base = NULL;
1043 xmlCatalogEntryPtr entry = NULL;
1044
1045 if (cur == NULL)
1046 return;
1047 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1048 xmlChar *prop;
1049
1050 prop = xmlGetProp(cur, BAD_CAST "prefer");
1051 if (prop != NULL) {
1052 if (xmlStrEqual(prop, BAD_CAST "system")) {
1053 prefer = XML_CATA_PREFER_SYSTEM;
1054 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1055 prefer = XML_CATA_PREFER_PUBLIC;
1056 } else {
1057 xmlGenericError(xmlGenericErrorContext,
1058 "Invalid value for prefer: '%s'\n", prop);
1059 }
1060 xmlFree(prop);
1061 }
1062 /*
1063 * Recurse to propagate prefer to the subtree
1064 * (xml:base handling is automated)
1065 */
1066 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1067 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1068 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001069 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001070 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1071 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001072 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001073 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1074 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1075 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001076 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001077 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1078 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1079 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001080 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001081 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1082 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1083 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001084 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001085 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1086 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1087 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001088 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001089 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1090 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1091 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001092 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001093 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1094 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1095 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001096 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001097 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1098 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1099 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001100 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001101 }
1102 if ((entry != NULL) && (parent != NULL)) {
1103 entry->parent = parent;
1104 if (parent->children == NULL)
1105 parent->children = entry;
1106 else {
1107 xmlCatalogEntryPtr prev;
1108
1109 prev = parent->children;
1110 while (prev->next != NULL)
1111 prev = prev->next;
1112 prev->next = entry;
1113 }
1114 }
1115 if (base != NULL)
1116 xmlFree(base);
1117 if (uri != NULL)
1118 xmlFree(uri);
1119 if (URL != NULL)
1120 xmlFree(URL);
1121}
1122
Daniel Veillard75b96822001-10-11 18:59:45 +00001123/**
1124 * xmlParseXMLCatalogNodeList:
1125 * @cur: the XML node list of siblings
1126 * @prefer: the PUBLIC vs. SYSTEM current preference value
1127 * @parent: the parent Catalog entry
1128 *
1129 * Examines a list of XML sibling nodes of a catalog and build
1130 * a list of Catalog entry from it adding it to the parent.
1131 * The examination will recurse to examine node subtrees.
1132 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001133static void
1134xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1135 xmlCatalogEntryPtr parent) {
1136 while (cur != NULL) {
1137 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1138 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1139 xmlParseXMLCatalogNode(cur, prefer, parent);
1140 }
1141 cur = cur->next;
1142 }
1143 /* TODO: sort the list according to REWRITE lengths and prefer value */
1144}
1145
Daniel Veillard75b96822001-10-11 18:59:45 +00001146/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001147 * xmlParseXMLCatalogFile:
1148 * @prefer: the PUBLIC vs. SYSTEM current preference value
1149 * @filename: the filename for the catalog
1150 *
1151 * Parses the catalog file to extract the XML tree and then analyze the
1152 * tree to build a list of Catalog entries corresponding to this catalog
1153 *
1154 * Returns the resulting Catalog entries list
1155 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001156static xmlCatalogEntryPtr
1157xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1158 xmlDocPtr doc;
1159 xmlNodePtr cur;
1160 xmlChar *prop;
1161 xmlCatalogEntryPtr parent = NULL;
1162
1163 if (filename == NULL)
1164 return(NULL);
1165
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001166 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001167 if (doc == NULL) {
1168 if (xmlDebugCatalogs)
1169 xmlGenericError(xmlGenericErrorContext,
1170 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001171 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001172 }
1173
1174 if (xmlDebugCatalogs)
1175 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001176 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001177
1178 cur = xmlDocGetRootElement(doc);
1179 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1180 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1181 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1182
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001183 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00001184 (const xmlChar *)filename, NULL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001185 if (parent == NULL) {
1186 xmlFreeDoc(doc);
1187 return(NULL);
1188 }
1189
1190 prop = xmlGetProp(cur, BAD_CAST "prefer");
1191 if (prop != NULL) {
1192 if (xmlStrEqual(prop, BAD_CAST "system")) {
1193 prefer = XML_CATA_PREFER_SYSTEM;
1194 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1195 prefer = XML_CATA_PREFER_PUBLIC;
1196 } else {
1197 xmlGenericError(xmlGenericErrorContext,
1198 "Invalid value for prefer: '%s'\n",
1199 prop);
1200 }
1201 xmlFree(prop);
1202 }
1203 cur = cur->children;
1204 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1205 } else {
1206 xmlGenericError(xmlGenericErrorContext,
1207 "File %s is not an XML Catalog\n", filename);
1208 xmlFreeDoc(doc);
1209 return(NULL);
1210 }
1211 xmlFreeDoc(doc);
1212 return(parent);
1213}
1214
Daniel Veillardcda96922001-08-21 10:56:31 +00001215/**
1216 * xmlFetchXMLCatalogFile:
1217 * @catal: an existing but incomplete catalog entry
1218 *
1219 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001220 *
1221 * Returns 0 in case of success, -1 otherwise
1222 */
1223static int
1224xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001225 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001226
1227 if (catal == NULL)
1228 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001229 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001230 return(-1);
1231 if (catal->children != NULL)
1232 return(-1);
1233
Daniel Veillard81463942001-10-16 12:34:39 +00001234 /*
1235 * lock the whole catalog for modification
1236 */
1237 xmlRMutexLock(xmlCatalogMutex);
1238 if (catal->children != NULL) {
1239 /* Okay someone else did it in the meantime */
1240 xmlRMutexUnlock(xmlCatalogMutex);
1241 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001242 }
1243
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001244 if (xmlCatalogXMLFiles != NULL) {
1245 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001246 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001247 if (doc != NULL) {
1248 if (xmlDebugCatalogs)
1249 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001250 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001251
1252 if (catal->type == XML_CATA_CATALOG)
1253 catal->children = doc->children;
1254 else
1255 catal->children = doc;
1256 catal->dealloc = 0;
1257 xmlRMutexUnlock(xmlCatalogMutex);
1258 return(0);
1259 }
1260 if (xmlDebugCatalogs)
1261 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001262 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001263 }
1264
Daniel Veillardcda96922001-08-21 10:56:31 +00001265 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001266 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001267 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001268 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001269 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001270 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001271 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001272 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001273 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001274 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001275 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001276
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001277 if (catal->type == XML_CATA_CATALOG)
1278 catal->children = doc->children;
1279 else
1280 catal->children = doc;
1281
1282 doc->dealloc = 1;
1283
Daniel Veillard81463942001-10-16 12:34:39 +00001284 if (xmlCatalogXMLFiles == NULL)
1285 xmlCatalogXMLFiles = xmlHashCreate(10);
1286 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001287 if (xmlDebugCatalogs)
1288 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001289 "%s added to file hash\n", catal->URL);
1290 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001291 }
Daniel Veillard81463942001-10-16 12:34:39 +00001292 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001293 return(0);
1294}
1295
Daniel Veillard75b96822001-10-11 18:59:45 +00001296/************************************************************************
1297 * *
1298 * XML Catalog handling *
1299 * *
1300 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001301
1302/**
1303 * xmlAddXMLCatalog:
1304 * @catal: top of an XML catalog
1305 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001306 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001307 * @replace: the replacement value for the match
1308 *
1309 * Add an entry in the XML catalog, it may overwrite existing but
1310 * different entries.
1311 *
1312 * Returns 0 if successful, -1 otherwise
1313 */
1314static int
1315xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1316 const xmlChar *orig, const xmlChar *replace) {
1317 xmlCatalogEntryPtr cur;
1318 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001319 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001320
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001321 if ((catal == NULL) ||
1322 ((catal->type != XML_CATA_CATALOG) &&
1323 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001324 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001325 if (catal->children == NULL) {
1326 xmlFetchXMLCatalogFile(catal);
1327 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001328 if (catal->children == NULL)
1329 doregister = 1;
1330
Daniel Veillard344cee72001-08-20 00:08:40 +00001331 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001332 if (typ == XML_CATA_NONE) {
1333 if (xmlDebugCatalogs)
1334 xmlGenericError(xmlGenericErrorContext,
1335 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001336 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001337 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001338
1339 cur = catal->children;
1340 /*
1341 * Might be a simple "update in place"
1342 */
1343 if (cur != NULL) {
1344 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001345 if ((orig != NULL) && (cur->type == typ) &&
1346 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001347 if (xmlDebugCatalogs)
1348 xmlGenericError(xmlGenericErrorContext,
1349 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001350 if (cur->value != NULL)
1351 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001352 if (cur->URL != NULL)
1353 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001354 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001355 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001356 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001357 }
1358 if (cur->next == NULL)
1359 break;
1360 cur = cur->next;
1361 }
1362 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001363 if (xmlDebugCatalogs)
1364 xmlGenericError(xmlGenericErrorContext,
1365 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001366 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001367 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1368 NULL, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001369 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001370 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1371 NULL, catal->prefer);
1372 if (doregister) {
1373 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1374 if (cur != NULL)
1375 cur->children = catal->children;
1376 }
1377
Daniel Veillardcda96922001-08-21 10:56:31 +00001378 return(0);
1379}
1380
1381/**
1382 * xmlDelXMLCatalog:
1383 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001384 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001385 *
1386 * Remove entries in the XML catalog where the value or the URI
1387 * is equal to @value
1388 *
1389 * Returns the number of entries removed if successful, -1 otherwise
1390 */
1391static int
1392xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001393 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001394 int ret = 0;
1395
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001396 if ((catal == NULL) ||
1397 ((catal->type != XML_CATA_CATALOG) &&
1398 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001399 return(-1);
1400 if (value == NULL)
1401 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001402 if (catal->children == NULL) {
1403 xmlFetchXMLCatalogFile(catal);
1404 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001405
1406 /*
1407 * Scan the children
1408 */
1409 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001410 while (cur != NULL) {
1411 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1412 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001413 if (xmlDebugCatalogs) {
1414 if (cur->name != NULL)
1415 xmlGenericError(xmlGenericErrorContext,
1416 "Removing element %s from catalog\n", cur->name);
1417 else
1418 xmlGenericError(xmlGenericErrorContext,
1419 "Removing element %s from catalog\n", cur->value);
1420 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001421 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001422 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001423 cur = cur->next;
1424 }
1425 return(ret);
1426}
1427
1428/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001429 * xmlCatalogXMLResolve:
1430 * @catal: a catalog list
1431 * @pubId: the public ID string
1432 * @sysId: the system ID string
1433 *
1434 * Do a complete resolution lookup of an External Identifier for a
1435 * list of catalog entries.
1436 *
1437 * Implements (or tries to) 7.1. External Identifier Resolution
1438 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1439 *
1440 * Returns the URI of the resource or NULL if not found
1441 */
1442static xmlChar *
1443xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1444 const xmlChar *sysID) {
1445 xmlChar *ret = NULL;
1446 xmlCatalogEntryPtr cur;
1447 int haveDelegate = 0;
1448 int haveNext = 0;
1449
1450 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001451 * protection against loops
1452 */
1453 if (catal->depth > MAX_CATAL_DEPTH) {
1454 if (catal->name != NULL)
1455 xmlGenericError(xmlGenericErrorContext,
1456 "Detected recursion in catalog %s\n", catal->name);
1457 else
1458 xmlGenericError(xmlGenericErrorContext,
1459 "Detected recursion in catalog\n");
1460 return(NULL);
1461 }
1462 catal->depth++;
1463
1464 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001465 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1466 */
1467 if (sysID != NULL) {
1468 xmlCatalogEntryPtr rewrite = NULL;
1469 int lenrewrite = 0, len;
1470 cur = catal;
1471 haveDelegate = 0;
1472 while (cur != NULL) {
1473 switch (cur->type) {
1474 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001475 if (xmlStrEqual(sysID, cur->name)) {
1476 if (xmlDebugCatalogs)
1477 xmlGenericError(xmlGenericErrorContext,
1478 "Found system match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001479 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001480 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001481 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001482 break;
1483 case XML_CATA_REWRITE_SYSTEM:
1484 len = xmlStrlen(cur->name);
1485 if ((len > lenrewrite) &&
1486 (!xmlStrncmp(sysID, cur->name, len))) {
1487 lenrewrite = len;
1488 rewrite = cur;
1489 }
1490 break;
1491 case XML_CATA_DELEGATE_SYSTEM:
1492 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1493 haveDelegate++;
1494 break;
1495 case XML_CATA_NEXT_CATALOG:
1496 haveNext++;
1497 break;
1498 default:
1499 break;
1500 }
1501 cur = cur->next;
1502 }
1503 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001504 if (xmlDebugCatalogs)
1505 xmlGenericError(xmlGenericErrorContext,
1506 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001507 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001508 if (ret != NULL)
1509 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001510 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001511 return(ret);
1512 }
1513 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001514 const xmlChar *delegates[MAX_DELEGATE];
1515 int nbList = 0, i;
1516
Daniel Veillardcda96922001-08-21 10:56:31 +00001517 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001518 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001519 * matches when the list was produced.
1520 */
1521 cur = catal;
1522 while (cur != NULL) {
1523 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1524 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001525 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001526 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001527 break;
1528 if (i < nbList) {
1529 cur = cur->next;
1530 continue;
1531 }
1532 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001533 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001534
Daniel Veillardcda96922001-08-21 10:56:31 +00001535 if (cur->children == NULL) {
1536 xmlFetchXMLCatalogFile(cur);
1537 }
1538 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001539 if (xmlDebugCatalogs)
1540 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001541 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001542 ret = xmlCatalogListXMLResolve(
1543 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001544 if (ret != NULL) {
1545 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001546 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001547 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001548 }
1549 }
1550 cur = cur->next;
1551 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001552 /*
1553 * Apply the cut algorithm explained in 4/
1554 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001555 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001556 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001557 }
1558 }
1559 /*
1560 * Then tries 5/ 6/ if a public ID is provided
1561 */
1562 if (pubID != NULL) {
1563 cur = catal;
1564 haveDelegate = 0;
1565 while (cur != NULL) {
1566 switch (cur->type) {
1567 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001568 if (xmlStrEqual(pubID, cur->name)) {
1569 if (xmlDebugCatalogs)
1570 xmlGenericError(xmlGenericErrorContext,
1571 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001572 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001573 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001574 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001575 break;
1576 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001577 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1578 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001579 haveDelegate++;
1580 break;
1581 case XML_CATA_NEXT_CATALOG:
1582 if (sysID == NULL)
1583 haveNext++;
1584 break;
1585 default:
1586 break;
1587 }
1588 cur = cur->next;
1589 }
1590 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001591 const xmlChar *delegates[MAX_DELEGATE];
1592 int nbList = 0, i;
1593
Daniel Veillardcda96922001-08-21 10:56:31 +00001594 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001595 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001596 * matches when the list was produced.
1597 */
1598 cur = catal;
1599 while (cur != NULL) {
1600 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001601 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1602 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001603
1604 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001605 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001606 break;
1607 if (i < nbList) {
1608 cur = cur->next;
1609 continue;
1610 }
1611 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001612 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001613
Daniel Veillardcda96922001-08-21 10:56:31 +00001614 if (cur->children == NULL) {
1615 xmlFetchXMLCatalogFile(cur);
1616 }
1617 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001618 if (xmlDebugCatalogs)
1619 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001620 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001621 ret = xmlCatalogListXMLResolve(
1622 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001623 if (ret != NULL) {
1624 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001625 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001626 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001627 }
1628 }
1629 cur = cur->next;
1630 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001631 /*
1632 * Apply the cut algorithm explained in 4/
1633 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001634 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001635 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001636 }
1637 }
1638 if (haveNext) {
1639 cur = catal;
1640 while (cur != NULL) {
1641 if (cur->type == XML_CATA_NEXT_CATALOG) {
1642 if (cur->children == NULL) {
1643 xmlFetchXMLCatalogFile(cur);
1644 }
1645 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001646 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001647 if (ret != NULL) {
1648 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001649 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001650 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001651 }
1652 }
1653 cur = cur->next;
1654 }
1655 }
1656
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001657 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001658 return(NULL);
1659}
1660
1661/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001662 * xmlCatalogXMLResolveURI:
1663 * @catal: a catalog list
1664 * @URI: the URI
1665 * @sysId: the system ID string
1666 *
1667 * Do a complete resolution lookup of an External Identifier for a
1668 * list of catalog entries.
1669 *
1670 * Implements (or tries to) 7.2.2. URI Resolution
1671 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1672 *
1673 * Returns the URI of the resource or NULL if not found
1674 */
1675static xmlChar *
1676xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1677 xmlChar *ret = NULL;
1678 xmlCatalogEntryPtr cur;
1679 int haveDelegate = 0;
1680 int haveNext = 0;
1681 xmlCatalogEntryPtr rewrite = NULL;
1682 int lenrewrite = 0, len;
1683
1684 if (catal == NULL)
1685 return(NULL);
1686
1687 if (URI == NULL)
1688 return(NULL);
1689
1690 /*
1691 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1692 */
1693 cur = catal;
1694 haveDelegate = 0;
1695 while (cur != NULL) {
1696 switch (cur->type) {
1697 case XML_CATA_URI:
1698 if (xmlStrEqual(URI, cur->name)) {
1699 if (xmlDebugCatalogs)
1700 xmlGenericError(xmlGenericErrorContext,
1701 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001702 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001703 }
1704 break;
1705 case XML_CATA_REWRITE_URI:
1706 len = xmlStrlen(cur->name);
1707 if ((len > lenrewrite) &&
1708 (!xmlStrncmp(URI, cur->name, len))) {
1709 lenrewrite = len;
1710 rewrite = cur;
1711 }
1712 break;
1713 case XML_CATA_DELEGATE_URI:
1714 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1715 haveDelegate++;
1716 break;
1717 case XML_CATA_NEXT_CATALOG:
1718 haveNext++;
1719 break;
1720 default:
1721 break;
1722 }
1723 cur = cur->next;
1724 }
1725 if (rewrite != NULL) {
1726 if (xmlDebugCatalogs)
1727 xmlGenericError(xmlGenericErrorContext,
1728 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001729 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001730 if (ret != NULL)
1731 ret = xmlStrcat(ret, &URI[lenrewrite]);
1732 return(ret);
1733 }
1734 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001735 const xmlChar *delegates[MAX_DELEGATE];
1736 int nbList = 0, i;
1737
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001738 /*
1739 * Assume the entries have been sorted by decreasing substring
1740 * matches when the list was produced.
1741 */
1742 cur = catal;
1743 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001744 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1745 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001746 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001747 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001748 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001749 break;
1750 if (i < nbList) {
1751 cur = cur->next;
1752 continue;
1753 }
1754 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001755 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001756
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001757 if (cur->children == NULL) {
1758 xmlFetchXMLCatalogFile(cur);
1759 }
1760 if (cur->children != NULL) {
1761 if (xmlDebugCatalogs)
1762 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001763 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001764 ret = xmlCatalogListXMLResolveURI(
1765 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001766 if (ret != NULL)
1767 return(ret);
1768 }
1769 }
1770 cur = cur->next;
1771 }
1772 /*
1773 * Apply the cut algorithm explained in 4/
1774 */
1775 return(XML_CATAL_BREAK);
1776 }
1777 if (haveNext) {
1778 cur = catal;
1779 while (cur != NULL) {
1780 if (cur->type == XML_CATA_NEXT_CATALOG) {
1781 if (cur->children == NULL) {
1782 xmlFetchXMLCatalogFile(cur);
1783 }
1784 if (cur->children != NULL) {
1785 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1786 if (ret != NULL)
1787 return(ret);
1788 }
1789 }
1790 cur = cur->next;
1791 }
1792 }
1793
1794 return(NULL);
1795}
1796
1797/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001798 * xmlCatalogListXMLResolve:
1799 * @catal: a catalog list
1800 * @pubId: the public ID string
1801 * @sysId: the system ID string
1802 *
1803 * Do a complete resolution lookup of an External Identifier for a
1804 * list of catalogs
1805 *
1806 * Implements (or tries to) 7.1. External Identifier Resolution
1807 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1808 *
1809 * Returns the URI of the resource or NULL if not found
1810 */
1811static xmlChar *
1812xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1813 const xmlChar *sysID) {
1814 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001815 xmlChar *urnID = NULL;
1816
1817 if (catal == NULL)
1818 return(NULL);
1819 if ((pubID == NULL) && (sysID == NULL))
1820 return(NULL);
1821
1822 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1823 urnID = xmlCatalogUnWrapURN(pubID);
1824 if (xmlDebugCatalogs) {
1825 if (urnID == NULL)
1826 xmlGenericError(xmlGenericErrorContext,
1827 "Public URN ID %s expanded to NULL\n", pubID);
1828 else
1829 xmlGenericError(xmlGenericErrorContext,
1830 "Public URN ID expanded to %s\n", urnID);
1831 }
1832 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1833 if (urnID != NULL)
1834 xmlFree(urnID);
1835 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001836 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001837 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1838 urnID = xmlCatalogUnWrapURN(sysID);
1839 if (xmlDebugCatalogs) {
1840 if (urnID == NULL)
1841 xmlGenericError(xmlGenericErrorContext,
1842 "System URN ID %s expanded to NULL\n", sysID);
1843 else
1844 xmlGenericError(xmlGenericErrorContext,
1845 "System URN ID expanded to %s\n", urnID);
1846 }
1847 if (pubID == NULL)
1848 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1849 else if (xmlStrEqual(pubID, urnID))
1850 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1851 else {
1852 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1853 }
1854 if (urnID != NULL)
1855 xmlFree(urnID);
1856 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001857 }
1858 while (catal != NULL) {
1859 if (catal->type == XML_CATA_CATALOG) {
1860 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001861 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001862 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001863 if (catal->children != NULL) {
1864 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1865 if (ret != NULL)
1866 return(ret);
1867 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001868 }
1869 catal = catal->next;
1870 }
1871 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001872}
1873
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001874/**
1875 * xmlCatalogListXMLResolveURI:
1876 * @catal: a catalog list
1877 * @URI: the URI
1878 *
1879 * Do a complete resolution lookup of an URI for a list of catalogs
1880 *
1881 * Implements (or tries to) 7.2. URI Resolution
1882 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1883 *
1884 * Returns the URI of the resource or NULL if not found
1885 */
1886static xmlChar *
1887xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1888 xmlChar *ret = NULL;
1889 xmlChar *urnID = NULL;
1890
1891 if (catal == NULL)
1892 return(NULL);
1893 if (URI == NULL)
1894 return(NULL);
1895
1896 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1897 urnID = xmlCatalogUnWrapURN(URI);
1898 if (xmlDebugCatalogs) {
1899 if (urnID == NULL)
1900 xmlGenericError(xmlGenericErrorContext,
1901 "URN ID %s expanded to NULL\n", URI);
1902 else
1903 xmlGenericError(xmlGenericErrorContext,
1904 "URN ID expanded to %s\n", urnID);
1905 }
1906 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1907 if (urnID != NULL)
1908 xmlFree(urnID);
1909 return(ret);
1910 }
1911 while (catal != NULL) {
1912 if (catal->type == XML_CATA_CATALOG) {
1913 if (catal->children == NULL) {
1914 xmlFetchXMLCatalogFile(catal);
1915 }
1916 if (catal->children != NULL) {
1917 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1918 if (ret != NULL)
1919 return(ret);
1920 }
1921 }
1922 catal = catal->next;
1923 }
1924 return(ret);
1925}
1926
Daniel Veillard344cee72001-08-20 00:08:40 +00001927/************************************************************************
1928 * *
1929 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001930 * *
1931 ************************************************************************/
1932
1933
1934#define RAW *cur
1935#define NEXT cur++;
1936#define SKIP(x) cur += x;
1937
1938#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1939
Daniel Veillard75b96822001-10-11 18:59:45 +00001940/**
1941 * xmlParseSGMLCatalogComment:
1942 * @cur: the current character
1943 *
1944 * Skip a comment in an SGML catalog
1945 *
1946 * Returns new current character
1947 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001948static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001949xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001950 if ((cur[0] != '-') || (cur[1] != '-'))
1951 return(cur);
1952 SKIP(2);
1953 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1954 NEXT;
1955 if (cur[0] == 0) {
1956 return(NULL);
1957 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001958 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001959}
1960
Daniel Veillard75b96822001-10-11 18:59:45 +00001961/**
1962 * xmlParseSGMLCatalogPubid:
1963 * @cur: the current character
1964 * @id: the return location
1965 *
1966 * Parse an SGML catalog ID
1967 *
1968 * Returns new current character and store the value in @id
1969 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001970static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001971xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001972 xmlChar *buf = NULL;
1973 int len = 0;
1974 int size = 50;
1975 xmlChar stop;
1976 int count = 0;
1977
1978 *id = NULL;
1979
1980 if (RAW == '"') {
1981 NEXT;
1982 stop = '"';
1983 } else if (RAW == '\'') {
1984 NEXT;
1985 stop = '\'';
1986 } else {
1987 stop = ' ';
1988 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00001989 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00001990 if (buf == NULL) {
1991 xmlGenericError(xmlGenericErrorContext,
1992 "malloc of %d byte failed\n", size);
1993 return(NULL);
1994 }
Daniel Veillard935494a2002-10-22 14:22:46 +00001995 while (xmlIsPubidChar(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001996 if ((*cur == stop) && (stop != ' '))
1997 break;
1998 if ((stop == ' ') && (IS_BLANK(*cur)))
1999 break;
2000 if (len + 1 >= size) {
2001 size *= 2;
2002 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2003 if (buf == NULL) {
2004 xmlGenericError(xmlGenericErrorContext,
2005 "realloc of %d byte failed\n", size);
2006 return(NULL);
2007 }
2008 }
2009 buf[len++] = *cur;
2010 count++;
2011 NEXT;
2012 }
2013 buf[len] = 0;
2014 if (stop == ' ') {
2015 if (!IS_BLANK(*cur)) {
2016 xmlFree(buf);
2017 return(NULL);
2018 }
2019 } else {
2020 if (*cur != stop) {
2021 xmlFree(buf);
2022 return(NULL);
2023 }
2024 NEXT;
2025 }
2026 *id = buf;
2027 return(cur);
2028}
2029
Daniel Veillard75b96822001-10-11 18:59:45 +00002030/**
2031 * xmlParseSGMLCatalogName:
2032 * @cur: the current character
2033 * @name: the return location
2034 *
2035 * Parse an SGML catalog name
2036 *
2037 * Returns new current character and store the value in @name
2038 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002039static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002040xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002041 xmlChar buf[XML_MAX_NAMELEN + 5];
2042 int len = 0;
2043 int c;
2044
2045 *name = NULL;
2046
2047 /*
2048 * Handler for more complex cases
2049 */
2050 c = *cur;
2051 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2052 return(NULL);
2053 }
2054
2055 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2056 (c == '.') || (c == '-') ||
2057 (c == '_') || (c == ':'))) {
2058 buf[len++] = c;
2059 cur++;
2060 c = *cur;
2061 if (len >= XML_MAX_NAMELEN)
2062 return(NULL);
2063 }
2064 *name = xmlStrndup(buf, len);
2065 return(cur);
2066}
2067
Daniel Veillard75b96822001-10-11 18:59:45 +00002068/**
2069 * xmlGetSGMLCatalogEntryType:
2070 * @name: the entry name
2071 *
2072 * Get the Catalog entry type for a given SGML Catalog name
2073 *
2074 * Returns Catalog entry type
2075 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002076static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002077xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002078 xmlCatalogEntryType type = XML_CATA_NONE;
2079 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2080 type = SGML_CATA_SYSTEM;
2081 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2082 type = SGML_CATA_PUBLIC;
2083 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2084 type = SGML_CATA_DELEGATE;
2085 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2086 type = SGML_CATA_ENTITY;
2087 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2088 type = SGML_CATA_DOCTYPE;
2089 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2090 type = SGML_CATA_LINKTYPE;
2091 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2092 type = SGML_CATA_NOTATION;
2093 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2094 type = SGML_CATA_SGMLDECL;
2095 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2096 type = SGML_CATA_DOCUMENT;
2097 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2098 type = SGML_CATA_CATALOG;
2099 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2100 type = SGML_CATA_BASE;
2101 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2102 type = SGML_CATA_DELEGATE;
2103 return(type);
2104}
2105
Daniel Veillard75b96822001-10-11 18:59:45 +00002106/**
2107 * xmlParseSGMLCatalog:
2108 * @catal: the SGML Catalog
2109 * @value: the content of the SGML Catalog serialization
2110 * @file: the filepath for the catalog
2111 * @super: should this be handled as a Super Catalog in which case
2112 * parsing is not recursive
2113 *
2114 * Parse an SGML catalog content and fill up the @catal hash table with
2115 * the new entries found.
2116 *
2117 * Returns 0 in case of success, -1 in case of error.
2118 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002119static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002120xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2121 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002122 const xmlChar *cur = value;
2123 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002124 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002125
2126 if ((cur == NULL) || (file == NULL))
2127 return(-1);
2128 base = xmlStrdup((const xmlChar *) file);
2129
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002130 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002131 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002132 if (cur[0] == 0)
2133 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002134 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002135 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002136 if (cur == NULL) {
2137 /* error */
2138 break;
2139 }
2140 } else {
2141 xmlChar *sysid = NULL;
2142 xmlChar *name = NULL;
2143 xmlCatalogEntryType type = XML_CATA_NONE;
2144
Daniel Veillardcda96922001-08-21 10:56:31 +00002145 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002146 if (name == NULL) {
2147 /* error */
2148 break;
2149 }
2150 if (!IS_BLANK(*cur)) {
2151 /* error */
2152 break;
2153 }
2154 SKIP_BLANKS;
2155 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002156 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002157 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002158 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002159 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002160 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002161 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002162 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002163 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002164 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002165 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002166 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002167 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002168 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002169 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002170 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002171 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002172 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002173 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002174 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002175 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002176 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002177 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002178 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002179 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2180 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002181 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002182 if (name == NULL) {
2183 /* error */
2184 break;
2185 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002186 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002187 continue;
2188 }
2189 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002190 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002191
2192 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002193 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002194 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002195 type = SGML_CATA_PENTITY;
2196 case SGML_CATA_PENTITY:
2197 case SGML_CATA_DOCTYPE:
2198 case SGML_CATA_LINKTYPE:
2199 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002200 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002201 if (cur == NULL) {
2202 /* error */
2203 break;
2204 }
2205 if (!IS_BLANK(*cur)) {
2206 /* error */
2207 break;
2208 }
2209 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002210 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002211 if (cur == NULL) {
2212 /* error */
2213 break;
2214 }
2215 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002216 case SGML_CATA_PUBLIC:
2217 case SGML_CATA_SYSTEM:
2218 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002219 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002220 if (cur == NULL) {
2221 /* error */
2222 break;
2223 }
2224 if (!IS_BLANK(*cur)) {
2225 /* error */
2226 break;
2227 }
2228 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002229 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002230 if (cur == NULL) {
2231 /* error */
2232 break;
2233 }
2234 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002235 case SGML_CATA_BASE:
2236 case SGML_CATA_CATALOG:
2237 case SGML_CATA_DOCUMENT:
2238 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002239 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002240 if (cur == NULL) {
2241 /* error */
2242 break;
2243 }
2244 break;
2245 default:
2246 break;
2247 }
2248 if (cur == NULL) {
2249 if (name != NULL)
2250 xmlFree(name);
2251 if (sysid != NULL)
2252 xmlFree(sysid);
2253 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002254 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002255 if (base != NULL)
2256 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002257 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002258 } else if ((type == SGML_CATA_PUBLIC) ||
2259 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002260 xmlChar *filename;
2261
2262 filename = xmlBuildURI(sysid, base);
2263 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002264 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002265
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002266 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002267 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002268 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002269 if (res < 0) {
2270 xmlFreeCatalogEntry(entry);
2271 }
2272 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002273 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002274
Daniel Veillard344cee72001-08-20 00:08:40 +00002275 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002276 if (super) {
2277 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002278
Daniel Veillardc853b322001-11-06 15:24:37 +00002279 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002280 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002281 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002282 if (res < 0) {
2283 xmlFreeCatalogEntry(entry);
2284 }
2285 } else {
2286 xmlChar *filename;
2287
2288 filename = xmlBuildURI(sysid, base);
2289 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002290 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002291 xmlFree(filename);
2292 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002293 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002294 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002295 /*
2296 * drop anything else we won't handle it
2297 */
2298 if (name != NULL)
2299 xmlFree(name);
2300 if (sysid != NULL)
2301 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002302 }
2303 }
2304 if (base != NULL)
2305 xmlFree(base);
2306 if (cur == NULL)
2307 return(-1);
2308 return(0);
2309}
2310
Daniel Veillard75b96822001-10-11 18:59:45 +00002311/************************************************************************
2312 * *
2313 * SGML Catalog handling *
2314 * *
2315 ************************************************************************/
2316
Daniel Veillardcda96922001-08-21 10:56:31 +00002317/**
2318 * xmlCatalogGetSGMLPublic:
2319 * @catal: an SGML catalog hash
2320 * @pubId: the public ID string
2321 *
2322 * Try to lookup the system ID associated to a public ID
2323 *
2324 * Returns the system ID if found or NULL otherwise.
2325 */
2326static const xmlChar *
2327xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2328 xmlCatalogEntryPtr entry;
2329
2330 if (catal == NULL)
2331 return(NULL);
2332
2333 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2334 if (entry == NULL)
2335 return(NULL);
2336 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillardc853b322001-11-06 15:24:37 +00002337 return(entry->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002338 return(NULL);
2339}
2340
2341/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002342 * xmlCatalogGetSGMLSystem:
2343 * @catal: an SGML catalog hash
2344 * @sysId: the public ID string
2345 *
2346 * Try to lookup the catalog local reference for a system ID
2347 *
2348 * Returns the system ID if found or NULL otherwise.
2349 */
2350static const xmlChar *
2351xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2352 xmlCatalogEntryPtr entry;
2353
2354 if (catal == NULL)
2355 return(NULL);
2356
2357 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2358 if (entry == NULL)
2359 return(NULL);
2360 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002361 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002362 return(NULL);
2363}
2364
2365/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002366 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002367 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002368 * @pubId: the public ID string
2369 * @sysId: the system ID string
2370 *
2371 * Do a complete resolution lookup of an External Identifier
2372 *
2373 * Returns the URI of the resource or NULL if not found
2374 */
2375static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002376xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2377 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002378 const xmlChar *ret = NULL;
2379
Daniel Veillard75b96822001-10-11 18:59:45 +00002380 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002381 return(NULL);
2382
2383 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002384 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002385 if (ret != NULL)
2386 return(ret);
2387 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002388 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002389 return(NULL);
2390}
2391
Daniel Veillarda7374592001-05-10 14:17:55 +00002392/************************************************************************
2393 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002394 * Specific Public interfaces *
2395 * *
2396 ************************************************************************/
2397
2398/**
2399 * xmlLoadSGMLSuperCatalog:
2400 * @filename: a file path
2401 *
2402 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2403 * references. This is only needed for manipulating SGML Super Catalogs
2404 * like adding and removing CATALOG or DELEGATE entries.
2405 *
2406 * Returns the catalog parsed or NULL in case of error
2407 */
2408xmlCatalogPtr
2409xmlLoadSGMLSuperCatalog(const char *filename)
2410{
2411 xmlChar *content;
2412 xmlCatalogPtr catal;
2413 int ret;
2414
2415 content = xmlLoadFileContent(filename);
2416 if (content == NULL)
2417 return(NULL);
2418
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002419 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002420 if (catal == NULL) {
2421 xmlFree(content);
2422 return(NULL);
2423 }
2424
2425 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2426 xmlFree(content);
2427 if (ret < 0) {
2428 xmlFreeCatalog(catal);
2429 return(NULL);
2430 }
2431 return (catal);
2432}
2433
2434/**
2435 * xmlLoadACatalog:
2436 * @filename: a file path
2437 *
2438 * Load the catalog and build the associated data structures.
2439 * This can be either an XML Catalog or an SGML Catalog
2440 * It will recurse in SGML CATALOG entries. On the other hand XML
2441 * Catalogs are not handled recursively.
2442 *
2443 * Returns the catalog parsed or NULL in case of error
2444 */
2445xmlCatalogPtr
2446xmlLoadACatalog(const char *filename)
2447{
2448 xmlChar *content;
2449 xmlChar *first;
2450 xmlCatalogPtr catal;
2451 int ret;
2452
2453 content = xmlLoadFileContent(filename);
2454 if (content == NULL)
2455 return(NULL);
2456
2457
2458 first = content;
2459
2460 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2461 (!(((*first >= 'A') && (*first <= 'Z')) ||
2462 ((*first >= 'a') && (*first <= 'z')))))
2463 first++;
2464
2465 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002466 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002467 if (catal == NULL) {
2468 xmlFree(content);
2469 return(NULL);
2470 }
2471 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2472 if (ret < 0) {
2473 xmlFreeCatalog(catal);
2474 xmlFree(content);
2475 return(NULL);
2476 }
2477 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002478 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002479 if (catal == NULL) {
2480 xmlFree(content);
2481 return(NULL);
2482 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002483 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002484 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002485 }
2486 xmlFree(content);
2487 return (catal);
2488}
2489
2490/**
2491 * xmlExpandCatalog:
2492 * @catal: a catalog
2493 * @filename: a file path
2494 *
2495 * Load the catalog and expand the existing catal structure.
2496 * This can be either an XML Catalog or an SGML Catalog
2497 *
2498 * Returns 0 in case of success, -1 in case of error
2499 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002500static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002501xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2502{
Daniel Veillard75b96822001-10-11 18:59:45 +00002503 int ret;
2504
2505 if ((catal == NULL) || (filename == NULL))
2506 return(-1);
2507
Daniel Veillard75b96822001-10-11 18:59:45 +00002508
2509 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002510 xmlChar *content;
2511
2512 content = xmlLoadFileContent(filename);
2513 if (content == NULL)
2514 return(-1);
2515
Daniel Veillard75b96822001-10-11 18:59:45 +00002516 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2517 if (ret < 0) {
2518 xmlFree(content);
2519 return(-1);
2520 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002521 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002522 } else {
2523 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002524 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002525 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002526
Daniel Veillard75b96822001-10-11 18:59:45 +00002527 cur = catal->xml;
2528 if (cur == NULL) {
2529 catal->xml = tmp;
2530 } else {
2531 while (cur->next != NULL) cur = cur->next;
2532 cur->next = tmp;
2533 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002534 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002535 return (0);
2536}
2537
2538/**
2539 * xmlACatalogResolveSystem:
2540 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002541 * @sysID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002542 *
2543 * Try to lookup the catalog resource for a system ID
2544 *
2545 * Returns the system ID if found or NULL otherwise, the value returned
2546 * must be freed by the caller.
2547 */
2548xmlChar *
2549xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2550 xmlChar *ret = NULL;
2551
2552 if ((sysID == NULL) || (catal == NULL))
2553 return(NULL);
2554
2555 if (xmlDebugCatalogs)
2556 xmlGenericError(xmlGenericErrorContext,
2557 "Resolve sysID %s\n", sysID);
2558
2559 if (catal->type == XML_XML_CATALOG_TYPE) {
2560 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2561 if (ret == XML_CATAL_BREAK)
2562 ret = NULL;
2563 } else {
2564 const xmlChar *sgml;
2565
2566 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2567 if (sgml != NULL)
2568 ret = xmlStrdup(sgml);
2569 }
2570 return(ret);
2571}
2572
2573/**
2574 * xmlACatalogResolvePublic:
2575 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002576 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002577 *
2578 * Try to lookup the system ID associated to a public ID in that catalog
2579 *
2580 * Returns the system ID if found or NULL otherwise, the value returned
2581 * must be freed by the caller.
2582 */
2583xmlChar *
2584xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2585 xmlChar *ret = NULL;
2586
2587 if ((pubID == NULL) || (catal == NULL))
2588 return(NULL);
2589
2590 if (xmlDebugCatalogs)
2591 xmlGenericError(xmlGenericErrorContext,
2592 "Resolve pubID %s\n", pubID);
2593
2594 if (catal->type == XML_XML_CATALOG_TYPE) {
2595 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2596 if (ret == XML_CATAL_BREAK)
2597 ret = NULL;
2598 } else {
2599 const xmlChar *sgml;
2600
2601 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2602 if (sgml != NULL)
2603 ret = xmlStrdup(sgml);
2604 }
2605 return(ret);
2606}
2607
2608/**
2609 * xmlACatalogResolve:
2610 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002611 * @pubID: the public ID string
2612 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002613 *
2614 * Do a complete resolution lookup of an External Identifier
2615 *
2616 * Returns the URI of the resource or NULL if not found, it must be freed
2617 * by the caller.
2618 */
2619xmlChar *
2620xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2621 const xmlChar * sysID)
2622{
2623 xmlChar *ret = NULL;
2624
2625 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2626 return (NULL);
2627
2628 if (xmlDebugCatalogs) {
2629 if (pubID != NULL) {
2630 xmlGenericError(xmlGenericErrorContext,
2631 "Resolve: pubID %s\n", pubID);
2632 } else {
2633 xmlGenericError(xmlGenericErrorContext,
2634 "Resolve: sysID %s\n", sysID);
2635 }
2636 }
2637
2638 if (catal->type == XML_XML_CATALOG_TYPE) {
2639 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2640 if (ret == XML_CATAL_BREAK)
2641 ret = NULL;
2642 } else {
2643 const xmlChar *sgml;
2644
2645 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2646 if (sgml != NULL)
2647 ret = xmlStrdup(sgml);
2648 }
2649 return (ret);
2650}
2651
2652/**
2653 * xmlACatalogResolveURI:
2654 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002655 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002656 *
2657 * Do a complete resolution lookup of an URI
2658 *
2659 * Returns the URI of the resource or NULL if not found, it must be freed
2660 * by the caller.
2661 */
2662xmlChar *
2663xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2664 xmlChar *ret = NULL;
2665
2666 if ((URI == NULL) || (catal == NULL))
2667 return(NULL);
2668
Daniel Veillardb44025c2001-10-11 22:55:55 +00002669 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002670 xmlGenericError(xmlGenericErrorContext,
2671 "Resolve URI %s\n", URI);
2672
2673 if (catal->type == XML_XML_CATALOG_TYPE) {
2674 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2675 if (ret == XML_CATAL_BREAK)
2676 ret = NULL;
2677 } else {
2678 const xmlChar *sgml;
2679
2680 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2681 if (sgml != NULL)
2682 sgml = xmlStrdup(sgml);
2683 }
2684 return(ret);
2685}
2686
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002687#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002688/**
2689 * xmlACatalogDump:
2690 * @catal: a Catalog
2691 * @out: the file.
2692 *
2693 * Free up all the memory associated with catalogs
2694 */
2695void
2696xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002697 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002698 return;
2699
2700 if (catal->type == XML_XML_CATALOG_TYPE) {
2701 xmlDumpXMLCatalog(out, catal->xml);
2702 } else {
2703 xmlHashScan(catal->sgml,
2704 (xmlHashScanner) xmlCatalogDumpEntry, out);
2705 }
2706}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002707#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002708
2709/**
2710 * xmlACatalogAdd:
2711 * @catal: a Catalog
2712 * @type: the type of record to add to the catalog
2713 * @orig: the system, public or prefix to match
2714 * @replace: the replacement value for the match
2715 *
2716 * Add an entry in the catalog, it may overwrite existing but
2717 * different entries.
2718 *
2719 * Returns 0 if successful, -1 otherwise
2720 */
2721int
2722xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2723 const xmlChar * orig, const xmlChar * replace)
2724{
2725 int res = -1;
2726
2727 if (catal == NULL)
2728 return(-1);
2729
2730 if (catal->type == XML_XML_CATALOG_TYPE) {
2731 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2732 } else {
2733 xmlCatalogEntryType cattype;
2734
2735 cattype = xmlGetSGMLCatalogEntryType(type);
2736 if (cattype != XML_CATA_NONE) {
2737 xmlCatalogEntryPtr entry;
2738
Daniel Veillardc853b322001-11-06 15:24:37 +00002739 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002740 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002741 if (catal->sgml == NULL)
2742 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002743 res = xmlHashAddEntry(catal->sgml, orig, entry);
2744 }
2745 }
2746 return (res);
2747}
2748
2749/**
2750 * xmlACatalogRemove:
2751 * @catal: a Catalog
2752 * @value: the value to remove
2753 *
2754 * Remove an entry from the catalog
2755 *
2756 * Returns the number of entries removed if successful, -1 otherwise
2757 */
2758int
2759xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2760 int res = -1;
2761
2762 if ((catal == NULL) || (value == NULL))
2763 return(-1);
2764
2765 if (catal->type == XML_XML_CATALOG_TYPE) {
2766 res = xmlDelXMLCatalog(catal->xml, value);
2767 } else {
2768 res = xmlHashRemoveEntry(catal->sgml, value,
2769 (xmlHashDeallocator) xmlFreeCatalogEntry);
2770 if (res == 0)
2771 res = 1;
2772 }
2773 return(res);
2774}
2775
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002776/**
2777 * xmlNewCatalog:
2778 * @sgml: should this create an SGML catalog
2779 *
2780 * create a new Catalog.
2781 *
2782 * Returns the xmlCatalogPtr or NULL in case of error
2783 */
2784xmlCatalogPtr
2785xmlNewCatalog(int sgml) {
2786 xmlCatalogPtr catal = NULL;
2787
2788 if (sgml) {
2789 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2790 xmlCatalogDefaultPrefer);
2791 if ((catal != NULL) && (catal->sgml == NULL))
2792 catal->sgml = xmlHashCreate(10);
2793 } else
2794 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2795 xmlCatalogDefaultPrefer);
2796 return(catal);
2797}
2798
2799/**
2800 * xmlCatalogIsEmpty:
2801 * @catal: should this create an SGML catalog
2802 *
2803 * Check is a catalog is empty
2804 *
2805 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2806 */
2807int
2808xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2809 if (catal == NULL)
2810 return(-1);
2811
2812 if (catal->type == XML_XML_CATALOG_TYPE) {
2813 if (catal->xml == NULL)
2814 return(1);
2815 if ((catal->xml->type != XML_CATA_CATALOG) &&
2816 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2817 return(-1);
2818 if (catal->xml->children == NULL)
2819 return(1);
2820 return(0);
2821 } else {
2822 int res;
2823
2824 if (catal->sgml == NULL)
2825 return(1);
2826 res = xmlHashSize(catal->sgml);
2827 if (res == 0)
2828 return(1);
2829 if (res < 0)
2830 return(-1);
2831 }
2832 return(0);
2833}
2834
Daniel Veillard75b96822001-10-11 18:59:45 +00002835/************************************************************************
2836 * *
2837 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002838 * *
2839 ************************************************************************/
2840
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002841/**
Daniel Veillard81463942001-10-16 12:34:39 +00002842 * xmlInitializeCatalogData:
2843 *
2844 * Do the catalog initialization only of global data, doesn't try to load
2845 * any catalog actually.
2846 * this function is not thread safe, catalog initialization should
2847 * preferably be done once at startup
2848 */
2849static void
2850xmlInitializeCatalogData(void) {
2851 if (xmlCatalogInitialized != 0)
2852 return;
2853
2854 if (getenv("XML_DEBUG_CATALOG"))
2855 xmlDebugCatalogs = 1;
2856 xmlCatalogMutex = xmlNewRMutex();
2857
2858 xmlCatalogInitialized = 1;
2859}
2860/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002861 * xmlInitializeCatalog:
2862 *
2863 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002864 * this function is not thread safe, catalog initialization should
2865 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002866 */
2867void
2868xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002869 if (xmlCatalogInitialized != 0)
2870 return;
2871
Daniel Veillard81463942001-10-16 12:34:39 +00002872 xmlInitializeCatalogData();
2873 xmlRMutexLock(xmlCatalogMutex);
2874
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002875 if (getenv("XML_DEBUG_CATALOG"))
2876 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002877
Daniel Veillard75b96822001-10-11 18:59:45 +00002878 if (xmlDefaultCatalog == NULL) {
2879 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002880 char *path;
2881 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00002882 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002883 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00002884
Daniel Veillardb44025c2001-10-11 22:55:55 +00002885 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002886 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002887 catalogs = XML_XML_DEFAULT_CATALOG;
2888
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002889 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2890 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002891 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002892 /* the XML_CATALOG_FILES envvar is allowed to contain a
2893 space-separated list of entries. */
2894 cur = catalogs;
2895 nextent = &catal->xml;
2896 while (*cur != '\0') {
2897 while (IS_BLANK(*cur))
2898 cur++;
2899 if (*cur != 0) {
2900 paths = cur;
2901 while ((*cur != 0) && (!IS_BLANK(*cur)))
2902 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002903 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002904 if (path != NULL) {
2905 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2906 NULL, BAD_CAST path, xmlCatalogDefaultPrefer);
2907 if (*nextent != NULL)
2908 nextent = &((*nextent)->next);
2909 xmlFree(path);
2910 }
2911 }
2912 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002913 xmlDefaultCatalog = catal;
2914 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002915 }
2916
Daniel Veillard81463942001-10-16 12:34:39 +00002917 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002918}
2919
Daniel Veillard82d75332001-10-08 15:01:59 +00002920
2921/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002922 * xmlLoadCatalog:
2923 * @filename: a file path
2924 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002925 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002926 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002927 * this function is not thread safe, catalog initialization should
2928 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002929 *
2930 * Returns 0 in case of success -1 in case of error
2931 */
2932int
Daniel Veillard16756b62001-10-01 07:36:25 +00002933xmlLoadCatalog(const char *filename)
2934{
Daniel Veillard75b96822001-10-11 18:59:45 +00002935 int ret;
2936 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002937
Daniel Veillard81463942001-10-16 12:34:39 +00002938 if (!xmlCatalogInitialized)
2939 xmlInitializeCatalogData();
2940
2941 xmlRMutexLock(xmlCatalogMutex);
2942
Daniel Veillard75b96822001-10-11 18:59:45 +00002943 if (xmlDefaultCatalog == NULL) {
2944 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00002945 if (catal == NULL) {
2946 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002947 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00002948 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002949
Daniel Veillard75b96822001-10-11 18:59:45 +00002950 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002951 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002952 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002953 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002954
Daniel Veillard75b96822001-10-11 18:59:45 +00002955 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002956 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002957 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002958}
2959
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002960/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002961 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00002962 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00002963 *
2964 * Load the catalogs and makes their definitions effective for the default
2965 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002966 * this function is not thread safe, catalog initialization should
2967 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002968 */
2969void
2970xmlLoadCatalogs(const char *pathss) {
2971 const char *cur;
2972 const char *paths;
2973 xmlChar *path;
2974
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002975 if (pathss == NULL)
2976 return;
2977
Daniel Veillard81418e32001-05-22 15:08:55 +00002978 cur = pathss;
2979 while ((cur != NULL) && (*cur != 0)) {
2980 while (IS_BLANK(*cur)) cur++;
2981 if (*cur != 0) {
2982 paths = cur;
Igor Zlatkovicee1494a2002-10-31 16:15:29 +00002983 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00002984 cur++;
2985 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2986 if (path != NULL) {
2987 xmlLoadCatalog((const char *) path);
2988 xmlFree(path);
2989 }
2990 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00002991 while (*cur == ':')
2992 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00002993 }
2994}
2995
Daniel Veillarda7374592001-05-10 14:17:55 +00002996/**
2997 * xmlCatalogCleanup:
2998 *
2999 * Free up all the memory associated with catalogs
3000 */
3001void
3002xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003003 if (xmlCatalogInitialized == 0)
3004 return;
3005
Daniel Veillard81463942001-10-16 12:34:39 +00003006 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003007 if (xmlDebugCatalogs)
3008 xmlGenericError(xmlGenericErrorContext,
3009 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003010 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003011 xmlHashFree(xmlCatalogXMLFiles,
3012 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003013 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003014 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003015 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003016 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003017 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003018 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003019 xmlRMutexUnlock(xmlCatalogMutex);
3020 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003021}
3022
3023/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003024 * xmlCatalogResolveSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003025 * @sysID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003026 *
3027 * Try to lookup the catalog resource for a system ID
3028 *
3029 * Returns the system ID if found or NULL otherwise, the value returned
3030 * must be freed by the caller.
3031 */
3032xmlChar *
3033xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003034 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003035
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003036 if (!xmlCatalogInitialized)
3037 xmlInitializeCatalog();
3038
Daniel Veillard75b96822001-10-11 18:59:45 +00003039 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3040 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003041}
3042
3043/**
3044 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003045 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003046 *
3047 * Try to lookup the system ID associated to a public ID
3048 *
3049 * Returns the system ID if found or NULL otherwise, the value returned
3050 * must be freed by the caller.
3051 */
3052xmlChar *
3053xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003054 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003055
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003056 if (!xmlCatalogInitialized)
3057 xmlInitializeCatalog();
3058
Daniel Veillard75b96822001-10-11 18:59:45 +00003059 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3060 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003061}
Daniel Veillard344cee72001-08-20 00:08:40 +00003062
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003063/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003064 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003065 * @pubID: the public ID string
3066 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003067 *
3068 * Do a complete resolution lookup of an External Identifier
3069 *
3070 * Returns the URI of the resource or NULL if not found, it must be freed
3071 * by the caller.
3072 */
3073xmlChar *
3074xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003075 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003076
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003077 if (!xmlCatalogInitialized)
3078 xmlInitializeCatalog();
3079
Daniel Veillard75b96822001-10-11 18:59:45 +00003080 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3081 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003082}
3083
3084/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003085 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003086 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003087 *
3088 * Do a complete resolution lookup of an URI
3089 *
3090 * Returns the URI of the resource or NULL if not found, it must be freed
3091 * by the caller.
3092 */
3093xmlChar *
3094xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003095 xmlChar *ret;
3096
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003097 if (!xmlCatalogInitialized)
3098 xmlInitializeCatalog();
3099
Daniel Veillard75b96822001-10-11 18:59:45 +00003100 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3101 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003102}
3103
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003104#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003105/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003106 * xmlCatalogDump:
3107 * @out: the file.
3108 *
3109 * Free up all the memory associated with catalogs
3110 */
3111void
3112xmlCatalogDump(FILE *out) {
3113 if (out == NULL)
3114 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003115
Daniel Veillard75b96822001-10-11 18:59:45 +00003116 if (!xmlCatalogInitialized)
3117 xmlInitializeCatalog();
3118
3119 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003120}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003121#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003122
3123/**
3124 * xmlCatalogAdd:
3125 * @type: the type of record to add to the catalog
3126 * @orig: the system, public or prefix to match
3127 * @replace: the replacement value for the match
3128 *
3129 * Add an entry in the catalog, it may overwrite existing but
3130 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003131 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003132 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003133 *
3134 * Returns 0 if successful, -1 otherwise
3135 */
3136int
3137xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3138 int res = -1;
3139
Daniel Veillard81463942001-10-16 12:34:39 +00003140 if (!xmlCatalogInitialized)
3141 xmlInitializeCatalogData();
3142
3143 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003144 /*
3145 * Specific case where one want to override the default catalog
3146 * put in place by xmlInitializeCatalog();
3147 */
3148 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003149 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003150 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003151 xmlCatalogDefaultPrefer);
3152 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003153 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003154
Daniel Veillard81463942001-10-16 12:34:39 +00003155 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003156 return(0);
3157 }
3158
Daniel Veillard75b96822001-10-11 18:59:45 +00003159 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003160 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003161 return(res);
3162}
3163
3164/**
3165 * xmlCatalogRemove:
3166 * @value: the value to remove
3167 *
3168 * Remove an entry from the catalog
3169 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003170 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003171 */
3172int
3173xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003174 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003175
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003176 if (!xmlCatalogInitialized)
3177 xmlInitializeCatalog();
3178
Daniel Veillard81463942001-10-16 12:34:39 +00003179 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003180 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003181 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003182 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003183}
3184
3185/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003186 * xmlCatalogConvert:
3187 *
3188 * Convert all the SGML catalog entries as XML ones
3189 *
3190 * Returns the number of entries converted if successful, -1 otherwise
3191 */
3192int
3193xmlCatalogConvert(void) {
3194 int res = -1;
3195
3196 if (!xmlCatalogInitialized)
3197 xmlInitializeCatalog();
3198
Daniel Veillard81463942001-10-16 12:34:39 +00003199 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003200 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003201 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003202 return(res);
3203}
3204
Daniel Veillard75b96822001-10-11 18:59:45 +00003205/************************************************************************
3206 * *
3207 * Public interface manipulating the common preferences *
3208 * *
3209 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003210
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003211/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003212 * xmlCatalogGetDefaults:
3213 *
3214 * Used to get the user preference w.r.t. to what catalogs should
3215 * be accepted
3216 *
3217 * Returns the current xmlCatalogAllow value
3218 */
3219xmlCatalogAllow
3220xmlCatalogGetDefaults(void) {
3221 return(xmlCatalogDefaultAllow);
3222}
3223
3224/**
3225 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003226 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003227 *
3228 * Used to set the user preference w.r.t. to what catalogs should
3229 * be accepted
3230 */
3231void
3232xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003233 if (xmlDebugCatalogs) {
3234 switch (allow) {
3235 case XML_CATA_ALLOW_NONE:
3236 xmlGenericError(xmlGenericErrorContext,
3237 "Disabling catalog usage\n");
3238 break;
3239 case XML_CATA_ALLOW_GLOBAL:
3240 xmlGenericError(xmlGenericErrorContext,
3241 "Allowing only global catalogs\n");
3242 break;
3243 case XML_CATA_ALLOW_DOCUMENT:
3244 xmlGenericError(xmlGenericErrorContext,
3245 "Allowing only catalogs from the document\n");
3246 break;
3247 case XML_CATA_ALLOW_ALL:
3248 xmlGenericError(xmlGenericErrorContext,
3249 "Allowing all catalogs\n");
3250 break;
3251 }
3252 }
3253 xmlCatalogDefaultAllow = allow;
3254}
3255
3256/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003257 * xmlCatalogSetDefaultPrefer:
3258 * @prefer: the default preference for delegation
3259 *
3260 * Allows to set the preference between public and system for deletion
3261 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003262 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003263 *
3264 * Returns the previous value of the default preference for delegation
3265 */
3266xmlCatalogPrefer
3267xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3268 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3269
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003270 if (prefer == XML_CATA_PREFER_NONE)
3271 return(ret);
3272
3273 if (xmlDebugCatalogs) {
3274 switch (prefer) {
3275 case XML_CATA_PREFER_PUBLIC:
3276 xmlGenericError(xmlGenericErrorContext,
3277 "Setting catalog preference to PUBLIC\n");
3278 break;
3279 case XML_CATA_PREFER_SYSTEM:
3280 xmlGenericError(xmlGenericErrorContext,
3281 "Setting catalog preference to SYSTEM\n");
3282 break;
3283 case XML_CATA_PREFER_NONE:
3284 break;
3285 }
3286 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003287 xmlCatalogDefaultPrefer = prefer;
3288 return(ret);
3289}
3290
3291/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003292 * xmlCatalogSetDebug:
3293 * @level: the debug level of catalogs required
3294 *
3295 * Used to set the debug level for catalog operation, 0 disable
3296 * debugging, 1 enable it
3297 *
3298 * Returns the previous value of the catalog debugging level
3299 */
3300int
3301xmlCatalogSetDebug(int level) {
3302 int ret = xmlDebugCatalogs;
3303
3304 if (level <= 0)
3305 xmlDebugCatalogs = 0;
3306 else
3307 xmlDebugCatalogs = level;
3308 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003309}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003310
Daniel Veillard75b96822001-10-11 18:59:45 +00003311/************************************************************************
3312 * *
3313 * Minimal interfaces used for per-document catalogs by the parser *
3314 * *
3315 ************************************************************************/
3316
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003317/**
3318 * xmlCatalogFreeLocal:
3319 * @catalogs: a document's list of catalogs
3320 *
3321 * Free up the memory associated to the catalog list
3322 */
3323void
3324xmlCatalogFreeLocal(void *catalogs) {
3325 xmlCatalogEntryPtr catal;
3326
Daniel Veillard81463942001-10-16 12:34:39 +00003327 if (!xmlCatalogInitialized)
3328 xmlInitializeCatalog();
3329
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003330 catal = (xmlCatalogEntryPtr) catalogs;
3331 if (catal != NULL)
3332 xmlFreeCatalogEntryList(catal);
3333}
3334
3335
3336/**
3337 * xmlCatalogAddLocal:
3338 * @catalogs: a document's list of catalogs
3339 * @URL: the URL to a new local catalog
3340 *
3341 * Add the new entry to the catalog list
3342 *
3343 * Returns the updated list
3344 */
3345void *
3346xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3347 xmlCatalogEntryPtr catal, add;
3348
3349 if (!xmlCatalogInitialized)
3350 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003351
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003352 if (URL == NULL)
3353 return(catalogs);
3354
3355 if (xmlDebugCatalogs)
3356 xmlGenericError(xmlGenericErrorContext,
3357 "Adding document catalog %s\n", URL);
3358
Daniel Veillardc853b322001-11-06 15:24:37 +00003359 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003360 xmlCatalogDefaultPrefer);
3361 if (add == NULL)
3362 return(catalogs);
3363
3364 catal = (xmlCatalogEntryPtr) catalogs;
3365 if (catal == NULL)
3366 return((void *) add);
3367
3368 while (catal->next != NULL)
3369 catal = catal->next;
3370 catal->next = add;
3371 return(catalogs);
3372}
3373
3374/**
3375 * xmlCatalogLocalResolve:
3376 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003377 * @pubID: the public ID string
3378 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003379 *
3380 * Do a complete resolution lookup of an External Identifier using a
3381 * document's private catalog list
3382 *
3383 * Returns the URI of the resource or NULL if not found, it must be freed
3384 * by the caller.
3385 */
3386xmlChar *
3387xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3388 const xmlChar *sysID) {
3389 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003390 xmlChar *ret;
3391
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003392 if (!xmlCatalogInitialized)
3393 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003394
Daniel Veillard81463942001-10-16 12:34:39 +00003395 if ((pubID == NULL) && (sysID == NULL))
3396 return(NULL);
3397
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003398 if (xmlDebugCatalogs) {
3399 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003400 xmlGenericError(xmlGenericErrorContext,
3401 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003402 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003403 xmlGenericError(xmlGenericErrorContext,
3404 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003405 }
3406 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003407
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003408 catal = (xmlCatalogEntryPtr) catalogs;
3409 if (catal == NULL)
3410 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003411 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3412 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3413 return(ret);
3414 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003415}
3416
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003417/**
3418 * xmlCatalogLocalResolveURI:
3419 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003420 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003421 *
3422 * Do a complete resolution lookup of an URI using a
3423 * document's private catalog list
3424 *
3425 * Returns the URI of the resource or NULL if not found, it must be freed
3426 * by the caller.
3427 */
3428xmlChar *
3429xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3430 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003431 xmlChar *ret;
3432
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003433 if (!xmlCatalogInitialized)
3434 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003435
Daniel Veillard81463942001-10-16 12:34:39 +00003436 if (URI == NULL)
3437 return(NULL);
3438
Daniel Veillard6990bf32001-08-23 21:17:48 +00003439 if (xmlDebugCatalogs)
3440 xmlGenericError(xmlGenericErrorContext,
3441 "Resolve URI %s\n", URI);
3442
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003443 catal = (xmlCatalogEntryPtr) catalogs;
3444 if (catal == NULL)
3445 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003446 ret = xmlCatalogListXMLResolveURI(catal, URI);
3447 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3448 return(ret);
3449 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003450}
3451
Daniel Veillard75b96822001-10-11 18:59:45 +00003452/************************************************************************
3453 * *
3454 * Deprecated interfaces *
3455 * *
3456 ************************************************************************/
3457/**
3458 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003459 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003460 *
3461 * Try to lookup the system ID associated to a public ID
3462 * DEPRECATED, use xmlCatalogResolveSystem()
3463 *
3464 * Returns the system ID if found or NULL otherwise.
3465 */
3466const xmlChar *
3467xmlCatalogGetSystem(const xmlChar *sysID) {
3468 xmlChar *ret;
3469 static xmlChar result[1000];
3470 static int msg = 0;
3471
Daniel Veillard81463942001-10-16 12:34:39 +00003472 if (!xmlCatalogInitialized)
3473 xmlInitializeCatalog();
3474
Daniel Veillard75b96822001-10-11 18:59:45 +00003475 if (msg == 0) {
3476 xmlGenericError(xmlGenericErrorContext,
3477 "Use of deprecated xmlCatalogGetSystem() call\n");
3478 msg++;
3479 }
3480
3481 if (sysID == NULL)
3482 return(NULL);
3483
Daniel Veillard75b96822001-10-11 18:59:45 +00003484 /*
3485 * Check first the XML catalogs
3486 */
3487 if (xmlDefaultCatalog != NULL) {
3488 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3489 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3490 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3491 result[sizeof(result) - 1] = 0;
3492 return(result);
3493 }
3494 }
3495
3496 if (xmlDefaultCatalog != NULL)
3497 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3498 return(NULL);
3499}
3500
3501/**
3502 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003503 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003504 *
3505 * Try to lookup the system ID associated to a public ID
3506 * DEPRECATED, use xmlCatalogResolvePublic()
3507 *
3508 * Returns the system ID if found or NULL otherwise.
3509 */
3510const xmlChar *
3511xmlCatalogGetPublic(const xmlChar *pubID) {
3512 xmlChar *ret;
3513 static xmlChar result[1000];
3514 static int msg = 0;
3515
Daniel Veillard81463942001-10-16 12:34:39 +00003516 if (!xmlCatalogInitialized)
3517 xmlInitializeCatalog();
3518
Daniel Veillard75b96822001-10-11 18:59:45 +00003519 if (msg == 0) {
3520 xmlGenericError(xmlGenericErrorContext,
3521 "Use of deprecated xmlCatalogGetPublic() call\n");
3522 msg++;
3523 }
3524
3525 if (pubID == NULL)
3526 return(NULL);
3527
Daniel Veillard75b96822001-10-11 18:59:45 +00003528 /*
3529 * Check first the XML catalogs
3530 */
3531 if (xmlDefaultCatalog != NULL) {
3532 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3533 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3534 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3535 result[sizeof(result) - 1] = 0;
3536 return(result);
3537 }
3538 }
3539
3540 if (xmlDefaultCatalog != NULL)
3541 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3542 return(NULL);
3543}
3544
Daniel Veillarda7374592001-05-10 14:17:55 +00003545#endif /* LIBXML_CATALOG_ENABLED */