blob: d307bf4ea4ad8fd104be0e23becbcb9df02699a2 [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
377/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000378 * xmlCatalogDumpEntry:
379 * @entry: the
380 * @out: the file.
381 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000382 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000383 */
384static void
385xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
386 if ((entry == NULL) || (out == NULL))
387 return;
388 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000389 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000390 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000391 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000392 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000393 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000394 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000395 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000396 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000397 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000398 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000399 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000400 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000401 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000402 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000403 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000404 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000405 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000406 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000407 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000408 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000409 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000410 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000411 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000412 fprintf(out, "SGMLDECL "); break;
413 default:
414 return;
415 }
416 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000417 case SGML_CATA_ENTITY:
418 case SGML_CATA_PENTITY:
419 case SGML_CATA_DOCTYPE:
420 case SGML_CATA_LINKTYPE:
421 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000422 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000423 case SGML_CATA_PUBLIC:
424 case SGML_CATA_SYSTEM:
425 case SGML_CATA_SGMLDECL:
426 case SGML_CATA_DOCUMENT:
427 case SGML_CATA_CATALOG:
428 case SGML_CATA_BASE:
429 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000430 fprintf(out, "\"%s\"", entry->name); break;
431 default:
432 break;
433 }
434 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000435 case SGML_CATA_ENTITY:
436 case SGML_CATA_PENTITY:
437 case SGML_CATA_DOCTYPE:
438 case SGML_CATA_LINKTYPE:
439 case SGML_CATA_NOTATION:
440 case SGML_CATA_PUBLIC:
441 case SGML_CATA_SYSTEM:
442 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000443 fprintf(out, " \"%s\"", entry->value); break;
444 default:
445 break;
446 }
447 fprintf(out, "\n");
448}
449
Daniel Veillard75b96822001-10-11 18:59:45 +0000450static int
451xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
452 int ret;
453 xmlDocPtr doc;
454 xmlNsPtr ns;
455 xmlDtdPtr dtd;
456 xmlNodePtr node, catalog;
457 xmlOutputBufferPtr buf;
458 xmlCatalogEntryPtr cur;
459
460 /*
461 * Rebuild a catalog
462 */
463 doc = xmlNewDoc(NULL);
464 if (doc == NULL)
465 return(-1);
466 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
467 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
468BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
469
470 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
471
472 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
473 if (ns == NULL) {
474 xmlFreeDoc(doc);
475 return(-1);
476 }
477 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
478 if (catalog == NULL) {
479 xmlFreeNs(ns);
480 xmlFreeDoc(doc);
481 return(-1);
482 }
483 catalog->nsDef = ns;
484 xmlAddChild((xmlNodePtr) doc, catalog);
485
486 /*
487 * add all the catalog entries
488 */
489 cur = catal;
490 while (cur != NULL) {
491 switch (cur->type) {
Daniel Veillardc853b322001-11-06 15:24:37 +0000492 case XML_CATA_REMOVED:
493 break;
Daniel Veillard75b96822001-10-11 18:59:45 +0000494 case XML_CATA_BROKEN_CATALOG:
495 case XML_CATA_CATALOG:
496 if (cur == catal) {
497 cur = cur->children;
498 continue;
499 }
500 break;
501 case XML_CATA_NEXT_CATALOG:
502 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
503 xmlSetProp(node, BAD_CAST "catalog", cur->value);
504 xmlAddChild(catalog, node);
505 break;
506 case XML_CATA_NONE:
507 break;
508 case XML_CATA_PUBLIC:
509 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
510 xmlSetProp(node, BAD_CAST "publicId", cur->name);
511 xmlSetProp(node, BAD_CAST "uri", cur->value);
512 xmlAddChild(catalog, node);
513 break;
514 case XML_CATA_SYSTEM:
515 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
516 xmlSetProp(node, BAD_CAST "systemId", cur->name);
517 xmlSetProp(node, BAD_CAST "uri", cur->value);
518 xmlAddChild(catalog, node);
519 break;
520 case XML_CATA_REWRITE_SYSTEM:
521 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
522 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
523 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
524 xmlAddChild(catalog, node);
525 break;
526 case XML_CATA_DELEGATE_PUBLIC:
527 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
528 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
529 xmlSetProp(node, BAD_CAST "catalog", cur->value);
530 xmlAddChild(catalog, node);
531 break;
532 case XML_CATA_DELEGATE_SYSTEM:
533 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
534 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
535 xmlSetProp(node, BAD_CAST "catalog", cur->value);
536 xmlAddChild(catalog, node);
537 break;
538 case XML_CATA_URI:
539 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
540 xmlSetProp(node, BAD_CAST "name", cur->name);
541 xmlSetProp(node, BAD_CAST "uri", cur->value);
542 xmlAddChild(catalog, node);
543 break;
544 case XML_CATA_REWRITE_URI:
545 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
546 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
547 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
548 xmlAddChild(catalog, node);
549 break;
550 case XML_CATA_DELEGATE_URI:
551 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
552 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
553 xmlSetProp(node, BAD_CAST "catalog", cur->value);
554 xmlAddChild(catalog, node);
555 break;
556 case SGML_CATA_SYSTEM:
557 case SGML_CATA_PUBLIC:
558 case SGML_CATA_ENTITY:
559 case SGML_CATA_PENTITY:
560 case SGML_CATA_DOCTYPE:
561 case SGML_CATA_LINKTYPE:
562 case SGML_CATA_NOTATION:
563 case SGML_CATA_DELEGATE:
564 case SGML_CATA_BASE:
565 case SGML_CATA_CATALOG:
566 case SGML_CATA_DOCUMENT:
567 case SGML_CATA_SGMLDECL:
568 break;
569 }
570 cur = cur->next;
571 }
572
573 /*
574 * reserialize it
575 */
576 buf = xmlOutputBufferCreateFile(out, NULL);
577 if (buf == NULL) {
578 xmlFreeDoc(doc);
579 return(-1);
580 }
581 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
582
583 /*
584 * Free it
585 */
586 xmlFreeDoc(doc);
587
588 return(ret);
589}
590
591/************************************************************************
592 * *
593 * Converting SGML Catalogs to XML *
594 * *
595 ************************************************************************/
596
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000597/**
598 * xmlCatalogConvertEntry:
599 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000600 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000601 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000602 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000603 */
604static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000605xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
606 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
607 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000608 return;
609 switch (entry->type) {
610 case SGML_CATA_ENTITY:
611 entry->type = XML_CATA_PUBLIC;
612 break;
613 case SGML_CATA_PENTITY:
614 entry->type = XML_CATA_PUBLIC;
615 break;
616 case SGML_CATA_DOCTYPE:
617 entry->type = XML_CATA_PUBLIC;
618 break;
619 case SGML_CATA_LINKTYPE:
620 entry->type = XML_CATA_PUBLIC;
621 break;
622 case SGML_CATA_NOTATION:
623 entry->type = XML_CATA_PUBLIC;
624 break;
625 case SGML_CATA_PUBLIC:
626 entry->type = XML_CATA_PUBLIC;
627 break;
628 case SGML_CATA_SYSTEM:
629 entry->type = XML_CATA_SYSTEM;
630 break;
631 case SGML_CATA_DELEGATE:
632 entry->type = XML_CATA_DELEGATE_PUBLIC;
633 break;
634 case SGML_CATA_CATALOG:
635 entry->type = XML_CATA_CATALOG;
636 break;
637 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000638 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000639 (xmlHashDeallocator) xmlFreeCatalogEntry);
640 return;
641 }
642 /*
643 * Conversion successful, remove from the SGML catalog
644 * and add it to the default XML one
645 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000646 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
647 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000648 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000649 if (catal->xml->children == NULL)
650 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000651 else {
652 xmlCatalogEntryPtr prev;
653
Daniel Veillard75b96822001-10-11 18:59:45 +0000654 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000655 while (prev->next != NULL)
656 prev = prev->next;
657 prev->next = entry;
658 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000659}
660
661/**
662 * xmlConvertSGMLCatalog:
663 * @catal: the catalog
664 *
665 * Convert all the SGML catalog entries as XML ones
666 *
667 * Returns the number of entries converted if successful, -1 otherwise
668 */
669int
670xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
671
672 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
673 return(-1);
674
675 if (xmlDebugCatalogs) {
676 xmlGenericError(xmlGenericErrorContext,
677 "Converting SGML catalog to XML\n");
678 }
679 xmlHashScan(catal->sgml,
680 (xmlHashScanner) xmlCatalogConvertEntry,
681 &catal);
682 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000683}
684
Daniel Veillarda7374592001-05-10 14:17:55 +0000685/************************************************************************
686 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000687 * Helper function *
688 * *
689 ************************************************************************/
690
691/**
692 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000693 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000694 *
695 * Expand the URN into the equivalent Public Identifier
696 *
697 * Returns the new identifier or NULL, the string must be deallocated
698 * by the caller.
699 */
700static xmlChar *
701xmlCatalogUnWrapURN(const xmlChar *urn) {
702 xmlChar result[2000];
703 unsigned int i = 0;
704
705 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
706 return(NULL);
707 urn += sizeof(XML_URN_PUBID) - 1;
708
709 while (*urn != 0) {
710 if (i > sizeof(result) - 3)
711 break;
712 if (*urn == '+') {
713 result[i++] = ' ';
714 urn++;
715 } else if (*urn == ':') {
716 result[i++] = '/';
717 result[i++] = '/';
718 urn++;
719 } else if (*urn == ';') {
720 result[i++] = ':';
721 result[i++] = ':';
722 urn++;
723 } else if (*urn == '%') {
724 if ((urn[1] == '2') && (urn[1] == 'B'))
725 result[i++] = '+';
726 else if ((urn[1] == '3') && (urn[1] == 'A'))
727 result[i++] = ':';
728 else if ((urn[1] == '2') && (urn[1] == 'F'))
729 result[i++] = '/';
730 else if ((urn[1] == '3') && (urn[1] == 'B'))
731 result[i++] = ';';
732 else if ((urn[1] == '2') && (urn[1] == '7'))
733 result[i++] = '\'';
734 else if ((urn[1] == '3') && (urn[1] == 'F'))
735 result[i++] = '?';
736 else if ((urn[1] == '2') && (urn[1] == '3'))
737 result[i++] = '#';
738 else if ((urn[1] == '2') && (urn[1] == '5'))
739 result[i++] = '%';
740 else {
741 result[i++] = *urn;
742 urn++;
743 continue;
744 }
745 urn += 3;
746 } else {
747 result[i++] = *urn;
748 urn++;
749 }
750 }
751 result[i] = 0;
752
753 return(xmlStrdup(result));
754}
755
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000756/**
757 * xmlParseCatalogFile:
758 * @filename: the filename
759 *
760 * parse an XML file and build a tree. It's like xmlParseFile()
761 * except it bypass all catalog lookups.
762 *
763 * Returns the resulting document tree or NULL in case of error
764 */
765
766xmlDocPtr
767xmlParseCatalogFile(const char *filename) {
768 xmlDocPtr ret;
769 xmlParserCtxtPtr ctxt;
770 char *directory = NULL;
771 xmlParserInputPtr inputStream;
772 xmlParserInputBufferPtr buf;
773
774 ctxt = xmlNewParserCtxt();
775 if (ctxt == NULL) {
776 if (xmlDefaultSAXHandler.error != NULL) {
777 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
778 }
779 return(NULL);
780 }
781
782 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
783 if (buf == NULL) {
784 xmlFreeParserCtxt(ctxt);
785 return(NULL);
786 }
787
788 inputStream = xmlNewInputStream(ctxt);
789 if (inputStream == NULL) {
790 xmlFreeParserCtxt(ctxt);
791 return(NULL);
792 }
793
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000794 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000795 inputStream->buf = buf;
796 inputStream->base = inputStream->buf->buffer->content;
797 inputStream->cur = inputStream->buf->buffer->content;
798 inputStream->end =
799 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
800
801 inputPush(ctxt, inputStream);
802 if ((ctxt->directory == NULL) && (directory == NULL))
803 directory = xmlParserGetDirectory(filename);
804 if ((ctxt->directory == NULL) && (directory != NULL))
805 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000806 ctxt->valid = 0;
807 ctxt->validate = 0;
808 ctxt->loadsubset = 0;
809 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000810
811 xmlParseDocument(ctxt);
812
813 if (ctxt->wellFormed)
814 ret = ctxt->myDoc;
815 else {
816 ret = NULL;
817 xmlFreeDoc(ctxt->myDoc);
818 ctxt->myDoc = NULL;
819 }
820 xmlFreeParserCtxt(ctxt);
821
822 return(ret);
823}
824
Daniel Veillard75b96822001-10-11 18:59:45 +0000825/**
826 * xmlLoadFileContent:
827 * @filename: a file path
828 *
829 * Load a file content into memory.
830 *
831 * Returns a pointer to the 0 terminated string or NULL in case of error
832 */
833static xmlChar *
834xmlLoadFileContent(const char *filename)
835{
836#ifdef HAVE_STAT
837 int fd;
838#else
839 FILE *fd;
840#endif
841 int len;
842 long size;
843
844#ifdef HAVE_STAT
845 struct stat info;
846#endif
847 xmlChar *content;
848
849 if (filename == NULL)
850 return (NULL);
851
852#ifdef HAVE_STAT
853 if (stat(filename, &info) < 0)
854 return (NULL);
855#endif
856
857#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000858 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000859#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000860 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000861#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000862 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000863 return (NULL);
864 }
865#ifdef HAVE_STAT
866 size = info.st_size;
867#else
868 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
869 fclose(fd);
870 return (NULL);
871 }
872#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000873 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000874 if (content == NULL) {
875 xmlGenericError(xmlGenericErrorContext,
876 "malloc of %d byte failed\n", size + 10);
877 return (NULL);
878 }
879#ifdef HAVE_STAT
880 len = read(fd, content, size);
881#else
882 len = fread(content, 1, size, fd);
883#endif
884 if (len < 0) {
885 xmlFree(content);
886 return (NULL);
887 }
888#ifdef HAVE_STAT
889 close(fd);
890#else
891 fclose(fd);
892#endif
893 content[len] = 0;
894
895 return(content);
896}
897
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000898/************************************************************************
899 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000900 * The XML Catalog parser *
901 * *
902 ************************************************************************/
903
904static xmlCatalogEntryPtr
905xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000906static void
907xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
908 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000909static xmlChar *
910xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
911 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000912static xmlChar *
913xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
914
Daniel Veillard344cee72001-08-20 00:08:40 +0000915
Daniel Veillard75b96822001-10-11 18:59:45 +0000916/**
917 * xmlGetXMLCatalogEntryType:
918 * @name: the name
919 *
920 * lookup the internal type associated to an XML catalog entry name
921 *
922 * Returns the type associate with that name
923 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000924static xmlCatalogEntryType
925xmlGetXMLCatalogEntryType(const xmlChar *name) {
926 xmlCatalogEntryType type = XML_CATA_NONE;
927 if (xmlStrEqual(name, (const xmlChar *) "system"))
928 type = XML_CATA_SYSTEM;
929 else if (xmlStrEqual(name, (const xmlChar *) "public"))
930 type = XML_CATA_PUBLIC;
931 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
932 type = XML_CATA_REWRITE_SYSTEM;
933 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
934 type = XML_CATA_DELEGATE_PUBLIC;
935 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
936 type = XML_CATA_DELEGATE_SYSTEM;
937 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
938 type = XML_CATA_URI;
939 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
940 type = XML_CATA_REWRITE_URI;
941 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
942 type = XML_CATA_DELEGATE_URI;
943 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
944 type = XML_CATA_NEXT_CATALOG;
945 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
946 type = XML_CATA_CATALOG;
947 return(type);
948}
949
Daniel Veillard75b96822001-10-11 18:59:45 +0000950/**
951 * xmlParseXMLCatalogOneNode:
952 * @cur: the XML node
953 * @type: the type of Catalog entry
954 * @name: the name of the node
955 * @attrName: the attribute holding the value
956 * @uriAttrName: the attribute holding the URI-Reference
957 * @prefer: the PUBLIC vs. SYSTEM current preference value
958 *
959 * Finishes the examination of an XML tree node of a catalog and build
960 * a Catalog entry from it.
961 *
962 * Returns the new Catalog entry node or NULL in case of error.
963 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000964static xmlCatalogEntryPtr
965xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
966 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000967 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000968 int ok = 1;
969 xmlChar *uriValue;
970 xmlChar *nameValue = NULL;
971 xmlChar *base = NULL;
972 xmlChar *URL = NULL;
973 xmlCatalogEntryPtr ret = NULL;
974
975 if (attrName != NULL) {
976 nameValue = xmlGetProp(cur, attrName);
977 if (nameValue == NULL) {
978 xmlGenericError(xmlGenericErrorContext,
979 "%s entry lacks '%s'\n", name, attrName);
980 ok = 0;
981 }
982 }
983 uriValue = xmlGetProp(cur, uriAttrName);
984 if (uriValue == NULL) {
985 xmlGenericError(xmlGenericErrorContext,
986 "%s entry lacks '%s'\n", name, uriAttrName);
987 ok = 0;
988 }
989 if (!ok) {
990 if (nameValue != NULL)
991 xmlFree(nameValue);
992 if (uriValue != NULL)
993 xmlFree(uriValue);
994 return(NULL);
995 }
996
997 base = xmlNodeGetBase(cur->doc, cur);
998 URL = xmlBuildURI(uriValue, base);
999 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001000 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001001 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001002 xmlGenericError(xmlGenericErrorContext,
1003 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001004 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001005 xmlGenericError(xmlGenericErrorContext,
1006 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001007 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001008 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001009 } else {
1010 xmlGenericError(xmlGenericErrorContext,
1011 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1012 }
1013 if (nameValue != NULL)
1014 xmlFree(nameValue);
1015 if (uriValue != NULL)
1016 xmlFree(uriValue);
1017 if (base != NULL)
1018 xmlFree(base);
1019 if (URL != NULL)
1020 xmlFree(URL);
1021 return(ret);
1022}
1023
Daniel Veillard75b96822001-10-11 18:59:45 +00001024/**
1025 * xmlParseXMLCatalogNode:
1026 * @cur: the XML node
1027 * @prefer: the PUBLIC vs. SYSTEM current preference value
1028 * @parent: the parent Catalog entry
1029 *
1030 * Examines an XML tree node of a catalog and build
1031 * a Catalog entry from it adding it to its parent. The examination can
1032 * be recursive.
1033 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001034static void
1035xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1036 xmlCatalogEntryPtr parent)
1037{
1038 xmlChar *uri = NULL;
1039 xmlChar *URL = NULL;
1040 xmlChar *base = NULL;
1041 xmlCatalogEntryPtr entry = NULL;
1042
1043 if (cur == NULL)
1044 return;
1045 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1046 xmlChar *prop;
1047
1048 prop = xmlGetProp(cur, BAD_CAST "prefer");
1049 if (prop != NULL) {
1050 if (xmlStrEqual(prop, BAD_CAST "system")) {
1051 prefer = XML_CATA_PREFER_SYSTEM;
1052 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1053 prefer = XML_CATA_PREFER_PUBLIC;
1054 } else {
1055 xmlGenericError(xmlGenericErrorContext,
1056 "Invalid value for prefer: '%s'\n", prop);
1057 }
1058 xmlFree(prop);
1059 }
1060 /*
1061 * Recurse to propagate prefer to the subtree
1062 * (xml:base handling is automated)
1063 */
1064 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1065 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1066 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001067 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001068 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1069 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001070 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001071 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1072 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1073 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001074 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001075 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1076 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1077 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001078 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001079 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1080 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1081 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001082 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001083 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1084 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1085 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001086 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001087 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1088 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1089 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001090 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001091 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1092 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1093 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001094 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001095 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1096 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1097 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001098 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001099 }
1100 if ((entry != NULL) && (parent != NULL)) {
1101 entry->parent = parent;
1102 if (parent->children == NULL)
1103 parent->children = entry;
1104 else {
1105 xmlCatalogEntryPtr prev;
1106
1107 prev = parent->children;
1108 while (prev->next != NULL)
1109 prev = prev->next;
1110 prev->next = entry;
1111 }
1112 }
1113 if (base != NULL)
1114 xmlFree(base);
1115 if (uri != NULL)
1116 xmlFree(uri);
1117 if (URL != NULL)
1118 xmlFree(URL);
1119}
1120
Daniel Veillard75b96822001-10-11 18:59:45 +00001121/**
1122 * xmlParseXMLCatalogNodeList:
1123 * @cur: the XML node list of siblings
1124 * @prefer: the PUBLIC vs. SYSTEM current preference value
1125 * @parent: the parent Catalog entry
1126 *
1127 * Examines a list of XML sibling nodes of a catalog and build
1128 * a list of Catalog entry from it adding it to the parent.
1129 * The examination will recurse to examine node subtrees.
1130 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001131static void
1132xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1133 xmlCatalogEntryPtr parent) {
1134 while (cur != NULL) {
1135 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1136 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1137 xmlParseXMLCatalogNode(cur, prefer, parent);
1138 }
1139 cur = cur->next;
1140 }
1141 /* TODO: sort the list according to REWRITE lengths and prefer value */
1142}
1143
Daniel Veillard75b96822001-10-11 18:59:45 +00001144/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001145 * xmlParseXMLCatalogFile:
1146 * @prefer: the PUBLIC vs. SYSTEM current preference value
1147 * @filename: the filename for the catalog
1148 *
1149 * Parses the catalog file to extract the XML tree and then analyze the
1150 * tree to build a list of Catalog entries corresponding to this catalog
1151 *
1152 * Returns the resulting Catalog entries list
1153 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001154static xmlCatalogEntryPtr
1155xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1156 xmlDocPtr doc;
1157 xmlNodePtr cur;
1158 xmlChar *prop;
1159 xmlCatalogEntryPtr parent = NULL;
1160
1161 if (filename == NULL)
1162 return(NULL);
1163
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001164 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001165 if (doc == NULL) {
1166 if (xmlDebugCatalogs)
1167 xmlGenericError(xmlGenericErrorContext,
1168 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001169 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001170 }
1171
1172 if (xmlDebugCatalogs)
1173 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001174 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001175
1176 cur = xmlDocGetRootElement(doc);
1177 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1178 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1179 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1180
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001181 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00001182 (const xmlChar *)filename, NULL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001183 if (parent == NULL) {
1184 xmlFreeDoc(doc);
1185 return(NULL);
1186 }
1187
1188 prop = xmlGetProp(cur, BAD_CAST "prefer");
1189 if (prop != NULL) {
1190 if (xmlStrEqual(prop, BAD_CAST "system")) {
1191 prefer = XML_CATA_PREFER_SYSTEM;
1192 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1193 prefer = XML_CATA_PREFER_PUBLIC;
1194 } else {
1195 xmlGenericError(xmlGenericErrorContext,
1196 "Invalid value for prefer: '%s'\n",
1197 prop);
1198 }
1199 xmlFree(prop);
1200 }
1201 cur = cur->children;
1202 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1203 } else {
1204 xmlGenericError(xmlGenericErrorContext,
1205 "File %s is not an XML Catalog\n", filename);
1206 xmlFreeDoc(doc);
1207 return(NULL);
1208 }
1209 xmlFreeDoc(doc);
1210 return(parent);
1211}
1212
Daniel Veillardcda96922001-08-21 10:56:31 +00001213/**
1214 * xmlFetchXMLCatalogFile:
1215 * @catal: an existing but incomplete catalog entry
1216 *
1217 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001218 *
1219 * Returns 0 in case of success, -1 otherwise
1220 */
1221static int
1222xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001223 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001224
1225 if (catal == NULL)
1226 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001227 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001228 return(-1);
1229 if (catal->children != NULL)
1230 return(-1);
1231
Daniel Veillard81463942001-10-16 12:34:39 +00001232 /*
1233 * lock the whole catalog for modification
1234 */
1235 xmlRMutexLock(xmlCatalogMutex);
1236 if (catal->children != NULL) {
1237 /* Okay someone else did it in the meantime */
1238 xmlRMutexUnlock(xmlCatalogMutex);
1239 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001240 }
1241
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001242 if (xmlCatalogXMLFiles != NULL) {
1243 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001244 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001245 if (doc != NULL) {
1246 if (xmlDebugCatalogs)
1247 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001248 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001249
1250 if (catal->type == XML_CATA_CATALOG)
1251 catal->children = doc->children;
1252 else
1253 catal->children = doc;
1254 catal->dealloc = 0;
1255 xmlRMutexUnlock(xmlCatalogMutex);
1256 return(0);
1257 }
1258 if (xmlDebugCatalogs)
1259 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001260 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001261 }
1262
Daniel Veillardcda96922001-08-21 10:56:31 +00001263 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001264 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001265 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001266 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001267 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001268 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001269 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001270 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001271 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001272 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001273 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001274
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001275 if (catal->type == XML_CATA_CATALOG)
1276 catal->children = doc->children;
1277 else
1278 catal->children = doc;
1279
1280 doc->dealloc = 1;
1281
Daniel Veillard81463942001-10-16 12:34:39 +00001282 if (xmlCatalogXMLFiles == NULL)
1283 xmlCatalogXMLFiles = xmlHashCreate(10);
1284 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001285 if (xmlDebugCatalogs)
1286 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001287 "%s added to file hash\n", catal->URL);
1288 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001289 }
Daniel Veillard81463942001-10-16 12:34:39 +00001290 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001291 return(0);
1292}
1293
Daniel Veillard75b96822001-10-11 18:59:45 +00001294/************************************************************************
1295 * *
1296 * XML Catalog handling *
1297 * *
1298 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001299
1300/**
1301 * xmlAddXMLCatalog:
1302 * @catal: top of an XML catalog
1303 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001304 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001305 * @replace: the replacement value for the match
1306 *
1307 * Add an entry in the XML catalog, it may overwrite existing but
1308 * different entries.
1309 *
1310 * Returns 0 if successful, -1 otherwise
1311 */
1312static int
1313xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1314 const xmlChar *orig, const xmlChar *replace) {
1315 xmlCatalogEntryPtr cur;
1316 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001317 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001318
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001319 if ((catal == NULL) ||
1320 ((catal->type != XML_CATA_CATALOG) &&
1321 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001322 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001323 if (catal->children == NULL) {
1324 xmlFetchXMLCatalogFile(catal);
1325 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001326 if (catal->children == NULL)
1327 doregister = 1;
1328
Daniel Veillard344cee72001-08-20 00:08:40 +00001329 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001330 if (typ == XML_CATA_NONE) {
1331 if (xmlDebugCatalogs)
1332 xmlGenericError(xmlGenericErrorContext,
1333 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001334 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001335 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001336
1337 cur = catal->children;
1338 /*
1339 * Might be a simple "update in place"
1340 */
1341 if (cur != NULL) {
1342 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001343 if ((orig != NULL) && (cur->type == typ) &&
1344 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001345 if (xmlDebugCatalogs)
1346 xmlGenericError(xmlGenericErrorContext,
1347 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001348 if (cur->value != NULL)
1349 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001350 if (cur->URL != NULL)
1351 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001352 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001353 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001354 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001355 }
1356 if (cur->next == NULL)
1357 break;
1358 cur = cur->next;
1359 }
1360 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001361 if (xmlDebugCatalogs)
1362 xmlGenericError(xmlGenericErrorContext,
1363 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001364 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001365 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1366 NULL, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001367 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001368 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1369 NULL, catal->prefer);
1370 if (doregister) {
1371 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1372 if (cur != NULL)
1373 cur->children = catal->children;
1374 }
1375
Daniel Veillardcda96922001-08-21 10:56:31 +00001376 return(0);
1377}
1378
1379/**
1380 * xmlDelXMLCatalog:
1381 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001382 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001383 *
1384 * Remove entries in the XML catalog where the value or the URI
1385 * is equal to @value
1386 *
1387 * Returns the number of entries removed if successful, -1 otherwise
1388 */
1389static int
1390xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001391 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001392 int ret = 0;
1393
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001394 if ((catal == NULL) ||
1395 ((catal->type != XML_CATA_CATALOG) &&
1396 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001397 return(-1);
1398 if (value == NULL)
1399 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001400 if (catal->children == NULL) {
1401 xmlFetchXMLCatalogFile(catal);
1402 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001403
1404 /*
1405 * Scan the children
1406 */
1407 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001408 while (cur != NULL) {
1409 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1410 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001411 if (xmlDebugCatalogs) {
1412 if (cur->name != NULL)
1413 xmlGenericError(xmlGenericErrorContext,
1414 "Removing element %s from catalog\n", cur->name);
1415 else
1416 xmlGenericError(xmlGenericErrorContext,
1417 "Removing element %s from catalog\n", cur->value);
1418 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001419 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001420 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001421 cur = cur->next;
1422 }
1423 return(ret);
1424}
1425
1426/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001427 * xmlCatalogXMLResolve:
1428 * @catal: a catalog list
1429 * @pubId: the public ID string
1430 * @sysId: the system ID string
1431 *
1432 * Do a complete resolution lookup of an External Identifier for a
1433 * list of catalog entries.
1434 *
1435 * Implements (or tries to) 7.1. External Identifier Resolution
1436 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1437 *
1438 * Returns the URI of the resource or NULL if not found
1439 */
1440static xmlChar *
1441xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1442 const xmlChar *sysID) {
1443 xmlChar *ret = NULL;
1444 xmlCatalogEntryPtr cur;
1445 int haveDelegate = 0;
1446 int haveNext = 0;
1447
1448 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001449 * protection against loops
1450 */
1451 if (catal->depth > MAX_CATAL_DEPTH) {
1452 if (catal->name != NULL)
1453 xmlGenericError(xmlGenericErrorContext,
1454 "Detected recursion in catalog %s\n", catal->name);
1455 else
1456 xmlGenericError(xmlGenericErrorContext,
1457 "Detected recursion in catalog\n");
1458 return(NULL);
1459 }
1460 catal->depth++;
1461
1462 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001463 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1464 */
1465 if (sysID != NULL) {
1466 xmlCatalogEntryPtr rewrite = NULL;
1467 int lenrewrite = 0, len;
1468 cur = catal;
1469 haveDelegate = 0;
1470 while (cur != NULL) {
1471 switch (cur->type) {
1472 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001473 if (xmlStrEqual(sysID, cur->name)) {
1474 if (xmlDebugCatalogs)
1475 xmlGenericError(xmlGenericErrorContext,
1476 "Found system match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001477 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001478 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001479 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001480 break;
1481 case XML_CATA_REWRITE_SYSTEM:
1482 len = xmlStrlen(cur->name);
1483 if ((len > lenrewrite) &&
1484 (!xmlStrncmp(sysID, cur->name, len))) {
1485 lenrewrite = len;
1486 rewrite = cur;
1487 }
1488 break;
1489 case XML_CATA_DELEGATE_SYSTEM:
1490 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1491 haveDelegate++;
1492 break;
1493 case XML_CATA_NEXT_CATALOG:
1494 haveNext++;
1495 break;
1496 default:
1497 break;
1498 }
1499 cur = cur->next;
1500 }
1501 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001502 if (xmlDebugCatalogs)
1503 xmlGenericError(xmlGenericErrorContext,
1504 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001505 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001506 if (ret != NULL)
1507 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001508 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001509 return(ret);
1510 }
1511 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001512 const xmlChar *delegates[MAX_DELEGATE];
1513 int nbList = 0, i;
1514
Daniel Veillardcda96922001-08-21 10:56:31 +00001515 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001516 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001517 * matches when the list was produced.
1518 */
1519 cur = catal;
1520 while (cur != NULL) {
1521 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1522 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001523 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001524 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001525 break;
1526 if (i < nbList) {
1527 cur = cur->next;
1528 continue;
1529 }
1530 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001531 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001532
Daniel Veillardcda96922001-08-21 10:56:31 +00001533 if (cur->children == NULL) {
1534 xmlFetchXMLCatalogFile(cur);
1535 }
1536 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001537 if (xmlDebugCatalogs)
1538 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001539 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001540 ret = xmlCatalogListXMLResolve(
1541 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001542 if (ret != NULL) {
1543 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001544 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001545 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001546 }
1547 }
1548 cur = cur->next;
1549 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001550 /*
1551 * Apply the cut algorithm explained in 4/
1552 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001553 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001554 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001555 }
1556 }
1557 /*
1558 * Then tries 5/ 6/ if a public ID is provided
1559 */
1560 if (pubID != NULL) {
1561 cur = catal;
1562 haveDelegate = 0;
1563 while (cur != NULL) {
1564 switch (cur->type) {
1565 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001566 if (xmlStrEqual(pubID, cur->name)) {
1567 if (xmlDebugCatalogs)
1568 xmlGenericError(xmlGenericErrorContext,
1569 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001570 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001571 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001572 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001573 break;
1574 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001575 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1576 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001577 haveDelegate++;
1578 break;
1579 case XML_CATA_NEXT_CATALOG:
1580 if (sysID == NULL)
1581 haveNext++;
1582 break;
1583 default:
1584 break;
1585 }
1586 cur = cur->next;
1587 }
1588 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001589 const xmlChar *delegates[MAX_DELEGATE];
1590 int nbList = 0, i;
1591
Daniel Veillardcda96922001-08-21 10:56:31 +00001592 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001593 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001594 * matches when the list was produced.
1595 */
1596 cur = catal;
1597 while (cur != NULL) {
1598 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001599 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1600 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001601
1602 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001603 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001604 break;
1605 if (i < nbList) {
1606 cur = cur->next;
1607 continue;
1608 }
1609 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001610 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001611
Daniel Veillardcda96922001-08-21 10:56:31 +00001612 if (cur->children == NULL) {
1613 xmlFetchXMLCatalogFile(cur);
1614 }
1615 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001616 if (xmlDebugCatalogs)
1617 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001618 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001619 ret = xmlCatalogListXMLResolve(
1620 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001621 if (ret != NULL) {
1622 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001623 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001624 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001625 }
1626 }
1627 cur = cur->next;
1628 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001629 /*
1630 * Apply the cut algorithm explained in 4/
1631 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001632 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001633 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001634 }
1635 }
1636 if (haveNext) {
1637 cur = catal;
1638 while (cur != NULL) {
1639 if (cur->type == XML_CATA_NEXT_CATALOG) {
1640 if (cur->children == NULL) {
1641 xmlFetchXMLCatalogFile(cur);
1642 }
1643 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001644 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001645 if (ret != NULL) {
1646 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001647 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001648 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001649 }
1650 }
1651 cur = cur->next;
1652 }
1653 }
1654
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001655 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001656 return(NULL);
1657}
1658
1659/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001660 * xmlCatalogXMLResolveURI:
1661 * @catal: a catalog list
1662 * @URI: the URI
1663 * @sysId: the system ID string
1664 *
1665 * Do a complete resolution lookup of an External Identifier for a
1666 * list of catalog entries.
1667 *
1668 * Implements (or tries to) 7.2.2. URI Resolution
1669 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1670 *
1671 * Returns the URI of the resource or NULL if not found
1672 */
1673static xmlChar *
1674xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1675 xmlChar *ret = NULL;
1676 xmlCatalogEntryPtr cur;
1677 int haveDelegate = 0;
1678 int haveNext = 0;
1679 xmlCatalogEntryPtr rewrite = NULL;
1680 int lenrewrite = 0, len;
1681
1682 if (catal == NULL)
1683 return(NULL);
1684
1685 if (URI == NULL)
1686 return(NULL);
1687
1688 /*
1689 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1690 */
1691 cur = catal;
1692 haveDelegate = 0;
1693 while (cur != NULL) {
1694 switch (cur->type) {
1695 case XML_CATA_URI:
1696 if (xmlStrEqual(URI, cur->name)) {
1697 if (xmlDebugCatalogs)
1698 xmlGenericError(xmlGenericErrorContext,
1699 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001700 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001701 }
1702 break;
1703 case XML_CATA_REWRITE_URI:
1704 len = xmlStrlen(cur->name);
1705 if ((len > lenrewrite) &&
1706 (!xmlStrncmp(URI, cur->name, len))) {
1707 lenrewrite = len;
1708 rewrite = cur;
1709 }
1710 break;
1711 case XML_CATA_DELEGATE_URI:
1712 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1713 haveDelegate++;
1714 break;
1715 case XML_CATA_NEXT_CATALOG:
1716 haveNext++;
1717 break;
1718 default:
1719 break;
1720 }
1721 cur = cur->next;
1722 }
1723 if (rewrite != NULL) {
1724 if (xmlDebugCatalogs)
1725 xmlGenericError(xmlGenericErrorContext,
1726 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001727 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001728 if (ret != NULL)
1729 ret = xmlStrcat(ret, &URI[lenrewrite]);
1730 return(ret);
1731 }
1732 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001733 const xmlChar *delegates[MAX_DELEGATE];
1734 int nbList = 0, i;
1735
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001736 /*
1737 * Assume the entries have been sorted by decreasing substring
1738 * matches when the list was produced.
1739 */
1740 cur = catal;
1741 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001742 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1743 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001744 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001745 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001746 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001747 break;
1748 if (i < nbList) {
1749 cur = cur->next;
1750 continue;
1751 }
1752 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001753 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001754
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001755 if (cur->children == NULL) {
1756 xmlFetchXMLCatalogFile(cur);
1757 }
1758 if (cur->children != NULL) {
1759 if (xmlDebugCatalogs)
1760 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001761 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001762 ret = xmlCatalogListXMLResolveURI(
1763 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001764 if (ret != NULL)
1765 return(ret);
1766 }
1767 }
1768 cur = cur->next;
1769 }
1770 /*
1771 * Apply the cut algorithm explained in 4/
1772 */
1773 return(XML_CATAL_BREAK);
1774 }
1775 if (haveNext) {
1776 cur = catal;
1777 while (cur != NULL) {
1778 if (cur->type == XML_CATA_NEXT_CATALOG) {
1779 if (cur->children == NULL) {
1780 xmlFetchXMLCatalogFile(cur);
1781 }
1782 if (cur->children != NULL) {
1783 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1784 if (ret != NULL)
1785 return(ret);
1786 }
1787 }
1788 cur = cur->next;
1789 }
1790 }
1791
1792 return(NULL);
1793}
1794
1795/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001796 * xmlCatalogListXMLResolve:
1797 * @catal: a catalog list
1798 * @pubId: the public ID string
1799 * @sysId: the system ID string
1800 *
1801 * Do a complete resolution lookup of an External Identifier for a
1802 * list of catalogs
1803 *
1804 * Implements (or tries to) 7.1. External Identifier Resolution
1805 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1806 *
1807 * Returns the URI of the resource or NULL if not found
1808 */
1809static xmlChar *
1810xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1811 const xmlChar *sysID) {
1812 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001813 xmlChar *urnID = NULL;
1814
1815 if (catal == NULL)
1816 return(NULL);
1817 if ((pubID == NULL) && (sysID == NULL))
1818 return(NULL);
1819
1820 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1821 urnID = xmlCatalogUnWrapURN(pubID);
1822 if (xmlDebugCatalogs) {
1823 if (urnID == NULL)
1824 xmlGenericError(xmlGenericErrorContext,
1825 "Public URN ID %s expanded to NULL\n", pubID);
1826 else
1827 xmlGenericError(xmlGenericErrorContext,
1828 "Public URN ID expanded to %s\n", urnID);
1829 }
1830 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1831 if (urnID != NULL)
1832 xmlFree(urnID);
1833 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001834 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001835 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1836 urnID = xmlCatalogUnWrapURN(sysID);
1837 if (xmlDebugCatalogs) {
1838 if (urnID == NULL)
1839 xmlGenericError(xmlGenericErrorContext,
1840 "System URN ID %s expanded to NULL\n", sysID);
1841 else
1842 xmlGenericError(xmlGenericErrorContext,
1843 "System URN ID expanded to %s\n", urnID);
1844 }
1845 if (pubID == NULL)
1846 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1847 else if (xmlStrEqual(pubID, urnID))
1848 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1849 else {
1850 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1851 }
1852 if (urnID != NULL)
1853 xmlFree(urnID);
1854 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001855 }
1856 while (catal != NULL) {
1857 if (catal->type == XML_CATA_CATALOG) {
1858 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001859 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001860 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001861 if (catal->children != NULL) {
1862 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1863 if (ret != NULL)
1864 return(ret);
1865 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001866 }
1867 catal = catal->next;
1868 }
1869 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001870}
1871
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001872/**
1873 * xmlCatalogListXMLResolveURI:
1874 * @catal: a catalog list
1875 * @URI: the URI
1876 *
1877 * Do a complete resolution lookup of an URI for a list of catalogs
1878 *
1879 * Implements (or tries to) 7.2. URI Resolution
1880 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1881 *
1882 * Returns the URI of the resource or NULL if not found
1883 */
1884static xmlChar *
1885xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1886 xmlChar *ret = NULL;
1887 xmlChar *urnID = NULL;
1888
1889 if (catal == NULL)
1890 return(NULL);
1891 if (URI == NULL)
1892 return(NULL);
1893
1894 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1895 urnID = xmlCatalogUnWrapURN(URI);
1896 if (xmlDebugCatalogs) {
1897 if (urnID == NULL)
1898 xmlGenericError(xmlGenericErrorContext,
1899 "URN ID %s expanded to NULL\n", URI);
1900 else
1901 xmlGenericError(xmlGenericErrorContext,
1902 "URN ID expanded to %s\n", urnID);
1903 }
1904 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1905 if (urnID != NULL)
1906 xmlFree(urnID);
1907 return(ret);
1908 }
1909 while (catal != NULL) {
1910 if (catal->type == XML_CATA_CATALOG) {
1911 if (catal->children == NULL) {
1912 xmlFetchXMLCatalogFile(catal);
1913 }
1914 if (catal->children != NULL) {
1915 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1916 if (ret != NULL)
1917 return(ret);
1918 }
1919 }
1920 catal = catal->next;
1921 }
1922 return(ret);
1923}
1924
Daniel Veillard344cee72001-08-20 00:08:40 +00001925/************************************************************************
1926 * *
1927 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001928 * *
1929 ************************************************************************/
1930
1931
1932#define RAW *cur
1933#define NEXT cur++;
1934#define SKIP(x) cur += x;
1935
1936#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1937
Daniel Veillard75b96822001-10-11 18:59:45 +00001938/**
1939 * xmlParseSGMLCatalogComment:
1940 * @cur: the current character
1941 *
1942 * Skip a comment in an SGML catalog
1943 *
1944 * Returns new current character
1945 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001946static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001947xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001948 if ((cur[0] != '-') || (cur[1] != '-'))
1949 return(cur);
1950 SKIP(2);
1951 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1952 NEXT;
1953 if (cur[0] == 0) {
1954 return(NULL);
1955 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001956 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001957}
1958
Daniel Veillard75b96822001-10-11 18:59:45 +00001959/**
1960 * xmlParseSGMLCatalogPubid:
1961 * @cur: the current character
1962 * @id: the return location
1963 *
1964 * Parse an SGML catalog ID
1965 *
1966 * Returns new current character and store the value in @id
1967 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001968static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001969xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001970 xmlChar *buf = NULL;
1971 int len = 0;
1972 int size = 50;
1973 xmlChar stop;
1974 int count = 0;
1975
1976 *id = NULL;
1977
1978 if (RAW == '"') {
1979 NEXT;
1980 stop = '"';
1981 } else if (RAW == '\'') {
1982 NEXT;
1983 stop = '\'';
1984 } else {
1985 stop = ' ';
1986 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00001987 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00001988 if (buf == NULL) {
1989 xmlGenericError(xmlGenericErrorContext,
1990 "malloc of %d byte failed\n", size);
1991 return(NULL);
1992 }
Daniel Veillard935494a2002-10-22 14:22:46 +00001993 while (xmlIsPubidChar(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001994 if ((*cur == stop) && (stop != ' '))
1995 break;
1996 if ((stop == ' ') && (IS_BLANK(*cur)))
1997 break;
1998 if (len + 1 >= size) {
1999 size *= 2;
2000 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2001 if (buf == NULL) {
2002 xmlGenericError(xmlGenericErrorContext,
2003 "realloc of %d byte failed\n", size);
2004 return(NULL);
2005 }
2006 }
2007 buf[len++] = *cur;
2008 count++;
2009 NEXT;
2010 }
2011 buf[len] = 0;
2012 if (stop == ' ') {
2013 if (!IS_BLANK(*cur)) {
2014 xmlFree(buf);
2015 return(NULL);
2016 }
2017 } else {
2018 if (*cur != stop) {
2019 xmlFree(buf);
2020 return(NULL);
2021 }
2022 NEXT;
2023 }
2024 *id = buf;
2025 return(cur);
2026}
2027
Daniel Veillard75b96822001-10-11 18:59:45 +00002028/**
2029 * xmlParseSGMLCatalogName:
2030 * @cur: the current character
2031 * @name: the return location
2032 *
2033 * Parse an SGML catalog name
2034 *
2035 * Returns new current character and store the value in @name
2036 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002037static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002038xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002039 xmlChar buf[XML_MAX_NAMELEN + 5];
2040 int len = 0;
2041 int c;
2042
2043 *name = NULL;
2044
2045 /*
2046 * Handler for more complex cases
2047 */
2048 c = *cur;
2049 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2050 return(NULL);
2051 }
2052
2053 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2054 (c == '.') || (c == '-') ||
2055 (c == '_') || (c == ':'))) {
2056 buf[len++] = c;
2057 cur++;
2058 c = *cur;
2059 if (len >= XML_MAX_NAMELEN)
2060 return(NULL);
2061 }
2062 *name = xmlStrndup(buf, len);
2063 return(cur);
2064}
2065
Daniel Veillard75b96822001-10-11 18:59:45 +00002066/**
2067 * xmlGetSGMLCatalogEntryType:
2068 * @name: the entry name
2069 *
2070 * Get the Catalog entry type for a given SGML Catalog name
2071 *
2072 * Returns Catalog entry type
2073 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002074static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002075xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002076 xmlCatalogEntryType type = XML_CATA_NONE;
2077 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2078 type = SGML_CATA_SYSTEM;
2079 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2080 type = SGML_CATA_PUBLIC;
2081 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2082 type = SGML_CATA_DELEGATE;
2083 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2084 type = SGML_CATA_ENTITY;
2085 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2086 type = SGML_CATA_DOCTYPE;
2087 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2088 type = SGML_CATA_LINKTYPE;
2089 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2090 type = SGML_CATA_NOTATION;
2091 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2092 type = SGML_CATA_SGMLDECL;
2093 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2094 type = SGML_CATA_DOCUMENT;
2095 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2096 type = SGML_CATA_CATALOG;
2097 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2098 type = SGML_CATA_BASE;
2099 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2100 type = SGML_CATA_DELEGATE;
2101 return(type);
2102}
2103
Daniel Veillard75b96822001-10-11 18:59:45 +00002104/**
2105 * xmlParseSGMLCatalog:
2106 * @catal: the SGML Catalog
2107 * @value: the content of the SGML Catalog serialization
2108 * @file: the filepath for the catalog
2109 * @super: should this be handled as a Super Catalog in which case
2110 * parsing is not recursive
2111 *
2112 * Parse an SGML catalog content and fill up the @catal hash table with
2113 * the new entries found.
2114 *
2115 * Returns 0 in case of success, -1 in case of error.
2116 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002117static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002118xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2119 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002120 const xmlChar *cur = value;
2121 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002122 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002123
2124 if ((cur == NULL) || (file == NULL))
2125 return(-1);
2126 base = xmlStrdup((const xmlChar *) file);
2127
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002128 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002129 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002130 if (cur[0] == 0)
2131 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002132 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002133 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002134 if (cur == NULL) {
2135 /* error */
2136 break;
2137 }
2138 } else {
2139 xmlChar *sysid = NULL;
2140 xmlChar *name = NULL;
2141 xmlCatalogEntryType type = XML_CATA_NONE;
2142
Daniel Veillardcda96922001-08-21 10:56:31 +00002143 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002144 if (name == NULL) {
2145 /* error */
2146 break;
2147 }
2148 if (!IS_BLANK(*cur)) {
2149 /* error */
2150 break;
2151 }
2152 SKIP_BLANKS;
2153 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002154 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002155 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002156 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002157 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002158 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002159 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002160 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002161 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002162 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002163 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002164 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002165 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002166 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002167 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002168 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002169 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002170 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002171 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002172 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002173 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002174 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002175 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002176 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002177 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2178 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002179 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002180 if (name == NULL) {
2181 /* error */
2182 break;
2183 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002184 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002185 continue;
2186 }
2187 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002188 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002189
2190 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002191 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002192 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002193 type = SGML_CATA_PENTITY;
2194 case SGML_CATA_PENTITY:
2195 case SGML_CATA_DOCTYPE:
2196 case SGML_CATA_LINKTYPE:
2197 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002198 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002199 if (cur == NULL) {
2200 /* error */
2201 break;
2202 }
2203 if (!IS_BLANK(*cur)) {
2204 /* error */
2205 break;
2206 }
2207 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002208 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002209 if (cur == NULL) {
2210 /* error */
2211 break;
2212 }
2213 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002214 case SGML_CATA_PUBLIC:
2215 case SGML_CATA_SYSTEM:
2216 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002217 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002218 if (cur == NULL) {
2219 /* error */
2220 break;
2221 }
2222 if (!IS_BLANK(*cur)) {
2223 /* error */
2224 break;
2225 }
2226 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002227 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002228 if (cur == NULL) {
2229 /* error */
2230 break;
2231 }
2232 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002233 case SGML_CATA_BASE:
2234 case SGML_CATA_CATALOG:
2235 case SGML_CATA_DOCUMENT:
2236 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002237 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002238 if (cur == NULL) {
2239 /* error */
2240 break;
2241 }
2242 break;
2243 default:
2244 break;
2245 }
2246 if (cur == NULL) {
2247 if (name != NULL)
2248 xmlFree(name);
2249 if (sysid != NULL)
2250 xmlFree(sysid);
2251 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002252 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002253 if (base != NULL)
2254 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002255 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002256 } else if ((type == SGML_CATA_PUBLIC) ||
2257 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002258 xmlChar *filename;
2259
2260 filename = xmlBuildURI(sysid, base);
2261 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002262 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002263
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002264 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002265 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002266 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002267 if (res < 0) {
2268 xmlFreeCatalogEntry(entry);
2269 }
2270 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002271 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002272
Daniel Veillard344cee72001-08-20 00:08:40 +00002273 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002274 if (super) {
2275 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002276
Daniel Veillardc853b322001-11-06 15:24:37 +00002277 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002278 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002279 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002280 if (res < 0) {
2281 xmlFreeCatalogEntry(entry);
2282 }
2283 } else {
2284 xmlChar *filename;
2285
2286 filename = xmlBuildURI(sysid, base);
2287 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002288 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002289 xmlFree(filename);
2290 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002291 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002292 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002293 /*
2294 * drop anything else we won't handle it
2295 */
2296 if (name != NULL)
2297 xmlFree(name);
2298 if (sysid != NULL)
2299 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002300 }
2301 }
2302 if (base != NULL)
2303 xmlFree(base);
2304 if (cur == NULL)
2305 return(-1);
2306 return(0);
2307}
2308
Daniel Veillard75b96822001-10-11 18:59:45 +00002309/************************************************************************
2310 * *
2311 * SGML Catalog handling *
2312 * *
2313 ************************************************************************/
2314
Daniel Veillardcda96922001-08-21 10:56:31 +00002315/**
2316 * xmlCatalogGetSGMLPublic:
2317 * @catal: an SGML catalog hash
2318 * @pubId: the public ID string
2319 *
2320 * Try to lookup the system ID associated to a public ID
2321 *
2322 * Returns the system ID if found or NULL otherwise.
2323 */
2324static const xmlChar *
2325xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2326 xmlCatalogEntryPtr entry;
2327
2328 if (catal == NULL)
2329 return(NULL);
2330
2331 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2332 if (entry == NULL)
2333 return(NULL);
2334 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillardc853b322001-11-06 15:24:37 +00002335 return(entry->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002336 return(NULL);
2337}
2338
2339/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002340 * xmlCatalogGetSGMLSystem:
2341 * @catal: an SGML catalog hash
2342 * @sysId: the public ID string
2343 *
2344 * Try to lookup the catalog local reference for a system ID
2345 *
2346 * Returns the system ID if found or NULL otherwise.
2347 */
2348static const xmlChar *
2349xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2350 xmlCatalogEntryPtr entry;
2351
2352 if (catal == NULL)
2353 return(NULL);
2354
2355 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2356 if (entry == NULL)
2357 return(NULL);
2358 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002359 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002360 return(NULL);
2361}
2362
2363/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002364 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002365 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002366 * @pubId: the public ID string
2367 * @sysId: the system ID string
2368 *
2369 * Do a complete resolution lookup of an External Identifier
2370 *
2371 * Returns the URI of the resource or NULL if not found
2372 */
2373static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002374xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2375 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002376 const xmlChar *ret = NULL;
2377
Daniel Veillard75b96822001-10-11 18:59:45 +00002378 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002379 return(NULL);
2380
2381 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002382 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002383 if (ret != NULL)
2384 return(ret);
2385 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002386 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002387 return(NULL);
2388}
2389
Daniel Veillarda7374592001-05-10 14:17:55 +00002390/************************************************************************
2391 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002392 * Specific Public interfaces *
2393 * *
2394 ************************************************************************/
2395
2396/**
2397 * xmlLoadSGMLSuperCatalog:
2398 * @filename: a file path
2399 *
2400 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2401 * references. This is only needed for manipulating SGML Super Catalogs
2402 * like adding and removing CATALOG or DELEGATE entries.
2403 *
2404 * Returns the catalog parsed or NULL in case of error
2405 */
2406xmlCatalogPtr
2407xmlLoadSGMLSuperCatalog(const char *filename)
2408{
2409 xmlChar *content;
2410 xmlCatalogPtr catal;
2411 int ret;
2412
2413 content = xmlLoadFileContent(filename);
2414 if (content == NULL)
2415 return(NULL);
2416
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002417 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002418 if (catal == NULL) {
2419 xmlFree(content);
2420 return(NULL);
2421 }
2422
2423 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2424 xmlFree(content);
2425 if (ret < 0) {
2426 xmlFreeCatalog(catal);
2427 return(NULL);
2428 }
2429 return (catal);
2430}
2431
2432/**
2433 * xmlLoadACatalog:
2434 * @filename: a file path
2435 *
2436 * Load the catalog and build the associated data structures.
2437 * This can be either an XML Catalog or an SGML Catalog
2438 * It will recurse in SGML CATALOG entries. On the other hand XML
2439 * Catalogs are not handled recursively.
2440 *
2441 * Returns the catalog parsed or NULL in case of error
2442 */
2443xmlCatalogPtr
2444xmlLoadACatalog(const char *filename)
2445{
2446 xmlChar *content;
2447 xmlChar *first;
2448 xmlCatalogPtr catal;
2449 int ret;
2450
2451 content = xmlLoadFileContent(filename);
2452 if (content == NULL)
2453 return(NULL);
2454
2455
2456 first = content;
2457
2458 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2459 (!(((*first >= 'A') && (*first <= 'Z')) ||
2460 ((*first >= 'a') && (*first <= 'z')))))
2461 first++;
2462
2463 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002464 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002465 if (catal == NULL) {
2466 xmlFree(content);
2467 return(NULL);
2468 }
2469 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2470 if (ret < 0) {
2471 xmlFreeCatalog(catal);
2472 xmlFree(content);
2473 return(NULL);
2474 }
2475 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002476 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002477 if (catal == NULL) {
2478 xmlFree(content);
2479 return(NULL);
2480 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002481 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002482 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002483 }
2484 xmlFree(content);
2485 return (catal);
2486}
2487
2488/**
2489 * xmlExpandCatalog:
2490 * @catal: a catalog
2491 * @filename: a file path
2492 *
2493 * Load the catalog and expand the existing catal structure.
2494 * This can be either an XML Catalog or an SGML Catalog
2495 *
2496 * Returns 0 in case of success, -1 in case of error
2497 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002498static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002499xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2500{
Daniel Veillard75b96822001-10-11 18:59:45 +00002501 int ret;
2502
2503 if ((catal == NULL) || (filename == NULL))
2504 return(-1);
2505
Daniel Veillard75b96822001-10-11 18:59:45 +00002506
2507 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002508 xmlChar *content;
2509
2510 content = xmlLoadFileContent(filename);
2511 if (content == NULL)
2512 return(-1);
2513
Daniel Veillard75b96822001-10-11 18:59:45 +00002514 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2515 if (ret < 0) {
2516 xmlFree(content);
2517 return(-1);
2518 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002519 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002520 } else {
2521 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002522 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002523 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002524
Daniel Veillard75b96822001-10-11 18:59:45 +00002525 cur = catal->xml;
2526 if (cur == NULL) {
2527 catal->xml = tmp;
2528 } else {
2529 while (cur->next != NULL) cur = cur->next;
2530 cur->next = tmp;
2531 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002532 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002533 return (0);
2534}
2535
2536/**
2537 * xmlACatalogResolveSystem:
2538 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002539 * @sysID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002540 *
2541 * Try to lookup the catalog resource for a system ID
2542 *
2543 * Returns the system ID if found or NULL otherwise, the value returned
2544 * must be freed by the caller.
2545 */
2546xmlChar *
2547xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2548 xmlChar *ret = NULL;
2549
2550 if ((sysID == NULL) || (catal == NULL))
2551 return(NULL);
2552
2553 if (xmlDebugCatalogs)
2554 xmlGenericError(xmlGenericErrorContext,
2555 "Resolve sysID %s\n", sysID);
2556
2557 if (catal->type == XML_XML_CATALOG_TYPE) {
2558 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2559 if (ret == XML_CATAL_BREAK)
2560 ret = NULL;
2561 } else {
2562 const xmlChar *sgml;
2563
2564 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2565 if (sgml != NULL)
2566 ret = xmlStrdup(sgml);
2567 }
2568 return(ret);
2569}
2570
2571/**
2572 * xmlACatalogResolvePublic:
2573 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002574 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002575 *
2576 * Try to lookup the system ID associated to a public ID in that catalog
2577 *
2578 * Returns the system ID if found or NULL otherwise, the value returned
2579 * must be freed by the caller.
2580 */
2581xmlChar *
2582xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2583 xmlChar *ret = NULL;
2584
2585 if ((pubID == NULL) || (catal == NULL))
2586 return(NULL);
2587
2588 if (xmlDebugCatalogs)
2589 xmlGenericError(xmlGenericErrorContext,
2590 "Resolve pubID %s\n", pubID);
2591
2592 if (catal->type == XML_XML_CATALOG_TYPE) {
2593 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2594 if (ret == XML_CATAL_BREAK)
2595 ret = NULL;
2596 } else {
2597 const xmlChar *sgml;
2598
2599 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2600 if (sgml != NULL)
2601 ret = xmlStrdup(sgml);
2602 }
2603 return(ret);
2604}
2605
2606/**
2607 * xmlACatalogResolve:
2608 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002609 * @pubID: the public ID string
2610 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002611 *
2612 * Do a complete resolution lookup of an External Identifier
2613 *
2614 * Returns the URI of the resource or NULL if not found, it must be freed
2615 * by the caller.
2616 */
2617xmlChar *
2618xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2619 const xmlChar * sysID)
2620{
2621 xmlChar *ret = NULL;
2622
2623 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2624 return (NULL);
2625
2626 if (xmlDebugCatalogs) {
2627 if (pubID != NULL) {
2628 xmlGenericError(xmlGenericErrorContext,
2629 "Resolve: pubID %s\n", pubID);
2630 } else {
2631 xmlGenericError(xmlGenericErrorContext,
2632 "Resolve: sysID %s\n", sysID);
2633 }
2634 }
2635
2636 if (catal->type == XML_XML_CATALOG_TYPE) {
2637 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2638 if (ret == XML_CATAL_BREAK)
2639 ret = NULL;
2640 } else {
2641 const xmlChar *sgml;
2642
2643 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2644 if (sgml != NULL)
2645 ret = xmlStrdup(sgml);
2646 }
2647 return (ret);
2648}
2649
2650/**
2651 * xmlACatalogResolveURI:
2652 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002653 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002654 *
2655 * Do a complete resolution lookup of an URI
2656 *
2657 * Returns the URI of the resource or NULL if not found, it must be freed
2658 * by the caller.
2659 */
2660xmlChar *
2661xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2662 xmlChar *ret = NULL;
2663
2664 if ((URI == NULL) || (catal == NULL))
2665 return(NULL);
2666
Daniel Veillardb44025c2001-10-11 22:55:55 +00002667 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002668 xmlGenericError(xmlGenericErrorContext,
2669 "Resolve URI %s\n", URI);
2670
2671 if (catal->type == XML_XML_CATALOG_TYPE) {
2672 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2673 if (ret == XML_CATAL_BREAK)
2674 ret = NULL;
2675 } else {
2676 const xmlChar *sgml;
2677
2678 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2679 if (sgml != NULL)
2680 sgml = xmlStrdup(sgml);
2681 }
2682 return(ret);
2683}
2684
2685/**
2686 * xmlACatalogDump:
2687 * @catal: a Catalog
2688 * @out: the file.
2689 *
2690 * Free up all the memory associated with catalogs
2691 */
2692void
2693xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002694 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002695 return;
2696
2697 if (catal->type == XML_XML_CATALOG_TYPE) {
2698 xmlDumpXMLCatalog(out, catal->xml);
2699 } else {
2700 xmlHashScan(catal->sgml,
2701 (xmlHashScanner) xmlCatalogDumpEntry, out);
2702 }
2703}
2704
2705/**
2706 * xmlACatalogAdd:
2707 * @catal: a Catalog
2708 * @type: the type of record to add to the catalog
2709 * @orig: the system, public or prefix to match
2710 * @replace: the replacement value for the match
2711 *
2712 * Add an entry in the catalog, it may overwrite existing but
2713 * different entries.
2714 *
2715 * Returns 0 if successful, -1 otherwise
2716 */
2717int
2718xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2719 const xmlChar * orig, const xmlChar * replace)
2720{
2721 int res = -1;
2722
2723 if (catal == NULL)
2724 return(-1);
2725
2726 if (catal->type == XML_XML_CATALOG_TYPE) {
2727 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2728 } else {
2729 xmlCatalogEntryType cattype;
2730
2731 cattype = xmlGetSGMLCatalogEntryType(type);
2732 if (cattype != XML_CATA_NONE) {
2733 xmlCatalogEntryPtr entry;
2734
Daniel Veillardc853b322001-11-06 15:24:37 +00002735 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002736 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002737 if (catal->sgml == NULL)
2738 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002739 res = xmlHashAddEntry(catal->sgml, orig, entry);
2740 }
2741 }
2742 return (res);
2743}
2744
2745/**
2746 * xmlACatalogRemove:
2747 * @catal: a Catalog
2748 * @value: the value to remove
2749 *
2750 * Remove an entry from the catalog
2751 *
2752 * Returns the number of entries removed if successful, -1 otherwise
2753 */
2754int
2755xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2756 int res = -1;
2757
2758 if ((catal == NULL) || (value == NULL))
2759 return(-1);
2760
2761 if (catal->type == XML_XML_CATALOG_TYPE) {
2762 res = xmlDelXMLCatalog(catal->xml, value);
2763 } else {
2764 res = xmlHashRemoveEntry(catal->sgml, value,
2765 (xmlHashDeallocator) xmlFreeCatalogEntry);
2766 if (res == 0)
2767 res = 1;
2768 }
2769 return(res);
2770}
2771
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002772/**
2773 * xmlNewCatalog:
2774 * @sgml: should this create an SGML catalog
2775 *
2776 * create a new Catalog.
2777 *
2778 * Returns the xmlCatalogPtr or NULL in case of error
2779 */
2780xmlCatalogPtr
2781xmlNewCatalog(int sgml) {
2782 xmlCatalogPtr catal = NULL;
2783
2784 if (sgml) {
2785 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2786 xmlCatalogDefaultPrefer);
2787 if ((catal != NULL) && (catal->sgml == NULL))
2788 catal->sgml = xmlHashCreate(10);
2789 } else
2790 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2791 xmlCatalogDefaultPrefer);
2792 return(catal);
2793}
2794
2795/**
2796 * xmlCatalogIsEmpty:
2797 * @catal: should this create an SGML catalog
2798 *
2799 * Check is a catalog is empty
2800 *
2801 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2802 */
2803int
2804xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2805 if (catal == NULL)
2806 return(-1);
2807
2808 if (catal->type == XML_XML_CATALOG_TYPE) {
2809 if (catal->xml == NULL)
2810 return(1);
2811 if ((catal->xml->type != XML_CATA_CATALOG) &&
2812 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2813 return(-1);
2814 if (catal->xml->children == NULL)
2815 return(1);
2816 return(0);
2817 } else {
2818 int res;
2819
2820 if (catal->sgml == NULL)
2821 return(1);
2822 res = xmlHashSize(catal->sgml);
2823 if (res == 0)
2824 return(1);
2825 if (res < 0)
2826 return(-1);
2827 }
2828 return(0);
2829}
2830
Daniel Veillard75b96822001-10-11 18:59:45 +00002831/************************************************************************
2832 * *
2833 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002834 * *
2835 ************************************************************************/
2836
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002837/**
Daniel Veillard81463942001-10-16 12:34:39 +00002838 * xmlInitializeCatalogData:
2839 *
2840 * Do the catalog initialization only of global data, doesn't try to load
2841 * any catalog actually.
2842 * this function is not thread safe, catalog initialization should
2843 * preferably be done once at startup
2844 */
2845static void
2846xmlInitializeCatalogData(void) {
2847 if (xmlCatalogInitialized != 0)
2848 return;
2849
2850 if (getenv("XML_DEBUG_CATALOG"))
2851 xmlDebugCatalogs = 1;
2852 xmlCatalogMutex = xmlNewRMutex();
2853
2854 xmlCatalogInitialized = 1;
2855}
2856/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002857 * xmlInitializeCatalog:
2858 *
2859 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002860 * this function is not thread safe, catalog initialization should
2861 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002862 */
2863void
2864xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002865 if (xmlCatalogInitialized != 0)
2866 return;
2867
Daniel Veillard81463942001-10-16 12:34:39 +00002868 xmlInitializeCatalogData();
2869 xmlRMutexLock(xmlCatalogMutex);
2870
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002871 if (getenv("XML_DEBUG_CATALOG"))
2872 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002873
Daniel Veillard75b96822001-10-11 18:59:45 +00002874 if (xmlDefaultCatalog == NULL) {
2875 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002876 char *path;
2877 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00002878 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002879 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00002880
Daniel Veillardb44025c2001-10-11 22:55:55 +00002881 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002882 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002883 catalogs = XML_XML_DEFAULT_CATALOG;
2884
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002885 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2886 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002887 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002888 /* the XML_CATALOG_FILES envvar is allowed to contain a
2889 space-separated list of entries. */
2890 cur = catalogs;
2891 nextent = &catal->xml;
2892 while (*cur != '\0') {
2893 while (IS_BLANK(*cur))
2894 cur++;
2895 if (*cur != 0) {
2896 paths = cur;
2897 while ((*cur != 0) && (!IS_BLANK(*cur)))
2898 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002899 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002900 if (path != NULL) {
2901 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2902 NULL, BAD_CAST path, xmlCatalogDefaultPrefer);
2903 if (*nextent != NULL)
2904 nextent = &((*nextent)->next);
2905 xmlFree(path);
2906 }
2907 }
2908 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002909 xmlDefaultCatalog = catal;
2910 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002911 }
2912
Daniel Veillard81463942001-10-16 12:34:39 +00002913 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002914}
2915
Daniel Veillard82d75332001-10-08 15:01:59 +00002916
2917/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002918 * xmlLoadCatalog:
2919 * @filename: a file path
2920 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002921 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002922 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002923 * this function is not thread safe, catalog initialization should
2924 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002925 *
2926 * Returns 0 in case of success -1 in case of error
2927 */
2928int
Daniel Veillard16756b62001-10-01 07:36:25 +00002929xmlLoadCatalog(const char *filename)
2930{
Daniel Veillard75b96822001-10-11 18:59:45 +00002931 int ret;
2932 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002933
Daniel Veillard81463942001-10-16 12:34:39 +00002934 if (!xmlCatalogInitialized)
2935 xmlInitializeCatalogData();
2936
2937 xmlRMutexLock(xmlCatalogMutex);
2938
Daniel Veillard75b96822001-10-11 18:59:45 +00002939 if (xmlDefaultCatalog == NULL) {
2940 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00002941 if (catal == NULL) {
2942 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002943 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00002944 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002945
Daniel Veillard75b96822001-10-11 18:59:45 +00002946 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002947 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002948 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002949 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002950
Daniel Veillard75b96822001-10-11 18:59:45 +00002951 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002952 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002953 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002954}
2955
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002956/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002957 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00002958 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00002959 *
2960 * Load the catalogs and makes their definitions effective for the default
2961 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002962 * this function is not thread safe, catalog initialization should
2963 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002964 */
2965void
2966xmlLoadCatalogs(const char *pathss) {
2967 const char *cur;
2968 const char *paths;
2969 xmlChar *path;
2970
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002971 if (pathss == NULL)
2972 return;
2973
Daniel Veillard81418e32001-05-22 15:08:55 +00002974 cur = pathss;
2975 while ((cur != NULL) && (*cur != 0)) {
2976 while (IS_BLANK(*cur)) cur++;
2977 if (*cur != 0) {
2978 paths = cur;
Igor Zlatkovicee1494a2002-10-31 16:15:29 +00002979 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00002980 cur++;
2981 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2982 if (path != NULL) {
2983 xmlLoadCatalog((const char *) path);
2984 xmlFree(path);
2985 }
2986 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00002987 while (*cur == ':')
2988 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00002989 }
2990}
2991
Daniel Veillarda7374592001-05-10 14:17:55 +00002992/**
2993 * xmlCatalogCleanup:
2994 *
2995 * Free up all the memory associated with catalogs
2996 */
2997void
2998xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00002999 if (xmlCatalogInitialized == 0)
3000 return;
3001
Daniel Veillard81463942001-10-16 12:34:39 +00003002 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003003 if (xmlDebugCatalogs)
3004 xmlGenericError(xmlGenericErrorContext,
3005 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003006 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003007 xmlHashFree(xmlCatalogXMLFiles,
3008 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003009 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003010 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003011 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003012 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003013 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003014 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003015 xmlRMutexUnlock(xmlCatalogMutex);
3016 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003017}
3018
3019/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003020 * xmlCatalogResolveSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003021 * @sysID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003022 *
3023 * Try to lookup the catalog resource for a system ID
3024 *
3025 * Returns the system ID if found or NULL otherwise, the value returned
3026 * must be freed by the caller.
3027 */
3028xmlChar *
3029xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003030 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003031
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003032 if (!xmlCatalogInitialized)
3033 xmlInitializeCatalog();
3034
Daniel Veillard75b96822001-10-11 18:59:45 +00003035 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3036 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003037}
3038
3039/**
3040 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003041 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003042 *
3043 * Try to lookup the system ID associated to a public ID
3044 *
3045 * Returns the system ID if found or NULL otherwise, the value returned
3046 * must be freed by the caller.
3047 */
3048xmlChar *
3049xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003050 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003051
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003052 if (!xmlCatalogInitialized)
3053 xmlInitializeCatalog();
3054
Daniel Veillard75b96822001-10-11 18:59:45 +00003055 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3056 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003057}
Daniel Veillard344cee72001-08-20 00:08:40 +00003058
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003059/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003060 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003061 * @pubID: the public ID string
3062 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003063 *
3064 * Do a complete resolution lookup of an External Identifier
3065 *
3066 * Returns the URI of the resource or NULL if not found, it must be freed
3067 * by the caller.
3068 */
3069xmlChar *
3070xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003071 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003072
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003073 if (!xmlCatalogInitialized)
3074 xmlInitializeCatalog();
3075
Daniel Veillard75b96822001-10-11 18:59:45 +00003076 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3077 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003078}
3079
3080/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003081 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003082 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003083 *
3084 * Do a complete resolution lookup of an URI
3085 *
3086 * Returns the URI of the resource or NULL if not found, it must be freed
3087 * by the caller.
3088 */
3089xmlChar *
3090xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003091 xmlChar *ret;
3092
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003093 if (!xmlCatalogInitialized)
3094 xmlInitializeCatalog();
3095
Daniel Veillard75b96822001-10-11 18:59:45 +00003096 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3097 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003098}
3099
3100/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003101 * xmlCatalogDump:
3102 * @out: the file.
3103 *
3104 * Free up all the memory associated with catalogs
3105 */
3106void
3107xmlCatalogDump(FILE *out) {
3108 if (out == NULL)
3109 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003110
Daniel Veillard75b96822001-10-11 18:59:45 +00003111 if (!xmlCatalogInitialized)
3112 xmlInitializeCatalog();
3113
3114 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003115}
3116
3117/**
3118 * xmlCatalogAdd:
3119 * @type: the type of record to add to the catalog
3120 * @orig: the system, public or prefix to match
3121 * @replace: the replacement value for the match
3122 *
3123 * Add an entry in the catalog, it may overwrite existing but
3124 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003125 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003126 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003127 *
3128 * Returns 0 if successful, -1 otherwise
3129 */
3130int
3131xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3132 int res = -1;
3133
Daniel Veillard81463942001-10-16 12:34:39 +00003134 if (!xmlCatalogInitialized)
3135 xmlInitializeCatalogData();
3136
3137 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003138 /*
3139 * Specific case where one want to override the default catalog
3140 * put in place by xmlInitializeCatalog();
3141 */
3142 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003143 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003144 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003145 xmlCatalogDefaultPrefer);
3146 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003147 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003148
Daniel Veillard81463942001-10-16 12:34:39 +00003149 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003150 return(0);
3151 }
3152
Daniel Veillard75b96822001-10-11 18:59:45 +00003153 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003154 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003155 return(res);
3156}
3157
3158/**
3159 * xmlCatalogRemove:
3160 * @value: the value to remove
3161 *
3162 * Remove an entry from the catalog
3163 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003164 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003165 */
3166int
3167xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003168 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003169
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003170 if (!xmlCatalogInitialized)
3171 xmlInitializeCatalog();
3172
Daniel Veillard81463942001-10-16 12:34:39 +00003173 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003174 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003175 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003176 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003177}
3178
3179/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003180 * xmlCatalogConvert:
3181 *
3182 * Convert all the SGML catalog entries as XML ones
3183 *
3184 * Returns the number of entries converted if successful, -1 otherwise
3185 */
3186int
3187xmlCatalogConvert(void) {
3188 int res = -1;
3189
3190 if (!xmlCatalogInitialized)
3191 xmlInitializeCatalog();
3192
Daniel Veillard81463942001-10-16 12:34:39 +00003193 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003194 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003195 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003196 return(res);
3197}
3198
Daniel Veillard75b96822001-10-11 18:59:45 +00003199/************************************************************************
3200 * *
3201 * Public interface manipulating the common preferences *
3202 * *
3203 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003204
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003205/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003206 * xmlCatalogGetDefaults:
3207 *
3208 * Used to get the user preference w.r.t. to what catalogs should
3209 * be accepted
3210 *
3211 * Returns the current xmlCatalogAllow value
3212 */
3213xmlCatalogAllow
3214xmlCatalogGetDefaults(void) {
3215 return(xmlCatalogDefaultAllow);
3216}
3217
3218/**
3219 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003220 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003221 *
3222 * Used to set the user preference w.r.t. to what catalogs should
3223 * be accepted
3224 */
3225void
3226xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003227 if (xmlDebugCatalogs) {
3228 switch (allow) {
3229 case XML_CATA_ALLOW_NONE:
3230 xmlGenericError(xmlGenericErrorContext,
3231 "Disabling catalog usage\n");
3232 break;
3233 case XML_CATA_ALLOW_GLOBAL:
3234 xmlGenericError(xmlGenericErrorContext,
3235 "Allowing only global catalogs\n");
3236 break;
3237 case XML_CATA_ALLOW_DOCUMENT:
3238 xmlGenericError(xmlGenericErrorContext,
3239 "Allowing only catalogs from the document\n");
3240 break;
3241 case XML_CATA_ALLOW_ALL:
3242 xmlGenericError(xmlGenericErrorContext,
3243 "Allowing all catalogs\n");
3244 break;
3245 }
3246 }
3247 xmlCatalogDefaultAllow = allow;
3248}
3249
3250/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003251 * xmlCatalogSetDefaultPrefer:
3252 * @prefer: the default preference for delegation
3253 *
3254 * Allows to set the preference between public and system for deletion
3255 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003256 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003257 *
3258 * Returns the previous value of the default preference for delegation
3259 */
3260xmlCatalogPrefer
3261xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3262 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3263
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003264 if (prefer == XML_CATA_PREFER_NONE)
3265 return(ret);
3266
3267 if (xmlDebugCatalogs) {
3268 switch (prefer) {
3269 case XML_CATA_PREFER_PUBLIC:
3270 xmlGenericError(xmlGenericErrorContext,
3271 "Setting catalog preference to PUBLIC\n");
3272 break;
3273 case XML_CATA_PREFER_SYSTEM:
3274 xmlGenericError(xmlGenericErrorContext,
3275 "Setting catalog preference to SYSTEM\n");
3276 break;
3277 case XML_CATA_PREFER_NONE:
3278 break;
3279 }
3280 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003281 xmlCatalogDefaultPrefer = prefer;
3282 return(ret);
3283}
3284
3285/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003286 * xmlCatalogSetDebug:
3287 * @level: the debug level of catalogs required
3288 *
3289 * Used to set the debug level for catalog operation, 0 disable
3290 * debugging, 1 enable it
3291 *
3292 * Returns the previous value of the catalog debugging level
3293 */
3294int
3295xmlCatalogSetDebug(int level) {
3296 int ret = xmlDebugCatalogs;
3297
3298 if (level <= 0)
3299 xmlDebugCatalogs = 0;
3300 else
3301 xmlDebugCatalogs = level;
3302 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003303}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003304
Daniel Veillard75b96822001-10-11 18:59:45 +00003305/************************************************************************
3306 * *
3307 * Minimal interfaces used for per-document catalogs by the parser *
3308 * *
3309 ************************************************************************/
3310
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003311/**
3312 * xmlCatalogFreeLocal:
3313 * @catalogs: a document's list of catalogs
3314 *
3315 * Free up the memory associated to the catalog list
3316 */
3317void
3318xmlCatalogFreeLocal(void *catalogs) {
3319 xmlCatalogEntryPtr catal;
3320
Daniel Veillard81463942001-10-16 12:34:39 +00003321 if (!xmlCatalogInitialized)
3322 xmlInitializeCatalog();
3323
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003324 catal = (xmlCatalogEntryPtr) catalogs;
3325 if (catal != NULL)
3326 xmlFreeCatalogEntryList(catal);
3327}
3328
3329
3330/**
3331 * xmlCatalogAddLocal:
3332 * @catalogs: a document's list of catalogs
3333 * @URL: the URL to a new local catalog
3334 *
3335 * Add the new entry to the catalog list
3336 *
3337 * Returns the updated list
3338 */
3339void *
3340xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3341 xmlCatalogEntryPtr catal, add;
3342
3343 if (!xmlCatalogInitialized)
3344 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003345
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003346 if (URL == NULL)
3347 return(catalogs);
3348
3349 if (xmlDebugCatalogs)
3350 xmlGenericError(xmlGenericErrorContext,
3351 "Adding document catalog %s\n", URL);
3352
Daniel Veillardc853b322001-11-06 15:24:37 +00003353 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003354 xmlCatalogDefaultPrefer);
3355 if (add == NULL)
3356 return(catalogs);
3357
3358 catal = (xmlCatalogEntryPtr) catalogs;
3359 if (catal == NULL)
3360 return((void *) add);
3361
3362 while (catal->next != NULL)
3363 catal = catal->next;
3364 catal->next = add;
3365 return(catalogs);
3366}
3367
3368/**
3369 * xmlCatalogLocalResolve:
3370 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003371 * @pubID: the public ID string
3372 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003373 *
3374 * Do a complete resolution lookup of an External Identifier using a
3375 * document's private catalog list
3376 *
3377 * Returns the URI of the resource or NULL if not found, it must be freed
3378 * by the caller.
3379 */
3380xmlChar *
3381xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3382 const xmlChar *sysID) {
3383 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003384 xmlChar *ret;
3385
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003386 if (!xmlCatalogInitialized)
3387 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003388
Daniel Veillard81463942001-10-16 12:34:39 +00003389 if ((pubID == NULL) && (sysID == NULL))
3390 return(NULL);
3391
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003392 if (xmlDebugCatalogs) {
3393 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003394 xmlGenericError(xmlGenericErrorContext,
3395 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003396 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003397 xmlGenericError(xmlGenericErrorContext,
3398 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003399 }
3400 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003401
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003402 catal = (xmlCatalogEntryPtr) catalogs;
3403 if (catal == NULL)
3404 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003405 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3406 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3407 return(ret);
3408 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003409}
3410
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003411/**
3412 * xmlCatalogLocalResolveURI:
3413 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003414 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003415 *
3416 * Do a complete resolution lookup of an URI using a
3417 * document's private catalog list
3418 *
3419 * Returns the URI of the resource or NULL if not found, it must be freed
3420 * by the caller.
3421 */
3422xmlChar *
3423xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3424 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003425 xmlChar *ret;
3426
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003427 if (!xmlCatalogInitialized)
3428 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003429
Daniel Veillard81463942001-10-16 12:34:39 +00003430 if (URI == NULL)
3431 return(NULL);
3432
Daniel Veillard6990bf32001-08-23 21:17:48 +00003433 if (xmlDebugCatalogs)
3434 xmlGenericError(xmlGenericErrorContext,
3435 "Resolve URI %s\n", URI);
3436
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003437 catal = (xmlCatalogEntryPtr) catalogs;
3438 if (catal == NULL)
3439 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003440 ret = xmlCatalogListXMLResolveURI(catal, URI);
3441 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3442 return(ret);
3443 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003444}
3445
Daniel Veillard75b96822001-10-11 18:59:45 +00003446/************************************************************************
3447 * *
3448 * Deprecated interfaces *
3449 * *
3450 ************************************************************************/
3451/**
3452 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003453 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003454 *
3455 * Try to lookup the system ID associated to a public ID
3456 * DEPRECATED, use xmlCatalogResolveSystem()
3457 *
3458 * Returns the system ID if found or NULL otherwise.
3459 */
3460const xmlChar *
3461xmlCatalogGetSystem(const xmlChar *sysID) {
3462 xmlChar *ret;
3463 static xmlChar result[1000];
3464 static int msg = 0;
3465
Daniel Veillard81463942001-10-16 12:34:39 +00003466 if (!xmlCatalogInitialized)
3467 xmlInitializeCatalog();
3468
Daniel Veillard75b96822001-10-11 18:59:45 +00003469 if (msg == 0) {
3470 xmlGenericError(xmlGenericErrorContext,
3471 "Use of deprecated xmlCatalogGetSystem() call\n");
3472 msg++;
3473 }
3474
3475 if (sysID == NULL)
3476 return(NULL);
3477
Daniel Veillard75b96822001-10-11 18:59:45 +00003478 /*
3479 * Check first the XML catalogs
3480 */
3481 if (xmlDefaultCatalog != NULL) {
3482 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3483 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3484 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3485 result[sizeof(result) - 1] = 0;
3486 return(result);
3487 }
3488 }
3489
3490 if (xmlDefaultCatalog != NULL)
3491 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3492 return(NULL);
3493}
3494
3495/**
3496 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003497 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003498 *
3499 * Try to lookup the system ID associated to a public ID
3500 * DEPRECATED, use xmlCatalogResolvePublic()
3501 *
3502 * Returns the system ID if found or NULL otherwise.
3503 */
3504const xmlChar *
3505xmlCatalogGetPublic(const xmlChar *pubID) {
3506 xmlChar *ret;
3507 static xmlChar result[1000];
3508 static int msg = 0;
3509
Daniel Veillard81463942001-10-16 12:34:39 +00003510 if (!xmlCatalogInitialized)
3511 xmlInitializeCatalog();
3512
Daniel Veillard75b96822001-10-11 18:59:45 +00003513 if (msg == 0) {
3514 xmlGenericError(xmlGenericErrorContext,
3515 "Use of deprecated xmlCatalogGetPublic() call\n");
3516 msg++;
3517 }
3518
3519 if (pubID == NULL)
3520 return(NULL);
3521
Daniel Veillard75b96822001-10-11 18:59:45 +00003522 /*
3523 * Check first the XML catalogs
3524 */
3525 if (xmlDefaultCatalog != NULL) {
3526 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3527 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3528 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3529 result[sizeof(result) - 1] = 0;
3530 return(result);
3531 }
3532 }
3533
3534 if (xmlDefaultCatalog != NULL)
3535 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3536 return(NULL);
3537}
3538
Daniel Veillarda7374592001-05-10 14:17:55 +00003539#endif /* LIBXML_CATALOG_ENABLED */