blob: 040d99ca15c2dbe0a25e816c71d0739393e6a9e4 [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
50 */
51#define TODO \
52 xmlGenericError(xmlGenericErrorContext, \
53 "Unimplemented block at %s:%d\n", \
54 __FILE__, __LINE__);
55
Daniel Veillardcda96922001-08-21 10:56:31 +000056#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000057#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000058#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000059#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000060#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000061#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000062#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000063#endif
64
Daniel Veillard85c11fa2001-10-16 21:03:08 +000065static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000066
Daniel Veillarda7374592001-05-10 14:17:55 +000067/************************************************************************
68 * *
69 * Types, all private *
70 * *
71 ************************************************************************/
72
73typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000074 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000075 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000076 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000077 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000078 XML_CATA_NEXT_CATALOG,
79 XML_CATA_PUBLIC,
80 XML_CATA_SYSTEM,
81 XML_CATA_REWRITE_SYSTEM,
82 XML_CATA_DELEGATE_PUBLIC,
83 XML_CATA_DELEGATE_SYSTEM,
84 XML_CATA_URI,
85 XML_CATA_REWRITE_URI,
86 XML_CATA_DELEGATE_URI,
87 SGML_CATA_SYSTEM,
88 SGML_CATA_PUBLIC,
89 SGML_CATA_ENTITY,
90 SGML_CATA_PENTITY,
91 SGML_CATA_DOCTYPE,
92 SGML_CATA_LINKTYPE,
93 SGML_CATA_NOTATION,
94 SGML_CATA_DELEGATE,
95 SGML_CATA_BASE,
96 SGML_CATA_CATALOG,
97 SGML_CATA_DOCUMENT,
98 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000099} xmlCatalogEntryType;
100
101typedef struct _xmlCatalogEntry xmlCatalogEntry;
102typedef xmlCatalogEntry *xmlCatalogEntryPtr;
103struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000104 struct _xmlCatalogEntry *next;
105 struct _xmlCatalogEntry *parent;
106 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000107 xmlCatalogEntryType type;
108 xmlChar *name;
109 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000110 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000111 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000112 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +0000113};
114
Daniel Veillard75b96822001-10-11 18:59:45 +0000115typedef enum {
116 XML_XML_CATALOG_TYPE = 1,
117 XML_SGML_CATALOG_TYPE
118} xmlCatalogType;
119
120#define XML_MAX_SGML_CATA_DEPTH 10
121struct _xmlCatalog {
122 xmlCatalogType type; /* either XML or SGML */
123
124 /*
125 * SGML Catalogs are stored as a simple hash table of catalog entries
126 * Catalog stack to check against overflows when building the
127 * SGML catalog
128 */
129 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
130 int catalNr; /* Number of current catal streams */
131 int catalMax; /* Max number of catal streams */
132 xmlHashTablePtr sgml;
133
134 /*
135 * XML Catalogs are stored as a tree of Catalog entries
136 */
137 xmlCatalogPrefer prefer;
138 xmlCatalogEntryPtr xml;
139};
140
141/************************************************************************
142 * *
143 * Global variables *
144 * *
145 ************************************************************************/
146
Daniel Veillard81463942001-10-16 12:34:39 +0000147/*
148 * Those are preferences
149 */
150static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000151static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000152static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000153
154/*
155 * Hash table containing all the trees of XML catalogs parsed by
156 * the application.
157 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000158static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000159
160/*
161 * The default catalog in use by the application
162 */
163static xmlCatalogPtr xmlDefaultCatalog = NULL;
164
165/*
Daniel Veillard81463942001-10-16 12:34:39 +0000166 * A mutex for modifying the shared global catalog(s)
167 * xmlDefaultCatalog tree.
168 * It also protects xmlCatalogXMLFiles
169 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
170 */
171static xmlRMutexPtr xmlCatalogMutex = NULL;
172
173/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000174 * Whether the catalog support was initialized.
175 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000176static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000177
Daniel Veillarda7374592001-05-10 14:17:55 +0000178
179/************************************************************************
180 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000181 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000182 * *
183 ************************************************************************/
184
Daniel Veillard75b96822001-10-11 18:59:45 +0000185/**
186 * xmlNewCatalogEntry:
187 * @type: type of entry
188 * @name: name of the entry
189 * @value: value of the entry
190 * @prefer: the PUBLIC vs. SYSTEM current preference value
191 *
192 * create a new Catalog entry, this type is shared both by XML and
193 * SGML catalogs, but the acceptable types values differs.
194 *
195 * Returns the xmlCatalogEntryPtr or NULL in case of error
196 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000197static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000198xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillardc853b322001-11-06 15:24:37 +0000199 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000200 xmlCatalogEntryPtr ret;
201
202 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
203 if (ret == NULL) {
204 xmlGenericError(xmlGenericErrorContext,
205 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
206 return(NULL);
207 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000208 ret->next = NULL;
209 ret->parent = NULL;
210 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000211 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000212 if (name != NULL)
213 ret->name = xmlStrdup(name);
214 else
215 ret->name = NULL;
216 if (value != NULL)
217 ret->value = xmlStrdup(value);
218 else
219 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000220 if (URL == NULL)
221 URL = value;
222 if (URL != NULL)
223 ret->URL = xmlStrdup(URL);
224 else
225 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000226 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000227 ret->dealloc = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +0000228 return(ret);
229}
230
231static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000232xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
233
Daniel Veillard75b96822001-10-11 18:59:45 +0000234/**
235 * xmlFreeCatalogEntry:
236 * @ret: a Catalog entry
237 *
238 * Free the memory allocated to a Catalog entry
239 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000240static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000241xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
242 if (ret == NULL)
243 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000244 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000245 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000246 * only by the file hash cleaner !
247 */
248 if (ret->dealloc == 1)
249 return;
250
251 if (xmlDebugCatalogs) {
252 if (ret->name != NULL)
253 xmlGenericError(xmlGenericErrorContext,
254 "Free catalog entry %s\n", ret->name);
255 else if (ret->value != NULL)
256 xmlGenericError(xmlGenericErrorContext,
257 "Free catalog entry %s\n", ret->value);
258 else
259 xmlGenericError(xmlGenericErrorContext,
260 "Free catalog entry\n");
261 }
262
Daniel Veillarda7374592001-05-10 14:17:55 +0000263 if (ret->name != NULL)
264 xmlFree(ret->name);
265 if (ret->value != NULL)
266 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000267 if (ret->URL != NULL)
268 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000269 xmlFree(ret);
270}
271
Daniel Veillard75b96822001-10-11 18:59:45 +0000272/**
273 * xmlFreeCatalogEntryList:
274 * @ret: a Catalog entry list
275 *
276 * Free the memory allocated to a full chained list of Catalog entries
277 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000278static void
279xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
280 xmlCatalogEntryPtr next;
281
282 while (ret != NULL) {
283 next = ret->next;
284 xmlFreeCatalogEntry(ret);
285 ret = next;
286 }
287}
288
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000289/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000290 * xmlFreeCatalogHashEntryList:
291 * @ret: a Catalog entry list
292 *
293 * Free the memory allocated to list of Catalog entries from the
294 * catalog file hash.
295 */
296static void
297xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
298 xmlCatalogEntryPtr children, next;
299
300 if (catal == NULL)
301 return;
302
303 children = catal->children;
304 while (children != NULL) {
305 next = children->next;
306 children->dealloc = 0;
307 children->children = NULL;
308 xmlFreeCatalogEntry(children);
309 children = next;
310 }
311 catal->dealloc = 0;
312 xmlFreeCatalogEntry(catal);
313}
314
315/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000316 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000317 * @type: type of catalog
318 * @prefer: the PUBLIC vs. SYSTEM current preference value
319 *
320 * create a new Catalog, this type is shared both by XML and
321 * SGML catalogs, but the acceptable types values differs.
322 *
323 * Returns the xmlCatalogPtr or NULL in case of error
324 */
325static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000326xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000327 xmlCatalogPtr ret;
328
329 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
330 if (ret == NULL) {
331 xmlGenericError(xmlGenericErrorContext,
332 "malloc of %d byte failed\n", sizeof(xmlCatalog));
333 return(NULL);
334 }
335 memset(ret, 0, sizeof(xmlCatalog));
336 ret->type = type;
337 ret->catalNr = 0;
338 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
339 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000340 if (ret->type == XML_SGML_CATALOG_TYPE)
341 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000342 return(ret);
343}
344
345/**
346 * xmlFreeCatalog:
347 * @catal: a Catalog entry
348 *
349 * Free the memory allocated to a Catalog
350 */
351void
352xmlFreeCatalog(xmlCatalogPtr catal) {
353 if (catal == NULL)
354 return;
355 if (catal->xml != NULL)
356 xmlFreeCatalogEntryList(catal->xml);
357 if (catal->sgml != NULL)
358 xmlHashFree(catal->sgml,
359 (xmlHashDeallocator) xmlFreeCatalogEntry);
360 xmlFree(catal);
361}
362
363/************************************************************************
364 * *
365 * Serializing Catalogs *
366 * *
367 ************************************************************************/
368
369/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000370 * xmlCatalogDumpEntry:
371 * @entry: the
372 * @out: the file.
373 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000374 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000375 */
376static void
377xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
378 if ((entry == NULL) || (out == NULL))
379 return;
380 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000381 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000382 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000383 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000384 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000385 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000386 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000387 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000388 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000389 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000390 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000391 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000392 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000393 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000394 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000395 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000396 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000397 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000398 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000399 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000400 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000401 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000402 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000403 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000404 fprintf(out, "SGMLDECL "); break;
405 default:
406 return;
407 }
408 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000409 case SGML_CATA_ENTITY:
410 case SGML_CATA_PENTITY:
411 case SGML_CATA_DOCTYPE:
412 case SGML_CATA_LINKTYPE:
413 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000414 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000415 case SGML_CATA_PUBLIC:
416 case SGML_CATA_SYSTEM:
417 case SGML_CATA_SGMLDECL:
418 case SGML_CATA_DOCUMENT:
419 case SGML_CATA_CATALOG:
420 case SGML_CATA_BASE:
421 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000422 fprintf(out, "\"%s\"", entry->name); break;
423 default:
424 break;
425 }
426 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000427 case SGML_CATA_ENTITY:
428 case SGML_CATA_PENTITY:
429 case SGML_CATA_DOCTYPE:
430 case SGML_CATA_LINKTYPE:
431 case SGML_CATA_NOTATION:
432 case SGML_CATA_PUBLIC:
433 case SGML_CATA_SYSTEM:
434 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000435 fprintf(out, " \"%s\"", entry->value); break;
436 default:
437 break;
438 }
439 fprintf(out, "\n");
440}
441
Daniel Veillard75b96822001-10-11 18:59:45 +0000442static int
443xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
444 int ret;
445 xmlDocPtr doc;
446 xmlNsPtr ns;
447 xmlDtdPtr dtd;
448 xmlNodePtr node, catalog;
449 xmlOutputBufferPtr buf;
450 xmlCatalogEntryPtr cur;
451
452 /*
453 * Rebuild a catalog
454 */
455 doc = xmlNewDoc(NULL);
456 if (doc == NULL)
457 return(-1);
458 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
459 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
460BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
461
462 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
463
464 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
465 if (ns == NULL) {
466 xmlFreeDoc(doc);
467 return(-1);
468 }
469 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
470 if (catalog == NULL) {
471 xmlFreeNs(ns);
472 xmlFreeDoc(doc);
473 return(-1);
474 }
475 catalog->nsDef = ns;
476 xmlAddChild((xmlNodePtr) doc, catalog);
477
478 /*
479 * add all the catalog entries
480 */
481 cur = catal;
482 while (cur != NULL) {
483 switch (cur->type) {
Daniel Veillardc853b322001-11-06 15:24:37 +0000484 case XML_CATA_REMOVED:
485 break;
Daniel Veillard75b96822001-10-11 18:59:45 +0000486 case XML_CATA_BROKEN_CATALOG:
487 case XML_CATA_CATALOG:
488 if (cur == catal) {
489 cur = cur->children;
490 continue;
491 }
492 break;
493 case XML_CATA_NEXT_CATALOG:
494 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
495 xmlSetProp(node, BAD_CAST "catalog", cur->value);
496 xmlAddChild(catalog, node);
497 break;
498 case XML_CATA_NONE:
499 break;
500 case XML_CATA_PUBLIC:
501 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
502 xmlSetProp(node, BAD_CAST "publicId", cur->name);
503 xmlSetProp(node, BAD_CAST "uri", cur->value);
504 xmlAddChild(catalog, node);
505 break;
506 case XML_CATA_SYSTEM:
507 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
508 xmlSetProp(node, BAD_CAST "systemId", cur->name);
509 xmlSetProp(node, BAD_CAST "uri", cur->value);
510 xmlAddChild(catalog, node);
511 break;
512 case XML_CATA_REWRITE_SYSTEM:
513 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
514 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
515 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
516 xmlAddChild(catalog, node);
517 break;
518 case XML_CATA_DELEGATE_PUBLIC:
519 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
520 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
521 xmlSetProp(node, BAD_CAST "catalog", cur->value);
522 xmlAddChild(catalog, node);
523 break;
524 case XML_CATA_DELEGATE_SYSTEM:
525 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
526 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
527 xmlSetProp(node, BAD_CAST "catalog", cur->value);
528 xmlAddChild(catalog, node);
529 break;
530 case XML_CATA_URI:
531 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
532 xmlSetProp(node, BAD_CAST "name", cur->name);
533 xmlSetProp(node, BAD_CAST "uri", cur->value);
534 xmlAddChild(catalog, node);
535 break;
536 case XML_CATA_REWRITE_URI:
537 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
538 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
539 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
540 xmlAddChild(catalog, node);
541 break;
542 case XML_CATA_DELEGATE_URI:
543 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
544 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
545 xmlSetProp(node, BAD_CAST "catalog", cur->value);
546 xmlAddChild(catalog, node);
547 break;
548 case SGML_CATA_SYSTEM:
549 case SGML_CATA_PUBLIC:
550 case SGML_CATA_ENTITY:
551 case SGML_CATA_PENTITY:
552 case SGML_CATA_DOCTYPE:
553 case SGML_CATA_LINKTYPE:
554 case SGML_CATA_NOTATION:
555 case SGML_CATA_DELEGATE:
556 case SGML_CATA_BASE:
557 case SGML_CATA_CATALOG:
558 case SGML_CATA_DOCUMENT:
559 case SGML_CATA_SGMLDECL:
560 break;
561 }
562 cur = cur->next;
563 }
564
565 /*
566 * reserialize it
567 */
568 buf = xmlOutputBufferCreateFile(out, NULL);
569 if (buf == NULL) {
570 xmlFreeDoc(doc);
571 return(-1);
572 }
573 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
574
575 /*
576 * Free it
577 */
578 xmlFreeDoc(doc);
579
580 return(ret);
581}
582
583/************************************************************************
584 * *
585 * Converting SGML Catalogs to XML *
586 * *
587 ************************************************************************/
588
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000589/**
590 * xmlCatalogConvertEntry:
591 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000592 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000593 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000594 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000595 */
596static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000597xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
598 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
599 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000600 return;
601 switch (entry->type) {
602 case SGML_CATA_ENTITY:
603 entry->type = XML_CATA_PUBLIC;
604 break;
605 case SGML_CATA_PENTITY:
606 entry->type = XML_CATA_PUBLIC;
607 break;
608 case SGML_CATA_DOCTYPE:
609 entry->type = XML_CATA_PUBLIC;
610 break;
611 case SGML_CATA_LINKTYPE:
612 entry->type = XML_CATA_PUBLIC;
613 break;
614 case SGML_CATA_NOTATION:
615 entry->type = XML_CATA_PUBLIC;
616 break;
617 case SGML_CATA_PUBLIC:
618 entry->type = XML_CATA_PUBLIC;
619 break;
620 case SGML_CATA_SYSTEM:
621 entry->type = XML_CATA_SYSTEM;
622 break;
623 case SGML_CATA_DELEGATE:
624 entry->type = XML_CATA_DELEGATE_PUBLIC;
625 break;
626 case SGML_CATA_CATALOG:
627 entry->type = XML_CATA_CATALOG;
628 break;
629 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000630 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000631 (xmlHashDeallocator) xmlFreeCatalogEntry);
632 return;
633 }
634 /*
635 * Conversion successful, remove from the SGML catalog
636 * and add it to the default XML one
637 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000638 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
639 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000640 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000641 if (catal->xml->children == NULL)
642 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000643 else {
644 xmlCatalogEntryPtr prev;
645
Daniel Veillard75b96822001-10-11 18:59:45 +0000646 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000647 while (prev->next != NULL)
648 prev = prev->next;
649 prev->next = entry;
650 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000651}
652
653/**
654 * xmlConvertSGMLCatalog:
655 * @catal: the catalog
656 *
657 * Convert all the SGML catalog entries as XML ones
658 *
659 * Returns the number of entries converted if successful, -1 otherwise
660 */
661int
662xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
663
664 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
665 return(-1);
666
667 if (xmlDebugCatalogs) {
668 xmlGenericError(xmlGenericErrorContext,
669 "Converting SGML catalog to XML\n");
670 }
671 xmlHashScan(catal->sgml,
672 (xmlHashScanner) xmlCatalogConvertEntry,
673 &catal);
674 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000675}
676
Daniel Veillarda7374592001-05-10 14:17:55 +0000677/************************************************************************
678 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000679 * Helper function *
680 * *
681 ************************************************************************/
682
683/**
684 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000685 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000686 *
687 * Expand the URN into the equivalent Public Identifier
688 *
689 * Returns the new identifier or NULL, the string must be deallocated
690 * by the caller.
691 */
692static xmlChar *
693xmlCatalogUnWrapURN(const xmlChar *urn) {
694 xmlChar result[2000];
695 unsigned int i = 0;
696
697 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
698 return(NULL);
699 urn += sizeof(XML_URN_PUBID) - 1;
700
701 while (*urn != 0) {
702 if (i > sizeof(result) - 3)
703 break;
704 if (*urn == '+') {
705 result[i++] = ' ';
706 urn++;
707 } else if (*urn == ':') {
708 result[i++] = '/';
709 result[i++] = '/';
710 urn++;
711 } else if (*urn == ';') {
712 result[i++] = ':';
713 result[i++] = ':';
714 urn++;
715 } else if (*urn == '%') {
716 if ((urn[1] == '2') && (urn[1] == 'B'))
717 result[i++] = '+';
718 else if ((urn[1] == '3') && (urn[1] == 'A'))
719 result[i++] = ':';
720 else if ((urn[1] == '2') && (urn[1] == 'F'))
721 result[i++] = '/';
722 else if ((urn[1] == '3') && (urn[1] == 'B'))
723 result[i++] = ';';
724 else if ((urn[1] == '2') && (urn[1] == '7'))
725 result[i++] = '\'';
726 else if ((urn[1] == '3') && (urn[1] == 'F'))
727 result[i++] = '?';
728 else if ((urn[1] == '2') && (urn[1] == '3'))
729 result[i++] = '#';
730 else if ((urn[1] == '2') && (urn[1] == '5'))
731 result[i++] = '%';
732 else {
733 result[i++] = *urn;
734 urn++;
735 continue;
736 }
737 urn += 3;
738 } else {
739 result[i++] = *urn;
740 urn++;
741 }
742 }
743 result[i] = 0;
744
745 return(xmlStrdup(result));
746}
747
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000748/**
749 * xmlParseCatalogFile:
750 * @filename: the filename
751 *
752 * parse an XML file and build a tree. It's like xmlParseFile()
753 * except it bypass all catalog lookups.
754 *
755 * Returns the resulting document tree or NULL in case of error
756 */
757
758xmlDocPtr
759xmlParseCatalogFile(const char *filename) {
760 xmlDocPtr ret;
761 xmlParserCtxtPtr ctxt;
762 char *directory = NULL;
763 xmlParserInputPtr inputStream;
764 xmlParserInputBufferPtr buf;
765
766 ctxt = xmlNewParserCtxt();
767 if (ctxt == NULL) {
768 if (xmlDefaultSAXHandler.error != NULL) {
769 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
770 }
771 return(NULL);
772 }
773
774 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
775 if (buf == NULL) {
776 xmlFreeParserCtxt(ctxt);
777 return(NULL);
778 }
779
780 inputStream = xmlNewInputStream(ctxt);
781 if (inputStream == NULL) {
782 xmlFreeParserCtxt(ctxt);
783 return(NULL);
784 }
785
786 inputStream->filename = xmlMemStrdup(filename);
787 inputStream->buf = buf;
788 inputStream->base = inputStream->buf->buffer->content;
789 inputStream->cur = inputStream->buf->buffer->content;
790 inputStream->end =
791 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
792
793 inputPush(ctxt, inputStream);
794 if ((ctxt->directory == NULL) && (directory == NULL))
795 directory = xmlParserGetDirectory(filename);
796 if ((ctxt->directory == NULL) && (directory != NULL))
797 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000798 ctxt->valid = 0;
799 ctxt->validate = 0;
800 ctxt->loadsubset = 0;
801 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000802
803 xmlParseDocument(ctxt);
804
805 if (ctxt->wellFormed)
806 ret = ctxt->myDoc;
807 else {
808 ret = NULL;
809 xmlFreeDoc(ctxt->myDoc);
810 ctxt->myDoc = NULL;
811 }
812 xmlFreeParserCtxt(ctxt);
813
814 return(ret);
815}
816
Daniel Veillard75b96822001-10-11 18:59:45 +0000817/**
818 * xmlLoadFileContent:
819 * @filename: a file path
820 *
821 * Load a file content into memory.
822 *
823 * Returns a pointer to the 0 terminated string or NULL in case of error
824 */
825static xmlChar *
826xmlLoadFileContent(const char *filename)
827{
828#ifdef HAVE_STAT
829 int fd;
830#else
831 FILE *fd;
832#endif
833 int len;
834 long size;
835
836#ifdef HAVE_STAT
837 struct stat info;
838#endif
839 xmlChar *content;
840
841 if (filename == NULL)
842 return (NULL);
843
844#ifdef HAVE_STAT
845 if (stat(filename, &info) < 0)
846 return (NULL);
847#endif
848
849#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000850 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000851#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000852 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000853#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000854 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000855 return (NULL);
856 }
857#ifdef HAVE_STAT
858 size = info.st_size;
859#else
860 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
861 fclose(fd);
862 return (NULL);
863 }
864#endif
865 content = xmlMalloc(size + 10);
866 if (content == NULL) {
867 xmlGenericError(xmlGenericErrorContext,
868 "malloc of %d byte failed\n", size + 10);
869 return (NULL);
870 }
871#ifdef HAVE_STAT
872 len = read(fd, content, size);
873#else
874 len = fread(content, 1, size, fd);
875#endif
876 if (len < 0) {
877 xmlFree(content);
878 return (NULL);
879 }
880#ifdef HAVE_STAT
881 close(fd);
882#else
883 fclose(fd);
884#endif
885 content[len] = 0;
886
887 return(content);
888}
889
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000890/************************************************************************
891 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000892 * The XML Catalog parser *
893 * *
894 ************************************************************************/
895
896static xmlCatalogEntryPtr
897xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000898static void
899xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
900 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000901static xmlChar *
902xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
903 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000904static xmlChar *
905xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
906
Daniel Veillard344cee72001-08-20 00:08:40 +0000907
Daniel Veillard75b96822001-10-11 18:59:45 +0000908/**
909 * xmlGetXMLCatalogEntryType:
910 * @name: the name
911 *
912 * lookup the internal type associated to an XML catalog entry name
913 *
914 * Returns the type associate with that name
915 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000916static xmlCatalogEntryType
917xmlGetXMLCatalogEntryType(const xmlChar *name) {
918 xmlCatalogEntryType type = XML_CATA_NONE;
919 if (xmlStrEqual(name, (const xmlChar *) "system"))
920 type = XML_CATA_SYSTEM;
921 else if (xmlStrEqual(name, (const xmlChar *) "public"))
922 type = XML_CATA_PUBLIC;
923 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
924 type = XML_CATA_REWRITE_SYSTEM;
925 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
926 type = XML_CATA_DELEGATE_PUBLIC;
927 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
928 type = XML_CATA_DELEGATE_SYSTEM;
929 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
930 type = XML_CATA_URI;
931 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
932 type = XML_CATA_REWRITE_URI;
933 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
934 type = XML_CATA_DELEGATE_URI;
935 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
936 type = XML_CATA_NEXT_CATALOG;
937 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
938 type = XML_CATA_CATALOG;
939 return(type);
940}
941
Daniel Veillard75b96822001-10-11 18:59:45 +0000942/**
943 * xmlParseXMLCatalogOneNode:
944 * @cur: the XML node
945 * @type: the type of Catalog entry
946 * @name: the name of the node
947 * @attrName: the attribute holding the value
948 * @uriAttrName: the attribute holding the URI-Reference
949 * @prefer: the PUBLIC vs. SYSTEM current preference value
950 *
951 * Finishes the examination of an XML tree node of a catalog and build
952 * a Catalog entry from it.
953 *
954 * Returns the new Catalog entry node or NULL in case of error.
955 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000956static xmlCatalogEntryPtr
957xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
958 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000959 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000960 int ok = 1;
961 xmlChar *uriValue;
962 xmlChar *nameValue = NULL;
963 xmlChar *base = NULL;
964 xmlChar *URL = NULL;
965 xmlCatalogEntryPtr ret = NULL;
966
967 if (attrName != NULL) {
968 nameValue = xmlGetProp(cur, attrName);
969 if (nameValue == NULL) {
970 xmlGenericError(xmlGenericErrorContext,
971 "%s entry lacks '%s'\n", name, attrName);
972 ok = 0;
973 }
974 }
975 uriValue = xmlGetProp(cur, uriAttrName);
976 if (uriValue == NULL) {
977 xmlGenericError(xmlGenericErrorContext,
978 "%s entry lacks '%s'\n", name, uriAttrName);
979 ok = 0;
980 }
981 if (!ok) {
982 if (nameValue != NULL)
983 xmlFree(nameValue);
984 if (uriValue != NULL)
985 xmlFree(uriValue);
986 return(NULL);
987 }
988
989 base = xmlNodeGetBase(cur->doc, cur);
990 URL = xmlBuildURI(uriValue, base);
991 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000992 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000993 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000994 xmlGenericError(xmlGenericErrorContext,
995 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000996 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000997 xmlGenericError(xmlGenericErrorContext,
998 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000999 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001000 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001001 } else {
1002 xmlGenericError(xmlGenericErrorContext,
1003 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1004 }
1005 if (nameValue != NULL)
1006 xmlFree(nameValue);
1007 if (uriValue != NULL)
1008 xmlFree(uriValue);
1009 if (base != NULL)
1010 xmlFree(base);
1011 if (URL != NULL)
1012 xmlFree(URL);
1013 return(ret);
1014}
1015
Daniel Veillard75b96822001-10-11 18:59:45 +00001016/**
1017 * xmlParseXMLCatalogNode:
1018 * @cur: the XML node
1019 * @prefer: the PUBLIC vs. SYSTEM current preference value
1020 * @parent: the parent Catalog entry
1021 *
1022 * Examines an XML tree node of a catalog and build
1023 * a Catalog entry from it adding it to its parent. The examination can
1024 * be recursive.
1025 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001026static void
1027xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1028 xmlCatalogEntryPtr parent)
1029{
1030 xmlChar *uri = NULL;
1031 xmlChar *URL = NULL;
1032 xmlChar *base = NULL;
1033 xmlCatalogEntryPtr entry = NULL;
1034
1035 if (cur == NULL)
1036 return;
1037 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1038 xmlChar *prop;
1039
1040 prop = xmlGetProp(cur, BAD_CAST "prefer");
1041 if (prop != NULL) {
1042 if (xmlStrEqual(prop, BAD_CAST "system")) {
1043 prefer = XML_CATA_PREFER_SYSTEM;
1044 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1045 prefer = XML_CATA_PREFER_PUBLIC;
1046 } else {
1047 xmlGenericError(xmlGenericErrorContext,
1048 "Invalid value for prefer: '%s'\n", prop);
1049 }
1050 xmlFree(prop);
1051 }
1052 /*
1053 * Recurse to propagate prefer to the subtree
1054 * (xml:base handling is automated)
1055 */
1056 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1057 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1058 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001059 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001060 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1061 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001062 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001063 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1064 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1065 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001066 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001067 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1068 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1069 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001070 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001071 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1072 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1073 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001074 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001075 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1076 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1077 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001078 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001079 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1080 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1081 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001082 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001083 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1084 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1085 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001086 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001087 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1088 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1089 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001090 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001091 }
1092 if ((entry != NULL) && (parent != NULL)) {
1093 entry->parent = parent;
1094 if (parent->children == NULL)
1095 parent->children = entry;
1096 else {
1097 xmlCatalogEntryPtr prev;
1098
1099 prev = parent->children;
1100 while (prev->next != NULL)
1101 prev = prev->next;
1102 prev->next = entry;
1103 }
1104 }
1105 if (base != NULL)
1106 xmlFree(base);
1107 if (uri != NULL)
1108 xmlFree(uri);
1109 if (URL != NULL)
1110 xmlFree(URL);
1111}
1112
Daniel Veillard75b96822001-10-11 18:59:45 +00001113/**
1114 * xmlParseXMLCatalogNodeList:
1115 * @cur: the XML node list of siblings
1116 * @prefer: the PUBLIC vs. SYSTEM current preference value
1117 * @parent: the parent Catalog entry
1118 *
1119 * Examines a list of XML sibling nodes of a catalog and build
1120 * a list of Catalog entry from it adding it to the parent.
1121 * The examination will recurse to examine node subtrees.
1122 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001123static void
1124xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1125 xmlCatalogEntryPtr parent) {
1126 while (cur != NULL) {
1127 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1128 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1129 xmlParseXMLCatalogNode(cur, prefer, parent);
1130 }
1131 cur = cur->next;
1132 }
1133 /* TODO: sort the list according to REWRITE lengths and prefer value */
1134}
1135
Daniel Veillard75b96822001-10-11 18:59:45 +00001136/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001137 * xmlParseXMLCatalogFile:
1138 * @prefer: the PUBLIC vs. SYSTEM current preference value
1139 * @filename: the filename for the catalog
1140 *
1141 * Parses the catalog file to extract the XML tree and then analyze the
1142 * tree to build a list of Catalog entries corresponding to this catalog
1143 *
1144 * Returns the resulting Catalog entries list
1145 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001146static xmlCatalogEntryPtr
1147xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1148 xmlDocPtr doc;
1149 xmlNodePtr cur;
1150 xmlChar *prop;
1151 xmlCatalogEntryPtr parent = NULL;
1152
1153 if (filename == NULL)
1154 return(NULL);
1155
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001156 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001157 if (doc == NULL) {
1158 if (xmlDebugCatalogs)
1159 xmlGenericError(xmlGenericErrorContext,
1160 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001161 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001162 }
1163
1164 if (xmlDebugCatalogs)
1165 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001166 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001167
1168 cur = xmlDocGetRootElement(doc);
1169 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1170 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1171 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1172
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001173 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00001174 (const xmlChar *)filename, NULL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001175 if (parent == NULL) {
1176 xmlFreeDoc(doc);
1177 return(NULL);
1178 }
1179
1180 prop = xmlGetProp(cur, BAD_CAST "prefer");
1181 if (prop != NULL) {
1182 if (xmlStrEqual(prop, BAD_CAST "system")) {
1183 prefer = XML_CATA_PREFER_SYSTEM;
1184 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1185 prefer = XML_CATA_PREFER_PUBLIC;
1186 } else {
1187 xmlGenericError(xmlGenericErrorContext,
1188 "Invalid value for prefer: '%s'\n",
1189 prop);
1190 }
1191 xmlFree(prop);
1192 }
1193 cur = cur->children;
1194 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1195 } else {
1196 xmlGenericError(xmlGenericErrorContext,
1197 "File %s is not an XML Catalog\n", filename);
1198 xmlFreeDoc(doc);
1199 return(NULL);
1200 }
1201 xmlFreeDoc(doc);
1202 return(parent);
1203}
1204
Daniel Veillardcda96922001-08-21 10:56:31 +00001205/**
1206 * xmlFetchXMLCatalogFile:
1207 * @catal: an existing but incomplete catalog entry
1208 *
1209 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001210 *
1211 * Returns 0 in case of success, -1 otherwise
1212 */
1213static int
1214xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001215 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001216
1217 if (catal == NULL)
1218 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001219 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001220 return(-1);
1221 if (catal->children != NULL)
1222 return(-1);
1223
Daniel Veillard81463942001-10-16 12:34:39 +00001224 /*
1225 * lock the whole catalog for modification
1226 */
1227 xmlRMutexLock(xmlCatalogMutex);
1228 if (catal->children != NULL) {
1229 /* Okay someone else did it in the meantime */
1230 xmlRMutexUnlock(xmlCatalogMutex);
1231 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001232 }
1233
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001234 if (xmlCatalogXMLFiles != NULL) {
1235 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001236 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001237 if (doc != NULL) {
1238 if (xmlDebugCatalogs)
1239 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001240 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001241
1242 if (catal->type == XML_CATA_CATALOG)
1243 catal->children = doc->children;
1244 else
1245 catal->children = doc;
1246 catal->dealloc = 0;
1247 xmlRMutexUnlock(xmlCatalogMutex);
1248 return(0);
1249 }
1250 if (xmlDebugCatalogs)
1251 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001252 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001253 }
1254
Daniel Veillardcda96922001-08-21 10:56:31 +00001255 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001256 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001257 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001258 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001259 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001260 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001261 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001262 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001263 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001264 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001265 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001266
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001267 if (catal->type == XML_CATA_CATALOG)
1268 catal->children = doc->children;
1269 else
1270 catal->children = doc;
1271
1272 doc->dealloc = 1;
1273
Daniel Veillard81463942001-10-16 12:34:39 +00001274 if (xmlCatalogXMLFiles == NULL)
1275 xmlCatalogXMLFiles = xmlHashCreate(10);
1276 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001277 if (xmlDebugCatalogs)
1278 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001279 "%s added to file hash\n", catal->URL);
1280 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001281 }
Daniel Veillard81463942001-10-16 12:34:39 +00001282 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001283 return(0);
1284}
1285
Daniel Veillard75b96822001-10-11 18:59:45 +00001286/************************************************************************
1287 * *
1288 * XML Catalog handling *
1289 * *
1290 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001291
1292/**
1293 * xmlAddXMLCatalog:
1294 * @catal: top of an XML catalog
1295 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001296 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001297 * @replace: the replacement value for the match
1298 *
1299 * Add an entry in the XML catalog, it may overwrite existing but
1300 * different entries.
1301 *
1302 * Returns 0 if successful, -1 otherwise
1303 */
1304static int
1305xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1306 const xmlChar *orig, const xmlChar *replace) {
1307 xmlCatalogEntryPtr cur;
1308 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001309 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001310
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001311 if ((catal == NULL) ||
1312 ((catal->type != XML_CATA_CATALOG) &&
1313 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001314 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001315 if (catal->children == NULL) {
1316 xmlFetchXMLCatalogFile(catal);
1317 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001318 if (catal->children == NULL)
1319 doregister = 1;
1320
Daniel Veillard344cee72001-08-20 00:08:40 +00001321 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001322 if (typ == XML_CATA_NONE) {
1323 if (xmlDebugCatalogs)
1324 xmlGenericError(xmlGenericErrorContext,
1325 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001326 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001327 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001328
1329 cur = catal->children;
1330 /*
1331 * Might be a simple "update in place"
1332 */
1333 if (cur != NULL) {
1334 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001335 if ((orig != NULL) && (cur->type == typ) &&
1336 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001337 if (xmlDebugCatalogs)
1338 xmlGenericError(xmlGenericErrorContext,
1339 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001340 if (cur->value != NULL)
1341 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001342 if (cur->URL != NULL)
1343 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001344 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001345 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001346 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001347 }
1348 if (cur->next == NULL)
1349 break;
1350 cur = cur->next;
1351 }
1352 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001353 if (xmlDebugCatalogs)
1354 xmlGenericError(xmlGenericErrorContext,
1355 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001356 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001357 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1358 NULL, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001359 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001360 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1361 NULL, catal->prefer);
1362 if (doregister) {
1363 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1364 if (cur != NULL)
1365 cur->children = catal->children;
1366 }
1367
Daniel Veillardcda96922001-08-21 10:56:31 +00001368 return(0);
1369}
1370
1371/**
1372 * xmlDelXMLCatalog:
1373 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001374 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001375 *
1376 * Remove entries in the XML catalog where the value or the URI
1377 * is equal to @value
1378 *
1379 * Returns the number of entries removed if successful, -1 otherwise
1380 */
1381static int
1382xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001383 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001384 int ret = 0;
1385
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001386 if ((catal == NULL) ||
1387 ((catal->type != XML_CATA_CATALOG) &&
1388 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001389 return(-1);
1390 if (value == NULL)
1391 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001392 if (catal->children == NULL) {
1393 xmlFetchXMLCatalogFile(catal);
1394 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001395
1396 /*
1397 * Scan the children
1398 */
1399 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001400 while (cur != NULL) {
1401 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1402 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001403 if (xmlDebugCatalogs) {
1404 if (cur->name != NULL)
1405 xmlGenericError(xmlGenericErrorContext,
1406 "Removing element %s from catalog\n", cur->name);
1407 else
1408 xmlGenericError(xmlGenericErrorContext,
1409 "Removing element %s from catalog\n", cur->value);
1410 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001411 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001412 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001413 cur = cur->next;
1414 }
1415 return(ret);
1416}
1417
1418/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001419 * xmlCatalogXMLResolve:
1420 * @catal: a catalog list
1421 * @pubId: the public ID string
1422 * @sysId: the system ID string
1423 *
1424 * Do a complete resolution lookup of an External Identifier for a
1425 * list of catalog entries.
1426 *
1427 * Implements (or tries to) 7.1. External Identifier Resolution
1428 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1429 *
1430 * Returns the URI of the resource or NULL if not found
1431 */
1432static xmlChar *
1433xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1434 const xmlChar *sysID) {
1435 xmlChar *ret = NULL;
1436 xmlCatalogEntryPtr cur;
1437 int haveDelegate = 0;
1438 int haveNext = 0;
1439
1440 /*
1441 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1442 */
1443 if (sysID != NULL) {
1444 xmlCatalogEntryPtr rewrite = NULL;
1445 int lenrewrite = 0, len;
1446 cur = catal;
1447 haveDelegate = 0;
1448 while (cur != NULL) {
1449 switch (cur->type) {
1450 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001451 if (xmlStrEqual(sysID, cur->name)) {
1452 if (xmlDebugCatalogs)
1453 xmlGenericError(xmlGenericErrorContext,
1454 "Found system match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001455 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001456 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001457 break;
1458 case XML_CATA_REWRITE_SYSTEM:
1459 len = xmlStrlen(cur->name);
1460 if ((len > lenrewrite) &&
1461 (!xmlStrncmp(sysID, cur->name, len))) {
1462 lenrewrite = len;
1463 rewrite = cur;
1464 }
1465 break;
1466 case XML_CATA_DELEGATE_SYSTEM:
1467 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1468 haveDelegate++;
1469 break;
1470 case XML_CATA_NEXT_CATALOG:
1471 haveNext++;
1472 break;
1473 default:
1474 break;
1475 }
1476 cur = cur->next;
1477 }
1478 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001479 if (xmlDebugCatalogs)
1480 xmlGenericError(xmlGenericErrorContext,
1481 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001482 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001483 if (ret != NULL)
1484 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1485 return(ret);
1486 }
1487 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001488 const xmlChar *delegates[MAX_DELEGATE];
1489 int nbList = 0, i;
1490
Daniel Veillardcda96922001-08-21 10:56:31 +00001491 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001492 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001493 * matches when the list was produced.
1494 */
1495 cur = catal;
1496 while (cur != NULL) {
1497 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1498 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001499 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001500 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001501 break;
1502 if (i < nbList) {
1503 cur = cur->next;
1504 continue;
1505 }
1506 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001507 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001508
Daniel Veillardcda96922001-08-21 10:56:31 +00001509 if (cur->children == NULL) {
1510 xmlFetchXMLCatalogFile(cur);
1511 }
1512 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001513 if (xmlDebugCatalogs)
1514 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001515 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001516 ret = xmlCatalogListXMLResolve(
1517 cur->children, NULL, sysID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001518 if (ret != NULL)
1519 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001520 }
1521 }
1522 cur = cur->next;
1523 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001524 /*
1525 * Apply the cut algorithm explained in 4/
1526 */
1527 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001528 }
1529 }
1530 /*
1531 * Then tries 5/ 6/ if a public ID is provided
1532 */
1533 if (pubID != NULL) {
1534 cur = catal;
1535 haveDelegate = 0;
1536 while (cur != NULL) {
1537 switch (cur->type) {
1538 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001539 if (xmlStrEqual(pubID, cur->name)) {
1540 if (xmlDebugCatalogs)
1541 xmlGenericError(xmlGenericErrorContext,
1542 "Found public match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001543 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001544 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001545 break;
1546 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001547 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1548 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001549 haveDelegate++;
1550 break;
1551 case XML_CATA_NEXT_CATALOG:
1552 if (sysID == NULL)
1553 haveNext++;
1554 break;
1555 default:
1556 break;
1557 }
1558 cur = cur->next;
1559 }
1560 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001561 const xmlChar *delegates[MAX_DELEGATE];
1562 int nbList = 0, i;
1563
Daniel Veillardcda96922001-08-21 10:56:31 +00001564 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001565 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001566 * matches when the list was produced.
1567 */
1568 cur = catal;
1569 while (cur != NULL) {
1570 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001571 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1572 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001573
1574 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001575 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001576 break;
1577 if (i < nbList) {
1578 cur = cur->next;
1579 continue;
1580 }
1581 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001582 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001583
Daniel Veillardcda96922001-08-21 10:56:31 +00001584 if (cur->children == NULL) {
1585 xmlFetchXMLCatalogFile(cur);
1586 }
1587 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001588 if (xmlDebugCatalogs)
1589 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001590 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001591 ret = xmlCatalogListXMLResolve(
1592 cur->children, pubID, NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001593 if (ret != NULL)
1594 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001595 }
1596 }
1597 cur = cur->next;
1598 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001599 /*
1600 * Apply the cut algorithm explained in 4/
1601 */
1602 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001603 }
1604 }
1605 if (haveNext) {
1606 cur = catal;
1607 while (cur != NULL) {
1608 if (cur->type == XML_CATA_NEXT_CATALOG) {
1609 if (cur->children == NULL) {
1610 xmlFetchXMLCatalogFile(cur);
1611 }
1612 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001613 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1614 if (ret != NULL)
1615 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001616 }
1617 }
1618 cur = cur->next;
1619 }
1620 }
1621
1622 return(NULL);
1623}
1624
1625/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001626 * xmlCatalogXMLResolveURI:
1627 * @catal: a catalog list
1628 * @URI: the URI
1629 * @sysId: the system ID string
1630 *
1631 * Do a complete resolution lookup of an External Identifier for a
1632 * list of catalog entries.
1633 *
1634 * Implements (or tries to) 7.2.2. URI Resolution
1635 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1636 *
1637 * Returns the URI of the resource or NULL if not found
1638 */
1639static xmlChar *
1640xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1641 xmlChar *ret = NULL;
1642 xmlCatalogEntryPtr cur;
1643 int haveDelegate = 0;
1644 int haveNext = 0;
1645 xmlCatalogEntryPtr rewrite = NULL;
1646 int lenrewrite = 0, len;
1647
1648 if (catal == NULL)
1649 return(NULL);
1650
1651 if (URI == NULL)
1652 return(NULL);
1653
1654 /*
1655 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1656 */
1657 cur = catal;
1658 haveDelegate = 0;
1659 while (cur != NULL) {
1660 switch (cur->type) {
1661 case XML_CATA_URI:
1662 if (xmlStrEqual(URI, cur->name)) {
1663 if (xmlDebugCatalogs)
1664 xmlGenericError(xmlGenericErrorContext,
1665 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001666 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001667 }
1668 break;
1669 case XML_CATA_REWRITE_URI:
1670 len = xmlStrlen(cur->name);
1671 if ((len > lenrewrite) &&
1672 (!xmlStrncmp(URI, cur->name, len))) {
1673 lenrewrite = len;
1674 rewrite = cur;
1675 }
1676 break;
1677 case XML_CATA_DELEGATE_URI:
1678 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1679 haveDelegate++;
1680 break;
1681 case XML_CATA_NEXT_CATALOG:
1682 haveNext++;
1683 break;
1684 default:
1685 break;
1686 }
1687 cur = cur->next;
1688 }
1689 if (rewrite != NULL) {
1690 if (xmlDebugCatalogs)
1691 xmlGenericError(xmlGenericErrorContext,
1692 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001693 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001694 if (ret != NULL)
1695 ret = xmlStrcat(ret, &URI[lenrewrite]);
1696 return(ret);
1697 }
1698 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001699 const xmlChar *delegates[MAX_DELEGATE];
1700 int nbList = 0, i;
1701
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001702 /*
1703 * Assume the entries have been sorted by decreasing substring
1704 * matches when the list was produced.
1705 */
1706 cur = catal;
1707 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001708 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1709 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001710 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001711 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001712 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001713 break;
1714 if (i < nbList) {
1715 cur = cur->next;
1716 continue;
1717 }
1718 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001719 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001720
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001721 if (cur->children == NULL) {
1722 xmlFetchXMLCatalogFile(cur);
1723 }
1724 if (cur->children != NULL) {
1725 if (xmlDebugCatalogs)
1726 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001727 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001728 ret = xmlCatalogListXMLResolveURI(
1729 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001730 if (ret != NULL)
1731 return(ret);
1732 }
1733 }
1734 cur = cur->next;
1735 }
1736 /*
1737 * Apply the cut algorithm explained in 4/
1738 */
1739 return(XML_CATAL_BREAK);
1740 }
1741 if (haveNext) {
1742 cur = catal;
1743 while (cur != NULL) {
1744 if (cur->type == XML_CATA_NEXT_CATALOG) {
1745 if (cur->children == NULL) {
1746 xmlFetchXMLCatalogFile(cur);
1747 }
1748 if (cur->children != NULL) {
1749 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1750 if (ret != NULL)
1751 return(ret);
1752 }
1753 }
1754 cur = cur->next;
1755 }
1756 }
1757
1758 return(NULL);
1759}
1760
1761/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001762 * xmlCatalogListXMLResolve:
1763 * @catal: a catalog list
1764 * @pubId: the public ID string
1765 * @sysId: the system ID string
1766 *
1767 * Do a complete resolution lookup of an External Identifier for a
1768 * list of catalogs
1769 *
1770 * Implements (or tries to) 7.1. External Identifier Resolution
1771 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1772 *
1773 * Returns the URI of the resource or NULL if not found
1774 */
1775static xmlChar *
1776xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1777 const xmlChar *sysID) {
1778 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001779 xmlChar *urnID = NULL;
1780
1781 if (catal == NULL)
1782 return(NULL);
1783 if ((pubID == NULL) && (sysID == NULL))
1784 return(NULL);
1785
1786 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1787 urnID = xmlCatalogUnWrapURN(pubID);
1788 if (xmlDebugCatalogs) {
1789 if (urnID == NULL)
1790 xmlGenericError(xmlGenericErrorContext,
1791 "Public URN ID %s expanded to NULL\n", pubID);
1792 else
1793 xmlGenericError(xmlGenericErrorContext,
1794 "Public URN ID expanded to %s\n", urnID);
1795 }
1796 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1797 if (urnID != NULL)
1798 xmlFree(urnID);
1799 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001800 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001801 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1802 urnID = xmlCatalogUnWrapURN(sysID);
1803 if (xmlDebugCatalogs) {
1804 if (urnID == NULL)
1805 xmlGenericError(xmlGenericErrorContext,
1806 "System URN ID %s expanded to NULL\n", sysID);
1807 else
1808 xmlGenericError(xmlGenericErrorContext,
1809 "System URN ID expanded to %s\n", urnID);
1810 }
1811 if (pubID == NULL)
1812 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1813 else if (xmlStrEqual(pubID, urnID))
1814 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1815 else {
1816 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1817 }
1818 if (urnID != NULL)
1819 xmlFree(urnID);
1820 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001821 }
1822 while (catal != NULL) {
1823 if (catal->type == XML_CATA_CATALOG) {
1824 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001825 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001826 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001827 if (catal->children != NULL) {
1828 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1829 if (ret != NULL)
1830 return(ret);
1831 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001832 }
1833 catal = catal->next;
1834 }
1835 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001836}
1837
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001838/**
1839 * xmlCatalogListXMLResolveURI:
1840 * @catal: a catalog list
1841 * @URI: the URI
1842 *
1843 * Do a complete resolution lookup of an URI for a list of catalogs
1844 *
1845 * Implements (or tries to) 7.2. URI Resolution
1846 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1847 *
1848 * Returns the URI of the resource or NULL if not found
1849 */
1850static xmlChar *
1851xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1852 xmlChar *ret = NULL;
1853 xmlChar *urnID = NULL;
1854
1855 if (catal == NULL)
1856 return(NULL);
1857 if (URI == NULL)
1858 return(NULL);
1859
1860 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1861 urnID = xmlCatalogUnWrapURN(URI);
1862 if (xmlDebugCatalogs) {
1863 if (urnID == NULL)
1864 xmlGenericError(xmlGenericErrorContext,
1865 "URN ID %s expanded to NULL\n", URI);
1866 else
1867 xmlGenericError(xmlGenericErrorContext,
1868 "URN ID expanded to %s\n", urnID);
1869 }
1870 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1871 if (urnID != NULL)
1872 xmlFree(urnID);
1873 return(ret);
1874 }
1875 while (catal != NULL) {
1876 if (catal->type == XML_CATA_CATALOG) {
1877 if (catal->children == NULL) {
1878 xmlFetchXMLCatalogFile(catal);
1879 }
1880 if (catal->children != NULL) {
1881 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1882 if (ret != NULL)
1883 return(ret);
1884 }
1885 }
1886 catal = catal->next;
1887 }
1888 return(ret);
1889}
1890
Daniel Veillard344cee72001-08-20 00:08:40 +00001891/************************************************************************
1892 * *
1893 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001894 * *
1895 ************************************************************************/
1896
1897
1898#define RAW *cur
1899#define NEXT cur++;
1900#define SKIP(x) cur += x;
1901
1902#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1903
Daniel Veillard75b96822001-10-11 18:59:45 +00001904/**
1905 * xmlParseSGMLCatalogComment:
1906 * @cur: the current character
1907 *
1908 * Skip a comment in an SGML catalog
1909 *
1910 * Returns new current character
1911 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001912static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001913xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001914 if ((cur[0] != '-') || (cur[1] != '-'))
1915 return(cur);
1916 SKIP(2);
1917 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1918 NEXT;
1919 if (cur[0] == 0) {
1920 return(NULL);
1921 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001922 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001923}
1924
Daniel Veillard75b96822001-10-11 18:59:45 +00001925/**
1926 * xmlParseSGMLCatalogPubid:
1927 * @cur: the current character
1928 * @id: the return location
1929 *
1930 * Parse an SGML catalog ID
1931 *
1932 * Returns new current character and store the value in @id
1933 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001934static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001935xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001936 xmlChar *buf = NULL;
1937 int len = 0;
1938 int size = 50;
1939 xmlChar stop;
1940 int count = 0;
1941
1942 *id = NULL;
1943
1944 if (RAW == '"') {
1945 NEXT;
1946 stop = '"';
1947 } else if (RAW == '\'') {
1948 NEXT;
1949 stop = '\'';
1950 } else {
1951 stop = ' ';
1952 }
1953 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1954 if (buf == NULL) {
1955 xmlGenericError(xmlGenericErrorContext,
1956 "malloc of %d byte failed\n", size);
1957 return(NULL);
1958 }
Daniel Veillard935494a2002-10-22 14:22:46 +00001959 while (xmlIsPubidChar(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001960 if ((*cur == stop) && (stop != ' '))
1961 break;
1962 if ((stop == ' ') && (IS_BLANK(*cur)))
1963 break;
1964 if (len + 1 >= size) {
1965 size *= 2;
1966 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1967 if (buf == NULL) {
1968 xmlGenericError(xmlGenericErrorContext,
1969 "realloc of %d byte failed\n", size);
1970 return(NULL);
1971 }
1972 }
1973 buf[len++] = *cur;
1974 count++;
1975 NEXT;
1976 }
1977 buf[len] = 0;
1978 if (stop == ' ') {
1979 if (!IS_BLANK(*cur)) {
1980 xmlFree(buf);
1981 return(NULL);
1982 }
1983 } else {
1984 if (*cur != stop) {
1985 xmlFree(buf);
1986 return(NULL);
1987 }
1988 NEXT;
1989 }
1990 *id = buf;
1991 return(cur);
1992}
1993
Daniel Veillard75b96822001-10-11 18:59:45 +00001994/**
1995 * xmlParseSGMLCatalogName:
1996 * @cur: the current character
1997 * @name: the return location
1998 *
1999 * Parse an SGML catalog name
2000 *
2001 * Returns new current character and store the value in @name
2002 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002003static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002004xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002005 xmlChar buf[XML_MAX_NAMELEN + 5];
2006 int len = 0;
2007 int c;
2008
2009 *name = NULL;
2010
2011 /*
2012 * Handler for more complex cases
2013 */
2014 c = *cur;
2015 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2016 return(NULL);
2017 }
2018
2019 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2020 (c == '.') || (c == '-') ||
2021 (c == '_') || (c == ':'))) {
2022 buf[len++] = c;
2023 cur++;
2024 c = *cur;
2025 if (len >= XML_MAX_NAMELEN)
2026 return(NULL);
2027 }
2028 *name = xmlStrndup(buf, len);
2029 return(cur);
2030}
2031
Daniel Veillard75b96822001-10-11 18:59:45 +00002032/**
2033 * xmlGetSGMLCatalogEntryType:
2034 * @name: the entry name
2035 *
2036 * Get the Catalog entry type for a given SGML Catalog name
2037 *
2038 * Returns Catalog entry type
2039 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002040static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002041xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002042 xmlCatalogEntryType type = XML_CATA_NONE;
2043 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2044 type = SGML_CATA_SYSTEM;
2045 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2046 type = SGML_CATA_PUBLIC;
2047 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2048 type = SGML_CATA_DELEGATE;
2049 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2050 type = SGML_CATA_ENTITY;
2051 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2052 type = SGML_CATA_DOCTYPE;
2053 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2054 type = SGML_CATA_LINKTYPE;
2055 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2056 type = SGML_CATA_NOTATION;
2057 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2058 type = SGML_CATA_SGMLDECL;
2059 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2060 type = SGML_CATA_DOCUMENT;
2061 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2062 type = SGML_CATA_CATALOG;
2063 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2064 type = SGML_CATA_BASE;
2065 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2066 type = SGML_CATA_DELEGATE;
2067 return(type);
2068}
2069
Daniel Veillard75b96822001-10-11 18:59:45 +00002070/**
2071 * xmlParseSGMLCatalog:
2072 * @catal: the SGML Catalog
2073 * @value: the content of the SGML Catalog serialization
2074 * @file: the filepath for the catalog
2075 * @super: should this be handled as a Super Catalog in which case
2076 * parsing is not recursive
2077 *
2078 * Parse an SGML catalog content and fill up the @catal hash table with
2079 * the new entries found.
2080 *
2081 * Returns 0 in case of success, -1 in case of error.
2082 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002083static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002084xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2085 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002086 const xmlChar *cur = value;
2087 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002088 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002089
2090 if ((cur == NULL) || (file == NULL))
2091 return(-1);
2092 base = xmlStrdup((const xmlChar *) file);
2093
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002094 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002095 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002096 if (cur[0] == 0)
2097 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002098 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002099 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002100 if (cur == NULL) {
2101 /* error */
2102 break;
2103 }
2104 } else {
2105 xmlChar *sysid = NULL;
2106 xmlChar *name = NULL;
2107 xmlCatalogEntryType type = XML_CATA_NONE;
2108
Daniel Veillardcda96922001-08-21 10:56:31 +00002109 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002110 if (name == NULL) {
2111 /* error */
2112 break;
2113 }
2114 if (!IS_BLANK(*cur)) {
2115 /* error */
2116 break;
2117 }
2118 SKIP_BLANKS;
2119 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002120 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002121 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002122 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002123 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002124 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002125 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002126 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002127 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002128 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002129 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002130 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002131 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002132 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002133 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002134 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002135 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002136 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002137 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002138 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002139 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002140 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002141 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002142 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002143 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2144 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002145 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002146 if (name == NULL) {
2147 /* error */
2148 break;
2149 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002150 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002151 continue;
2152 }
2153 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002154 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002155
2156 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002157 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002158 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002159 type = SGML_CATA_PENTITY;
2160 case SGML_CATA_PENTITY:
2161 case SGML_CATA_DOCTYPE:
2162 case SGML_CATA_LINKTYPE:
2163 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002164 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002165 if (cur == NULL) {
2166 /* error */
2167 break;
2168 }
2169 if (!IS_BLANK(*cur)) {
2170 /* error */
2171 break;
2172 }
2173 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002174 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002175 if (cur == NULL) {
2176 /* error */
2177 break;
2178 }
2179 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002180 case SGML_CATA_PUBLIC:
2181 case SGML_CATA_SYSTEM:
2182 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002183 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002184 if (cur == NULL) {
2185 /* error */
2186 break;
2187 }
2188 if (!IS_BLANK(*cur)) {
2189 /* error */
2190 break;
2191 }
2192 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002193 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002194 if (cur == NULL) {
2195 /* error */
2196 break;
2197 }
2198 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002199 case SGML_CATA_BASE:
2200 case SGML_CATA_CATALOG:
2201 case SGML_CATA_DOCUMENT:
2202 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002203 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002204 if (cur == NULL) {
2205 /* error */
2206 break;
2207 }
2208 break;
2209 default:
2210 break;
2211 }
2212 if (cur == NULL) {
2213 if (name != NULL)
2214 xmlFree(name);
2215 if (sysid != NULL)
2216 xmlFree(sysid);
2217 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002218 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002219 if (base != NULL)
2220 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002221 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002222 } else if ((type == SGML_CATA_PUBLIC) ||
2223 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002224 xmlChar *filename;
2225
2226 filename = xmlBuildURI(sysid, base);
2227 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002228 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002229
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002230 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002231 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002232 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002233 if (res < 0) {
2234 xmlFreeCatalogEntry(entry);
2235 }
2236 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002237 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002238
Daniel Veillard344cee72001-08-20 00:08:40 +00002239 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002240 if (super) {
2241 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002242
Daniel Veillardc853b322001-11-06 15:24:37 +00002243 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002244 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002245 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002246 if (res < 0) {
2247 xmlFreeCatalogEntry(entry);
2248 }
2249 } else {
2250 xmlChar *filename;
2251
2252 filename = xmlBuildURI(sysid, base);
2253 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002254 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002255 xmlFree(filename);
2256 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002257 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002258 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002259 /*
2260 * drop anything else we won't handle it
2261 */
2262 if (name != NULL)
2263 xmlFree(name);
2264 if (sysid != NULL)
2265 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002266 }
2267 }
2268 if (base != NULL)
2269 xmlFree(base);
2270 if (cur == NULL)
2271 return(-1);
2272 return(0);
2273}
2274
Daniel Veillard75b96822001-10-11 18:59:45 +00002275/************************************************************************
2276 * *
2277 * SGML Catalog handling *
2278 * *
2279 ************************************************************************/
2280
Daniel Veillardcda96922001-08-21 10:56:31 +00002281/**
2282 * xmlCatalogGetSGMLPublic:
2283 * @catal: an SGML catalog hash
2284 * @pubId: the public ID string
2285 *
2286 * Try to lookup the system ID associated to a public ID
2287 *
2288 * Returns the system ID if found or NULL otherwise.
2289 */
2290static const xmlChar *
2291xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2292 xmlCatalogEntryPtr entry;
2293
2294 if (catal == NULL)
2295 return(NULL);
2296
2297 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2298 if (entry == NULL)
2299 return(NULL);
2300 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillardc853b322001-11-06 15:24:37 +00002301 return(entry->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002302 return(NULL);
2303}
2304
2305/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002306 * xmlCatalogGetSGMLSystem:
2307 * @catal: an SGML catalog hash
2308 * @sysId: the public ID string
2309 *
2310 * Try to lookup the catalog local reference for a system ID
2311 *
2312 * Returns the system ID if found or NULL otherwise.
2313 */
2314static const xmlChar *
2315xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2316 xmlCatalogEntryPtr entry;
2317
2318 if (catal == NULL)
2319 return(NULL);
2320
2321 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2322 if (entry == NULL)
2323 return(NULL);
2324 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002325 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002326 return(NULL);
2327}
2328
2329/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002330 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002331 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002332 * @pubId: the public ID string
2333 * @sysId: the system ID string
2334 *
2335 * Do a complete resolution lookup of an External Identifier
2336 *
2337 * Returns the URI of the resource or NULL if not found
2338 */
2339static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002340xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2341 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002342 const xmlChar *ret = NULL;
2343
Daniel Veillard75b96822001-10-11 18:59:45 +00002344 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002345 return(NULL);
2346
2347 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002348 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002349 if (ret != NULL)
2350 return(ret);
2351 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002352 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002353 return(NULL);
2354}
2355
Daniel Veillarda7374592001-05-10 14:17:55 +00002356/************************************************************************
2357 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002358 * Specific Public interfaces *
2359 * *
2360 ************************************************************************/
2361
2362/**
2363 * xmlLoadSGMLSuperCatalog:
2364 * @filename: a file path
2365 *
2366 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2367 * references. This is only needed for manipulating SGML Super Catalogs
2368 * like adding and removing CATALOG or DELEGATE entries.
2369 *
2370 * Returns the catalog parsed or NULL in case of error
2371 */
2372xmlCatalogPtr
2373xmlLoadSGMLSuperCatalog(const char *filename)
2374{
2375 xmlChar *content;
2376 xmlCatalogPtr catal;
2377 int ret;
2378
2379 content = xmlLoadFileContent(filename);
2380 if (content == NULL)
2381 return(NULL);
2382
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002383 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002384 if (catal == NULL) {
2385 xmlFree(content);
2386 return(NULL);
2387 }
2388
2389 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2390 xmlFree(content);
2391 if (ret < 0) {
2392 xmlFreeCatalog(catal);
2393 return(NULL);
2394 }
2395 return (catal);
2396}
2397
2398/**
2399 * xmlLoadACatalog:
2400 * @filename: a file path
2401 *
2402 * Load the catalog and build the associated data structures.
2403 * This can be either an XML Catalog or an SGML Catalog
2404 * It will recurse in SGML CATALOG entries. On the other hand XML
2405 * Catalogs are not handled recursively.
2406 *
2407 * Returns the catalog parsed or NULL in case of error
2408 */
2409xmlCatalogPtr
2410xmlLoadACatalog(const char *filename)
2411{
2412 xmlChar *content;
2413 xmlChar *first;
2414 xmlCatalogPtr catal;
2415 int ret;
2416
2417 content = xmlLoadFileContent(filename);
2418 if (content == NULL)
2419 return(NULL);
2420
2421
2422 first = content;
2423
2424 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2425 (!(((*first >= 'A') && (*first <= 'Z')) ||
2426 ((*first >= 'a') && (*first <= 'z')))))
2427 first++;
2428
2429 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002430 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002431 if (catal == NULL) {
2432 xmlFree(content);
2433 return(NULL);
2434 }
2435 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2436 if (ret < 0) {
2437 xmlFreeCatalog(catal);
2438 xmlFree(content);
2439 return(NULL);
2440 }
2441 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002442 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002443 if (catal == NULL) {
2444 xmlFree(content);
2445 return(NULL);
2446 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002447 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002448 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002449 }
2450 xmlFree(content);
2451 return (catal);
2452}
2453
2454/**
2455 * xmlExpandCatalog:
2456 * @catal: a catalog
2457 * @filename: a file path
2458 *
2459 * Load the catalog and expand the existing catal structure.
2460 * This can be either an XML Catalog or an SGML Catalog
2461 *
2462 * Returns 0 in case of success, -1 in case of error
2463 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002464static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002465xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2466{
Daniel Veillard75b96822001-10-11 18:59:45 +00002467 int ret;
2468
2469 if ((catal == NULL) || (filename == NULL))
2470 return(-1);
2471
Daniel Veillard75b96822001-10-11 18:59:45 +00002472
2473 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002474 xmlChar *content;
2475
2476 content = xmlLoadFileContent(filename);
2477 if (content == NULL)
2478 return(-1);
2479
Daniel Veillard75b96822001-10-11 18:59:45 +00002480 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2481 if (ret < 0) {
2482 xmlFree(content);
2483 return(-1);
2484 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002485 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002486 } else {
2487 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002488 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002489 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002490
Daniel Veillard75b96822001-10-11 18:59:45 +00002491 cur = catal->xml;
2492 if (cur == NULL) {
2493 catal->xml = tmp;
2494 } else {
2495 while (cur->next != NULL) cur = cur->next;
2496 cur->next = tmp;
2497 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002498 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002499 return (0);
2500}
2501
2502/**
2503 * xmlACatalogResolveSystem:
2504 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002505 * @sysID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002506 *
2507 * Try to lookup the catalog resource for a system ID
2508 *
2509 * Returns the system ID if found or NULL otherwise, the value returned
2510 * must be freed by the caller.
2511 */
2512xmlChar *
2513xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2514 xmlChar *ret = NULL;
2515
2516 if ((sysID == NULL) || (catal == NULL))
2517 return(NULL);
2518
2519 if (xmlDebugCatalogs)
2520 xmlGenericError(xmlGenericErrorContext,
2521 "Resolve sysID %s\n", sysID);
2522
2523 if (catal->type == XML_XML_CATALOG_TYPE) {
2524 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2525 if (ret == XML_CATAL_BREAK)
2526 ret = NULL;
2527 } else {
2528 const xmlChar *sgml;
2529
2530 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2531 if (sgml != NULL)
2532 ret = xmlStrdup(sgml);
2533 }
2534 return(ret);
2535}
2536
2537/**
2538 * xmlACatalogResolvePublic:
2539 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002540 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002541 *
2542 * Try to lookup the system ID associated to a public ID in that catalog
2543 *
2544 * Returns the system ID if found or NULL otherwise, the value returned
2545 * must be freed by the caller.
2546 */
2547xmlChar *
2548xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2549 xmlChar *ret = NULL;
2550
2551 if ((pubID == NULL) || (catal == NULL))
2552 return(NULL);
2553
2554 if (xmlDebugCatalogs)
2555 xmlGenericError(xmlGenericErrorContext,
2556 "Resolve pubID %s\n", pubID);
2557
2558 if (catal->type == XML_XML_CATALOG_TYPE) {
2559 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2560 if (ret == XML_CATAL_BREAK)
2561 ret = NULL;
2562 } else {
2563 const xmlChar *sgml;
2564
2565 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2566 if (sgml != NULL)
2567 ret = xmlStrdup(sgml);
2568 }
2569 return(ret);
2570}
2571
2572/**
2573 * xmlACatalogResolve:
2574 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002575 * @pubID: the public ID string
2576 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002577 *
2578 * Do a complete resolution lookup of an External Identifier
2579 *
2580 * Returns the URI of the resource or NULL if not found, it must be freed
2581 * by the caller.
2582 */
2583xmlChar *
2584xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2585 const xmlChar * sysID)
2586{
2587 xmlChar *ret = NULL;
2588
2589 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2590 return (NULL);
2591
2592 if (xmlDebugCatalogs) {
2593 if (pubID != NULL) {
2594 xmlGenericError(xmlGenericErrorContext,
2595 "Resolve: pubID %s\n", pubID);
2596 } else {
2597 xmlGenericError(xmlGenericErrorContext,
2598 "Resolve: sysID %s\n", sysID);
2599 }
2600 }
2601
2602 if (catal->type == XML_XML_CATALOG_TYPE) {
2603 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2604 if (ret == XML_CATAL_BREAK)
2605 ret = NULL;
2606 } else {
2607 const xmlChar *sgml;
2608
2609 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2610 if (sgml != NULL)
2611 ret = xmlStrdup(sgml);
2612 }
2613 return (ret);
2614}
2615
2616/**
2617 * xmlACatalogResolveURI:
2618 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002619 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002620 *
2621 * Do a complete resolution lookup of an URI
2622 *
2623 * Returns the URI of the resource or NULL if not found, it must be freed
2624 * by the caller.
2625 */
2626xmlChar *
2627xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2628 xmlChar *ret = NULL;
2629
2630 if ((URI == NULL) || (catal == NULL))
2631 return(NULL);
2632
Daniel Veillardb44025c2001-10-11 22:55:55 +00002633 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002634 xmlGenericError(xmlGenericErrorContext,
2635 "Resolve URI %s\n", URI);
2636
2637 if (catal->type == XML_XML_CATALOG_TYPE) {
2638 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2639 if (ret == XML_CATAL_BREAK)
2640 ret = NULL;
2641 } else {
2642 const xmlChar *sgml;
2643
2644 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2645 if (sgml != NULL)
2646 sgml = xmlStrdup(sgml);
2647 }
2648 return(ret);
2649}
2650
2651/**
2652 * xmlACatalogDump:
2653 * @catal: a Catalog
2654 * @out: the file.
2655 *
2656 * Free up all the memory associated with catalogs
2657 */
2658void
2659xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002660 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002661 return;
2662
2663 if (catal->type == XML_XML_CATALOG_TYPE) {
2664 xmlDumpXMLCatalog(out, catal->xml);
2665 } else {
2666 xmlHashScan(catal->sgml,
2667 (xmlHashScanner) xmlCatalogDumpEntry, out);
2668 }
2669}
2670
2671/**
2672 * xmlACatalogAdd:
2673 * @catal: a Catalog
2674 * @type: the type of record to add to the catalog
2675 * @orig: the system, public or prefix to match
2676 * @replace: the replacement value for the match
2677 *
2678 * Add an entry in the catalog, it may overwrite existing but
2679 * different entries.
2680 *
2681 * Returns 0 if successful, -1 otherwise
2682 */
2683int
2684xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2685 const xmlChar * orig, const xmlChar * replace)
2686{
2687 int res = -1;
2688
2689 if (catal == NULL)
2690 return(-1);
2691
2692 if (catal->type == XML_XML_CATALOG_TYPE) {
2693 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2694 } else {
2695 xmlCatalogEntryType cattype;
2696
2697 cattype = xmlGetSGMLCatalogEntryType(type);
2698 if (cattype != XML_CATA_NONE) {
2699 xmlCatalogEntryPtr entry;
2700
Daniel Veillardc853b322001-11-06 15:24:37 +00002701 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002702 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002703 if (catal->sgml == NULL)
2704 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002705 res = xmlHashAddEntry(catal->sgml, orig, entry);
2706 }
2707 }
2708 return (res);
2709}
2710
2711/**
2712 * xmlACatalogRemove:
2713 * @catal: a Catalog
2714 * @value: the value to remove
2715 *
2716 * Remove an entry from the catalog
2717 *
2718 * Returns the number of entries removed if successful, -1 otherwise
2719 */
2720int
2721xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2722 int res = -1;
2723
2724 if ((catal == NULL) || (value == NULL))
2725 return(-1);
2726
2727 if (catal->type == XML_XML_CATALOG_TYPE) {
2728 res = xmlDelXMLCatalog(catal->xml, value);
2729 } else {
2730 res = xmlHashRemoveEntry(catal->sgml, value,
2731 (xmlHashDeallocator) xmlFreeCatalogEntry);
2732 if (res == 0)
2733 res = 1;
2734 }
2735 return(res);
2736}
2737
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002738/**
2739 * xmlNewCatalog:
2740 * @sgml: should this create an SGML catalog
2741 *
2742 * create a new Catalog.
2743 *
2744 * Returns the xmlCatalogPtr or NULL in case of error
2745 */
2746xmlCatalogPtr
2747xmlNewCatalog(int sgml) {
2748 xmlCatalogPtr catal = NULL;
2749
2750 if (sgml) {
2751 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2752 xmlCatalogDefaultPrefer);
2753 if ((catal != NULL) && (catal->sgml == NULL))
2754 catal->sgml = xmlHashCreate(10);
2755 } else
2756 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2757 xmlCatalogDefaultPrefer);
2758 return(catal);
2759}
2760
2761/**
2762 * xmlCatalogIsEmpty:
2763 * @catal: should this create an SGML catalog
2764 *
2765 * Check is a catalog is empty
2766 *
2767 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2768 */
2769int
2770xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2771 if (catal == NULL)
2772 return(-1);
2773
2774 if (catal->type == XML_XML_CATALOG_TYPE) {
2775 if (catal->xml == NULL)
2776 return(1);
2777 if ((catal->xml->type != XML_CATA_CATALOG) &&
2778 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2779 return(-1);
2780 if (catal->xml->children == NULL)
2781 return(1);
2782 return(0);
2783 } else {
2784 int res;
2785
2786 if (catal->sgml == NULL)
2787 return(1);
2788 res = xmlHashSize(catal->sgml);
2789 if (res == 0)
2790 return(1);
2791 if (res < 0)
2792 return(-1);
2793 }
2794 return(0);
2795}
2796
Daniel Veillard75b96822001-10-11 18:59:45 +00002797/************************************************************************
2798 * *
2799 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002800 * *
2801 ************************************************************************/
2802
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002803/**
Daniel Veillard81463942001-10-16 12:34:39 +00002804 * xmlInitializeCatalogData:
2805 *
2806 * Do the catalog initialization only of global data, doesn't try to load
2807 * any catalog actually.
2808 * this function is not thread safe, catalog initialization should
2809 * preferably be done once at startup
2810 */
2811static void
2812xmlInitializeCatalogData(void) {
2813 if (xmlCatalogInitialized != 0)
2814 return;
2815
2816 if (getenv("XML_DEBUG_CATALOG"))
2817 xmlDebugCatalogs = 1;
2818 xmlCatalogMutex = xmlNewRMutex();
2819
2820 xmlCatalogInitialized = 1;
2821}
2822/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002823 * xmlInitializeCatalog:
2824 *
2825 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002826 * this function is not thread safe, catalog initialization should
2827 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002828 */
2829void
2830xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002831 if (xmlCatalogInitialized != 0)
2832 return;
2833
Daniel Veillard81463942001-10-16 12:34:39 +00002834 xmlInitializeCatalogData();
2835 xmlRMutexLock(xmlCatalogMutex);
2836
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002837 if (getenv("XML_DEBUG_CATALOG"))
2838 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002839
Daniel Veillard75b96822001-10-11 18:59:45 +00002840 if (xmlDefaultCatalog == NULL) {
2841 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002842 char *path;
2843 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00002844 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002845 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00002846
Daniel Veillardb44025c2001-10-11 22:55:55 +00002847 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002848 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002849 catalogs = XML_XML_DEFAULT_CATALOG;
2850
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002851 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2852 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002853 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002854 /* the XML_CATALOG_FILES envvar is allowed to contain a
2855 space-separated list of entries. */
2856 cur = catalogs;
2857 nextent = &catal->xml;
2858 while (*cur != '\0') {
2859 while (IS_BLANK(*cur))
2860 cur++;
2861 if (*cur != 0) {
2862 paths = cur;
2863 while ((*cur != 0) && (!IS_BLANK(*cur)))
2864 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002865 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002866 if (path != NULL) {
2867 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2868 NULL, BAD_CAST path, xmlCatalogDefaultPrefer);
2869 if (*nextent != NULL)
2870 nextent = &((*nextent)->next);
2871 xmlFree(path);
2872 }
2873 }
2874 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002875 xmlDefaultCatalog = catal;
2876 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002877 }
2878
Daniel Veillard81463942001-10-16 12:34:39 +00002879 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002880}
2881
Daniel Veillard82d75332001-10-08 15:01:59 +00002882
2883/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002884 * xmlLoadCatalog:
2885 * @filename: a file path
2886 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002887 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002888 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002889 * this function is not thread safe, catalog initialization should
2890 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002891 *
2892 * Returns 0 in case of success -1 in case of error
2893 */
2894int
Daniel Veillard16756b62001-10-01 07:36:25 +00002895xmlLoadCatalog(const char *filename)
2896{
Daniel Veillard75b96822001-10-11 18:59:45 +00002897 int ret;
2898 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002899
Daniel Veillard81463942001-10-16 12:34:39 +00002900 if (!xmlCatalogInitialized)
2901 xmlInitializeCatalogData();
2902
2903 xmlRMutexLock(xmlCatalogMutex);
2904
Daniel Veillard75b96822001-10-11 18:59:45 +00002905 if (xmlDefaultCatalog == NULL) {
2906 catal = xmlLoadACatalog(filename);
2907 if (catal == NULL)
2908 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002909
Daniel Veillard75b96822001-10-11 18:59:45 +00002910 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002911 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002912 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002913 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002914
Daniel Veillard75b96822001-10-11 18:59:45 +00002915 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002916 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002917 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002918}
2919
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002920/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002921 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00002922 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00002923 *
2924 * Load the catalogs and makes their definitions effective for the default
2925 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002926 * this function is not thread safe, catalog initialization should
2927 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002928 */
2929void
2930xmlLoadCatalogs(const char *pathss) {
2931 const char *cur;
2932 const char *paths;
2933 xmlChar *path;
2934
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002935 if (pathss == NULL)
2936 return;
2937
Daniel Veillard81418e32001-05-22 15:08:55 +00002938 cur = pathss;
2939 while ((cur != NULL) && (*cur != 0)) {
2940 while (IS_BLANK(*cur)) cur++;
2941 if (*cur != 0) {
2942 paths = cur;
Igor Zlatkovicee1494a2002-10-31 16:15:29 +00002943 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00002944 cur++;
2945 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2946 if (path != NULL) {
2947 xmlLoadCatalog((const char *) path);
2948 xmlFree(path);
2949 }
2950 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00002951 while (*cur == ':')
2952 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00002953 }
2954}
2955
Daniel Veillarda7374592001-05-10 14:17:55 +00002956/**
2957 * xmlCatalogCleanup:
2958 *
2959 * Free up all the memory associated with catalogs
2960 */
2961void
2962xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00002963 if (xmlCatalogInitialized == 0)
2964 return;
2965
Daniel Veillard81463942001-10-16 12:34:39 +00002966 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002967 if (xmlDebugCatalogs)
2968 xmlGenericError(xmlGenericErrorContext,
2969 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002970 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002971 xmlHashFree(xmlCatalogXMLFiles,
2972 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002973 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002974 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002975 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002976 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002977 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002978 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00002979 xmlRMutexUnlock(xmlCatalogMutex);
2980 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00002981}
2982
2983/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002984 * xmlCatalogResolveSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00002985 * @sysID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002986 *
2987 * Try to lookup the catalog resource for a system ID
2988 *
2989 * Returns the system ID if found or NULL otherwise, the value returned
2990 * must be freed by the caller.
2991 */
2992xmlChar *
2993xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002994 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002995
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002996 if (!xmlCatalogInitialized)
2997 xmlInitializeCatalog();
2998
Daniel Veillard75b96822001-10-11 18:59:45 +00002999 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3000 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003001}
3002
3003/**
3004 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003005 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003006 *
3007 * Try to lookup the system ID associated to a public ID
3008 *
3009 * Returns the system ID if found or NULL otherwise, the value returned
3010 * must be freed by the caller.
3011 */
3012xmlChar *
3013xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003014 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003015
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003016 if (!xmlCatalogInitialized)
3017 xmlInitializeCatalog();
3018
Daniel Veillard75b96822001-10-11 18:59:45 +00003019 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3020 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003021}
Daniel Veillard344cee72001-08-20 00:08:40 +00003022
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003023/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003024 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003025 * @pubID: the public ID string
3026 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003027 *
3028 * Do a complete resolution lookup of an External Identifier
3029 *
3030 * Returns the URI of the resource or NULL if not found, it must be freed
3031 * by the caller.
3032 */
3033xmlChar *
3034xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003035 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003036
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003037 if (!xmlCatalogInitialized)
3038 xmlInitializeCatalog();
3039
Daniel Veillard75b96822001-10-11 18:59:45 +00003040 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3041 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003042}
3043
3044/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003045 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003046 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003047 *
3048 * Do a complete resolution lookup of an URI
3049 *
3050 * Returns the URI of the resource or NULL if not found, it must be freed
3051 * by the caller.
3052 */
3053xmlChar *
3054xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003055 xmlChar *ret;
3056
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003057 if (!xmlCatalogInitialized)
3058 xmlInitializeCatalog();
3059
Daniel Veillard75b96822001-10-11 18:59:45 +00003060 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3061 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003062}
3063
3064/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003065 * xmlCatalogDump:
3066 * @out: the file.
3067 *
3068 * Free up all the memory associated with catalogs
3069 */
3070void
3071xmlCatalogDump(FILE *out) {
3072 if (out == NULL)
3073 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003074
Daniel Veillard75b96822001-10-11 18:59:45 +00003075 if (!xmlCatalogInitialized)
3076 xmlInitializeCatalog();
3077
3078 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003079}
3080
3081/**
3082 * xmlCatalogAdd:
3083 * @type: the type of record to add to the catalog
3084 * @orig: the system, public or prefix to match
3085 * @replace: the replacement value for the match
3086 *
3087 * Add an entry in the catalog, it may overwrite existing but
3088 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003089 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003090 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003091 *
3092 * Returns 0 if successful, -1 otherwise
3093 */
3094int
3095xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3096 int res = -1;
3097
Daniel Veillard81463942001-10-16 12:34:39 +00003098 if (!xmlCatalogInitialized)
3099 xmlInitializeCatalogData();
3100
3101 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003102 /*
3103 * Specific case where one want to override the default catalog
3104 * put in place by xmlInitializeCatalog();
3105 */
3106 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003107 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003108 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003109 xmlCatalogDefaultPrefer);
3110 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003111 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003112
Daniel Veillard81463942001-10-16 12:34:39 +00003113 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003114 return(0);
3115 }
3116
Daniel Veillard75b96822001-10-11 18:59:45 +00003117 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003118 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003119 return(res);
3120}
3121
3122/**
3123 * xmlCatalogRemove:
3124 * @value: the value to remove
3125 *
3126 * Remove an entry from the catalog
3127 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003128 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003129 */
3130int
3131xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003132 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003133
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003134 if (!xmlCatalogInitialized)
3135 xmlInitializeCatalog();
3136
Daniel Veillard81463942001-10-16 12:34:39 +00003137 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003138 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003139 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003140 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003141}
3142
3143/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003144 * xmlCatalogConvert:
3145 *
3146 * Convert all the SGML catalog entries as XML ones
3147 *
3148 * Returns the number of entries converted if successful, -1 otherwise
3149 */
3150int
3151xmlCatalogConvert(void) {
3152 int res = -1;
3153
3154 if (!xmlCatalogInitialized)
3155 xmlInitializeCatalog();
3156
Daniel Veillard81463942001-10-16 12:34:39 +00003157 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003158 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003159 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003160 return(res);
3161}
3162
Daniel Veillard75b96822001-10-11 18:59:45 +00003163/************************************************************************
3164 * *
3165 * Public interface manipulating the common preferences *
3166 * *
3167 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003168
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003169/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003170 * xmlCatalogGetDefaults:
3171 *
3172 * Used to get the user preference w.r.t. to what catalogs should
3173 * be accepted
3174 *
3175 * Returns the current xmlCatalogAllow value
3176 */
3177xmlCatalogAllow
3178xmlCatalogGetDefaults(void) {
3179 return(xmlCatalogDefaultAllow);
3180}
3181
3182/**
3183 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003184 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003185 *
3186 * Used to set the user preference w.r.t. to what catalogs should
3187 * be accepted
3188 */
3189void
3190xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003191 if (xmlDebugCatalogs) {
3192 switch (allow) {
3193 case XML_CATA_ALLOW_NONE:
3194 xmlGenericError(xmlGenericErrorContext,
3195 "Disabling catalog usage\n");
3196 break;
3197 case XML_CATA_ALLOW_GLOBAL:
3198 xmlGenericError(xmlGenericErrorContext,
3199 "Allowing only global catalogs\n");
3200 break;
3201 case XML_CATA_ALLOW_DOCUMENT:
3202 xmlGenericError(xmlGenericErrorContext,
3203 "Allowing only catalogs from the document\n");
3204 break;
3205 case XML_CATA_ALLOW_ALL:
3206 xmlGenericError(xmlGenericErrorContext,
3207 "Allowing all catalogs\n");
3208 break;
3209 }
3210 }
3211 xmlCatalogDefaultAllow = allow;
3212}
3213
3214/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003215 * xmlCatalogSetDefaultPrefer:
3216 * @prefer: the default preference for delegation
3217 *
3218 * Allows to set the preference between public and system for deletion
3219 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003220 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003221 *
3222 * Returns the previous value of the default preference for delegation
3223 */
3224xmlCatalogPrefer
3225xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3226 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3227
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003228 if (prefer == XML_CATA_PREFER_NONE)
3229 return(ret);
3230
3231 if (xmlDebugCatalogs) {
3232 switch (prefer) {
3233 case XML_CATA_PREFER_PUBLIC:
3234 xmlGenericError(xmlGenericErrorContext,
3235 "Setting catalog preference to PUBLIC\n");
3236 break;
3237 case XML_CATA_PREFER_SYSTEM:
3238 xmlGenericError(xmlGenericErrorContext,
3239 "Setting catalog preference to SYSTEM\n");
3240 break;
3241 case XML_CATA_PREFER_NONE:
3242 break;
3243 }
3244 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003245 xmlCatalogDefaultPrefer = prefer;
3246 return(ret);
3247}
3248
3249/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003250 * xmlCatalogSetDebug:
3251 * @level: the debug level of catalogs required
3252 *
3253 * Used to set the debug level for catalog operation, 0 disable
3254 * debugging, 1 enable it
3255 *
3256 * Returns the previous value of the catalog debugging level
3257 */
3258int
3259xmlCatalogSetDebug(int level) {
3260 int ret = xmlDebugCatalogs;
3261
3262 if (level <= 0)
3263 xmlDebugCatalogs = 0;
3264 else
3265 xmlDebugCatalogs = level;
3266 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003267}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003268
Daniel Veillard75b96822001-10-11 18:59:45 +00003269/************************************************************************
3270 * *
3271 * Minimal interfaces used for per-document catalogs by the parser *
3272 * *
3273 ************************************************************************/
3274
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003275/**
3276 * xmlCatalogFreeLocal:
3277 * @catalogs: a document's list of catalogs
3278 *
3279 * Free up the memory associated to the catalog list
3280 */
3281void
3282xmlCatalogFreeLocal(void *catalogs) {
3283 xmlCatalogEntryPtr catal;
3284
Daniel Veillard81463942001-10-16 12:34:39 +00003285 if (!xmlCatalogInitialized)
3286 xmlInitializeCatalog();
3287
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003288 catal = (xmlCatalogEntryPtr) catalogs;
3289 if (catal != NULL)
3290 xmlFreeCatalogEntryList(catal);
3291}
3292
3293
3294/**
3295 * xmlCatalogAddLocal:
3296 * @catalogs: a document's list of catalogs
3297 * @URL: the URL to a new local catalog
3298 *
3299 * Add the new entry to the catalog list
3300 *
3301 * Returns the updated list
3302 */
3303void *
3304xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3305 xmlCatalogEntryPtr catal, add;
3306
3307 if (!xmlCatalogInitialized)
3308 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003309
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003310 if (URL == NULL)
3311 return(catalogs);
3312
3313 if (xmlDebugCatalogs)
3314 xmlGenericError(xmlGenericErrorContext,
3315 "Adding document catalog %s\n", URL);
3316
Daniel Veillardc853b322001-11-06 15:24:37 +00003317 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003318 xmlCatalogDefaultPrefer);
3319 if (add == NULL)
3320 return(catalogs);
3321
3322 catal = (xmlCatalogEntryPtr) catalogs;
3323 if (catal == NULL)
3324 return((void *) add);
3325
3326 while (catal->next != NULL)
3327 catal = catal->next;
3328 catal->next = add;
3329 return(catalogs);
3330}
3331
3332/**
3333 * xmlCatalogLocalResolve:
3334 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003335 * @pubID: the public ID string
3336 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003337 *
3338 * Do a complete resolution lookup of an External Identifier using a
3339 * document's private catalog list
3340 *
3341 * Returns the URI of the resource or NULL if not found, it must be freed
3342 * by the caller.
3343 */
3344xmlChar *
3345xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3346 const xmlChar *sysID) {
3347 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003348 xmlChar *ret;
3349
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003350 if (!xmlCatalogInitialized)
3351 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003352
Daniel Veillard81463942001-10-16 12:34:39 +00003353 if ((pubID == NULL) && (sysID == NULL))
3354 return(NULL);
3355
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003356 if (xmlDebugCatalogs) {
3357 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003358 xmlGenericError(xmlGenericErrorContext,
3359 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003360 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003361 xmlGenericError(xmlGenericErrorContext,
3362 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003363 }
3364 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003365
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003366 catal = (xmlCatalogEntryPtr) catalogs;
3367 if (catal == NULL)
3368 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003369 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3370 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3371 return(ret);
3372 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003373}
3374
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003375/**
3376 * xmlCatalogLocalResolveURI:
3377 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003378 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003379 *
3380 * Do a complete resolution lookup of an URI using a
3381 * document's private catalog list
3382 *
3383 * Returns the URI of the resource or NULL if not found, it must be freed
3384 * by the caller.
3385 */
3386xmlChar *
3387xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3388 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003389 xmlChar *ret;
3390
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003391 if (!xmlCatalogInitialized)
3392 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003393
Daniel Veillard81463942001-10-16 12:34:39 +00003394 if (URI == NULL)
3395 return(NULL);
3396
Daniel Veillard6990bf32001-08-23 21:17:48 +00003397 if (xmlDebugCatalogs)
3398 xmlGenericError(xmlGenericErrorContext,
3399 "Resolve URI %s\n", URI);
3400
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003401 catal = (xmlCatalogEntryPtr) catalogs;
3402 if (catal == NULL)
3403 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003404 ret = xmlCatalogListXMLResolveURI(catal, URI);
3405 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3406 return(ret);
3407 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003408}
3409
Daniel Veillard75b96822001-10-11 18:59:45 +00003410/************************************************************************
3411 * *
3412 * Deprecated interfaces *
3413 * *
3414 ************************************************************************/
3415/**
3416 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003417 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003418 *
3419 * Try to lookup the system ID associated to a public ID
3420 * DEPRECATED, use xmlCatalogResolveSystem()
3421 *
3422 * Returns the system ID if found or NULL otherwise.
3423 */
3424const xmlChar *
3425xmlCatalogGetSystem(const xmlChar *sysID) {
3426 xmlChar *ret;
3427 static xmlChar result[1000];
3428 static int msg = 0;
3429
Daniel Veillard81463942001-10-16 12:34:39 +00003430 if (!xmlCatalogInitialized)
3431 xmlInitializeCatalog();
3432
Daniel Veillard75b96822001-10-11 18:59:45 +00003433 if (msg == 0) {
3434 xmlGenericError(xmlGenericErrorContext,
3435 "Use of deprecated xmlCatalogGetSystem() call\n");
3436 msg++;
3437 }
3438
3439 if (sysID == NULL)
3440 return(NULL);
3441
Daniel Veillard75b96822001-10-11 18:59:45 +00003442 /*
3443 * Check first the XML catalogs
3444 */
3445 if (xmlDefaultCatalog != NULL) {
3446 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3447 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3448 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3449 result[sizeof(result) - 1] = 0;
3450 return(result);
3451 }
3452 }
3453
3454 if (xmlDefaultCatalog != NULL)
3455 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3456 return(NULL);
3457}
3458
3459/**
3460 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003461 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003462 *
3463 * Try to lookup the system ID associated to a public ID
3464 * DEPRECATED, use xmlCatalogResolvePublic()
3465 *
3466 * Returns the system ID if found or NULL otherwise.
3467 */
3468const xmlChar *
3469xmlCatalogGetPublic(const xmlChar *pubID) {
3470 xmlChar *ret;
3471 static xmlChar result[1000];
3472 static int msg = 0;
3473
Daniel Veillard81463942001-10-16 12:34:39 +00003474 if (!xmlCatalogInitialized)
3475 xmlInitializeCatalog();
3476
Daniel Veillard75b96822001-10-11 18:59:45 +00003477 if (msg == 0) {
3478 xmlGenericError(xmlGenericErrorContext,
3479 "Use of deprecated xmlCatalogGetPublic() call\n");
3480 msg++;
3481 }
3482
3483 if (pubID == NULL)
3484 return(NULL);
3485
Daniel Veillard75b96822001-10-11 18:59:45 +00003486 /*
3487 * Check first the XML catalogs
3488 */
3489 if (xmlDefaultCatalog != NULL) {
3490 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3491 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3492 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3493 result[sizeof(result) - 1] = 0;
3494 return(result);
3495 }
3496 }
3497
3498 if (xmlDefaultCatalog != NULL)
3499 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3500 return(NULL);
3501}
3502
Daniel Veillarda7374592001-05-10 14:17:55 +00003503#endif /* LIBXML_CATALOG_ENABLED */