blob: 1a0ebcb52add334501c3cb13841dc229b132d432 [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
45
Daniel Veillard344cee72001-08-20 00:08:40 +000046/**
47 * TODO:
48 *
49 * macro to flag unimplemented blocks
Daniel Veillard3e59fc52003-04-18 12:34:58 +000050 * XML_CATALOG_PREFER user env to select between system/public prefered
51 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
52 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
53 *> values "system" and "public". I have made the default be "system" to
54 *> match yours.
Daniel Veillard344cee72001-08-20 00:08:40 +000055 */
56#define TODO \
57 xmlGenericError(xmlGenericErrorContext, \
58 "Unimplemented block at %s:%d\n", \
59 __FILE__, __LINE__);
60
Daniel Veillardcda96922001-08-21 10:56:31 +000061#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000062#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000063#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000064#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000065#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000066#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000067#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000068#endif
69
Daniel Veillard85c11fa2001-10-16 21:03:08 +000070static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000071
Daniel Veillarda7374592001-05-10 14:17:55 +000072/************************************************************************
73 * *
74 * Types, all private *
75 * *
76 ************************************************************************/
77
78typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000079 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000080 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000081 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000082 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000083 XML_CATA_NEXT_CATALOG,
84 XML_CATA_PUBLIC,
85 XML_CATA_SYSTEM,
86 XML_CATA_REWRITE_SYSTEM,
87 XML_CATA_DELEGATE_PUBLIC,
88 XML_CATA_DELEGATE_SYSTEM,
89 XML_CATA_URI,
90 XML_CATA_REWRITE_URI,
91 XML_CATA_DELEGATE_URI,
92 SGML_CATA_SYSTEM,
93 SGML_CATA_PUBLIC,
94 SGML_CATA_ENTITY,
95 SGML_CATA_PENTITY,
96 SGML_CATA_DOCTYPE,
97 SGML_CATA_LINKTYPE,
98 SGML_CATA_NOTATION,
99 SGML_CATA_DELEGATE,
100 SGML_CATA_BASE,
101 SGML_CATA_CATALOG,
102 SGML_CATA_DOCUMENT,
103 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000104} xmlCatalogEntryType;
105
106typedef struct _xmlCatalogEntry xmlCatalogEntry;
107typedef xmlCatalogEntry *xmlCatalogEntryPtr;
108struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000109 struct _xmlCatalogEntry *next;
110 struct _xmlCatalogEntry *parent;
111 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000112 xmlCatalogEntryType type;
113 xmlChar *name;
114 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000115 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000116 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000117 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +0000118};
119
Daniel Veillard75b96822001-10-11 18:59:45 +0000120typedef enum {
121 XML_XML_CATALOG_TYPE = 1,
122 XML_SGML_CATALOG_TYPE
123} xmlCatalogType;
124
125#define XML_MAX_SGML_CATA_DEPTH 10
126struct _xmlCatalog {
127 xmlCatalogType type; /* either XML or SGML */
128
129 /*
130 * SGML Catalogs are stored as a simple hash table of catalog entries
131 * Catalog stack to check against overflows when building the
132 * SGML catalog
133 */
134 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
135 int catalNr; /* Number of current catal streams */
136 int catalMax; /* Max number of catal streams */
137 xmlHashTablePtr sgml;
138
139 /*
140 * XML Catalogs are stored as a tree of Catalog entries
141 */
142 xmlCatalogPrefer prefer;
143 xmlCatalogEntryPtr xml;
144};
145
146/************************************************************************
147 * *
148 * Global variables *
149 * *
150 ************************************************************************/
151
Daniel Veillard81463942001-10-16 12:34:39 +0000152/*
153 * Those are preferences
154 */
155static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000156static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000157static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000158
159/*
160 * Hash table containing all the trees of XML catalogs parsed by
161 * the application.
162 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000163static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000164
165/*
166 * The default catalog in use by the application
167 */
168static xmlCatalogPtr xmlDefaultCatalog = NULL;
169
170/*
Daniel Veillard81463942001-10-16 12:34:39 +0000171 * A mutex for modifying the shared global catalog(s)
172 * xmlDefaultCatalog tree.
173 * It also protects xmlCatalogXMLFiles
174 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
175 */
176static xmlRMutexPtr xmlCatalogMutex = NULL;
177
178/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000179 * Whether the catalog support was initialized.
180 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000181static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000182
Daniel Veillarda7374592001-05-10 14:17:55 +0000183
184/************************************************************************
185 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000186 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000187 * *
188 ************************************************************************/
189
Daniel Veillard75b96822001-10-11 18:59:45 +0000190/**
191 * xmlNewCatalogEntry:
192 * @type: type of entry
193 * @name: name of the entry
194 * @value: value of the entry
195 * @prefer: the PUBLIC vs. SYSTEM current preference value
196 *
197 * create a new Catalog entry, this type is shared both by XML and
198 * SGML catalogs, but the acceptable types values differs.
199 *
200 * Returns the xmlCatalogEntryPtr or NULL in case of error
201 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000202static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000203xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillardc853b322001-11-06 15:24:37 +0000204 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000205 xmlCatalogEntryPtr ret;
206
207 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
208 if (ret == NULL) {
209 xmlGenericError(xmlGenericErrorContext,
210 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
211 return(NULL);
212 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000213 ret->next = NULL;
214 ret->parent = NULL;
215 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000216 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000217 if (name != NULL)
218 ret->name = xmlStrdup(name);
219 else
220 ret->name = NULL;
221 if (value != NULL)
222 ret->value = xmlStrdup(value);
223 else
224 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000225 if (URL == NULL)
226 URL = value;
227 if (URL != NULL)
228 ret->URL = xmlStrdup(URL);
229 else
230 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000231 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000232 ret->dealloc = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +0000233 return(ret);
234}
235
236static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000237xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
238
Daniel Veillard75b96822001-10-11 18:59:45 +0000239/**
240 * xmlFreeCatalogEntry:
241 * @ret: a Catalog entry
242 *
243 * Free the memory allocated to a Catalog entry
244 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000245static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000246xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
247 if (ret == NULL)
248 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000249 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000250 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000251 * only by the file hash cleaner !
252 */
253 if (ret->dealloc == 1)
254 return;
255
256 if (xmlDebugCatalogs) {
257 if (ret->name != NULL)
258 xmlGenericError(xmlGenericErrorContext,
259 "Free catalog entry %s\n", ret->name);
260 else if (ret->value != NULL)
261 xmlGenericError(xmlGenericErrorContext,
262 "Free catalog entry %s\n", ret->value);
263 else
264 xmlGenericError(xmlGenericErrorContext,
265 "Free catalog entry\n");
266 }
267
Daniel Veillarda7374592001-05-10 14:17:55 +0000268 if (ret->name != NULL)
269 xmlFree(ret->name);
270 if (ret->value != NULL)
271 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000272 if (ret->URL != NULL)
273 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000274 xmlFree(ret);
275}
276
Daniel Veillard75b96822001-10-11 18:59:45 +0000277/**
278 * xmlFreeCatalogEntryList:
279 * @ret: a Catalog entry list
280 *
281 * Free the memory allocated to a full chained list of Catalog entries
282 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000283static void
284xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
285 xmlCatalogEntryPtr next;
286
287 while (ret != NULL) {
288 next = ret->next;
289 xmlFreeCatalogEntry(ret);
290 ret = next;
291 }
292}
293
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000294/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000295 * xmlFreeCatalogHashEntryList:
296 * @ret: a Catalog entry list
297 *
298 * Free the memory allocated to list of Catalog entries from the
299 * catalog file hash.
300 */
301static void
302xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
303 xmlCatalogEntryPtr children, next;
304
305 if (catal == NULL)
306 return;
307
308 children = catal->children;
309 while (children != NULL) {
310 next = children->next;
311 children->dealloc = 0;
312 children->children = NULL;
313 xmlFreeCatalogEntry(children);
314 children = next;
315 }
316 catal->dealloc = 0;
317 xmlFreeCatalogEntry(catal);
318}
319
320/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000321 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000322 * @type: type of catalog
323 * @prefer: the PUBLIC vs. SYSTEM current preference value
324 *
325 * create a new Catalog, this type is shared both by XML and
326 * SGML catalogs, but the acceptable types values differs.
327 *
328 * Returns the xmlCatalogPtr or NULL in case of error
329 */
330static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000331xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000332 xmlCatalogPtr ret;
333
334 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
335 if (ret == NULL) {
336 xmlGenericError(xmlGenericErrorContext,
337 "malloc of %d byte failed\n", sizeof(xmlCatalog));
338 return(NULL);
339 }
340 memset(ret, 0, sizeof(xmlCatalog));
341 ret->type = type;
342 ret->catalNr = 0;
343 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
344 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000345 if (ret->type == XML_SGML_CATALOG_TYPE)
346 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000347 return(ret);
348}
349
350/**
351 * xmlFreeCatalog:
352 * @catal: a Catalog entry
353 *
354 * Free the memory allocated to a Catalog
355 */
356void
357xmlFreeCatalog(xmlCatalogPtr catal) {
358 if (catal == NULL)
359 return;
360 if (catal->xml != NULL)
361 xmlFreeCatalogEntryList(catal->xml);
362 if (catal->sgml != NULL)
363 xmlHashFree(catal->sgml,
364 (xmlHashDeallocator) xmlFreeCatalogEntry);
365 xmlFree(catal);
366}
367
368/************************************************************************
369 * *
370 * Serializing Catalogs *
371 * *
372 ************************************************************************/
373
374/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000375 * xmlCatalogDumpEntry:
376 * @entry: the
377 * @out: the file.
378 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000379 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000380 */
381static void
382xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
383 if ((entry == NULL) || (out == NULL))
384 return;
385 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000386 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000387 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000388 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000389 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000390 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000391 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000392 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000393 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000394 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000395 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000396 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000397 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000398 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000399 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000400 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000401 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000402 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000403 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000404 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000405 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000406 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000407 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000408 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000409 fprintf(out, "SGMLDECL "); break;
410 default:
411 return;
412 }
413 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000414 case SGML_CATA_ENTITY:
415 case SGML_CATA_PENTITY:
416 case SGML_CATA_DOCTYPE:
417 case SGML_CATA_LINKTYPE:
418 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000419 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000420 case SGML_CATA_PUBLIC:
421 case SGML_CATA_SYSTEM:
422 case SGML_CATA_SGMLDECL:
423 case SGML_CATA_DOCUMENT:
424 case SGML_CATA_CATALOG:
425 case SGML_CATA_BASE:
426 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000427 fprintf(out, "\"%s\"", entry->name); break;
428 default:
429 break;
430 }
431 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000432 case SGML_CATA_ENTITY:
433 case SGML_CATA_PENTITY:
434 case SGML_CATA_DOCTYPE:
435 case SGML_CATA_LINKTYPE:
436 case SGML_CATA_NOTATION:
437 case SGML_CATA_PUBLIC:
438 case SGML_CATA_SYSTEM:
439 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000440 fprintf(out, " \"%s\"", entry->value); break;
441 default:
442 break;
443 }
444 fprintf(out, "\n");
445}
446
Daniel Veillard75b96822001-10-11 18:59:45 +0000447static int
448xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
449 int ret;
450 xmlDocPtr doc;
451 xmlNsPtr ns;
452 xmlDtdPtr dtd;
453 xmlNodePtr node, catalog;
454 xmlOutputBufferPtr buf;
455 xmlCatalogEntryPtr cur;
456
457 /*
458 * Rebuild a catalog
459 */
460 doc = xmlNewDoc(NULL);
461 if (doc == NULL)
462 return(-1);
463 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
464 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
465BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
466
467 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
468
469 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
470 if (ns == NULL) {
471 xmlFreeDoc(doc);
472 return(-1);
473 }
474 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
475 if (catalog == NULL) {
476 xmlFreeNs(ns);
477 xmlFreeDoc(doc);
478 return(-1);
479 }
480 catalog->nsDef = ns;
481 xmlAddChild((xmlNodePtr) doc, catalog);
482
483 /*
484 * add all the catalog entries
485 */
486 cur = catal;
487 while (cur != NULL) {
488 switch (cur->type) {
Daniel Veillardc853b322001-11-06 15:24:37 +0000489 case XML_CATA_REMOVED:
490 break;
Daniel Veillard75b96822001-10-11 18:59:45 +0000491 case XML_CATA_BROKEN_CATALOG:
492 case XML_CATA_CATALOG:
493 if (cur == catal) {
494 cur = cur->children;
495 continue;
496 }
497 break;
498 case XML_CATA_NEXT_CATALOG:
499 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
500 xmlSetProp(node, BAD_CAST "catalog", cur->value);
501 xmlAddChild(catalog, node);
502 break;
503 case XML_CATA_NONE:
504 break;
505 case XML_CATA_PUBLIC:
506 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
507 xmlSetProp(node, BAD_CAST "publicId", cur->name);
508 xmlSetProp(node, BAD_CAST "uri", cur->value);
509 xmlAddChild(catalog, node);
510 break;
511 case XML_CATA_SYSTEM:
512 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
513 xmlSetProp(node, BAD_CAST "systemId", cur->name);
514 xmlSetProp(node, BAD_CAST "uri", cur->value);
515 xmlAddChild(catalog, node);
516 break;
517 case XML_CATA_REWRITE_SYSTEM:
518 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
519 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
520 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
521 xmlAddChild(catalog, node);
522 break;
523 case XML_CATA_DELEGATE_PUBLIC:
524 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
525 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
526 xmlSetProp(node, BAD_CAST "catalog", cur->value);
527 xmlAddChild(catalog, node);
528 break;
529 case XML_CATA_DELEGATE_SYSTEM:
530 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
531 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
532 xmlSetProp(node, BAD_CAST "catalog", cur->value);
533 xmlAddChild(catalog, node);
534 break;
535 case XML_CATA_URI:
536 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
537 xmlSetProp(node, BAD_CAST "name", cur->name);
538 xmlSetProp(node, BAD_CAST "uri", cur->value);
539 xmlAddChild(catalog, node);
540 break;
541 case XML_CATA_REWRITE_URI:
542 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
543 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
544 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
545 xmlAddChild(catalog, node);
546 break;
547 case XML_CATA_DELEGATE_URI:
548 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
549 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
550 xmlSetProp(node, BAD_CAST "catalog", cur->value);
551 xmlAddChild(catalog, node);
552 break;
553 case SGML_CATA_SYSTEM:
554 case SGML_CATA_PUBLIC:
555 case SGML_CATA_ENTITY:
556 case SGML_CATA_PENTITY:
557 case SGML_CATA_DOCTYPE:
558 case SGML_CATA_LINKTYPE:
559 case SGML_CATA_NOTATION:
560 case SGML_CATA_DELEGATE:
561 case SGML_CATA_BASE:
562 case SGML_CATA_CATALOG:
563 case SGML_CATA_DOCUMENT:
564 case SGML_CATA_SGMLDECL:
565 break;
566 }
567 cur = cur->next;
568 }
569
570 /*
571 * reserialize it
572 */
573 buf = xmlOutputBufferCreateFile(out, NULL);
574 if (buf == NULL) {
575 xmlFreeDoc(doc);
576 return(-1);
577 }
578 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
579
580 /*
581 * Free it
582 */
583 xmlFreeDoc(doc);
584
585 return(ret);
586}
587
588/************************************************************************
589 * *
590 * Converting SGML Catalogs to XML *
591 * *
592 ************************************************************************/
593
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000594/**
595 * xmlCatalogConvertEntry:
596 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000597 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000598 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000599 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000600 */
601static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000602xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
603 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
604 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000605 return;
606 switch (entry->type) {
607 case SGML_CATA_ENTITY:
608 entry->type = XML_CATA_PUBLIC;
609 break;
610 case SGML_CATA_PENTITY:
611 entry->type = XML_CATA_PUBLIC;
612 break;
613 case SGML_CATA_DOCTYPE:
614 entry->type = XML_CATA_PUBLIC;
615 break;
616 case SGML_CATA_LINKTYPE:
617 entry->type = XML_CATA_PUBLIC;
618 break;
619 case SGML_CATA_NOTATION:
620 entry->type = XML_CATA_PUBLIC;
621 break;
622 case SGML_CATA_PUBLIC:
623 entry->type = XML_CATA_PUBLIC;
624 break;
625 case SGML_CATA_SYSTEM:
626 entry->type = XML_CATA_SYSTEM;
627 break;
628 case SGML_CATA_DELEGATE:
629 entry->type = XML_CATA_DELEGATE_PUBLIC;
630 break;
631 case SGML_CATA_CATALOG:
632 entry->type = XML_CATA_CATALOG;
633 break;
634 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000635 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000636 (xmlHashDeallocator) xmlFreeCatalogEntry);
637 return;
638 }
639 /*
640 * Conversion successful, remove from the SGML catalog
641 * and add it to the default XML one
642 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000643 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
644 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000645 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000646 if (catal->xml->children == NULL)
647 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000648 else {
649 xmlCatalogEntryPtr prev;
650
Daniel Veillard75b96822001-10-11 18:59:45 +0000651 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000652 while (prev->next != NULL)
653 prev = prev->next;
654 prev->next = entry;
655 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000656}
657
658/**
659 * xmlConvertSGMLCatalog:
660 * @catal: the catalog
661 *
662 * Convert all the SGML catalog entries as XML ones
663 *
664 * Returns the number of entries converted if successful, -1 otherwise
665 */
666int
667xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
668
669 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
670 return(-1);
671
672 if (xmlDebugCatalogs) {
673 xmlGenericError(xmlGenericErrorContext,
674 "Converting SGML catalog to XML\n");
675 }
676 xmlHashScan(catal->sgml,
677 (xmlHashScanner) xmlCatalogConvertEntry,
678 &catal);
679 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000680}
681
Daniel Veillarda7374592001-05-10 14:17:55 +0000682/************************************************************************
683 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000684 * Helper function *
685 * *
686 ************************************************************************/
687
688/**
689 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000690 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000691 *
692 * Expand the URN into the equivalent Public Identifier
693 *
694 * Returns the new identifier or NULL, the string must be deallocated
695 * by the caller.
696 */
697static xmlChar *
698xmlCatalogUnWrapURN(const xmlChar *urn) {
699 xmlChar result[2000];
700 unsigned int i = 0;
701
702 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
703 return(NULL);
704 urn += sizeof(XML_URN_PUBID) - 1;
705
706 while (*urn != 0) {
707 if (i > sizeof(result) - 3)
708 break;
709 if (*urn == '+') {
710 result[i++] = ' ';
711 urn++;
712 } else if (*urn == ':') {
713 result[i++] = '/';
714 result[i++] = '/';
715 urn++;
716 } else if (*urn == ';') {
717 result[i++] = ':';
718 result[i++] = ':';
719 urn++;
720 } else if (*urn == '%') {
721 if ((urn[1] == '2') && (urn[1] == 'B'))
722 result[i++] = '+';
723 else if ((urn[1] == '3') && (urn[1] == 'A'))
724 result[i++] = ':';
725 else if ((urn[1] == '2') && (urn[1] == 'F'))
726 result[i++] = '/';
727 else if ((urn[1] == '3') && (urn[1] == 'B'))
728 result[i++] = ';';
729 else if ((urn[1] == '2') && (urn[1] == '7'))
730 result[i++] = '\'';
731 else if ((urn[1] == '3') && (urn[1] == 'F'))
732 result[i++] = '?';
733 else if ((urn[1] == '2') && (urn[1] == '3'))
734 result[i++] = '#';
735 else if ((urn[1] == '2') && (urn[1] == '5'))
736 result[i++] = '%';
737 else {
738 result[i++] = *urn;
739 urn++;
740 continue;
741 }
742 urn += 3;
743 } else {
744 result[i++] = *urn;
745 urn++;
746 }
747 }
748 result[i] = 0;
749
750 return(xmlStrdup(result));
751}
752
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000753/**
754 * xmlParseCatalogFile:
755 * @filename: the filename
756 *
757 * parse an XML file and build a tree. It's like xmlParseFile()
758 * except it bypass all catalog lookups.
759 *
760 * Returns the resulting document tree or NULL in case of error
761 */
762
763xmlDocPtr
764xmlParseCatalogFile(const char *filename) {
765 xmlDocPtr ret;
766 xmlParserCtxtPtr ctxt;
767 char *directory = NULL;
768 xmlParserInputPtr inputStream;
769 xmlParserInputBufferPtr buf;
770
771 ctxt = xmlNewParserCtxt();
772 if (ctxt == NULL) {
773 if (xmlDefaultSAXHandler.error != NULL) {
774 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
775 }
776 return(NULL);
777 }
778
779 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
780 if (buf == NULL) {
781 xmlFreeParserCtxt(ctxt);
782 return(NULL);
783 }
784
785 inputStream = xmlNewInputStream(ctxt);
786 if (inputStream == NULL) {
787 xmlFreeParserCtxt(ctxt);
788 return(NULL);
789 }
790
Daniel Veillard85095e22003-04-23 13:56:44 +0000791 inputStream->filename = xmlCanonicPath(filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000792 inputStream->buf = buf;
793 inputStream->base = inputStream->buf->buffer->content;
794 inputStream->cur = inputStream->buf->buffer->content;
795 inputStream->end =
796 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
797
798 inputPush(ctxt, inputStream);
799 if ((ctxt->directory == NULL) && (directory == NULL))
800 directory = xmlParserGetDirectory(filename);
801 if ((ctxt->directory == NULL) && (directory != NULL))
802 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000803 ctxt->valid = 0;
804 ctxt->validate = 0;
805 ctxt->loadsubset = 0;
806 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000807
808 xmlParseDocument(ctxt);
809
810 if (ctxt->wellFormed)
811 ret = ctxt->myDoc;
812 else {
813 ret = NULL;
814 xmlFreeDoc(ctxt->myDoc);
815 ctxt->myDoc = NULL;
816 }
817 xmlFreeParserCtxt(ctxt);
818
819 return(ret);
820}
821
Daniel Veillard75b96822001-10-11 18:59:45 +0000822/**
823 * xmlLoadFileContent:
824 * @filename: a file path
825 *
826 * Load a file content into memory.
827 *
828 * Returns a pointer to the 0 terminated string or NULL in case of error
829 */
830static xmlChar *
831xmlLoadFileContent(const char *filename)
832{
833#ifdef HAVE_STAT
834 int fd;
835#else
836 FILE *fd;
837#endif
838 int len;
839 long size;
840
841#ifdef HAVE_STAT
842 struct stat info;
843#endif
844 xmlChar *content;
845
846 if (filename == NULL)
847 return (NULL);
848
849#ifdef HAVE_STAT
850 if (stat(filename, &info) < 0)
851 return (NULL);
852#endif
853
854#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000855 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000856#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000857 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000858#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000859 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000860 return (NULL);
861 }
862#ifdef HAVE_STAT
863 size = info.st_size;
864#else
865 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
866 fclose(fd);
867 return (NULL);
868 }
869#endif
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000870 content = xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000871 if (content == NULL) {
872 xmlGenericError(xmlGenericErrorContext,
873 "malloc of %d byte failed\n", size + 10);
874 return (NULL);
875 }
876#ifdef HAVE_STAT
877 len = read(fd, content, size);
878#else
879 len = fread(content, 1, size, fd);
880#endif
881 if (len < 0) {
882 xmlFree(content);
883 return (NULL);
884 }
885#ifdef HAVE_STAT
886 close(fd);
887#else
888 fclose(fd);
889#endif
890 content[len] = 0;
891
892 return(content);
893}
894
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000895/************************************************************************
896 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000897 * The XML Catalog parser *
898 * *
899 ************************************************************************/
900
901static xmlCatalogEntryPtr
902xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000903static void
904xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
905 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000906static xmlChar *
907xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
908 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000909static xmlChar *
910xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
911
Daniel Veillard344cee72001-08-20 00:08:40 +0000912
Daniel Veillard75b96822001-10-11 18:59:45 +0000913/**
914 * xmlGetXMLCatalogEntryType:
915 * @name: the name
916 *
917 * lookup the internal type associated to an XML catalog entry name
918 *
919 * Returns the type associate with that name
920 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000921static xmlCatalogEntryType
922xmlGetXMLCatalogEntryType(const xmlChar *name) {
923 xmlCatalogEntryType type = XML_CATA_NONE;
924 if (xmlStrEqual(name, (const xmlChar *) "system"))
925 type = XML_CATA_SYSTEM;
926 else if (xmlStrEqual(name, (const xmlChar *) "public"))
927 type = XML_CATA_PUBLIC;
928 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
929 type = XML_CATA_REWRITE_SYSTEM;
930 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
931 type = XML_CATA_DELEGATE_PUBLIC;
932 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
933 type = XML_CATA_DELEGATE_SYSTEM;
934 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
935 type = XML_CATA_URI;
936 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
937 type = XML_CATA_REWRITE_URI;
938 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
939 type = XML_CATA_DELEGATE_URI;
940 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
941 type = XML_CATA_NEXT_CATALOG;
942 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
943 type = XML_CATA_CATALOG;
944 return(type);
945}
946
Daniel Veillard75b96822001-10-11 18:59:45 +0000947/**
948 * xmlParseXMLCatalogOneNode:
949 * @cur: the XML node
950 * @type: the type of Catalog entry
951 * @name: the name of the node
952 * @attrName: the attribute holding the value
953 * @uriAttrName: the attribute holding the URI-Reference
954 * @prefer: the PUBLIC vs. SYSTEM current preference value
955 *
956 * Finishes the examination of an XML tree node of a catalog and build
957 * a Catalog entry from it.
958 *
959 * Returns the new Catalog entry node or NULL in case of error.
960 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000961static xmlCatalogEntryPtr
962xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
963 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000964 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000965 int ok = 1;
966 xmlChar *uriValue;
967 xmlChar *nameValue = NULL;
968 xmlChar *base = NULL;
969 xmlChar *URL = NULL;
970 xmlCatalogEntryPtr ret = NULL;
971
972 if (attrName != NULL) {
973 nameValue = xmlGetProp(cur, attrName);
974 if (nameValue == NULL) {
975 xmlGenericError(xmlGenericErrorContext,
976 "%s entry lacks '%s'\n", name, attrName);
977 ok = 0;
978 }
979 }
980 uriValue = xmlGetProp(cur, uriAttrName);
981 if (uriValue == NULL) {
982 xmlGenericError(xmlGenericErrorContext,
983 "%s entry lacks '%s'\n", name, uriAttrName);
984 ok = 0;
985 }
986 if (!ok) {
987 if (nameValue != NULL)
988 xmlFree(nameValue);
989 if (uriValue != NULL)
990 xmlFree(uriValue);
991 return(NULL);
992 }
993
994 base = xmlNodeGetBase(cur->doc, cur);
995 URL = xmlBuildURI(uriValue, base);
996 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000997 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000998 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000999 xmlGenericError(xmlGenericErrorContext,
1000 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001001 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001002 xmlGenericError(xmlGenericErrorContext,
1003 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001004 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001005 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001006 } else {
1007 xmlGenericError(xmlGenericErrorContext,
1008 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1009 }
1010 if (nameValue != NULL)
1011 xmlFree(nameValue);
1012 if (uriValue != NULL)
1013 xmlFree(uriValue);
1014 if (base != NULL)
1015 xmlFree(base);
1016 if (URL != NULL)
1017 xmlFree(URL);
1018 return(ret);
1019}
1020
Daniel Veillard75b96822001-10-11 18:59:45 +00001021/**
1022 * xmlParseXMLCatalogNode:
1023 * @cur: the XML node
1024 * @prefer: the PUBLIC vs. SYSTEM current preference value
1025 * @parent: the parent Catalog entry
1026 *
1027 * Examines an XML tree node of a catalog and build
1028 * a Catalog entry from it adding it to its parent. The examination can
1029 * be recursive.
1030 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001031static void
1032xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1033 xmlCatalogEntryPtr parent)
1034{
1035 xmlChar *uri = NULL;
1036 xmlChar *URL = NULL;
1037 xmlChar *base = NULL;
1038 xmlCatalogEntryPtr entry = NULL;
1039
1040 if (cur == NULL)
1041 return;
1042 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1043 xmlChar *prop;
1044
1045 prop = xmlGetProp(cur, BAD_CAST "prefer");
1046 if (prop != NULL) {
1047 if (xmlStrEqual(prop, BAD_CAST "system")) {
1048 prefer = XML_CATA_PREFER_SYSTEM;
1049 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1050 prefer = XML_CATA_PREFER_PUBLIC;
1051 } else {
1052 xmlGenericError(xmlGenericErrorContext,
1053 "Invalid value for prefer: '%s'\n", prop);
1054 }
1055 xmlFree(prop);
1056 }
1057 /*
1058 * Recurse to propagate prefer to the subtree
1059 * (xml:base handling is automated)
1060 */
1061 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1062 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1063 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001064 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001065 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1066 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001067 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001068 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1069 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1070 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001071 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001072 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1073 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1074 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001075 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001076 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1077 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1078 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001079 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001080 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1081 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1082 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001083 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001084 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1085 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1086 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001087 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001088 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1089 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1090 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001091 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001092 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1093 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1094 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001095 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001096 }
1097 if ((entry != NULL) && (parent != NULL)) {
1098 entry->parent = parent;
1099 if (parent->children == NULL)
1100 parent->children = entry;
1101 else {
1102 xmlCatalogEntryPtr prev;
1103
1104 prev = parent->children;
1105 while (prev->next != NULL)
1106 prev = prev->next;
1107 prev->next = entry;
1108 }
1109 }
1110 if (base != NULL)
1111 xmlFree(base);
1112 if (uri != NULL)
1113 xmlFree(uri);
1114 if (URL != NULL)
1115 xmlFree(URL);
1116}
1117
Daniel Veillard75b96822001-10-11 18:59:45 +00001118/**
1119 * xmlParseXMLCatalogNodeList:
1120 * @cur: the XML node list of siblings
1121 * @prefer: the PUBLIC vs. SYSTEM current preference value
1122 * @parent: the parent Catalog entry
1123 *
1124 * Examines a list of XML sibling nodes of a catalog and build
1125 * a list of Catalog entry from it adding it to the parent.
1126 * The examination will recurse to examine node subtrees.
1127 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001128static void
1129xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1130 xmlCatalogEntryPtr parent) {
1131 while (cur != NULL) {
1132 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1133 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1134 xmlParseXMLCatalogNode(cur, prefer, parent);
1135 }
1136 cur = cur->next;
1137 }
1138 /* TODO: sort the list according to REWRITE lengths and prefer value */
1139}
1140
Daniel Veillard75b96822001-10-11 18:59:45 +00001141/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001142 * xmlParseXMLCatalogFile:
1143 * @prefer: the PUBLIC vs. SYSTEM current preference value
1144 * @filename: the filename for the catalog
1145 *
1146 * Parses the catalog file to extract the XML tree and then analyze the
1147 * tree to build a list of Catalog entries corresponding to this catalog
1148 *
1149 * Returns the resulting Catalog entries list
1150 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001151static xmlCatalogEntryPtr
1152xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1153 xmlDocPtr doc;
1154 xmlNodePtr cur;
1155 xmlChar *prop;
1156 xmlCatalogEntryPtr parent = NULL;
1157
1158 if (filename == NULL)
1159 return(NULL);
1160
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001161 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001162 if (doc == NULL) {
1163 if (xmlDebugCatalogs)
1164 xmlGenericError(xmlGenericErrorContext,
1165 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001166 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001167 }
1168
1169 if (xmlDebugCatalogs)
1170 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001171 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001172
1173 cur = xmlDocGetRootElement(doc);
1174 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1175 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1176 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1177
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001178 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00001179 (const xmlChar *)filename, NULL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001180 if (parent == NULL) {
1181 xmlFreeDoc(doc);
1182 return(NULL);
1183 }
1184
1185 prop = xmlGetProp(cur, BAD_CAST "prefer");
1186 if (prop != NULL) {
1187 if (xmlStrEqual(prop, BAD_CAST "system")) {
1188 prefer = XML_CATA_PREFER_SYSTEM;
1189 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1190 prefer = XML_CATA_PREFER_PUBLIC;
1191 } else {
1192 xmlGenericError(xmlGenericErrorContext,
1193 "Invalid value for prefer: '%s'\n",
1194 prop);
1195 }
1196 xmlFree(prop);
1197 }
1198 cur = cur->children;
1199 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1200 } else {
1201 xmlGenericError(xmlGenericErrorContext,
1202 "File %s is not an XML Catalog\n", filename);
1203 xmlFreeDoc(doc);
1204 return(NULL);
1205 }
1206 xmlFreeDoc(doc);
1207 return(parent);
1208}
1209
Daniel Veillardcda96922001-08-21 10:56:31 +00001210/**
1211 * xmlFetchXMLCatalogFile:
1212 * @catal: an existing but incomplete catalog entry
1213 *
1214 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001215 *
1216 * Returns 0 in case of success, -1 otherwise
1217 */
1218static int
1219xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001220 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001221
1222 if (catal == NULL)
1223 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001224 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001225 return(-1);
1226 if (catal->children != NULL)
1227 return(-1);
1228
Daniel Veillard81463942001-10-16 12:34:39 +00001229 /*
1230 * lock the whole catalog for modification
1231 */
1232 xmlRMutexLock(xmlCatalogMutex);
1233 if (catal->children != NULL) {
1234 /* Okay someone else did it in the meantime */
1235 xmlRMutexUnlock(xmlCatalogMutex);
1236 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001237 }
1238
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001239 if (xmlCatalogXMLFiles != NULL) {
1240 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001241 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001242 if (doc != NULL) {
1243 if (xmlDebugCatalogs)
1244 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001245 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001246
1247 if (catal->type == XML_CATA_CATALOG)
1248 catal->children = doc->children;
1249 else
1250 catal->children = doc;
1251 catal->dealloc = 0;
1252 xmlRMutexUnlock(xmlCatalogMutex);
1253 return(0);
1254 }
1255 if (xmlDebugCatalogs)
1256 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001257 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001258 }
1259
Daniel Veillardcda96922001-08-21 10:56:31 +00001260 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001261 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001262 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001263 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001264 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001265 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001266 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001267 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001268 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001269 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001270 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001271
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001272 if (catal->type == XML_CATA_CATALOG)
1273 catal->children = doc->children;
1274 else
1275 catal->children = doc;
1276
1277 doc->dealloc = 1;
1278
Daniel Veillard81463942001-10-16 12:34:39 +00001279 if (xmlCatalogXMLFiles == NULL)
1280 xmlCatalogXMLFiles = xmlHashCreate(10);
1281 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001282 if (xmlDebugCatalogs)
1283 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001284 "%s added to file hash\n", catal->URL);
1285 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001286 }
Daniel Veillard81463942001-10-16 12:34:39 +00001287 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001288 return(0);
1289}
1290
Daniel Veillard75b96822001-10-11 18:59:45 +00001291/************************************************************************
1292 * *
1293 * XML Catalog handling *
1294 * *
1295 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001296
1297/**
1298 * xmlAddXMLCatalog:
1299 * @catal: top of an XML catalog
1300 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001301 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001302 * @replace: the replacement value for the match
1303 *
1304 * Add an entry in the XML catalog, it may overwrite existing but
1305 * different entries.
1306 *
1307 * Returns 0 if successful, -1 otherwise
1308 */
1309static int
1310xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1311 const xmlChar *orig, const xmlChar *replace) {
1312 xmlCatalogEntryPtr cur;
1313 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001314 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001315
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001316 if ((catal == NULL) ||
1317 ((catal->type != XML_CATA_CATALOG) &&
1318 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001319 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001320 if (catal->children == NULL) {
1321 xmlFetchXMLCatalogFile(catal);
1322 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001323 if (catal->children == NULL)
1324 doregister = 1;
1325
Daniel Veillard344cee72001-08-20 00:08:40 +00001326 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001327 if (typ == XML_CATA_NONE) {
1328 if (xmlDebugCatalogs)
1329 xmlGenericError(xmlGenericErrorContext,
1330 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001331 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001332 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001333
1334 cur = catal->children;
1335 /*
1336 * Might be a simple "update in place"
1337 */
1338 if (cur != NULL) {
1339 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001340 if ((orig != NULL) && (cur->type == typ) &&
1341 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001342 if (xmlDebugCatalogs)
1343 xmlGenericError(xmlGenericErrorContext,
1344 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001345 if (cur->value != NULL)
1346 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001347 if (cur->URL != NULL)
1348 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001349 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001350 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001351 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001352 }
1353 if (cur->next == NULL)
1354 break;
1355 cur = cur->next;
1356 }
1357 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001358 if (xmlDebugCatalogs)
1359 xmlGenericError(xmlGenericErrorContext,
1360 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001361 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001362 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1363 NULL, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001364 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001365 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1366 NULL, catal->prefer);
1367 if (doregister) {
1368 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1369 if (cur != NULL)
1370 cur->children = catal->children;
1371 }
1372
Daniel Veillardcda96922001-08-21 10:56:31 +00001373 return(0);
1374}
1375
1376/**
1377 * xmlDelXMLCatalog:
1378 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001379 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001380 *
1381 * Remove entries in the XML catalog where the value or the URI
1382 * is equal to @value
1383 *
1384 * Returns the number of entries removed if successful, -1 otherwise
1385 */
1386static int
1387xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001388 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001389 int ret = 0;
1390
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001391 if ((catal == NULL) ||
1392 ((catal->type != XML_CATA_CATALOG) &&
1393 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001394 return(-1);
1395 if (value == NULL)
1396 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001397 if (catal->children == NULL) {
1398 xmlFetchXMLCatalogFile(catal);
1399 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001400
1401 /*
1402 * Scan the children
1403 */
1404 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001405 while (cur != NULL) {
1406 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1407 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001408 if (xmlDebugCatalogs) {
1409 if (cur->name != NULL)
1410 xmlGenericError(xmlGenericErrorContext,
1411 "Removing element %s from catalog\n", cur->name);
1412 else
1413 xmlGenericError(xmlGenericErrorContext,
1414 "Removing element %s from catalog\n", cur->value);
1415 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001416 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001417 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001418 cur = cur->next;
1419 }
1420 return(ret);
1421}
1422
1423/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001424 * xmlCatalogXMLResolve:
1425 * @catal: a catalog list
1426 * @pubId: the public ID string
1427 * @sysId: the system ID string
1428 *
1429 * Do a complete resolution lookup of an External Identifier for a
1430 * list of catalog entries.
1431 *
1432 * Implements (or tries to) 7.1. External Identifier Resolution
1433 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1434 *
1435 * Returns the URI of the resource or NULL if not found
1436 */
1437static xmlChar *
1438xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1439 const xmlChar *sysID) {
1440 xmlChar *ret = NULL;
1441 xmlCatalogEntryPtr cur;
1442 int haveDelegate = 0;
1443 int haveNext = 0;
1444
1445 /*
1446 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1447 */
1448 if (sysID != NULL) {
1449 xmlCatalogEntryPtr rewrite = NULL;
1450 int lenrewrite = 0, len;
1451 cur = catal;
1452 haveDelegate = 0;
1453 while (cur != NULL) {
1454 switch (cur->type) {
1455 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001456 if (xmlStrEqual(sysID, cur->name)) {
1457 if (xmlDebugCatalogs)
1458 xmlGenericError(xmlGenericErrorContext,
1459 "Found system match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001460 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001461 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001462 break;
1463 case XML_CATA_REWRITE_SYSTEM:
1464 len = xmlStrlen(cur->name);
1465 if ((len > lenrewrite) &&
1466 (!xmlStrncmp(sysID, cur->name, len))) {
1467 lenrewrite = len;
1468 rewrite = cur;
1469 }
1470 break;
1471 case XML_CATA_DELEGATE_SYSTEM:
1472 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1473 haveDelegate++;
1474 break;
1475 case XML_CATA_NEXT_CATALOG:
1476 haveNext++;
1477 break;
1478 default:
1479 break;
1480 }
1481 cur = cur->next;
1482 }
1483 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001484 if (xmlDebugCatalogs)
1485 xmlGenericError(xmlGenericErrorContext,
1486 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001487 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001488 if (ret != NULL)
1489 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1490 return(ret);
1491 }
1492 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001493 const xmlChar *delegates[MAX_DELEGATE];
1494 int nbList = 0, i;
1495
Daniel Veillardcda96922001-08-21 10:56:31 +00001496 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001497 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001498 * matches when the list was produced.
1499 */
1500 cur = catal;
1501 while (cur != NULL) {
1502 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1503 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001504 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001505 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001506 break;
1507 if (i < nbList) {
1508 cur = cur->next;
1509 continue;
1510 }
1511 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001512 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001513
Daniel Veillardcda96922001-08-21 10:56:31 +00001514 if (cur->children == NULL) {
1515 xmlFetchXMLCatalogFile(cur);
1516 }
1517 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001518 if (xmlDebugCatalogs)
1519 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001520 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001521 ret = xmlCatalogListXMLResolve(
1522 cur->children, NULL, sysID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001523 if (ret != NULL)
1524 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001525 }
1526 }
1527 cur = cur->next;
1528 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001529 /*
1530 * Apply the cut algorithm explained in 4/
1531 */
1532 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001533 }
1534 }
1535 /*
1536 * Then tries 5/ 6/ if a public ID is provided
1537 */
1538 if (pubID != NULL) {
1539 cur = catal;
1540 haveDelegate = 0;
1541 while (cur != NULL) {
1542 switch (cur->type) {
1543 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001544 if (xmlStrEqual(pubID, cur->name)) {
1545 if (xmlDebugCatalogs)
1546 xmlGenericError(xmlGenericErrorContext,
1547 "Found public match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001548 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001549 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001550 break;
1551 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001552 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1553 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001554 haveDelegate++;
1555 break;
1556 case XML_CATA_NEXT_CATALOG:
1557 if (sysID == NULL)
1558 haveNext++;
1559 break;
1560 default:
1561 break;
1562 }
1563 cur = cur->next;
1564 }
1565 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001566 const xmlChar *delegates[MAX_DELEGATE];
1567 int nbList = 0, i;
1568
Daniel Veillardcda96922001-08-21 10:56:31 +00001569 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001570 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001571 * matches when the list was produced.
1572 */
1573 cur = catal;
1574 while (cur != NULL) {
1575 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001576 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1577 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001578
1579 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001580 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001581 break;
1582 if (i < nbList) {
1583 cur = cur->next;
1584 continue;
1585 }
1586 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001587 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001588
Daniel Veillardcda96922001-08-21 10:56:31 +00001589 if (cur->children == NULL) {
1590 xmlFetchXMLCatalogFile(cur);
1591 }
1592 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001593 if (xmlDebugCatalogs)
1594 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001595 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001596 ret = xmlCatalogListXMLResolve(
1597 cur->children, pubID, NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001598 if (ret != NULL)
1599 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001600 }
1601 }
1602 cur = cur->next;
1603 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001604 /*
1605 * Apply the cut algorithm explained in 4/
1606 */
1607 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001608 }
1609 }
1610 if (haveNext) {
1611 cur = catal;
1612 while (cur != NULL) {
1613 if (cur->type == XML_CATA_NEXT_CATALOG) {
1614 if (cur->children == NULL) {
1615 xmlFetchXMLCatalogFile(cur);
1616 }
1617 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001618 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1619 if (ret != NULL)
1620 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001621 }
1622 }
1623 cur = cur->next;
1624 }
1625 }
1626
1627 return(NULL);
1628}
1629
1630/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001631 * xmlCatalogXMLResolveURI:
1632 * @catal: a catalog list
1633 * @URI: the URI
1634 * @sysId: the system ID string
1635 *
1636 * Do a complete resolution lookup of an External Identifier for a
1637 * list of catalog entries.
1638 *
1639 * Implements (or tries to) 7.2.2. URI Resolution
1640 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1641 *
1642 * Returns the URI of the resource or NULL if not found
1643 */
1644static xmlChar *
1645xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1646 xmlChar *ret = NULL;
1647 xmlCatalogEntryPtr cur;
1648 int haveDelegate = 0;
1649 int haveNext = 0;
1650 xmlCatalogEntryPtr rewrite = NULL;
1651 int lenrewrite = 0, len;
1652
1653 if (catal == NULL)
1654 return(NULL);
1655
1656 if (URI == NULL)
1657 return(NULL);
1658
1659 /*
1660 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1661 */
1662 cur = catal;
1663 haveDelegate = 0;
1664 while (cur != NULL) {
1665 switch (cur->type) {
1666 case XML_CATA_URI:
1667 if (xmlStrEqual(URI, cur->name)) {
1668 if (xmlDebugCatalogs)
1669 xmlGenericError(xmlGenericErrorContext,
1670 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001671 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001672 }
1673 break;
1674 case XML_CATA_REWRITE_URI:
1675 len = xmlStrlen(cur->name);
1676 if ((len > lenrewrite) &&
1677 (!xmlStrncmp(URI, cur->name, len))) {
1678 lenrewrite = len;
1679 rewrite = cur;
1680 }
1681 break;
1682 case XML_CATA_DELEGATE_URI:
1683 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1684 haveDelegate++;
1685 break;
1686 case XML_CATA_NEXT_CATALOG:
1687 haveNext++;
1688 break;
1689 default:
1690 break;
1691 }
1692 cur = cur->next;
1693 }
1694 if (rewrite != NULL) {
1695 if (xmlDebugCatalogs)
1696 xmlGenericError(xmlGenericErrorContext,
1697 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001698 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001699 if (ret != NULL)
1700 ret = xmlStrcat(ret, &URI[lenrewrite]);
1701 return(ret);
1702 }
1703 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001704 const xmlChar *delegates[MAX_DELEGATE];
1705 int nbList = 0, i;
1706
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001707 /*
1708 * Assume the entries have been sorted by decreasing substring
1709 * matches when the list was produced.
1710 */
1711 cur = catal;
1712 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001713 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1714 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001715 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001716 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001717 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001718 break;
1719 if (i < nbList) {
1720 cur = cur->next;
1721 continue;
1722 }
1723 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001724 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001725
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001726 if (cur->children == NULL) {
1727 xmlFetchXMLCatalogFile(cur);
1728 }
1729 if (cur->children != NULL) {
1730 if (xmlDebugCatalogs)
1731 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001732 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001733 ret = xmlCatalogListXMLResolveURI(
1734 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001735 if (ret != NULL)
1736 return(ret);
1737 }
1738 }
1739 cur = cur->next;
1740 }
1741 /*
1742 * Apply the cut algorithm explained in 4/
1743 */
1744 return(XML_CATAL_BREAK);
1745 }
1746 if (haveNext) {
1747 cur = catal;
1748 while (cur != NULL) {
1749 if (cur->type == XML_CATA_NEXT_CATALOG) {
1750 if (cur->children == NULL) {
1751 xmlFetchXMLCatalogFile(cur);
1752 }
1753 if (cur->children != NULL) {
1754 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1755 if (ret != NULL)
1756 return(ret);
1757 }
1758 }
1759 cur = cur->next;
1760 }
1761 }
1762
1763 return(NULL);
1764}
1765
1766/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001767 * xmlCatalogListXMLResolve:
1768 * @catal: a catalog list
1769 * @pubId: the public ID string
1770 * @sysId: the system ID string
1771 *
1772 * Do a complete resolution lookup of an External Identifier for a
1773 * list of catalogs
1774 *
1775 * Implements (or tries to) 7.1. External Identifier Resolution
1776 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1777 *
1778 * Returns the URI of the resource or NULL if not found
1779 */
1780static xmlChar *
1781xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1782 const xmlChar *sysID) {
1783 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001784 xmlChar *urnID = NULL;
1785
1786 if (catal == NULL)
1787 return(NULL);
1788 if ((pubID == NULL) && (sysID == NULL))
1789 return(NULL);
1790
1791 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1792 urnID = xmlCatalogUnWrapURN(pubID);
1793 if (xmlDebugCatalogs) {
1794 if (urnID == NULL)
1795 xmlGenericError(xmlGenericErrorContext,
1796 "Public URN ID %s expanded to NULL\n", pubID);
1797 else
1798 xmlGenericError(xmlGenericErrorContext,
1799 "Public URN ID expanded to %s\n", urnID);
1800 }
1801 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1802 if (urnID != NULL)
1803 xmlFree(urnID);
1804 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001805 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001806 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1807 urnID = xmlCatalogUnWrapURN(sysID);
1808 if (xmlDebugCatalogs) {
1809 if (urnID == NULL)
1810 xmlGenericError(xmlGenericErrorContext,
1811 "System URN ID %s expanded to NULL\n", sysID);
1812 else
1813 xmlGenericError(xmlGenericErrorContext,
1814 "System URN ID expanded to %s\n", urnID);
1815 }
1816 if (pubID == NULL)
1817 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1818 else if (xmlStrEqual(pubID, urnID))
1819 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1820 else {
1821 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1822 }
1823 if (urnID != NULL)
1824 xmlFree(urnID);
1825 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001826 }
1827 while (catal != NULL) {
1828 if (catal->type == XML_CATA_CATALOG) {
1829 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001830 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001831 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001832 if (catal->children != NULL) {
1833 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1834 if (ret != NULL)
1835 return(ret);
1836 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001837 }
1838 catal = catal->next;
1839 }
1840 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001841}
1842
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001843/**
1844 * xmlCatalogListXMLResolveURI:
1845 * @catal: a catalog list
1846 * @URI: the URI
1847 *
1848 * Do a complete resolution lookup of an URI for a list of catalogs
1849 *
1850 * Implements (or tries to) 7.2. URI Resolution
1851 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1852 *
1853 * Returns the URI of the resource or NULL if not found
1854 */
1855static xmlChar *
1856xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1857 xmlChar *ret = NULL;
1858 xmlChar *urnID = NULL;
1859
1860 if (catal == NULL)
1861 return(NULL);
1862 if (URI == NULL)
1863 return(NULL);
1864
1865 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1866 urnID = xmlCatalogUnWrapURN(URI);
1867 if (xmlDebugCatalogs) {
1868 if (urnID == NULL)
1869 xmlGenericError(xmlGenericErrorContext,
1870 "URN ID %s expanded to NULL\n", URI);
1871 else
1872 xmlGenericError(xmlGenericErrorContext,
1873 "URN ID expanded to %s\n", urnID);
1874 }
1875 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1876 if (urnID != NULL)
1877 xmlFree(urnID);
1878 return(ret);
1879 }
1880 while (catal != NULL) {
1881 if (catal->type == XML_CATA_CATALOG) {
1882 if (catal->children == NULL) {
1883 xmlFetchXMLCatalogFile(catal);
1884 }
1885 if (catal->children != NULL) {
1886 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1887 if (ret != NULL)
1888 return(ret);
1889 }
1890 }
1891 catal = catal->next;
1892 }
1893 return(ret);
1894}
1895
Daniel Veillard344cee72001-08-20 00:08:40 +00001896/************************************************************************
1897 * *
1898 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001899 * *
1900 ************************************************************************/
1901
1902
1903#define RAW *cur
1904#define NEXT cur++;
1905#define SKIP(x) cur += x;
1906
1907#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1908
Daniel Veillard75b96822001-10-11 18:59:45 +00001909/**
1910 * xmlParseSGMLCatalogComment:
1911 * @cur: the current character
1912 *
1913 * Skip a comment in an SGML catalog
1914 *
1915 * Returns new current character
1916 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001917static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001918xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001919 if ((cur[0] != '-') || (cur[1] != '-'))
1920 return(cur);
1921 SKIP(2);
1922 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1923 NEXT;
1924 if (cur[0] == 0) {
1925 return(NULL);
1926 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001927 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001928}
1929
Daniel Veillard75b96822001-10-11 18:59:45 +00001930/**
1931 * xmlParseSGMLCatalogPubid:
1932 * @cur: the current character
1933 * @id: the return location
1934 *
1935 * Parse an SGML catalog ID
1936 *
1937 * Returns new current character and store the value in @id
1938 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001939static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001940xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001941 xmlChar *buf = NULL;
1942 int len = 0;
1943 int size = 50;
1944 xmlChar stop;
1945 int count = 0;
1946
1947 *id = NULL;
1948
1949 if (RAW == '"') {
1950 NEXT;
1951 stop = '"';
1952 } else if (RAW == '\'') {
1953 NEXT;
1954 stop = '\'';
1955 } else {
1956 stop = ' ';
1957 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00001958 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00001959 if (buf == NULL) {
1960 xmlGenericError(xmlGenericErrorContext,
1961 "malloc of %d byte failed\n", size);
1962 return(NULL);
1963 }
Daniel Veillard935494a2002-10-22 14:22:46 +00001964 while (xmlIsPubidChar(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001965 if ((*cur == stop) && (stop != ' '))
1966 break;
1967 if ((stop == ' ') && (IS_BLANK(*cur)))
1968 break;
1969 if (len + 1 >= size) {
1970 size *= 2;
1971 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1972 if (buf == NULL) {
1973 xmlGenericError(xmlGenericErrorContext,
1974 "realloc of %d byte failed\n", size);
1975 return(NULL);
1976 }
1977 }
1978 buf[len++] = *cur;
1979 count++;
1980 NEXT;
1981 }
1982 buf[len] = 0;
1983 if (stop == ' ') {
1984 if (!IS_BLANK(*cur)) {
1985 xmlFree(buf);
1986 return(NULL);
1987 }
1988 } else {
1989 if (*cur != stop) {
1990 xmlFree(buf);
1991 return(NULL);
1992 }
1993 NEXT;
1994 }
1995 *id = buf;
1996 return(cur);
1997}
1998
Daniel Veillard75b96822001-10-11 18:59:45 +00001999/**
2000 * xmlParseSGMLCatalogName:
2001 * @cur: the current character
2002 * @name: the return location
2003 *
2004 * Parse an SGML catalog name
2005 *
2006 * Returns new current character and store the value in @name
2007 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002008static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002009xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002010 xmlChar buf[XML_MAX_NAMELEN + 5];
2011 int len = 0;
2012 int c;
2013
2014 *name = NULL;
2015
2016 /*
2017 * Handler for more complex cases
2018 */
2019 c = *cur;
2020 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2021 return(NULL);
2022 }
2023
2024 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2025 (c == '.') || (c == '-') ||
2026 (c == '_') || (c == ':'))) {
2027 buf[len++] = c;
2028 cur++;
2029 c = *cur;
2030 if (len >= XML_MAX_NAMELEN)
2031 return(NULL);
2032 }
2033 *name = xmlStrndup(buf, len);
2034 return(cur);
2035}
2036
Daniel Veillard75b96822001-10-11 18:59:45 +00002037/**
2038 * xmlGetSGMLCatalogEntryType:
2039 * @name: the entry name
2040 *
2041 * Get the Catalog entry type for a given SGML Catalog name
2042 *
2043 * Returns Catalog entry type
2044 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002045static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002046xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002047 xmlCatalogEntryType type = XML_CATA_NONE;
2048 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2049 type = SGML_CATA_SYSTEM;
2050 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2051 type = SGML_CATA_PUBLIC;
2052 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2053 type = SGML_CATA_DELEGATE;
2054 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2055 type = SGML_CATA_ENTITY;
2056 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2057 type = SGML_CATA_DOCTYPE;
2058 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2059 type = SGML_CATA_LINKTYPE;
2060 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2061 type = SGML_CATA_NOTATION;
2062 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2063 type = SGML_CATA_SGMLDECL;
2064 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2065 type = SGML_CATA_DOCUMENT;
2066 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2067 type = SGML_CATA_CATALOG;
2068 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2069 type = SGML_CATA_BASE;
2070 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2071 type = SGML_CATA_DELEGATE;
2072 return(type);
2073}
2074
Daniel Veillard75b96822001-10-11 18:59:45 +00002075/**
2076 * xmlParseSGMLCatalog:
2077 * @catal: the SGML Catalog
2078 * @value: the content of the SGML Catalog serialization
2079 * @file: the filepath for the catalog
2080 * @super: should this be handled as a Super Catalog in which case
2081 * parsing is not recursive
2082 *
2083 * Parse an SGML catalog content and fill up the @catal hash table with
2084 * the new entries found.
2085 *
2086 * Returns 0 in case of success, -1 in case of error.
2087 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002088static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002089xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2090 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002091 const xmlChar *cur = value;
2092 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002093 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002094
2095 if ((cur == NULL) || (file == NULL))
2096 return(-1);
2097 base = xmlStrdup((const xmlChar *) file);
2098
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002099 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002100 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002101 if (cur[0] == 0)
2102 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002103 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002104 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002105 if (cur == NULL) {
2106 /* error */
2107 break;
2108 }
2109 } else {
2110 xmlChar *sysid = NULL;
2111 xmlChar *name = NULL;
2112 xmlCatalogEntryType type = XML_CATA_NONE;
2113
Daniel Veillardcda96922001-08-21 10:56:31 +00002114 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002115 if (name == NULL) {
2116 /* error */
2117 break;
2118 }
2119 if (!IS_BLANK(*cur)) {
2120 /* error */
2121 break;
2122 }
2123 SKIP_BLANKS;
2124 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002125 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002126 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002127 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002128 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002129 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002130 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002131 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002132 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002133 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002134 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002135 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002136 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002137 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002138 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002139 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002140 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002141 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002142 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002143 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002144 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002145 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002146 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002147 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002148 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2149 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002150 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002151 if (name == NULL) {
2152 /* error */
2153 break;
2154 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002155 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002156 continue;
2157 }
2158 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002159 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002160
2161 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002162 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002163 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002164 type = SGML_CATA_PENTITY;
2165 case SGML_CATA_PENTITY:
2166 case SGML_CATA_DOCTYPE:
2167 case SGML_CATA_LINKTYPE:
2168 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002169 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002170 if (cur == NULL) {
2171 /* error */
2172 break;
2173 }
2174 if (!IS_BLANK(*cur)) {
2175 /* error */
2176 break;
2177 }
2178 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002179 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002180 if (cur == NULL) {
2181 /* error */
2182 break;
2183 }
2184 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002185 case SGML_CATA_PUBLIC:
2186 case SGML_CATA_SYSTEM:
2187 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002188 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002189 if (cur == NULL) {
2190 /* error */
2191 break;
2192 }
2193 if (!IS_BLANK(*cur)) {
2194 /* error */
2195 break;
2196 }
2197 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002198 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002199 if (cur == NULL) {
2200 /* error */
2201 break;
2202 }
2203 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002204 case SGML_CATA_BASE:
2205 case SGML_CATA_CATALOG:
2206 case SGML_CATA_DOCUMENT:
2207 case SGML_CATA_SGMLDECL:
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;
2214 default:
2215 break;
2216 }
2217 if (cur == NULL) {
2218 if (name != NULL)
2219 xmlFree(name);
2220 if (sysid != NULL)
2221 xmlFree(sysid);
2222 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002223 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002224 if (base != NULL)
2225 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002226 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002227 } else if ((type == SGML_CATA_PUBLIC) ||
2228 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002229 xmlChar *filename;
2230
2231 filename = xmlBuildURI(sysid, base);
2232 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002233 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002234
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002235 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002236 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002237 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002238 if (res < 0) {
2239 xmlFreeCatalogEntry(entry);
2240 }
2241 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002242 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002243
Daniel Veillard344cee72001-08-20 00:08:40 +00002244 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002245 if (super) {
2246 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002247
Daniel Veillardc853b322001-11-06 15:24:37 +00002248 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002249 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002250 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002251 if (res < 0) {
2252 xmlFreeCatalogEntry(entry);
2253 }
2254 } else {
2255 xmlChar *filename;
2256
2257 filename = xmlBuildURI(sysid, base);
2258 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002259 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002260 xmlFree(filename);
2261 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002262 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002263 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002264 /*
2265 * drop anything else we won't handle it
2266 */
2267 if (name != NULL)
2268 xmlFree(name);
2269 if (sysid != NULL)
2270 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002271 }
2272 }
2273 if (base != NULL)
2274 xmlFree(base);
2275 if (cur == NULL)
2276 return(-1);
2277 return(0);
2278}
2279
Daniel Veillard75b96822001-10-11 18:59:45 +00002280/************************************************************************
2281 * *
2282 * SGML Catalog handling *
2283 * *
2284 ************************************************************************/
2285
Daniel Veillardcda96922001-08-21 10:56:31 +00002286/**
2287 * xmlCatalogGetSGMLPublic:
2288 * @catal: an SGML catalog hash
2289 * @pubId: the public ID string
2290 *
2291 * Try to lookup the system ID associated to a public ID
2292 *
2293 * Returns the system ID if found or NULL otherwise.
2294 */
2295static const xmlChar *
2296xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2297 xmlCatalogEntryPtr entry;
2298
2299 if (catal == NULL)
2300 return(NULL);
2301
2302 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2303 if (entry == NULL)
2304 return(NULL);
2305 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillardc853b322001-11-06 15:24:37 +00002306 return(entry->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002307 return(NULL);
2308}
2309
2310/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002311 * xmlCatalogGetSGMLSystem:
2312 * @catal: an SGML catalog hash
2313 * @sysId: the public ID string
2314 *
2315 * Try to lookup the catalog local reference for a system ID
2316 *
2317 * Returns the system ID if found or NULL otherwise.
2318 */
2319static const xmlChar *
2320xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2321 xmlCatalogEntryPtr entry;
2322
2323 if (catal == NULL)
2324 return(NULL);
2325
2326 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2327 if (entry == NULL)
2328 return(NULL);
2329 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002330 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002331 return(NULL);
2332}
2333
2334/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002335 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002336 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002337 * @pubId: the public ID string
2338 * @sysId: the system ID string
2339 *
2340 * Do a complete resolution lookup of an External Identifier
2341 *
2342 * Returns the URI of the resource or NULL if not found
2343 */
2344static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002345xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2346 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002347 const xmlChar *ret = NULL;
2348
Daniel Veillard75b96822001-10-11 18:59:45 +00002349 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002350 return(NULL);
2351
2352 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002353 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002354 if (ret != NULL)
2355 return(ret);
2356 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002357 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002358 return(NULL);
2359}
2360
Daniel Veillarda7374592001-05-10 14:17:55 +00002361/************************************************************************
2362 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002363 * Specific Public interfaces *
2364 * *
2365 ************************************************************************/
2366
2367/**
2368 * xmlLoadSGMLSuperCatalog:
2369 * @filename: a file path
2370 *
2371 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2372 * references. This is only needed for manipulating SGML Super Catalogs
2373 * like adding and removing CATALOG or DELEGATE entries.
2374 *
2375 * Returns the catalog parsed or NULL in case of error
2376 */
2377xmlCatalogPtr
2378xmlLoadSGMLSuperCatalog(const char *filename)
2379{
2380 xmlChar *content;
2381 xmlCatalogPtr catal;
2382 int ret;
2383
2384 content = xmlLoadFileContent(filename);
2385 if (content == NULL)
2386 return(NULL);
2387
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002388 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002389 if (catal == NULL) {
2390 xmlFree(content);
2391 return(NULL);
2392 }
2393
2394 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2395 xmlFree(content);
2396 if (ret < 0) {
2397 xmlFreeCatalog(catal);
2398 return(NULL);
2399 }
2400 return (catal);
2401}
2402
2403/**
2404 * xmlLoadACatalog:
2405 * @filename: a file path
2406 *
2407 * Load the catalog and build the associated data structures.
2408 * This can be either an XML Catalog or an SGML Catalog
2409 * It will recurse in SGML CATALOG entries. On the other hand XML
2410 * Catalogs are not handled recursively.
2411 *
2412 * Returns the catalog parsed or NULL in case of error
2413 */
2414xmlCatalogPtr
2415xmlLoadACatalog(const char *filename)
2416{
2417 xmlChar *content;
2418 xmlChar *first;
2419 xmlCatalogPtr catal;
2420 int ret;
2421
2422 content = xmlLoadFileContent(filename);
2423 if (content == NULL)
2424 return(NULL);
2425
2426
2427 first = content;
2428
2429 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2430 (!(((*first >= 'A') && (*first <= 'Z')) ||
2431 ((*first >= 'a') && (*first <= 'z')))))
2432 first++;
2433
2434 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002435 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002436 if (catal == NULL) {
2437 xmlFree(content);
2438 return(NULL);
2439 }
2440 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2441 if (ret < 0) {
2442 xmlFreeCatalog(catal);
2443 xmlFree(content);
2444 return(NULL);
2445 }
2446 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002447 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002448 if (catal == NULL) {
2449 xmlFree(content);
2450 return(NULL);
2451 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002452 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002453 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002454 }
2455 xmlFree(content);
2456 return (catal);
2457}
2458
2459/**
2460 * xmlExpandCatalog:
2461 * @catal: a catalog
2462 * @filename: a file path
2463 *
2464 * Load the catalog and expand the existing catal structure.
2465 * This can be either an XML Catalog or an SGML Catalog
2466 *
2467 * Returns 0 in case of success, -1 in case of error
2468 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002469static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002470xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2471{
Daniel Veillard75b96822001-10-11 18:59:45 +00002472 int ret;
2473
2474 if ((catal == NULL) || (filename == NULL))
2475 return(-1);
2476
Daniel Veillard75b96822001-10-11 18:59:45 +00002477
2478 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002479 xmlChar *content;
2480
2481 content = xmlLoadFileContent(filename);
2482 if (content == NULL)
2483 return(-1);
2484
Daniel Veillard75b96822001-10-11 18:59:45 +00002485 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2486 if (ret < 0) {
2487 xmlFree(content);
2488 return(-1);
2489 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002490 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002491 } else {
2492 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002493 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002494 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002495
Daniel Veillard75b96822001-10-11 18:59:45 +00002496 cur = catal->xml;
2497 if (cur == NULL) {
2498 catal->xml = tmp;
2499 } else {
2500 while (cur->next != NULL) cur = cur->next;
2501 cur->next = tmp;
2502 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002503 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002504 return (0);
2505}
2506
2507/**
2508 * xmlACatalogResolveSystem:
2509 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002510 * @sysID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002511 *
2512 * Try to lookup the catalog resource for a system ID
2513 *
2514 * Returns the system ID if found or NULL otherwise, the value returned
2515 * must be freed by the caller.
2516 */
2517xmlChar *
2518xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2519 xmlChar *ret = NULL;
2520
2521 if ((sysID == NULL) || (catal == NULL))
2522 return(NULL);
2523
2524 if (xmlDebugCatalogs)
2525 xmlGenericError(xmlGenericErrorContext,
2526 "Resolve sysID %s\n", sysID);
2527
2528 if (catal->type == XML_XML_CATALOG_TYPE) {
2529 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2530 if (ret == XML_CATAL_BREAK)
2531 ret = NULL;
2532 } else {
2533 const xmlChar *sgml;
2534
2535 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2536 if (sgml != NULL)
2537 ret = xmlStrdup(sgml);
2538 }
2539 return(ret);
2540}
2541
2542/**
2543 * xmlACatalogResolvePublic:
2544 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002545 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002546 *
2547 * Try to lookup the system ID associated to a public ID in that catalog
2548 *
2549 * Returns the system ID if found or NULL otherwise, the value returned
2550 * must be freed by the caller.
2551 */
2552xmlChar *
2553xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2554 xmlChar *ret = NULL;
2555
2556 if ((pubID == NULL) || (catal == NULL))
2557 return(NULL);
2558
2559 if (xmlDebugCatalogs)
2560 xmlGenericError(xmlGenericErrorContext,
2561 "Resolve pubID %s\n", pubID);
2562
2563 if (catal->type == XML_XML_CATALOG_TYPE) {
2564 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2565 if (ret == XML_CATAL_BREAK)
2566 ret = NULL;
2567 } else {
2568 const xmlChar *sgml;
2569
2570 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2571 if (sgml != NULL)
2572 ret = xmlStrdup(sgml);
2573 }
2574 return(ret);
2575}
2576
2577/**
2578 * xmlACatalogResolve:
2579 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002580 * @pubID: the public ID string
2581 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002582 *
2583 * Do a complete resolution lookup of an External Identifier
2584 *
2585 * Returns the URI of the resource or NULL if not found, it must be freed
2586 * by the caller.
2587 */
2588xmlChar *
2589xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2590 const xmlChar * sysID)
2591{
2592 xmlChar *ret = NULL;
2593
2594 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2595 return (NULL);
2596
2597 if (xmlDebugCatalogs) {
2598 if (pubID != NULL) {
2599 xmlGenericError(xmlGenericErrorContext,
2600 "Resolve: pubID %s\n", pubID);
2601 } else {
2602 xmlGenericError(xmlGenericErrorContext,
2603 "Resolve: sysID %s\n", sysID);
2604 }
2605 }
2606
2607 if (catal->type == XML_XML_CATALOG_TYPE) {
2608 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2609 if (ret == XML_CATAL_BREAK)
2610 ret = NULL;
2611 } else {
2612 const xmlChar *sgml;
2613
2614 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2615 if (sgml != NULL)
2616 ret = xmlStrdup(sgml);
2617 }
2618 return (ret);
2619}
2620
2621/**
2622 * xmlACatalogResolveURI:
2623 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002624 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002625 *
2626 * Do a complete resolution lookup of an URI
2627 *
2628 * Returns the URI of the resource or NULL if not found, it must be freed
2629 * by the caller.
2630 */
2631xmlChar *
2632xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2633 xmlChar *ret = NULL;
2634
2635 if ((URI == NULL) || (catal == NULL))
2636 return(NULL);
2637
Daniel Veillardb44025c2001-10-11 22:55:55 +00002638 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002639 xmlGenericError(xmlGenericErrorContext,
2640 "Resolve URI %s\n", URI);
2641
2642 if (catal->type == XML_XML_CATALOG_TYPE) {
2643 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2644 if (ret == XML_CATAL_BREAK)
2645 ret = NULL;
2646 } else {
2647 const xmlChar *sgml;
2648
2649 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2650 if (sgml != NULL)
2651 sgml = xmlStrdup(sgml);
2652 }
2653 return(ret);
2654}
2655
2656/**
2657 * xmlACatalogDump:
2658 * @catal: a Catalog
2659 * @out: the file.
2660 *
2661 * Free up all the memory associated with catalogs
2662 */
2663void
2664xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002665 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002666 return;
2667
2668 if (catal->type == XML_XML_CATALOG_TYPE) {
2669 xmlDumpXMLCatalog(out, catal->xml);
2670 } else {
2671 xmlHashScan(catal->sgml,
2672 (xmlHashScanner) xmlCatalogDumpEntry, out);
2673 }
2674}
2675
2676/**
2677 * xmlACatalogAdd:
2678 * @catal: a Catalog
2679 * @type: the type of record to add to the catalog
2680 * @orig: the system, public or prefix to match
2681 * @replace: the replacement value for the match
2682 *
2683 * Add an entry in the catalog, it may overwrite existing but
2684 * different entries.
2685 *
2686 * Returns 0 if successful, -1 otherwise
2687 */
2688int
2689xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2690 const xmlChar * orig, const xmlChar * replace)
2691{
2692 int res = -1;
2693
2694 if (catal == NULL)
2695 return(-1);
2696
2697 if (catal->type == XML_XML_CATALOG_TYPE) {
2698 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2699 } else {
2700 xmlCatalogEntryType cattype;
2701
2702 cattype = xmlGetSGMLCatalogEntryType(type);
2703 if (cattype != XML_CATA_NONE) {
2704 xmlCatalogEntryPtr entry;
2705
Daniel Veillardc853b322001-11-06 15:24:37 +00002706 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002707 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002708 if (catal->sgml == NULL)
2709 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002710 res = xmlHashAddEntry(catal->sgml, orig, entry);
2711 }
2712 }
2713 return (res);
2714}
2715
2716/**
2717 * xmlACatalogRemove:
2718 * @catal: a Catalog
2719 * @value: the value to remove
2720 *
2721 * Remove an entry from the catalog
2722 *
2723 * Returns the number of entries removed if successful, -1 otherwise
2724 */
2725int
2726xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2727 int res = -1;
2728
2729 if ((catal == NULL) || (value == NULL))
2730 return(-1);
2731
2732 if (catal->type == XML_XML_CATALOG_TYPE) {
2733 res = xmlDelXMLCatalog(catal->xml, value);
2734 } else {
2735 res = xmlHashRemoveEntry(catal->sgml, value,
2736 (xmlHashDeallocator) xmlFreeCatalogEntry);
2737 if (res == 0)
2738 res = 1;
2739 }
2740 return(res);
2741}
2742
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002743/**
2744 * xmlNewCatalog:
2745 * @sgml: should this create an SGML catalog
2746 *
2747 * create a new Catalog.
2748 *
2749 * Returns the xmlCatalogPtr or NULL in case of error
2750 */
2751xmlCatalogPtr
2752xmlNewCatalog(int sgml) {
2753 xmlCatalogPtr catal = NULL;
2754
2755 if (sgml) {
2756 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2757 xmlCatalogDefaultPrefer);
2758 if ((catal != NULL) && (catal->sgml == NULL))
2759 catal->sgml = xmlHashCreate(10);
2760 } else
2761 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2762 xmlCatalogDefaultPrefer);
2763 return(catal);
2764}
2765
2766/**
2767 * xmlCatalogIsEmpty:
2768 * @catal: should this create an SGML catalog
2769 *
2770 * Check is a catalog is empty
2771 *
2772 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2773 */
2774int
2775xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2776 if (catal == NULL)
2777 return(-1);
2778
2779 if (catal->type == XML_XML_CATALOG_TYPE) {
2780 if (catal->xml == NULL)
2781 return(1);
2782 if ((catal->xml->type != XML_CATA_CATALOG) &&
2783 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2784 return(-1);
2785 if (catal->xml->children == NULL)
2786 return(1);
2787 return(0);
2788 } else {
2789 int res;
2790
2791 if (catal->sgml == NULL)
2792 return(1);
2793 res = xmlHashSize(catal->sgml);
2794 if (res == 0)
2795 return(1);
2796 if (res < 0)
2797 return(-1);
2798 }
2799 return(0);
2800}
2801
Daniel Veillard75b96822001-10-11 18:59:45 +00002802/************************************************************************
2803 * *
2804 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002805 * *
2806 ************************************************************************/
2807
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002808/**
Daniel Veillard81463942001-10-16 12:34:39 +00002809 * xmlInitializeCatalogData:
2810 *
2811 * Do the catalog initialization only of global data, doesn't try to load
2812 * any catalog actually.
2813 * this function is not thread safe, catalog initialization should
2814 * preferably be done once at startup
2815 */
2816static void
2817xmlInitializeCatalogData(void) {
2818 if (xmlCatalogInitialized != 0)
2819 return;
2820
2821 if (getenv("XML_DEBUG_CATALOG"))
2822 xmlDebugCatalogs = 1;
2823 xmlCatalogMutex = xmlNewRMutex();
2824
2825 xmlCatalogInitialized = 1;
2826}
2827/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002828 * xmlInitializeCatalog:
2829 *
2830 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002831 * this function is not thread safe, catalog initialization should
2832 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002833 */
2834void
2835xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002836 if (xmlCatalogInitialized != 0)
2837 return;
2838
Daniel Veillard81463942001-10-16 12:34:39 +00002839 xmlInitializeCatalogData();
2840 xmlRMutexLock(xmlCatalogMutex);
2841
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002842 if (getenv("XML_DEBUG_CATALOG"))
2843 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002844
Daniel Veillard75b96822001-10-11 18:59:45 +00002845 if (xmlDefaultCatalog == NULL) {
2846 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002847 char *path;
2848 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00002849 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002850 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00002851
Daniel Veillardb44025c2001-10-11 22:55:55 +00002852 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002853 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002854 catalogs = XML_XML_DEFAULT_CATALOG;
2855
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002856 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2857 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002858 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002859 /* the XML_CATALOG_FILES envvar is allowed to contain a
2860 space-separated list of entries. */
2861 cur = catalogs;
2862 nextent = &catal->xml;
2863 while (*cur != '\0') {
2864 while (IS_BLANK(*cur))
2865 cur++;
2866 if (*cur != 0) {
2867 paths = cur;
2868 while ((*cur != 0) && (!IS_BLANK(*cur)))
2869 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002870 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002871 if (path != NULL) {
2872 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2873 NULL, BAD_CAST path, xmlCatalogDefaultPrefer);
2874 if (*nextent != NULL)
2875 nextent = &((*nextent)->next);
2876 xmlFree(path);
2877 }
2878 }
2879 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002880 xmlDefaultCatalog = catal;
2881 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002882 }
2883
Daniel Veillard81463942001-10-16 12:34:39 +00002884 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002885}
2886
Daniel Veillard82d75332001-10-08 15:01:59 +00002887
2888/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002889 * xmlLoadCatalog:
2890 * @filename: a file path
2891 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002892 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002893 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002894 * this function is not thread safe, catalog initialization should
2895 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002896 *
2897 * Returns 0 in case of success -1 in case of error
2898 */
2899int
Daniel Veillard16756b62001-10-01 07:36:25 +00002900xmlLoadCatalog(const char *filename)
2901{
Daniel Veillard75b96822001-10-11 18:59:45 +00002902 int ret;
2903 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002904
Daniel Veillard81463942001-10-16 12:34:39 +00002905 if (!xmlCatalogInitialized)
2906 xmlInitializeCatalogData();
2907
2908 xmlRMutexLock(xmlCatalogMutex);
2909
Daniel Veillard75b96822001-10-11 18:59:45 +00002910 if (xmlDefaultCatalog == NULL) {
2911 catal = xmlLoadACatalog(filename);
2912 if (catal == NULL)
2913 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002914
Daniel Veillard75b96822001-10-11 18:59:45 +00002915 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002916 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002917 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002918 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002919
Daniel Veillard75b96822001-10-11 18:59:45 +00002920 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002921 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002922 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002923}
2924
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002925/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002926 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00002927 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00002928 *
2929 * Load the catalogs and makes their definitions effective for the default
2930 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002931 * this function is not thread safe, catalog initialization should
2932 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002933 */
2934void
2935xmlLoadCatalogs(const char *pathss) {
2936 const char *cur;
2937 const char *paths;
2938 xmlChar *path;
2939
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002940 if (pathss == NULL)
2941 return;
2942
Daniel Veillard81418e32001-05-22 15:08:55 +00002943 cur = pathss;
2944 while ((cur != NULL) && (*cur != 0)) {
2945 while (IS_BLANK(*cur)) cur++;
2946 if (*cur != 0) {
2947 paths = cur;
Igor Zlatkovicee1494a2002-10-31 16:15:29 +00002948 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00002949 cur++;
2950 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2951 if (path != NULL) {
2952 xmlLoadCatalog((const char *) path);
2953 xmlFree(path);
2954 }
2955 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00002956 while (*cur == ':')
2957 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00002958 }
2959}
2960
Daniel Veillarda7374592001-05-10 14:17:55 +00002961/**
2962 * xmlCatalogCleanup:
2963 *
2964 * Free up all the memory associated with catalogs
2965 */
2966void
2967xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00002968 if (xmlCatalogInitialized == 0)
2969 return;
2970
Daniel Veillard81463942001-10-16 12:34:39 +00002971 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002972 if (xmlDebugCatalogs)
2973 xmlGenericError(xmlGenericErrorContext,
2974 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002975 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002976 xmlHashFree(xmlCatalogXMLFiles,
2977 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002978 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002979 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002980 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002981 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002982 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002983 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00002984 xmlRMutexUnlock(xmlCatalogMutex);
2985 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00002986}
2987
2988/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002989 * xmlCatalogResolveSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00002990 * @sysID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002991 *
2992 * Try to lookup the catalog resource for a system ID
2993 *
2994 * Returns the system ID if found or NULL otherwise, the value returned
2995 * must be freed by the caller.
2996 */
2997xmlChar *
2998xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002999 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003000
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003001 if (!xmlCatalogInitialized)
3002 xmlInitializeCatalog();
3003
Daniel Veillard75b96822001-10-11 18:59:45 +00003004 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3005 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003006}
3007
3008/**
3009 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003010 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003011 *
3012 * Try to lookup the system ID associated to a public ID
3013 *
3014 * Returns the system ID if found or NULL otherwise, the value returned
3015 * must be freed by the caller.
3016 */
3017xmlChar *
3018xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003019 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003020
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003021 if (!xmlCatalogInitialized)
3022 xmlInitializeCatalog();
3023
Daniel Veillard75b96822001-10-11 18:59:45 +00003024 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3025 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003026}
Daniel Veillard344cee72001-08-20 00:08:40 +00003027
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003028/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003029 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003030 * @pubID: the public ID string
3031 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003032 *
3033 * Do a complete resolution lookup of an External Identifier
3034 *
3035 * Returns the URI of the resource or NULL if not found, it must be freed
3036 * by the caller.
3037 */
3038xmlChar *
3039xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003040 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003041
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003042 if (!xmlCatalogInitialized)
3043 xmlInitializeCatalog();
3044
Daniel Veillard75b96822001-10-11 18:59:45 +00003045 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3046 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003047}
3048
3049/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003050 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003051 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003052 *
3053 * Do a complete resolution lookup of an URI
3054 *
3055 * Returns the URI of the resource or NULL if not found, it must be freed
3056 * by the caller.
3057 */
3058xmlChar *
3059xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003060 xmlChar *ret;
3061
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003062 if (!xmlCatalogInitialized)
3063 xmlInitializeCatalog();
3064
Daniel Veillard75b96822001-10-11 18:59:45 +00003065 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3066 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003067}
3068
3069/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003070 * xmlCatalogDump:
3071 * @out: the file.
3072 *
3073 * Free up all the memory associated with catalogs
3074 */
3075void
3076xmlCatalogDump(FILE *out) {
3077 if (out == NULL)
3078 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003079
Daniel Veillard75b96822001-10-11 18:59:45 +00003080 if (!xmlCatalogInitialized)
3081 xmlInitializeCatalog();
3082
3083 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003084}
3085
3086/**
3087 * xmlCatalogAdd:
3088 * @type: the type of record to add to the catalog
3089 * @orig: the system, public or prefix to match
3090 * @replace: the replacement value for the match
3091 *
3092 * Add an entry in the catalog, it may overwrite existing but
3093 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003094 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003095 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003096 *
3097 * Returns 0 if successful, -1 otherwise
3098 */
3099int
3100xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3101 int res = -1;
3102
Daniel Veillard81463942001-10-16 12:34:39 +00003103 if (!xmlCatalogInitialized)
3104 xmlInitializeCatalogData();
3105
3106 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003107 /*
3108 * Specific case where one want to override the default catalog
3109 * put in place by xmlInitializeCatalog();
3110 */
3111 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003112 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003113 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003114 xmlCatalogDefaultPrefer);
3115 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003116 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003117
Daniel Veillard81463942001-10-16 12:34:39 +00003118 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003119 return(0);
3120 }
3121
Daniel Veillard75b96822001-10-11 18:59:45 +00003122 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003123 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003124 return(res);
3125}
3126
3127/**
3128 * xmlCatalogRemove:
3129 * @value: the value to remove
3130 *
3131 * Remove an entry from the catalog
3132 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003133 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003134 */
3135int
3136xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003137 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003138
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003139 if (!xmlCatalogInitialized)
3140 xmlInitializeCatalog();
3141
Daniel Veillard81463942001-10-16 12:34:39 +00003142 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003143 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003144 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003145 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003146}
3147
3148/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003149 * xmlCatalogConvert:
3150 *
3151 * Convert all the SGML catalog entries as XML ones
3152 *
3153 * Returns the number of entries converted if successful, -1 otherwise
3154 */
3155int
3156xmlCatalogConvert(void) {
3157 int res = -1;
3158
3159 if (!xmlCatalogInitialized)
3160 xmlInitializeCatalog();
3161
Daniel Veillard81463942001-10-16 12:34:39 +00003162 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003163 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003164 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003165 return(res);
3166}
3167
Daniel Veillard75b96822001-10-11 18:59:45 +00003168/************************************************************************
3169 * *
3170 * Public interface manipulating the common preferences *
3171 * *
3172 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003173
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003174/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003175 * xmlCatalogGetDefaults:
3176 *
3177 * Used to get the user preference w.r.t. to what catalogs should
3178 * be accepted
3179 *
3180 * Returns the current xmlCatalogAllow value
3181 */
3182xmlCatalogAllow
3183xmlCatalogGetDefaults(void) {
3184 return(xmlCatalogDefaultAllow);
3185}
3186
3187/**
3188 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003189 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003190 *
3191 * Used to set the user preference w.r.t. to what catalogs should
3192 * be accepted
3193 */
3194void
3195xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003196 if (xmlDebugCatalogs) {
3197 switch (allow) {
3198 case XML_CATA_ALLOW_NONE:
3199 xmlGenericError(xmlGenericErrorContext,
3200 "Disabling catalog usage\n");
3201 break;
3202 case XML_CATA_ALLOW_GLOBAL:
3203 xmlGenericError(xmlGenericErrorContext,
3204 "Allowing only global catalogs\n");
3205 break;
3206 case XML_CATA_ALLOW_DOCUMENT:
3207 xmlGenericError(xmlGenericErrorContext,
3208 "Allowing only catalogs from the document\n");
3209 break;
3210 case XML_CATA_ALLOW_ALL:
3211 xmlGenericError(xmlGenericErrorContext,
3212 "Allowing all catalogs\n");
3213 break;
3214 }
3215 }
3216 xmlCatalogDefaultAllow = allow;
3217}
3218
3219/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003220 * xmlCatalogSetDefaultPrefer:
3221 * @prefer: the default preference for delegation
3222 *
3223 * Allows to set the preference between public and system for deletion
3224 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003225 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003226 *
3227 * Returns the previous value of the default preference for delegation
3228 */
3229xmlCatalogPrefer
3230xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3231 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3232
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003233 if (prefer == XML_CATA_PREFER_NONE)
3234 return(ret);
3235
3236 if (xmlDebugCatalogs) {
3237 switch (prefer) {
3238 case XML_CATA_PREFER_PUBLIC:
3239 xmlGenericError(xmlGenericErrorContext,
3240 "Setting catalog preference to PUBLIC\n");
3241 break;
3242 case XML_CATA_PREFER_SYSTEM:
3243 xmlGenericError(xmlGenericErrorContext,
3244 "Setting catalog preference to SYSTEM\n");
3245 break;
3246 case XML_CATA_PREFER_NONE:
3247 break;
3248 }
3249 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003250 xmlCatalogDefaultPrefer = prefer;
3251 return(ret);
3252}
3253
3254/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003255 * xmlCatalogSetDebug:
3256 * @level: the debug level of catalogs required
3257 *
3258 * Used to set the debug level for catalog operation, 0 disable
3259 * debugging, 1 enable it
3260 *
3261 * Returns the previous value of the catalog debugging level
3262 */
3263int
3264xmlCatalogSetDebug(int level) {
3265 int ret = xmlDebugCatalogs;
3266
3267 if (level <= 0)
3268 xmlDebugCatalogs = 0;
3269 else
3270 xmlDebugCatalogs = level;
3271 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003272}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003273
Daniel Veillard75b96822001-10-11 18:59:45 +00003274/************************************************************************
3275 * *
3276 * Minimal interfaces used for per-document catalogs by the parser *
3277 * *
3278 ************************************************************************/
3279
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003280/**
3281 * xmlCatalogFreeLocal:
3282 * @catalogs: a document's list of catalogs
3283 *
3284 * Free up the memory associated to the catalog list
3285 */
3286void
3287xmlCatalogFreeLocal(void *catalogs) {
3288 xmlCatalogEntryPtr catal;
3289
Daniel Veillard81463942001-10-16 12:34:39 +00003290 if (!xmlCatalogInitialized)
3291 xmlInitializeCatalog();
3292
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003293 catal = (xmlCatalogEntryPtr) catalogs;
3294 if (catal != NULL)
3295 xmlFreeCatalogEntryList(catal);
3296}
3297
3298
3299/**
3300 * xmlCatalogAddLocal:
3301 * @catalogs: a document's list of catalogs
3302 * @URL: the URL to a new local catalog
3303 *
3304 * Add the new entry to the catalog list
3305 *
3306 * Returns the updated list
3307 */
3308void *
3309xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3310 xmlCatalogEntryPtr catal, add;
3311
3312 if (!xmlCatalogInitialized)
3313 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003314
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003315 if (URL == NULL)
3316 return(catalogs);
3317
3318 if (xmlDebugCatalogs)
3319 xmlGenericError(xmlGenericErrorContext,
3320 "Adding document catalog %s\n", URL);
3321
Daniel Veillardc853b322001-11-06 15:24:37 +00003322 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003323 xmlCatalogDefaultPrefer);
3324 if (add == NULL)
3325 return(catalogs);
3326
3327 catal = (xmlCatalogEntryPtr) catalogs;
3328 if (catal == NULL)
3329 return((void *) add);
3330
3331 while (catal->next != NULL)
3332 catal = catal->next;
3333 catal->next = add;
3334 return(catalogs);
3335}
3336
3337/**
3338 * xmlCatalogLocalResolve:
3339 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003340 * @pubID: the public ID string
3341 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003342 *
3343 * Do a complete resolution lookup of an External Identifier using a
3344 * document's private catalog list
3345 *
3346 * Returns the URI of the resource or NULL if not found, it must be freed
3347 * by the caller.
3348 */
3349xmlChar *
3350xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3351 const xmlChar *sysID) {
3352 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003353 xmlChar *ret;
3354
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003355 if (!xmlCatalogInitialized)
3356 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003357
Daniel Veillard81463942001-10-16 12:34:39 +00003358 if ((pubID == NULL) && (sysID == NULL))
3359 return(NULL);
3360
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003361 if (xmlDebugCatalogs) {
3362 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003363 xmlGenericError(xmlGenericErrorContext,
3364 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003365 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003366 xmlGenericError(xmlGenericErrorContext,
3367 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003368 }
3369 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003370
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003371 catal = (xmlCatalogEntryPtr) catalogs;
3372 if (catal == NULL)
3373 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003374 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3375 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3376 return(ret);
3377 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003378}
3379
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003380/**
3381 * xmlCatalogLocalResolveURI:
3382 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003383 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003384 *
3385 * Do a complete resolution lookup of an URI using a
3386 * document's private catalog list
3387 *
3388 * Returns the URI of the resource or NULL if not found, it must be freed
3389 * by the caller.
3390 */
3391xmlChar *
3392xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3393 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003394 xmlChar *ret;
3395
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003396 if (!xmlCatalogInitialized)
3397 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003398
Daniel Veillard81463942001-10-16 12:34:39 +00003399 if (URI == NULL)
3400 return(NULL);
3401
Daniel Veillard6990bf32001-08-23 21:17:48 +00003402 if (xmlDebugCatalogs)
3403 xmlGenericError(xmlGenericErrorContext,
3404 "Resolve URI %s\n", URI);
3405
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003406 catal = (xmlCatalogEntryPtr) catalogs;
3407 if (catal == NULL)
3408 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003409 ret = xmlCatalogListXMLResolveURI(catal, URI);
3410 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3411 return(ret);
3412 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003413}
3414
Daniel Veillard75b96822001-10-11 18:59:45 +00003415/************************************************************************
3416 * *
3417 * Deprecated interfaces *
3418 * *
3419 ************************************************************************/
3420/**
3421 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003422 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003423 *
3424 * Try to lookup the system ID associated to a public ID
3425 * DEPRECATED, use xmlCatalogResolveSystem()
3426 *
3427 * Returns the system ID if found or NULL otherwise.
3428 */
3429const xmlChar *
3430xmlCatalogGetSystem(const xmlChar *sysID) {
3431 xmlChar *ret;
3432 static xmlChar result[1000];
3433 static int msg = 0;
3434
Daniel Veillard81463942001-10-16 12:34:39 +00003435 if (!xmlCatalogInitialized)
3436 xmlInitializeCatalog();
3437
Daniel Veillard75b96822001-10-11 18:59:45 +00003438 if (msg == 0) {
3439 xmlGenericError(xmlGenericErrorContext,
3440 "Use of deprecated xmlCatalogGetSystem() call\n");
3441 msg++;
3442 }
3443
3444 if (sysID == NULL)
3445 return(NULL);
3446
Daniel Veillard75b96822001-10-11 18:59:45 +00003447 /*
3448 * Check first the XML catalogs
3449 */
3450 if (xmlDefaultCatalog != NULL) {
3451 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3452 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3453 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3454 result[sizeof(result) - 1] = 0;
3455 return(result);
3456 }
3457 }
3458
3459 if (xmlDefaultCatalog != NULL)
3460 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3461 return(NULL);
3462}
3463
3464/**
3465 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003466 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003467 *
3468 * Try to lookup the system ID associated to a public ID
3469 * DEPRECATED, use xmlCatalogResolvePublic()
3470 *
3471 * Returns the system ID if found or NULL otherwise.
3472 */
3473const xmlChar *
3474xmlCatalogGetPublic(const xmlChar *pubID) {
3475 xmlChar *ret;
3476 static xmlChar result[1000];
3477 static int msg = 0;
3478
Daniel Veillard81463942001-10-16 12:34:39 +00003479 if (!xmlCatalogInitialized)
3480 xmlInitializeCatalog();
3481
Daniel Veillard75b96822001-10-11 18:59:45 +00003482 if (msg == 0) {
3483 xmlGenericError(xmlGenericErrorContext,
3484 "Use of deprecated xmlCatalogGetPublic() call\n");
3485 msg++;
3486 }
3487
3488 if (pubID == NULL)
3489 return(NULL);
3490
Daniel Veillard75b96822001-10-11 18:59:45 +00003491 /*
3492 * Check first the XML catalogs
3493 */
3494 if (xmlDefaultCatalog != NULL) {
3495 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3496 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3497 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3498 result[sizeof(result) - 1] = 0;
3499 return(result);
3500 }
3501 }
3502
3503 if (xmlDefaultCatalog != NULL)
3504 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3505 return(NULL);
3506}
3507
Daniel Veillarda7374592001-05-10 14:17:55 +00003508#endif /* LIBXML_CATALOG_ENABLED */