blob: e0159e2b9fa98a2cb8e0a0b73da16223f8f6feea [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 Veillard7d6fd212001-05-10 15:34:11 +0000414 fprintf(out, "%s", 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) {
1708 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1709 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001710 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001711 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001712 break;
1713 if (i < nbList) {
1714 cur = cur->next;
1715 continue;
1716 }
1717 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001718 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001719
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001720 if (cur->children == NULL) {
1721 xmlFetchXMLCatalogFile(cur);
1722 }
1723 if (cur->children != NULL) {
1724 if (xmlDebugCatalogs)
1725 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001726 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001727 ret = xmlCatalogListXMLResolveURI(
1728 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001729 if (ret != NULL)
1730 return(ret);
1731 }
1732 }
1733 cur = cur->next;
1734 }
1735 /*
1736 * Apply the cut algorithm explained in 4/
1737 */
1738 return(XML_CATAL_BREAK);
1739 }
1740 if (haveNext) {
1741 cur = catal;
1742 while (cur != NULL) {
1743 if (cur->type == XML_CATA_NEXT_CATALOG) {
1744 if (cur->children == NULL) {
1745 xmlFetchXMLCatalogFile(cur);
1746 }
1747 if (cur->children != NULL) {
1748 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1749 if (ret != NULL)
1750 return(ret);
1751 }
1752 }
1753 cur = cur->next;
1754 }
1755 }
1756
1757 return(NULL);
1758}
1759
1760/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001761 * xmlCatalogListXMLResolve:
1762 * @catal: a catalog list
1763 * @pubId: the public ID string
1764 * @sysId: the system ID string
1765 *
1766 * Do a complete resolution lookup of an External Identifier for a
1767 * list of catalogs
1768 *
1769 * Implements (or tries to) 7.1. External Identifier Resolution
1770 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1771 *
1772 * Returns the URI of the resource or NULL if not found
1773 */
1774static xmlChar *
1775xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1776 const xmlChar *sysID) {
1777 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001778 xmlChar *urnID = NULL;
1779
1780 if (catal == NULL)
1781 return(NULL);
1782 if ((pubID == NULL) && (sysID == NULL))
1783 return(NULL);
1784
1785 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1786 urnID = xmlCatalogUnWrapURN(pubID);
1787 if (xmlDebugCatalogs) {
1788 if (urnID == NULL)
1789 xmlGenericError(xmlGenericErrorContext,
1790 "Public URN ID %s expanded to NULL\n", pubID);
1791 else
1792 xmlGenericError(xmlGenericErrorContext,
1793 "Public URN ID expanded to %s\n", urnID);
1794 }
1795 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1796 if (urnID != NULL)
1797 xmlFree(urnID);
1798 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001799 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001800 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1801 urnID = xmlCatalogUnWrapURN(sysID);
1802 if (xmlDebugCatalogs) {
1803 if (urnID == NULL)
1804 xmlGenericError(xmlGenericErrorContext,
1805 "System URN ID %s expanded to NULL\n", sysID);
1806 else
1807 xmlGenericError(xmlGenericErrorContext,
1808 "System URN ID expanded to %s\n", urnID);
1809 }
1810 if (pubID == NULL)
1811 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1812 else if (xmlStrEqual(pubID, urnID))
1813 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1814 else {
1815 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1816 }
1817 if (urnID != NULL)
1818 xmlFree(urnID);
1819 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001820 }
1821 while (catal != NULL) {
1822 if (catal->type == XML_CATA_CATALOG) {
1823 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001824 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001825 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001826 if (catal->children != NULL) {
1827 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1828 if (ret != NULL)
1829 return(ret);
1830 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001831 }
1832 catal = catal->next;
1833 }
1834 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001835}
1836
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001837/**
1838 * xmlCatalogListXMLResolveURI:
1839 * @catal: a catalog list
1840 * @URI: the URI
1841 *
1842 * Do a complete resolution lookup of an URI for a list of catalogs
1843 *
1844 * Implements (or tries to) 7.2. URI Resolution
1845 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1846 *
1847 * Returns the URI of the resource or NULL if not found
1848 */
1849static xmlChar *
1850xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1851 xmlChar *ret = NULL;
1852 xmlChar *urnID = NULL;
1853
1854 if (catal == NULL)
1855 return(NULL);
1856 if (URI == NULL)
1857 return(NULL);
1858
1859 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1860 urnID = xmlCatalogUnWrapURN(URI);
1861 if (xmlDebugCatalogs) {
1862 if (urnID == NULL)
1863 xmlGenericError(xmlGenericErrorContext,
1864 "URN ID %s expanded to NULL\n", URI);
1865 else
1866 xmlGenericError(xmlGenericErrorContext,
1867 "URN ID expanded to %s\n", urnID);
1868 }
1869 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1870 if (urnID != NULL)
1871 xmlFree(urnID);
1872 return(ret);
1873 }
1874 while (catal != NULL) {
1875 if (catal->type == XML_CATA_CATALOG) {
1876 if (catal->children == NULL) {
1877 xmlFetchXMLCatalogFile(catal);
1878 }
1879 if (catal->children != NULL) {
1880 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1881 if (ret != NULL)
1882 return(ret);
1883 }
1884 }
1885 catal = catal->next;
1886 }
1887 return(ret);
1888}
1889
Daniel Veillard344cee72001-08-20 00:08:40 +00001890/************************************************************************
1891 * *
1892 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001893 * *
1894 ************************************************************************/
1895
1896
1897#define RAW *cur
1898#define NEXT cur++;
1899#define SKIP(x) cur += x;
1900
1901#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1902
Daniel Veillard75b96822001-10-11 18:59:45 +00001903/**
1904 * xmlParseSGMLCatalogComment:
1905 * @cur: the current character
1906 *
1907 * Skip a comment in an SGML catalog
1908 *
1909 * Returns new current character
1910 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001911static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001912xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001913 if ((cur[0] != '-') || (cur[1] != '-'))
1914 return(cur);
1915 SKIP(2);
1916 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1917 NEXT;
1918 if (cur[0] == 0) {
1919 return(NULL);
1920 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001921 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001922}
1923
Daniel Veillard75b96822001-10-11 18:59:45 +00001924/**
1925 * xmlParseSGMLCatalogPubid:
1926 * @cur: the current character
1927 * @id: the return location
1928 *
1929 * Parse an SGML catalog ID
1930 *
1931 * Returns new current character and store the value in @id
1932 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001933static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001934xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001935 xmlChar *buf = NULL;
1936 int len = 0;
1937 int size = 50;
1938 xmlChar stop;
1939 int count = 0;
1940
1941 *id = NULL;
1942
1943 if (RAW == '"') {
1944 NEXT;
1945 stop = '"';
1946 } else if (RAW == '\'') {
1947 NEXT;
1948 stop = '\'';
1949 } else {
1950 stop = ' ';
1951 }
1952 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1953 if (buf == NULL) {
1954 xmlGenericError(xmlGenericErrorContext,
1955 "malloc of %d byte failed\n", size);
1956 return(NULL);
1957 }
Daniel Veillard935494a2002-10-22 14:22:46 +00001958 while (xmlIsPubidChar(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001959 if ((*cur == stop) && (stop != ' '))
1960 break;
1961 if ((stop == ' ') && (IS_BLANK(*cur)))
1962 break;
1963 if (len + 1 >= size) {
1964 size *= 2;
1965 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1966 if (buf == NULL) {
1967 xmlGenericError(xmlGenericErrorContext,
1968 "realloc of %d byte failed\n", size);
1969 return(NULL);
1970 }
1971 }
1972 buf[len++] = *cur;
1973 count++;
1974 NEXT;
1975 }
1976 buf[len] = 0;
1977 if (stop == ' ') {
1978 if (!IS_BLANK(*cur)) {
1979 xmlFree(buf);
1980 return(NULL);
1981 }
1982 } else {
1983 if (*cur != stop) {
1984 xmlFree(buf);
1985 return(NULL);
1986 }
1987 NEXT;
1988 }
1989 *id = buf;
1990 return(cur);
1991}
1992
Daniel Veillard75b96822001-10-11 18:59:45 +00001993/**
1994 * xmlParseSGMLCatalogName:
1995 * @cur: the current character
1996 * @name: the return location
1997 *
1998 * Parse an SGML catalog name
1999 *
2000 * Returns new current character and store the value in @name
2001 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002002static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002003xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002004 xmlChar buf[XML_MAX_NAMELEN + 5];
2005 int len = 0;
2006 int c;
2007
2008 *name = NULL;
2009
2010 /*
2011 * Handler for more complex cases
2012 */
2013 c = *cur;
2014 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2015 return(NULL);
2016 }
2017
2018 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2019 (c == '.') || (c == '-') ||
2020 (c == '_') || (c == ':'))) {
2021 buf[len++] = c;
2022 cur++;
2023 c = *cur;
2024 if (len >= XML_MAX_NAMELEN)
2025 return(NULL);
2026 }
2027 *name = xmlStrndup(buf, len);
2028 return(cur);
2029}
2030
Daniel Veillard75b96822001-10-11 18:59:45 +00002031/**
2032 * xmlGetSGMLCatalogEntryType:
2033 * @name: the entry name
2034 *
2035 * Get the Catalog entry type for a given SGML Catalog name
2036 *
2037 * Returns Catalog entry type
2038 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002039static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002040xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002041 xmlCatalogEntryType type = XML_CATA_NONE;
2042 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2043 type = SGML_CATA_SYSTEM;
2044 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2045 type = SGML_CATA_PUBLIC;
2046 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2047 type = SGML_CATA_DELEGATE;
2048 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2049 type = SGML_CATA_ENTITY;
2050 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2051 type = SGML_CATA_DOCTYPE;
2052 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2053 type = SGML_CATA_LINKTYPE;
2054 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2055 type = SGML_CATA_NOTATION;
2056 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2057 type = SGML_CATA_SGMLDECL;
2058 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2059 type = SGML_CATA_DOCUMENT;
2060 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2061 type = SGML_CATA_CATALOG;
2062 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2063 type = SGML_CATA_BASE;
2064 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2065 type = SGML_CATA_DELEGATE;
2066 return(type);
2067}
2068
Daniel Veillard75b96822001-10-11 18:59:45 +00002069/**
2070 * xmlParseSGMLCatalog:
2071 * @catal: the SGML Catalog
2072 * @value: the content of the SGML Catalog serialization
2073 * @file: the filepath for the catalog
2074 * @super: should this be handled as a Super Catalog in which case
2075 * parsing is not recursive
2076 *
2077 * Parse an SGML catalog content and fill up the @catal hash table with
2078 * the new entries found.
2079 *
2080 * Returns 0 in case of success, -1 in case of error.
2081 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002082static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002083xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2084 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002085 const xmlChar *cur = value;
2086 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002087 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002088
2089 if ((cur == NULL) || (file == NULL))
2090 return(-1);
2091 base = xmlStrdup((const xmlChar *) file);
2092
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002093 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002094 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002095 if (cur[0] == 0)
2096 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002097 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002098 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002099 if (cur == NULL) {
2100 /* error */
2101 break;
2102 }
2103 } else {
2104 xmlChar *sysid = NULL;
2105 xmlChar *name = NULL;
2106 xmlCatalogEntryType type = XML_CATA_NONE;
2107
Daniel Veillardcda96922001-08-21 10:56:31 +00002108 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002109 if (name == NULL) {
2110 /* error */
2111 break;
2112 }
2113 if (!IS_BLANK(*cur)) {
2114 /* error */
2115 break;
2116 }
2117 SKIP_BLANKS;
2118 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002119 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002120 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002121 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002122 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002123 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002124 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002125 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002126 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002127 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002128 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002129 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002130 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002131 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002132 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002133 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002134 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002135 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002136 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002137 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002138 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002139 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002140 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002141 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002142 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2143 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002144 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002145 if (name == NULL) {
2146 /* error */
2147 break;
2148 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002149 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002150 continue;
2151 }
2152 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002153 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002154
2155 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002156 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002157 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002158 type = SGML_CATA_PENTITY;
2159 case SGML_CATA_PENTITY:
2160 case SGML_CATA_DOCTYPE:
2161 case SGML_CATA_LINKTYPE:
2162 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002163 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002164 if (cur == NULL) {
2165 /* error */
2166 break;
2167 }
2168 if (!IS_BLANK(*cur)) {
2169 /* error */
2170 break;
2171 }
2172 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002173 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002174 if (cur == NULL) {
2175 /* error */
2176 break;
2177 }
2178 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002179 case SGML_CATA_PUBLIC:
2180 case SGML_CATA_SYSTEM:
2181 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002182 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002183 if (cur == NULL) {
2184 /* error */
2185 break;
2186 }
2187 if (!IS_BLANK(*cur)) {
2188 /* error */
2189 break;
2190 }
2191 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002192 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002193 if (cur == NULL) {
2194 /* error */
2195 break;
2196 }
2197 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002198 case SGML_CATA_BASE:
2199 case SGML_CATA_CATALOG:
2200 case SGML_CATA_DOCUMENT:
2201 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002202 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002203 if (cur == NULL) {
2204 /* error */
2205 break;
2206 }
2207 break;
2208 default:
2209 break;
2210 }
2211 if (cur == NULL) {
2212 if (name != NULL)
2213 xmlFree(name);
2214 if (sysid != NULL)
2215 xmlFree(sysid);
2216 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002217 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002218 if (base != NULL)
2219 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002220 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002221 } else if ((type == SGML_CATA_PUBLIC) ||
2222 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002223 xmlChar *filename;
2224
2225 filename = xmlBuildURI(sysid, base);
2226 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002227 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002228
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002229 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002230 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002231 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002232 if (res < 0) {
2233 xmlFreeCatalogEntry(entry);
2234 }
2235 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002236 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002237
Daniel Veillard344cee72001-08-20 00:08:40 +00002238 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002239 if (super) {
2240 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002241
Daniel Veillardc853b322001-11-06 15:24:37 +00002242 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002243 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002244 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002245 if (res < 0) {
2246 xmlFreeCatalogEntry(entry);
2247 }
2248 } else {
2249 xmlChar *filename;
2250
2251 filename = xmlBuildURI(sysid, base);
2252 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002253 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002254 xmlFree(filename);
2255 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002256 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002257 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002258 /*
2259 * drop anything else we won't handle it
2260 */
2261 if (name != NULL)
2262 xmlFree(name);
2263 if (sysid != NULL)
2264 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002265 }
2266 }
2267 if (base != NULL)
2268 xmlFree(base);
2269 if (cur == NULL)
2270 return(-1);
2271 return(0);
2272}
2273
Daniel Veillard75b96822001-10-11 18:59:45 +00002274/************************************************************************
2275 * *
2276 * SGML Catalog handling *
2277 * *
2278 ************************************************************************/
2279
Daniel Veillardcda96922001-08-21 10:56:31 +00002280/**
2281 * xmlCatalogGetSGMLPublic:
2282 * @catal: an SGML catalog hash
2283 * @pubId: the public ID string
2284 *
2285 * Try to lookup the system ID associated to a public ID
2286 *
2287 * Returns the system ID if found or NULL otherwise.
2288 */
2289static const xmlChar *
2290xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2291 xmlCatalogEntryPtr entry;
2292
2293 if (catal == NULL)
2294 return(NULL);
2295
2296 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2297 if (entry == NULL)
2298 return(NULL);
2299 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillardc853b322001-11-06 15:24:37 +00002300 return(entry->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002301 return(NULL);
2302}
2303
2304/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002305 * xmlCatalogGetSGMLSystem:
2306 * @catal: an SGML catalog hash
2307 * @sysId: the public ID string
2308 *
2309 * Try to lookup the catalog local reference for a system ID
2310 *
2311 * Returns the system ID if found or NULL otherwise.
2312 */
2313static const xmlChar *
2314xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2315 xmlCatalogEntryPtr entry;
2316
2317 if (catal == NULL)
2318 return(NULL);
2319
2320 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2321 if (entry == NULL)
2322 return(NULL);
2323 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002324 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002325 return(NULL);
2326}
2327
2328/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002329 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002330 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002331 * @pubId: the public ID string
2332 * @sysId: the system ID string
2333 *
2334 * Do a complete resolution lookup of an External Identifier
2335 *
2336 * Returns the URI of the resource or NULL if not found
2337 */
2338static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002339xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2340 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002341 const xmlChar *ret = NULL;
2342
Daniel Veillard75b96822001-10-11 18:59:45 +00002343 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002344 return(NULL);
2345
2346 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002347 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002348 if (ret != NULL)
2349 return(ret);
2350 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002351 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002352 return(NULL);
2353}
2354
Daniel Veillarda7374592001-05-10 14:17:55 +00002355/************************************************************************
2356 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002357 * Specific Public interfaces *
2358 * *
2359 ************************************************************************/
2360
2361/**
2362 * xmlLoadSGMLSuperCatalog:
2363 * @filename: a file path
2364 *
2365 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2366 * references. This is only needed for manipulating SGML Super Catalogs
2367 * like adding and removing CATALOG or DELEGATE entries.
2368 *
2369 * Returns the catalog parsed or NULL in case of error
2370 */
2371xmlCatalogPtr
2372xmlLoadSGMLSuperCatalog(const char *filename)
2373{
2374 xmlChar *content;
2375 xmlCatalogPtr catal;
2376 int ret;
2377
2378 content = xmlLoadFileContent(filename);
2379 if (content == NULL)
2380 return(NULL);
2381
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002382 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002383 if (catal == NULL) {
2384 xmlFree(content);
2385 return(NULL);
2386 }
2387
2388 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2389 xmlFree(content);
2390 if (ret < 0) {
2391 xmlFreeCatalog(catal);
2392 return(NULL);
2393 }
2394 return (catal);
2395}
2396
2397/**
2398 * xmlLoadACatalog:
2399 * @filename: a file path
2400 *
2401 * Load the catalog and build the associated data structures.
2402 * This can be either an XML Catalog or an SGML Catalog
2403 * It will recurse in SGML CATALOG entries. On the other hand XML
2404 * Catalogs are not handled recursively.
2405 *
2406 * Returns the catalog parsed or NULL in case of error
2407 */
2408xmlCatalogPtr
2409xmlLoadACatalog(const char *filename)
2410{
2411 xmlChar *content;
2412 xmlChar *first;
2413 xmlCatalogPtr catal;
2414 int ret;
2415
2416 content = xmlLoadFileContent(filename);
2417 if (content == NULL)
2418 return(NULL);
2419
2420
2421 first = content;
2422
2423 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2424 (!(((*first >= 'A') && (*first <= 'Z')) ||
2425 ((*first >= 'a') && (*first <= 'z')))))
2426 first++;
2427
2428 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002429 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002430 if (catal == NULL) {
2431 xmlFree(content);
2432 return(NULL);
2433 }
2434 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2435 if (ret < 0) {
2436 xmlFreeCatalog(catal);
2437 xmlFree(content);
2438 return(NULL);
2439 }
2440 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002441 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002442 if (catal == NULL) {
2443 xmlFree(content);
2444 return(NULL);
2445 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002446 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002447 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002448 }
2449 xmlFree(content);
2450 return (catal);
2451}
2452
2453/**
2454 * xmlExpandCatalog:
2455 * @catal: a catalog
2456 * @filename: a file path
2457 *
2458 * Load the catalog and expand the existing catal structure.
2459 * This can be either an XML Catalog or an SGML Catalog
2460 *
2461 * Returns 0 in case of success, -1 in case of error
2462 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002463static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002464xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2465{
Daniel Veillard75b96822001-10-11 18:59:45 +00002466 int ret;
2467
2468 if ((catal == NULL) || (filename == NULL))
2469 return(-1);
2470
Daniel Veillard75b96822001-10-11 18:59:45 +00002471
2472 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002473 xmlChar *content;
2474
2475 content = xmlLoadFileContent(filename);
2476 if (content == NULL)
2477 return(-1);
2478
Daniel Veillard75b96822001-10-11 18:59:45 +00002479 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2480 if (ret < 0) {
2481 xmlFree(content);
2482 return(-1);
2483 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002484 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002485 } else {
2486 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002487 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002488 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002489
Daniel Veillard75b96822001-10-11 18:59:45 +00002490 cur = catal->xml;
2491 if (cur == NULL) {
2492 catal->xml = tmp;
2493 } else {
2494 while (cur->next != NULL) cur = cur->next;
2495 cur->next = tmp;
2496 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002497 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002498 return (0);
2499}
2500
2501/**
2502 * xmlACatalogResolveSystem:
2503 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002504 * @sysID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002505 *
2506 * Try to lookup the catalog resource for a system ID
2507 *
2508 * Returns the system ID if found or NULL otherwise, the value returned
2509 * must be freed by the caller.
2510 */
2511xmlChar *
2512xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2513 xmlChar *ret = NULL;
2514
2515 if ((sysID == NULL) || (catal == NULL))
2516 return(NULL);
2517
2518 if (xmlDebugCatalogs)
2519 xmlGenericError(xmlGenericErrorContext,
2520 "Resolve sysID %s\n", sysID);
2521
2522 if (catal->type == XML_XML_CATALOG_TYPE) {
2523 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2524 if (ret == XML_CATAL_BREAK)
2525 ret = NULL;
2526 } else {
2527 const xmlChar *sgml;
2528
2529 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2530 if (sgml != NULL)
2531 ret = xmlStrdup(sgml);
2532 }
2533 return(ret);
2534}
2535
2536/**
2537 * xmlACatalogResolvePublic:
2538 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002539 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002540 *
2541 * Try to lookup the system ID associated to a public ID in that catalog
2542 *
2543 * Returns the system ID if found or NULL otherwise, the value returned
2544 * must be freed by the caller.
2545 */
2546xmlChar *
2547xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2548 xmlChar *ret = NULL;
2549
2550 if ((pubID == NULL) || (catal == NULL))
2551 return(NULL);
2552
2553 if (xmlDebugCatalogs)
2554 xmlGenericError(xmlGenericErrorContext,
2555 "Resolve pubID %s\n", pubID);
2556
2557 if (catal->type == XML_XML_CATALOG_TYPE) {
2558 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2559 if (ret == XML_CATAL_BREAK)
2560 ret = NULL;
2561 } else {
2562 const xmlChar *sgml;
2563
2564 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2565 if (sgml != NULL)
2566 ret = xmlStrdup(sgml);
2567 }
2568 return(ret);
2569}
2570
2571/**
2572 * xmlACatalogResolve:
2573 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002574 * @pubID: the public ID string
2575 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002576 *
2577 * Do a complete resolution lookup of an External Identifier
2578 *
2579 * Returns the URI of the resource or NULL if not found, it must be freed
2580 * by the caller.
2581 */
2582xmlChar *
2583xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2584 const xmlChar * sysID)
2585{
2586 xmlChar *ret = NULL;
2587
2588 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2589 return (NULL);
2590
2591 if (xmlDebugCatalogs) {
2592 if (pubID != NULL) {
2593 xmlGenericError(xmlGenericErrorContext,
2594 "Resolve: pubID %s\n", pubID);
2595 } else {
2596 xmlGenericError(xmlGenericErrorContext,
2597 "Resolve: sysID %s\n", sysID);
2598 }
2599 }
2600
2601 if (catal->type == XML_XML_CATALOG_TYPE) {
2602 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2603 if (ret == XML_CATAL_BREAK)
2604 ret = NULL;
2605 } else {
2606 const xmlChar *sgml;
2607
2608 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2609 if (sgml != NULL)
2610 ret = xmlStrdup(sgml);
2611 }
2612 return (ret);
2613}
2614
2615/**
2616 * xmlACatalogResolveURI:
2617 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002618 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002619 *
2620 * Do a complete resolution lookup of an URI
2621 *
2622 * Returns the URI of the resource or NULL if not found, it must be freed
2623 * by the caller.
2624 */
2625xmlChar *
2626xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2627 xmlChar *ret = NULL;
2628
2629 if ((URI == NULL) || (catal == NULL))
2630 return(NULL);
2631
Daniel Veillardb44025c2001-10-11 22:55:55 +00002632 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002633 xmlGenericError(xmlGenericErrorContext,
2634 "Resolve URI %s\n", URI);
2635
2636 if (catal->type == XML_XML_CATALOG_TYPE) {
2637 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2638 if (ret == XML_CATAL_BREAK)
2639 ret = NULL;
2640 } else {
2641 const xmlChar *sgml;
2642
2643 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2644 if (sgml != NULL)
2645 sgml = xmlStrdup(sgml);
2646 }
2647 return(ret);
2648}
2649
2650/**
2651 * xmlACatalogDump:
2652 * @catal: a Catalog
2653 * @out: the file.
2654 *
2655 * Free up all the memory associated with catalogs
2656 */
2657void
2658xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002659 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002660 return;
2661
2662 if (catal->type == XML_XML_CATALOG_TYPE) {
2663 xmlDumpXMLCatalog(out, catal->xml);
2664 } else {
2665 xmlHashScan(catal->sgml,
2666 (xmlHashScanner) xmlCatalogDumpEntry, out);
2667 }
2668}
2669
2670/**
2671 * xmlACatalogAdd:
2672 * @catal: a Catalog
2673 * @type: the type of record to add to the catalog
2674 * @orig: the system, public or prefix to match
2675 * @replace: the replacement value for the match
2676 *
2677 * Add an entry in the catalog, it may overwrite existing but
2678 * different entries.
2679 *
2680 * Returns 0 if successful, -1 otherwise
2681 */
2682int
2683xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2684 const xmlChar * orig, const xmlChar * replace)
2685{
2686 int res = -1;
2687
2688 if (catal == NULL)
2689 return(-1);
2690
2691 if (catal->type == XML_XML_CATALOG_TYPE) {
2692 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2693 } else {
2694 xmlCatalogEntryType cattype;
2695
2696 cattype = xmlGetSGMLCatalogEntryType(type);
2697 if (cattype != XML_CATA_NONE) {
2698 xmlCatalogEntryPtr entry;
2699
Daniel Veillardc853b322001-11-06 15:24:37 +00002700 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002701 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002702 if (catal->sgml == NULL)
2703 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002704 res = xmlHashAddEntry(catal->sgml, orig, entry);
2705 }
2706 }
2707 return (res);
2708}
2709
2710/**
2711 * xmlACatalogRemove:
2712 * @catal: a Catalog
2713 * @value: the value to remove
2714 *
2715 * Remove an entry from the catalog
2716 *
2717 * Returns the number of entries removed if successful, -1 otherwise
2718 */
2719int
2720xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2721 int res = -1;
2722
2723 if ((catal == NULL) || (value == NULL))
2724 return(-1);
2725
2726 if (catal->type == XML_XML_CATALOG_TYPE) {
2727 res = xmlDelXMLCatalog(catal->xml, value);
2728 } else {
2729 res = xmlHashRemoveEntry(catal->sgml, value,
2730 (xmlHashDeallocator) xmlFreeCatalogEntry);
2731 if (res == 0)
2732 res = 1;
2733 }
2734 return(res);
2735}
2736
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002737/**
2738 * xmlNewCatalog:
2739 * @sgml: should this create an SGML catalog
2740 *
2741 * create a new Catalog.
2742 *
2743 * Returns the xmlCatalogPtr or NULL in case of error
2744 */
2745xmlCatalogPtr
2746xmlNewCatalog(int sgml) {
2747 xmlCatalogPtr catal = NULL;
2748
2749 if (sgml) {
2750 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2751 xmlCatalogDefaultPrefer);
2752 if ((catal != NULL) && (catal->sgml == NULL))
2753 catal->sgml = xmlHashCreate(10);
2754 } else
2755 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2756 xmlCatalogDefaultPrefer);
2757 return(catal);
2758}
2759
2760/**
2761 * xmlCatalogIsEmpty:
2762 * @catal: should this create an SGML catalog
2763 *
2764 * Check is a catalog is empty
2765 *
2766 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2767 */
2768int
2769xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2770 if (catal == NULL)
2771 return(-1);
2772
2773 if (catal->type == XML_XML_CATALOG_TYPE) {
2774 if (catal->xml == NULL)
2775 return(1);
2776 if ((catal->xml->type != XML_CATA_CATALOG) &&
2777 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2778 return(-1);
2779 if (catal->xml->children == NULL)
2780 return(1);
2781 return(0);
2782 } else {
2783 int res;
2784
2785 if (catal->sgml == NULL)
2786 return(1);
2787 res = xmlHashSize(catal->sgml);
2788 if (res == 0)
2789 return(1);
2790 if (res < 0)
2791 return(-1);
2792 }
2793 return(0);
2794}
2795
Daniel Veillard75b96822001-10-11 18:59:45 +00002796/************************************************************************
2797 * *
2798 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002799 * *
2800 ************************************************************************/
2801
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002802/**
Daniel Veillard81463942001-10-16 12:34:39 +00002803 * xmlInitializeCatalogData:
2804 *
2805 * Do the catalog initialization only of global data, doesn't try to load
2806 * any catalog actually.
2807 * this function is not thread safe, catalog initialization should
2808 * preferably be done once at startup
2809 */
2810static void
2811xmlInitializeCatalogData(void) {
2812 if (xmlCatalogInitialized != 0)
2813 return;
2814
2815 if (getenv("XML_DEBUG_CATALOG"))
2816 xmlDebugCatalogs = 1;
2817 xmlCatalogMutex = xmlNewRMutex();
2818
2819 xmlCatalogInitialized = 1;
2820}
2821/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002822 * xmlInitializeCatalog:
2823 *
2824 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002825 * this function is not thread safe, catalog initialization should
2826 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002827 */
2828void
2829xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002830 if (xmlCatalogInitialized != 0)
2831 return;
2832
Daniel Veillard81463942001-10-16 12:34:39 +00002833 xmlInitializeCatalogData();
2834 xmlRMutexLock(xmlCatalogMutex);
2835
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002836 if (getenv("XML_DEBUG_CATALOG"))
2837 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002838
Daniel Veillard75b96822001-10-11 18:59:45 +00002839 if (xmlDefaultCatalog == NULL) {
2840 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002841 char *path;
2842 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00002843 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002844 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00002845
Daniel Veillardb44025c2001-10-11 22:55:55 +00002846 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002847 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002848 catalogs = XML_XML_DEFAULT_CATALOG;
2849
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002850 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2851 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002852 if (catal != NULL) {
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002853 /* the XML_CATALOG_FILES envvar is allowed to contain a
2854 space-separated list of entries. */
2855 cur = catalogs;
2856 nextent = &catal->xml;
2857 while (*cur != '\0') {
2858 while (IS_BLANK(*cur))
2859 cur++;
2860 if (*cur != 0) {
2861 paths = cur;
2862 while ((*cur != 0) && (!IS_BLANK(*cur)))
2863 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00002864 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00002865 if (path != NULL) {
2866 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2867 NULL, BAD_CAST path, xmlCatalogDefaultPrefer);
2868 if (*nextent != NULL)
2869 nextent = &((*nextent)->next);
2870 xmlFree(path);
2871 }
2872 }
2873 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002874 xmlDefaultCatalog = catal;
2875 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002876 }
2877
Daniel Veillard81463942001-10-16 12:34:39 +00002878 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002879}
2880
Daniel Veillard82d75332001-10-08 15:01:59 +00002881
2882/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002883 * xmlLoadCatalog:
2884 * @filename: a file path
2885 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002886 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002887 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002888 * this function is not thread safe, catalog initialization should
2889 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002890 *
2891 * Returns 0 in case of success -1 in case of error
2892 */
2893int
Daniel Veillard16756b62001-10-01 07:36:25 +00002894xmlLoadCatalog(const char *filename)
2895{
Daniel Veillard75b96822001-10-11 18:59:45 +00002896 int ret;
2897 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002898
Daniel Veillard81463942001-10-16 12:34:39 +00002899 if (!xmlCatalogInitialized)
2900 xmlInitializeCatalogData();
2901
2902 xmlRMutexLock(xmlCatalogMutex);
2903
Daniel Veillard75b96822001-10-11 18:59:45 +00002904 if (xmlDefaultCatalog == NULL) {
2905 catal = xmlLoadACatalog(filename);
2906 if (catal == NULL)
2907 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002908
Daniel Veillard75b96822001-10-11 18:59:45 +00002909 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002910 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002911 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002912 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002913
Daniel Veillard75b96822001-10-11 18:59:45 +00002914 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002915 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002916 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002917}
2918
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002919/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002920 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00002921 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00002922 *
2923 * Load the catalogs and makes their definitions effective for the default
2924 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002925 * this function is not thread safe, catalog initialization should
2926 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002927 */
2928void
2929xmlLoadCatalogs(const char *pathss) {
2930 const char *cur;
2931 const char *paths;
2932 xmlChar *path;
2933
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002934 if (pathss == NULL)
2935 return;
2936
Daniel Veillard81418e32001-05-22 15:08:55 +00002937 cur = pathss;
2938 while ((cur != NULL) && (*cur != 0)) {
2939 while (IS_BLANK(*cur)) cur++;
2940 if (*cur != 0) {
2941 paths = cur;
Igor Zlatkovicee1494a2002-10-31 16:15:29 +00002942 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00002943 cur++;
2944 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2945 if (path != NULL) {
2946 xmlLoadCatalog((const char *) path);
2947 xmlFree(path);
2948 }
2949 }
Igor Zlatkovic130e5792002-11-06 22:51:58 +00002950 while (*cur == ':')
2951 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00002952 }
2953}
2954
Daniel Veillarda7374592001-05-10 14:17:55 +00002955/**
2956 * xmlCatalogCleanup:
2957 *
2958 * Free up all the memory associated with catalogs
2959 */
2960void
2961xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00002962 if (xmlCatalogInitialized == 0)
2963 return;
2964
Daniel Veillard81463942001-10-16 12:34:39 +00002965 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002966 if (xmlDebugCatalogs)
2967 xmlGenericError(xmlGenericErrorContext,
2968 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002969 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002970 xmlHashFree(xmlCatalogXMLFiles,
2971 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002972 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002973 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002974 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002975 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002976 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002977 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00002978 xmlRMutexUnlock(xmlCatalogMutex);
2979 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00002980}
2981
2982/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002983 * xmlCatalogResolveSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00002984 * @sysID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002985 *
2986 * Try to lookup the catalog resource for a system ID
2987 *
2988 * Returns the system ID if found or NULL otherwise, the value returned
2989 * must be freed by the caller.
2990 */
2991xmlChar *
2992xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002993 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002994
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002995 if (!xmlCatalogInitialized)
2996 xmlInitializeCatalog();
2997
Daniel Veillard75b96822001-10-11 18:59:45 +00002998 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
2999 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003000}
3001
3002/**
3003 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003004 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003005 *
3006 * Try to lookup the system ID associated to a public ID
3007 *
3008 * Returns the system ID if found or NULL otherwise, the value returned
3009 * must be freed by the caller.
3010 */
3011xmlChar *
3012xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003013 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003014
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003015 if (!xmlCatalogInitialized)
3016 xmlInitializeCatalog();
3017
Daniel Veillard75b96822001-10-11 18:59:45 +00003018 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3019 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003020}
Daniel Veillard344cee72001-08-20 00:08:40 +00003021
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003022/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003023 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003024 * @pubID: the public ID string
3025 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003026 *
3027 * Do a complete resolution lookup of an External Identifier
3028 *
3029 * Returns the URI of the resource or NULL if not found, it must be freed
3030 * by the caller.
3031 */
3032xmlChar *
3033xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003034 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003035
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003036 if (!xmlCatalogInitialized)
3037 xmlInitializeCatalog();
3038
Daniel Veillard75b96822001-10-11 18:59:45 +00003039 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3040 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003041}
3042
3043/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003044 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003045 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003046 *
3047 * Do a complete resolution lookup of an URI
3048 *
3049 * Returns the URI of the resource or NULL if not found, it must be freed
3050 * by the caller.
3051 */
3052xmlChar *
3053xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003054 xmlChar *ret;
3055
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003056 if (!xmlCatalogInitialized)
3057 xmlInitializeCatalog();
3058
Daniel Veillard75b96822001-10-11 18:59:45 +00003059 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3060 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003061}
3062
3063/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003064 * xmlCatalogDump:
3065 * @out: the file.
3066 *
3067 * Free up all the memory associated with catalogs
3068 */
3069void
3070xmlCatalogDump(FILE *out) {
3071 if (out == NULL)
3072 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003073
Daniel Veillard75b96822001-10-11 18:59:45 +00003074 if (!xmlCatalogInitialized)
3075 xmlInitializeCatalog();
3076
3077 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003078}
3079
3080/**
3081 * xmlCatalogAdd:
3082 * @type: the type of record to add to the catalog
3083 * @orig: the system, public or prefix to match
3084 * @replace: the replacement value for the match
3085 *
3086 * Add an entry in the catalog, it may overwrite existing but
3087 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003088 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003089 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003090 *
3091 * Returns 0 if successful, -1 otherwise
3092 */
3093int
3094xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3095 int res = -1;
3096
Daniel Veillard81463942001-10-16 12:34:39 +00003097 if (!xmlCatalogInitialized)
3098 xmlInitializeCatalogData();
3099
3100 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003101 /*
3102 * Specific case where one want to override the default catalog
3103 * put in place by xmlInitializeCatalog();
3104 */
3105 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003106 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003107 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003108 xmlCatalogDefaultPrefer);
3109 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003110 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003111
Daniel Veillard81463942001-10-16 12:34:39 +00003112 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003113 return(0);
3114 }
3115
Daniel Veillard75b96822001-10-11 18:59:45 +00003116 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003117 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003118 return(res);
3119}
3120
3121/**
3122 * xmlCatalogRemove:
3123 * @value: the value to remove
3124 *
3125 * Remove an entry from the catalog
3126 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003127 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003128 */
3129int
3130xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003131 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003132
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003133 if (!xmlCatalogInitialized)
3134 xmlInitializeCatalog();
3135
Daniel Veillard81463942001-10-16 12:34:39 +00003136 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003137 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003138 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003139 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003140}
3141
3142/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003143 * xmlCatalogConvert:
3144 *
3145 * Convert all the SGML catalog entries as XML ones
3146 *
3147 * Returns the number of entries converted if successful, -1 otherwise
3148 */
3149int
3150xmlCatalogConvert(void) {
3151 int res = -1;
3152
3153 if (!xmlCatalogInitialized)
3154 xmlInitializeCatalog();
3155
Daniel Veillard81463942001-10-16 12:34:39 +00003156 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003157 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003158 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003159 return(res);
3160}
3161
Daniel Veillard75b96822001-10-11 18:59:45 +00003162/************************************************************************
3163 * *
3164 * Public interface manipulating the common preferences *
3165 * *
3166 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003167
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003168/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003169 * xmlCatalogGetDefaults:
3170 *
3171 * Used to get the user preference w.r.t. to what catalogs should
3172 * be accepted
3173 *
3174 * Returns the current xmlCatalogAllow value
3175 */
3176xmlCatalogAllow
3177xmlCatalogGetDefaults(void) {
3178 return(xmlCatalogDefaultAllow);
3179}
3180
3181/**
3182 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003183 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003184 *
3185 * Used to set the user preference w.r.t. to what catalogs should
3186 * be accepted
3187 */
3188void
3189xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003190 if (xmlDebugCatalogs) {
3191 switch (allow) {
3192 case XML_CATA_ALLOW_NONE:
3193 xmlGenericError(xmlGenericErrorContext,
3194 "Disabling catalog usage\n");
3195 break;
3196 case XML_CATA_ALLOW_GLOBAL:
3197 xmlGenericError(xmlGenericErrorContext,
3198 "Allowing only global catalogs\n");
3199 break;
3200 case XML_CATA_ALLOW_DOCUMENT:
3201 xmlGenericError(xmlGenericErrorContext,
3202 "Allowing only catalogs from the document\n");
3203 break;
3204 case XML_CATA_ALLOW_ALL:
3205 xmlGenericError(xmlGenericErrorContext,
3206 "Allowing all catalogs\n");
3207 break;
3208 }
3209 }
3210 xmlCatalogDefaultAllow = allow;
3211}
3212
3213/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003214 * xmlCatalogSetDefaultPrefer:
3215 * @prefer: the default preference for delegation
3216 *
3217 * Allows to set the preference between public and system for deletion
3218 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003219 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003220 *
3221 * Returns the previous value of the default preference for delegation
3222 */
3223xmlCatalogPrefer
3224xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3225 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3226
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003227 if (prefer == XML_CATA_PREFER_NONE)
3228 return(ret);
3229
3230 if (xmlDebugCatalogs) {
3231 switch (prefer) {
3232 case XML_CATA_PREFER_PUBLIC:
3233 xmlGenericError(xmlGenericErrorContext,
3234 "Setting catalog preference to PUBLIC\n");
3235 break;
3236 case XML_CATA_PREFER_SYSTEM:
3237 xmlGenericError(xmlGenericErrorContext,
3238 "Setting catalog preference to SYSTEM\n");
3239 break;
3240 case XML_CATA_PREFER_NONE:
3241 break;
3242 }
3243 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003244 xmlCatalogDefaultPrefer = prefer;
3245 return(ret);
3246}
3247
3248/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003249 * xmlCatalogSetDebug:
3250 * @level: the debug level of catalogs required
3251 *
3252 * Used to set the debug level for catalog operation, 0 disable
3253 * debugging, 1 enable it
3254 *
3255 * Returns the previous value of the catalog debugging level
3256 */
3257int
3258xmlCatalogSetDebug(int level) {
3259 int ret = xmlDebugCatalogs;
3260
3261 if (level <= 0)
3262 xmlDebugCatalogs = 0;
3263 else
3264 xmlDebugCatalogs = level;
3265 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003266}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003267
Daniel Veillard75b96822001-10-11 18:59:45 +00003268/************************************************************************
3269 * *
3270 * Minimal interfaces used for per-document catalogs by the parser *
3271 * *
3272 ************************************************************************/
3273
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003274/**
3275 * xmlCatalogFreeLocal:
3276 * @catalogs: a document's list of catalogs
3277 *
3278 * Free up the memory associated to the catalog list
3279 */
3280void
3281xmlCatalogFreeLocal(void *catalogs) {
3282 xmlCatalogEntryPtr catal;
3283
Daniel Veillard81463942001-10-16 12:34:39 +00003284 if (!xmlCatalogInitialized)
3285 xmlInitializeCatalog();
3286
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003287 catal = (xmlCatalogEntryPtr) catalogs;
3288 if (catal != NULL)
3289 xmlFreeCatalogEntryList(catal);
3290}
3291
3292
3293/**
3294 * xmlCatalogAddLocal:
3295 * @catalogs: a document's list of catalogs
3296 * @URL: the URL to a new local catalog
3297 *
3298 * Add the new entry to the catalog list
3299 *
3300 * Returns the updated list
3301 */
3302void *
3303xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3304 xmlCatalogEntryPtr catal, add;
3305
3306 if (!xmlCatalogInitialized)
3307 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003308
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003309 if (URL == NULL)
3310 return(catalogs);
3311
3312 if (xmlDebugCatalogs)
3313 xmlGenericError(xmlGenericErrorContext,
3314 "Adding document catalog %s\n", URL);
3315
Daniel Veillardc853b322001-11-06 15:24:37 +00003316 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003317 xmlCatalogDefaultPrefer);
3318 if (add == NULL)
3319 return(catalogs);
3320
3321 catal = (xmlCatalogEntryPtr) catalogs;
3322 if (catal == NULL)
3323 return((void *) add);
3324
3325 while (catal->next != NULL)
3326 catal = catal->next;
3327 catal->next = add;
3328 return(catalogs);
3329}
3330
3331/**
3332 * xmlCatalogLocalResolve:
3333 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003334 * @pubID: the public ID string
3335 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003336 *
3337 * Do a complete resolution lookup of an External Identifier using a
3338 * document's private catalog list
3339 *
3340 * Returns the URI of the resource or NULL if not found, it must be freed
3341 * by the caller.
3342 */
3343xmlChar *
3344xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3345 const xmlChar *sysID) {
3346 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003347 xmlChar *ret;
3348
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003349 if (!xmlCatalogInitialized)
3350 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003351
Daniel Veillard81463942001-10-16 12:34:39 +00003352 if ((pubID == NULL) && (sysID == NULL))
3353 return(NULL);
3354
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003355 if (xmlDebugCatalogs) {
3356 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003357 xmlGenericError(xmlGenericErrorContext,
3358 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003359 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003360 xmlGenericError(xmlGenericErrorContext,
3361 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003362 }
3363 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003364
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003365 catal = (xmlCatalogEntryPtr) catalogs;
3366 if (catal == NULL)
3367 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003368 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3369 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3370 return(ret);
3371 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003372}
3373
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003374/**
3375 * xmlCatalogLocalResolveURI:
3376 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003377 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003378 *
3379 * Do a complete resolution lookup of an URI using a
3380 * document's private catalog list
3381 *
3382 * Returns the URI of the resource or NULL if not found, it must be freed
3383 * by the caller.
3384 */
3385xmlChar *
3386xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3387 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003388 xmlChar *ret;
3389
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003390 if (!xmlCatalogInitialized)
3391 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003392
Daniel Veillard81463942001-10-16 12:34:39 +00003393 if (URI == NULL)
3394 return(NULL);
3395
Daniel Veillard6990bf32001-08-23 21:17:48 +00003396 if (xmlDebugCatalogs)
3397 xmlGenericError(xmlGenericErrorContext,
3398 "Resolve URI %s\n", URI);
3399
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003400 catal = (xmlCatalogEntryPtr) catalogs;
3401 if (catal == NULL)
3402 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003403 ret = xmlCatalogListXMLResolveURI(catal, URI);
3404 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3405 return(ret);
3406 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003407}
3408
Daniel Veillard75b96822001-10-11 18:59:45 +00003409/************************************************************************
3410 * *
3411 * Deprecated interfaces *
3412 * *
3413 ************************************************************************/
3414/**
3415 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003416 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003417 *
3418 * Try to lookup the system ID associated to a public ID
3419 * DEPRECATED, use xmlCatalogResolveSystem()
3420 *
3421 * Returns the system ID if found or NULL otherwise.
3422 */
3423const xmlChar *
3424xmlCatalogGetSystem(const xmlChar *sysID) {
3425 xmlChar *ret;
3426 static xmlChar result[1000];
3427 static int msg = 0;
3428
Daniel Veillard81463942001-10-16 12:34:39 +00003429 if (!xmlCatalogInitialized)
3430 xmlInitializeCatalog();
3431
Daniel Veillard75b96822001-10-11 18:59:45 +00003432 if (msg == 0) {
3433 xmlGenericError(xmlGenericErrorContext,
3434 "Use of deprecated xmlCatalogGetSystem() call\n");
3435 msg++;
3436 }
3437
3438 if (sysID == NULL)
3439 return(NULL);
3440
Daniel Veillard75b96822001-10-11 18:59:45 +00003441 /*
3442 * Check first the XML catalogs
3443 */
3444 if (xmlDefaultCatalog != NULL) {
3445 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3446 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3447 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3448 result[sizeof(result) - 1] = 0;
3449 return(result);
3450 }
3451 }
3452
3453 if (xmlDefaultCatalog != NULL)
3454 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3455 return(NULL);
3456}
3457
3458/**
3459 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003460 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003461 *
3462 * Try to lookup the system ID associated to a public ID
3463 * DEPRECATED, use xmlCatalogResolvePublic()
3464 *
3465 * Returns the system ID if found or NULL otherwise.
3466 */
3467const xmlChar *
3468xmlCatalogGetPublic(const xmlChar *pubID) {
3469 xmlChar *ret;
3470 static xmlChar result[1000];
3471 static int msg = 0;
3472
Daniel Veillard81463942001-10-16 12:34:39 +00003473 if (!xmlCatalogInitialized)
3474 xmlInitializeCatalog();
3475
Daniel Veillard75b96822001-10-11 18:59:45 +00003476 if (msg == 0) {
3477 xmlGenericError(xmlGenericErrorContext,
3478 "Use of deprecated xmlCatalogGetPublic() call\n");
3479 msg++;
3480 }
3481
3482 if (pubID == NULL)
3483 return(NULL);
3484
Daniel Veillard75b96822001-10-11 18:59:45 +00003485 /*
3486 * Check first the XML catalogs
3487 */
3488 if (xmlDefaultCatalog != NULL) {
3489 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3490 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3491 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3492 result[sizeof(result) - 1] = 0;
3493 return(result);
3494 }
3495 }
3496
3497 if (xmlDefaultCatalog != NULL)
3498 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3499 return(NULL);
3500}
3501
Daniel Veillarda7374592001-05-10 14:17:55 +00003502#endif /* LIBXML_CATALOG_ENABLED */