blob: 1fc419d759173d38da2375877893baa438280942 [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
850 if ((fd = open(filename, O_RDONLY)) < 0) {
851#else
852 if ((fd = fopen(filename, "rb")) == NULL) {
853#endif
854 return (NULL);
855 }
856#ifdef HAVE_STAT
857 size = info.st_size;
858#else
859 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
860 fclose(fd);
861 return (NULL);
862 }
863#endif
864 content = xmlMalloc(size + 10);
865 if (content == NULL) {
866 xmlGenericError(xmlGenericErrorContext,
867 "malloc of %d byte failed\n", size + 10);
868 return (NULL);
869 }
870#ifdef HAVE_STAT
871 len = read(fd, content, size);
872#else
873 len = fread(content, 1, size, fd);
874#endif
875 if (len < 0) {
876 xmlFree(content);
877 return (NULL);
878 }
879#ifdef HAVE_STAT
880 close(fd);
881#else
882 fclose(fd);
883#endif
884 content[len] = 0;
885
886 return(content);
887}
888
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000889/************************************************************************
890 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000891 * The XML Catalog parser *
892 * *
893 ************************************************************************/
894
895static xmlCatalogEntryPtr
896xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000897static void
898xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
899 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000900static xmlChar *
901xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
902 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000903static xmlChar *
904xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
905
Daniel Veillard344cee72001-08-20 00:08:40 +0000906
Daniel Veillard75b96822001-10-11 18:59:45 +0000907/**
908 * xmlGetXMLCatalogEntryType:
909 * @name: the name
910 *
911 * lookup the internal type associated to an XML catalog entry name
912 *
913 * Returns the type associate with that name
914 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000915static xmlCatalogEntryType
916xmlGetXMLCatalogEntryType(const xmlChar *name) {
917 xmlCatalogEntryType type = XML_CATA_NONE;
918 if (xmlStrEqual(name, (const xmlChar *) "system"))
919 type = XML_CATA_SYSTEM;
920 else if (xmlStrEqual(name, (const xmlChar *) "public"))
921 type = XML_CATA_PUBLIC;
922 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
923 type = XML_CATA_REWRITE_SYSTEM;
924 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
925 type = XML_CATA_DELEGATE_PUBLIC;
926 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
927 type = XML_CATA_DELEGATE_SYSTEM;
928 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
929 type = XML_CATA_URI;
930 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
931 type = XML_CATA_REWRITE_URI;
932 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
933 type = XML_CATA_DELEGATE_URI;
934 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
935 type = XML_CATA_NEXT_CATALOG;
936 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
937 type = XML_CATA_CATALOG;
938 return(type);
939}
940
Daniel Veillard75b96822001-10-11 18:59:45 +0000941/**
942 * xmlParseXMLCatalogOneNode:
943 * @cur: the XML node
944 * @type: the type of Catalog entry
945 * @name: the name of the node
946 * @attrName: the attribute holding the value
947 * @uriAttrName: the attribute holding the URI-Reference
948 * @prefer: the PUBLIC vs. SYSTEM current preference value
949 *
950 * Finishes the examination of an XML tree node of a catalog and build
951 * a Catalog entry from it.
952 *
953 * Returns the new Catalog entry node or NULL in case of error.
954 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000955static xmlCatalogEntryPtr
956xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
957 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000958 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000959 int ok = 1;
960 xmlChar *uriValue;
961 xmlChar *nameValue = NULL;
962 xmlChar *base = NULL;
963 xmlChar *URL = NULL;
964 xmlCatalogEntryPtr ret = NULL;
965
966 if (attrName != NULL) {
967 nameValue = xmlGetProp(cur, attrName);
968 if (nameValue == NULL) {
969 xmlGenericError(xmlGenericErrorContext,
970 "%s entry lacks '%s'\n", name, attrName);
971 ok = 0;
972 }
973 }
974 uriValue = xmlGetProp(cur, uriAttrName);
975 if (uriValue == NULL) {
976 xmlGenericError(xmlGenericErrorContext,
977 "%s entry lacks '%s'\n", name, uriAttrName);
978 ok = 0;
979 }
980 if (!ok) {
981 if (nameValue != NULL)
982 xmlFree(nameValue);
983 if (uriValue != NULL)
984 xmlFree(uriValue);
985 return(NULL);
986 }
987
988 base = xmlNodeGetBase(cur->doc, cur);
989 URL = xmlBuildURI(uriValue, base);
990 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000991 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000992 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000993 xmlGenericError(xmlGenericErrorContext,
994 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000995 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000996 xmlGenericError(xmlGenericErrorContext,
997 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000998 }
Daniel Veillardc853b322001-11-06 15:24:37 +0000999 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001000 } else {
1001 xmlGenericError(xmlGenericErrorContext,
1002 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1003 }
1004 if (nameValue != NULL)
1005 xmlFree(nameValue);
1006 if (uriValue != NULL)
1007 xmlFree(uriValue);
1008 if (base != NULL)
1009 xmlFree(base);
1010 if (URL != NULL)
1011 xmlFree(URL);
1012 return(ret);
1013}
1014
Daniel Veillard75b96822001-10-11 18:59:45 +00001015/**
1016 * xmlParseXMLCatalogNode:
1017 * @cur: the XML node
1018 * @prefer: the PUBLIC vs. SYSTEM current preference value
1019 * @parent: the parent Catalog entry
1020 *
1021 * Examines an XML tree node of a catalog and build
1022 * a Catalog entry from it adding it to its parent. The examination can
1023 * be recursive.
1024 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001025static void
1026xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1027 xmlCatalogEntryPtr parent)
1028{
1029 xmlChar *uri = NULL;
1030 xmlChar *URL = NULL;
1031 xmlChar *base = NULL;
1032 xmlCatalogEntryPtr entry = NULL;
1033
1034 if (cur == NULL)
1035 return;
1036 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1037 xmlChar *prop;
1038
1039 prop = xmlGetProp(cur, BAD_CAST "prefer");
1040 if (prop != NULL) {
1041 if (xmlStrEqual(prop, BAD_CAST "system")) {
1042 prefer = XML_CATA_PREFER_SYSTEM;
1043 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1044 prefer = XML_CATA_PREFER_PUBLIC;
1045 } else {
1046 xmlGenericError(xmlGenericErrorContext,
1047 "Invalid value for prefer: '%s'\n", prop);
1048 }
1049 xmlFree(prop);
1050 }
1051 /*
1052 * Recurse to propagate prefer to the subtree
1053 * (xml:base handling is automated)
1054 */
1055 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1056 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1057 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001058 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001059 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1060 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001061 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001062 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1063 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1064 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001065 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001066 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1067 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1068 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001069 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001070 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1071 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1072 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001073 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001074 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1075 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1076 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001077 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001078 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1079 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1080 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001081 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001082 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1083 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1084 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001085 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001086 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1087 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1088 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001089 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001090 }
1091 if ((entry != NULL) && (parent != NULL)) {
1092 entry->parent = parent;
1093 if (parent->children == NULL)
1094 parent->children = entry;
1095 else {
1096 xmlCatalogEntryPtr prev;
1097
1098 prev = parent->children;
1099 while (prev->next != NULL)
1100 prev = prev->next;
1101 prev->next = entry;
1102 }
1103 }
1104 if (base != NULL)
1105 xmlFree(base);
1106 if (uri != NULL)
1107 xmlFree(uri);
1108 if (URL != NULL)
1109 xmlFree(URL);
1110}
1111
Daniel Veillard75b96822001-10-11 18:59:45 +00001112/**
1113 * xmlParseXMLCatalogNodeList:
1114 * @cur: the XML node list of siblings
1115 * @prefer: the PUBLIC vs. SYSTEM current preference value
1116 * @parent: the parent Catalog entry
1117 *
1118 * Examines a list of XML sibling nodes of a catalog and build
1119 * a list of Catalog entry from it adding it to the parent.
1120 * The examination will recurse to examine node subtrees.
1121 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001122static void
1123xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1124 xmlCatalogEntryPtr parent) {
1125 while (cur != NULL) {
1126 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1127 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1128 xmlParseXMLCatalogNode(cur, prefer, parent);
1129 }
1130 cur = cur->next;
1131 }
1132 /* TODO: sort the list according to REWRITE lengths and prefer value */
1133}
1134
Daniel Veillard75b96822001-10-11 18:59:45 +00001135/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001136 * xmlParseXMLCatalogFile:
1137 * @prefer: the PUBLIC vs. SYSTEM current preference value
1138 * @filename: the filename for the catalog
1139 *
1140 * Parses the catalog file to extract the XML tree and then analyze the
1141 * tree to build a list of Catalog entries corresponding to this catalog
1142 *
1143 * Returns the resulting Catalog entries list
1144 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001145static xmlCatalogEntryPtr
1146xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1147 xmlDocPtr doc;
1148 xmlNodePtr cur;
1149 xmlChar *prop;
1150 xmlCatalogEntryPtr parent = NULL;
1151
1152 if (filename == NULL)
1153 return(NULL);
1154
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001155 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001156 if (doc == NULL) {
1157 if (xmlDebugCatalogs)
1158 xmlGenericError(xmlGenericErrorContext,
1159 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001160 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001161 }
1162
1163 if (xmlDebugCatalogs)
1164 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001165 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001166
1167 cur = xmlDocGetRootElement(doc);
1168 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1169 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1170 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1171
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001172 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00001173 (const xmlChar *)filename, NULL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001174 if (parent == NULL) {
1175 xmlFreeDoc(doc);
1176 return(NULL);
1177 }
1178
1179 prop = xmlGetProp(cur, BAD_CAST "prefer");
1180 if (prop != NULL) {
1181 if (xmlStrEqual(prop, BAD_CAST "system")) {
1182 prefer = XML_CATA_PREFER_SYSTEM;
1183 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1184 prefer = XML_CATA_PREFER_PUBLIC;
1185 } else {
1186 xmlGenericError(xmlGenericErrorContext,
1187 "Invalid value for prefer: '%s'\n",
1188 prop);
1189 }
1190 xmlFree(prop);
1191 }
1192 cur = cur->children;
1193 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1194 } else {
1195 xmlGenericError(xmlGenericErrorContext,
1196 "File %s is not an XML Catalog\n", filename);
1197 xmlFreeDoc(doc);
1198 return(NULL);
1199 }
1200 xmlFreeDoc(doc);
1201 return(parent);
1202}
1203
Daniel Veillardcda96922001-08-21 10:56:31 +00001204/**
1205 * xmlFetchXMLCatalogFile:
1206 * @catal: an existing but incomplete catalog entry
1207 *
1208 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001209 *
1210 * Returns 0 in case of success, -1 otherwise
1211 */
1212static int
1213xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001214 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001215
1216 if (catal == NULL)
1217 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001218 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001219 return(-1);
1220 if (catal->children != NULL)
1221 return(-1);
1222
Daniel Veillard81463942001-10-16 12:34:39 +00001223 /*
1224 * lock the whole catalog for modification
1225 */
1226 xmlRMutexLock(xmlCatalogMutex);
1227 if (catal->children != NULL) {
1228 /* Okay someone else did it in the meantime */
1229 xmlRMutexUnlock(xmlCatalogMutex);
1230 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001231 }
1232
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001233 if (xmlCatalogXMLFiles != NULL) {
1234 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001235 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001236 if (doc != NULL) {
1237 if (xmlDebugCatalogs)
1238 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001239 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001240
1241 if (catal->type == XML_CATA_CATALOG)
1242 catal->children = doc->children;
1243 else
1244 catal->children = doc;
1245 catal->dealloc = 0;
1246 xmlRMutexUnlock(xmlCatalogMutex);
1247 return(0);
1248 }
1249 if (xmlDebugCatalogs)
1250 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001251 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001252 }
1253
Daniel Veillardcda96922001-08-21 10:56:31 +00001254 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001255 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001256 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001257 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001258 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001259 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001260 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001261 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001262 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001263 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001264 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001265
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001266 if (catal->type == XML_CATA_CATALOG)
1267 catal->children = doc->children;
1268 else
1269 catal->children = doc;
1270
1271 doc->dealloc = 1;
1272
Daniel Veillard81463942001-10-16 12:34:39 +00001273 if (xmlCatalogXMLFiles == NULL)
1274 xmlCatalogXMLFiles = xmlHashCreate(10);
1275 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001276 if (xmlDebugCatalogs)
1277 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001278 "%s added to file hash\n", catal->URL);
1279 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001280 }
Daniel Veillard81463942001-10-16 12:34:39 +00001281 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001282 return(0);
1283}
1284
Daniel Veillard75b96822001-10-11 18:59:45 +00001285/************************************************************************
1286 * *
1287 * XML Catalog handling *
1288 * *
1289 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001290
1291/**
1292 * xmlAddXMLCatalog:
1293 * @catal: top of an XML catalog
1294 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001295 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001296 * @replace: the replacement value for the match
1297 *
1298 * Add an entry in the XML catalog, it may overwrite existing but
1299 * different entries.
1300 *
1301 * Returns 0 if successful, -1 otherwise
1302 */
1303static int
1304xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1305 const xmlChar *orig, const xmlChar *replace) {
1306 xmlCatalogEntryPtr cur;
1307 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001308 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001309
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001310 if ((catal == NULL) ||
1311 ((catal->type != XML_CATA_CATALOG) &&
1312 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001313 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001314 if (catal->children == NULL) {
1315 xmlFetchXMLCatalogFile(catal);
1316 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001317 if (catal->children == NULL)
1318 doregister = 1;
1319
Daniel Veillard344cee72001-08-20 00:08:40 +00001320 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001321 if (typ == XML_CATA_NONE) {
1322 if (xmlDebugCatalogs)
1323 xmlGenericError(xmlGenericErrorContext,
1324 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001325 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001326 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001327
1328 cur = catal->children;
1329 /*
1330 * Might be a simple "update in place"
1331 */
1332 if (cur != NULL) {
1333 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001334 if ((orig != NULL) && (cur->type == typ) &&
1335 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001336 if (xmlDebugCatalogs)
1337 xmlGenericError(xmlGenericErrorContext,
1338 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001339 if (cur->value != NULL)
1340 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001341 if (cur->URL != NULL)
1342 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001343 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001344 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001345 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001346 }
1347 if (cur->next == NULL)
1348 break;
1349 cur = cur->next;
1350 }
1351 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001352 if (xmlDebugCatalogs)
1353 xmlGenericError(xmlGenericErrorContext,
1354 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001355 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001356 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1357 NULL, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001358 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001359 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1360 NULL, catal->prefer);
1361 if (doregister) {
1362 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1363 if (cur != NULL)
1364 cur->children = catal->children;
1365 }
1366
Daniel Veillardcda96922001-08-21 10:56:31 +00001367 return(0);
1368}
1369
1370/**
1371 * xmlDelXMLCatalog:
1372 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001373 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001374 *
1375 * Remove entries in the XML catalog where the value or the URI
1376 * is equal to @value
1377 *
1378 * Returns the number of entries removed if successful, -1 otherwise
1379 */
1380static int
1381xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001382 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001383 int ret = 0;
1384
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001385 if ((catal == NULL) ||
1386 ((catal->type != XML_CATA_CATALOG) &&
1387 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001388 return(-1);
1389 if (value == NULL)
1390 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001391 if (catal->children == NULL) {
1392 xmlFetchXMLCatalogFile(catal);
1393 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001394
1395 /*
1396 * Scan the children
1397 */
1398 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001399 while (cur != NULL) {
1400 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1401 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001402 if (xmlDebugCatalogs) {
1403 if (cur->name != NULL)
1404 xmlGenericError(xmlGenericErrorContext,
1405 "Removing element %s from catalog\n", cur->name);
1406 else
1407 xmlGenericError(xmlGenericErrorContext,
1408 "Removing element %s from catalog\n", cur->value);
1409 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001410 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001411 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001412 cur = cur->next;
1413 }
1414 return(ret);
1415}
1416
1417/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001418 * xmlCatalogXMLResolve:
1419 * @catal: a catalog list
1420 * @pubId: the public ID string
1421 * @sysId: the system ID string
1422 *
1423 * Do a complete resolution lookup of an External Identifier for a
1424 * list of catalog entries.
1425 *
1426 * Implements (or tries to) 7.1. External Identifier Resolution
1427 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1428 *
1429 * Returns the URI of the resource or NULL if not found
1430 */
1431static xmlChar *
1432xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1433 const xmlChar *sysID) {
1434 xmlChar *ret = NULL;
1435 xmlCatalogEntryPtr cur;
1436 int haveDelegate = 0;
1437 int haveNext = 0;
1438
1439 /*
1440 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1441 */
1442 if (sysID != NULL) {
1443 xmlCatalogEntryPtr rewrite = NULL;
1444 int lenrewrite = 0, len;
1445 cur = catal;
1446 haveDelegate = 0;
1447 while (cur != NULL) {
1448 switch (cur->type) {
1449 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001450 if (xmlStrEqual(sysID, cur->name)) {
1451 if (xmlDebugCatalogs)
1452 xmlGenericError(xmlGenericErrorContext,
1453 "Found system match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001454 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001455 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001456 break;
1457 case XML_CATA_REWRITE_SYSTEM:
1458 len = xmlStrlen(cur->name);
1459 if ((len > lenrewrite) &&
1460 (!xmlStrncmp(sysID, cur->name, len))) {
1461 lenrewrite = len;
1462 rewrite = cur;
1463 }
1464 break;
1465 case XML_CATA_DELEGATE_SYSTEM:
1466 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1467 haveDelegate++;
1468 break;
1469 case XML_CATA_NEXT_CATALOG:
1470 haveNext++;
1471 break;
1472 default:
1473 break;
1474 }
1475 cur = cur->next;
1476 }
1477 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001478 if (xmlDebugCatalogs)
1479 xmlGenericError(xmlGenericErrorContext,
1480 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001481 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001482 if (ret != NULL)
1483 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1484 return(ret);
1485 }
1486 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001487 const xmlChar *delegates[MAX_DELEGATE];
1488 int nbList = 0, i;
1489
Daniel Veillardcda96922001-08-21 10:56:31 +00001490 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001491 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001492 * matches when the list was produced.
1493 */
1494 cur = catal;
1495 while (cur != NULL) {
1496 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1497 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001498 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001499 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001500 break;
1501 if (i < nbList) {
1502 cur = cur->next;
1503 continue;
1504 }
1505 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001506 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001507
Daniel Veillardcda96922001-08-21 10:56:31 +00001508 if (cur->children == NULL) {
1509 xmlFetchXMLCatalogFile(cur);
1510 }
1511 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001512 if (xmlDebugCatalogs)
1513 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001514 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001515 ret = xmlCatalogListXMLResolve(
1516 cur->children, NULL, sysID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001517 if (ret != NULL)
1518 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001519 }
1520 }
1521 cur = cur->next;
1522 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001523 /*
1524 * Apply the cut algorithm explained in 4/
1525 */
1526 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001527 }
1528 }
1529 /*
1530 * Then tries 5/ 6/ if a public ID is provided
1531 */
1532 if (pubID != NULL) {
1533 cur = catal;
1534 haveDelegate = 0;
1535 while (cur != NULL) {
1536 switch (cur->type) {
1537 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001538 if (xmlStrEqual(pubID, cur->name)) {
1539 if (xmlDebugCatalogs)
1540 xmlGenericError(xmlGenericErrorContext,
1541 "Found public match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001542 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001543 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001544 break;
1545 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001546 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1547 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001548 haveDelegate++;
1549 break;
1550 case XML_CATA_NEXT_CATALOG:
1551 if (sysID == NULL)
1552 haveNext++;
1553 break;
1554 default:
1555 break;
1556 }
1557 cur = cur->next;
1558 }
1559 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001560 const xmlChar *delegates[MAX_DELEGATE];
1561 int nbList = 0, i;
1562
Daniel Veillardcda96922001-08-21 10:56:31 +00001563 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001564 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001565 * matches when the list was produced.
1566 */
1567 cur = catal;
1568 while (cur != NULL) {
1569 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001570 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1571 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001572
1573 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001574 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001575 break;
1576 if (i < nbList) {
1577 cur = cur->next;
1578 continue;
1579 }
1580 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001581 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001582
Daniel Veillardcda96922001-08-21 10:56:31 +00001583 if (cur->children == NULL) {
1584 xmlFetchXMLCatalogFile(cur);
1585 }
1586 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001587 if (xmlDebugCatalogs)
1588 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001589 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001590 ret = xmlCatalogListXMLResolve(
1591 cur->children, pubID, NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001592 if (ret != NULL)
1593 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001594 }
1595 }
1596 cur = cur->next;
1597 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001598 /*
1599 * Apply the cut algorithm explained in 4/
1600 */
1601 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001602 }
1603 }
1604 if (haveNext) {
1605 cur = catal;
1606 while (cur != NULL) {
1607 if (cur->type == XML_CATA_NEXT_CATALOG) {
1608 if (cur->children == NULL) {
1609 xmlFetchXMLCatalogFile(cur);
1610 }
1611 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001612 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1613 if (ret != NULL)
1614 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001615 }
1616 }
1617 cur = cur->next;
1618 }
1619 }
1620
1621 return(NULL);
1622}
1623
1624/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001625 * xmlCatalogXMLResolveURI:
1626 * @catal: a catalog list
1627 * @URI: the URI
1628 * @sysId: the system ID string
1629 *
1630 * Do a complete resolution lookup of an External Identifier for a
1631 * list of catalog entries.
1632 *
1633 * Implements (or tries to) 7.2.2. URI Resolution
1634 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1635 *
1636 * Returns the URI of the resource or NULL if not found
1637 */
1638static xmlChar *
1639xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1640 xmlChar *ret = NULL;
1641 xmlCatalogEntryPtr cur;
1642 int haveDelegate = 0;
1643 int haveNext = 0;
1644 xmlCatalogEntryPtr rewrite = NULL;
1645 int lenrewrite = 0, len;
1646
1647 if (catal == NULL)
1648 return(NULL);
1649
1650 if (URI == NULL)
1651 return(NULL);
1652
1653 /*
1654 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1655 */
1656 cur = catal;
1657 haveDelegate = 0;
1658 while (cur != NULL) {
1659 switch (cur->type) {
1660 case XML_CATA_URI:
1661 if (xmlStrEqual(URI, cur->name)) {
1662 if (xmlDebugCatalogs)
1663 xmlGenericError(xmlGenericErrorContext,
1664 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001665 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001666 }
1667 break;
1668 case XML_CATA_REWRITE_URI:
1669 len = xmlStrlen(cur->name);
1670 if ((len > lenrewrite) &&
1671 (!xmlStrncmp(URI, cur->name, len))) {
1672 lenrewrite = len;
1673 rewrite = cur;
1674 }
1675 break;
1676 case XML_CATA_DELEGATE_URI:
1677 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1678 haveDelegate++;
1679 break;
1680 case XML_CATA_NEXT_CATALOG:
1681 haveNext++;
1682 break;
1683 default:
1684 break;
1685 }
1686 cur = cur->next;
1687 }
1688 if (rewrite != NULL) {
1689 if (xmlDebugCatalogs)
1690 xmlGenericError(xmlGenericErrorContext,
1691 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001692 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001693 if (ret != NULL)
1694 ret = xmlStrcat(ret, &URI[lenrewrite]);
1695 return(ret);
1696 }
1697 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001698 const xmlChar *delegates[MAX_DELEGATE];
1699 int nbList = 0, i;
1700
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001701 /*
1702 * Assume the entries have been sorted by decreasing substring
1703 * matches when the list was produced.
1704 */
1705 cur = catal;
1706 while (cur != NULL) {
1707 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1708 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001709 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001710 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001711 break;
1712 if (i < nbList) {
1713 cur = cur->next;
1714 continue;
1715 }
1716 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001717 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001718
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001719 if (cur->children == NULL) {
1720 xmlFetchXMLCatalogFile(cur);
1721 }
1722 if (cur->children != NULL) {
1723 if (xmlDebugCatalogs)
1724 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001725 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001726 ret = xmlCatalogListXMLResolveURI(
1727 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001728 if (ret != NULL)
1729 return(ret);
1730 }
1731 }
1732 cur = cur->next;
1733 }
1734 /*
1735 * Apply the cut algorithm explained in 4/
1736 */
1737 return(XML_CATAL_BREAK);
1738 }
1739 if (haveNext) {
1740 cur = catal;
1741 while (cur != NULL) {
1742 if (cur->type == XML_CATA_NEXT_CATALOG) {
1743 if (cur->children == NULL) {
1744 xmlFetchXMLCatalogFile(cur);
1745 }
1746 if (cur->children != NULL) {
1747 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1748 if (ret != NULL)
1749 return(ret);
1750 }
1751 }
1752 cur = cur->next;
1753 }
1754 }
1755
1756 return(NULL);
1757}
1758
1759/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001760 * xmlCatalogListXMLResolve:
1761 * @catal: a catalog list
1762 * @pubId: the public ID string
1763 * @sysId: the system ID string
1764 *
1765 * Do a complete resolution lookup of an External Identifier for a
1766 * list of catalogs
1767 *
1768 * Implements (or tries to) 7.1. External Identifier Resolution
1769 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1770 *
1771 * Returns the URI of the resource or NULL if not found
1772 */
1773static xmlChar *
1774xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1775 const xmlChar *sysID) {
1776 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001777 xmlChar *urnID = NULL;
1778
1779 if (catal == NULL)
1780 return(NULL);
1781 if ((pubID == NULL) && (sysID == NULL))
1782 return(NULL);
1783
1784 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1785 urnID = xmlCatalogUnWrapURN(pubID);
1786 if (xmlDebugCatalogs) {
1787 if (urnID == NULL)
1788 xmlGenericError(xmlGenericErrorContext,
1789 "Public URN ID %s expanded to NULL\n", pubID);
1790 else
1791 xmlGenericError(xmlGenericErrorContext,
1792 "Public URN ID expanded to %s\n", urnID);
1793 }
1794 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1795 if (urnID != NULL)
1796 xmlFree(urnID);
1797 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001798 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001799 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1800 urnID = xmlCatalogUnWrapURN(sysID);
1801 if (xmlDebugCatalogs) {
1802 if (urnID == NULL)
1803 xmlGenericError(xmlGenericErrorContext,
1804 "System URN ID %s expanded to NULL\n", sysID);
1805 else
1806 xmlGenericError(xmlGenericErrorContext,
1807 "System URN ID expanded to %s\n", urnID);
1808 }
1809 if (pubID == NULL)
1810 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1811 else if (xmlStrEqual(pubID, urnID))
1812 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1813 else {
1814 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1815 }
1816 if (urnID != NULL)
1817 xmlFree(urnID);
1818 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001819 }
1820 while (catal != NULL) {
1821 if (catal->type == XML_CATA_CATALOG) {
1822 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001823 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001824 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001825 if (catal->children != NULL) {
1826 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1827 if (ret != NULL)
1828 return(ret);
1829 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001830 }
1831 catal = catal->next;
1832 }
1833 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001834}
1835
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001836/**
1837 * xmlCatalogListXMLResolveURI:
1838 * @catal: a catalog list
1839 * @URI: the URI
1840 *
1841 * Do a complete resolution lookup of an URI for a list of catalogs
1842 *
1843 * Implements (or tries to) 7.2. URI Resolution
1844 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1845 *
1846 * Returns the URI of the resource or NULL if not found
1847 */
1848static xmlChar *
1849xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1850 xmlChar *ret = NULL;
1851 xmlChar *urnID = NULL;
1852
1853 if (catal == NULL)
1854 return(NULL);
1855 if (URI == NULL)
1856 return(NULL);
1857
1858 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1859 urnID = xmlCatalogUnWrapURN(URI);
1860 if (xmlDebugCatalogs) {
1861 if (urnID == NULL)
1862 xmlGenericError(xmlGenericErrorContext,
1863 "URN ID %s expanded to NULL\n", URI);
1864 else
1865 xmlGenericError(xmlGenericErrorContext,
1866 "URN ID expanded to %s\n", urnID);
1867 }
1868 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1869 if (urnID != NULL)
1870 xmlFree(urnID);
1871 return(ret);
1872 }
1873 while (catal != NULL) {
1874 if (catal->type == XML_CATA_CATALOG) {
1875 if (catal->children == NULL) {
1876 xmlFetchXMLCatalogFile(catal);
1877 }
1878 if (catal->children != NULL) {
1879 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1880 if (ret != NULL)
1881 return(ret);
1882 }
1883 }
1884 catal = catal->next;
1885 }
1886 return(ret);
1887}
1888
Daniel Veillard344cee72001-08-20 00:08:40 +00001889/************************************************************************
1890 * *
1891 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001892 * *
1893 ************************************************************************/
1894
1895
1896#define RAW *cur
1897#define NEXT cur++;
1898#define SKIP(x) cur += x;
1899
1900#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1901
Daniel Veillard75b96822001-10-11 18:59:45 +00001902/**
1903 * xmlParseSGMLCatalogComment:
1904 * @cur: the current character
1905 *
1906 * Skip a comment in an SGML catalog
1907 *
1908 * Returns new current character
1909 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001910static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001911xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001912 if ((cur[0] != '-') || (cur[1] != '-'))
1913 return(cur);
1914 SKIP(2);
1915 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1916 NEXT;
1917 if (cur[0] == 0) {
1918 return(NULL);
1919 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001920 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001921}
1922
Daniel Veillard75b96822001-10-11 18:59:45 +00001923/**
1924 * xmlParseSGMLCatalogPubid:
1925 * @cur: the current character
1926 * @id: the return location
1927 *
1928 * Parse an SGML catalog ID
1929 *
1930 * Returns new current character and store the value in @id
1931 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001932static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001933xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001934 xmlChar *buf = NULL;
1935 int len = 0;
1936 int size = 50;
1937 xmlChar stop;
1938 int count = 0;
1939
1940 *id = NULL;
1941
1942 if (RAW == '"') {
1943 NEXT;
1944 stop = '"';
1945 } else if (RAW == '\'') {
1946 NEXT;
1947 stop = '\'';
1948 } else {
1949 stop = ' ';
1950 }
1951 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1952 if (buf == NULL) {
1953 xmlGenericError(xmlGenericErrorContext,
1954 "malloc of %d byte failed\n", size);
1955 return(NULL);
1956 }
1957 while (xmlIsPubidChar(*cur)) {
1958 if ((*cur == stop) && (stop != ' '))
1959 break;
1960 if ((stop == ' ') && (IS_BLANK(*cur)))
1961 break;
1962 if (len + 1 >= size) {
1963 size *= 2;
1964 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1965 if (buf == NULL) {
1966 xmlGenericError(xmlGenericErrorContext,
1967 "realloc of %d byte failed\n", size);
1968 return(NULL);
1969 }
1970 }
1971 buf[len++] = *cur;
1972 count++;
1973 NEXT;
1974 }
1975 buf[len] = 0;
1976 if (stop == ' ') {
1977 if (!IS_BLANK(*cur)) {
1978 xmlFree(buf);
1979 return(NULL);
1980 }
1981 } else {
1982 if (*cur != stop) {
1983 xmlFree(buf);
1984 return(NULL);
1985 }
1986 NEXT;
1987 }
1988 *id = buf;
1989 return(cur);
1990}
1991
Daniel Veillard75b96822001-10-11 18:59:45 +00001992/**
1993 * xmlParseSGMLCatalogName:
1994 * @cur: the current character
1995 * @name: the return location
1996 *
1997 * Parse an SGML catalog name
1998 *
1999 * Returns new current character and store the value in @name
2000 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002001static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002002xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002003 xmlChar buf[XML_MAX_NAMELEN + 5];
2004 int len = 0;
2005 int c;
2006
2007 *name = NULL;
2008
2009 /*
2010 * Handler for more complex cases
2011 */
2012 c = *cur;
2013 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2014 return(NULL);
2015 }
2016
2017 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2018 (c == '.') || (c == '-') ||
2019 (c == '_') || (c == ':'))) {
2020 buf[len++] = c;
2021 cur++;
2022 c = *cur;
2023 if (len >= XML_MAX_NAMELEN)
2024 return(NULL);
2025 }
2026 *name = xmlStrndup(buf, len);
2027 return(cur);
2028}
2029
Daniel Veillard75b96822001-10-11 18:59:45 +00002030/**
2031 * xmlGetSGMLCatalogEntryType:
2032 * @name: the entry name
2033 *
2034 * Get the Catalog entry type for a given SGML Catalog name
2035 *
2036 * Returns Catalog entry type
2037 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002038static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002039xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002040 xmlCatalogEntryType type = XML_CATA_NONE;
2041 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2042 type = SGML_CATA_SYSTEM;
2043 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2044 type = SGML_CATA_PUBLIC;
2045 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2046 type = SGML_CATA_DELEGATE;
2047 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2048 type = SGML_CATA_ENTITY;
2049 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2050 type = SGML_CATA_DOCTYPE;
2051 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2052 type = SGML_CATA_LINKTYPE;
2053 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2054 type = SGML_CATA_NOTATION;
2055 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2056 type = SGML_CATA_SGMLDECL;
2057 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2058 type = SGML_CATA_DOCUMENT;
2059 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2060 type = SGML_CATA_CATALOG;
2061 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2062 type = SGML_CATA_BASE;
2063 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2064 type = SGML_CATA_DELEGATE;
2065 return(type);
2066}
2067
Daniel Veillard75b96822001-10-11 18:59:45 +00002068/**
2069 * xmlParseSGMLCatalog:
2070 * @catal: the SGML Catalog
2071 * @value: the content of the SGML Catalog serialization
2072 * @file: the filepath for the catalog
2073 * @super: should this be handled as a Super Catalog in which case
2074 * parsing is not recursive
2075 *
2076 * Parse an SGML catalog content and fill up the @catal hash table with
2077 * the new entries found.
2078 *
2079 * Returns 0 in case of success, -1 in case of error.
2080 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002081static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002082xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2083 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002084 const xmlChar *cur = value;
2085 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002086 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002087
2088 if ((cur == NULL) || (file == NULL))
2089 return(-1);
2090 base = xmlStrdup((const xmlChar *) file);
2091
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002092 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002093 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002094 if (cur[0] == 0)
2095 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002096 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002097 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002098 if (cur == NULL) {
2099 /* error */
2100 break;
2101 }
2102 } else {
2103 xmlChar *sysid = NULL;
2104 xmlChar *name = NULL;
2105 xmlCatalogEntryType type = XML_CATA_NONE;
2106
Daniel Veillardcda96922001-08-21 10:56:31 +00002107 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002108 if (name == NULL) {
2109 /* error */
2110 break;
2111 }
2112 if (!IS_BLANK(*cur)) {
2113 /* error */
2114 break;
2115 }
2116 SKIP_BLANKS;
2117 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002118 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002119 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002120 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002121 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002122 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002123 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002124 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002125 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002126 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002127 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002128 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002129 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002130 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002131 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002132 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002133 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002134 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002135 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002136 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002137 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002138 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002139 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002140 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002141 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2142 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002143 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002144 if (name == NULL) {
2145 /* error */
2146 break;
2147 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002148 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002149 continue;
2150 }
2151 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002152 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002153
2154 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002155 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002156 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002157 type = SGML_CATA_PENTITY;
2158 case SGML_CATA_PENTITY:
2159 case SGML_CATA_DOCTYPE:
2160 case SGML_CATA_LINKTYPE:
2161 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002162 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002163 if (cur == NULL) {
2164 /* error */
2165 break;
2166 }
2167 if (!IS_BLANK(*cur)) {
2168 /* error */
2169 break;
2170 }
2171 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002172 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002173 if (cur == NULL) {
2174 /* error */
2175 break;
2176 }
2177 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002178 case SGML_CATA_PUBLIC:
2179 case SGML_CATA_SYSTEM:
2180 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002181 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002182 if (cur == NULL) {
2183 /* error */
2184 break;
2185 }
2186 if (!IS_BLANK(*cur)) {
2187 /* error */
2188 break;
2189 }
2190 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002191 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002192 if (cur == NULL) {
2193 /* error */
2194 break;
2195 }
2196 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002197 case SGML_CATA_BASE:
2198 case SGML_CATA_CATALOG:
2199 case SGML_CATA_DOCUMENT:
2200 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002201 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002202 if (cur == NULL) {
2203 /* error */
2204 break;
2205 }
2206 break;
2207 default:
2208 break;
2209 }
2210 if (cur == NULL) {
2211 if (name != NULL)
2212 xmlFree(name);
2213 if (sysid != NULL)
2214 xmlFree(sysid);
2215 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002216 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002217 if (base != NULL)
2218 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002219 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002220 } else if ((type == SGML_CATA_PUBLIC) ||
2221 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002222 xmlChar *filename;
2223
2224 filename = xmlBuildURI(sysid, base);
2225 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002226 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002227
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002228 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002229 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002230 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002231 if (res < 0) {
2232 xmlFreeCatalogEntry(entry);
2233 }
2234 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002235 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002236
Daniel Veillard344cee72001-08-20 00:08:40 +00002237 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002238 if (super) {
2239 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002240
Daniel Veillardc853b322001-11-06 15:24:37 +00002241 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002242 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002243 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002244 if (res < 0) {
2245 xmlFreeCatalogEntry(entry);
2246 }
2247 } else {
2248 xmlChar *filename;
2249
2250 filename = xmlBuildURI(sysid, base);
2251 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002252 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002253 xmlFree(filename);
2254 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002255 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002256 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002257 /*
2258 * drop anything else we won't handle it
2259 */
2260 if (name != NULL)
2261 xmlFree(name);
2262 if (sysid != NULL)
2263 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002264 }
2265 }
2266 if (base != NULL)
2267 xmlFree(base);
2268 if (cur == NULL)
2269 return(-1);
2270 return(0);
2271}
2272
Daniel Veillard75b96822001-10-11 18:59:45 +00002273/************************************************************************
2274 * *
2275 * SGML Catalog handling *
2276 * *
2277 ************************************************************************/
2278
Daniel Veillardcda96922001-08-21 10:56:31 +00002279/**
2280 * xmlCatalogGetSGMLPublic:
2281 * @catal: an SGML catalog hash
2282 * @pubId: the public ID string
2283 *
2284 * Try to lookup the system ID associated to a public ID
2285 *
2286 * Returns the system ID if found or NULL otherwise.
2287 */
2288static const xmlChar *
2289xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2290 xmlCatalogEntryPtr entry;
2291
2292 if (catal == NULL)
2293 return(NULL);
2294
2295 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2296 if (entry == NULL)
2297 return(NULL);
2298 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillardc853b322001-11-06 15:24:37 +00002299 return(entry->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002300 return(NULL);
2301}
2302
2303/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002304 * xmlCatalogGetSGMLSystem:
2305 * @catal: an SGML catalog hash
2306 * @sysId: the public ID string
2307 *
2308 * Try to lookup the catalog local reference for a system ID
2309 *
2310 * Returns the system ID if found or NULL otherwise.
2311 */
2312static const xmlChar *
2313xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2314 xmlCatalogEntryPtr entry;
2315
2316 if (catal == NULL)
2317 return(NULL);
2318
2319 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2320 if (entry == NULL)
2321 return(NULL);
2322 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002323 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002324 return(NULL);
2325}
2326
2327/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002328 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002329 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002330 * @pubId: the public ID string
2331 * @sysId: the system ID string
2332 *
2333 * Do a complete resolution lookup of an External Identifier
2334 *
2335 * Returns the URI of the resource or NULL if not found
2336 */
2337static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002338xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2339 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002340 const xmlChar *ret = NULL;
2341
Daniel Veillard75b96822001-10-11 18:59:45 +00002342 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002343 return(NULL);
2344
2345 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002346 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002347 if (ret != NULL)
2348 return(ret);
2349 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002350 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002351 return(NULL);
2352}
2353
Daniel Veillarda7374592001-05-10 14:17:55 +00002354/************************************************************************
2355 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002356 * Specific Public interfaces *
2357 * *
2358 ************************************************************************/
2359
2360/**
2361 * xmlLoadSGMLSuperCatalog:
2362 * @filename: a file path
2363 *
2364 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2365 * references. This is only needed for manipulating SGML Super Catalogs
2366 * like adding and removing CATALOG or DELEGATE entries.
2367 *
2368 * Returns the catalog parsed or NULL in case of error
2369 */
2370xmlCatalogPtr
2371xmlLoadSGMLSuperCatalog(const char *filename)
2372{
2373 xmlChar *content;
2374 xmlCatalogPtr catal;
2375 int ret;
2376
2377 content = xmlLoadFileContent(filename);
2378 if (content == NULL)
2379 return(NULL);
2380
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002381 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002382 if (catal == NULL) {
2383 xmlFree(content);
2384 return(NULL);
2385 }
2386
2387 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2388 xmlFree(content);
2389 if (ret < 0) {
2390 xmlFreeCatalog(catal);
2391 return(NULL);
2392 }
2393 return (catal);
2394}
2395
2396/**
2397 * xmlLoadACatalog:
2398 * @filename: a file path
2399 *
2400 * Load the catalog and build the associated data structures.
2401 * This can be either an XML Catalog or an SGML Catalog
2402 * It will recurse in SGML CATALOG entries. On the other hand XML
2403 * Catalogs are not handled recursively.
2404 *
2405 * Returns the catalog parsed or NULL in case of error
2406 */
2407xmlCatalogPtr
2408xmlLoadACatalog(const char *filename)
2409{
2410 xmlChar *content;
2411 xmlChar *first;
2412 xmlCatalogPtr catal;
2413 int ret;
2414
2415 content = xmlLoadFileContent(filename);
2416 if (content == NULL)
2417 return(NULL);
2418
2419
2420 first = content;
2421
2422 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2423 (!(((*first >= 'A') && (*first <= 'Z')) ||
2424 ((*first >= 'a') && (*first <= 'z')))))
2425 first++;
2426
2427 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002428 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002429 if (catal == NULL) {
2430 xmlFree(content);
2431 return(NULL);
2432 }
2433 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2434 if (ret < 0) {
2435 xmlFreeCatalog(catal);
2436 xmlFree(content);
2437 return(NULL);
2438 }
2439 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002440 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002441 if (catal == NULL) {
2442 xmlFree(content);
2443 return(NULL);
2444 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002445 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002446 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002447 }
2448 xmlFree(content);
2449 return (catal);
2450}
2451
2452/**
2453 * xmlExpandCatalog:
2454 * @catal: a catalog
2455 * @filename: a file path
2456 *
2457 * Load the catalog and expand the existing catal structure.
2458 * This can be either an XML Catalog or an SGML Catalog
2459 *
2460 * Returns 0 in case of success, -1 in case of error
2461 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002462static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002463xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2464{
Daniel Veillard75b96822001-10-11 18:59:45 +00002465 int ret;
2466
2467 if ((catal == NULL) || (filename == NULL))
2468 return(-1);
2469
Daniel Veillard75b96822001-10-11 18:59:45 +00002470
2471 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002472 xmlChar *content;
2473
2474 content = xmlLoadFileContent(filename);
2475 if (content == NULL)
2476 return(-1);
2477
Daniel Veillard75b96822001-10-11 18:59:45 +00002478 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2479 if (ret < 0) {
2480 xmlFree(content);
2481 return(-1);
2482 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002483 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002484 } else {
2485 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002486 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002487 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002488
Daniel Veillard75b96822001-10-11 18:59:45 +00002489 cur = catal->xml;
2490 if (cur == NULL) {
2491 catal->xml = tmp;
2492 } else {
2493 while (cur->next != NULL) cur = cur->next;
2494 cur->next = tmp;
2495 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002496 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002497 return (0);
2498}
2499
2500/**
2501 * xmlACatalogResolveSystem:
2502 * @catal: a Catalog
2503 * @sysId: the public ID string
2504 *
2505 * Try to lookup the catalog resource for a system ID
2506 *
2507 * Returns the system ID if found or NULL otherwise, the value returned
2508 * must be freed by the caller.
2509 */
2510xmlChar *
2511xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2512 xmlChar *ret = NULL;
2513
2514 if ((sysID == NULL) || (catal == NULL))
2515 return(NULL);
2516
2517 if (xmlDebugCatalogs)
2518 xmlGenericError(xmlGenericErrorContext,
2519 "Resolve sysID %s\n", sysID);
2520
2521 if (catal->type == XML_XML_CATALOG_TYPE) {
2522 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2523 if (ret == XML_CATAL_BREAK)
2524 ret = NULL;
2525 } else {
2526 const xmlChar *sgml;
2527
2528 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2529 if (sgml != NULL)
2530 ret = xmlStrdup(sgml);
2531 }
2532 return(ret);
2533}
2534
2535/**
2536 * xmlACatalogResolvePublic:
2537 * @catal: a Catalog
2538 * @pubId: the public ID string
2539 *
2540 * Try to lookup the system ID associated to a public ID in that catalog
2541 *
2542 * Returns the system ID if found or NULL otherwise, the value returned
2543 * must be freed by the caller.
2544 */
2545xmlChar *
2546xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2547 xmlChar *ret = NULL;
2548
2549 if ((pubID == NULL) || (catal == NULL))
2550 return(NULL);
2551
2552 if (xmlDebugCatalogs)
2553 xmlGenericError(xmlGenericErrorContext,
2554 "Resolve pubID %s\n", pubID);
2555
2556 if (catal->type == XML_XML_CATALOG_TYPE) {
2557 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2558 if (ret == XML_CATAL_BREAK)
2559 ret = NULL;
2560 } else {
2561 const xmlChar *sgml;
2562
2563 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2564 if (sgml != NULL)
2565 ret = xmlStrdup(sgml);
2566 }
2567 return(ret);
2568}
2569
2570/**
2571 * xmlACatalogResolve:
2572 * @catal: a Catalog
2573 * @pubId: the public ID string
2574 * @sysId: the system ID string
2575 *
2576 * Do a complete resolution lookup of an External Identifier
2577 *
2578 * Returns the URI of the resource or NULL if not found, it must be freed
2579 * by the caller.
2580 */
2581xmlChar *
2582xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2583 const xmlChar * sysID)
2584{
2585 xmlChar *ret = NULL;
2586
2587 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2588 return (NULL);
2589
2590 if (xmlDebugCatalogs) {
2591 if (pubID != NULL) {
2592 xmlGenericError(xmlGenericErrorContext,
2593 "Resolve: pubID %s\n", pubID);
2594 } else {
2595 xmlGenericError(xmlGenericErrorContext,
2596 "Resolve: sysID %s\n", sysID);
2597 }
2598 }
2599
2600 if (catal->type == XML_XML_CATALOG_TYPE) {
2601 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2602 if (ret == XML_CATAL_BREAK)
2603 ret = NULL;
2604 } else {
2605 const xmlChar *sgml;
2606
2607 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2608 if (sgml != NULL)
2609 ret = xmlStrdup(sgml);
2610 }
2611 return (ret);
2612}
2613
2614/**
2615 * xmlACatalogResolveURI:
2616 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002617 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002618 *
2619 * Do a complete resolution lookup of an URI
2620 *
2621 * Returns the URI of the resource or NULL if not found, it must be freed
2622 * by the caller.
2623 */
2624xmlChar *
2625xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2626 xmlChar *ret = NULL;
2627
2628 if ((URI == NULL) || (catal == NULL))
2629 return(NULL);
2630
Daniel Veillardb44025c2001-10-11 22:55:55 +00002631 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002632 xmlGenericError(xmlGenericErrorContext,
2633 "Resolve URI %s\n", URI);
2634
2635 if (catal->type == XML_XML_CATALOG_TYPE) {
2636 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2637 if (ret == XML_CATAL_BREAK)
2638 ret = NULL;
2639 } else {
2640 const xmlChar *sgml;
2641
2642 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2643 if (sgml != NULL)
2644 sgml = xmlStrdup(sgml);
2645 }
2646 return(ret);
2647}
2648
2649/**
2650 * xmlACatalogDump:
2651 * @catal: a Catalog
2652 * @out: the file.
2653 *
2654 * Free up all the memory associated with catalogs
2655 */
2656void
2657xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002658 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002659 return;
2660
2661 if (catal->type == XML_XML_CATALOG_TYPE) {
2662 xmlDumpXMLCatalog(out, catal->xml);
2663 } else {
2664 xmlHashScan(catal->sgml,
2665 (xmlHashScanner) xmlCatalogDumpEntry, out);
2666 }
2667}
2668
2669/**
2670 * xmlACatalogAdd:
2671 * @catal: a Catalog
2672 * @type: the type of record to add to the catalog
2673 * @orig: the system, public or prefix to match
2674 * @replace: the replacement value for the match
2675 *
2676 * Add an entry in the catalog, it may overwrite existing but
2677 * different entries.
2678 *
2679 * Returns 0 if successful, -1 otherwise
2680 */
2681int
2682xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2683 const xmlChar * orig, const xmlChar * replace)
2684{
2685 int res = -1;
2686
2687 if (catal == NULL)
2688 return(-1);
2689
2690 if (catal->type == XML_XML_CATALOG_TYPE) {
2691 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2692 } else {
2693 xmlCatalogEntryType cattype;
2694
2695 cattype = xmlGetSGMLCatalogEntryType(type);
2696 if (cattype != XML_CATA_NONE) {
2697 xmlCatalogEntryPtr entry;
2698
Daniel Veillardc853b322001-11-06 15:24:37 +00002699 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002700 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002701 if (catal->sgml == NULL)
2702 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002703 res = xmlHashAddEntry(catal->sgml, orig, entry);
2704 }
2705 }
2706 return (res);
2707}
2708
2709/**
2710 * xmlACatalogRemove:
2711 * @catal: a Catalog
2712 * @value: the value to remove
2713 *
2714 * Remove an entry from the catalog
2715 *
2716 * Returns the number of entries removed if successful, -1 otherwise
2717 */
2718int
2719xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2720 int res = -1;
2721
2722 if ((catal == NULL) || (value == NULL))
2723 return(-1);
2724
2725 if (catal->type == XML_XML_CATALOG_TYPE) {
2726 res = xmlDelXMLCatalog(catal->xml, value);
2727 } else {
2728 res = xmlHashRemoveEntry(catal->sgml, value,
2729 (xmlHashDeallocator) xmlFreeCatalogEntry);
2730 if (res == 0)
2731 res = 1;
2732 }
2733 return(res);
2734}
2735
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002736/**
2737 * xmlNewCatalog:
2738 * @sgml: should this create an SGML catalog
2739 *
2740 * create a new Catalog.
2741 *
2742 * Returns the xmlCatalogPtr or NULL in case of error
2743 */
2744xmlCatalogPtr
2745xmlNewCatalog(int sgml) {
2746 xmlCatalogPtr catal = NULL;
2747
2748 if (sgml) {
2749 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2750 xmlCatalogDefaultPrefer);
2751 if ((catal != NULL) && (catal->sgml == NULL))
2752 catal->sgml = xmlHashCreate(10);
2753 } else
2754 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2755 xmlCatalogDefaultPrefer);
2756 return(catal);
2757}
2758
2759/**
2760 * xmlCatalogIsEmpty:
2761 * @catal: should this create an SGML catalog
2762 *
2763 * Check is a catalog is empty
2764 *
2765 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2766 */
2767int
2768xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2769 if (catal == NULL)
2770 return(-1);
2771
2772 if (catal->type == XML_XML_CATALOG_TYPE) {
2773 if (catal->xml == NULL)
2774 return(1);
2775 if ((catal->xml->type != XML_CATA_CATALOG) &&
2776 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2777 return(-1);
2778 if (catal->xml->children == NULL)
2779 return(1);
2780 return(0);
2781 } else {
2782 int res;
2783
2784 if (catal->sgml == NULL)
2785 return(1);
2786 res = xmlHashSize(catal->sgml);
2787 if (res == 0)
2788 return(1);
2789 if (res < 0)
2790 return(-1);
2791 }
2792 return(0);
2793}
2794
Daniel Veillard75b96822001-10-11 18:59:45 +00002795/************************************************************************
2796 * *
2797 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002798 * *
2799 ************************************************************************/
2800
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002801/**
Daniel Veillard81463942001-10-16 12:34:39 +00002802 * xmlInitializeCatalogData:
2803 *
2804 * Do the catalog initialization only of global data, doesn't try to load
2805 * any catalog actually.
2806 * this function is not thread safe, catalog initialization should
2807 * preferably be done once at startup
2808 */
2809static void
2810xmlInitializeCatalogData(void) {
2811 if (xmlCatalogInitialized != 0)
2812 return;
2813
2814 if (getenv("XML_DEBUG_CATALOG"))
2815 xmlDebugCatalogs = 1;
2816 xmlCatalogMutex = xmlNewRMutex();
2817
2818 xmlCatalogInitialized = 1;
2819}
2820/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002821 * xmlInitializeCatalog:
2822 *
2823 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002824 * this function is not thread safe, catalog initialization should
2825 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002826 */
2827void
2828xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002829 if (xmlCatalogInitialized != 0)
2830 return;
2831
Daniel Veillard81463942001-10-16 12:34:39 +00002832 xmlInitializeCatalogData();
2833 xmlRMutexLock(xmlCatalogMutex);
2834
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002835 if (getenv("XML_DEBUG_CATALOG"))
2836 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002837
Daniel Veillard75b96822001-10-11 18:59:45 +00002838 if (xmlDefaultCatalog == NULL) {
2839 const char *catalogs;
2840 xmlCatalogPtr catal;
2841
Daniel Veillardb44025c2001-10-11 22:55:55 +00002842 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002843 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002844 catalogs = XML_XML_DEFAULT_CATALOG;
2845
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002846 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002847 if (catal != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002848
Daniel Veillardc853b322001-11-06 15:24:37 +00002849 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002850 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002851
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002852 xmlDefaultCatalog = catal;
2853 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002854 }
2855
Daniel Veillard81463942001-10-16 12:34:39 +00002856 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002857}
2858
Daniel Veillard82d75332001-10-08 15:01:59 +00002859
2860/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002861 * xmlLoadCatalog:
2862 * @filename: a file path
2863 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002864 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002865 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002866 * this function is not thread safe, catalog initialization should
2867 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002868 *
2869 * Returns 0 in case of success -1 in case of error
2870 */
2871int
Daniel Veillard16756b62001-10-01 07:36:25 +00002872xmlLoadCatalog(const char *filename)
2873{
Daniel Veillard75b96822001-10-11 18:59:45 +00002874 int ret;
2875 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002876
Daniel Veillard81463942001-10-16 12:34:39 +00002877 if (!xmlCatalogInitialized)
2878 xmlInitializeCatalogData();
2879
2880 xmlRMutexLock(xmlCatalogMutex);
2881
Daniel Veillard75b96822001-10-11 18:59:45 +00002882 if (xmlDefaultCatalog == NULL) {
2883 catal = xmlLoadACatalog(filename);
2884 if (catal == NULL)
2885 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002886
Daniel Veillard75b96822001-10-11 18:59:45 +00002887 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002888 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002889 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002890 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002891
Daniel Veillard75b96822001-10-11 18:59:45 +00002892 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002893 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002894 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002895}
2896
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002897/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002898 * xmlLoadCatalogs:
2899 * @paths: a list of file path separated by ':' or spaces
2900 *
2901 * Load the catalogs and makes their definitions effective for the default
2902 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002903 * this function is not thread safe, catalog initialization should
2904 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002905 */
2906void
2907xmlLoadCatalogs(const char *pathss) {
2908 const char *cur;
2909 const char *paths;
2910 xmlChar *path;
2911
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002912 if (pathss == NULL)
2913 return;
2914
Daniel Veillard81418e32001-05-22 15:08:55 +00002915 cur = pathss;
2916 while ((cur != NULL) && (*cur != 0)) {
2917 while (IS_BLANK(*cur)) cur++;
2918 if (*cur != 0) {
2919 paths = cur;
2920 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2921 cur++;
2922 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2923 if (path != NULL) {
2924 xmlLoadCatalog((const char *) path);
2925 xmlFree(path);
2926 }
2927 }
2928 while (*cur == ':')
2929 cur++;
2930 }
2931}
2932
Daniel Veillarda7374592001-05-10 14:17:55 +00002933/**
2934 * xmlCatalogCleanup:
2935 *
2936 * Free up all the memory associated with catalogs
2937 */
2938void
2939xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00002940 if (xmlCatalogInitialized == 0)
2941 return;
2942
Daniel Veillard81463942001-10-16 12:34:39 +00002943 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002944 if (xmlDebugCatalogs)
2945 xmlGenericError(xmlGenericErrorContext,
2946 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002947 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002948 xmlHashFree(xmlCatalogXMLFiles,
2949 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002950 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002951 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002952 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002953 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002954 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002955 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00002956 xmlRMutexUnlock(xmlCatalogMutex);
2957 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00002958}
2959
2960/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002961 * xmlCatalogResolveSystem:
2962 * @sysId: the public ID string
2963 *
2964 * Try to lookup the catalog resource for a system ID
2965 *
2966 * Returns the system ID if found or NULL otherwise, the value returned
2967 * must be freed by the caller.
2968 */
2969xmlChar *
2970xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002971 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002972
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002973 if (!xmlCatalogInitialized)
2974 xmlInitializeCatalog();
2975
Daniel Veillard75b96822001-10-11 18:59:45 +00002976 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
2977 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002978}
2979
2980/**
2981 * xmlCatalogResolvePublic:
2982 * @pubId: the public ID string
2983 *
2984 * Try to lookup the system ID associated to a public ID
2985 *
2986 * Returns the system ID if found or NULL otherwise, the value returned
2987 * must be freed by the caller.
2988 */
2989xmlChar *
2990xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002991 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002992
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002993 if (!xmlCatalogInitialized)
2994 xmlInitializeCatalog();
2995
Daniel Veillard75b96822001-10-11 18:59:45 +00002996 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
2997 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002998}
Daniel Veillard344cee72001-08-20 00:08:40 +00002999
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003000/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003001 * xmlCatalogResolve:
3002 * @pubId: the public ID string
3003 * @sysId: the system ID string
3004 *
3005 * Do a complete resolution lookup of an External Identifier
3006 *
3007 * Returns the URI of the resource or NULL if not found, it must be freed
3008 * by the caller.
3009 */
3010xmlChar *
3011xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003012 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003013
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003014 if (!xmlCatalogInitialized)
3015 xmlInitializeCatalog();
3016
Daniel Veillard75b96822001-10-11 18:59:45 +00003017 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3018 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003019}
3020
3021/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003022 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003023 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003024 *
3025 * Do a complete resolution lookup of an URI
3026 *
3027 * Returns the URI of the resource or NULL if not found, it must be freed
3028 * by the caller.
3029 */
3030xmlChar *
3031xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003032 xmlChar *ret;
3033
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003034 if (!xmlCatalogInitialized)
3035 xmlInitializeCatalog();
3036
Daniel Veillard75b96822001-10-11 18:59:45 +00003037 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3038 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003039}
3040
3041/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003042 * xmlCatalogDump:
3043 * @out: the file.
3044 *
3045 * Free up all the memory associated with catalogs
3046 */
3047void
3048xmlCatalogDump(FILE *out) {
3049 if (out == NULL)
3050 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003051
Daniel Veillard75b96822001-10-11 18:59:45 +00003052 if (!xmlCatalogInitialized)
3053 xmlInitializeCatalog();
3054
3055 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003056}
3057
3058/**
3059 * xmlCatalogAdd:
3060 * @type: the type of record to add to the catalog
3061 * @orig: the system, public or prefix to match
3062 * @replace: the replacement value for the match
3063 *
3064 * Add an entry in the catalog, it may overwrite existing but
3065 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003066 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003067 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003068 *
3069 * Returns 0 if successful, -1 otherwise
3070 */
3071int
3072xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3073 int res = -1;
3074
Daniel Veillard81463942001-10-16 12:34:39 +00003075 if (!xmlCatalogInitialized)
3076 xmlInitializeCatalogData();
3077
3078 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003079 /*
3080 * Specific case where one want to override the default catalog
3081 * put in place by xmlInitializeCatalog();
3082 */
3083 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003084 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003085 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003086 xmlCatalogDefaultPrefer);
3087 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003088 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003089
Daniel Veillard81463942001-10-16 12:34:39 +00003090 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003091 return(0);
3092 }
3093
Daniel Veillard75b96822001-10-11 18:59:45 +00003094 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003095 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003096 return(res);
3097}
3098
3099/**
3100 * xmlCatalogRemove:
3101 * @value: the value to remove
3102 *
3103 * Remove an entry from the catalog
3104 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003105 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003106 */
3107int
3108xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003109 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003110
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003111 if (!xmlCatalogInitialized)
3112 xmlInitializeCatalog();
3113
Daniel Veillard81463942001-10-16 12:34:39 +00003114 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003115 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003116 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003117 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003118}
3119
3120/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003121 * xmlCatalogConvert:
3122 *
3123 * Convert all the SGML catalog entries as XML ones
3124 *
3125 * Returns the number of entries converted if successful, -1 otherwise
3126 */
3127int
3128xmlCatalogConvert(void) {
3129 int res = -1;
3130
3131 if (!xmlCatalogInitialized)
3132 xmlInitializeCatalog();
3133
Daniel Veillard81463942001-10-16 12:34:39 +00003134 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003135 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003136 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003137 return(res);
3138}
3139
Daniel Veillard75b96822001-10-11 18:59:45 +00003140/************************************************************************
3141 * *
3142 * Public interface manipulating the common preferences *
3143 * *
3144 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003145
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003146/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003147 * xmlCatalogGetDefaults:
3148 *
3149 * Used to get the user preference w.r.t. to what catalogs should
3150 * be accepted
3151 *
3152 * Returns the current xmlCatalogAllow value
3153 */
3154xmlCatalogAllow
3155xmlCatalogGetDefaults(void) {
3156 return(xmlCatalogDefaultAllow);
3157}
3158
3159/**
3160 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003161 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003162 *
3163 * Used to set the user preference w.r.t. to what catalogs should
3164 * be accepted
3165 */
3166void
3167xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003168 if (xmlDebugCatalogs) {
3169 switch (allow) {
3170 case XML_CATA_ALLOW_NONE:
3171 xmlGenericError(xmlGenericErrorContext,
3172 "Disabling catalog usage\n");
3173 break;
3174 case XML_CATA_ALLOW_GLOBAL:
3175 xmlGenericError(xmlGenericErrorContext,
3176 "Allowing only global catalogs\n");
3177 break;
3178 case XML_CATA_ALLOW_DOCUMENT:
3179 xmlGenericError(xmlGenericErrorContext,
3180 "Allowing only catalogs from the document\n");
3181 break;
3182 case XML_CATA_ALLOW_ALL:
3183 xmlGenericError(xmlGenericErrorContext,
3184 "Allowing all catalogs\n");
3185 break;
3186 }
3187 }
3188 xmlCatalogDefaultAllow = allow;
3189}
3190
3191/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003192 * xmlCatalogSetDefaultPrefer:
3193 * @prefer: the default preference for delegation
3194 *
3195 * Allows to set the preference between public and system for deletion
3196 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003197 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003198 *
3199 * Returns the previous value of the default preference for delegation
3200 */
3201xmlCatalogPrefer
3202xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3203 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3204
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003205 if (prefer == XML_CATA_PREFER_NONE)
3206 return(ret);
3207
3208 if (xmlDebugCatalogs) {
3209 switch (prefer) {
3210 case XML_CATA_PREFER_PUBLIC:
3211 xmlGenericError(xmlGenericErrorContext,
3212 "Setting catalog preference to PUBLIC\n");
3213 break;
3214 case XML_CATA_PREFER_SYSTEM:
3215 xmlGenericError(xmlGenericErrorContext,
3216 "Setting catalog preference to SYSTEM\n");
3217 break;
3218 case XML_CATA_PREFER_NONE:
3219 break;
3220 }
3221 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003222 xmlCatalogDefaultPrefer = prefer;
3223 return(ret);
3224}
3225
3226/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003227 * xmlCatalogSetDebug:
3228 * @level: the debug level of catalogs required
3229 *
3230 * Used to set the debug level for catalog operation, 0 disable
3231 * debugging, 1 enable it
3232 *
3233 * Returns the previous value of the catalog debugging level
3234 */
3235int
3236xmlCatalogSetDebug(int level) {
3237 int ret = xmlDebugCatalogs;
3238
3239 if (level <= 0)
3240 xmlDebugCatalogs = 0;
3241 else
3242 xmlDebugCatalogs = level;
3243 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003244}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003245
Daniel Veillard75b96822001-10-11 18:59:45 +00003246/************************************************************************
3247 * *
3248 * Minimal interfaces used for per-document catalogs by the parser *
3249 * *
3250 ************************************************************************/
3251
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003252/**
3253 * xmlCatalogFreeLocal:
3254 * @catalogs: a document's list of catalogs
3255 *
3256 * Free up the memory associated to the catalog list
3257 */
3258void
3259xmlCatalogFreeLocal(void *catalogs) {
3260 xmlCatalogEntryPtr catal;
3261
Daniel Veillard81463942001-10-16 12:34:39 +00003262 if (!xmlCatalogInitialized)
3263 xmlInitializeCatalog();
3264
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003265 catal = (xmlCatalogEntryPtr) catalogs;
3266 if (catal != NULL)
3267 xmlFreeCatalogEntryList(catal);
3268}
3269
3270
3271/**
3272 * xmlCatalogAddLocal:
3273 * @catalogs: a document's list of catalogs
3274 * @URL: the URL to a new local catalog
3275 *
3276 * Add the new entry to the catalog list
3277 *
3278 * Returns the updated list
3279 */
3280void *
3281xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3282 xmlCatalogEntryPtr catal, add;
3283
3284 if (!xmlCatalogInitialized)
3285 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003286
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003287 if (URL == NULL)
3288 return(catalogs);
3289
3290 if (xmlDebugCatalogs)
3291 xmlGenericError(xmlGenericErrorContext,
3292 "Adding document catalog %s\n", URL);
3293
Daniel Veillardc853b322001-11-06 15:24:37 +00003294 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003295 xmlCatalogDefaultPrefer);
3296 if (add == NULL)
3297 return(catalogs);
3298
3299 catal = (xmlCatalogEntryPtr) catalogs;
3300 if (catal == NULL)
3301 return((void *) add);
3302
3303 while (catal->next != NULL)
3304 catal = catal->next;
3305 catal->next = add;
3306 return(catalogs);
3307}
3308
3309/**
3310 * xmlCatalogLocalResolve:
3311 * @catalogs: a document's list of catalogs
3312 * @pubId: the public ID string
3313 * @sysId: the system ID string
3314 *
3315 * Do a complete resolution lookup of an External Identifier using a
3316 * document's private catalog list
3317 *
3318 * Returns the URI of the resource or NULL if not found, it must be freed
3319 * by the caller.
3320 */
3321xmlChar *
3322xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3323 const xmlChar *sysID) {
3324 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003325 xmlChar *ret;
3326
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003327 if (!xmlCatalogInitialized)
3328 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003329
Daniel Veillard81463942001-10-16 12:34:39 +00003330 if ((pubID == NULL) && (sysID == NULL))
3331 return(NULL);
3332
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003333 if (xmlDebugCatalogs) {
3334 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003335 xmlGenericError(xmlGenericErrorContext,
3336 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003337 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003338 xmlGenericError(xmlGenericErrorContext,
3339 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003340 }
3341 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003342
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003343 catal = (xmlCatalogEntryPtr) catalogs;
3344 if (catal == NULL)
3345 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003346 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3347 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3348 return(ret);
3349 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003350}
3351
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003352/**
3353 * xmlCatalogLocalResolveURI:
3354 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003355 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003356 *
3357 * Do a complete resolution lookup of an URI using a
3358 * document's private catalog list
3359 *
3360 * Returns the URI of the resource or NULL if not found, it must be freed
3361 * by the caller.
3362 */
3363xmlChar *
3364xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3365 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003366 xmlChar *ret;
3367
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003368 if (!xmlCatalogInitialized)
3369 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003370
Daniel Veillard81463942001-10-16 12:34:39 +00003371 if (URI == NULL)
3372 return(NULL);
3373
Daniel Veillard6990bf32001-08-23 21:17:48 +00003374 if (xmlDebugCatalogs)
3375 xmlGenericError(xmlGenericErrorContext,
3376 "Resolve URI %s\n", URI);
3377
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003378 catal = (xmlCatalogEntryPtr) catalogs;
3379 if (catal == NULL)
3380 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003381 ret = xmlCatalogListXMLResolveURI(catal, URI);
3382 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3383 return(ret);
3384 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003385}
3386
Daniel Veillard75b96822001-10-11 18:59:45 +00003387/************************************************************************
3388 * *
3389 * Deprecated interfaces *
3390 * *
3391 ************************************************************************/
3392/**
3393 * xmlCatalogGetSystem:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003394 * @sysId: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003395 *
3396 * Try to lookup the system ID associated to a public ID
3397 * DEPRECATED, use xmlCatalogResolveSystem()
3398 *
3399 * Returns the system ID if found or NULL otherwise.
3400 */
3401const xmlChar *
3402xmlCatalogGetSystem(const xmlChar *sysID) {
3403 xmlChar *ret;
3404 static xmlChar result[1000];
3405 static int msg = 0;
3406
Daniel Veillard81463942001-10-16 12:34:39 +00003407 if (!xmlCatalogInitialized)
3408 xmlInitializeCatalog();
3409
Daniel Veillard75b96822001-10-11 18:59:45 +00003410 if (msg == 0) {
3411 xmlGenericError(xmlGenericErrorContext,
3412 "Use of deprecated xmlCatalogGetSystem() call\n");
3413 msg++;
3414 }
3415
3416 if (sysID == NULL)
3417 return(NULL);
3418
Daniel Veillard75b96822001-10-11 18:59:45 +00003419 /*
3420 * Check first the XML catalogs
3421 */
3422 if (xmlDefaultCatalog != NULL) {
3423 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3424 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3425 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3426 result[sizeof(result) - 1] = 0;
3427 return(result);
3428 }
3429 }
3430
3431 if (xmlDefaultCatalog != NULL)
3432 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3433 return(NULL);
3434}
3435
3436/**
3437 * xmlCatalogGetPublic:
3438 * @pubId: the public ID string
3439 *
3440 * Try to lookup the system ID associated to a public ID
3441 * DEPRECATED, use xmlCatalogResolvePublic()
3442 *
3443 * Returns the system ID if found or NULL otherwise.
3444 */
3445const xmlChar *
3446xmlCatalogGetPublic(const xmlChar *pubID) {
3447 xmlChar *ret;
3448 static xmlChar result[1000];
3449 static int msg = 0;
3450
Daniel Veillard81463942001-10-16 12:34:39 +00003451 if (!xmlCatalogInitialized)
3452 xmlInitializeCatalog();
3453
Daniel Veillard75b96822001-10-11 18:59:45 +00003454 if (msg == 0) {
3455 xmlGenericError(xmlGenericErrorContext,
3456 "Use of deprecated xmlCatalogGetPublic() call\n");
3457 msg++;
3458 }
3459
3460 if (pubID == NULL)
3461 return(NULL);
3462
Daniel Veillard75b96822001-10-11 18:59:45 +00003463 /*
3464 * Check first the XML catalogs
3465 */
3466 if (xmlDefaultCatalog != NULL) {
3467 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3468 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3469 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3470 result[sizeof(result) - 1] = 0;
3471 return(result);
3472 }
3473 }
3474
3475 if (xmlDefaultCatalog != NULL)
3476 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3477 return(NULL);
3478}
3479
Daniel Veillarda7374592001-05-10 14:17:55 +00003480#endif /* LIBXML_CATALOG_ENABLED */